Loading core/java/android/view/PointerIcon.java +79 −160 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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) Loading @@ -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. Loading @@ -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); Loading @@ -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); Loading @@ -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(); } /** Loading Loading @@ -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) { Loading @@ -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; } Loading Loading @@ -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) { Loading Loading @@ -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 Loading Loading @@ -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); } } Loading core/jni/android_view_PointerIcon.cpp +13 −68 Original line number Diff line number Diff line Loading @@ -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" Loading @@ -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 --- Loading @@ -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; } Loading core/jni/android_view_PointerIcon.h +6 −18 Original line number Diff line number Diff line Loading @@ -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 Loading services/core/java/com/android/server/input/InputManagerService.java +70 −3 Original line number Diff line number Diff line Loading @@ -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 { Loading Loading @@ -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(); Loading Loading @@ -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); } Loading Loading @@ -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. Loading Loading @@ -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) {} Loading services/core/java/com/android/server/input/InputSettingsObserver.java +1 −3 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading
core/java/android/view/PointerIcon.java +79 −160 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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) Loading @@ -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. Loading @@ -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); Loading @@ -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); Loading @@ -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(); } /** Loading Loading @@ -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) { Loading @@ -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; } Loading Loading @@ -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) { Loading Loading @@ -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 Loading Loading @@ -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); } } Loading
core/jni/android_view_PointerIcon.cpp +13 −68 Original line number Diff line number Diff line Loading @@ -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" Loading @@ -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 --- Loading @@ -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; } Loading
core/jni/android_view_PointerIcon.h +6 −18 Original line number Diff line number Diff line Loading @@ -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 Loading
services/core/java/com/android/server/input/InputManagerService.java +70 −3 Original line number Diff line number Diff line Loading @@ -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 { Loading Loading @@ -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(); Loading Loading @@ -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); } Loading Loading @@ -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. Loading Loading @@ -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) {} Loading
services/core/java/com/android/server/input/InputSettingsObserver.java +1 −3 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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