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

Commit 80727587 authored by Prabir Pradhan's avatar Prabir Pradhan
Browse files

Pointer Icon Refactor: Load resources for system icons before drawing

In this refactor, we ensure that we load the resource for system icon
types (as opposed to custom icons that use TYPE_CUSTOM) once in the
system before drawing the icon, instead of resolving the resource in the
app using the app context.

The main reason for this refactor is to simplify the pipeline by
eliminating the unnecessary step of resolving the system icon resource
using the app context. The app-resolved resource IDs are already being
ignored, because the native code only caches the icon by type and not
the resource IDs. This refactor only makes that behavior explicit in the
code, so there should be no behavior changes.

Notable changes:
- Do not resolve the resource IDs of system icons in
  PointerIcon#getSystemIcon().
- There is no need to register a display listener in PointerIcon.
- When parceling a system icon, only send the type.
- Get the loaded system icon in native code directly from the java
  InputManagerService, instead of loading it using native code.
- Cache loaded icons in the java IMS so that bitmaps don't need to be
  copied when used by multiple pointer controllers.

To recap, the Java PointerIcon object can be in one of three states:
1. Custom icon: The PointerIcon holds a custom bitmap provided by the
   app to use as the cursor icon.
2. System icon (Unloaded): The PointerIcon object refers to specific
   system icon differentiated by the TYPE_* constants. The bitmap of the
   system icon is not yet loaded in this state.
3. System icon (Loaded): The PointerIcon object refers to a specific
   system icon, and it holds the bitmap for that icon, which has been
   loaded into memory.

Apps only have the ability to create icons in states 1 and 2, since
they don't need to load the system icon bitmaps that are drawn by the
system.

Bug: 293587049
Test: manual
Change-Id: I6f79ca0611019501e0ca02c0edfa16d39578e927
parent e8c4c3b0
Loading
Loading
Loading
Loading
+79 −160
Original line number Diff line number Diff line
@@ -32,7 +32,6 @@ import android.graphics.RectF;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.hardware.display.DisplayManager;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -156,14 +155,12 @@ public final class PointerIcon implements Parcelable {
     */
    public static final int TYPE_DEFAULT = TYPE_ARROW;

    private static final PointerIcon gNullIcon = new PointerIcon(TYPE_NULL);
    private static final SparseArray<SparseArray<PointerIcon>> gSystemIconsByDisplay =
            new SparseArray<SparseArray<PointerIcon>>();
    private static boolean sUseLargeIcons = false;
    // A cache of the system icons used by the app, used to avoid creating a new PointerIcon object
    // every time we need to resolve the icon (i.e. on each input event).
    private static final SparseArray<PointerIcon> SYSTEM_ICONS = new SparseArray<>();

    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
    private final int mType;
    private int mSystemIconResourceId;
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    private Bitmap mBitmap;
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -177,44 +174,12 @@ public final class PointerIcon implements Parcelable {
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    private int mDurationPerFrame;

    /**
     * Listener for displays lifecycle.
     * @hide
     */
    private static DisplayManager.DisplayListener sDisplayListener;

    private PointerIcon(int type) {
        mType = type;
    }

    /**
     * Gets a special pointer icon that has no bitmap.
     *
     * @return The null pointer icon.
     *
     * @see #TYPE_NULL
     * @hide
     */
    public static @NonNull PointerIcon getNullIcon() {
        return gNullIcon;
    }

    /**
     * Gets the default pointer icon.
     *
     * @param context The context.
     * @return The default pointer icon.
     *
     * @throws IllegalArgumentException if context is null.
     * @hide
     */
    public static @NonNull PointerIcon getDefaultIcon(@NonNull Context context) {
        return getSystemIcon(context, TYPE_DEFAULT);
    }

    /**
     * Gets a system pointer icon for the given type.
     * If typeis not recognized, returns the default pointer icon.
     *
     * @param context The context.
     * @param type The pointer icon type.
@@ -223,32 +188,42 @@ public final class PointerIcon implements Parcelable {
     * @throws IllegalArgumentException if context is null.
     */
    public static @NonNull PointerIcon getSystemIcon(@NonNull Context context, int type) {
        // TODO(b/293587049): Pointer Icon Refactor: There is no need to load the system
        // icon resource into memory outside of system server. Remove the need to load
        // resources when getting a system icon.
        if (context == null) {
            // We no longer use the context to resolve the system icon resource here, because the
            // system will use its own context to do the type-to-resource resolution and cache it
            // for use across different apps. Therefore, apps cannot customize the resource of a
            // system icon. To avoid changing the public API, we keep the context parameter
            // requirement.
            throw new IllegalArgumentException("context must not be null");
        }

        if (type == TYPE_NULL) {
            return gNullIcon;
        return getSystemIcon(type);
    }

        if (sDisplayListener == null) {
            registerDisplayListener(context);
    private static @NonNull PointerIcon getSystemIcon(int type) {
        if (type == TYPE_CUSTOM) {
            throw new IllegalArgumentException("cannot get system icon for TYPE_CUSTOM");
        }
        PointerIcon icon = SYSTEM_ICONS.get(type);
        if (icon == null) {
            icon = new PointerIcon(type);
            SYSTEM_ICONS.put(type, icon);
        }
        return icon;
    }

        final int displayId = context.getDisplayId();
        SparseArray<PointerIcon> systemIcons = gSystemIconsByDisplay.get(displayId);
        if (systemIcons == null) {
            systemIcons = new SparseArray<>();
            gSystemIconsByDisplay.put(displayId, systemIcons);
    /**
     * Get a system icon with its resources loaded.
     * This should only be used by the system for drawing icons to the screen.
     * @hide
     */
    public static @NonNull PointerIcon getLoadedSystemIcon(@NonNull Context context, int type,
            boolean useLargeIcons) {
        if (type == TYPE_NOT_SPECIFIED) {
            throw new IllegalStateException("Cannot load icon for type TYPE_NOT_SPECIFIED");
        }

        PointerIcon icon = systemIcons.get(type);
        // Reload if not in the same display.
        if (icon != null) {
            return icon;
        if (type == TYPE_CUSTOM) {
            throw new IllegalArgumentException("Custom icons must be loaded when they're created");
        }

        int typeIndex = getSystemIconTypeIndex(type);
@@ -256,8 +231,9 @@ public final class PointerIcon implements Parcelable {
            typeIndex = getSystemIconTypeIndex(TYPE_DEFAULT);
        }

        int defStyle = sUseLargeIcons ?
                com.android.internal.R.style.LargePointer : com.android.internal.R.style.Pointer;
        final int defStyle = useLargeIcons
                ? com.android.internal.R.style.LargePointer
                : com.android.internal.R.style.Pointer;
        TypedArray a = context.obtainStyledAttributes(null,
                com.android.internal.R.styleable.Pointer,
                0, defStyle);
@@ -266,26 +242,19 @@ public final class PointerIcon implements Parcelable {

        if (resourceId == -1) {
            Log.w(TAG, "Missing theme resources for pointer icon type " + type);
            return type == TYPE_DEFAULT ? gNullIcon : getSystemIcon(context, TYPE_DEFAULT);
            return type == TYPE_DEFAULT
                    ? getSystemIcon(TYPE_NULL)
                    : getLoadedSystemIcon(context, TYPE_DEFAULT, useLargeIcons);
        }

        icon = new PointerIcon(type);
        if ((resourceId & 0xff000000) == 0x01000000) {
            icon.mSystemIconResourceId = resourceId;
        } else {
        final PointerIcon icon = new PointerIcon(type);
        icon.loadResource(context, context.getResources(), resourceId);
        }
        systemIcons.append(type, icon);
        return icon;
    }

    /**
     * Updates wheter accessibility large icons are used or not.
     * @hide
     */
    public static void setUseLargeIcons(boolean use) {
        sUseLargeIcons = use;
        gSystemIconsByDisplay.clear();
    private boolean isLoaded() {
        return mBitmap != null && mHotSpotX >= 0 && mHotSpotX < mBitmap.getWidth() && mHotSpotY >= 0
                && mHotSpotY < mBitmap.getHeight();
    }

    /**
@@ -346,79 +315,54 @@ public final class PointerIcon implements Parcelable {
        return icon;
    }

    /**
     * Loads the bitmap and hotspot information for a pointer icon, if it is not already loaded.
     * Returns a pointer icon (not necessarily the same instance) with the information filled in.
     *
     * @param context The context.
     * @return The loaded pointer icon.
     *
     * @throws IllegalArgumentException if context is null.
     * @hide
     */
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
    public @NonNull PointerIcon load(@NonNull Context context) {
        if (context == null) {
            throw new IllegalArgumentException("context must not be null");
        }

        if (mSystemIconResourceId == 0 || mBitmap != null) {
            return this;
        }

        PointerIcon result = new PointerIcon(mType);
        result.mSystemIconResourceId = mSystemIconResourceId;
        result.loadResource(context, context.getResources(), mSystemIconResourceId);
        return result;
    }

    /** @hide */
    public int getType() {
        return mType;
    }

    public static final @NonNull Parcelable.Creator<PointerIcon> CREATOR
            = new Parcelable.Creator<PointerIcon>() {
    public static final @NonNull Parcelable.Creator<PointerIcon> CREATOR =
            new Parcelable.Creator<>() {
                @Override
                public PointerIcon createFromParcel(Parcel in) {
            int type = in.readInt();
            if (type == TYPE_NULL) {
                return getNullIcon();
            }

            int systemIconResourceId = in.readInt();
            if (systemIconResourceId != 0) {
                PointerIcon icon = new PointerIcon(type);
                icon.mSystemIconResourceId = systemIconResourceId;
                    final int type = in.readInt();
                    if (type != TYPE_CUSTOM) {
                        return getSystemIcon(type);
                    }
                    final PointerIcon icon =
                            PointerIcon.create(
                                    Bitmap.CREATOR.createFromParcel(in),
                                    in.readFloat(),
                                    in.readFloat());
                    return icon;
                }

            Bitmap bitmap = Bitmap.CREATOR.createFromParcel(in);
            float hotSpotX = in.readFloat();
            float hotSpotY = in.readFloat();
            return PointerIcon.create(bitmap, hotSpotX, hotSpotY);
        }

                @Override
                public PointerIcon[] newArray(int size) {
                    return new PointerIcon[size];
                }
            };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel out, int flags) {
        out.writeInt(mType);
        if (mType != TYPE_CUSTOM) {
            // When parceling a non-custom icon type, do not write the icon bitmap into the parcel
            // because it can be re-loaded from resources after un-parceling.
            return;
        }

        if (mType != TYPE_NULL) {
            out.writeInt(mSystemIconResourceId);
            if (mSystemIconResourceId == 0) {
        if (!isLoaded()) {
            throw new IllegalStateException("Custom icon should be loaded upon creation");
        }
        mBitmap.writeToParcel(out, flags);
        out.writeFloat(mHotSpotX);
        out.writeFloat(mHotSpotY);
    }
        }
    }

    @Override
    public boolean equals(@Nullable Object other) {
@@ -431,14 +375,13 @@ public final class PointerIcon implements Parcelable {
        }

        PointerIcon otherIcon = (PointerIcon) other;
        if (mType != otherIcon.mType
                || mSystemIconResourceId != otherIcon.mSystemIconResourceId) {
        if (mType != otherIcon.mType) {
            return false;
        }

        if (mSystemIconResourceId == 0 && (mBitmap != otherIcon.mBitmap
        if (mBitmap != otherIcon.mBitmap
                || mHotSpotX != otherIcon.mHotSpotX
                || mHotSpotY != otherIcon.mHotSpotY)) {
                || mHotSpotY != otherIcon.mHotSpotY) {
            return false;
        }

@@ -545,13 +488,13 @@ public final class PointerIcon implements Parcelable {
        mBitmap = bitmap;
        mHotSpotX = hotSpotX;
        mHotSpotY = hotSpotY;
        assert isLoaded();
    }

    @Override
    public String toString() {
        return "PointerIcon{type=" + typeToString(mType)
                + ", hotspotX=" + mHotSpotX + ", hotspotY=" + mHotSpotY
                + ", systemIconResourceId=" + mSystemIconResourceId + "}";
                + ", hotspotX=" + mHotSpotX + ", hotspotY=" + mHotSpotY + "}";
    }

    private static void validateHotSpot(Bitmap bitmap, float hotSpotX, float hotSpotY) {
@@ -622,31 +565,6 @@ public final class PointerIcon implements Parcelable {
        }
    }

    /**
     * Manage system icon cache handled by display lifecycle.
     * @param context The context.
     */
    private static void registerDisplayListener(@NonNull Context context) {
        sDisplayListener = new DisplayManager.DisplayListener() {
            @Override
            public void onDisplayAdded(int displayId) {
            }

            @Override
            public void onDisplayRemoved(int displayId) {
                gSystemIconsByDisplay.remove(displayId);
            }

            @Override
            public void onDisplayChanged(int displayId) {
                gSystemIconsByDisplay.remove(displayId);
            }
        };

        DisplayManager displayManager = context.getSystemService(DisplayManager.class);
        displayManager.registerDisplayListener(sDisplayListener, null /* handler */);
    }

    /**
     * Convert type constant to string.
     * @hide
@@ -680,6 +598,7 @@ public final class PointerIcon implements Parcelable {
            case TYPE_ZOOM_OUT: return "ZOOM_OUT";
            case TYPE_GRAB: return "GRAB";
            case TYPE_GRABBING: return "GRABBING";
            case TYPE_HANDWRITING: return "HANDWRITING";
            default: return Integer.toString(type);
        }
    }
+13 −68
Original line number Diff line number Diff line
@@ -18,12 +18,12 @@

#include "android_view_PointerIcon.h"

#include <android-base/logging.h>
#include <android/graphics/bitmap.h>
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/Log.h>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedLocalRef.h>
#include <utils/Log.h>

#include "core_jni_helpers.h"

@@ -37,90 +37,41 @@ static struct {
    jfieldID mHotSpotY;
    jfieldID mBitmapFrames;
    jfieldID mDurationPerFrame;
    jmethodID getSystemIcon;
    jmethodID load;
} gPointerIconClassInfo;


// --- Global Functions ---

jobject android_view_PointerIcon_getSystemIcon(JNIEnv* env, jobject contextObj,
                                               PointerIconStyle style) {
    jobject pointerIconObj = env->CallStaticObjectMethod(gPointerIconClassInfo.clazz,
            gPointerIconClassInfo.getSystemIcon, contextObj, style);
    if (env->ExceptionCheck()) {
        ALOGW("An exception occurred while getting a pointer icon with style %d.", style);
        LOGW_EX(env);
        env->ExceptionClear();
        return NULL;
    }
    return pointerIconObj;
}

status_t android_view_PointerIcon_load(JNIEnv* env, jobject pointerIconObj, jobject contextObj,
        PointerIcon* outPointerIcon) {
    outPointerIcon->reset();

PointerIcon android_view_PointerIcon_toNative(JNIEnv* env, jobject pointerIconObj) {
    if (!pointerIconObj) {
        return OK;
        LOG(FATAL) << __func__ << ": pointerIconObj is null";
    }

    ScopedLocalRef<jobject> loadedPointerIconObj(env, env->CallObjectMethod(pointerIconObj,
            gPointerIconClassInfo.load, contextObj));
    if (env->ExceptionCheck() || !loadedPointerIconObj.get()) {
        ALOGW("An exception occurred while loading a pointer icon.");
        LOGW_EX(env);
        env->ExceptionClear();
        return UNKNOWN_ERROR;
    }
    return android_view_PointerIcon_getLoadedIcon(env, loadedPointerIconObj.get(), outPointerIcon);
}

status_t android_view_PointerIcon_getLoadedIcon(JNIEnv* env, jobject pointerIconObj,
        PointerIcon* outPointerIcon) {
    if (!pointerIconObj) {
        return BAD_VALUE;
    }
    outPointerIcon->style = static_cast<PointerIconStyle>(
    PointerIcon icon;
    icon.style = static_cast<PointerIconStyle>(
            env->GetIntField(pointerIconObj, gPointerIconClassInfo.mType));
    outPointerIcon->hotSpotX = env->GetFloatField(pointerIconObj, gPointerIconClassInfo.mHotSpotX);
    outPointerIcon->hotSpotY = env->GetFloatField(pointerIconObj, gPointerIconClassInfo.mHotSpotY);
    icon.hotSpotX = env->GetFloatField(pointerIconObj, gPointerIconClassInfo.mHotSpotX);
    icon.hotSpotY = env->GetFloatField(pointerIconObj, gPointerIconClassInfo.mHotSpotY);

    ScopedLocalRef<jobject> bitmapObj(
            env, env->GetObjectField(pointerIconObj, gPointerIconClassInfo.mBitmap));
    if (bitmapObj.get()) {
        outPointerIcon->bitmap = graphics::Bitmap(env, bitmapObj.get());
        icon.bitmap = graphics::Bitmap(env, bitmapObj.get());
    }

    ScopedLocalRef<jobjectArray> bitmapFramesObj(env, reinterpret_cast<jobjectArray>(
            env->GetObjectField(pointerIconObj, gPointerIconClassInfo.mBitmapFrames)));
    if (bitmapFramesObj.get()) {
        outPointerIcon->durationPerFrame = env->GetIntField(
                pointerIconObj, gPointerIconClassInfo.mDurationPerFrame);
        icon.durationPerFrame =
                env->GetIntField(pointerIconObj, gPointerIconClassInfo.mDurationPerFrame);
        jsize size = env->GetArrayLength(bitmapFramesObj.get());
        outPointerIcon->bitmapFrames.resize(size);
        icon.bitmapFrames.resize(size);
        for (jsize i = 0; i < size; ++i) {
            ScopedLocalRef<jobject> bitmapObj(env, env->GetObjectArrayElement(bitmapFramesObj.get(), i));
            outPointerIcon->bitmapFrames[i] = graphics::Bitmap(env, bitmapObj.get());
        }
    }

    return OK;
            icon.bitmapFrames[i] = graphics::Bitmap(env, bitmapObj.get());
        }

status_t android_view_PointerIcon_loadSystemIcon(JNIEnv* env, jobject contextObj,
                                                 PointerIconStyle style,
                                                 PointerIcon* outPointerIcon) {
    jobject pointerIconObj = android_view_PointerIcon_getSystemIcon(env, contextObj, style);
    if (!pointerIconObj) {
        outPointerIcon->reset();
        return UNKNOWN_ERROR;
    }

    status_t status = android_view_PointerIcon_load(env, pointerIconObj,
            contextObj, outPointerIcon);
    env->DeleteLocalRef(pointerIconObj);
    return status;
    return icon;
}

// --- JNI Registration ---
@@ -147,12 +98,6 @@ int register_android_view_PointerIcon(JNIEnv* env) {
    gPointerIconClassInfo.mDurationPerFrame = GetFieldIDOrDie(env, gPointerIconClassInfo.clazz,
            "mDurationPerFrame", "I");

    gPointerIconClassInfo.getSystemIcon = GetStaticMethodIDOrDie(env, gPointerIconClassInfo.clazz,
            "getSystemIcon", "(Landroid/content/Context;I)Landroid/view/PointerIcon;");

    gPointerIconClassInfo.load = GetMethodIDOrDie(env, gPointerIconClassInfo.clazz,
            "load", "(Landroid/content/Context;)Landroid/view/PointerIcon;");

    return 0;
}

+6 −18
Original line number Diff line number Diff line
@@ -52,24 +52,12 @@ struct PointerIcon {
    }
};

/* Gets a system pointer icon with the specified style. */
extern jobject android_view_PointerIcon_getSystemIcon(JNIEnv* env, jobject contextObj,
                                                      PointerIconStyle style);

/* Loads the bitmap associated with a pointer icon.
 * If pointerIconObj is NULL, returns OK and a pointer icon with POINTER_ICON_STYLE_NULL. */
extern status_t android_view_PointerIcon_load(JNIEnv* env, jobject pointerIconObj,
                                              jobject contextObj, PointerIcon* outPointerIcon);

/* Obtain the data of pointerIconObj and put to outPointerIcon. */
extern status_t android_view_PointerIcon_getLoadedIcon(JNIEnv* env, jobject pointerIconObj,
                                                       PointerIcon* outPointerIcon);

/* Loads the bitmap associated with a pointer icon by style.
 * If pointerIconObj is NULL, returns OK and a pointer icon with POINTER_ICON_STYLE_NULL. */
extern status_t android_view_PointerIcon_loadSystemIcon(JNIEnv* env, jobject contextObj,
                                                        PointerIconStyle style,
                                                        PointerIcon* outPointerIcon);
/*
 * Obtain the data of the Java pointerIconObj into a native PointerIcon.
 *
 * The pointerIconObj must not be null.
 */
PointerIcon android_view_PointerIcon_toNative(JNIEnv* env, jobject pointerIconObj);

} // namespace android

+70 −3
Original line number Diff line number Diff line
@@ -411,6 +411,40 @@ 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;

    final DisplayManager.DisplayListener mDisplayListener = new DisplayManager.DisplayListener() {
        @Override
        public void onDisplayAdded(int displayId) {

        }

        @Override
        public void onDisplayRemoved(int displayId) {
            synchronized (mLoadedPointerIconsByDisplayAndType) {
                mLoadedPointerIconsByDisplayAndType.remove(displayId);
            }
        }

        @Override
        public void onDisplayChanged(int displayId) {
            synchronized (mLoadedPointerIconsByDisplayAndType) {
                // The display density could have changed, so force all cached pointer icons to be
                // reloaded for the display.
                var iconsByType = mLoadedPointerIconsByDisplayAndType.get(displayId);
                if (iconsByType == null) {
                    return;
                }
                iconsByType.clear();
            }
            mNative.reloadPointerIcons();
        }
    };

    /** Point of injection for test dependencies. */
    @VisibleForTesting
    static class Injector {
@@ -578,6 +612,10 @@ public class InputManagerService extends IInputManager.Stub
            mWiredAccessoryCallbacks.systemReady();
        }

        Objects.requireNonNull(
                mContext.getSystemService(DisplayManager.class)).registerDisplayListener(
                mDisplayListener, mHandler);

        mKeyboardLayoutManager.systemRunning();
        mBatteryController.systemRunning();
        mKeyboardBacklightController.systemRunning();
@@ -1290,8 +1328,11 @@ public class InputManagerService extends IInputManager.Stub
            mPointerIconDisplayContext = null;
        }

        updateAdditionalDisplayInputProperties(displayId, AdditionalDisplayInputProperties::reset);
        updateAdditionalDisplayInputProperties(displayId,
                AdditionalDisplayInputProperties::reset);

        // TODO(b/320763728): Rely on WindowInfosListener to determine when a display has been
        //  removed in InputDispatcher instead of this callback.
        mNative.displayRemoved(displayId);
    }

@@ -2721,8 +2762,22 @@ public class InputManagerService extends IInputManager.Stub

    // Native callback.
    @SuppressWarnings("unused")
    private PointerIcon getPointerIcon(int displayId) {
        return PointerIcon.getDefaultIcon(getContextForPointerIcon(displayId));
    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(getContextForPointerIcon(displayId), type,
                        mUseLargePointerIcons);
                iconsByType.put(type, icon);
            }
            return Objects.requireNonNull(icon);
        }
    }

    // Native callback.
@@ -3556,6 +3611,18 @@ public class InputManagerService extends IInputManager.Stub
        mNative.setAccessibilityStickyKeysEnabled(enabled);
    }

    void setUseLargePointerIcons(boolean useLargeIcons) {
        synchronized (mLoadedPointerIconsByDisplayAndType) {
            if (mUseLargePointerIcons == useLargeIcons) {
                return;
            }
            mUseLargePointerIcons = useLargeIcons;
            // Clear all cached icons on all displays.
            mLoadedPointerIconsByDisplayAndType.clear();
        }
        mNative.reloadPointerIcons();
    }

    interface KeyboardBacklightControllerInterface {
        default void incrementKeyboardBacklight(int deviceId) {}
        default void decrementKeyboardBacklight(int deviceId) {}
+1 −3
Original line number Diff line number Diff line
@@ -28,7 +28,6 @@ import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.util.Log;
import android.view.PointerIcon;
import android.view.ViewConfiguration;

import java.util.Map;
@@ -178,8 +177,7 @@ class InputSettingsObserver extends ContentObserver {
        final int accessibilityConfig = Settings.Secure.getIntForUser(
                mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON,
                0, UserHandle.USER_CURRENT);
        PointerIcon.setUseLargeIcons(accessibilityConfig == 1);
        mNative.reloadPointerIcons();
        mService.setUseLargePointerIcons(accessibilityConfig == 1);
    }

    private void updateLongPressTimeout(String reason) {
Loading