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 Original line Diff line number Diff line
@@ -32,7 +32,6 @@ import android.graphics.RectF;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Drawable;
import android.hardware.display.DisplayManager;
import android.os.Build;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Parcelable;
@@ -156,14 +155,12 @@ public final class PointerIcon implements Parcelable {
     */
     */
    public static final int TYPE_DEFAULT = TYPE_ARROW;
    public static final int TYPE_DEFAULT = TYPE_ARROW;


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


    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
    private final int mType;
    private final int mType;
    private int mSystemIconResourceId;
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    private Bitmap mBitmap;
    private Bitmap mBitmap;
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    @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)
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    private int mDurationPerFrame;
    private int mDurationPerFrame;


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

    private PointerIcon(int type) {
    private PointerIcon(int type) {
        mType = 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.
     * Gets a system pointer icon for the given type.
     * If typeis not recognized, returns the default pointer icon.
     *
     *
     * @param context The context.
     * @param context The context.
     * @param type The pointer icon type.
     * @param type The pointer icon type.
@@ -223,32 +188,42 @@ public final class PointerIcon implements Parcelable {
     * @throws IllegalArgumentException if context is null.
     * @throws IllegalArgumentException if context is null.
     */
     */
    public static @NonNull PointerIcon getSystemIcon(@NonNull Context context, int type) {
    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) {
        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");
            throw new IllegalArgumentException("context must not be null");
        }
        }

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


        if (sDisplayListener == null) {
    private static @NonNull PointerIcon getSystemIcon(int type) {
            registerDisplayListener(context);
        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);
     * Get a system icon with its resources loaded.
        if (systemIcons == null) {
     * This should only be used by the system for drawing icons to the screen.
            systemIcons = new SparseArray<>();
     * @hide
            gSystemIconsByDisplay.put(displayId, systemIcons);
     */
    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);
        if (type == TYPE_CUSTOM) {
        // Reload if not in the same display.
            throw new IllegalArgumentException("Custom icons must be loaded when they're created");
        if (icon != null) {
            return icon;
        }
        }


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


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


        if (resourceId == -1) {
        if (resourceId == -1) {
            Log.w(TAG, "Missing theme resources for pointer icon type " + type);
            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);
        final PointerIcon icon = new PointerIcon(type);
        if ((resourceId & 0xff000000) == 0x01000000) {
            icon.mSystemIconResourceId = resourceId;
        } else {
        icon.loadResource(context, context.getResources(), resourceId);
        icon.loadResource(context, context.getResources(), resourceId);
        }
        systemIcons.append(type, icon);
        return icon;
        return icon;
    }
    }


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


    /**
    /**
@@ -346,79 +315,54 @@ public final class PointerIcon implements Parcelable {
        return icon;
        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 */
    /** @hide */
    public int getType() {
    public int getType() {
        return mType;
        return mType;
    }
    }


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

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


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

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


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


    @Override
    public void writeToParcel(Parcel out, int flags) {
    public void writeToParcel(Parcel out, int flags) {
        out.writeInt(mType);
        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) {
        if (!isLoaded()) {
            out.writeInt(mSystemIconResourceId);
            throw new IllegalStateException("Custom icon should be loaded upon creation");
            if (mSystemIconResourceId == 0) {
        }
        mBitmap.writeToParcel(out, flags);
        mBitmap.writeToParcel(out, flags);
        out.writeFloat(mHotSpotX);
        out.writeFloat(mHotSpotX);
        out.writeFloat(mHotSpotY);
        out.writeFloat(mHotSpotY);
    }
    }
        }
    }


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


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


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


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


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


    private static void validateHotSpot(Bitmap bitmap, float hotSpotX, float hotSpotY) {
    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.
     * Convert type constant to string.
     * @hide
     * @hide
@@ -680,6 +598,7 @@ public final class PointerIcon implements Parcelable {
            case TYPE_ZOOM_OUT: return "ZOOM_OUT";
            case TYPE_ZOOM_OUT: return "ZOOM_OUT";
            case TYPE_GRAB: return "GRAB";
            case TYPE_GRAB: return "GRAB";
            case TYPE_GRABBING: return "GRABBING";
            case TYPE_GRABBING: return "GRABBING";
            case TYPE_HANDWRITING: return "HANDWRITING";
            default: return Integer.toString(type);
            default: return Integer.toString(type);
        }
        }
    }
    }
+13 −68
Original line number Original line Diff line number Diff line
@@ -18,12 +18,12 @@


#include "android_view_PointerIcon.h"
#include "android_view_PointerIcon.h"


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


#include "core_jni_helpers.h"
#include "core_jni_helpers.h"


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




// --- Global Functions ---
// --- Global Functions ---


jobject android_view_PointerIcon_getSystemIcon(JNIEnv* env, jobject contextObj,
PointerIcon android_view_PointerIcon_toNative(JNIEnv* env, jobject pointerIconObj) {
                                               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();

    if (!pointerIconObj) {
    if (!pointerIconObj) {
        return OK;
        LOG(FATAL) << __func__ << ": pointerIconObj is null";
    }
    }

    PointerIcon icon;
    ScopedLocalRef<jobject> loadedPointerIconObj(env, env->CallObjectMethod(pointerIconObj,
    icon.style = static_cast<PointerIconStyle>(
            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>(
            env->GetIntField(pointerIconObj, gPointerIconClassInfo.mType));
            env->GetIntField(pointerIconObj, gPointerIconClassInfo.mType));
    outPointerIcon->hotSpotX = env->GetFloatField(pointerIconObj, gPointerIconClassInfo.mHotSpotX);
    icon.hotSpotX = env->GetFloatField(pointerIconObj, gPointerIconClassInfo.mHotSpotX);
    outPointerIcon->hotSpotY = env->GetFloatField(pointerIconObj, gPointerIconClassInfo.mHotSpotY);
    icon.hotSpotY = env->GetFloatField(pointerIconObj, gPointerIconClassInfo.mHotSpotY);


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


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

    return OK;
        }
        }

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,
    return icon;
            contextObj, outPointerIcon);
    env->DeleteLocalRef(pointerIconObj);
    return status;
}
}


// --- JNI Registration ---
// --- JNI Registration ---
@@ -147,12 +98,6 @@ int register_android_view_PointerIcon(JNIEnv* env) {
    gPointerIconClassInfo.mDurationPerFrame = GetFieldIDOrDie(env, gPointerIconClassInfo.clazz,
    gPointerIconClassInfo.mDurationPerFrame = GetFieldIDOrDie(env, gPointerIconClassInfo.clazz,
            "mDurationPerFrame", "I");
            "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;
    return 0;
}
}


+6 −18
Original line number Original line 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,
 * Obtain the data of the Java pointerIconObj into a native PointerIcon.
                                                      PointerIconStyle style);
 *

 * The pointerIconObj must not be null.
/* Loads the bitmap associated with a pointer icon.
 */
 * If pointerIconObj is NULL, returns OK and a pointer icon with POINTER_ICON_STYLE_NULL. */
PointerIcon android_view_PointerIcon_toNative(JNIEnv* env, jobject pointerIconObj);
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);


} // namespace android
} // namespace android


+70 −3
Original line number Original line Diff line number Diff line
@@ -411,6 +411,40 @@ public class InputManagerService extends IInputManager.Stub
    private boolean mShowKeyPresses = false;
    private boolean mShowKeyPresses = false;
    private boolean mShowRotaryInput = 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. */
    /** Point of injection for test dependencies. */
    @VisibleForTesting
    @VisibleForTesting
    static class Injector {
    static class Injector {
@@ -578,6 +612,10 @@ public class InputManagerService extends IInputManager.Stub
            mWiredAccessoryCallbacks.systemReady();
            mWiredAccessoryCallbacks.systemReady();
        }
        }


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

        mKeyboardLayoutManager.systemRunning();
        mKeyboardLayoutManager.systemRunning();
        mBatteryController.systemRunning();
        mBatteryController.systemRunning();
        mKeyboardBacklightController.systemRunning();
        mKeyboardBacklightController.systemRunning();
@@ -1290,8 +1328,11 @@ public class InputManagerService extends IInputManager.Stub
            mPointerIconDisplayContext = null;
            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);
        mNative.displayRemoved(displayId);
    }
    }


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


    // Native callback.
    // Native callback.
    @SuppressWarnings("unused")
    @SuppressWarnings("unused")
    private PointerIcon getPointerIcon(int displayId) {
    private @NonNull PointerIcon getLoadedPointerIcon(int displayId, int type) {
        return PointerIcon.getDefaultIcon(getContextForPointerIcon(displayId));
        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.
    // Native callback.
@@ -3556,6 +3611,18 @@ public class InputManagerService extends IInputManager.Stub
        mNative.setAccessibilityStickyKeysEnabled(enabled);
        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 {
    interface KeyboardBacklightControllerInterface {
        default void incrementKeyboardBacklight(int deviceId) {}
        default void incrementKeyboardBacklight(int deviceId) {}
        default void decrementKeyboardBacklight(int deviceId) {}
        default void decrementKeyboardBacklight(int deviceId) {}
+1 −3
Original line number Original line Diff line number Diff line
@@ -28,7 +28,6 @@ import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.provider.Settings;
import android.util.Log;
import android.util.Log;
import android.view.PointerIcon;
import android.view.ViewConfiguration;
import android.view.ViewConfiguration;


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


    private void updateLongPressTimeout(String reason) {
    private void updateLongPressTimeout(String reason) {
Loading