diff options
212 files changed, 7513 insertions, 1555 deletions
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index a81bcbcce9c9..a452226c81ac 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -575,14 +575,22 @@ public final class DisplayManager { EVENT_FLAG_DISPLAY_ADDED, EVENT_FLAG_DISPLAY_CHANGED, EVENT_FLAG_DISPLAY_REMOVED, - EVENT_FLAG_DISPLAY_BRIGHTNESS, - EVENT_FLAG_HDR_SDR_RATIO_CHANGED, - EVENT_FLAG_DISPLAY_CONNECTION_CHANGED, }) @Retention(RetentionPolicy.SOURCE) public @interface EventFlag {} /** + * @hide + */ + @LongDef(flag = true, prefix = {"PRIVATE_EVENT_FLAG_"}, value = { + PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS, + PRIVATE_EVENT_FLAG_HDR_SDR_RATIO_CHANGED, + PRIVATE_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface PrivateEventFlag {} + + /** * Event type for when a new display is added. * * @see #registerDisplayListener(DisplayListener, Handler, long) @@ -618,7 +626,7 @@ public final class DisplayManager { * * @hide */ - public static final long EVENT_FLAG_DISPLAY_BRIGHTNESS = 1L << 3; + public static final long PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS = 1L << 0; /** * Event flag to register for a display's hdr/sdr ratio changes. This notification is sent @@ -631,14 +639,16 @@ public final class DisplayManager { * * @hide */ - public static final long EVENT_FLAG_HDR_SDR_RATIO_CHANGED = 1L << 4; + public static final long PRIVATE_EVENT_FLAG_HDR_SDR_RATIO_CHANGED = 1L << 1; /** * Event flag to register for a display's connection changed. * + * @see #registerDisplayListener(DisplayListener, Handler, long) * @hide */ - public static final long EVENT_FLAG_DISPLAY_CONNECTION_CHANGED = 1L << 5; + public static final long PRIVATE_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED = 1L << 2; + /** @hide */ public DisplayManager(Context context) { @@ -774,20 +784,49 @@ public final class DisplayManager { * @param listener The listener to register. * @param handler The handler on which the listener should be invoked, or null * if the listener should be invoked on the calling thread's looper. - * @param eventFlagsMask A bitmask of the event types for which this listener is subscribed. + * @param eventFlags A bitmask of the event types for which this listener is subscribed. + * + * @see #EVENT_FLAG_DISPLAY_ADDED + * @see #EVENT_FLAG_DISPLAY_CHANGED + * @see #EVENT_FLAG_DISPLAY_REMOVED + * @see #registerDisplayListener(DisplayListener, Handler) + * @see #unregisterDisplayListener + * + * @hide + */ + public void registerDisplayListener(@NonNull DisplayListener listener, + @Nullable Handler handler, @EventFlag long eventFlags) { + mGlobal.registerDisplayListener(listener, handler, + mGlobal.mapFlagsToInternalEventFlag(eventFlags, 0), + ActivityThread.currentPackageName()); + } + + /** + * Registers a display listener to receive notifications about given display event types. + * + * @param listener The listener to register. + * @param handler The handler on which the listener should be invoked, or null + * if the listener should be invoked on the calling thread's looper. + * @param eventFlags A bitmask of the event types for which this listener is subscribed. + * @param privateEventFlags A bitmask of the private event types for which this listener + * is subscribed. * * @see #EVENT_FLAG_DISPLAY_ADDED * @see #EVENT_FLAG_DISPLAY_CHANGED * @see #EVENT_FLAG_DISPLAY_REMOVED - * @see #EVENT_FLAG_DISPLAY_BRIGHTNESS + * @see #PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS + * @see #PRIVATE_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED + * @see #PRIVATE_EVENT_FLAG_HDR_SDR_RATIO_CHANGED * @see #registerDisplayListener(DisplayListener, Handler) * @see #unregisterDisplayListener * * @hide */ public void registerDisplayListener(@NonNull DisplayListener listener, - @Nullable Handler handler, @EventFlag long eventFlagsMask) { - mGlobal.registerDisplayListener(listener, handler, eventFlagsMask, + @Nullable Handler handler, @EventFlag long eventFlags, + @PrivateEventFlag long privateEventFlags) { + mGlobal.registerDisplayListener(listener, handler, + mGlobal.mapFlagsToInternalEventFlag(eventFlags, privateEventFlags), ActivityThread.currentPackageName()); } diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java index 56307ae53a0c..644850a5c2e1 100644 --- a/core/java/android/hardware/display/DisplayManagerGlobal.java +++ b/core/java/android/hardware/display/DisplayManagerGlobal.java @@ -24,6 +24,7 @@ import android.Manifest; import android.annotation.FlaggedApi; import android.annotation.FloatRange; import android.annotation.IntDef; +import android.annotation.LongDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -118,6 +119,24 @@ public final class DisplayManagerGlobal { public static final int EVENT_DISPLAY_CONNECTED = 6; public static final int EVENT_DISPLAY_DISCONNECTED = 7; + @LongDef(prefix = {"INTERNAL_EVENT_DISPLAY"}, flag = true, value = { + INTERNAL_EVENT_FLAG_DISPLAY_ADDED, + INTERNAL_EVENT_FLAG_DISPLAY_CHANGED, + INTERNAL_EVENT_FLAG_DISPLAY_REMOVED, + INTERNAL_EVENT_FLAG_DISPLAY_BRIGHTNESS_CHANGED, + INTERNAL_EVENT_FLAG_DISPLAY_HDR_SDR_RATIO_CHANGED, + INTERNAL_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface InternalEventFlag {} + + public static final long INTERNAL_EVENT_FLAG_DISPLAY_ADDED = 1L << 0; + public static final long INTERNAL_EVENT_FLAG_DISPLAY_CHANGED = 1L << 1; + public static final long INTERNAL_EVENT_FLAG_DISPLAY_REMOVED = 1L << 2; + public static final long INTERNAL_EVENT_FLAG_DISPLAY_BRIGHTNESS_CHANGED = 1L << 3; + public static final long INTERNAL_EVENT_FLAG_DISPLAY_HDR_SDR_RATIO_CHANGED = 1L << 4; + public static final long INTERNAL_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED = 1L << 5; + @UnsupportedAppUsage private static DisplayManagerGlobal sInstance; @@ -130,7 +149,7 @@ public final class DisplayManagerGlobal { private final IDisplayManager mDm; private DisplayManagerCallback mCallback; - private @EventFlag long mRegisteredEventFlagsMask = 0; + private @InternalEventFlag long mRegisteredInternalEventFlag = 0; private final CopyOnWriteArrayList<DisplayListenerDelegate> mDisplayListeners = new CopyOnWriteArrayList<>(); @@ -346,11 +365,11 @@ public final class DisplayManagerGlobal { * @param packageName of the calling package. */ public void registerDisplayListener(@NonNull DisplayListener listener, - @Nullable Handler handler, @EventFlag long eventFlagsMask, + @Nullable Handler handler, @InternalEventFlag long internalEventFlagsMask, String packageName) { Looper looper = getLooperForHandler(handler); Handler springBoard = new Handler(looper); - registerDisplayListener(listener, new HandlerExecutor(springBoard), eventFlagsMask, + registerDisplayListener(listener, new HandlerExecutor(springBoard), internalEventFlagsMask, packageName); } @@ -359,32 +378,34 @@ public final class DisplayManagerGlobal { * * @param listener The listener that will be called when display changes occur. * @param executor Executor for the thread that will be receiving the callbacks. Cannot be null. - * @param eventFlagsMask Flag of events to be listened to. + * @param internalEventFlagsMask Mask of events to be listened to. * @param packageName of the calling package. */ public void registerDisplayListener(@NonNull DisplayListener listener, - @NonNull Executor executor, @EventFlag long eventFlagsMask, String packageName) { + @NonNull Executor executor, @InternalEventFlag long internalEventFlagsMask, + String packageName) { if (listener == null) { throw new IllegalArgumentException("listener must not be null"); } - if (eventFlagsMask == 0) { + if (internalEventFlagsMask == 0) { throw new IllegalArgumentException("The set of events to listen to must not be empty."); } if (extraLogging()) { Slog.i(TAG, "Registering Display Listener: " - + Long.toBinaryString(eventFlagsMask) + ", packageName: " + packageName); + + Long.toBinaryString(internalEventFlagsMask) + + ", packageName: " + packageName); } synchronized (mLock) { int index = findDisplayListenerLocked(listener); if (index < 0) { mDisplayListeners.add(new DisplayListenerDelegate(listener, executor, - eventFlagsMask, packageName)); + internalEventFlagsMask, packageName)); registerCallbackIfNeededLocked(); } else { - mDisplayListeners.get(index).setEventFlagsMask(eventFlagsMask); + mDisplayListeners.get(index).setEventsMask(internalEventFlagsMask); } updateCallbackIfNeededLocked(); maybeLogAllDisplayListeners(); @@ -456,17 +477,17 @@ public final class DisplayManagerGlobal { return -1; } - @EventFlag - private int calculateEventFlagsMaskLocked() { - int mask = 0; + @InternalEventFlag + private long calculateEventsMaskLocked() { + long mask = 0; final int numListeners = mDisplayListeners.size(); for (int i = 0; i < numListeners; i++) { - mask |= mDisplayListeners.get(i).mEventFlagsMask; + mask |= mDisplayListeners.get(i).mInternalEventFlagsMask; } if (mDispatchNativeCallbacks) { - mask |= DisplayManager.EVENT_FLAG_DISPLAY_ADDED - | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED - | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED; + mask |= INTERNAL_EVENT_FLAG_DISPLAY_ADDED + | INTERNAL_EVENT_FLAG_DISPLAY_CHANGED + | INTERNAL_EVENT_FLAG_DISPLAY_REMOVED; } return mask; } @@ -479,14 +500,14 @@ public final class DisplayManagerGlobal { } private void updateCallbackIfNeededLocked() { - int mask = calculateEventFlagsMaskLocked(); + long mask = calculateEventsMaskLocked(); if (DEBUG) { - Log.d(TAG, "Flag for listener: " + mask); + Log.d(TAG, "Mask for listener: " + mask); } - if (mask != mRegisteredEventFlagsMask) { + if (mask != mRegisteredInternalEventFlag) { try { mDm.registerCallbackWithEventMask(mCallback, mask); - mRegisteredEventFlagsMask = mask; + mRegisteredInternalEventFlag = mask; } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } @@ -1268,8 +1289,8 @@ public final class DisplayManagerGlobal { @Override public void onDisplayEvent(int displayId, @DisplayEvent int event) { if (DEBUG) { - Log.d(TAG, "onDisplayEvent: displayId=" + displayId + ", event=" + eventToString( - event)); + Log.d(TAG, "onDisplayEvent: displayId=" + displayId + ", event=" + + eventToString(event)); } handleDisplayEvent(displayId, event, false /* forceUpdate */); } @@ -1277,7 +1298,7 @@ public final class DisplayManagerGlobal { private static final class DisplayListenerDelegate { public final DisplayListener mListener; - public volatile long mEventFlagsMask; + public volatile long mInternalEventFlagsMask; private final DisplayInfo mDisplayInfo = new DisplayInfo(); private final Executor mExecutor; @@ -1285,10 +1306,10 @@ public final class DisplayManagerGlobal { private final String mPackageName; DisplayListenerDelegate(DisplayListener listener, @NonNull Executor executor, - @EventFlag long eventFlag, String packageName) { + @InternalEventFlag long internalEventFlag, String packageName) { mExecutor = executor; mListener = listener; - mEventFlagsMask = eventFlag; + mInternalEventFlagsMask = internalEventFlag; mPackageName = packageName; } @@ -1310,16 +1331,16 @@ public final class DisplayManagerGlobal { mGenerationId.incrementAndGet(); } - void setEventFlagsMask(@EventFlag long newEventsFlag) { - mEventFlagsMask = newEventsFlag; + void setEventsMask(@InternalEventFlag long newInternalEventFlagsMask) { + mInternalEventFlagsMask = newInternalEventFlagsMask; } - private void handleDisplayEventInner(int displayId, @DisplayEvent int eventFlagsMask, + private void handleDisplayEventInner(int displayId, @DisplayEvent int event, @Nullable DisplayInfo info, boolean forceUpdate) { if (extraLogging()) { - Slog.i(TAG, "DLD(" + eventToString(eventFlagsMask) + Slog.i(TAG, "DLD(" + eventToString(event) + ", display=" + displayId - + ", mEventsFlagMask=" + Long.toBinaryString(mEventFlagsMask) + + ", mEventsMask=" + Long.toBinaryString(mInternalEventFlagsMask) + ", mPackageName=" + mPackageName + ", displayInfo=" + info + ", listener=" + mListener.getClass() + ")"); @@ -1327,18 +1348,19 @@ public final class DisplayManagerGlobal { if (DEBUG) { Trace.beginSection( TextUtils.trimToSize( - "DLD(" + eventToString(eventFlagsMask) + "DLD(" + eventToString(event) + ", display=" + displayId + ", listener=" + mListener.getClass() + ")", 127)); } - switch (eventFlagsMask) { + switch (event) { case EVENT_DISPLAY_ADDED: - if ((mEventFlagsMask & DisplayManager.EVENT_FLAG_DISPLAY_ADDED) != 0) { + if ((mInternalEventFlagsMask & INTERNAL_EVENT_FLAG_DISPLAY_ADDED) != 0) { mListener.onDisplayAdded(displayId); } break; case EVENT_DISPLAY_CHANGED: - if ((mEventFlagsMask & DisplayManager.EVENT_FLAG_DISPLAY_CHANGED) != 0) { + if ((mInternalEventFlagsMask & INTERNAL_EVENT_FLAG_DISPLAY_CHANGED) + != 0) { if (info != null && (forceUpdate || !info.equals(mDisplayInfo))) { if (extraLogging()) { Slog.i(TAG, "Sending onDisplayChanged: Display Changed. Info: " @@ -1350,29 +1372,32 @@ public final class DisplayManagerGlobal { } break; case EVENT_DISPLAY_BRIGHTNESS_CHANGED: - if ((mEventFlagsMask & DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS) != 0) { + if ((mInternalEventFlagsMask + & INTERNAL_EVENT_FLAG_DISPLAY_BRIGHTNESS_CHANGED) != 0) { mListener.onDisplayChanged(displayId); } break; case EVENT_DISPLAY_REMOVED: - if ((mEventFlagsMask & DisplayManager.EVENT_FLAG_DISPLAY_REMOVED) != 0) { + if ((mInternalEventFlagsMask & INTERNAL_EVENT_FLAG_DISPLAY_REMOVED) + != 0) { mListener.onDisplayRemoved(displayId); } break; case EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED: - if ((mEventFlagsMask & DisplayManager.EVENT_FLAG_HDR_SDR_RATIO_CHANGED) != 0) { + if ((mInternalEventFlagsMask + & INTERNAL_EVENT_FLAG_DISPLAY_HDR_SDR_RATIO_CHANGED) != 0) { mListener.onDisplayChanged(displayId); } break; case EVENT_DISPLAY_CONNECTED: - if ((mEventFlagsMask & DisplayManager.EVENT_FLAG_DISPLAY_CONNECTION_CHANGED) - != 0) { + if ((mInternalEventFlagsMask + & INTERNAL_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED) != 0) { mListener.onDisplayConnected(displayId); } break; case EVENT_DISPLAY_DISCONNECTED: - if ((mEventFlagsMask & DisplayManager.EVENT_FLAG_DISPLAY_CONNECTION_CHANGED) - != 0) { + if ((mInternalEventFlagsMask + & INTERNAL_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED) != 0) { mListener.onDisplayDisconnected(displayId); } break; @@ -1384,7 +1409,7 @@ public final class DisplayManagerGlobal { @Override public String toString() { - return "mEventFlagsMask: {" + mEventFlagsMask + "}, for " + mListener.getClass(); + return "flag: {" + mInternalEventFlagsMask + "}, for " + mListener.getClass(); } } @@ -1532,4 +1557,53 @@ public final class DisplayManagerGlobal { private static boolean extraLogging() { return sExtraDisplayListenerLogging; } + + + /** + * Maps the supplied public and private event flags to a unified InternalEventFlag + * @param eventFlags A bitmask of the event types for which this listener is subscribed. + * @param privateEventFlags A bitmask of the private event types for which this listener + * is subscribed. + * @return returns the bitmask of both public and private event flags unified to + * InternalEventFlag + */ + public @InternalEventFlag long mapFlagsToInternalEventFlag(@EventFlag long eventFlags, + @DisplayManager.PrivateEventFlag long privateEventFlags) { + return mapPrivateEventFlags(privateEventFlags) | mapPublicEventFlags(eventFlags); + } + + private long mapPrivateEventFlags(@DisplayManager.PrivateEventFlag long privateEventFlags) { + long baseEventMask = 0; + if ((privateEventFlags & DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS) != 0) { + baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_BRIGHTNESS_CHANGED; + } + + if ((privateEventFlags & DisplayManager.PRIVATE_EVENT_FLAG_HDR_SDR_RATIO_CHANGED) != 0) { + baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_HDR_SDR_RATIO_CHANGED; + } + + if ((privateEventFlags + & DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED) != 0) { + baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED; + } + return baseEventMask; + } + + private long mapPublicEventFlags(@EventFlag long eventFlags) { + long baseEventMask = 0; + if ((eventFlags & DisplayManager.EVENT_FLAG_DISPLAY_ADDED) != 0) { + baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_ADDED; + } + + if ((eventFlags & DisplayManager.EVENT_FLAG_DISPLAY_CHANGED) != 0) { + baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_CHANGED; + } + + if ((eventFlags + & DisplayManager.EVENT_FLAG_DISPLAY_REMOVED) != 0) { + baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_REMOVED; + } + + return baseEventMask; + } } diff --git a/core/java/android/net/vcn/flags.aconfig b/core/java/android/net/vcn/flags.aconfig index 1adefe5a0b86..1b2c575917b2 100644 --- a/core/java/android/net/vcn/flags.aconfig +++ b/core/java/android/net/vcn/flags.aconfig @@ -18,13 +18,6 @@ flag { } flag { - name: "safe_mode_timeout_config" - namespace: "vcn" - description: "Feature flag for adjustable safe mode timeout" - bug: "317406085" -} - -flag { name: "fix_config_garbage_collection" namespace: "vcn" description: "Handle race condition in subscription change" diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index 910e644f7b6f..0241e9437950 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -1549,8 +1549,9 @@ public final class Display { // Although we only care about the HDR/SDR ratio changing, that can also come in the // form of the larger DISPLAY_CHANGED event mGlobal.registerDisplayListener(toRegister, executor, - DisplayManager.EVENT_FLAG_HDR_SDR_RATIO_CHANGED - | DisplayManagerGlobal.EVENT_DISPLAY_CHANGED, + DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CHANGED + | DisplayManagerGlobal + .INTERNAL_EVENT_FLAG_DISPLAY_HDR_SDR_RATIO_CHANGED, ActivityThread.currentPackageName()); } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 3ce6870bf2ca..9a2aa0b8a682 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -185,7 +185,6 @@ import android.graphics.RenderNode; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.hardware.SyncFence; -import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager.DisplayListener; import android.hardware.display.DisplayManagerGlobal; import android.hardware.input.InputManagerGlobal; @@ -1816,9 +1815,9 @@ public final class ViewRootImpl implements ViewParent, .registerDisplayListener( mDisplayListener, mHandler, - DisplayManager.EVENT_FLAG_DISPLAY_ADDED - | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED - | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED, + DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED + | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CHANGED + | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REMOVED, mBasePackageName); if (forceInvertColor()) { diff --git a/core/java/android/window/BackProgressAnimator.java b/core/java/android/window/BackProgressAnimator.java index a5be58b7b183..16eb43700aef 100644 --- a/core/java/android/window/BackProgressAnimator.java +++ b/core/java/android/window/BackProgressAnimator.java @@ -16,8 +16,11 @@ package android.window; +import static android.window.BackEvent.EDGE_NONE; + import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; import static com.android.window.flags.Flags.predictiveBackTimestampApi; +import static com.android.window.flags.Flags.predictiveBackSwipeEdgeNoneApi; import android.annotation.NonNull; import android.annotation.Nullable; @@ -60,6 +63,12 @@ public class BackProgressAnimator implements DynamicAnimation.OnAnimationUpdateL @Nullable private Runnable mBackInvokedFinishRunnable; private FlingAnimation mBackInvokedFlingAnim; + private final SpringForce mGestureSpringForce = new SpringForce() + .setStiffness(SpringForce.STIFFNESS_MEDIUM) + .setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY); + private final SpringForce mButtonSpringForce = new SpringForce() + .setStiffness(500) + .setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY); private final DynamicAnimation.OnAnimationEndListener mOnAnimationEndListener = (animation, canceled, value, velocity) -> { if (mBackCancelledFinishRunnable != null) invokeBackCancelledRunnable(); @@ -109,9 +118,7 @@ public class BackProgressAnimator implements DynamicAnimation.OnAnimationUpdateL public BackProgressAnimator() { mSpring = new SpringAnimation(this, PROGRESS_PROP); mSpring.addUpdateListener(this); - mSpring.setSpring(new SpringForce() - .setStiffness(SpringForce.STIFFNESS_MEDIUM) - .setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY)); + mSpring.setSpring(mGestureSpringForce); } /** @@ -123,6 +130,11 @@ public class BackProgressAnimator implements DynamicAnimation.OnAnimationUpdateL if (!mBackAnimationInProgress) { return; } + if (predictiveBackSwipeEdgeNoneApi()) { + if (event.getSwipeEdge() == EDGE_NONE) { + return; + } + } mLastBackEvent = event; if (mSpring == null) { return; @@ -143,7 +155,17 @@ public class BackProgressAnimator implements DynamicAnimation.OnAnimationUpdateL mBackAnimationInProgress = true; updateProgressValue(/* progress */ 0, /* velocity */ 0, /* frameTime */ System.nanoTime() / TimeUtils.NANOS_PER_MS); - onBackProgressed(event); + if (predictiveBackSwipeEdgeNoneApi()) { + if (event.getSwipeEdge() == EDGE_NONE) { + mSpring.setSpring(mButtonSpringForce); + mSpring.animateToFinalPosition(SCALE_FACTOR); + } else { + mSpring.setSpring(mGestureSpringForce); + onBackProgressed(event); + } + } else { + onBackProgressed(event); + } } /** diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig index 11f68496fa90..9845bf00d937 100644 --- a/core/java/android/window/flags/windowing_frontend.aconfig +++ b/core/java/android/window/flags/windowing_frontend.aconfig @@ -388,4 +388,11 @@ flag { description: "Provide pre-make predictive back API extension" is_fixed_read_only: true bug: "362938401" -}
\ No newline at end of file +} + +flag { + name: "predictive_back_three_button_nav" + namespace: "systemui" + description: "Enable Predictive Back Animation for 3-button-nav" + bug: "373544911" +} diff --git a/core/java/com/android/internal/display/BrightnessSynchronizer.java b/core/java/com/android/internal/display/BrightnessSynchronizer.java index 21fbf9d03c71..a50dbb0223b7 100644 --- a/core/java/com/android/internal/display/BrightnessSynchronizer.java +++ b/core/java/com/android/internal/display/BrightnessSynchronizer.java @@ -600,8 +600,8 @@ public class BrightnessSynchronizer { final ContentResolver cr = mContext.getContentResolver(); cr.registerContentObserver(BRIGHTNESS_URI, false, createBrightnessContentObserver(handler), UserHandle.USER_ALL); - mDisplayManager.registerDisplayListener(mListener, handler, - DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS); + mDisplayManager.registerDisplayListener(mListener, handler, /* eventFlags */ 0, + DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS); mIsObserving = true; } } diff --git a/core/java/com/android/internal/jank/DisplayResolutionTracker.java b/core/java/com/android/internal/jank/DisplayResolutionTracker.java index ca6c54dc0285..0c2fd4bbd7ae 100644 --- a/core/java/com/android/internal/jank/DisplayResolutionTracker.java +++ b/core/java/com/android/internal/jank/DisplayResolutionTracker.java @@ -147,8 +147,9 @@ public class DisplayResolutionTracker { @Override public void registerDisplayListener(DisplayManager.DisplayListener listener) { manager.registerDisplayListener(listener, handler, - DisplayManager.EVENT_FLAG_DISPLAY_ADDED - | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED, + DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED + | DisplayManagerGlobal + .INTERNAL_EVENT_FLAG_DISPLAY_CHANGED, ActivityThread.currentPackageName()); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java b/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java index 212df02b1bd3..0761a244b9f2 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java +++ b/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java @@ -15,12 +15,14 @@ */ package com.android.internal.widget.remotecompose.core; +import android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.operations.ComponentValue; import com.android.internal.widget.remotecompose.core.operations.IntegerExpression; import com.android.internal.widget.remotecompose.core.operations.NamedVariable; import com.android.internal.widget.remotecompose.core.operations.RootContentBehavior; import com.android.internal.widget.remotecompose.core.operations.Theme; -import com.android.internal.widget.remotecompose.core.operations.layout.ClickModifierEnd; import com.android.internal.widget.remotecompose.core.operations.layout.ClickModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.Component; import com.android.internal.widget.remotecompose.core.operations.layout.ComponentEnd; @@ -28,7 +30,11 @@ import com.android.internal.widget.remotecompose.core.operations.layout.Componen import com.android.internal.widget.remotecompose.core.operations.layout.LayoutComponent; import com.android.internal.widget.remotecompose.core.operations.layout.LoopEnd; import com.android.internal.widget.remotecompose.core.operations.layout.LoopOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.OperationsListEnd; import com.android.internal.widget.remotecompose.core.operations.layout.RootLayoutComponent; +import com.android.internal.widget.remotecompose.core.operations.layout.TouchCancelModifierOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.TouchDownModifierOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.TouchUpModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ComponentModifiers; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ModifierOperation; import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; @@ -49,12 +55,12 @@ public class CoreDocument { ArrayList<Operation> mOperations; - RootLayoutComponent mRootLayoutComponent = null; + @Nullable RootLayoutComponent mRootLayoutComponent = null; RemoteComposeState mRemoteComposeState = new RemoteComposeState(); - TimeVariables mTimeVariables = new TimeVariables(); + @NonNull TimeVariables mTimeVariables = new TimeVariables(); // Semantic version of the document - Version mVersion = new Version(0, 1, 0); + @NonNull Version mVersion = new Version(0, 1, 0); String mContentDescription; // text description of the document (used for accessibility) @@ -72,6 +78,8 @@ public class CoreDocument { private final HashMap<Long, IntegerExpression> mIntegerExpressions = new HashMap<>(); + private HashSet<Component> mAppliedTouchOperations = new HashSet<>(); + private int mLastId = 1; // last component id when inflating the file public String getContentDescription() { @@ -272,6 +280,7 @@ public class CoreDocument { * * @return list of click areas in document coordinates */ + @NonNull public Set<ClickAreaRepresentation> getClickAreas() { return mClickAreas; } @@ -281,6 +290,7 @@ public class CoreDocument { * * @return returns the root component if it exists, null otherwise */ + @Nullable public RootLayoutComponent getRootLayoutComponent() { return mRootLayoutComponent; } @@ -298,6 +308,7 @@ public class CoreDocument { * @param id component id * @return the component if it exists, null otherwise */ + @Nullable public Component getComponent(int id) { if (mRootLayoutComponent != null) { return mRootLayoutComponent.getComponent(id); @@ -310,6 +321,7 @@ public class CoreDocument { * * @return a standardized string representation of the component hierarchy */ + @NonNull public String displayHierarchy() { StringSerializer serializer = new StringSerializer(); for (Operation op : mOperations) { @@ -329,7 +341,8 @@ public class CoreDocument { * @param targetId the id of the value to update with the expression * @param context the current context */ - public void evaluateIntExpression(long expressionId, int targetId, RemoteContext context) { + public void evaluateIntExpression( + long expressionId, int targetId, @NonNull RemoteContext context) { IntegerExpression expression = mIntegerExpressions.get(expressionId); if (expression != null) { int v = expression.evaluate(context); @@ -337,22 +350,46 @@ public class CoreDocument { } } + // ============== Haptic support ================== + public interface HapticEngine { + void haptic(int type); + } + + HapticEngine mHapticEngine; + + public void setHapticEngine(HapticEngine engine) { + mHapticEngine = engine; + } + + public void haptic(int type) { + if (mHapticEngine != null) { + mHapticEngine.haptic(type); + } + } + + // ============== Haptic support ================== + + public void appliedTouchOperation(Component operation) { + mAppliedTouchOperations.add(operation); + } + /** Callback interface for host actions */ public interface ActionCallback { - // TODO: add payload support - void onAction(String name); + void onAction(String name, Object value); } - HashSet<ActionCallback> mActionListeners = new HashSet<ActionCallback>(); + @NonNull HashSet<ActionCallback> mActionListeners = new HashSet<ActionCallback>(); /** * Warn action listeners for the given named action * * @param name the action name + * @param value a parameter to the action */ - public void runNamedAction(String name) { + public void runNamedAction(String name, Object value) { + // TODO: we might add an interface to group all valid parameter types for (ActionCallback callback : mActionListeners) { - callback.onAction(name); + callback.onAction(name, value); } } @@ -374,8 +411,9 @@ public class CoreDocument { void click(int id, String metadata); } - HashSet<ClickCallbacks> mClickListeners = new HashSet<>(); - HashSet<ClickAreaRepresentation> mClickAreas = new HashSet<>(); + @NonNull HashSet<ClickCallbacks> mClickListeners = new HashSet<>(); + @NonNull HashSet<TouchListener> mTouchListeners = new HashSet<>(); + @NonNull HashSet<ClickAreaRepresentation> mClickAreas = new HashSet<>(); static class Version { public final int major; @@ -456,7 +494,7 @@ public class CoreDocument { } /** Load operations from the given buffer */ - public void initFromBuffer(RemoteComposeBuffer buffer) { + public void initFromBuffer(@NonNull RemoteComposeBuffer buffer) { mOperations = new ArrayList<Operation>(); buffer.inflateFromBuffer(mOperations); for (Operation op : mOperations) { @@ -484,12 +522,16 @@ public class CoreDocument { * @param operations flat list of operations * @return nested list of operations / components */ - private ArrayList<Operation> inflateComponents(ArrayList<Operation> operations) { + @NonNull + private ArrayList<Operation> inflateComponents(@NonNull ArrayList<Operation> operations) { Component currentComponent = null; ArrayList<Component> components = new ArrayList<>(); ArrayList<Operation> finalOperationsList = new ArrayList<>(); ArrayList<Operation> ops = finalOperationsList; ClickModifierOperation currentClickModifier = null; + TouchDownModifierOperation currentTouchDownModifier = null; + TouchUpModifierOperation currentTouchUpModifier = null; + TouchCancelModifierOperation currentTouchCancelModifier = null; LoopOperation currentLoop = null; mLastId = -1; @@ -519,10 +561,30 @@ public class CoreDocument { // TODO: refactor to add container <- component... currentClickModifier = (ClickModifierOperation) o; ops = currentClickModifier.getList(); - } else if (o instanceof ClickModifierEnd) { + } else if (o instanceof TouchDownModifierOperation) { + currentTouchDownModifier = (TouchDownModifierOperation) o; + ops = currentTouchDownModifier.getList(); + } else if (o instanceof TouchUpModifierOperation) { + currentTouchUpModifier = (TouchUpModifierOperation) o; + ops = currentTouchUpModifier.getList(); + } else if (o instanceof TouchCancelModifierOperation) { + currentTouchCancelModifier = (TouchCancelModifierOperation) o; + ops = currentTouchCancelModifier.getList(); + } else if (o instanceof OperationsListEnd) { ops = currentComponent.getList(); - ops.add(currentClickModifier); - currentClickModifier = null; + if (currentClickModifier != null) { + ops.add(currentClickModifier); + currentClickModifier = null; + } else if (currentTouchDownModifier != null) { + ops.add(currentTouchDownModifier); + currentTouchDownModifier = null; + } else if (currentTouchUpModifier != null) { + ops.add(currentTouchUpModifier); + currentTouchUpModifier = null; + } else if (currentTouchCancelModifier != null) { + ops.add(currentTouchCancelModifier); + currentTouchCancelModifier = null; + } } else if (o instanceof LoopOperation) { currentLoop = (LoopOperation) o; ops = currentLoop.getList(); @@ -541,9 +603,9 @@ public class CoreDocument { return ops; } - private HashMap<Integer, Component> mComponentMap = new HashMap<Integer, Component>(); + @NonNull private HashMap<Integer, Component> mComponentMap = new HashMap<Integer, Component>(); - private void registerVariables(RemoteContext context, ArrayList<Operation> list) { + private void registerVariables(RemoteContext context, @NonNull ArrayList<Operation> list) { for (Operation op : list) { if (op instanceof VariableSupport) { ((VariableSupport) op).updateVariables(context); @@ -578,7 +640,7 @@ public class CoreDocument { * Called when an initialization is needed, allowing the document to eg load resources / cache * them. */ - public void initializeContext(RemoteContext context) { + public void initializeContext(@NonNull RemoteContext context) { mRemoteComposeState.reset(); mRemoteComposeState.setContext(context); mClickAreas.clear(); @@ -651,6 +713,15 @@ public class CoreDocument { } /** + * Called by commands to listen to touch events + * + * @param listener + */ + public void addTouchListener(TouchListener listener) { + mTouchListeners.add(listener); + } + + /** * Add a click listener. This will get called when a click is detected on the document * * @param callback called when a click area has been hit, passing the click are id and metadata. @@ -664,6 +735,7 @@ public class CoreDocument { * * @return set of click listeners */ + @NonNull public HashSet<CoreDocument.ClickCallbacks> getClickListeners() { return mClickListeners; } @@ -700,12 +772,98 @@ public class CoreDocument { } /** Warn click listeners when a click area is activated */ - private void warnClickListeners(ClickAreaRepresentation clickArea) { + private void warnClickListeners(@NonNull ClickAreaRepresentation clickArea) { for (ClickCallbacks listener : mClickListeners) { listener.click(clickArea.mId, clickArea.mMetadata); } } + /** + * Returns true if the document has touch listeners + * + * @return true if the document needs to react to touch events + */ + public boolean hasTouchListener() { + boolean hasComponentsTouchListeners = + mRootLayoutComponent != null && mRootLayoutComponent.hasTouchListeners(); + return hasComponentsTouchListeners || !mTouchListeners.isEmpty(); + } + + // TODO support velocity estimate support, support regions + /** + * Support touch drag events on commands supporting touch + * + * @param x position of touch + * @param y position of touch + */ + public boolean touchDrag(RemoteContext context, float x, float y) { + context.loadFloat(RemoteContext.ID_TOUCH_POS_X, x); + context.loadFloat(RemoteContext.ID_TOUCH_POS_Y, y); + for (TouchListener clickArea : mTouchListeners) { + clickArea.touchDrag(context, x, y); + } + if (!mTouchListeners.isEmpty()) { + return true; + } + return false; + } + + /** + * Support touch down events on commands supporting touch + * + * @param x position of touch + * @param y position of touch + */ + public void touchDown(RemoteContext context, float x, float y) { + context.loadFloat(RemoteContext.ID_TOUCH_POS_X, x); + context.loadFloat(RemoteContext.ID_TOUCH_POS_Y, y); + for (TouchListener clickArea : mTouchListeners) { + clickArea.touchDown(context, x, y); + } + if (mRootLayoutComponent != null) { + mRootLayoutComponent.onTouchDown(context, this, x, y); + } + mRepaintNext = 1; + } + + /** + * Support touch up events on commands supporting touch + * + * @param x position of touch + * @param y position of touch + */ + public void touchUp(RemoteContext context, float x, float y, float dx, float dy) { + context.loadFloat(RemoteContext.ID_TOUCH_POS_X, x); + context.loadFloat(RemoteContext.ID_TOUCH_POS_Y, y); + for (TouchListener clickArea : mTouchListeners) { + clickArea.touchUp(context, x, y, dx, dy); + } + if (mRootLayoutComponent != null) { + for (Component component : mAppliedTouchOperations) { + component.onTouchUp(context, this, x, y, true); + } + mAppliedTouchOperations.clear(); + } + mRepaintNext = 1; + } + + /** + * Support touch cancel events on commands supporting touch + * + * @param x position of touch + * @param y position of touch + */ + public void touchCancel(RemoteContext context, float x, float y, float dx, float dy) { + if (mRootLayoutComponent != null) { + for (Component component : mAppliedTouchOperations) { + component.onTouchCancel(context, this, x, y, true); + } + mAppliedTouchOperations.clear(); + } + mRepaintNext = 1; + } + + @NonNull @Override public String toString() { StringBuilder builder = new StringBuilder(); @@ -721,12 +879,22 @@ public class CoreDocument { * * @return array of named colors or null */ + @Nullable public String[] getNamedColors() { + return getNamedVariables(NamedVariable.COLOR_TYPE); + } + + /** + * Gets the names of all named Variables. + * + * @return array of named variables or null + */ + public String[] getNamedVariables(int type) { int count = 0; for (Operation op : mOperations) { if (op instanceof NamedVariable) { NamedVariable n = (NamedVariable) op; - if (n.mVarType == NamedVariable.COLOR_TYPE) { + if (n.mVarType == type) { count++; } } @@ -739,7 +907,7 @@ public class CoreDocument { for (Operation op : mOperations) { if (op instanceof NamedVariable) { NamedVariable n = (NamedVariable) op; - if (n.mVarType == NamedVariable.COLOR_TYPE) { + if (n.mVarType == type) { ret[i++] = n.mVarName; } } @@ -770,10 +938,9 @@ public class CoreDocument { * @param context the provided PaintContext * @param theme the theme we want to use for this document. */ - public void paint(RemoteContext context, int theme) { + public void paint(@NonNull RemoteContext context, int theme) { context.getPaintContext().clearNeedsRepaint(); context.mMode = RemoteContext.ContextMode.UNSET; - // current theme starts as UNSPECIFIED, until a Theme setter // operation gets executed and modify it. context.setTheme(Theme.UNSPECIFIED); @@ -807,6 +974,7 @@ public class CoreDocument { } // TODO -- this should be specifically about applying animation, not paint mRootLayoutComponent.paint(context.getPaintContext()); + context.mPaintContext.reset(); // TODO -- should be able to remove this mRootLayoutComponent.updateVariables(context); if (DEBUG) { @@ -843,6 +1011,7 @@ public class CoreDocument { } } + @NonNull public String[] getStats() { ArrayList<String> ret = new ArrayList<>(); WireBuffer buffer = new WireBuffer(); @@ -875,7 +1044,7 @@ public class CoreDocument { return ret.toArray(new String[0]); } - private int sizeOfComponent(Operation com, WireBuffer tmp) { + private int sizeOfComponent(@NonNull Operation com, @NonNull WireBuffer tmp) { tmp.reset(100); com.write(tmp); int size = tmp.getSize(); @@ -883,7 +1052,8 @@ public class CoreDocument { return size; } - private int addChildren(Component base, HashMap<String, int[]> map, WireBuffer tmp) { + private int addChildren( + @NonNull Component base, @NonNull HashMap<String, int[]> map, @NonNull WireBuffer tmp) { int count = base.mList.size(); for (Operation mOperation : base.mList) { Class<? extends Operation> c = mOperation.getClass(); @@ -903,6 +1073,7 @@ public class CoreDocument { return count; } + @NonNull public String toNestedString() { StringBuilder ret = new StringBuilder(); for (Operation mOperation : mOperations) { @@ -915,7 +1086,8 @@ public class CoreDocument { return ret.toString(); } - private void toNestedString(Component base, StringBuilder ret, String indent) { + private void toNestedString( + @NonNull Component base, @NonNull StringBuilder ret, String indent) { for (Operation mOperation : base.mList) { ret.append(mOperation.toString()); ret.append("\n"); diff --git a/core/java/com/android/internal/widget/remotecompose/core/Operation.java b/core/java/com/android/internal/widget/remotecompose/core/Operation.java index 9f565a2915fb..f1885f942ee1 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/Operation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/Operation.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core; +import android.annotation.Nullable; + /** Base interface for RemoteCompose operations */ public interface Operation { @@ -29,5 +31,6 @@ public interface Operation { void apply(RemoteContext context); /** Debug utility to display an operation + indentation */ + @Nullable String deepToString(String indent); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/Operations.java b/core/java/com/android/internal/widget/remotecompose/core/Operations.java index acebe0761b79..53c45fac826c 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/Operations.java +++ b/core/java/com/android/internal/widget/remotecompose/core/Operations.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.operations.BitmapData; import com.android.internal.widget.remotecompose.core.operations.ClickArea; import com.android.internal.widget.remotecompose.core.operations.ClipPath; @@ -65,15 +67,19 @@ import com.android.internal.widget.remotecompose.core.operations.TextLookupInt; import com.android.internal.widget.remotecompose.core.operations.TextMeasure; import com.android.internal.widget.remotecompose.core.operations.TextMerge; import com.android.internal.widget.remotecompose.core.operations.Theme; +import com.android.internal.widget.remotecompose.core.operations.TouchExpression; import com.android.internal.widget.remotecompose.core.operations.layout.CanvasContent; -import com.android.internal.widget.remotecompose.core.operations.layout.ClickModifierEnd; import com.android.internal.widget.remotecompose.core.operations.layout.ClickModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.ComponentEnd; import com.android.internal.widget.remotecompose.core.operations.layout.ComponentStart; import com.android.internal.widget.remotecompose.core.operations.layout.LayoutComponentContent; import com.android.internal.widget.remotecompose.core.operations.layout.LoopEnd; import com.android.internal.widget.remotecompose.core.operations.layout.LoopOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.OperationsListEnd; import com.android.internal.widget.remotecompose.core.operations.layout.RootLayoutComponent; +import com.android.internal.widget.remotecompose.core.operations.layout.TouchCancelModifierOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.TouchDownModifierOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.TouchUpModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.animation.AnimationSpec; import com.android.internal.widget.remotecompose.core.operations.layout.managers.BoxLayout; import com.android.internal.widget.remotecompose.core.operations.layout.managers.CanvasLayout; @@ -85,15 +91,19 @@ import com.android.internal.widget.remotecompose.core.operations.layout.modifier import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.BorderModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ClipRectModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ComponentVisibilityOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.GraphicsLayerModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.HeightModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.HostActionOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.HostNamedActionOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.OffsetModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.PaddingModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.RoundedClipRectModifierOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ValueFloatChangeActionOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ValueIntegerChangeActionOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ValueIntegerExpressionChangeActionOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ValueStringChangeActionOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.WidthModifierOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ZIndexModifierOperation; import com.android.internal.widget.remotecompose.core.operations.utilities.IntMap; import com.android.internal.widget.remotecompose.core.types.BooleanConstant; import com.android.internal.widget.remotecompose.core.types.IntegerConstant; @@ -165,6 +175,7 @@ public class Operations { public static final int DATA_MAP_LOOKUP = 154; public static final int TEXT_MEASURE = 155; public static final int TEXT_LENGTH = 156; + public static final int TOUCH_EXPRESSION = 157; ///////////////////////////////////////// ====================== @@ -194,8 +205,16 @@ public class Operations { public static final int MODIFIER_ROUNDED_CLIP_RECT = 54; public static final int MODIFIER_CLICK = 59; + public static final int MODIFIER_TOUCH_DOWN = 219; + public static final int MODIFIER_TOUCH_UP = 220; + public static final int MODIFIER_TOUCH_CANCEL = 225; + + public static final int OPERATIONS_LIST_END = 214; + + public static final int MODIFIER_OFFSET = 221; + public static final int MODIFIER_ZINDEX = 223; + public static final int MODIFIER_GRAPHICS_LAYER = 224; - public static final int MODIFIER_CLICK_END = 214; public static final int LOOP_START = 215; public static final int LOOP_END = 216; @@ -206,12 +225,13 @@ public class Operations { public static final int VALUE_INTEGER_CHANGE_ACTION = 212; public static final int VALUE_STRING_CHANGE_ACTION = 213; public static final int VALUE_INTEGER_EXPRESSION_CHANGE_ACTION = 218; + public static final int VALUE_FLOAT_CHANGE_ACTION = 222; public static final int ANIMATION_SPEC = 14; public static final int COMPONENT_VALUE = 150; - public static UniqueIntMap<CompanionOperation> map = new UniqueIntMap<>(); + @NonNull public static UniqueIntMap<CompanionOperation> map = new UniqueIntMap<>(); static class UniqueIntMap<T> extends IntMap<T> { @Override @@ -289,8 +309,16 @@ public class Operations { map.put(MODIFIER_ROUNDED_CLIP_RECT, RoundedClipRectModifierOperation::read); map.put(MODIFIER_CLIP_RECT, ClipRectModifierOperation::read); map.put(MODIFIER_CLICK, ClickModifierOperation::read); - map.put(MODIFIER_CLICK_END, ClickModifierEnd::read); + map.put(MODIFIER_TOUCH_DOWN, TouchDownModifierOperation::read); + map.put(MODIFIER_TOUCH_UP, TouchUpModifierOperation::read); + map.put(MODIFIER_TOUCH_CANCEL, TouchCancelModifierOperation::read); map.put(MODIFIER_VISIBILITY, ComponentVisibilityOperation::read); + map.put(MODIFIER_OFFSET, OffsetModifierOperation::read); + map.put(MODIFIER_ZINDEX, ZIndexModifierOperation::read); + map.put(MODIFIER_GRAPHICS_LAYER, GraphicsLayerModifierOperation::read); + + map.put(OPERATIONS_LIST_END, OperationsListEnd::read); + map.put(HOST_ACTION, HostActionOperation::read); map.put(HOST_NAMED_ACTION, HostNamedActionOperation::read); map.put(VALUE_INTEGER_CHANGE_ACTION, ValueIntegerChangeActionOperation::read); @@ -298,6 +326,7 @@ public class Operations { VALUE_INTEGER_EXPRESSION_CHANGE_ACTION, ValueIntegerExpressionChangeActionOperation::read); map.put(VALUE_STRING_CHANGE_ACTION, ValueStringChangeActionOperation::read); + map.put(VALUE_FLOAT_CHANGE_ACTION, ValueFloatChangeActionOperation::read); map.put(LAYOUT_ROOT, RootLayoutComponent::read); map.put(LAYOUT_CONTENT, LayoutComponentContent::read); @@ -315,5 +344,6 @@ public class Operations { map.put(DATA_MAP_LOOKUP, DataMapLookup::read); map.put(TEXT_MEASURE, TextMeasure::read); map.put(TEXT_LENGTH, TextLength::read); + map.put(TOUCH_EXPRESSION, TouchExpression::read); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java b/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java index 13d6f783a586..1a71afe068bd 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java +++ b/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java @@ -271,4 +271,24 @@ public abstract class PaintContext { public void needsRepaint() { mNeedsRepaint = true; } + + public abstract void startGraphicsLayer(int w, int h); + + public abstract void setGraphicsLayer( + float scaleX, + float scaleY, + float rotationX, + float rotationY, + float rotationZ, + float shadowElevation, + float transformOriginX, + float transformOriginY, + float alpha, + int renderEffectId); + + public abstract void endGraphicsLayer(); + + public boolean isVisualDebug() { + return mContext.isVisualDebug(); + } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/PaintOperation.java b/core/java/com/android/internal/widget/remotecompose/core/PaintOperation.java index 9b7b50f775b0..049e47744ce8 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/PaintOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/PaintOperation.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core; +import android.annotation.NonNull; + /** * PaintOperation interface, used for operations aimed at painting (while any operation _can_ paint, * this make it a little more explicit) @@ -22,7 +24,7 @@ package com.android.internal.widget.remotecompose.core; public abstract class PaintOperation implements Operation { @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { if (context.getMode() == RemoteContext.ContextMode.PAINT) { PaintContext paintContext = context.getPaintContext(); if (paintContext != null) { @@ -31,6 +33,7 @@ public abstract class PaintOperation implements Operation { } } + @NonNull @Override public String deepToString(String indent) { return indent + toString(); diff --git a/core/java/com/android/internal/widget/remotecompose/core/Platform.java b/core/java/com/android/internal/widget/remotecompose/core/Platform.java index 6725e7e6ac2b..7fbcfae54bcb 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/Platform.java +++ b/core/java/com/android/internal/widget/remotecompose/core/Platform.java @@ -15,16 +15,30 @@ */ package com.android.internal.widget.remotecompose.core; +import android.annotation.Nullable; + /** Services that are needed to be provided by the platform during encoding. */ public interface Platform { + @Nullable byte[] imageToByteArray(Object image); int getImageWidth(Object image); int getImageHeight(Object image); + @Nullable float[] pathToFloatArray(Object path); + enum LogCategory { + DEBUG, + INFO, + WARN, + ERROR, + TODO, + } + + void log(LogCategory category, String message); + Platform None = new Platform() { @Override @@ -46,5 +60,8 @@ public interface Platform { public float[] pathToFloatArray(Object path) { throw new UnsupportedOperationException(); } + + @Override + public void log(LogCategory category, String message) {} }; } diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java index 5b5adc28a676..7d9439dd186b 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java +++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java @@ -15,6 +15,9 @@ */ package com.android.internal.widget.remotecompose.core; +import android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.operations.BitmapData; import com.android.internal.widget.remotecompose.core.operations.ClickArea; import com.android.internal.widget.remotecompose.core.operations.ClipPath; @@ -64,6 +67,7 @@ import com.android.internal.widget.remotecompose.core.operations.TextLookupInt; import com.android.internal.widget.remotecompose.core.operations.TextMeasure; import com.android.internal.widget.remotecompose.core.operations.TextMerge; import com.android.internal.widget.remotecompose.core.operations.Theme; +import com.android.internal.widget.remotecompose.core.operations.TouchExpression; import com.android.internal.widget.remotecompose.core.operations.Utils; import com.android.internal.widget.remotecompose.core.operations.layout.CanvasContent; import com.android.internal.widget.remotecompose.core.operations.layout.ComponentEnd; @@ -81,8 +85,11 @@ import com.android.internal.widget.remotecompose.core.operations.layout.managers import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.BackgroundModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.BorderModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ClipRectModifierOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.GraphicsLayerModifierOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.OffsetModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.PaddingModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.RoundedClipRectModifierOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ZIndexModifierOperation; import com.android.internal.widget.remotecompose.core.operations.paint.PaintBundle; import com.android.internal.widget.remotecompose.core.operations.utilities.NanMap; import com.android.internal.widget.remotecompose.core.operations.utilities.easing.FloatAnimation; @@ -111,7 +118,7 @@ public class RemoteComposeBuffer { public static final int EASING_EASE_OUT_BOUNCE = FloatAnimation.EASE_OUT_BOUNCE; public static final int EASING_EASE_OUT_ELASTIC = FloatAnimation.EASE_OUT_ELASTIC; WireBuffer mBuffer = new WireBuffer(); - Platform mPlatform = null; + @Nullable Platform mPlatform = null; RemoteComposeState mRemoteComposeState; private static final boolean DEBUG = false; @@ -143,6 +150,7 @@ public class RemoteComposeBuffer { return mLastComponentId; } + @Nullable public Platform getPlatform() { return mPlatform; } @@ -172,7 +180,11 @@ public class RemoteComposeBuffer { * @param capabilities bitmask indicating needed capabilities (unused for now) */ public void header( - int width, int height, String contentDescription, float density, long capabilities) { + int width, + int height, + @Nullable String contentDescription, + float density, + long capabilities) { Header.apply(mBuffer, width, height, density, capabilities); int contentDescriptionId = 0; if (contentDescription != null) { @@ -219,7 +231,7 @@ public class RemoteComposeBuffer { int dstTop, int dstRight, int dstBottom, - String contentDescription) { + @Nullable String contentDescription) { int imageId = mRemoteComposeState.dataGetId(image); if (imageId == -1) { imageId = mRemoteComposeState.cacheData(image); @@ -267,7 +279,7 @@ public class RemoteComposeBuffer { * * @param text the string to inject in the buffer */ - public int addText(String text) { + public int addText(@NonNull String text) { int id = mRemoteComposeState.dataGetId(text); if (id == -1) { id = mRemoteComposeState.cacheData(text); @@ -289,12 +301,12 @@ public class RemoteComposeBuffer { */ public void addClickArea( int id, - String contentDescription, + @Nullable String contentDescription, float left, float top, float right, float bottom, - String metadata) { + @Nullable String metadata) { int contentDescriptionId = 0; if (contentDescription != null) { contentDescriptionId = addText(contentDescription); @@ -380,7 +392,7 @@ public class RemoteComposeBuffer { float top, float right, float bottom, - String contentDescription) { + @Nullable String contentDescription) { int imageId = mRemoteComposeState.dataGetId(image); if (imageId == -1) { imageId = mRemoteComposeState.cacheData(image); @@ -411,7 +423,7 @@ public class RemoteComposeBuffer { float top, float right, float bottom, - String contentDescription) { + @Nullable String contentDescription) { int contentDescriptionId = 0; if (contentDescription != null) { contentDescriptionId = addText(contentDescription); @@ -445,7 +457,7 @@ public class RemoteComposeBuffer { float dstBottom, int scaleType, float scaleFactor, - String contentDescription) { + @Nullable String contentDescription) { int imageId = mRemoteComposeState.dataGetId(image); if (imageId == -1) { imageId = mRemoteComposeState.cacheData(image); @@ -500,7 +512,7 @@ public class RemoteComposeBuffer { * @param image drawScaledBitmap * @return id of the image useful with */ - public int addBitmap(Object image, String name) { + public int addBitmap(Object image, @NonNull String name) { int imageId = mRemoteComposeState.dataGetId(image); if (imageId == -1) { imageId = mRemoteComposeState.cacheData(image); @@ -521,7 +533,7 @@ public class RemoteComposeBuffer { * @param id of the Bitmap * @param name Name of the color */ - public void setBitmapName(int id, String name) { + public void setBitmapName(int id, @NonNull String name) { NamedVariable.apply(mBuffer, id, NamedVariable.IMAGE_TYPE, name); } @@ -551,7 +563,7 @@ public class RemoteComposeBuffer { float dstBottom, int scaleType, float scaleFactor, - String contentDescription) { + @Nullable String contentDescription) { int contentDescriptionId = 0; if (contentDescription != null) { contentDescriptionId = addText(contentDescription); @@ -669,7 +681,7 @@ public class RemoteComposeBuffer { * @param hOffset The distance along the path to add to the text's starting position * @param vOffset The distance above(-) or below(+) the path to position the text */ - public void addDrawTextOnPath(String text, Object path, float hOffset, float vOffset) { + public void addDrawTextOnPath(@NonNull String text, Object path, float hOffset, float vOffset) { int pathId = mRemoteComposeState.dataGetId(path); if (pathId == -1) { // never been seen before pathId = addPathData(path); @@ -692,7 +704,7 @@ public class RemoteComposeBuffer { * @param rtl Draw RTTL */ public void addDrawTextRun( - String text, + @NonNull String text, int start, int end, int contextStart, @@ -749,7 +761,8 @@ public class RemoteComposeBuffer { * @param panY position text -1.0=above, 0.0=center, 1.0=below, Nan=baseline * @param flags 1 = RTL */ - public void drawTextAnchored(String text, float x, float y, float panX, float panY, int flags) { + public void drawTextAnchored( + @NonNull String text, float x, float y, float panX, float panY, int flags) { int textId = addText(text); DrawTextAnchored.apply(mBuffer, textId, x, y, panX, panY, flags); } @@ -760,7 +773,7 @@ public class RemoteComposeBuffer { * @param text * @return */ - public int createTextId(String text) { + public int createTextId(@NonNull String text) { return addText(text); } @@ -891,7 +904,7 @@ public class RemoteComposeBuffer { * * @param paint */ - public void addPaint(PaintBundle paint) { + public void addPaint(@NonNull PaintBundle paint) { PaintData.apply(mBuffer, paint); } @@ -912,7 +925,8 @@ public class RemoteComposeBuffer { } } - public static void readNextOperation(WireBuffer buffer, ArrayList<Operation> operations) { + public static void readNextOperation( + @NonNull WireBuffer buffer, ArrayList<Operation> operations) { int opId = buffer.readByte(); if (DEBUG) { Utils.log(">> " + opId); @@ -924,6 +938,7 @@ public class RemoteComposeBuffer { operation.read(buffer, operations); } + @NonNull RemoteComposeBuffer copy() { ArrayList<Operation> operations = new ArrayList<>(); inflateFromBuffer(operations); @@ -935,33 +950,38 @@ public class RemoteComposeBuffer { Theme.apply(mBuffer, theme); } + @NonNull static String version() { return "v1.0"; } - public static RemoteComposeBuffer fromFile(String path, RemoteComposeState remoteComposeState) - throws IOException { + @NonNull + public static RemoteComposeBuffer fromFile( + @NonNull String path, RemoteComposeState remoteComposeState) throws IOException { RemoteComposeBuffer buffer = new RemoteComposeBuffer(remoteComposeState); read(new File(path), buffer); return buffer; } - public RemoteComposeBuffer fromFile(File file, RemoteComposeState remoteComposeState) + @NonNull + public RemoteComposeBuffer fromFile(@NonNull File file, RemoteComposeState remoteComposeState) throws IOException { RemoteComposeBuffer buffer = new RemoteComposeBuffer(remoteComposeState); read(file, buffer); return buffer; } + @NonNull public static RemoteComposeBuffer fromInputStream( - InputStream inputStream, RemoteComposeState remoteComposeState) { + @NonNull InputStream inputStream, RemoteComposeState remoteComposeState) { RemoteComposeBuffer buffer = new RemoteComposeBuffer(remoteComposeState); read(inputStream, buffer); return buffer; } + @NonNull RemoteComposeBuffer copyFromOperations( - ArrayList<Operation> operations, RemoteComposeBuffer buffer) { + @NonNull ArrayList<Operation> operations, @NonNull RemoteComposeBuffer buffer) { for (Operation operation : operations) { operation.write(buffer.mBuffer); @@ -975,7 +995,7 @@ public class RemoteComposeBuffer { * @param buffer a RemoteComposeBuffer * @param file a target file */ - public void write(RemoteComposeBuffer buffer, File file) { + public void write(@NonNull RemoteComposeBuffer buffer, @NonNull File file) { try { FileOutputStream fd = new FileOutputStream(file); fd.write(buffer.mBuffer.getBuffer(), 0, buffer.mBuffer.getSize()); @@ -986,12 +1006,12 @@ public class RemoteComposeBuffer { } } - static void read(File file, RemoteComposeBuffer buffer) throws IOException { + static void read(@NonNull File file, @NonNull RemoteComposeBuffer buffer) throws IOException { FileInputStream fd = new FileInputStream(file); read(fd, buffer); } - public static void read(InputStream fd, RemoteComposeBuffer buffer) { + public static void read(@NonNull InputStream fd, @NonNull RemoteComposeBuffer buffer) { try { byte[] bytes = readAllBytes(fd); buffer.reset(bytes.length); @@ -1002,7 +1022,7 @@ public class RemoteComposeBuffer { } } - private static byte[] readAllBytes(InputStream is) throws IOException { + private static byte[] readAllBytes(@NonNull InputStream is) throws IOException { byte[] buff = new byte[32 * 1024]; // moderate size buff to start int red = 0; while (true) { @@ -1176,20 +1196,59 @@ public class RemoteComposeBuffer { * @param value A RPN style float operation i.e. "4, 3, ADD" outputs 7 * @return NaN id of the result of the calculation */ - public float addAnimatedFloat(float... value) { + public float addAnimatedFloat(@NonNull float... value) { int id = mRemoteComposeState.cacheData(value); FloatExpression.apply(mBuffer, id, value, null); return Utils.asNan(id); } /** + * Add a touch handle system + * + * @param value the default value + * @param min the minimum value + * @param max the maximum value + * @param velocityId the id for the velocity TODO support in v2 + * @param exp The Float Expression + * @param touchMode the touch up handling behaviour + * @param touchSpec the touch up handling parameters + * @param easingSpec the easing parameter TODO support in v2 + * @return id of the variable to be used controlled by touch handling + */ + public float addTouchExpression( + float value, + float min, + float max, + float velocityId, + int touchEffects, + float[] exp, + int touchMode, + float[] touchSpec, + float[] easingSpec) { + int id = mRemoteComposeState.nextId(); + TouchExpression.apply( + mBuffer, + id, + value, + min, + max, + velocityId, + touchEffects, + exp, + touchMode, + touchSpec, + easingSpec); + return Utils.asNan(id); + } + + /** * Add a float that is a computation based on variables. see packAnimation * * @param value A RPN style float operation i.e. "4, 3, ADD" outputs 7 * @param animation Array of floats that represents animation * @return NaN id of the result of the calculation */ - public float addAnimatedFloat(float[] value, float[] animation) { + public float addAnimatedFloat(@NonNull float[] value, float[] animation) { int id = mRemoteComposeState.cacheData(value); FloatExpression.apply(mBuffer, id, value, animation); return Utils.asNan(id); @@ -1228,7 +1287,7 @@ public class RemoteComposeBuffer { * @param values * @return the id of the array, encoded as a float NaN */ - public float addFloatArray(float[] values) { + public float addFloatArray(@NonNull float[] values) { int id = mRemoteComposeState.cacheData(values, NanMap.TYPE_ARRAY); DataListFloat.apply(mBuffer, id, values); return Utils.asNan(id); @@ -1240,7 +1299,7 @@ public class RemoteComposeBuffer { * @param values array of floats to be individually stored * @return id of the list */ - public float addFloatList(float[] values) { + public float addFloatList(@NonNull float[] values) { int[] listId = new int[values.length]; for (int i = 0; i < listId.length; i++) { listId[i] = mRemoteComposeState.cacheFloat(values[i]); @@ -1255,7 +1314,7 @@ public class RemoteComposeBuffer { * @param listId array id to be stored * @return id of the list */ - public float addList(int[] listId) { + public float addList(@NonNull int[] listId) { int id = mRemoteComposeState.cacheData(listId, NanMap.TYPE_ARRAY); DataListIds.apply(mBuffer, id, listId); return Utils.asNan(id); @@ -1268,7 +1327,7 @@ public class RemoteComposeBuffer { * @param values * @return the id of the map, encoded as a float NaN */ - public float addFloatMap(String[] keys, float[] values) { + public float addFloatMap(@NonNull String[] keys, @NonNull float[] values) { int[] listId = new int[values.length]; byte[] type = new byte[values.length]; for (int i = 0; i < listId.length; i++) { @@ -1286,7 +1345,7 @@ public class RemoteComposeBuffer { * @param listId * @return the id of the map, encoded as a float NaN */ - public int addMap(String[] keys, byte[] types, int[] listId) { + public int addMap(@NonNull String[] keys, byte[] types, int[] listId) { int id = mRemoteComposeState.cacheData(listId, NanMap.TYPE_ARRAY); DataMapIds.apply(mBuffer, id, keys, types, listId); return id; @@ -1331,7 +1390,7 @@ public class RemoteComposeBuffer { * @param value array of values to calculate maximum 32 * @return the id as an integer */ - public int addIntegerExpression(int mask, int[] value) { + public int addIntegerExpression(int mask, @NonNull int[] value) { int id = mRemoteComposeState.cacheData(value); IntegerExpression.apply(mBuffer, id, mask, value); return id; @@ -1474,7 +1533,7 @@ public class RemoteComposeBuffer { * @param id of the color * @param name Name of the color */ - public void setColorName(int id, String name) { + public void setColorName(int id, @NonNull String name) { NamedVariable.apply(mBuffer, id, NamedVariable.COLOR_TYPE, name); } @@ -1484,7 +1543,7 @@ public class RemoteComposeBuffer { * @param id of the string * @param name name of the string */ - public void setStringName(int id, String name) { + public void setStringName(int id, @NonNull String name) { NamedVariable.apply(mBuffer, id, NamedVariable.STRING_TYPE, name); } @@ -1576,6 +1635,72 @@ public class RemoteComposeBuffer { } /** + * Add an offset modifier + * + * @param x x offset + * @param y y offset + */ + public void addModifierOffset(float x, float y) { + OffsetModifierOperation.apply(mBuffer, x, y); + } + + /** + * Add a zIndex modifier + * + * @param value z-Index value + */ + public void addModifierZIndex(float value) { + ZIndexModifierOperation.apply(mBuffer, value); + } + + /** + * Add a graphics layer + * + * @param scaleX + * @param scaleY + * @param rotationX + * @param rotationY + * @param rotationZ + * @param shadowElevation + * @param transformOriginX + * @param transformOriginY + */ + public void addModifierGraphicsLayer( + float scaleX, + float scaleY, + float rotationX, + float rotationY, + float rotationZ, + float shadowElevation, + float transformOriginX, + float transformOriginY, + float alpha, + float cameraDistance, + int blendMode, + int spotShadowColorId, + int ambientShadowColorId, + int colorFilterId, + int renderEffectId) { + GraphicsLayerModifierOperation.apply( + mBuffer, + scaleX, + scaleY, + rotationX, + rotationY, + rotationZ, + shadowElevation, + transformOriginX, + transformOriginY, + alpha, + cameraDistance, + blendMode, + spotShadowColorId, + ambientShadowColorId, + colorFilterId, + renderEffectId); + } + + /** * Sets the clip based on rounded clip rect * * @param topStart @@ -1721,7 +1846,8 @@ public class RemoteComposeBuffer { float fontSize, int fontStyle, float fontWeight, - String fontFamily) { + @Nullable String fontFamily, + int textAlign) { mLastComponentId = getComponentId(componentId); int fontFamilyId = -1; if (fontFamily != null) { @@ -1736,6 +1862,11 @@ public class RemoteComposeBuffer { fontSize, fontStyle, fontWeight, - fontFamilyId); + fontFamilyId, + textAlign); + } + + public int createID(int type) { + return mRemoteComposeState.nextId(type); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java index 51445f2ff31d..303932814909 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java +++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java @@ -15,6 +15,9 @@ */ package com.android.internal.widget.remotecompose.core; +import android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.operations.utilities.ArrayAccess; import com.android.internal.widget.remotecompose.core.operations.utilities.CollectionsAccess; import com.android.internal.widget.remotecompose.core.operations.utilities.DataMap; @@ -50,10 +53,11 @@ public class RemoteComposeState implements CollectionsAccess { private final boolean[] mDataOverride = new boolean[MAX_DATA]; private final boolean[] mIntegerOverride = new boolean[MAX_DATA]; + private final boolean[] mFloatOverride = new boolean[MAX_DATA]; private int mNextId = START_ID; - private int[] mIdMaps = new int[] {START_ID, NanMap.START_VAR, NanMap.START_ARRAY}; - private RemoteContext mRemoteContext = null; + @NonNull private int[] mIdMaps = new int[] {START_ID, NanMap.START_VAR, NanMap.START_ARRAY}; + @Nullable private RemoteContext mRemoteContext = null; /** * Get Object based on id. The system will cache things like bitmaps Paths etc. They can be @@ -62,6 +66,7 @@ public class RemoteComposeState implements CollectionsAccess { * @param id * @return */ + @Nullable public Object getFromId(int id) { return mIntDataMap.get(id); } @@ -158,10 +163,28 @@ public class RemoteComposeState implements CollectionsAccess { /** Insert an float item in the cache */ public void updateFloat(int id, float value) { + if (!mFloatOverride[id]) { + float previous = mFloatMap.get(id); + if (previous != value) { + mFloatMap.put(id, value); + mIntegerMap.put(id, (int) value); + updateListeners(id); + } + } + } + + /** + * Adds a float Override. + * + * @param id + * @param value the new value + */ + public void overrideFloat(int id, float value) { float previous = mFloatMap.get(id); if (previous != value) { mFloatMap.put(id, value); mIntegerMap.put(id, (int) value); + mFloatOverride[id] = true; updateListeners(id); } } @@ -294,6 +317,16 @@ public class RemoteComposeState implements CollectionsAccess { } /** + * Clear the float override + * + * @param id the float id to clear + */ + public void clearFloatOverride(int id) { + mFloatOverride[id] = false; + updateListeners(id); + } + + /** * Method to determine if a cached value has been written to the documents WireBuffer based on * its id. */ @@ -322,7 +355,8 @@ public class RemoteComposeState implements CollectionsAccess { } /** - * Get the next available id + * Get the next available id 0 is normal (float,int,String,color) 1 is VARIABLES 2 is + * collections * * @return */ @@ -342,8 +376,8 @@ public class RemoteComposeState implements CollectionsAccess { mNextId = id; } - IntMap<ArrayList<VariableSupport>> mVarListeners = new IntMap<>(); - ArrayList<VariableSupport> mAllVarListeners = new ArrayList<>(); + @NonNull IntMap<ArrayList<VariableSupport>> mVarListeners = new IntMap<>(); + @NonNull ArrayList<VariableSupport> mAllVarListeners = new ArrayList<>(); private void add(int id, VariableSupport variableSupport) { ArrayList<VariableSupport> v = mVarListeners.get(id); diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java index 1066e7d9f617..23cc5b89d916 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java +++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.operations.FloatExpression; import com.android.internal.widget.remotecompose.core.operations.ShaderData; import com.android.internal.widget.remotecompose.core.operations.Theme; @@ -40,10 +42,12 @@ public abstract class RemoteContext { protected CoreDocument mDocument; public RemoteComposeState mRemoteComposeState; long mStart = System.nanoTime(); // todo This should be set at a hi level - protected PaintContext mPaintContext = null; + @Nullable protected PaintContext mPaintContext = null; + protected float mDensity = 2.75f; + ContextMode mMode = ContextMode.UNSET; - boolean mDebug = false; + int mDebug = 0; private int mTheme = Theme.UNSPECIFIED; @@ -56,6 +60,14 @@ public abstract class RemoteContext { public Component lastComponent; public long currentTime = 0L; + public float getDensity() { + return mDensity; + } + + public void setDensity(float density) { + mDensity = density; + } + public boolean isAnimationEnabled() { return mAnimate; } @@ -173,12 +185,22 @@ public abstract class RemoteContext { public abstract void runAction(int id, String metadata); - public abstract void runNamedAction(int textId); + // TODO: we might add an interface to group all valid parameter types + public abstract void runNamedAction(int textId, Object value); public abstract void putObject(int mId, Object command); public abstract Object getObject(int mId); + public void addTouchListener(TouchListener touchExpression) {} + + /** + * Vibrate the device + * + * @param type 0 = none, 1-21 ,see HapticFeedbackConstants + */ + public abstract void hapticEffect(int type); + /** * The context can be used in a few different mode, allowing operations to skip being executed: * - UNSET : all operations will get executed - DATA : only operations dealing with DATA (eg @@ -206,6 +228,7 @@ public abstract class RemoteContext { this.mMode = mode; } + @Nullable public PaintContext getPaintContext() { return mPaintContext; } @@ -219,10 +242,14 @@ public abstract class RemoteContext { } public boolean isDebug() { - return mDebug; + return mDebug == 1; } - public void setDebug(boolean debug) { + public boolean isVisualDebug() { + return mDebug == 2; + } + + public void setDebug(int debug) { this.mDebug = debug; } @@ -314,6 +341,14 @@ public abstract class RemoteContext { public abstract void loadFloat(int id, float value); /** + * Override an existing float value + * + * @param id + * @param value + */ + public abstract void overrideFloat(int id, float value); + + /** * Load a integer * * @param id id of the integer @@ -321,8 +356,20 @@ public abstract class RemoteContext { */ public abstract void loadInteger(int id, int value); + /** + * Override an existing int value + * + * @param id + * @param value + */ public abstract void overrideInteger(int id, int value); + /** + * Override an existing text value + * + * @param id + * @param valueId + */ public abstract void overrideText(int id, int valueId); /** @@ -400,6 +447,25 @@ public abstract class RemoteContext { public static final int ID_OFFSET_TO_UTC = 10; public static final int ID_WEEK_DAY = 11; public static final int ID_DAY_OF_MONTH = 12; + public static final int ID_TOUCH_POS_X = 13; + public static final int ID_TOUCH_POS_Y = 14; + + public static final int ID_TOUCH_VEL_X = 15; + public static final int ID_TOUCH_VEL_Y = 16; + + public static final int ID_ACCELERATION_X = 17; + public static final int ID_ACCELERATION_Y = 18; + public static final int ID_ACCELERATION_Z = 19; + + public static final int ID_GYRO_ROT_X = 20; + public static final int ID_GYRO_ROT_Y = 21; + public static final int ID_GYRO_ROT_Z = 22; + + public static final int ID_MAGNETIC_X = 23; + public static final int ID_MAGNETIC_Y = 24; + public static final int ID_MAGNETIC_Z = 25; + + public static final int ID_LIGHT = 26; /** CONTINUOUS_SEC is seconds from midnight looping every hour 0-3600 */ public static final float FLOAT_CONTINUOUS_SEC = Utils.asNan(ID_CONTINUOUS_SEC); @@ -426,9 +492,52 @@ public abstract class RemoteContext { public static final float FLOAT_WINDOW_HEIGHT = Utils.asNan(ID_WINDOW_HEIGHT); public static final float FLOAT_COMPONENT_WIDTH = Utils.asNan(ID_COMPONENT_WIDTH); public static final float FLOAT_COMPONENT_HEIGHT = Utils.asNan(ID_COMPONENT_HEIGHT); - // ID_OFFSET_TO_UTC is the offset from UTC in sec (typically / 3600f) + + /** ID_OFFSET_TO_UTC is the offset from UTC in sec (typically / 3600f) */ public static final float FLOAT_OFFSET_TO_UTC = Utils.asNan(ID_OFFSET_TO_UTC); + /** TOUCH_POS_X is the x position of the touch */ + public static final float FLOAT_TOUCH_POS_X = Utils.asNan(ID_TOUCH_POS_X); + + /** TOUCH_POS_Y is the y position of the touch */ + public static final float FLOAT_TOUCH_POS_Y = Utils.asNan(ID_TOUCH_POS_Y); + + /** TOUCH_VEL_X is the x velocity of the touch */ + public static final float FLOAT_TOUCH_VEL_X = Utils.asNan(ID_TOUCH_VEL_X); + + /** TOUCH_VEL_Y is the x velocity of the touch */ + public static final float FLOAT_TOUCH_VEL_Y = Utils.asNan(ID_TOUCH_VEL_Y); + + /** X acceleration sensor value in M/s^2 */ + public static final float FLOAT_ACCELERATION_X = Utils.asNan(ID_ACCELERATION_X); + + /** Y acceleration sensor value in M/s^2 */ + public static final float FLOAT_ACCELERATION_Y = Utils.asNan(ID_ACCELERATION_Y); + + /** Z acceleration sensor value in M/s^2 */ + public static final float FLOAT_ACCELERATION_Z = Utils.asNan(ID_ACCELERATION_Z); + + /** X Gyroscope rotation rate sensor value in radians/second */ + public static final float FLOAT_GYRO_ROT_X = Utils.asNan(ID_GYRO_ROT_X); + + /** Y Gyroscope rotation rate sensor value in radians/second */ + public static final float FLOAT_GYRO_ROT_Y = Utils.asNan(ID_GYRO_ROT_Y); + + /** Z Gyroscope rotation rate sensor value in radians/second */ + public static final float FLOAT_GYRO_ROT_Z = Utils.asNan(ID_GYRO_ROT_Z); + + /** Ambient magnetic field in X. sensor value in micro-Tesla (uT) */ + public static final float FLOAT_MAGNETIC_X = Utils.asNan(ID_MAGNETIC_X); + + /** Ambient magnetic field in Y. sensor value in micro-Tesla (uT) */ + public static final float FLOAT_MAGNETIC_Y = Utils.asNan(ID_MAGNETIC_Y); + + /** Ambient magnetic field in Z. sensor value in micro-Tesla (uT) */ + public static final float FLOAT_MAGNETIC_Z = Utils.asNan(ID_MAGNETIC_Z); + + /** Ambient light level in SI lux */ + public static final float FLOAT_LIGHT = Utils.asNan(ID_LIGHT); + /////////////////////////////////////////////////////////////////////////////////////////////// // Click handling /////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java b/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java index fa0cf3f455c4..14aed2f0c173 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java +++ b/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core; +import android.annotation.NonNull; + import java.time.LocalDateTime; import java.time.OffsetDateTime; import java.time.ZoneId; @@ -27,7 +29,7 @@ public class TimeVariables { * * @param context */ - public void updateTime(RemoteContext context) { + public void updateTime(@NonNull RemoteContext context) { LocalDateTime dateTime = LocalDateTime.now(ZoneId.systemDefault()); // TODO, pass in a timezone explicitly? // This define the time in the format diff --git a/core/java/com/android/internal/widget/remotecompose/core/TouchListener.java b/core/java/com/android/internal/widget/remotecompose/core/TouchListener.java new file mode 100644 index 000000000000..3dda678c2a3a --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/TouchListener.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core; + +public interface TouchListener { + void touchDown(RemoteContext context, float x, float y); + + void touchUp(RemoteContext context, float x, float y, float dx, float dy); + + void touchDrag(RemoteContext context, float x, float y); +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/WireBuffer.java b/core/java/com/android/internal/widget/remotecompose/core/WireBuffer.java index c71b4901ca78..738e42baae0b 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/WireBuffer.java +++ b/core/java/com/android/internal/widget/remotecompose/core/WireBuffer.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core; +import android.annotation.NonNull; + import java.util.Arrays; /** The base communication buffer capable of encoding and decoding various types */ @@ -184,11 +186,13 @@ public class WireBuffer { return b; } + @NonNull public String readUTF8() { byte[] stringBuffer = readBuffer(); return new String(stringBuffer); } + @NonNull public String readUTF8(int maxSize) { byte[] stringBuffer = readBuffer(maxSize); return new String(stringBuffer); @@ -250,7 +254,7 @@ public class WireBuffer { writeLong(Double.doubleToRawLongBits(value)); } - public void writeBuffer(byte[] b) { + public void writeBuffer(@NonNull byte[] b) { resize(b.length + 4); writeInt(b.length); for (int i = 0; i < b.length; i++) { @@ -259,7 +263,7 @@ public class WireBuffer { mSize += b.length; } - public void writeUTF8(String content) { + public void writeUTF8(@NonNull String content) { byte[] buffer = content.getBytes(); writeBuffer(buffer); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentedOperation.java b/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentedOperation.java index c33ae244b923..5edecaa01f82 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentedOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentedOperation.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.documentation; +import android.annotation.NonNull; + import java.util.ArrayList; public class DocumentedOperation { @@ -40,12 +42,13 @@ public class DocumentedOperation { boolean mWIP; String mTextExamples; - ArrayList<StringPair> mExamples = new ArrayList<>(); - ArrayList<OperationField> mFields = new ArrayList<>(); - String mVarSize = ""; + @NonNull ArrayList<StringPair> mExamples = new ArrayList<>(); + @NonNull ArrayList<OperationField> mFields = new ArrayList<>(); + @NonNull String mVarSize = ""; int mExamplesWidth = 100; int mExamplesHeight = 100; + @NonNull public static String getType(int type) { switch (type) { case INT: @@ -85,6 +88,7 @@ public class DocumentedOperation { this(category, id, name, false); } + @NonNull public ArrayList<OperationField> getFields() { return mFields; } @@ -105,6 +109,7 @@ public class DocumentedOperation { return mWIP; } + @NonNull public String getVarSize() { return mVarSize; } @@ -129,6 +134,7 @@ public class DocumentedOperation { return mTextExamples; } + @NonNull public ArrayList<StringPair> getExamples() { return mExamples; } @@ -141,16 +147,19 @@ public class DocumentedOperation { return mExamplesHeight; } + @NonNull public DocumentedOperation field(int type, String name, String description) { mFields.add(new OperationField(type, name, description)); return this; } + @NonNull public DocumentedOperation field(int type, String name, String varSize, String description) { mFields.add(new OperationField(type, name, varSize, description)); return this; } + @NonNull public DocumentedOperation possibleValues(String name, int value) { if (!mFields.isEmpty()) { mFields.get(mFields.size() - 1).possibleValue(name, "" + value); @@ -158,21 +167,25 @@ public class DocumentedOperation { return this; } + @NonNull public DocumentedOperation description(String description) { mDescription = description; return this; } + @NonNull public DocumentedOperation examples(String examples) { mTextExamples = examples; return this; } + @NonNull public DocumentedOperation exampleImage(String name, String imagePath) { mExamples.add(new StringPair(name, imagePath)); return this; } + @NonNull public DocumentedOperation examplesDimension(int width, int height) { mExamplesWidth = width; mExamplesHeight = height; diff --git a/core/java/com/android/internal/widget/remotecompose/core/documentation/OperationField.java b/core/java/com/android/internal/widget/remotecompose/core/documentation/OperationField.java index c77048391405..cbb5ca9821c3 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/documentation/OperationField.java +++ b/core/java/com/android/internal/widget/remotecompose/core/documentation/OperationField.java @@ -15,15 +15,18 @@ */ package com.android.internal.widget.remotecompose.core.documentation; +import android.annotation.NonNull; +import android.annotation.Nullable; + import java.util.ArrayList; public class OperationField { int mType; String mName; String mDescription; - String mVarSize = null; + @Nullable String mVarSize = null; - ArrayList<StringPair> mPossibleValues = new ArrayList<>(); + @NonNull ArrayList<StringPair> mPossibleValues = new ArrayList<>(); public OperationField(int type, String name, String description) { mType = type; @@ -50,6 +53,7 @@ public class OperationField { return mDescription; } + @NonNull public ArrayList<StringPair> getPossibleValues() { return mPossibleValues; } @@ -62,6 +66,7 @@ public class OperationField { return !mPossibleValues.isEmpty(); } + @Nullable public String getVarSize() { return mVarSize; } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java index 20ba8c313b47..8da0e184cbe7 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java @@ -18,6 +18,8 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT_ARRAY; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -58,15 +60,17 @@ public class BitmapData implements Operation, SerializableToString { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mImageId, mImageWidth, mImageHeight, mBitmap); } + @NonNull @Override public String toString() { return "BITMAP DATA " + mImageId; } + @NonNull public static String name() { return CLASS_NAME; } @@ -75,7 +79,12 @@ public class BitmapData implements Operation, SerializableToString { return OP_CODE; } - public static void apply(WireBuffer buffer, int imageId, int width, int height, byte[] bitmap) { + public static void apply( + @NonNull WireBuffer buffer, + int imageId, + int width, + int height, + @NonNull byte[] bitmap) { buffer.start(OP_CODE); buffer.writeInt(imageId); buffer.writeInt(width); @@ -83,7 +92,7 @@ public class BitmapData implements Operation, SerializableToString { buffer.writeBuffer(bitmap); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int imageId = buffer.readInt(); int width = buffer.readInt(); int height = buffer.readInt(); @@ -97,7 +106,7 @@ public class BitmapData implements Operation, SerializableToString { operations.add(new BitmapData(imageId, width, height, bitmap)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Data Operations", OP_CODE, CLASS_NAME) .description("Bitmap data") .field(DocumentedOperation.INT, "id", "id of bitmap data") @@ -107,17 +116,18 @@ public class BitmapData implements Operation, SerializableToString { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { context.loadBitmap(mImageId, mImageWidth, mImageHeight, mBitmap); } + @NonNull @Override public String deepToString(String indent) { return indent + toString(); } @Override - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { serializer.append( indent, CLASS_NAME + " id " + mImageId + " (" + mImageWidth + "x" + mImageHeight + ")"); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ClickArea.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ClickArea.java index 8b9e5a8d7625..83d0ac7a1eb2 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/ClickArea.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ClickArea.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteComposeOperation; @@ -67,10 +69,11 @@ public class ClickArea implements RemoteComposeOperation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mId, mContentDescription, mLeft, mTop, mRight, mBottom, mMetadata); } + @NonNull @Override public String toString() { return "CLICK_AREA <" @@ -97,18 +100,20 @@ public class ClickArea implements RemoteComposeOperation { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { if (context.getMode() != RemoteContext.ContextMode.DATA) { return; } context.addClickArea(mId, mContentDescription, mLeft, mTop, mRight, mBottom, mMetadata); } + @NonNull @Override public String deepToString(String indent) { return indent + toString(); } + @NonNull public static String name() { return CLASS_NAME; } @@ -118,7 +123,7 @@ public class ClickArea implements RemoteComposeOperation { } public static void apply( - WireBuffer buffer, + @NonNull WireBuffer buffer, int id, int contentDescription, float left, @@ -136,7 +141,7 @@ public class ClickArea implements RemoteComposeOperation { buffer.writeInt(metadata); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int id = buffer.readInt(); int contentDescription = buffer.readInt(); float left = buffer.readFloat(); @@ -149,7 +154,7 @@ public class ClickArea implements RemoteComposeOperation { operations.add(clickArea); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Canvas Operations", OP_CODE, CLASS_NAME) .description("Define a region you can click on") .field(DocumentedOperation.FLOAT, "left", "The left side of the region") diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java index 96b600acc971..db93829586bb 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -57,16 +59,17 @@ public class ClipPath extends PaintOperation { public static final int UNDEFINED = PATH_CLIP_UNDEFINED; @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mId); } + @NonNull @Override public String toString() { return "ClipPath " + mId + ";"; } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int pack = buffer.readInt(); int id = pack & 0xFFFFF; int regionOp = pack >> 24; @@ -74,6 +77,7 @@ public class ClipPath extends PaintOperation { operations.add(op); } + @NonNull public static String name() { return CLASS_NAME; } @@ -82,19 +86,19 @@ public class ClipPath extends PaintOperation { return OP_CODE; } - public static void apply(WireBuffer buffer, int id) { + public static void apply(@NonNull WireBuffer buffer, int id) { buffer.start(OP_CODE); buffer.writeInt(id); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Canvas Operations", OP_CODE, CLASS_NAME) .description("Intersect the current clip with the path") .field(DocumentedOperation.INT, "id", "id of the path"); } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.clipPath(mId, mRegionOp); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java index b101bfb2d151..df54fb1ed834 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -29,7 +31,7 @@ public class ClipRect extends DrawBase4 { public static final int OP_CODE = Operations.CLIP_RECT; public static final String CLASS_NAME = "ClipRect"; - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { Maker m = ClipRect::new; read(m, buffer, operations); } @@ -38,16 +40,17 @@ public class ClipRect extends DrawBase4 { return OP_CODE; } + @NonNull public static String name() { return CLASS_NAME; } @Override - protected void write(WireBuffer buffer, float v1, float v2, float v3, float v4) { + protected void write(@NonNull WireBuffer buffer, float v1, float v2, float v3, float v4) { apply(buffer, v1, v2, v3, v4); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Expressions Operations", OP_CODE, CLASS_NAME) .description("Intersect the current clip with rectangle") .field( @@ -74,7 +77,7 @@ public class ClipRect extends DrawBase4 { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.clipRect(mX1, mY1, mX2, mY2); } @@ -87,7 +90,7 @@ public class ClipRect extends DrawBase4 { * @param x2 end x of the DrawOval * @param y2 end y of the DrawOval */ - public static void apply(WireBuffer buffer, float x1, float y1, float x2, float y2) { + public static void apply(@NonNull WireBuffer buffer, float x1, float y1, float x2, float y2) { write(buffer, OP_CODE, x1, y1, x2, y2); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ColorConstant.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ColorConstant.java index 19d80daf0c8f..929c9a603079 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/ColorConstant.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ColorConstant.java @@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -39,15 +41,17 @@ public class ColorConstant implements Operation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mColorId, mColor); } + @NonNull @Override public String toString() { return "ColorConstant[" + mColorId + "] = " + Utils.colorInt(mColor) + ""; } + @NonNull public static String name() { return CLASS_NAME; } @@ -63,19 +67,19 @@ public class ColorConstant implements Operation { * @param colorId * @param color */ - public static void apply(WireBuffer buffer, int colorId, int color) { + public static void apply(@NonNull WireBuffer buffer, int colorId, int color) { buffer.start(OP_CODE); buffer.writeInt(colorId); buffer.writeInt(color); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int colorId = buffer.readInt(); int color = buffer.readInt(); operations.add(new ColorConstant(colorId, color)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Expressions Operations", OP_CODE, CLASS_NAME) .description("Define a Color") .field(DocumentedOperation.INT, "id", "Id of the color") @@ -83,10 +87,11 @@ public class ColorConstant implements Operation { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { context.loadColor(mColorId, mColor); } + @NonNull @Override public String deepToString(String indent) { return indent + toString(); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java index b6041eaeacdc..3d840c5b8203 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java @@ -18,6 +18,8 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -94,7 +96,7 @@ public class ColorExpression implements Operation, VariableSupport { } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { if (mMode == 4) { if (Float.isNaN(mHue)) { mOutHue = context.getFloat(Utils.idFromNan(mHue)); @@ -118,7 +120,7 @@ public class ColorExpression implements Operation, VariableSupport { } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { if (mMode == 4) { if (Float.isNaN(mHue)) { context.listensTo(Utils.idFromNan(mHue), this); @@ -143,7 +145,7 @@ public class ColorExpression implements Operation, VariableSupport { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { if (mMode == 4) { context.loadColor( mId, (mAlpha << 24) | (0xFFFFFF & Utils.hsvToRgb(mOutHue, mOutSat, mOutValue))); @@ -164,11 +166,12 @@ public class ColorExpression implements Operation, VariableSupport { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { int mode = mMode | (mAlpha << 16); apply(buffer, mId, mode, mColor1, mColor2, mTween); } + @NonNull @Override public String toString() { if (mMode == 4) { @@ -196,6 +199,7 @@ public class ColorExpression implements Operation, VariableSupport { + ")"; } + @NonNull public static String name() { return CLASS_NAME; } @@ -215,7 +219,7 @@ public class ColorExpression implements Operation, VariableSupport { * @param tween */ public static void apply( - WireBuffer buffer, int id, int mode, int color1, int color2, float tween) { + @NonNull WireBuffer buffer, int id, int mode, int color1, int color2, float tween) { buffer.start(OP_CODE); buffer.writeInt(id); buffer.writeInt(mode); @@ -224,7 +228,7 @@ public class ColorExpression implements Operation, VariableSupport { buffer.writeFloat(tween); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int id = buffer.readInt(); int mode = buffer.readInt(); int color1 = buffer.readInt(); @@ -234,7 +238,7 @@ public class ColorExpression implements Operation, VariableSupport { operations.add(new ColorExpression(id, mode, color1, color2, tween)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Expressions Operations", OP_CODE, CLASS_NAME) .description("A Color defined by an expression") .field(DocumentedOperation.INT, "id", "Id of the color") @@ -249,6 +253,7 @@ public class ColorExpression implements Operation, VariableSupport { .field(FLOAT, "tween", "32 bit ARGB color"); } + @NonNull @Override public String deepToString(String indent) { return indent + toString(); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ComponentValue.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ComponentValue.java index 992972076839..142c97b24d2e 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/ComponentValue.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ComponentValue.java @@ -17,6 +17,9 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; +import android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -43,10 +46,12 @@ public class ComponentValue implements Operation, SerializableToString { return OP_CODE; } + @NonNull public static String name() { return CLASS_NAME; } + @NonNull @Override public String toString() { return CLASS_NAME + "(" + mType + ", " + mComponentID + ", " + mValueId + ")"; @@ -65,7 +70,7 @@ public class ComponentValue implements Operation, SerializableToString { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mType, mComponentID, mValueId); } @@ -74,7 +79,7 @@ public class ComponentValue implements Operation, SerializableToString { // Nothing } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int type = buffer.readInt(); int componentId = buffer.readInt(); int valueId = buffer.readInt(); @@ -82,7 +87,7 @@ public class ComponentValue implements Operation, SerializableToString { operations.add(op); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Expressions Operations", OP_CODE, CLASS_NAME) .description("Encode a component-related value (eg its width, height etc.)") .field( @@ -111,20 +116,21 @@ public class ComponentValue implements Operation, SerializableToString { * @param componentId component id to reference * @param valueId remote float used to represent the component value */ - public static void apply(WireBuffer buffer, int type, int componentId, int valueId) { + public static void apply(@NonNull WireBuffer buffer, int type, int componentId, int valueId) { buffer.start(OP_CODE); buffer.writeInt(type); buffer.writeInt(componentId); buffer.writeInt(valueId); } + @Nullable @Override public String deepToString(String indent) { return null; } @Override - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { String type = "WIDTH"; if (mType == HEIGHT) { type = "HEIGHT"; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DataListFloat.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DataListFloat.java index 00758694c254..ba02b91b36ed 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DataListFloat.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DataListFloat.java @@ -18,6 +18,8 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT_ARRAY; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -48,7 +50,7 @@ public class DataListFloat implements VariableSupport, ArrayAccess, Operation { } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { context.addCollection(mId, this); for (float value : mValues) { if (Utils.isVariable(value)) { @@ -58,16 +60,17 @@ public class DataListFloat implements VariableSupport, ArrayAccess, Operation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mId, mValues); } + @NonNull @Override public String toString() { return "DataListFloat[" + Utils.idString(mId) + "] " + Arrays.toString(mValues); } - public static void apply(WireBuffer buffer, int id, float[] values) { + public static void apply(@NonNull WireBuffer buffer, int id, @NonNull float[] values) { buffer.start(OP_CODE); buffer.writeInt(id); buffer.writeInt(values.length); @@ -76,7 +79,7 @@ public class DataListFloat implements VariableSupport, ArrayAccess, Operation { } } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int id = buffer.readInt(); int len = buffer.readInt(); if (len > MAX_FLOAT_ARRAY) { @@ -90,7 +93,7 @@ public class DataListFloat implements VariableSupport, ArrayAccess, Operation { operations.add(data); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Data Operations", OP_CODE, CLASS_NAME) .description("a list of Floats") .field(DocumentedOperation.INT, "id", "id the array (2xxxxx)") @@ -98,13 +101,14 @@ public class DataListFloat implements VariableSupport, ArrayAccess, Operation { .field(FLOAT_ARRAY, "values", "length", "array of floats"); } + @NonNull @Override public String deepToString(String indent) { return indent + toString(); } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { context.addCollection(mId, this); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DataListIds.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DataListIds.java index c43dab4bbee0..b9820f856a92 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DataListIds.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DataListIds.java @@ -18,6 +18,8 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT_ARRAY; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -49,16 +51,17 @@ public class DataListIds implements VariableSupport, ArrayAccess, Operation { public void registerListening(RemoteContext context) {} @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mId, mIds); } + @NonNull @Override public String toString() { return "map[" + Utils.idString(mId) + "] \"" + Arrays.toString(mIds) + "\""; } - public static void apply(WireBuffer buffer, int id, int[] ids) { + public static void apply(@NonNull WireBuffer buffer, int id, @NonNull int[] ids) { buffer.start(OP_CODE); buffer.writeInt(id); buffer.writeInt(ids.length); @@ -67,7 +70,7 @@ public class DataListIds implements VariableSupport, ArrayAccess, Operation { } } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int id = buffer.readInt(); int len = buffer.readInt(); if (len > MAX_LIST) { @@ -81,7 +84,7 @@ public class DataListIds implements VariableSupport, ArrayAccess, Operation { operations.add(data); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Data Operations", OP_CODE, CLASS_NAME) .description("a list of id's") .field(DocumentedOperation.INT, "id", "id the array") @@ -89,13 +92,14 @@ public class DataListIds implements VariableSupport, ArrayAccess, Operation { .field(INT_ARRAY, "ids[n]", "length", "ids of other variables"); } + @NonNull @Override public String deepToString(String indent) { return indent + toString(); } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { context.addCollection(mId, this); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DataMapIds.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DataMapIds.java index 75db29d2781e..fb559bbf1863 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DataMapIds.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DataMapIds.java @@ -18,6 +18,8 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.UTF8; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -64,10 +66,11 @@ public class DataMapIds implements Operation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mId, mDataMap.mNames, mDataMap.mTypes, mDataMap.mIds); } + @NonNull @Override public String toString() { StringBuilder builder = new StringBuilder("DataMapIds[" + Utils.idString(mId) + "] "); @@ -84,7 +87,8 @@ public class DataMapIds implements Operation { return builder.toString(); } - public static void apply(WireBuffer buffer, int id, String[] names, byte[] type, int[] ids) { + public static void apply( + @NonNull WireBuffer buffer, int id, @NonNull String[] names, byte[] type, int[] ids) { buffer.start(OP_CODE); buffer.writeInt(id); buffer.writeInt(names.length); @@ -95,7 +99,7 @@ public class DataMapIds implements Operation { } } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int id = buffer.readInt(); int len = buffer.readInt(); if (len > MAX_MAP) { @@ -113,7 +117,7 @@ public class DataMapIds implements Operation { operations.add(data); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Data Operations", OP_CODE, CLASS_NAME) .description("Encode a collection of name id pairs") .field(INT, "id", "id the array") @@ -122,13 +126,14 @@ public class DataMapIds implements Operation { .field(UTF8, "id[0]", "length", "path encoded as floats"); } + @NonNull @Override public String deepToString(String indent) { return indent + toString(); } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { context.putDataMap(mId, mDataMap); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java index e078307f3bd9..629f78647079 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -28,7 +30,7 @@ public class DrawArc extends DrawBase6 { public static final int OP_CODE = Operations.DRAW_ARC; private static final String CLASS_NAME = "DrawArc"; - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { Maker m = DrawArc::new; read(m, buffer, operations); } @@ -49,7 +51,13 @@ public class DrawArc extends DrawBase6 { * @param v6 Sweep angle (in degrees) measured clockwise */ public static void apply( - WireBuffer buffer, float v1, float v2, float v3, float v4, float v5, float v6) { + @NonNull WireBuffer buffer, + float v1, + float v2, + float v3, + float v4, + float v5, + float v6) { buffer.start(OP_CODE); buffer.writeFloat(v1); buffer.writeFloat(v2); @@ -61,11 +69,17 @@ public class DrawArc extends DrawBase6 { @Override protected void write( - WireBuffer buffer, float v1, float v2, float v3, float v4, float v5, float v6) { + @NonNull WireBuffer buffer, + float v1, + float v2, + float v3, + float v4, + float v5, + float v6) { apply(buffer, v1, v2, v3, v4, v5, v6); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Canvas Operations", OP_CODE, CLASS_NAME) .description( "Draw the specified arc" @@ -90,7 +104,7 @@ public class DrawArc extends DrawBase6 { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.drawArc(mV1, mV2, mV3, mV4, mV5, mV6); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase2.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase2.java index c678cc4a36be..984599e09c19 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase2.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase2.java @@ -17,6 +17,9 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.operations.Utils.floatToString; +import android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.PaintOperation; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -27,7 +30,7 @@ import java.util.List; /** Base class for commands that take 3 float */ public abstract class DrawBase2 extends PaintOperation implements VariableSupport { - protected String mName = "DrawRectBase"; + @NonNull protected String mName = "DrawRectBase"; float mV1; float mV2; float mValue1; @@ -41,13 +44,13 @@ public abstract class DrawBase2 extends PaintOperation implements VariableSuppor } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { mV1 = Float.isNaN(mValue1) ? context.getFloat(Utils.idFromNan(mValue1)) : mValue1; mV2 = Float.isNaN(mValue2) ? context.getFloat(Utils.idFromNan(mValue2)) : mValue2; } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { if (Float.isNaN(mValue1)) { context.listensTo(Utils.idFromNan(mValue1), this); } @@ -67,12 +70,14 @@ public abstract class DrawBase2 extends PaintOperation implements VariableSuppor DrawBase2 create(float v1, float v2); } + @NonNull @Override public String toString() { return mName + " " + floatToString(mV1) + " " + floatToString(mV2); } - public static void read(Maker maker, WireBuffer buffer, List<Operation> operations) { + public static void read( + @NonNull Maker maker, @NonNull WireBuffer buffer, @NonNull List<Operation> operations) { float v1 = buffer.readFloat(); float v2 = buffer.readFloat(); @@ -87,6 +92,7 @@ public abstract class DrawBase2 extends PaintOperation implements VariableSuppor * @param y1 * @return */ + @Nullable public Operation construct(float x1, float y1) { return null; } @@ -99,7 +105,7 @@ public abstract class DrawBase2 extends PaintOperation implements VariableSuppor * @param x1 * @param y1 */ - protected static void write(WireBuffer buffer, int opCode, float x1, float y1) { + protected static void write(@NonNull WireBuffer buffer, int opCode, float x1, float y1) { buffer.start(opCode); buffer.writeFloat(x1); buffer.writeFloat(y1); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase3.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase3.java index e1108e906d8d..825da5240032 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase3.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase3.java @@ -17,6 +17,9 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.operations.Utils.floatToString; +import android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.PaintOperation; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -28,7 +31,7 @@ import java.util.List; /** Base class for commands that take 3 float */ public abstract class DrawBase3 extends PaintOperation implements VariableSupport { - protected String mName = "DrawRectBase"; + @NonNull protected String mName = "DrawRectBase"; float mV1; float mV2; float mV3; @@ -47,14 +50,14 @@ public abstract class DrawBase3 extends PaintOperation implements VariableSuppor } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { mV1 = Utils.isVariable(mValue1) ? context.getFloat(Utils.idFromNan(mValue1)) : mValue1; mV2 = Utils.isVariable(mValue2) ? context.getFloat(Utils.idFromNan(mValue2)) : mValue2; mV3 = Utils.isVariable(mValue3) ? context.getFloat(Utils.idFromNan(mValue3)) : mValue3; } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { if (Utils.isVariable(mValue1)) { context.listensTo(Utils.idFromNan(mValue1), this); } @@ -77,6 +80,7 @@ public abstract class DrawBase3 extends PaintOperation implements VariableSuppor DrawBase3 create(float v1, float v2, float v3); } + @NonNull @Override public String toString() { return mName @@ -88,7 +92,8 @@ public abstract class DrawBase3 extends PaintOperation implements VariableSuppor + floatToString(mV3); } - public static void read(Maker maker, WireBuffer buffer, List<Operation> operations) { + public static void read( + @NonNull Maker maker, @NonNull WireBuffer buffer, @NonNull List<Operation> operations) { float v1 = buffer.readFloat(); float v2 = buffer.readFloat(); float v3 = buffer.readFloat(); @@ -104,6 +109,7 @@ public abstract class DrawBase3 extends PaintOperation implements VariableSuppor * @param x2 * @return */ + @Nullable public Operation construct(float x1, float y1, float x2) { return null; } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase4.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase4.java index 09f0df985b5c..a23bcb9dca78 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase4.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase4.java @@ -17,6 +17,9 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.operations.Utils.floatToString; +import android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.PaintOperation; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -27,7 +30,7 @@ import java.util.List; /** Base class for draw commands that take 4 floats */ public abstract class DrawBase4 extends PaintOperation implements VariableSupport { - protected String mName = "DrawRectBase"; + @NonNull protected String mName = "DrawRectBase"; protected float mX1; protected float mY1; protected float mX2; @@ -50,7 +53,7 @@ public abstract class DrawBase4 extends PaintOperation implements VariableSuppor } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { mX1 = Float.isNaN(mX1Value) ? context.getFloat(Utils.idFromNan(mX1Value)) : mX1Value; mY1 = Float.isNaN(mY1Value) ? context.getFloat(Utils.idFromNan(mY1Value)) : mY1Value; mX2 = Float.isNaN(mX2Value) ? context.getFloat(Utils.idFromNan(mX2Value)) : mX2Value; @@ -58,7 +61,7 @@ public abstract class DrawBase4 extends PaintOperation implements VariableSuppor } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { if (Float.isNaN(mX1Value)) { context.listensTo(Utils.idFromNan(mX1Value), this); } @@ -84,6 +87,7 @@ public abstract class DrawBase4 extends PaintOperation implements VariableSuppor DrawBase4 create(float v1, float v2, float v3, float v4); } + @NonNull @Override public String toString() { return mName @@ -97,7 +101,8 @@ public abstract class DrawBase4 extends PaintOperation implements VariableSuppor + floatToString(mY2Value, mY2); } - public static void read(Maker maker, WireBuffer buffer, List<Operation> operations) { + public static void read( + @NonNull Maker maker, @NonNull WireBuffer buffer, @NonNull List<Operation> operations) { float v1 = buffer.readFloat(); float v2 = buffer.readFloat(); float v3 = buffer.readFloat(); @@ -116,6 +121,7 @@ public abstract class DrawBase4 extends PaintOperation implements VariableSuppor * @param y2 * @return */ + @Nullable public Operation construct(float x1, float y1, float x2, float y2) { return null; } @@ -131,7 +137,7 @@ public abstract class DrawBase4 extends PaintOperation implements VariableSuppor * @param y2 */ protected static void write( - WireBuffer buffer, int opCode, float x1, float y1, float x2, float y2) { + @NonNull WireBuffer buffer, int opCode, float x1, float y1, float x2, float y2) { buffer.start(opCode); buffer.writeFloat(x1); buffer.writeFloat(y1); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase6.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase6.java index e071d5f2096f..68c9f8cdc462 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase6.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase6.java @@ -15,6 +15,9 @@ */ package com.android.internal.widget.remotecompose.core.operations; +import android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.PaintOperation; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -25,7 +28,7 @@ import java.util.List; /** Base class for draw commands the take 6 floats */ public abstract class DrawBase6 extends PaintOperation implements VariableSupport { - protected String mName = "DrawRectBase"; + @NonNull protected String mName = "DrawRectBase"; float mV1; float mV2; float mV3; @@ -56,7 +59,7 @@ public abstract class DrawBase6 extends PaintOperation implements VariableSuppor } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { mV1 = Float.isNaN(mValue1) ? context.getFloat(Utils.idFromNan(mValue1)) : mValue1; mV2 = Float.isNaN(mValue2) ? context.getFloat(Utils.idFromNan(mValue2)) : mValue2; mV3 = Float.isNaN(mValue3) ? context.getFloat(Utils.idFromNan(mValue3)) : mValue3; @@ -66,7 +69,7 @@ public abstract class DrawBase6 extends PaintOperation implements VariableSuppor } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { if (Float.isNaN(mValue1)) { context.listensTo(Utils.idFromNan(mValue1), this); } @@ -95,6 +98,7 @@ public abstract class DrawBase6 extends PaintOperation implements VariableSuppor protected abstract void write( WireBuffer buffer, float v1, float v2, float v3, float v4, float v5, float v6); + @NonNull @Override public String toString() { return mName @@ -112,7 +116,8 @@ public abstract class DrawBase6 extends PaintOperation implements VariableSuppor DrawBase6 create(float v1, float v2, float v3, float v4, float v5, float v6); } - public static void read(Maker build, WireBuffer buffer, List<Operation> operations) { + public static void read( + @NonNull Maker build, @NonNull WireBuffer buffer, @NonNull List<Operation> operations) { float sv1 = buffer.readFloat(); float sv2 = buffer.readFloat(); float sv3 = buffer.readFloat(); @@ -135,10 +140,12 @@ public abstract class DrawBase6 extends PaintOperation implements VariableSuppor * @param v6 * @return */ + @Nullable public Operation construct(float v1, float v2, float v3, float v4, float v5, float v6) { return null; } + @NonNull public static String name() { return "DrawBase6"; } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java index 0b43fd24556a..9c23c9559953 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java @@ -18,6 +18,8 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -54,7 +56,7 @@ public class DrawBitmap extends PaintOperation implements VariableSupport { } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { mOutputLeft = Float.isNaN(mLeft) ? context.getFloat(Utils.idFromNan(mLeft)) : mLeft; mOutputTop = Float.isNaN(mTop) ? context.getFloat(Utils.idFromNan(mTop)) : mTop; mOutputRight = Float.isNaN(mRight) ? context.getFloat(Utils.idFromNan(mRight)) : mRight; @@ -62,7 +64,7 @@ public class DrawBitmap extends PaintOperation implements VariableSupport { } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { if (Float.isNaN(mLeft)) { context.listensTo(Utils.idFromNan(mLeft), this); } @@ -78,10 +80,11 @@ public class DrawBitmap extends PaintOperation implements VariableSupport { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mId, mLeft, mTop, mRight, mBottom, mDescriptionId); } + @NonNull @Override public String toString() { return "DrawBitmap (desc=" @@ -97,7 +100,7 @@ public class DrawBitmap extends PaintOperation implements VariableSupport { + ";"; } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int id = buffer.readInt(); float sLeft = buffer.readFloat(); float srcTop = buffer.readFloat(); @@ -109,6 +112,7 @@ public class DrawBitmap extends PaintOperation implements VariableSupport { operations.add(op); } + @NonNull public static String name() { return CLASS_NAME; } @@ -118,7 +122,7 @@ public class DrawBitmap extends PaintOperation implements VariableSupport { } public static void apply( - WireBuffer buffer, + @NonNull WireBuffer buffer, int id, float left, float top, @@ -134,7 +138,7 @@ public class DrawBitmap extends PaintOperation implements VariableSupport { buffer.writeInt(descriptionId); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Draw Operations", OP_CODE, CLASS_NAME) .description("Draw a bitmap") .field(INT, "id", "id of float") @@ -146,7 +150,7 @@ public class DrawBitmap extends PaintOperation implements VariableSupport { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.drawBitmap(mId, mOutputLeft, mOutputTop, mOutputRight, mOutputBottom); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapInt.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapInt.java index fc7482759369..da9fe247bced 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapInt.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapInt.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -64,7 +66,7 @@ public class DrawBitmapInt extends PaintOperation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply( buffer, mImageId, @@ -79,6 +81,7 @@ public class DrawBitmapInt extends PaintOperation { mContentDescId); } + @NonNull @Override public String toString() { return "DRAW_BITMAP_INT " @@ -103,6 +106,7 @@ public class DrawBitmapInt extends PaintOperation { + ";"; } + @NonNull public static String name() { return CLASS_NAME; } @@ -112,7 +116,7 @@ public class DrawBitmapInt extends PaintOperation { } public static void apply( - WireBuffer buffer, + @NonNull WireBuffer buffer, int imageId, int srcLeft, int srcTop, @@ -136,7 +140,7 @@ public class DrawBitmapInt extends PaintOperation { buffer.writeInt(cdId); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int imageId = buffer.readInt(); int sLeft = buffer.readInt(); int srcTop = buffer.readInt(); @@ -155,7 +159,7 @@ public class DrawBitmapInt extends PaintOperation { operations.add(op); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Draw Operations", OP_CODE, CLASS_NAME) .description("Draw a bitmap using integer coordinates") .field(DocumentedOperation.INT, "id", "id of bitmap") @@ -171,7 +175,7 @@ public class DrawBitmapInt extends PaintOperation { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.drawBitmap( mImageId, mSrcLeft, diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapScaled.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapScaled.java index 22742c63dd2d..e20bcd2d79b5 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapScaled.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapScaled.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -45,7 +47,7 @@ public class DrawBitmapScaled extends PaintOperation implements VariableSupport float mScaleFactor, mOutScaleFactor; int mScaleType; - ImageScaling mScaling = new ImageScaling(); + @NonNull ImageScaling mScaling = new ImageScaling(); public static final int SCALE_NONE = ImageScaling.SCALE_NONE; public static final int SCALE_INSIDE = ImageScaling.SCALE_INSIDE; public static final int SCALE_FILL_WIDTH = ImageScaling.SCALE_FILL_WIDTH; @@ -83,7 +85,7 @@ public class DrawBitmapScaled extends PaintOperation implements VariableSupport } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { mOutSrcLeft = Float.isNaN(mSrcLeft) ? context.getFloat(Utils.idFromNan(mSrcLeft)) : mSrcLeft; mOutSrcTop = Float.isNaN(mSrcTop) ? context.getFloat(Utils.idFromNan(mSrcTop)) : mSrcTop; @@ -109,7 +111,7 @@ public class DrawBitmapScaled extends PaintOperation implements VariableSupport } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { register(context, mSrcLeft); register(context, mSrcTop); register(context, mSrcRight); @@ -121,12 +123,13 @@ public class DrawBitmapScaled extends PaintOperation implements VariableSupport register(context, mScaleFactor); } - private void register(RemoteContext context, float value) { + private void register(@NonNull RemoteContext context, float value) { if (Float.isNaN(value)) { context.listensTo(Utils.idFromNan(value), this); } } + @NonNull static String str(float v) { String s = " " + (int) v; return s.substring(s.length() - 3); @@ -140,7 +143,7 @@ public class DrawBitmapScaled extends PaintOperation implements VariableSupport } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply( buffer, mImageId, @@ -157,6 +160,7 @@ public class DrawBitmapScaled extends PaintOperation implements VariableSupport mContentDescId); } + @NonNull @Override public String toString() { return "DrawBitmapScaled " @@ -185,6 +189,7 @@ public class DrawBitmapScaled extends PaintOperation implements VariableSupport + Utils.floatToString(mScaleFactor, mOutScaleFactor); } + @NonNull public static String name() { return CLASS_NAME; } @@ -194,7 +199,7 @@ public class DrawBitmapScaled extends PaintOperation implements VariableSupport } public static void apply( - WireBuffer buffer, + @NonNull WireBuffer buffer, int imageId, float srcLeft, float srcTop, @@ -225,7 +230,7 @@ public class DrawBitmapScaled extends PaintOperation implements VariableSupport buffer.writeInt(cdId); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int imageId = buffer.readInt(); float sLeft = buffer.readFloat(); @@ -258,7 +263,7 @@ public class DrawBitmapScaled extends PaintOperation implements VariableSupport operations.add(op); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Draw Operations", OP_CODE, CLASS_NAME) .description("Draw a bitmap using integer coordinates") .field(DocumentedOperation.INT, "id", "id of bitmap") @@ -289,7 +294,7 @@ public class DrawBitmapScaled extends PaintOperation implements VariableSupport // } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { mScaling.setup( mOutSrcLeft, mOutSrcTop, diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java index 04f095af29dc..11bd49a4a651 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -28,7 +30,7 @@ public class DrawCircle extends DrawBase3 { private static final int OP_CODE = Operations.DRAW_CIRCLE; private static final String CLASS_NAME = "DrawCircle"; - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { Maker m = DrawCircle::new; read(m, buffer, operations); } @@ -37,11 +39,12 @@ public class DrawCircle extends DrawBase3 { return OP_CODE; } + @NonNull public static String name() { return CLASS_NAME; } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Canvas Operations", OP_CODE, CLASS_NAME) .description("Draw a Circle") .field( @@ -56,7 +59,7 @@ public class DrawCircle extends DrawBase3 { } @Override - protected void write(WireBuffer buffer, float v1, float v2, float v3) { + protected void write(@NonNull WireBuffer buffer, float v1, float v2, float v3) { apply(buffer, v1, v2, v3); } @@ -66,7 +69,7 @@ public class DrawCircle extends DrawBase3 { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.drawCircle(mV1, mV2, mV3); } @@ -78,7 +81,7 @@ public class DrawCircle extends DrawBase3 { * @param y1 * @param x2 */ - public static void apply(WireBuffer buffer, float x1, float y1, float x2) { + public static void apply(@NonNull WireBuffer buffer, float x1, float y1, float x2) { buffer.start(OP_CODE); buffer.writeFloat(x1); buffer.writeFloat(y1); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java index dacbb0361761..7310a9defba6 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -30,7 +32,7 @@ public class DrawLine extends DrawBase4 implements SerializableToString { private static final int OP_CODE = Operations.DRAW_LINE; private static final String CLASS_NAME = "DrawLine"; - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { Maker m = DrawLine::new; read(m, buffer, operations); } @@ -39,11 +41,12 @@ public class DrawLine extends DrawBase4 implements SerializableToString { return OP_CODE; } + @NonNull public static String name() { return CLASS_NAME; } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Canvas Operations", OP_CODE, CLASS_NAME) .description("Draw a line segment") .field( @@ -65,7 +68,7 @@ public class DrawLine extends DrawBase4 implements SerializableToString { } @Override - protected void write(WireBuffer buffer, float v1, float v2, float v3, float v4) { + protected void write(@NonNull WireBuffer buffer, float v1, float v2, float v3, float v4) { apply(buffer, v1, v2, v3, v4); } @@ -75,7 +78,7 @@ public class DrawLine extends DrawBase4 implements SerializableToString { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.drawLine(mX1, mY1, mX2, mY2); } @@ -88,12 +91,12 @@ public class DrawLine extends DrawBase4 implements SerializableToString { * @param x2 end x of the line * @param y2 end y of the line */ - public static void apply(WireBuffer buffer, float x1, float y1, float x2, float y2) { + public static void apply(@NonNull WireBuffer buffer, float x1, float y1, float x2, float y2) { write(buffer, OP_CODE, x1, y1, x2, y2); } @Override - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { String x1 = "" + mX1; if (Float.isNaN(mX1Value)) { x1 = "[" + Utils.idFromNan(mX1Value) + " = " + mX1 + "]"; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java index 5d498e81c9d2..aa5116e950c5 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -28,7 +30,7 @@ public class DrawOval extends DrawBase4 { private static final int OP_CODE = Operations.DRAW_OVAL; private static final String CLASS_NAME = "DrawOval"; - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { Maker m = DrawOval::new; read(m, buffer, operations); } @@ -37,11 +39,12 @@ public class DrawOval extends DrawBase4 { return OP_CODE; } + @NonNull public static String name() { return CLASS_NAME; } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Canvas Operations", OP_CODE, CLASS_NAME) .description("Draw the specified oval") .field(DocumentedOperation.FLOAT, "left", "The left side of the oval") @@ -51,12 +54,12 @@ public class DrawOval extends DrawBase4 { } @Override - protected void write(WireBuffer buffer, float v1, float v2, float v3, float v4) { + protected void write(@NonNull WireBuffer buffer, float v1, float v2, float v3, float v4) { apply(buffer, v1, v2, v3, v4); } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mX1, mY1, mX2, mY2); } @@ -66,7 +69,7 @@ public class DrawOval extends DrawBase4 { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.drawOval(mX1, mY1, mX2, mY2); } @@ -79,7 +82,7 @@ public class DrawOval extends DrawBase4 { * @param x2 end x of the DrawOval * @param y2 end y of the DrawOval */ - public static void apply(WireBuffer buffer, float x1, float y1, float x2, float y2) { + public static void apply(@NonNull WireBuffer buffer, float x1, float y1, float x2, float y2) { write(buffer, OP_CODE, x1, y1, x2, y2); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java index ccbf3d9e3091..d35094b0b351 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -38,21 +40,23 @@ public class DrawPath extends PaintOperation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mId); } + @NonNull @Override public String toString() { return "DrawPath " + "[" + mId + "]" + ", " + mStart + ", " + mEnd; } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int id = buffer.readInt(); DrawPath op = new DrawPath(id); operations.add(op); } + @NonNull public static String name() { return CLASS_NAME; } @@ -61,19 +65,19 @@ public class DrawPath extends PaintOperation { return Operations.DRAW_PATH; } - public static void apply(WireBuffer buffer, int id) { + public static void apply(@NonNull WireBuffer buffer, int id) { buffer.start(Operations.DRAW_PATH); buffer.writeInt(id); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Draw Operations", OP_CODE, CLASS_NAME) .description("Draw a bitmap using integer coordinates") .field(DocumentedOperation.INT, "id", "id of path"); } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.drawPath(mId, mStart, mEnd); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java index 644011b8a214..db7633cbe335 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -29,7 +31,7 @@ public class DrawRect extends DrawBase4 { private static final int OP_CODE = Operations.DRAW_RECT; private static final String CLASS_NAME = "DrawRect"; - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { Maker m = DrawRect::new; read(m, buffer, operations); } @@ -38,11 +40,12 @@ public class DrawRect extends DrawBase4 { return OP_CODE; } + @NonNull public static String name() { return CLASS_NAME; } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Canvas Operations", OP_CODE, CLASS_NAME) .description("Draw the specified rectangle") .field(DocumentedOperation.FLOAT, "left", "The left side of the rectangle") @@ -52,7 +55,7 @@ public class DrawRect extends DrawBase4 { } @Override - protected void write(WireBuffer buffer, float v1, float v2, float v3, float v4) { + protected void write(@NonNull WireBuffer buffer, float v1, float v2, float v3, float v4) { apply(buffer, v1, v2, v3, v4); } @@ -62,7 +65,7 @@ public class DrawRect extends DrawBase4 { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.drawRect(mX1, mY1, mX2, mY2); } @@ -75,7 +78,7 @@ public class DrawRect extends DrawBase4 { * @param x2 right x of the rect * @param y2 bottom y of the rect */ - public static void apply(WireBuffer buffer, float x1, float y1, float x2, float y2) { + public static void apply(@NonNull WireBuffer buffer, float x1, float y1, float x2, float y2) { write(buffer, OP_CODE, x1, y1, x2, y2); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRoundRect.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRoundRect.java index 64a3b283505b..c306e2b5f041 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRoundRect.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRoundRect.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -29,7 +31,7 @@ public class DrawRoundRect extends DrawBase6 { private static final int OP_CODE = Operations.DRAW_ROUND_RECT; private static final String CLASS_NAME = "DrawRoundRect"; - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { Maker m = DrawRoundRect::new; read(m, buffer, operations); } @@ -50,7 +52,13 @@ public class DrawRoundRect extends DrawBase6 { * @param v6 The y-radius of the oval used to round the corners */ public static void apply( - WireBuffer buffer, float v1, float v2, float v3, float v4, float v5, float v6) { + @NonNull WireBuffer buffer, + float v1, + float v2, + float v3, + float v4, + float v5, + float v6) { buffer.start(OP_CODE); buffer.writeFloat(v1); buffer.writeFloat(v2); @@ -62,11 +70,17 @@ public class DrawRoundRect extends DrawBase6 { @Override protected void write( - WireBuffer buffer, float v1, float v2, float v3, float v4, float v5, float v6) { + @NonNull WireBuffer buffer, + float v1, + float v2, + float v3, + float v4, + float v5, + float v6) { apply(buffer, v1, v2, v3, v4, v5, v6); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Canvas Operations", OP_CODE, CLASS_NAME) .description("Draw the specified round-rect") .field(DocumentedOperation.FLOAT, "left", "The left side of the rect") @@ -89,7 +103,7 @@ public class DrawRoundRect extends DrawBase6 { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.drawRoundRect(mV1, mV2, mV3, mV4, mV5, mV6); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawSector.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawSector.java index 3cb191647c33..3b60df7d529e 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawSector.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawSector.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -28,7 +30,7 @@ public class DrawSector extends DrawBase6 { public static final int OP_CODE = Operations.DRAW_SECTOR; private static final String CLASS_NAME = "DrawSector"; - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { Maker m = DrawSector::new; read(m, buffer, operations); } @@ -49,7 +51,13 @@ public class DrawSector extends DrawBase6 { * @param v6 Sweep angle (in degrees) measured clockwise */ public static void apply( - WireBuffer buffer, float v1, float v2, float v3, float v4, float v5, float v6) { + @NonNull WireBuffer buffer, + float v1, + float v2, + float v3, + float v4, + float v5, + float v6) { buffer.start(OP_CODE); buffer.writeFloat(v1); buffer.writeFloat(v2); @@ -61,11 +69,17 @@ public class DrawSector extends DrawBase6 { @Override protected void write( - WireBuffer buffer, float v1, float v2, float v3, float v4, float v5, float v6) { + @NonNull WireBuffer buffer, + float v1, + float v2, + float v3, + float v4, + float v5, + float v6) { apply(buffer, v1, v2, v3, v4, v5, v6); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Canvas Operations", OP_CODE, CLASS_NAME) .description( "Draw the specified sector (pie shape)" @@ -90,7 +104,7 @@ public class DrawSector extends DrawBase6 { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.drawSector(mV1, mV2, mV3, mV4, mV5, mV6); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java index bcb7852e6615..9c587aba3f7b 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java @@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.operations.Utils.floatToString; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -64,13 +66,13 @@ public class DrawText extends PaintOperation implements VariableSupport { } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { mOutX = Float.isNaN(mX) ? context.getFloat(Utils.idFromNan(mX)) : mX; mOutY = Float.isNaN(mY) ? context.getFloat(Utils.idFromNan(mY)) : mY; } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { if (Float.isNaN(mX)) { context.listensTo(Utils.idFromNan(mX), this); } @@ -80,10 +82,11 @@ public class DrawText extends PaintOperation implements VariableSupport { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mTextID, mStart, mEnd, mContextStart, mContextEnd, mX, mY, mRtl); } + @NonNull @Override public String toString() { return "DrawTextRun [" @@ -98,7 +101,7 @@ public class DrawText extends PaintOperation implements VariableSupport { + floatToString(mY, mOutY); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int text = buffer.readInt(); int start = buffer.readInt(); int end = buffer.readInt(); @@ -112,6 +115,7 @@ public class DrawText extends PaintOperation implements VariableSupport { operations.add(op); } + @NonNull public static String name() { return CLASS_NAME; } @@ -134,7 +138,7 @@ public class DrawText extends PaintOperation implements VariableSupport { * @param rtl is it Right to Left text */ public static void apply( - WireBuffer buffer, + @NonNull WireBuffer buffer, int textID, int start, int end, @@ -154,7 +158,7 @@ public class DrawText extends PaintOperation implements VariableSupport { buffer.writeBoolean(rtl); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Draw Operations", id(), CLASS_NAME) .description("Draw a run of text, all in a single direction") .field(DocumentedOperation.INT, "textId", "id of bitmap") @@ -177,7 +181,7 @@ public class DrawText extends PaintOperation implements VariableSupport { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.drawTextRun(mTextID, mStart, mEnd, mContextStart, mContextEnd, mOutX, mOutY, mRtl); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java index 95a87667dfab..8b7018191f4d 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -57,7 +59,7 @@ public class DrawTextAnchored extends PaintOperation implements VariableSupport } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { mOutX = Float.isNaN(mX) ? context.getFloat(Utils.idFromNan(mX)) : mX; mOutY = Float.isNaN(mY) ? context.getFloat(Utils.idFromNan(mY)) : mY; mOutPanX = Float.isNaN(mPanX) ? context.getFloat(Utils.idFromNan(mPanX)) : mPanX; @@ -65,7 +67,7 @@ public class DrawTextAnchored extends PaintOperation implements VariableSupport } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { if (Float.isNaN(mX)) { context.listensTo(Utils.idFromNan(mX), this); } @@ -81,10 +83,11 @@ public class DrawTextAnchored extends PaintOperation implements VariableSupport } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mTextID, mX, mY, mPanX, mPanY, mFlags); } + @NonNull @Override public String toString() { return "DrawTextAnchored [" @@ -108,7 +111,7 @@ public class DrawTextAnchored extends PaintOperation implements VariableSupport return Float.toString(v); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int textID = buffer.readInt(); float x = buffer.readFloat(); float y = buffer.readFloat(); @@ -121,6 +124,7 @@ public class DrawTextAnchored extends PaintOperation implements VariableSupport operations.add(op); } + @NonNull public static String name() { return CLASS_NAME; } @@ -141,7 +145,13 @@ public class DrawTextAnchored extends PaintOperation implements VariableSupport * @param flags Change the behaviour */ public static void apply( - WireBuffer buffer, int textID, float x, float y, float panX, float panY, int flags) { + @NonNull WireBuffer buffer, + int textID, + float x, + float y, + float panX, + float panY, + int flags) { buffer.start(OP_CODE); buffer.writeInt(textID); buffer.writeFloat(x); @@ -151,7 +161,7 @@ public class DrawTextAnchored extends PaintOperation implements VariableSupport buffer.writeInt(flags); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Draw Operations", OP_CODE, CLASS_NAME) .description("Draw text centered about an anchor point") .field(DocumentedOperation.INT, "textId", "id of bitmap") @@ -168,7 +178,7 @@ public class DrawTextAnchored extends PaintOperation implements VariableSupport .field(DocumentedOperation.INT, "flags", "Change the behaviour"); } - float[] mBounds = new float[4]; + @NonNull float[] mBounds = new float[4]; private float getHorizontalOffset() { // TODO scale TextSize / BaseTextSize; @@ -188,7 +198,7 @@ public class DrawTextAnchored extends PaintOperation implements VariableSupport } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { int flags = ((mFlags & ANCHOR_MONOSPACE_MEASURE) != 0) ? PaintContext.TEXT_MEASURE_MONOSPACE_WIDTH diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java index aefd6f397ebf..e90122bb95ac 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -46,7 +48,7 @@ public class DrawTextOnPath extends PaintOperation implements VariableSupport { } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { mOutHOffset = Float.isNaN(mHOffset) ? context.getFloat(Utils.idFromNan(mHOffset)) : mHOffset; mOutVOffset = @@ -54,7 +56,7 @@ public class DrawTextOnPath extends PaintOperation implements VariableSupport { } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { if (Float.isNaN(mHOffset)) { context.listensTo(Utils.idFromNan(mHOffset), this); } @@ -64,10 +66,11 @@ public class DrawTextOnPath extends PaintOperation implements VariableSupport { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mTextId, mPathId, mHOffset, mVOffset); } + @NonNull @Override public String toString() { return "DrawTextOnPath [" @@ -80,7 +83,7 @@ public class DrawTextOnPath extends PaintOperation implements VariableSupport { + Utils.floatToString(mVOffset, mOutVOffset); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int textId = buffer.readInt(); int pathId = buffer.readInt(); float vOffset = buffer.readFloat(); @@ -89,6 +92,7 @@ public class DrawTextOnPath extends PaintOperation implements VariableSupport { operations.add(op); } + @NonNull public static String name() { return "DrawTextOnPath"; } @@ -98,7 +102,7 @@ public class DrawTextOnPath extends PaintOperation implements VariableSupport { } public static void apply( - WireBuffer buffer, int textId, int pathId, float hOffset, float vOffset) { + @NonNull WireBuffer buffer, int textId, int pathId, float hOffset, float vOffset) { buffer.start(OP_CODE); buffer.writeInt(textId); buffer.writeInt(pathId); @@ -106,7 +110,7 @@ public class DrawTextOnPath extends PaintOperation implements VariableSupport { buffer.writeFloat(hOffset); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Draw Operations", OP_CODE, CLASS_NAME) .description("Draw text along path object") .field(DocumentedOperation.INT, "textId", "id of the text") @@ -116,7 +120,7 @@ public class DrawTextOnPath extends PaintOperation implements VariableSupport { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.drawTextOnPath(mTextId, mPathId, mOutHOffset, mOutVOffset); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java index b6d45d95f2c0..0aaaf42ba838 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java @@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.operations.Utils.floatToString; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -50,14 +52,14 @@ public class DrawTweenPath extends PaintOperation implements VariableSupport { } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { mOutTween = Float.isNaN(mTween) ? context.getFloat(Utils.idFromNan(mTween)) : mTween; mOutStart = Float.isNaN(mStart) ? context.getFloat(Utils.idFromNan(mStart)) : mStart; mOutStop = Float.isNaN(mStop) ? context.getFloat(Utils.idFromNan(mStop)) : mStop; } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { if (Float.isNaN(mTween)) { context.listensTo(Utils.idFromNan(mTween), this); } @@ -70,10 +72,11 @@ public class DrawTweenPath extends PaintOperation implements VariableSupport { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mPath1Id, mPath2Id, mTween, mStart, mStop); } + @NonNull @Override public String toString() { return "DrawTweenPath " @@ -89,7 +92,7 @@ public class DrawTweenPath extends PaintOperation implements VariableSupport { + floatToString(mStop, mOutStop); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int path1Id = buffer.readInt(); int path2Id = buffer.readInt(); float tween = buffer.readFloat(); @@ -99,6 +102,7 @@ public class DrawTweenPath extends PaintOperation implements VariableSupport { operations.add(op); } + @NonNull public static String name() { return "DrawTweenPath"; } @@ -108,7 +112,12 @@ public class DrawTweenPath extends PaintOperation implements VariableSupport { } public static void apply( - WireBuffer buffer, int path1Id, int path2Id, float tween, float start, float stop) { + @NonNull WireBuffer buffer, + int path1Id, + int path2Id, + float tween, + float start, + float stop) { buffer.start(OP_CODE); buffer.writeInt(path1Id); buffer.writeInt(path2Id); @@ -117,7 +126,7 @@ public class DrawTweenPath extends PaintOperation implements VariableSupport { buffer.writeFloat(stop); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Draw Operations", OP_CODE, CLASS_NAME) .description("Draw text along path object") .field(DocumentedOperation.INT, "pathId1", "id of path 1") @@ -128,7 +137,7 @@ public class DrawTweenPath extends PaintOperation implements VariableSupport { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.drawTweenPath(mPath1Id, mPath2Id, mOutTween, mOutStart, mOutStop); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java index 765e150e81af..89390acb8c50 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java @@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -39,15 +41,17 @@ public class FloatConstant implements com.android.internal.widget.remotecompose. } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mTextId, mValue); } + @NonNull @Override public String toString() { return "FloatConstant[" + mTextId + "] = " + mValue; } + @NonNull public static String name() { return CLASS_NAME; } @@ -63,20 +67,20 @@ public class FloatConstant implements com.android.internal.widget.remotecompose. * @param id the id * @param value the value of the float */ - public static void apply(WireBuffer buffer, int id, float value) { + public static void apply(@NonNull WireBuffer buffer, int id, float value) { buffer.start(OP_CODE); buffer.writeInt(id); buffer.writeFloat(value); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int textId = buffer.readInt(); float value = buffer.readFloat(); operations.add(new FloatConstant(textId, value)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Expressions Operations", OP_CODE, CLASS_NAME) .description("A float and its associated id") .field(DocumentedOperation.INT, "id", "id of float") @@ -84,10 +88,11 @@ public class FloatConstant implements com.android.internal.widget.remotecompose. } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { context.loadFloat(mTextId, mValue); } + @NonNull @Override public String deepToString(String indent) { return indent + toString(); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java index d71793364a33..e1c6c2577860 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java @@ -20,6 +20,9 @@ import static com.android.internal.widget.remotecompose.core.documentation.Docum import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.SHORT; +import android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -48,7 +51,7 @@ public class FloatExpression implements Operation, VariableSupport { public float[] mPreCalcValue; private float mLastChange = Float.NaN; private float mLastCalculatedValue = Float.NaN; - AnimatedFloatExpression mExp = new AnimatedFloatExpression(); + @NonNull AnimatedFloatExpression mExp = new AnimatedFloatExpression(); public static final int MAX_EXPRESSION_SIZE = 32; public FloatExpression(int id, float[] value, float[] animation) { @@ -61,7 +64,7 @@ public class FloatExpression implements Operation, VariableSupport { } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { if (mPreCalcValue == null || mPreCalcValue.length != mSrcValue.length) { mPreCalcValue = new float[mSrcValue.length]; } @@ -107,7 +110,7 @@ public class FloatExpression implements Operation, VariableSupport { } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { for (float v : mSrcValue) { if (Float.isNaN(v) && !AnimatedFloatExpression.isMathOperator(v) @@ -118,7 +121,7 @@ public class FloatExpression implements Operation, VariableSupport { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { updateVariables(context); float t = context.getAnimationTime(); if (Float.isNaN(mLastChange)) { @@ -135,10 +138,11 @@ public class FloatExpression implements Operation, VariableSupport { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mId, mSrcValue, mSrcAnimation); } + @NonNull @Override public String toString() { String[] labels = new String[mSrcValue.length]; @@ -161,6 +165,7 @@ public class FloatExpression implements Operation, VariableSupport { + ")"; } + @NonNull public static String name() { return CLASS_NAME; } @@ -177,7 +182,11 @@ public class FloatExpression implements Operation, VariableSupport { * @param value the float expression array * @param animation the animation expression array */ - public static void apply(WireBuffer buffer, int id, float[] value, float[] animation) { + public static void apply( + @NonNull WireBuffer buffer, + int id, + @NonNull float[] value, + @Nullable float[] animation) { buffer.start(OP_CODE); buffer.writeInt(id); @@ -197,7 +206,7 @@ public class FloatExpression implements Operation, VariableSupport { } } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int id = buffer.readInt(); int len = buffer.readInt(); int valueLen = len & 0xFFFF; @@ -222,7 +231,7 @@ public class FloatExpression implements Operation, VariableSupport { operations.add(new FloatExpression(id, values, animation)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Expressions Operations", OP_CODE, CLASS_NAME) .description("A Float expression") .field(DocumentedOperation.INT, "id", "The id of the Color") @@ -245,6 +254,7 @@ public class FloatExpression implements Operation, VariableSupport { .field(FLOAT, "wrapValue", "> [Wrap value] "); } + @NonNull @Override public String deepToString(String indent) { return indent + toString(); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/Header.java b/core/java/com/android/internal/widget/remotecompose/core/operations/Header.java index 4f8516f5235d..1979bc5f4331 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/Header.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/Header.java @@ -18,6 +18,8 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.LONG; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteComposeOperation; @@ -80,10 +82,11 @@ public class Header implements RemoteComposeOperation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mWidth, mHeight, mDensity, mCapabilities); } + @NonNull @Override public String toString() { return "HEADER v" @@ -102,15 +105,17 @@ public class Header implements RemoteComposeOperation { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { context.header(mMajorVersion, mMinorVersion, mPatchVersion, mWidth, mHeight, mCapabilities); } + @NonNull @Override public String deepToString(String indent) { return toString(); } + @NonNull public static String name() { return CLASS_NAME; } @@ -120,7 +125,7 @@ public class Header implements RemoteComposeOperation { } public static void apply( - WireBuffer buffer, int width, int height, float density, long capabilities) { + @NonNull WireBuffer buffer, int width, int height, float density, long capabilities) { buffer.start(OP_CODE); buffer.writeInt(MAJOR_VERSION); // major version number of the protocol buffer.writeInt(MINOR_VERSION); // minor version number of the protocol @@ -131,7 +136,7 @@ public class Header implements RemoteComposeOperation { buffer.writeLong(capabilities); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int majorVersion = buffer.readInt(); int minorVersion = buffer.readInt(); int patchVersion = buffer.readInt(); @@ -152,7 +157,7 @@ public class Header implements RemoteComposeOperation { operations.add(header); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Protocol Operations", OP_CODE, CLASS_NAME) .description( "Document metadata, containing the version," diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/IntegerExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/IntegerExpression.java index c9a850875011..6375f001c818 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/IntegerExpression.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/IntegerExpression.java @@ -18,6 +18,8 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT_ARRAY; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -45,7 +47,7 @@ public class IntegerExpression implements Operation, VariableSupport { public int[] mPreCalcValue; private float mLastChange = Float.NaN; public static final int MAX_SIZE = 320; - IntegerExpressionEvaluator mExp = new IntegerExpressionEvaluator(); + @NonNull IntegerExpressionEvaluator mExp = new IntegerExpressionEvaluator(); public IntegerExpression(int id, int mask, int[] value) { this.mId = id; @@ -54,7 +56,7 @@ public class IntegerExpression implements Operation, VariableSupport { } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { if (mPreCalcValue == null || mPreCalcValue.length != mSrcValue.length) { mPreCalcValue = new int[mSrcValue.length]; } @@ -70,7 +72,7 @@ public class IntegerExpression implements Operation, VariableSupport { } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { for (int i = 0; i < mSrcValue.length; i++) { if (isId(mMask, i, mSrcValue[i])) { context.listensTo(mSrcValue[i], this); @@ -79,7 +81,7 @@ public class IntegerExpression implements Operation, VariableSupport { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { updateVariables(context); float t = context.getAnimationTime(); if (Float.isNaN(mLastChange)) { @@ -95,7 +97,7 @@ public class IntegerExpression implements Operation, VariableSupport { * @param context current context * @return the resulting value */ - public int evaluate(RemoteContext context) { + public int evaluate(@NonNull RemoteContext context) { updateVariables(context); float t = context.getAnimationTime(); if (Float.isNaN(mLastChange)) { @@ -105,10 +107,11 @@ public class IntegerExpression implements Operation, VariableSupport { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mId, mMask, mSrcValue); } + @NonNull @Override public String toString() { StringBuilder s = new StringBuilder(); @@ -132,6 +135,7 @@ public class IntegerExpression implements Operation, VariableSupport { return "IntegerExpression[" + mId + "] = (" + s + ")"; } + @NonNull public static String name() { return CLASS_NAME; } @@ -148,7 +152,7 @@ public class IntegerExpression implements Operation, VariableSupport { * @param mask the mask bits of ints & operators or variables * @param value array of integers to be evaluated */ - public static void apply(WireBuffer buffer, int id, int mask, int[] value) { + public static void apply(@NonNull WireBuffer buffer, int id, int mask, @NonNull int[] value) { buffer.start(OP_CODE); buffer.writeInt(id); buffer.writeInt(mask); @@ -158,7 +162,7 @@ public class IntegerExpression implements Operation, VariableSupport { } } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int id = buffer.readInt(); int mask = buffer.readInt(); int len = buffer.readInt(); @@ -173,7 +177,7 @@ public class IntegerExpression implements Operation, VariableSupport { operations.add(new IntegerExpression(id, mask, values)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Data Operations", OP_CODE, CLASS_NAME) .description("Expression that computes an integer") .field(DocumentedOperation.INT, "id", "id of integer") @@ -182,6 +186,7 @@ public class IntegerExpression implements Operation, VariableSupport { .field(INT_ARRAY, "values", "length", "Array of ints"); } + @NonNull @Override public String deepToString(String indent) { return indent + toString(); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java index 04f8a503adff..6a620e58570a 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -31,20 +33,22 @@ public class MatrixRestore extends PaintOperation { public MatrixRestore() {} @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(WireBuffer buffer, @NonNull List<Operation> operations) { MatrixRestore op = new MatrixRestore(); operations.add(op); } + @NonNull @Override public String toString() { return "MatrixRestore"; } + @NonNull public static String name() { return CLASS_NAME; } @@ -53,17 +57,17 @@ public class MatrixRestore extends PaintOperation { return OP_CODE; } - public static void apply(WireBuffer buffer) { + public static void apply(@NonNull WireBuffer buffer) { buffer.start(OP_CODE); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Canvas Operations", OP_CODE, CLASS_NAME) .description("Restore the matrix and clip"); } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.matrixRestore(); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java index df10f329630a..438a2aad648a 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -28,9 +30,10 @@ public class MatrixRotate extends DrawBase3 { public static final int OP_CODE = Operations.MATRIX_ROTATE; private static final String CLASS_NAME = "MatrixRotate"; - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { Maker m = new Maker() { + @NonNull @Override public DrawBase3 create(float v1, float v2, float v3) { return new MatrixRotate(v1, v2, v3); @@ -43,11 +46,12 @@ public class MatrixRotate extends DrawBase3 { return OP_CODE; } + @NonNull public static String name() { return CLASS_NAME; } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Canvas Operations", OP_CODE, CLASS_NAME) .description("apply rotation to matrix") .field(DocumentedOperation.FLOAT, "rotate", "Angle to rotate") @@ -56,7 +60,7 @@ public class MatrixRotate extends DrawBase3 { } @Override - protected void write(WireBuffer buffer, float v1, float v2, float v3) { + protected void write(@NonNull WireBuffer buffer, float v1, float v2, float v3) { apply(buffer, v1, v2, v3); } @@ -66,7 +70,7 @@ public class MatrixRotate extends DrawBase3 { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.matrixRotate(mV1, mV2, mV3); } @@ -78,7 +82,7 @@ public class MatrixRotate extends DrawBase3 { * @param y1 X Pivot point * @param x2 Y Pivot point */ - public static void apply(WireBuffer buffer, float x1, float y1, float x2) { + public static void apply(@NonNull WireBuffer buffer, float x1, float y1, float x2) { buffer.start(OP_CODE); buffer.writeFloat(x1); buffer.writeFloat(y1); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSave.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSave.java index 67612c7fd2f4..1880b19be1a7 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSave.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSave.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -29,20 +31,22 @@ public class MatrixSave extends PaintOperation { private static final String CLASS_NAME = "MatrixSave"; @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer); } + @NonNull @Override public String toString() { return "MatrixSave;"; } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(WireBuffer buffer, @NonNull List<Operation> operations) { MatrixSave op = new MatrixSave(); operations.add(op); } + @NonNull public static String name() { return CLASS_NAME; } @@ -51,17 +55,17 @@ public class MatrixSave extends PaintOperation { return OP_CODE; } - public static void apply(WireBuffer buffer) { + public static void apply(@NonNull WireBuffer buffer) { buffer.start(Operations.MATRIX_SAVE); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Canvas Operations", OP_CODE, CLASS_NAME) .description("Save the matrix and clip to a stack"); } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.matrixSave(); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java index 26c898acb67b..630458499977 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -28,7 +30,7 @@ public class MatrixScale extends DrawBase4 { public static final int OP_CODE = Operations.MATRIX_SCALE; public static final String CLASS_NAME = "MatrixScale"; - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { Maker m = MatrixScale::new; read(m, buffer, operations); } @@ -37,16 +39,17 @@ public class MatrixScale extends DrawBase4 { return OP_CODE; } + @NonNull public static String name() { return CLASS_NAME; } @Override - protected void write(WireBuffer buffer, float v1, float v2, float v3, float v4) { + protected void write(@NonNull WireBuffer buffer, float v1, float v2, float v3, float v4) { apply(buffer, v1, v2, v3, v4); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Canvas Operations", OP_CODE, CLASS_NAME) .description("Draw the specified Oval") .field(DocumentedOperation.FLOAT, "scaleX", "The amount to scale in X") @@ -61,7 +64,7 @@ public class MatrixScale extends DrawBase4 { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.matrixScale(mX1, mY1, mX2, mY2); } @@ -74,7 +77,7 @@ public class MatrixScale extends DrawBase4 { * @param x2 end x of the DrawOval * @param y2 end y of the DrawOval */ - public static void apply(WireBuffer buffer, float x1, float y1, float x2, float y2) { + public static void apply(@NonNull WireBuffer buffer, float x1, float y1, float x2, float y2) { write(buffer, OP_CODE, x1, y1, x2, y2); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSkew.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSkew.java index d64117871eaa..675cf0de4743 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSkew.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSkew.java @@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -29,7 +31,7 @@ public class MatrixSkew extends DrawBase2 { public static final int OP_CODE = Operations.MATRIX_SKEW; public static final String CLASS_NAME = "MatrixSkew"; - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { Maker m = MatrixSkew::new; read(m, buffer, operations); } @@ -38,16 +40,17 @@ public class MatrixSkew extends DrawBase2 { return OP_CODE; } + @NonNull public static String name() { return CLASS_NAME; } @Override - protected void write(WireBuffer buffer, float v1, float v2) { + protected void write(@NonNull WireBuffer buffer, float v1, float v2) { apply(buffer, v1, v2); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Canvas Operations", OP_CODE, CLASS_NAME) .description("Current matrix with the specified skew.") .field(FLOAT, "skewX", "The amount to skew in X") @@ -60,7 +63,7 @@ public class MatrixSkew extends DrawBase2 { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.matrixSkew(mV1, mV2); } @@ -71,7 +74,7 @@ public class MatrixSkew extends DrawBase2 { * @param x1 start x of DrawOval * @param y1 start y of the DrawOval */ - public static void apply(WireBuffer buffer, float x1, float y1) { + public static void apply(@NonNull WireBuffer buffer, float x1, float y1) { write(buffer, OP_CODE, x1, y1); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java index e008292f1107..b0a7d352dfe3 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -28,7 +30,7 @@ public class MatrixTranslate extends DrawBase2 { public static final int OP_CODE = Operations.MATRIX_TRANSLATE; public static final String CLASS_NAME = "MatrixTranslate"; - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { Maker m = MatrixTranslate::new; read(m, buffer, operations); } @@ -37,16 +39,17 @@ public class MatrixTranslate extends DrawBase2 { return OP_CODE; } + @NonNull public static String name() { return CLASS_NAME; } @Override - protected void write(WireBuffer buffer, float v1, float v2) { + protected void write(@NonNull WireBuffer buffer, float v1, float v2) { apply(buffer, v1, v2); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Canvas Operations", OP_CODE, "MatrixTranslate") .description("Preconcat the current matrix with the specified translation") .field(DocumentedOperation.FLOAT, "dx", "The distance to translate in X") @@ -59,7 +62,7 @@ public class MatrixTranslate extends DrawBase2 { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.matrixTranslate(mV1, mV2); } @@ -70,7 +73,7 @@ public class MatrixTranslate extends DrawBase2 { * @param x1 start x of DrawOval * @param y1 start y of the DrawOval */ - public static void apply(WireBuffer buffer, float x1, float y1) { + public static void apply(@NonNull WireBuffer buffer, float x1, float y1) { write(buffer, OP_CODE, x1, y1); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java b/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java index fa6e2712a0bb..6310521e4010 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java @@ -18,6 +18,8 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.UTF8; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -47,10 +49,11 @@ public class NamedVariable implements Operation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mVarId, mVarType, mVarName); } + @NonNull @Override public String toString() { return "VariableName[" @@ -61,6 +64,7 @@ public class NamedVariable implements Operation { + mVarType; } + @NonNull public static String name() { return CLASS_NAME; } @@ -77,21 +81,22 @@ public class NamedVariable implements Operation { * @param varType The type of variable * @param text String */ - public static void apply(WireBuffer buffer, int varId, int varType, String text) { + public static void apply( + @NonNull WireBuffer buffer, int varId, int varType, @NonNull String text) { buffer.start(Operations.NAMED_VARIABLE); buffer.writeInt(varId); buffer.writeInt(varType); buffer.writeUTF8(text); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int varId = buffer.readInt(); int varType = buffer.readInt(); String text = buffer.readUTF8(MAX_STRING_SIZE); operations.add(new NamedVariable(varId, varType, text)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Data Operations", OP_CODE, CLASS_NAME) .description("Add a string name for an ID") .field(DocumentedOperation.INT, "varId", "id to label") @@ -100,10 +105,11 @@ public class NamedVariable implements Operation { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { context.loadVariableName(mVarName, mVarId, mVarType); } + @NonNull @Override public String deepToString(String indent) { return indent + toString(); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java index 095a0106b3d7..527d5610788c 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java @@ -18,6 +18,8 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT_ARRAY; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -33,31 +35,33 @@ import java.util.List; public class PaintData extends PaintOperation implements VariableSupport { private static final int OP_CODE = Operations.PAINT_VALUES; private static final String CLASS_NAME = "PaintData"; - public PaintBundle mPaintData = new PaintBundle(); + @NonNull public PaintBundle mPaintData = new PaintBundle(); public static final int MAX_STRING_SIZE = 4000; public PaintData() {} @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { mPaintData.updateVariables(context); } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { mPaintData.registerVars(context, this); } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mPaintData); } + @NonNull @Override public String toString() { return "PaintData " + "\"" + mPaintData + "\""; } + @NonNull public static String name() { return CLASS_NAME; } @@ -66,31 +70,32 @@ public class PaintData extends PaintOperation implements VariableSupport { return OP_CODE; } - public static void apply(WireBuffer buffer, PaintBundle paintBundle) { + public static void apply(@NonNull WireBuffer buffer, @NonNull PaintBundle paintBundle) { buffer.start(Operations.PAINT_VALUES); paintBundle.writeBundle(buffer); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { PaintData data = new PaintData(); data.mPaintData.readBundle(buffer); operations.add(data); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Data Operations", OP_CODE, CLASS_NAME) .description("Encode a Paint ") .field(INT, "length", "id string") .field(INT_ARRAY, "paint", "length", "path encoded as floats"); } + @NonNull @Override public String deepToString(String indent) { return indent + toString(); } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.applyPaint(mPaintData); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java index 13d5a49a584b..06a1fec36196 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java @@ -18,6 +18,9 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT_ARRAY; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; +import android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -43,7 +46,7 @@ public class PathData implements Operation, VariableSupport { } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { for (int i = 0; i < mFloatPath.length; i++) { float v = mFloatPath[i]; if (Utils.isVariable(v)) { @@ -55,7 +58,7 @@ public class PathData implements Operation, VariableSupport { } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { for (float v : mFloatPath) { if (Float.isNaN(v)) { context.listensTo(Utils.idFromNan(v), this); @@ -64,15 +67,17 @@ public class PathData implements Operation, VariableSupport { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mInstanceId, mOutputPath); } + @NonNull @Override public String deepToString(String indent) { return pathString(mFloatPath); } + @NonNull @Override public String toString() { return "PathData[" + mInstanceId + "] = " + "\"" + deepToString(" ") + "\""; @@ -102,6 +107,7 @@ public class PathData implements Operation, VariableSupport { public static final float CLOSE_NAN = Utils.asNan(CLOSE); public static final float DONE_NAN = Utils.asNan(DONE); + @NonNull public static String name() { return CLASS_NAME; } @@ -110,7 +116,7 @@ public class PathData implements Operation, VariableSupport { return OP_CODE; } - public static void apply(WireBuffer buffer, int id, float[] data) { + public static void apply(@NonNull WireBuffer buffer, int id, @NonNull float[] data) { buffer.start(Operations.DATA_PATH); buffer.writeInt(id); buffer.writeInt(data.length); @@ -119,7 +125,7 @@ public class PathData implements Operation, VariableSupport { } } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int imageId = buffer.readInt(); int len = buffer.readInt(); float[] data = new float[len]; @@ -129,7 +135,7 @@ public class PathData implements Operation, VariableSupport { operations.add(new PathData(imageId, data)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Data Operations", OP_CODE, CLASS_NAME) .description("Encode a Path ") .field(DocumentedOperation.INT, "id", "id string") @@ -137,7 +143,8 @@ public class PathData implements Operation, VariableSupport { .field(FLOAT_ARRAY, "pathData", "length", "path encoded as floats"); } - public static String pathString(float[] path) { + @NonNull + public static String pathString(@Nullable float[] path) { if (path == null) { return "null"; } @@ -186,7 +193,7 @@ public class PathData implements Operation, VariableSupport { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { context.loadPathData(mInstanceId, mOutputPath); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java index 4a8f5324b74e..6ff9ad73e35f 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteComposeOperation; @@ -172,10 +174,11 @@ public class RootContentBehavior implements RemoteComposeOperation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mScroll, mAlignment, mSizing, mMode); } + @NonNull @Override public String toString() { return "ROOT_CONTENT_BEHAVIOR scroll: " @@ -187,15 +190,17 @@ public class RootContentBehavior implements RemoteComposeOperation { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { context.setRootContentBehavior(mScroll, mAlignment, mSizing, mMode); } + @NonNull @Override public String deepToString(String indent) { return toString(); } + @NonNull public static String name() { return CLASS_NAME; } @@ -204,7 +209,8 @@ public class RootContentBehavior implements RemoteComposeOperation { return OP_CODE; } - public static void apply(WireBuffer buffer, int scroll, int alignment, int sizing, int mode) { + public static void apply( + @NonNull WireBuffer buffer, int scroll, int alignment, int sizing, int mode) { buffer.start(OP_CODE); buffer.writeInt(scroll); buffer.writeInt(alignment); @@ -212,7 +218,7 @@ public class RootContentBehavior implements RemoteComposeOperation { buffer.writeInt(mode); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int scroll = buffer.readInt(); int alignment = buffer.readInt(); int sizing = buffer.readInt(); @@ -222,7 +228,7 @@ public class RootContentBehavior implements RemoteComposeOperation { operations.add(rootContentBehavior); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Protocol Operations", OP_CODE, CLASS_NAME) .description("Describes the behaviour of the root") .field(DocumentedOperation.INT, "scroll", "scroll") diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java index bff902926fd3..c2d62a7b3ac4 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteComposeOperation; @@ -41,25 +43,28 @@ public class RootContentDescription implements RemoteComposeOperation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mContentDescription); } + @NonNull @Override public String toString() { return "RootContentDescription " + mContentDescription; } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { context.setDocumentContentDescription(mContentDescription); } + @NonNull @Override public String deepToString(String indent) { return toString(); } + @NonNull public static String name() { return CLASS_NAME; } @@ -68,18 +73,18 @@ public class RootContentDescription implements RemoteComposeOperation { return OP_CODE; } - public static void apply(WireBuffer buffer, int contentDescription) { + public static void apply(@NonNull WireBuffer buffer, int contentDescription) { buffer.start(Operations.ROOT_CONTENT_DESCRIPTION); buffer.writeInt(contentDescription); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int contentDescription = buffer.readInt(); RootContentDescription header = new RootContentDescription(contentDescription); operations.add(header); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Protocol Operations", OP_CODE, CLASS_NAME) .description("Content description of root") .field(DocumentedOperation.INT, "id", "id of Int"); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java index 7ec7879bf8b2..ae61c3aa01c9 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java @@ -22,6 +22,9 @@ import static com.android.internal.widget.remotecompose.core.documentation.Docum import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.SHORT; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.UTF8; +import android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -43,17 +46,17 @@ public class ShaderData implements Operation, VariableSupport { private static final String CLASS_NAME = "ShaderData"; int mShaderTextId; // the actual text of a shader int mShaderID; // allows shaders to be referenced by number - HashMap<String, float[]> mUniformRawFloatMap = null; - HashMap<String, float[]> mUniformFloatMap = null; - HashMap<String, int[]> mUniformIntMap = null; - HashMap<String, Integer> mUniformBitmapMap = null; + @Nullable HashMap<String, float[]> mUniformRawFloatMap = null; + @Nullable HashMap<String, float[]> mUniformFloatMap = null; + @Nullable HashMap<String, int[]> mUniformIntMap = null; + @Nullable HashMap<String, Integer> mUniformBitmapMap = null; public ShaderData( int shaderID, int shaderTextId, - HashMap<String, float[]> floatMap, - HashMap<String, int[]> intMap, - HashMap<String, Integer> bitmapMap) { + @Nullable HashMap<String, float[]> floatMap, + @Nullable HashMap<String, int[]> intMap, + @Nullable HashMap<String, Integer> bitmapMap) { mShaderID = shaderID; mShaderTextId = shaderTextId; if (floatMap != null) { @@ -89,6 +92,7 @@ public class ShaderData implements Operation, VariableSupport { * * @return Names of all uniform floats or empty array */ + @NonNull public String[] getUniformFloatNames() { if (mUniformFloatMap == null) return new String[0]; return mUniformFloatMap.keySet().toArray(new String[0]); @@ -109,6 +113,7 @@ public class ShaderData implements Operation, VariableSupport { * * @return Name of all integer uniforms */ + @NonNull public String[] getUniformIntegerNames() { if (mUniformIntMap == null) return new String[0]; return mUniformIntMap.keySet().toArray(new String[0]); @@ -129,6 +134,7 @@ public class ShaderData implements Operation, VariableSupport { * * @return Name of all bitmap uniforms */ + @NonNull public String[] getUniformBitmapNames() { if (mUniformBitmapMap == null) return new String[0]; return mUniformBitmapMap.keySet().toArray(new String[0]); @@ -145,7 +151,7 @@ public class ShaderData implements Operation, VariableSupport { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply( buffer, mShaderID, @@ -155,13 +161,14 @@ public class ShaderData implements Operation, VariableSupport { mUniformBitmapMap); } + @NonNull @Override public String toString() { return "SHADER DATA " + mShaderID; } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { for (String name : mUniformRawFloatMap.keySet()) { float[] value = mUniformRawFloatMap.get(name); float[] out = null; @@ -178,7 +185,7 @@ public class ShaderData implements Operation, VariableSupport { } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { for (String name : mUniformRawFloatMap.keySet()) { float[] value = mUniformRawFloatMap.get(name); for (float v : value) { @@ -189,6 +196,7 @@ public class ShaderData implements Operation, VariableSupport { } } + @NonNull public static String name() { return CLASS_NAME; } @@ -208,12 +216,12 @@ public class ShaderData implements Operation, VariableSupport { * @param bitmapMap the map of bitmap uniforms */ public static void apply( - WireBuffer buffer, + @NonNull WireBuffer buffer, int shaderID, int shaderTextId, - HashMap<String, float[]> floatMap, - HashMap<String, int[]> intMap, - HashMap<String, Integer> bitmapMap) { + @Nullable HashMap<String, float[]> floatMap, + @Nullable HashMap<String, int[]> intMap, + @Nullable HashMap<String, Integer> bitmapMap) { buffer.start(OP_CODE); buffer.writeInt(shaderID); @@ -256,7 +264,7 @@ public class ShaderData implements Operation, VariableSupport { } } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int shaderID = buffer.readInt(); int shaderTextId = buffer.readInt(); HashMap<String, float[]> floatMap = null; @@ -308,7 +316,7 @@ public class ShaderData implements Operation, VariableSupport { operations.add(new ShaderData(shaderID, shaderTextId, floatMap, intMap, bitmapMap)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Data Operations", OP_CODE, CLASS_NAME) .description("Shader") .field(DocumentedOperation.INT, "shaderID", "id of shader") @@ -326,10 +334,11 @@ public class ShaderData implements Operation, VariableSupport { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { context.loadShader(mShaderID, this); } + @NonNull @Override public String deepToString(String indent) { return indent + toString(); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java index 638324950f88..dbaef7ef7ae1 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java @@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.UTF8; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -42,15 +44,17 @@ public class TextData implements Operation, SerializableToString { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mTextId, mText); } + @NonNull @Override public String toString() { return "TextData[" + mTextId + "] = \"" + Utils.trimString(mText, 10) + "\""; } + @NonNull public static String name() { return CLASS_NAME; } @@ -59,20 +63,20 @@ public class TextData implements Operation, SerializableToString { return OP_CODE; } - public static void apply(WireBuffer buffer, int textId, String text) { + public static void apply(@NonNull WireBuffer buffer, int textId, @NonNull String text) { buffer.start(OP_CODE); buffer.writeInt(textId); buffer.writeUTF8(text); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int textId = buffer.readInt(); String text = buffer.readUTF8(MAX_STRING_SIZE); operations.add(new TextData(textId, text)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Data Operations", OP_CODE, CLASS_NAME) .description("Encode a string ") .field(DocumentedOperation.INT, "id", "id string") @@ -80,20 +84,22 @@ public class TextData implements Operation, SerializableToString { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { context.loadText(mTextId, mText); } + @NonNull @Override public String deepToString(String indent) { return indent + toString(); } @Override - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { serializer.append(indent, getSerializedName() + "<" + mTextId + "> = \"" + mText + "\""); } + @NonNull private String getSerializedName() { return "DATA_TEXT"; } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java index 0d966d10384a..fb5087f3fee3 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java @@ -18,6 +18,8 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.SHORT; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -87,10 +89,11 @@ public class TextFromFloat implements Operation, VariableSupport { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mTextId, mValue, mDigitsBefore, mDigitsAfter, mFlags); } + @NonNull @Override public String toString() { return "TextFromFloat[" @@ -106,19 +109,20 @@ public class TextFromFloat implements Operation, VariableSupport { } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { if (Float.isNaN(mValue)) { mOutValue = context.getFloat(Utils.idFromNan(mValue)); } } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { if (Float.isNaN(mValue)) { context.listensTo(Utils.idFromNan(mValue), this); } } + @NonNull public static String name() { return CLASS_NAME; } @@ -138,7 +142,7 @@ public class TextFromFloat implements Operation, VariableSupport { * @param flags flags that control if and how to fill the empty spots */ public static void apply( - WireBuffer buffer, + @NonNull WireBuffer buffer, int textId, float value, short digitsBefore, @@ -151,7 +155,7 @@ public class TextFromFloat implements Operation, VariableSupport { buffer.writeInt(flags); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int textId = buffer.readInt(); float value = buffer.readFloat(); int tmp = buffer.readInt(); @@ -162,7 +166,7 @@ public class TextFromFloat implements Operation, VariableSupport { operations.add(new TextFromFloat(textId, value, pre, post, flags)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Expressions Operations", OP_CODE, CLASS_NAME) .description("Draw text along path object") .field(DocumentedOperation.INT, "textId", "id of the text generated") @@ -173,12 +177,13 @@ public class TextFromFloat implements Operation, VariableSupport { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { float v = mOutValue; String s = StringUtils.floatToString(v, mDigitsBefore, mDigitsAfter, mPre, mAfter); context.loadText(mTextId, s); } + @NonNull @Override public String deepToString(String indent) { return indent + toString(); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookup.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookup.java index b04d698fa36c..2129edde2f59 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookup.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookup.java @@ -18,6 +18,8 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -48,10 +50,11 @@ public class TextLookup implements Operation, VariableSupport { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mTextId, mDataSetId, mIndex); } + @NonNull @Override public String toString() { return "TextLookup[" @@ -63,19 +66,20 @@ public class TextLookup implements Operation, VariableSupport { } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { if (Float.isNaN(mIndex)) { mOutIndex = context.getFloat(Utils.idFromNan(mIndex)); } } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { if (Float.isNaN(mIndex)) { context.listensTo(Utils.idFromNan(mIndex), this); } } + @NonNull public static String name() { return CLASS_NAME; } @@ -92,21 +96,21 @@ public class TextLookup implements Operation, VariableSupport { * @param dataSet float pointer to the array/list to turn int a string * @param index index of element to return */ - public static void apply(WireBuffer buffer, int textId, int dataSet, float index) { + public static void apply(@NonNull WireBuffer buffer, int textId, int dataSet, float index) { buffer.start(OP_CODE); buffer.writeInt(textId); buffer.writeInt(dataSet); buffer.writeFloat(index); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int textId = buffer.readInt(); int dataSetId = buffer.readInt(); float index = buffer.readFloat(); operations.add(new TextLookup(textId, dataSetId, index)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Expressions Operations", OP_CODE, CLASS_NAME) .description("Look an array and turn into a text object") .field(INT, "textId", "id of the text generated") @@ -115,11 +119,12 @@ public class TextLookup implements Operation, VariableSupport { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { int id = context.getCollectionsAccess().getId(mDataSetId, (int) mOutIndex); context.loadText(mTextId, context.getText(id)); } + @NonNull @Override public String deepToString(String indent) { return indent + toString(); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookupInt.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookupInt.java index 171bea249273..ea550cbe010c 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookupInt.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookupInt.java @@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -45,10 +47,11 @@ public class TextLookupInt implements Operation, VariableSupport { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mTextId, mDataSetId, mIndex); } + @NonNull @Override public String toString() { return "TextLookupInt[" @@ -60,15 +63,16 @@ public class TextLookupInt implements Operation, VariableSupport { } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { mOutIndex = context.getInteger(mIndex); } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { context.listensTo(mIndex, this); } + @NonNull public static String name() { return CLASS_NAME; } @@ -85,21 +89,21 @@ public class TextLookupInt implements Operation, VariableSupport { * @param dataSet float pointer to the array/list to turn int a string * @param indexId index of element to return */ - public static void apply(WireBuffer buffer, int textId, int dataSet, int indexId) { + public static void apply(@NonNull WireBuffer buffer, int textId, int dataSet, int indexId) { buffer.start(OP_CODE); buffer.writeInt(textId); buffer.writeInt(dataSet); buffer.writeInt(indexId); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int textId = buffer.readInt(); int dataSetId = buffer.readInt(); int indexId = buffer.readInt(); operations.add(new TextLookupInt(textId, dataSetId, indexId)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Expressions Operations", OP_CODE, CLASS_NAME) .description("Look up an array and turn into a text object") .field(DocumentedOperation.INT, "textId", "id of the text generated") @@ -108,11 +112,12 @@ public class TextLookupInt implements Operation, VariableSupport { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { int id = context.getCollectionsAccess().getId(mDataSetId, (int) mOutIndex); context.loadText(mTextId, context.getText(id)); } + @NonNull @Override public String deepToString(String indent) { return indent + toString(); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java index 78cc674a22e9..fa18b4ddb2a2 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java @@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -41,15 +43,17 @@ public class TextMerge implements Operation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mTextId, mSrcId1, mSrcId2); } + @NonNull @Override public String toString() { return "TextMerge[" + mTextId + "] = [" + mSrcId1 + " ] + [ " + mSrcId2 + "]"; } + @NonNull public static String name() { return CLASS_NAME; } @@ -66,14 +70,14 @@ public class TextMerge implements Operation { * @param srcId1 source text 1 * @param srcId2 source text 2 */ - public static void apply(WireBuffer buffer, int textId, int srcId1, int srcId2) { + public static void apply(@NonNull WireBuffer buffer, int textId, int srcId1, int srcId2) { buffer.start(OP_CODE); buffer.writeInt(textId); buffer.writeInt(srcId1); buffer.writeInt(srcId2); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int textId = buffer.readInt(); int srcId1 = buffer.readInt(); int srcId2 = buffer.readInt(); @@ -81,7 +85,7 @@ public class TextMerge implements Operation { operations.add(new TextMerge(textId, srcId1, srcId2)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Data Operations", OP_CODE, CLASS_NAME) .description("Merge two string into one") .field(DocumentedOperation.INT, "textId", "id of the text") @@ -90,12 +94,13 @@ public class TextMerge implements Operation { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { String str1 = context.getText(mSrcId1); String str2 = context.getText(mSrcId2); context.loadText(mTextId, str1 + str2); } + @NonNull @Override public String deepToString(String indent) { return indent + toString(); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/Theme.java b/core/java/com/android/internal/widget/remotecompose/core/operations/Theme.java index 845f25d0cd67..1e90ab128e93 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/Theme.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/Theme.java @@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteComposeOperation; @@ -49,25 +51,28 @@ public class Theme implements RemoteComposeOperation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mTheme); } + @NonNull @Override public String toString() { return "SET_THEME " + mTheme; } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { context.setTheme(mTheme); } + @NonNull @Override public String deepToString(String indent) { return indent + toString(); } + @NonNull public static String name() { return CLASS_NAME; } @@ -76,17 +81,17 @@ public class Theme implements RemoteComposeOperation { return OP_CODE; } - public static void apply(WireBuffer buffer, int theme) { + public static void apply(@NonNull WireBuffer buffer, int theme) { buffer.start(OP_CODE); buffer.writeInt(theme); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int theme = buffer.readInt(); operations.add(new Theme(theme)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Protocol Operations", OP_CODE, CLASS_NAME) .description("Set a theme") .field(INT, "THEME", "theme id") diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java new file mode 100644 index 000000000000..b25a7f6ea09d --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java @@ -0,0 +1,599 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations; + +import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT; +import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT_ARRAY; +import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; +import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.SHORT; + +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.RemoteContext; +import com.android.internal.widget.remotecompose.core.TouchListener; +import com.android.internal.widget.remotecompose.core.VariableSupport; +import com.android.internal.widget.remotecompose.core.WireBuffer; +import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; +import com.android.internal.widget.remotecompose.core.operations.layout.Component; +import com.android.internal.widget.remotecompose.core.operations.utilities.AnimatedFloatExpression; +import com.android.internal.widget.remotecompose.core.operations.utilities.NanMap; +import com.android.internal.widget.remotecompose.core.operations.utilities.touch.VelocityEasing; + +import java.util.Arrays; +import java.util.List; + +/** + * Operation to deal with Touch handling (typically on canvas) This support handling of many typical + * touch behaviours. Including animating to Notched, positions. and tweaking the dynamics of the + * animation. + */ +public class TouchExpression implements Operation, VariableSupport, TouchListener { + private static final int OP_CODE = Operations.TOUCH_EXPRESSION; + private static final String CLASS_NAME = "TouchExpression"; + private float mDefValue; + private float mOutDefValue; + public int mId; + public float[] mSrcExp; + int mMode = 1; // 0 = delta, 1 = absolute + float mMax = 1; + float mMin = 1; + float mOutMax = 1; + float mOutMin = 1; + float mValue = 0; + boolean mUnmodified = true; + public float[] mPreCalcValue; + private float mLastChange = Float.NaN; + private float mLastCalculatedValue = Float.NaN; + AnimatedFloatExpression mExp = new AnimatedFloatExpression(); + public static final int MAX_EXPRESSION_SIZE = 32; + private VelocityEasing mEasyTouch = new VelocityEasing(); + private boolean mEasingToStop = false; + private float mTouchUpTime = 0; + private float mCurrentValue = Float.NaN; + private boolean mTouchDown = false; + float mMaxTime = 1; + float mMaxAcceleration = 5; + float mMaxVelocity = 7; + int mStopMode = 0; + boolean mWrapMode = false; + float[] mNotches; + float[] mStopSpec; + int mTouchEffects; + float mVelocityId; + + public static final int STOP_GENTLY = 0; + public static final int STOP_ENDS = 2; + public static final int STOP_INSTANTLY = 1; + public static final int STOP_NOTCHES_EVEN = 3; + public static final int STOP_NOTCHES_PERCENTS = 4; + public static final int STOP_NOTCHES_ABSOLUTE = 5; + public static final int STOP_ABSOLUTE_POS = 6; + + public TouchExpression( + int id, + float[] exp, + float defValue, + float min, + float max, + int touchEffects, + float velocityId, + int stopMode, + float[] stopSpec, + float[] easingSpec) { + this.mId = id; + this.mSrcExp = exp; + mOutDefValue = mDefValue = defValue; + mMode = STOP_ABSOLUTE_POS == stopMode ? 1 : 0; + mOutMax = mMax = max; + mTouchEffects = touchEffects; + mVelocityId = velocityId; + if (Float.isNaN(min) && Utils.idFromNan(min) == 0) { + mWrapMode = true; + } else { + mOutMin = mMin = min; + } + mStopMode = stopMode; + mStopSpec = stopSpec; + if (easingSpec != null) { + Utils.log("easingSpec " + Arrays.toString(easingSpec)); + if (easingSpec.length >= 4) { + if (Float.floatToRawIntBits(easingSpec[0]) == 0) { + Utils.log("easingSpec[2] " + easingSpec[2]); + mMaxTime = easingSpec[1]; + mMaxAcceleration = easingSpec[2]; + mMaxVelocity = easingSpec[3]; + } + } + } + } + + @Override + public void updateVariables(RemoteContext context) { + + if (mPreCalcValue == null || mPreCalcValue.length != mSrcExp.length) { + mPreCalcValue = new float[mSrcExp.length]; + } + if (Float.isNaN(mMax)) { + mOutMax = context.getFloat(Utils.idFromNan(mMax)); + } + if (Float.isNaN(mMin)) { + mOutMin = context.getFloat(Utils.idFromNan(mMin)); + } + if (Float.isNaN(mDefValue)) { + mOutDefValue = context.getFloat(Utils.idFromNan(mDefValue)); + } + + boolean value_changed = false; + for (int i = 0; i < mSrcExp.length; i++) { + float v = mSrcExp[i]; + if (Float.isNaN(v) + && !AnimatedFloatExpression.isMathOperator(v) + && !NanMap.isDataVariable(v)) { + float newValue = context.getFloat(Utils.idFromNan(v)); + + mPreCalcValue[i] = newValue; + + } else { + mPreCalcValue[i] = mSrcExp[i]; + } + } + float v = mLastCalculatedValue; + if (value_changed) { // inputs changed check if output changed + v = mExp.eval(mPreCalcValue, mPreCalcValue.length); + if (v != mLastCalculatedValue) { + mLastChange = context.getAnimationTime(); + mLastCalculatedValue = v; + } else { + value_changed = false; + } + } + } + + @Override + public void registerListening(RemoteContext context) { + if (Float.isNaN(mMax)) { + context.listensTo(Utils.idFromNan(mMax), this); + } + if (Float.isNaN(mMin)) { + context.listensTo(Utils.idFromNan(mMin), this); + } + if (Float.isNaN(mDefValue)) { + context.listensTo(Utils.idFromNan(mDefValue), this); + } + context.addTouchListener(this); + for (float v : mSrcExp) { + if (Float.isNaN(v) + && !AnimatedFloatExpression.isMathOperator(v) + && !NanMap.isDataVariable(v)) { + context.listensTo(Utils.idFromNan(v), this); + } + } + } + + private float wrap(float pos) { + if (!mWrapMode) { + return pos; + } + pos = pos % mOutMax; + if (pos < 0) { + pos += mOutMax; + } + return pos; + } + + private float getStopPosition(float pos, float slope) { + float target = pos + slope / mMaxAcceleration; + if (mWrapMode) { + pos = wrap(pos); + target = pos += +slope / mMaxAcceleration; + } else { + target = Math.max(Math.min(target, mOutMax), mOutMin); + } + float[] positions = new float[mStopSpec.length]; + float min = (mWrapMode) ? 0 : mOutMin; + + switch (mStopMode) { + case STOP_ENDS: + return ((pos + slope) > (mOutMax + min) / 2) ? mOutMax : min; + case STOP_INSTANTLY: + return pos; + case STOP_NOTCHES_EVEN: + int evenSpacing = (int) mStopSpec[0]; + float step = (mOutMax - min) / evenSpacing; + + float notch = min + step * (int) (0.5f + (target - mOutMin) / step); + + notch = Math.max(Math.min(notch, mOutMax), min); + return notch; + case STOP_NOTCHES_PERCENTS: + positions = new float[mStopSpec.length]; + float minPos = min; + float minPosDist = Math.abs(mOutMin - target); + for (int i = 0; i < positions.length; i++) { + float p = mOutMin + mStopSpec[i] * (mOutMax - mOutMin); + float dist = Math.abs(p - target); + if (minPosDist > dist) { + minPosDist = dist; + minPos = p; + } + } + return minPos; + case STOP_NOTCHES_ABSOLUTE: + positions = mStopSpec; + minPos = mOutMin; + minPosDist = Math.abs(mOutMin - target); + for (int i = 0; i < positions.length; i++) { + float dist = Math.abs(positions[i] - target); + if (minPosDist > dist) { + minPosDist = dist; + minPos = positions[i]; + } + } + return minPos; + case STOP_GENTLY: + default: + return target; + } + } + + void haptic(RemoteContext context) { + int touch = ((mTouchEffects) & 0xFF); + if ((mTouchEffects & (1 << 15)) != 0) { + touch = context.getInteger(mTouchEffects & 0x7FFF); + } + + context.hapticEffect(touch); + } + + float mLastValue = 0; + + void crossNotchCheck(RemoteContext context) { + float prev = mLastValue; + float next = mCurrentValue; + mLastValue = next; + + // System.out.println(mStopMode + " " + prev + " -> " + next); + float min = (mWrapMode) ? 0 : mOutMin; + float max = mOutMax; + + switch (mStopMode) { + case STOP_ENDS: + if (((min - prev) * (max - prev) < 0) ^ ((min - next) * (max - next)) < 0) { + haptic(context); + } + break; + case STOP_INSTANTLY: + haptic(context); + break; + case STOP_NOTCHES_EVEN: + int evenSpacing = (int) mStopSpec[0]; + float step = (max - min) / evenSpacing; + if ((int) ((prev - min) / step) != (int) ((next - min) / step)) { + haptic(context); + } + break; + case STOP_NOTCHES_PERCENTS: + for (int i = 0; i < mStopSpec.length; i++) { + float p = mOutMin + mStopSpec[i] * (mOutMax - mOutMin); + if ((prev - p) * (next - p) < 0) { + haptic(context); + } + } + break; + case STOP_NOTCHES_ABSOLUTE: + for (int i = 0; i < mStopSpec.length; i++) { + float p = mStopSpec[i]; + if ((prev - p) * (next - p) < 0) { + haptic(context); + } + } + break; + case STOP_GENTLY: + } + } + + float mScrLeft, mScrRight, mScrTop, mScrBottom; + + @Override + public void apply(RemoteContext context) { + Component comp = context.lastComponent; + if (comp != null) { + float x = comp.getX(); + float y = comp.getY(); + float w = comp.getWidth(); + float h = comp.getHeight(); + comp = comp.getParent(); + while (comp != null) { + x += comp.getX(); + y += comp.getY(); + comp = comp.getParent(); + } + mScrLeft = x; + mScrTop = y; + mScrRight = w + x; + mScrBottom = h + y; + } + updateVariables(context); + if (mUnmodified) { + mCurrentValue = mOutDefValue; + + context.loadFloat(mId, wrap(mCurrentValue)); + return; + } + if (mEasingToStop) { + float time = context.getAnimationTime() - mTouchUpTime; + float value = mEasyTouch.getPos(time); + mCurrentValue = value; + value = wrap(value); + context.loadFloat(mId, value); + if (mEasyTouch.getDuration() < time) { + mEasingToStop = false; + } + crossNotchCheck(context); + return; + } + if (mTouchDown) { + float value = + mExp.eval(context.getCollectionsAccess(), mPreCalcValue, mPreCalcValue.length); + if (mMode == 0) { + value = mValueAtDown + (value - mDownTouchValue); + } + if (mWrapMode) { + value = wrap(value); + } else { + value = Math.min(Math.max(value, mOutMin), mOutMax); + } + mCurrentValue = value; + } + crossNotchCheck(context); + context.loadFloat(mId, wrap(mCurrentValue)); + } + + float mValueAtDown; // The currently "displayed" value at down + float mDownTouchValue; // The calculated value at down + + @Override + public void touchDown(RemoteContext context, float x, float y) { + + if (!(x >= mScrLeft && x <= mScrRight && y >= mScrTop && y <= mScrBottom)) { + Utils.log("NOT IN WINDOW " + x + ", " + y + " " + mScrLeft + ", " + mScrTop); + return; + } + mTouchDown = true; + mUnmodified = false; + if (mMode == 0) { + mValueAtDown = context.getFloat(mId); + mDownTouchValue = + mExp.eval(context.getCollectionsAccess(), mPreCalcValue, mPreCalcValue.length); + } + } + + @Override + public void touchUp(RemoteContext context, float x, float y, float dx, float dy) { + // calculate the slope (using small changes) + if (!mTouchDown) { + return; + } + mTouchDown = false; + float dt = 0.0001f; + if (mStopMode == STOP_INSTANTLY) { + return; + } + float v = mExp.eval(context.getCollectionsAccess(), mPreCalcValue, mPreCalcValue.length); + for (int i = 0; i < mSrcExp.length; i++) { + if (Float.isNaN(mSrcExp[i])) { + int id = Utils.idFromNan(mSrcExp[i]); + if (id == RemoteContext.ID_TOUCH_POS_X) { + mPreCalcValue[i] = x + dx * dt; + } else if (id == RemoteContext.ID_TOUCH_POS_Y) { + mPreCalcValue[i] = y + dy * dt; + } + } + } + float vdt = mExp.eval(context.getCollectionsAccess(), mPreCalcValue, mPreCalcValue.length); + float slope = (vdt - v) / dt; // the rate of change with respect to the dx,dy movement + float value = context.getFloat(mId); + + mTouchUpTime = context.getAnimationTime(); + + float dest = getStopPosition(value, slope); + mEasyTouch.config(value, dest, slope, mMaxTime, mMaxAcceleration, mMaxVelocity, null); + mEasingToStop = true; + } + + @Override + public void touchDrag(RemoteContext context, float x, float y) { + if (!mTouchDown) { + return; + } + apply(context); + context.getDocument().getRootLayoutComponent().needsRepaint(); + } + + @Override + public void write(WireBuffer buffer) { + apply( + buffer, + mId, + mValue, + mMin, + mMax, + mVelocityId, + mTouchEffects, + mSrcExp, + mStopMode, + mNotches, + null); + } + + @Override + public String toString() { + String[] labels = new String[mSrcExp.length]; + for (int i = 0; i < mSrcExp.length; i++) { + if (Float.isNaN(mSrcExp[i])) { + labels[i] = "[" + Utils.idStringFromNan(mSrcExp[i]) + "]"; + } + } + if (mPreCalcValue == null) { + return CLASS_NAME + + "[" + + mId + + "] = (" + + AnimatedFloatExpression.toString(mSrcExp, labels) + + ")"; + } + return CLASS_NAME + + "[" + + mId + + "] = (" + + AnimatedFloatExpression.toString(mPreCalcValue, labels) + + ")"; + } + + // ===================== static ====================== + + public static String name() { + return CLASS_NAME; + } + + public static int id() { + return OP_CODE; + } + + /** + * Writes out the operation to the buffer + * + * @param buffer The buffer to write to + * @param id the id of the resulting float + * @param value the float expression array + */ + public static void apply( + WireBuffer buffer, + int id, + float value, + float min, + float max, + float velocityId, + int touchEffects, + float[] exp, + int touchMode, + float[] touchSpec, + float[] easingSpec) { + buffer.start(OP_CODE); + buffer.writeInt(id); + buffer.writeFloat(value); + buffer.writeFloat(min); + buffer.writeFloat(max); + buffer.writeFloat(velocityId); + buffer.writeInt(touchEffects); + buffer.writeInt(exp.length); + for (float v : exp) { + buffer.writeFloat(v); + } + int len = 0; + if (touchSpec != null) { + len = touchSpec.length; + } + buffer.writeInt((touchMode << 16) | len); + for (int i = 0; i < len; i++) { + buffer.writeFloat(touchSpec[i]); + } + + if (easingSpec != null) { + len = easingSpec.length; + } else { + len = 0; + } + buffer.writeInt(len); + for (int i = 0; i < len; i++) { + buffer.writeFloat(easingSpec[i]); + } + } + + public static void read(WireBuffer buffer, List<Operation> operations) { + int id = buffer.readInt(); + float startValue = buffer.readFloat(); + float min = buffer.readFloat(); + float max = buffer.readFloat(); + float velocityId = buffer.readFloat(); // TODO future support + int touchEffects = buffer.readInt(); + int len = buffer.readInt(); + int valueLen = len & 0xFFFF; + if (valueLen > MAX_EXPRESSION_SIZE) { + throw new RuntimeException("Float expression to long"); + } + float[] exp = new float[valueLen]; + for (int i = 0; i < exp.length; i++) { + exp[i] = buffer.readFloat(); + } + int stopLogic = buffer.readInt(); + int stopLen = stopLogic & 0xFFFF; + int stopMode = stopLogic >> 16; + + Utils.log("stopMode " + stopMode + " stopLen " + stopLen); + float[] stopsData = new float[stopLen]; + for (int i = 0; i < stopsData.length; i++) { + stopsData[i] = buffer.readFloat(); + } + int easingLen = buffer.readInt(); + + float[] easingData = new float[easingLen]; + for (int i = 0; i < easingData.length; i++) { + easingData[i] = buffer.readFloat(); + } + + operations.add( + new TouchExpression( + id, + exp, + startValue, + min, + max, + touchEffects, + velocityId, + stopMode, + stopsData, + easingData)); + } + + public static void documentation(DocumentationBuilder doc) { + doc.operation("Expressions Operations", OP_CODE, CLASS_NAME) + .description("A Float expression") + .field(INT, "id", "The id of the Color") + .field(SHORT, "expression_length", "expression length") + .field(SHORT, "animation_length", "animation description length") + .field( + FLOAT_ARRAY, + "expression", + "expression_length", + "Sequence of Floats representing and expression") + .field( + FLOAT_ARRAY, + "AnimationSpec", + "animation_length", + "Sequence of Floats representing animation curve") + .field(FLOAT, "duration", "> time in sec") + .field(INT, "bits", "> WRAP|INITALVALUE | TYPE ") + .field(FLOAT_ARRAY, "spec", "> [SPEC PARAMETERS] ") + .field(FLOAT, "initialValue", "> [Initial value] ") + .field(FLOAT, "wrapValue", "> [Wrap value] "); + } + + @Override + public String deepToString(String indent) { + return indent + toString(); + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java b/core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java index 8ebb40cab806..03f7e0563eeb 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations; +import android.annotation.NonNull; + /** Utilities to be used across all core operations */ public class Utils { public static float asNan(int v) { @@ -30,11 +32,13 @@ public class Utils { return v - 0x100000000L; } + @NonNull public static String idStringFromNan(float value) { int b = Float.floatToRawIntBits(value) & 0x3FFFFF; return idString(b); } + @NonNull public static String idString(int b) { return (b > 0xFFFFF) ? "A_" + (b & 0xFFFFF) : "" + b; } @@ -50,7 +54,8 @@ public class Utils { * @param n * @return */ - public static String trimString(String str, int n) { + @NonNull + public static String trimString(@NonNull String str, int n) { if (str.length() > n) { str = str.substring(0, n - 3) + "..."; } @@ -145,6 +150,7 @@ public class Utils { * @param color * @return */ + @NonNull public static String colorInt(int color) { String str = "000000000000" + Integer.toHexString(color); return "0x" + str.substring(str.length() - 8); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/AnimatableValue.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/AnimatableValue.java new file mode 100644 index 000000000000..e789710bb113 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/AnimatableValue.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations.layout; + +import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.operations.Utils; +import com.android.internal.widget.remotecompose.core.operations.utilities.easing.FloatAnimation; +import com.android.internal.widget.remotecompose.core.operations.utilities.easing.GeneralEasing; + +public class AnimatableValue { + boolean mIsVariable = false; + int mId = 0; + float mValue = 0f; + + boolean mAnimate = false; + long mAnimateTargetTime = 0; + float mAnimateDuration = 300f; + float mTargetRotationX; + float mStartRotationX; + + int mMotionEasingType = GeneralEasing.CUBIC_STANDARD; + FloatAnimation mMotionEasing; + + public AnimatableValue(float value) { + if (Utils.isVariable(value)) { + mId = Utils.idFromNan(value); + mIsVariable = true; + } else { + mValue = value; + } + } + + public float getValue() { + return mValue; + } + + public float evaluate(PaintContext context) { + if (!mIsVariable) { + return mValue; + } + float value = context.getContext().mRemoteComposeState.getFloat(mId); + + if (value != mValue && !mAnimate) { + // animate + mStartRotationX = mValue; + mTargetRotationX = value; + mAnimate = true; + mAnimateTargetTime = System.currentTimeMillis(); + mMotionEasing = + new FloatAnimation( + mMotionEasingType, mAnimateDuration / 1000f, null, 0f, Float.NaN); + mMotionEasing.setTargetValue(1f); + } + if (mAnimate) { + float elapsed = System.currentTimeMillis() - mAnimateTargetTime; + float p = mMotionEasing.get(elapsed / mAnimateDuration); + mValue = (1 - p) * mStartRotationX + p * mTargetRotationX; + if (p >= 1f) { + mAnimate = false; + } + } else { + mValue = mTargetRotationX; + } + + return mValue; + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasContent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasContent.java index 9d80d3cc40b0..988651895bae 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasContent.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasContent.java @@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.operations.layout; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.WireBuffer; @@ -38,6 +40,7 @@ public class CanvasContent extends Component implements ComponentStartOperation super(parent, componentId, animationId, x, y, width, height); } + @NonNull public static String name() { return "CanvasContent"; } @@ -46,29 +49,30 @@ public class CanvasContent extends Component implements ComponentStartOperation return Operations.LAYOUT_CANVAS_CONTENT; } + @NonNull @Override protected String getSerializedName() { return "CANVAS_CONTENT"; } - public static void apply(WireBuffer buffer, int componentId) { + public static void apply(@NonNull WireBuffer buffer, int componentId) { buffer.start(Operations.LAYOUT_CANVAS_CONTENT); buffer.writeInt(componentId); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int componentId = buffer.readInt(); operations.add(new CanvasContent(componentId, 0, 0, 0, 0, null, -1)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", id(), name()) .field(INT, "COMPONENT_ID", "unique id for this component") .description("Container for canvas commands."); } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mComponentId); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickHandler.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickHandler.java new file mode 100644 index 000000000000..0ca72fae9eea --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickHandler.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations.layout; + +import com.android.internal.widget.remotecompose.core.CoreDocument; +import com.android.internal.widget.remotecompose.core.RemoteContext; + +/** Interface to represent operations that can handle click events */ +public interface ClickHandler { + + /** + * callback for a click event + * + * @param context the current context + * @param document the current document + * @param component the component on which the click has been received + * @param x the x position of the click in document coordinates + * @param y the y position of the click in document coordinates + */ + void onClick( + RemoteContext context, CoreDocument document, Component component, float x, float y); +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierOperation.java index d5ff07df54cd..b567538b1c4e 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierOperation.java @@ -15,6 +15,9 @@ */ package com.android.internal.widget.remotecompose.core.operations.layout; +import android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.CoreDocument; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; @@ -37,7 +40,7 @@ import java.util.List; /** Represents a click modifier + actions */ public class ClickModifierOperation extends PaintOperation - implements ModifierOperation, DecoratorComponent { + implements ModifierOperation, DecoratorComponent, ClickHandler { private static final int OP_CODE = Operations.MODIFIER_CLICK; long mAnimateRippleStart = 0; @@ -48,9 +51,9 @@ public class ClickModifierOperation extends PaintOperation float mWidth = 0; float mHeight = 0; - public float[] locationInWindow = new float[2]; + @NonNull public float[] locationInWindow = new float[2]; - PaintBundle mPaint = new PaintBundle(); + @NonNull PaintBundle mPaint = new PaintBundle(); public void animateRipple(float x, float y) { mAnimateRippleStart = System.currentTimeMillis(); @@ -58,17 +61,19 @@ public class ClickModifierOperation extends PaintOperation mAnimateRippleY = y; } - public ArrayList<Operation> mList = new ArrayList<>(); + @NonNull public ArrayList<Operation> mList = new ArrayList<>(); + @NonNull public ArrayList<Operation> getList() { return mList; } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer); } + @NonNull @Override public String toString() { return "ClickModifier"; @@ -83,13 +88,14 @@ public class ClickModifierOperation extends PaintOperation } } + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@Nullable String indent) { return (indent != null ? indent : "") + toString(); } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { if (mAnimateRippleStart == 0) { return; } @@ -137,7 +143,7 @@ public class ClickModifierOperation extends PaintOperation } @Override - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { serializer.append(indent, "CLICK_MODIFIER"); for (Operation o : mList) { if (o instanceof ActionOperation) { @@ -148,7 +154,11 @@ public class ClickModifierOperation extends PaintOperation @Override public void onClick( - RemoteContext context, CoreDocument document, Component component, float x, float y) { + RemoteContext context, + CoreDocument document, + @NonNull Component component, + float x, + float y) { if (!component.isVisible()) { return; } @@ -163,19 +173,20 @@ public class ClickModifierOperation extends PaintOperation } } + @NonNull public static String name() { return "ClickModifier"; } - public static void apply(WireBuffer buffer) { + public static void apply(@NonNull WireBuffer buffer) { buffer.start(OP_CODE); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(WireBuffer buffer, @NonNull List<Operation> operations) { operations.add(new ClickModifierOperation()); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", OP_CODE, name()) .description( "Click modifier. This operation contains" diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java index 96dffca2042f..f4f4ee2a3416 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java @@ -15,6 +15,9 @@ */ package com.android.internal.widget.remotecompose.core.operations.layout; +import android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.CoreDocument; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -31,7 +34,6 @@ import com.android.internal.widget.remotecompose.core.operations.layout.animatio import com.android.internal.widget.remotecompose.core.operations.layout.measure.ComponentMeasure; import com.android.internal.widget.remotecompose.core.operations.layout.measure.Measurable; import com.android.internal.widget.remotecompose.core.operations.layout.measure.MeasurePass; -import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ComponentModifiers; import com.android.internal.widget.remotecompose.core.operations.paint.PaintBundle; import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; @@ -52,16 +54,23 @@ public class Component extends PaintOperation implements Measurable, Serializabl protected int mAnimationId = -1; public Visibility mVisibility = Visibility.VISIBLE; public Visibility mScheduledVisibility = Visibility.VISIBLE; - public ArrayList<Operation> mList = new ArrayList<>(); + @NonNull public ArrayList<Operation> mList = new ArrayList<>(); public PaintOperation mPreTranslate; public boolean mNeedsMeasure = true; public boolean mNeedsRepaint = false; - public AnimateMeasure mAnimateMeasure; - public AnimationSpec mAnimationSpec = new AnimationSpec(); + @Nullable public AnimateMeasure mAnimateMeasure; + @NonNull public AnimationSpec mAnimationSpec = new AnimationSpec(); public boolean mFirstLayout = true; - PaintBundle mPaint = new PaintBundle(); - protected HashSet<ComponentValue> mComponentValues = new HashSet<>(); + @NonNull PaintBundle mPaint = new PaintBundle(); + @NonNull protected HashSet<ComponentValue> mComponentValues = new HashSet<>(); + + protected float mZIndex = 0f; + public float getZIndex() { + return mZIndex; + } + + @NonNull public ArrayList<Operation> getList() { return mList; } @@ -115,7 +124,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl * * @param context the current context */ - private void updateComponentValues(RemoteContext context) { + private void updateComponentValues(@NonNull RemoteContext context) { if (DEBUG) { System.out.println( "UPDATE COMPONENT VALUES (" @@ -172,7 +181,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl this(parent, componentId, -1, x, y, width, height); } - public Component(Component component) { + public Component(@NonNull Component component) { this( component.mParent, component.mComponentId, @@ -212,7 +221,10 @@ public class Component extends PaintOperation implements Measurable, Serializabl * * @param context the current context */ - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { + Component prev = context.lastComponent; + context.lastComponent = this; + if (!mComponentValues.isEmpty()) { updateComponentValues(context); } @@ -224,6 +236,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl o.apply(context); } } + context.lastComponent = prev; } public void addComponentValue(ComponentValue v) { @@ -283,14 +296,14 @@ public class Component extends PaintOperation implements Measurable, Serializabl float maxWidth, float minHeight, float maxHeight, - MeasurePass measure) { + @NonNull MeasurePass measure) { ComponentMeasure m = measure.get(this); m.setW(mWidth); m.setH(mHeight); } @Override - public void layout(RemoteContext context, MeasurePass measure) { + public void layout(@NonNull RemoteContext context, @NonNull MeasurePass measure) { ComponentMeasure m = measure.get(this); if (!mFirstLayout && context.isAnimationEnabled() @@ -332,7 +345,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl mFirstLayout = false; } - public float[] locationInWindow = new float[2]; + @NonNull public float[] locationInWindow = new float[2]; public boolean contains(float x, float y) { locationInWindow[0] = 0f; @@ -353,13 +366,57 @@ public class Component extends PaintOperation implements Measurable, Serializabl if (op instanceof Component) { ((Component) op).onClick(context, document, x, y); } - if (op instanceof ComponentModifiers) { - ((ComponentModifiers) op).onClick(context, document, this, x, y); + if (op instanceof ClickHandler) { + ((ClickHandler) op).onClick(context, document, this, x, y); + } + } + } + + public void onTouchDown(RemoteContext context, CoreDocument document, float x, float y) { + if (!contains(x, y)) { + return; + } + for (Operation op : mList) { + if (op instanceof Component) { + ((Component) op).onTouchDown(context, document, x, y); + } + if (op instanceof TouchHandler) { + ((TouchHandler) op).onTouchDown(context, document, this, x, y); + } + } + } + + public void onTouchUp( + RemoteContext context, CoreDocument document, float x, float y, boolean force) { + if (!force && !contains(x, y)) { + return; + } + for (Operation op : mList) { + if (op instanceof Component) { + ((Component) op).onTouchUp(context, document, x, y, force); + } + if (op instanceof TouchHandler) { + ((TouchHandler) op).onTouchUp(context, document, this, x, y); + } + } + } + + public void onTouchCancel( + RemoteContext context, CoreDocument document, float x, float y, boolean force) { + if (!force && !contains(x, y)) { + return; + } + for (Operation op : mList) { + if (op instanceof Component) { + ((Component) op).onTouchCancel(context, document, x, y, force); + } + if (op instanceof TouchHandler) { + ((TouchHandler) op).onTouchCancel(context, document, this, x, y); } } } - public void getLocationInWindow(float[] value) { + public void getLocationInWindow(@NonNull float[] value) { value[0] += mX; value[1] += mY; if (mParent != null) { @@ -372,6 +429,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl } } + @NonNull @Override public String toString() { return "COMPONENT(<" @@ -393,14 +451,14 @@ public class Component extends PaintOperation implements Measurable, Serializabl + ") "; } + @NonNull protected String getSerializedName() { return "COMPONENT"; } @Override - public void serializeToString(int indent, StringSerializer serializer) { - serializer.append( - indent, + public void serializeToString(int indent, @NonNull StringSerializer serializer) { + String content = getSerializedName() + " [" + mComponentId @@ -416,9 +474,9 @@ public class Component extends PaintOperation implements Measurable, Serializabl + ", " + mHeight + "] " - + mVisibility - // + " [" + mNeedsMeasure + ", " + mNeedsRepaint + "]" - ); + + mVisibility; + // + " [" + mNeedsMeasure + ", " + mNeedsRepaint + "]" + serializer.append(indent, content); } @Override @@ -427,6 +485,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl } /** Returns the top-level RootLayoutComponent */ + @NonNull public RootLayoutComponent getRoot() throws Exception { if (this instanceof RootLayoutComponent) { return (RootLayoutComponent) this; @@ -441,6 +500,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl return (RootLayoutComponent) p; } + @NonNull @Override public String deepToString(String indent) { StringBuilder builder = new StringBuilder(); @@ -477,6 +537,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl } } + @NonNull public String content() { StringBuilder builder = new StringBuilder(); for (Operation op : mList) { @@ -487,6 +548,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl return builder.toString(); } + @NonNull public String textContent() { StringBuilder builder = new StringBuilder(); for (Operation ignored : mList) { @@ -499,7 +561,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl return builder.toString(); } - public void debugBox(Component component, PaintContext context) { + public void debugBox(@NonNull Component component, @NonNull PaintContext context) { float width = component.mWidth; float height = component.mHeight; @@ -536,13 +598,15 @@ public class Component extends PaintOperation implements Measurable, Serializabl return 0f; } - public void paintingComponent(PaintContext context) { + public void paintingComponent(@NonNull PaintContext context) { if (mPreTranslate != null) { mPreTranslate.paint(context); } + Component prev = context.getContext().lastComponent; + context.getContext().lastComponent = this; context.save(); context.translate(mX, mY); - if (context.isDebug()) { + if (context.isVisualDebug()) { debugBox(this, context); } for (Operation op : mList) { @@ -554,9 +618,10 @@ public class Component extends PaintOperation implements Measurable, Serializabl } } context.restore(); + context.getContext().lastComponent = prev; } - public boolean applyAnimationAsNeeded(PaintContext context) { + public boolean applyAnimationAsNeeded(@NonNull PaintContext context) { if (context.isAnimationEnabled() && mAnimateMeasure != null) { mAnimateMeasure.apply(context); needsRepaint(); @@ -566,8 +631,8 @@ public class Component extends PaintOperation implements Measurable, Serializabl } @Override - public void paint(PaintContext context) { - if (context.isDebug()) { + public void paint(@NonNull PaintContext context) { + if (context.isVisualDebug()) { context.save(); context.translate(mX, mY); context.savePaint(); @@ -594,7 +659,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl paintingComponent(context); } - public void getComponents(ArrayList<Component> components) { + public void getComponents(@NonNull ArrayList<Component> components) { for (Operation op : mList) { if (op instanceof Component) { components.add((Component) op); @@ -602,7 +667,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl } } - public void getData(ArrayList<TextData> data) { + public void getData(@NonNull ArrayList<TextData> data) { for (Operation op : mList) { if (op instanceof TextData) { data.add((TextData) op); @@ -631,6 +696,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl return mNeedsRepaint; } + @Nullable public Component getComponent(int cid) { if (mComponentId == cid || mAnimationId == cid) { return this; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentEnd.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentEnd.java index c83ee487a8ea..f370e20677e8 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentEnd.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentEnd.java @@ -15,6 +15,9 @@ */ package com.android.internal.widget.remotecompose.core.operations.layout; +import android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -26,10 +29,11 @@ import java.util.List; public class ComponentEnd implements Operation { @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer); } + @NonNull @Override public String toString() { return "COMPONENT_END"; @@ -40,11 +44,13 @@ public class ComponentEnd implements Operation { // nothing } + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@Nullable String indent) { return (indent != null ? indent : "") + toString(); } + @NonNull public static String name() { return "ComponentEnd"; } @@ -53,7 +59,7 @@ public class ComponentEnd implements Operation { return Operations.COMPONENT_END; } - public static void apply(WireBuffer buffer) { + public static void apply(@NonNull WireBuffer buffer) { buffer.start(Operations.COMPONENT_END); } @@ -61,11 +67,11 @@ public class ComponentEnd implements Operation { return 1 + 4 + 4 + 4; } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(WireBuffer buffer, @NonNull List<Operation> operations) { operations.add(new ComponentEnd()); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", id(), name()) .description( "End tag for components / layouts. This operation marks the end" diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentStart.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentStart.java index 72cc9b6d2613..f250d9ac4a01 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentStart.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentStart.java @@ -18,6 +18,9 @@ package com.android.internal.widget.remotecompose.core.operations.layout; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; +import android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -69,10 +72,11 @@ public class ComponentStart implements ComponentStartOperation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mType, mComponentId, mWidth, mHeight); } + @NonNull @Override public String toString() { return "COMPONENT_START (type " @@ -90,8 +94,9 @@ public class ComponentStart implements ComponentStartOperation { + ")"; } + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@Nullable String indent) { return (indent != null ? indent : "") + toString(); } @@ -119,6 +124,7 @@ public class ComponentStart implements ComponentStartOperation { public static final int LAYOUT_ROW = 15; public static final int LAYOUT_COLUMN = 16; + @NonNull public static String typeDescription(int type) { switch (type) { case DEFAULT: @@ -152,6 +158,7 @@ public class ComponentStart implements ComponentStartOperation { } } + @NonNull public static String name() { return "ComponentStart"; } @@ -161,7 +168,7 @@ public class ComponentStart implements ComponentStartOperation { } public static void apply( - WireBuffer buffer, int type, int componentId, float width, float height) { + @NonNull WireBuffer buffer, int type, int componentId, float width, float height) { buffer.start(Operations.COMPONENT_START); buffer.writeInt(type); buffer.writeInt(componentId); @@ -173,7 +180,7 @@ public class ComponentStart implements ComponentStartOperation { return 1 + 4 + 4 + 4; } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int type = buffer.readInt(); int componentId = buffer.readInt(); float width = buffer.readFloat(); @@ -181,7 +188,7 @@ public class ComponentStart implements ComponentStartOperation { operations.add(new ComponentStart(type, componentId, width, height)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", id(), name()) .description( "Basic component encapsulating draw commands." + "This is not resizable.") diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/DecoratorComponent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/DecoratorComponent.java index 314650fcd597..bb4311996df0 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/DecoratorComponent.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/DecoratorComponent.java @@ -15,7 +15,6 @@ */ package com.android.internal.widget.remotecompose.core.operations.layout; -import com.android.internal.widget.remotecompose.core.CoreDocument; import com.android.internal.widget.remotecompose.core.RemoteContext; /** @@ -24,7 +23,4 @@ import com.android.internal.widget.remotecompose.core.RemoteContext; */ public interface DecoratorComponent { void layout(RemoteContext context, float width, float height); - - void onClick( - RemoteContext context, CoreDocument document, Component component, float x, float y); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java index 8172502d092f..e0923dfb48fb 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java @@ -15,6 +15,9 @@ */ package com.android.internal.widget.remotecompose.core.operations.layout; +import android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.PaintContext; import com.android.internal.widget.remotecompose.core.operations.BitmapData; @@ -25,18 +28,22 @@ import com.android.internal.widget.remotecompose.core.operations.TextData; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ComponentModifiers; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ComponentVisibilityOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.DimensionModifierOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.GraphicsLayerModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.HeightModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.PaddingModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.WidthModifierOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ZIndexModifierOperation; import java.util.ArrayList; /** Component with modifiers and children */ public class LayoutComponent extends Component { - protected WidthModifierOperation mWidthModifier = null; - protected HeightModifierOperation mHeightModifier = null; + @Nullable protected WidthModifierOperation mWidthModifier = null; + @Nullable protected HeightModifierOperation mHeightModifier = null; + @Nullable protected ZIndexModifierOperation mZIndexModifier = null; + @Nullable protected GraphicsLayerModifierOperation mGraphicsLayerModifier = null; // Margins protected float mMarginLeft = 0f; @@ -49,8 +56,10 @@ public class LayoutComponent extends Component { protected float mPaddingTop = 0f; protected float mPaddingBottom = 0f; - protected ComponentModifiers mComponentModifiers = new ComponentModifiers(); - protected ArrayList<Component> mChildrenComponents = new ArrayList<>(); + @NonNull protected ComponentModifiers mComponentModifiers = new ComponentModifiers(); + @NonNull protected ArrayList<Component> mChildrenComponents = new ArrayList<>(); + + protected boolean mChildrenHaveZIndex = false; public LayoutComponent( Component parent, @@ -95,15 +104,25 @@ public class LayoutComponent extends Component { return mPaddingBottom; } + @Nullable public WidthModifierOperation getWidthModifier() { return mWidthModifier; } + @Nullable public HeightModifierOperation getHeightModifier() { return mHeightModifier; } - protected LayoutComponentContent mContent = null; + @Override + public float getZIndex() { + if (mZIndexModifier != null) { + return mZIndexModifier.getValue(); + } + return mZIndex; + } + + @Nullable protected LayoutComponentContent mContent = null; // Should be removed after ImageLayout is in private static final boolean USE_IMAGE_TEMP_FIX = true; @@ -164,6 +183,9 @@ public class LayoutComponent extends Component { for (Component c : mChildrenComponents) { c.mParent = this; mList.add(c); + if (c instanceof LayoutComponent && ((LayoutComponent) c).mZIndexModifier != null) { + mChildrenHaveZIndex = true; + } } mX = 0f; @@ -209,6 +231,12 @@ public class LayoutComponent extends Component { mHeightModifier = (HeightModifierOperation) op; applyVerticalMargin = false; } + if (op instanceof ZIndexModifierOperation) { + mZIndexModifier = (ZIndexModifierOperation) op; + } + if (op instanceof GraphicsLayerModifierOperation) { + mGraphicsLayerModifier = (GraphicsLayerModifierOperation) op; + } } if (mWidthModifier == null) { mWidthModifier = new WidthModifierOperation(DimensionModifierOperation.Type.WRAP); @@ -220,24 +248,64 @@ public class LayoutComponent extends Component { setHeight(computeModifierDefinedHeight()); } + @NonNull @Override public String toString() { return "UNKNOWN LAYOUT_COMPONENT"; } @Override - public void paintingComponent(PaintContext context) { + public void paintingComponent(@NonNull PaintContext context) { + Component prev = context.getContext().lastComponent; + context.getContext().lastComponent = this; context.save(); context.translate(mX, mY); + if (mGraphicsLayerModifier != null) { + context.startGraphicsLayer((int) getWidth(), (int) getHeight()); + float scaleX = mGraphicsLayerModifier.getScaleX(); + float scaleY = mGraphicsLayerModifier.getScaleY(); + float rotationX = mGraphicsLayerModifier.getRotationX(); + float rotationY = mGraphicsLayerModifier.getRotationY(); + float rotationZ = mGraphicsLayerModifier.getRotationZ(); + float shadowElevation = mGraphicsLayerModifier.getShadowElevation(); + float transformOriginX = mGraphicsLayerModifier.getTransformOriginX(); + float transformOriginY = mGraphicsLayerModifier.getTransformOriginY(); + float alpha = mGraphicsLayerModifier.getAlpha(); + int renderEffectId = mGraphicsLayerModifier.getRenderEffectId(); + context.setGraphicsLayer( + scaleX, + scaleY, + rotationX, + rotationY, + rotationZ, + shadowElevation, + transformOriginX, + transformOriginY, + alpha, + renderEffectId); + } mComponentModifiers.paint(context); float tx = mPaddingLeft; float ty = mPaddingTop; context.translate(tx, ty); - for (Component child : mChildrenComponents) { - child.paint(context); + if (mChildrenHaveZIndex) { + // TODO -- should only sort when something has changed + ArrayList<Component> sorted = new ArrayList<Component>(mChildrenComponents); + sorted.sort((a, b) -> (int) (a.getZIndex() - b.getZIndex())); + for (Component child : sorted) { + child.paint(context); + } + } else { + for (Component child : mChildrenComponents) { + child.paint(context); + } + } + if (mGraphicsLayerModifier != null) { + context.endGraphicsLayer(); } context.translate(-tx, -ty); context.restore(); + context.getContext().lastComponent = prev; } /** Traverse the modifiers to compute indicated dimension */ @@ -248,7 +316,8 @@ public class LayoutComponent extends Component { for (Operation c : mComponentModifiers.getList()) { if (c instanceof WidthModifierOperation) { WidthModifierOperation o = (WidthModifierOperation) c; - if (o.getType() == DimensionModifierOperation.Type.EXACT) { + if (o.getType() == DimensionModifierOperation.Type.EXACT + || o.getType() == DimensionModifierOperation.Type.EXACT_DP) { w = o.getValue(); } break; @@ -291,7 +360,8 @@ public class LayoutComponent extends Component { for (Operation c : mComponentModifiers.getList()) { if (c instanceof HeightModifierOperation) { HeightModifierOperation o = (HeightModifierOperation) c; - if (o.getType() == DimensionModifierOperation.Type.EXACT) { + if (o.getType() == DimensionModifierOperation.Type.EXACT + || o.getType() == DimensionModifierOperation.Type.EXACT_DP) { h = o.getValue(); } break; @@ -326,6 +396,7 @@ public class LayoutComponent extends Component { return t + b; } + @NonNull public ArrayList<Component> getChildrenComponents() { return mChildrenComponents; } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponentContent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponentContent.java index 66fd053c4b5e..0a085b43401c 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponentContent.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponentContent.java @@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.operations.layout; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.WireBuffer; @@ -38,6 +40,7 @@ public class LayoutComponentContent extends Component implements ComponentStartO super(parent, componentId, animationId, x, y, width, height); } + @NonNull public static String name() { return "LayoutContent"; } @@ -46,22 +49,23 @@ public class LayoutComponentContent extends Component implements ComponentStartO return Operations.LAYOUT_CONTENT; } + @NonNull @Override protected String getSerializedName() { return "CONTENT"; } - public static void apply(WireBuffer buffer, int componentId) { + public static void apply(@NonNull WireBuffer buffer, int componentId) { buffer.start(Operations.LAYOUT_CONTENT); buffer.writeInt(componentId); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int componentId = buffer.readInt(); operations.add(new LayoutComponentContent(componentId, 0, 0, 0, 0, null, -1)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", id(), name()) .field(INT, "COMPONENT_ID", "unique id for this component") .description( @@ -71,7 +75,7 @@ public class LayoutComponentContent extends Component implements ComponentStartO } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mComponentId); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ListActionsOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ListActionsOperation.java new file mode 100644 index 000000000000..c4df075bb9e8 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ListActionsOperation.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations.layout; + +import com.android.internal.widget.remotecompose.core.CoreDocument; +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.PaintOperation; +import com.android.internal.widget.remotecompose.core.RemoteContext; +import com.android.internal.widget.remotecompose.core.operations.TextData; +import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ModifierOperation; +import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; + +import java.util.ArrayList; + +public abstract class ListActionsOperation extends PaintOperation + implements ModifierOperation, DecoratorComponent { + + String mOperationName; + float mWidth = 0; + float mHeight = 0; + + private final float[] mLocationInWindow = new float[2]; + + public ListActionsOperation(String operationName) { + mOperationName = operationName; + } + + public ArrayList<Operation> mList = new ArrayList<>(); + + public ArrayList<Operation> getList() { + return mList; + } + + @Override + public String toString() { + return mOperationName; + } + + @Override + public void apply(RemoteContext context) { + for (Operation op : mList) { + if (op instanceof TextData) { + op.apply(context); + } + } + } + + @Override + public String deepToString(String indent) { + return (indent != null ? indent : "") + toString(); + } + + @Override + public void paint(PaintContext context) {} + + @Override + public void layout(RemoteContext context, float width, float height) { + mWidth = width; + mHeight = height; + } + + @Override + public void serializeToString(int indent, StringSerializer serializer) { + serializer.append(indent, mOperationName); + for (Operation o : mList) { + if (o instanceof ActionOperation) { + ((ActionOperation) o).serializeToString(indent + 1, serializer); + } + } + } + + public boolean applyActions( + RemoteContext context, + CoreDocument document, + Component component, + float x, + float y, + boolean force) { + if (!force && !component.isVisible()) { + return false; + } + if (!force && !component.contains(x, y)) { + return false; + } + mLocationInWindow[0] = 0f; + mLocationInWindow[1] = 0f; + component.getLocationInWindow(mLocationInWindow); + for (Operation o : mList) { + if (o instanceof ActionOperation) { + ((ActionOperation) o).runAction(context, document, component, x, y); + } + } + return true; + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopEnd.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopEnd.java index 3086d6aaa777..c90077b88782 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopEnd.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopEnd.java @@ -15,6 +15,9 @@ */ package com.android.internal.widget.remotecompose.core.operations.layout; +import android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -26,10 +29,11 @@ import java.util.List; public class LoopEnd implements Operation { @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer); } + @NonNull @Override public String toString() { return "LOOP_END"; @@ -40,11 +44,13 @@ public class LoopEnd implements Operation { // nothing } + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@Nullable String indent) { return (indent != null ? indent : "") + toString(); } + @NonNull public static String name() { return "LoopEnd"; } @@ -53,15 +59,15 @@ public class LoopEnd implements Operation { return Operations.LOOP_END; } - public static void apply(WireBuffer buffer) { + public static void apply(@NonNull WireBuffer buffer) { buffer.start(id()); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(WireBuffer buffer, @NonNull List<Operation> operations) { operations.add(new LoopEnd()); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Operations", id(), name()).description("End tag for loops"); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java index 691000810c20..eeaeafd284c0 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java @@ -15,6 +15,9 @@ */ package com.android.internal.widget.remotecompose.core.operations.layout; +import android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -30,7 +33,7 @@ import java.util.List; public class LoopOperation extends PaintOperation { private static final int OP_CODE = Operations.LOOP_START; - public ArrayList<Operation> mList = new ArrayList<>(); + @NonNull public ArrayList<Operation> mList = new ArrayList<>(); int mIndexVariableId; float mUntil = 12; @@ -49,27 +52,30 @@ public class LoopOperation extends PaintOperation { mIndexVariableId = indexId; } + @NonNull public ArrayList<Operation> getList() { return mList; } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mUntil, mFrom, mStep, mIndexVariableId); } + @NonNull @Override public String toString() { return "LoopOperation"; } + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@Nullable String indent) { return (indent != null ? indent : "") + toString(); } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { if (mIndexVariableId == 0) { for (float i = mFrom; i < mUntil; i += mStep) { for (Operation op : mList) { @@ -89,11 +95,13 @@ public class LoopOperation extends PaintOperation { } } + @NonNull public static String name() { return "Loop"; } - public static void apply(WireBuffer buffer, float count, float from, float step, int indexId) { + public static void apply( + @NonNull WireBuffer buffer, float count, float from, float step, int indexId) { buffer.start(OP_CODE); buffer.writeFloat(count); buffer.writeFloat(from); @@ -101,7 +109,7 @@ public class LoopOperation extends PaintOperation { buffer.writeInt(indexId); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { float count = buffer.readFloat(); float from = buffer.readFloat(); float step = buffer.readFloat(); @@ -109,7 +117,7 @@ public class LoopOperation extends PaintOperation { operations.add(new LoopOperation(count, from, step, indexId)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Operations", OP_CODE, name()) .description("Loop. This operation execute" + " a list of action in a loop"); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierEnd.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/OperationsListEnd.java index fe726ac78791..bd8d1f0ba9dd 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierEnd.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/OperationsListEnd.java @@ -15,6 +15,9 @@ */ package com.android.internal.widget.remotecompose.core.operations.layout; +import android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -23,16 +26,17 @@ import com.android.internal.widget.remotecompose.core.documentation.Documentatio import java.util.List; -public class ClickModifierEnd implements Operation { +public class OperationsListEnd implements Operation { @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer); } + @NonNull @Override public String toString() { - return "CLICK_END"; + return "LIST_END"; } @Override @@ -40,31 +44,31 @@ public class ClickModifierEnd implements Operation { // nothing } + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@Nullable String indent) { return (indent != null ? indent : "") + toString(); } + @NonNull public static String name() { - return "ClickModifierEnd"; + return "ListEnd"; } public static int id() { - return Operations.MODIFIER_CLICK_END; + return Operations.OPERATIONS_LIST_END; } - public static void apply(WireBuffer buffer) { + public static void apply(@NonNull WireBuffer buffer) { buffer.start(id()); } - public static void read(WireBuffer buffer, List<Operation> operations) { - operations.add(new ClickModifierEnd()); + public static void read(WireBuffer buffer, @NonNull List<Operation> operations) { + operations.add(new OperationsListEnd()); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", id(), name()) - .description( - "End tag for click modifiers. This operation marks the end" - + "of a click modifier"); + .description("End tag for list of operations."); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/RootLayoutComponent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/RootLayoutComponent.java index 680bb0b064d1..524ae59e70ec 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/RootLayoutComponent.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/RootLayoutComponent.java @@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.operations.layout; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -34,7 +36,8 @@ import java.util.List; /** Represents the root layout component. Entry point to the component tree layout/paint. */ public class RootLayoutComponent extends Component implements ComponentStartOperation { - int mCurrentId = -1; + private int mCurrentId = -1; + private boolean mHasTouchListeners = false; public RootLayoutComponent( int componentId, @@ -52,6 +55,7 @@ public class RootLayoutComponent extends Component implements ComponentStartOper super(parent, componentId, -1, x, y, width, height); } + @NonNull @Override public String toString() { return "ROOT " @@ -69,7 +73,7 @@ public class RootLayoutComponent extends Component implements ComponentStartOper } @Override - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { serializer.append( indent, "ROOT [" @@ -89,6 +93,15 @@ public class RootLayoutComponent extends Component implements ComponentStartOper } /** + * Set the flag to traverse the tree when touch events happen + * + * @param value true to indicate that the tree has touch listeners + */ + public void setHasTouchListeners(boolean value) { + mHasTouchListeners = value; + } + + /** * Traverse the hierarchy and assign generated ids to component without ids. Most components * would already have ids assigned during the document creation, but this allow us to take care * of any components added during the inflation. @@ -100,7 +113,7 @@ public class RootLayoutComponent extends Component implements ComponentStartOper assignId(this); } - private void assignId(Component component) { + private void assignId(@NonNull Component component) { if (component.mComponentId == -1) { mCurrentId--; component.mComponentId = mCurrentId; @@ -113,7 +126,7 @@ public class RootLayoutComponent extends Component implements ComponentStartOper } /** This will measure then layout the tree of components */ - public void layout(RemoteContext context) { + public void layout(@NonNull RemoteContext context) { if (!mNeedsMeasure) { return; } @@ -134,7 +147,7 @@ public class RootLayoutComponent extends Component implements ComponentStartOper } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { mNeedsRepaint = false; context.getContext().lastComponent = this; context.save(); @@ -152,13 +165,15 @@ public class RootLayoutComponent extends Component implements ComponentStartOper context.restore(); } + @NonNull public String displayHierarchy() { StringSerializer serializer = new StringSerializer(); displayHierarchy(this, 0, serializer); return serializer.toString(); } - public void displayHierarchy(Component component, int indent, StringSerializer serializer) { + public void displayHierarchy( + @NonNull Component component, int indent, @NonNull StringSerializer serializer) { component.serializeToString(indent, serializer); for (Operation c : component.mList) { if (c instanceof ComponentModifiers) { @@ -171,6 +186,7 @@ public class RootLayoutComponent extends Component implements ComponentStartOper } } + @NonNull public static String name() { return "RootLayout"; } @@ -179,17 +195,17 @@ public class RootLayoutComponent extends Component implements ComponentStartOper return Operations.LAYOUT_ROOT; } - public static void apply(WireBuffer buffer, int componentId) { + public static void apply(@NonNull WireBuffer buffer, int componentId) { buffer.start(Operations.LAYOUT_ROOT); buffer.writeInt(componentId); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int componentId = buffer.readInt(); operations.add(new RootLayoutComponent(componentId, 0, 0, 0, 0, null, -1)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", id(), name()) .field(INT, "COMPONENT_ID", "unique id for this component") .description( @@ -199,7 +215,11 @@ public class RootLayoutComponent extends Component implements ComponentStartOper } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mComponentId); } + + public boolean hasTouchListeners() { + return mHasTouchListeners; + } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchCancelModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchCancelModifierOperation.java new file mode 100644 index 000000000000..486efbd6e00f --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchCancelModifierOperation.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations.layout; + +import com.android.internal.widget.remotecompose.core.CoreDocument; +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.RemoteContext; +import com.android.internal.widget.remotecompose.core.WireBuffer; +import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; + +import java.util.List; + +/** Represents a touch cancel modifier + actions */ +public class TouchCancelModifierOperation extends ListActionsOperation implements TouchHandler { + + private static final int OP_CODE = Operations.MODIFIER_TOUCH_CANCEL; + + public TouchCancelModifierOperation() { + super("TOUCH_CANCEL_MODIFIER"); + } + + @Override + public void write(WireBuffer buffer) { + apply(buffer); + } + + @Override + public String toString() { + return "TouchCancelModifier"; + } + + @Override + public void apply(RemoteContext context) { + RootLayoutComponent root = context.getDocument().getRootLayoutComponent(); + if (root != null) { + root.setHasTouchListeners(true); + } + super.apply(context); + } + + @Override + public void onTouchDown( + RemoteContext context, CoreDocument document, Component component, float x, float y) { + // nothing + } + + @Override + public void onTouchUp( + RemoteContext context, CoreDocument document, Component component, float x, float y) { + // nothing + } + + @Override + public void onTouchCancel( + RemoteContext context, CoreDocument document, Component component, float x, float y) { + applyActions(context, document, component, x, y, true); + } + + public static String name() { + return "TouchCancelModifier"; + } + + public static void apply(WireBuffer buffer) { + buffer.start(OP_CODE); + } + + public static void read(WireBuffer buffer, List<Operation> operations) { + operations.add(new TouchCancelModifierOperation()); + } + + public static void documentation(DocumentationBuilder doc) { + doc.operation("Modifier Operations", OP_CODE, name()) + .description( + "Touch cancel modifier. This operation contains" + + " a list of action executed on Touch cancel"); + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchDownModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchDownModifierOperation.java new file mode 100644 index 000000000000..5d379fe01d61 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchDownModifierOperation.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations.layout; + +import com.android.internal.widget.remotecompose.core.CoreDocument; +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.RemoteContext; +import com.android.internal.widget.remotecompose.core.WireBuffer; +import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; + +import java.util.List; + +/** Represents a touch down modifier + actions */ +public class TouchDownModifierOperation extends ListActionsOperation implements TouchHandler { + + private static final int OP_CODE = Operations.MODIFIER_TOUCH_DOWN; + + public TouchDownModifierOperation() { + super("TOUCH_DOWN_MODIFIER"); + } + + @Override + public void write(WireBuffer buffer) { + apply(buffer); + } + + @Override + public String toString() { + return "TouchDownModifier"; + } + + @Override + public void apply(RemoteContext context) { + RootLayoutComponent root = context.getDocument().getRootLayoutComponent(); + if (root != null) { + root.setHasTouchListeners(true); + } + super.apply(context); + } + + @Override + public void onTouchDown( + RemoteContext context, CoreDocument document, Component component, float x, float y) { + if (applyActions(context, document, component, x, y, false)) { + document.appliedTouchOperation(component); + } + } + + @Override + public void onTouchUp( + RemoteContext context, CoreDocument document, Component component, float x, float y) { + // nothing + } + + @Override + public void onTouchCancel( + RemoteContext context, CoreDocument document, Component component, float x, float y) { + // nothing + } + + public static String name() { + return "TouchModifier"; + } + + public static void apply(WireBuffer buffer) { + buffer.start(OP_CODE); + } + + public static void read(WireBuffer buffer, List<Operation> operations) { + operations.add(new TouchDownModifierOperation()); + } + + public static void documentation(DocumentationBuilder doc) { + doc.operation("Modifier Operations", OP_CODE, name()) + .description( + "Touch down modifier. This operation contains" + + " a list of action executed on Touch down"); + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchHandler.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchHandler.java new file mode 100644 index 000000000000..5adfc33b5ef5 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchHandler.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations.layout; + +import com.android.internal.widget.remotecompose.core.CoreDocument; +import com.android.internal.widget.remotecompose.core.RemoteContext; + +/** Interface to represent operations that can handle touch events */ +public interface TouchHandler { + + /** + * callback for a touch down event + * + * @param context the current context + * @param document the current document + * @param component the component on which the touch has been received + * @param x the x position of the click in document coordinates + * @param y the y position of the click in document coordinates + */ + void onTouchDown( + RemoteContext context, CoreDocument document, Component component, float x, float y); + + /** + * callback for a touch up event + * + * @param context the current context + * @param document the current document + * @param component the component on which the touch has been received + * @param x the x position of the click in document coordinates + * @param y the y position of the click in document coordinates + */ + void onTouchUp( + RemoteContext context, CoreDocument document, Component component, float x, float y); + + /** + * callback for a touch cancel event + * + * @param context the current context + * @param document the current document + * @param component the component on which the touch has been received + * @param x the x position of the click in document coordinates + * @param y the y position of the click in document coordinates + */ + void onTouchCancel( + RemoteContext context, CoreDocument document, Component component, float x, float y); +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchUpModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchUpModifierOperation.java new file mode 100644 index 000000000000..263cc43d5e74 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchUpModifierOperation.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations.layout; + +import com.android.internal.widget.remotecompose.core.CoreDocument; +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.RemoteContext; +import com.android.internal.widget.remotecompose.core.WireBuffer; +import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; + +import java.util.List; + +/** Represents a touch up modifier + actions */ +public class TouchUpModifierOperation extends ListActionsOperation implements TouchHandler { + + private static final int OP_CODE = Operations.MODIFIER_TOUCH_UP; + + public TouchUpModifierOperation() { + super("TOUCH_UP_MODIFIER"); + } + + @Override + public void write(WireBuffer buffer) { + apply(buffer); + } + + @Override + public String toString() { + return "TouchUpModifier"; + } + + @Override + public void apply(RemoteContext context) { + RootLayoutComponent root = context.getDocument().getRootLayoutComponent(); + if (root != null) { + root.setHasTouchListeners(true); + } + super.apply(context); + } + + @Override + public void onTouchDown( + RemoteContext context, CoreDocument document, Component component, float x, float y) { + // nothing + } + + @Override + public void onTouchUp( + RemoteContext context, CoreDocument document, Component component, float x, float y) { + applyActions(context, document, component, x, y, true); + } + + @Override + public void onTouchCancel( + RemoteContext context, CoreDocument document, Component component, float x, float y) { + // nothing + } + + public static String name() { + return "TouchUpModifier"; + } + + public static void apply(WireBuffer buffer) { + buffer.start(OP_CODE); + } + + public static void read(WireBuffer buffer, List<Operation> operations) { + operations.add(new TouchUpModifierOperation()); + } + + public static void documentation(DocumentationBuilder doc) { + doc.operation("Modifier Operations", OP_CODE, name()) + .description( + "Touch up modifier. This operation contains" + + " a list of action executed on Touch up"); + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimateMeasure.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimateMeasure.java index e45058528859..6036b74efad3 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimateMeasure.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimateMeasure.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations.layout.animation; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.PaintContext; import com.android.internal.widget.remotecompose.core.operations.layout.Component; @@ -44,18 +46,23 @@ public class AnimateMeasure { float mP = 0f; float mVp = 0f; + + @NonNull FloatAnimation mMotionEasing = new FloatAnimation(mMotionEasingType, mDuration / 1000f, null, 0f, Float.NaN); + + @NonNull FloatAnimation mVisibilityEasing = new FloatAnimation( mVisibilityEasingType, mDurationVisibilityChange / 1000f, null, 0f, Float.NaN); + ParticleAnimation mParticleAnimation; public AnimateMeasure( long startTime, - Component component, + @NonNull Component component, ComponentMeasure original, - ComponentMeasure target, + @NonNull ComponentMeasure target, int duration, int durationVisibilityChange, AnimationSpec.ANIMATION enterAnimation, @@ -94,9 +101,9 @@ public class AnimateMeasure { mVp = mVisibilityEasing.get(visibilityProgress); } - public PaintBundle paint = new PaintBundle(); + @NonNull public PaintBundle paint = new PaintBundle(); - public void apply(PaintContext context) { + public void apply(@NonNull PaintContext context) { update(context.getContext().currentTime); mComponent.setX(getX()); @@ -338,7 +345,7 @@ public class AnimateMeasure { } } - public void updateTarget(ComponentMeasure measure, long currentTime) { + public void updateTarget(@NonNull ComponentMeasure measure, long currentTime) { mOriginal.setX(getX()); mOriginal.setY(getY()); mOriginal.setW(getWidth()); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimationSpec.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimationSpec.java index 35533cb95190..47abadeb70fa 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimationSpec.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimationSpec.java @@ -17,6 +17,9 @@ package com.android.internal.widget.remotecompose.core.operations.layout.animati import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; +import android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -92,6 +95,7 @@ public class AnimationSpec implements Operation { return mExitAnimation; } + @NonNull @Override public String toString() { return "ANIMATION_SPEC (" + mMotionDuration + " ms)"; @@ -109,7 +113,7 @@ public class AnimationSpec implements Operation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply( buffer, mAnimationId, @@ -126,11 +130,13 @@ public class AnimationSpec implements Operation { // nothing here } + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@Nullable String indent) { return (indent != null ? indent : "") + toString(); } + @NonNull public static String name() { return "AnimationSpec"; } @@ -139,10 +145,11 @@ public class AnimationSpec implements Operation { return Operations.ANIMATION_SPEC; } - public static int animationToInt(ANIMATION animation) { + public static int animationToInt(@NonNull ANIMATION animation) { return animation.ordinal(); } + @NonNull public static ANIMATION intToAnimation(int value) { switch (value) { case 0: @@ -167,14 +174,14 @@ public class AnimationSpec implements Operation { } public static void apply( - WireBuffer buffer, + @NonNull WireBuffer buffer, int animationId, int motionDuration, int motionEasingType, int visibilityDuration, int visibilityEasingType, - ANIMATION enterAnimation, - ANIMATION exitAnimation) { + @NonNull ANIMATION enterAnimation, + @NonNull ANIMATION exitAnimation) { buffer.start(Operations.ANIMATION_SPEC); buffer.writeInt(animationId); buffer.writeInt(motionDuration); @@ -185,7 +192,7 @@ public class AnimationSpec implements Operation { buffer.writeInt(animationToInt(exitAnimation)); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int animationId = buffer.readInt(); int motionDuration = buffer.readInt(); int motionEasingType = buffer.readInt(); @@ -205,7 +212,7 @@ public class AnimationSpec implements Operation { operations.add(op); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", id(), name()) .description("define the animation") .field(INT, "animationId", "") diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/ParticleAnimation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/ParticleAnimation.java index 686643fbe1bc..37d20781f4fa 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/ParticleAnimation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/ParticleAnimation.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations.layout.animation; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.PaintContext; import com.android.internal.widget.remotecompose.core.operations.layout.Component; import com.android.internal.widget.remotecompose.core.operations.layout.measure.ComponentMeasure; @@ -24,14 +26,14 @@ import java.util.ArrayList; import java.util.HashMap; public class ParticleAnimation { - HashMap<Integer, ArrayList<Particle>> mAllParticles = new HashMap<>(); + @NonNull HashMap<Integer, ArrayList<Particle>> mAllParticles = new HashMap<>(); - PaintBundle mPaint = new PaintBundle(); + @NonNull PaintBundle mPaint = new PaintBundle(); public void animate( - PaintContext context, - Component component, - ComponentMeasure start, + @NonNull PaintContext context, + @NonNull Component component, + @NonNull ComponentMeasure start, ComponentMeasure end, float progress) { ArrayList<Particle> particles = mAllParticles.get(component.getComponentId()); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/BoxLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/BoxLayout.java index 047a968785c4..f3e550903a65 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/BoxLayout.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/BoxLayout.java @@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.operations.layout.manager import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -75,6 +77,7 @@ public class BoxLayout extends LayoutManager implements ComponentStartOperation verticalPositioning); } + @NonNull @Override public String toString() { return "BOX [" @@ -93,6 +96,7 @@ public class BoxLayout extends LayoutManager implements ComponentStartOperation + mVisibility; } + @NonNull @Override protected String getSerializedName() { return "BOX"; @@ -100,7 +104,11 @@ public class BoxLayout extends LayoutManager implements ComponentStartOperation @Override public void computeWrapSize( - PaintContext context, float maxWidth, float maxHeight, MeasurePass measure, Size size) { + PaintContext context, + float maxWidth, + float maxHeight, + @NonNull MeasurePass measure, + @NonNull Size size) { for (Component c : mChildrenComponents) { c.measure(context, 0f, maxWidth, 0f, maxHeight, measure); ComponentMeasure m = measure.get(c); @@ -119,14 +127,14 @@ public class BoxLayout extends LayoutManager implements ComponentStartOperation float maxWidth, float minHeight, float maxHeight, - MeasurePass measure) { + @NonNull MeasurePass measure) { for (Component child : mChildrenComponents) { child.measure(context, minWidth, maxWidth, minHeight, maxHeight, measure); } } @Override - public void internalLayoutMeasure(PaintContext context, MeasurePass measure) { + public void internalLayoutMeasure(PaintContext context, @NonNull MeasurePass measure) { ComponentMeasure selfMeasure = measure.get(this); float selfWidth = selfMeasure.getW() - mPaddingLeft - mPaddingRight; float selfHeight = selfMeasure.getH() - mPaddingTop - mPaddingBottom; @@ -161,6 +169,7 @@ public class BoxLayout extends LayoutManager implements ComponentStartOperation } } + @NonNull public static String name() { return "BoxLayout"; } @@ -170,7 +179,7 @@ public class BoxLayout extends LayoutManager implements ComponentStartOperation } public static void apply( - WireBuffer buffer, + @NonNull WireBuffer buffer, int componentId, int animationId, int horizontalPositioning, @@ -182,7 +191,7 @@ public class BoxLayout extends LayoutManager implements ComponentStartOperation buffer.writeInt(verticalPositioning); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int componentId = buffer.readInt(); int animationId = buffer.readInt(); int horizontalPositioning = buffer.readInt(); @@ -196,7 +205,7 @@ public class BoxLayout extends LayoutManager implements ComponentStartOperation verticalPositioning)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", id(), name()) .description( "Box layout implementation.\n\n" @@ -224,7 +233,7 @@ public class BoxLayout extends LayoutManager implements ComponentStartOperation } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mComponentId, mAnimationId, mHorizontalPositioning, mVerticalPositioning); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CanvasLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CanvasLayout.java index f79976715ab3..12ff969530b3 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CanvasLayout.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CanvasLayout.java @@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.operations.layout.manager import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -44,6 +46,7 @@ public class CanvasLayout extends BoxLayout { this(parent, componentId, animationId, 0, 0, 0, 0); } + @NonNull @Override public String toString() { return "CANVAS [" @@ -62,11 +65,13 @@ public class CanvasLayout extends BoxLayout { + mVisibility; } + @NonNull @Override protected String getSerializedName() { return "CANVAS"; } + @NonNull public static String name() { return "CanvasLayout"; } @@ -75,19 +80,19 @@ public class CanvasLayout extends BoxLayout { return Operations.LAYOUT_CANVAS; } - public static void apply(WireBuffer buffer, int componentId, int animationId) { + public static void apply(@NonNull WireBuffer buffer, int componentId, int animationId) { buffer.start(Operations.LAYOUT_CANVAS); buffer.writeInt(componentId); buffer.writeInt(animationId); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int componentId = buffer.readInt(); int animationId = buffer.readInt(); operations.add(new CanvasLayout(null, componentId, animationId)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", id(), name()) .description("Canvas implementation. Encapsulate draw operations.\n\n") .field(INT, "COMPONENT_ID", "unique id for this component") @@ -98,7 +103,7 @@ public class CanvasLayout extends BoxLayout { } @Override - public void internalLayoutMeasure(PaintContext context, MeasurePass measure) { + public void internalLayoutMeasure(PaintContext context, @NonNull MeasurePass measure) { ComponentMeasure selfMeasure = measure.get(this); float selfWidth = selfMeasure.getW() - mPaddingLeft - mPaddingRight; float selfHeight = selfMeasure.getH() - mPaddingTop - mPaddingBottom; @@ -112,7 +117,7 @@ public class CanvasLayout extends BoxLayout { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mComponentId, mAnimationId); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/ColumnLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/ColumnLayout.java index 402b784343ad..52bf4c54faf6 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/ColumnLayout.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/ColumnLayout.java @@ -18,6 +18,8 @@ package com.android.internal.widget.remotecompose.core.operations.layout.manager import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -87,6 +89,7 @@ public class ColumnLayout extends LayoutManager implements ComponentStartOperati spacedBy); } + @NonNull @Override public String toString() { return "COLUMN [" @@ -105,14 +108,24 @@ public class ColumnLayout extends LayoutManager implements ComponentStartOperati + mVisibility; } + @NonNull @Override protected String getSerializedName() { return "COLUMN"; } @Override + public boolean isInVerticalFill() { + return super.isInVerticalFill() || childrenHaveVerticalWeights(); + } + + @Override public void computeWrapSize( - PaintContext context, float maxWidth, float maxHeight, MeasurePass measure, Size size) { + PaintContext context, + float maxWidth, + float maxHeight, + @NonNull MeasurePass measure, + @NonNull Size size) { DebugLog.s(() -> "COMPUTE WRAP SIZE in " + this + " (" + mComponentId + ")"); int visibleChildrens = 0; for (Component c : mChildrenComponents) { @@ -137,7 +150,7 @@ public class ColumnLayout extends LayoutManager implements ComponentStartOperati float maxWidth, float minHeight, float maxHeight, - MeasurePass measure) { + @NonNull MeasurePass measure) { DebugLog.s(() -> "COMPUTE SIZE in " + this + " (" + mComponentId + ")"); float mh = maxHeight; for (Component child : mChildrenComponents) { @@ -151,7 +164,7 @@ public class ColumnLayout extends LayoutManager implements ComponentStartOperati } @Override - public void internalLayoutMeasure(PaintContext context, MeasurePass measure) { + public void internalLayoutMeasure(PaintContext context, @NonNull MeasurePass measure) { ComponentMeasure selfMeasure = measure.get(this); DebugLog.s( () -> @@ -302,6 +315,7 @@ public class ColumnLayout extends LayoutManager implements ComponentStartOperati DebugLog.e(); } + @NonNull public static String name() { return "ColumnLayout"; } @@ -311,7 +325,7 @@ public class ColumnLayout extends LayoutManager implements ComponentStartOperati } public static void apply( - WireBuffer buffer, + @NonNull WireBuffer buffer, int componentId, int animationId, int horizontalPositioning, @@ -325,7 +339,7 @@ public class ColumnLayout extends LayoutManager implements ComponentStartOperati buffer.writeFloat(spacedBy); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int componentId = buffer.readInt(); int animationId = buffer.readInt(); int horizontalPositioning = buffer.readInt(); @@ -341,7 +355,7 @@ public class ColumnLayout extends LayoutManager implements ComponentStartOperati spacedBy)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", id(), name()) .description( "Column layout implementation, positioning components one" @@ -374,7 +388,7 @@ public class ColumnLayout extends LayoutManager implements ComponentStartOperati } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply( buffer, mComponentId, diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/LayoutManager.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/LayoutManager.java index 308ed64ee8ea..0c4d24a4561a 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/LayoutManager.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/LayoutManager.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations.layout.managers; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.PaintContext; import com.android.internal.widget.remotecompose.core.RemoteContext; import com.android.internal.widget.remotecompose.core.operations.layout.Component; @@ -27,7 +29,7 @@ import com.android.internal.widget.remotecompose.core.operations.layout.measure. /** Base class for layout managers -- resizable components. */ public abstract class LayoutManager extends LayoutComponent implements Measurable { - Size mCachedWrapSize = new Size(0f, 0f); + @NonNull Size mCachedWrapSize = new Size(0f, 0f); public LayoutManager( Component parent, @@ -62,6 +64,38 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl // nothing here } + protected boolean childrenHaveHorizontalWeights() { + for (Component c : mChildrenComponents) { + if (c instanceof LayoutManager) { + LayoutManager m = (LayoutManager) c; + if (m.getWidthModifier() != null && m.getWidthModifier().hasWeight()) { + return true; + } + } + } + return false; + } + + protected boolean childrenHaveVerticalWeights() { + for (Component c : mChildrenComponents) { + if (c instanceof LayoutManager) { + LayoutManager m = (LayoutManager) c; + if (m.getHeightModifier() != null && m.getHeightModifier().hasWeight()) { + return true; + } + } + } + return false; + } + + public boolean isInHorizontalFill() { + return mWidthModifier.isFill(); + } + + public boolean isInVerticalFill() { + return mHeightModifier.isFill(); + } + /** Base implementation of the measure resolution */ @Override public void measure( @@ -70,7 +104,7 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl float maxWidth, float minHeight, float maxHeight, - MeasurePass measure) { + @NonNull MeasurePass measure) { boolean hasWrap = true; float measuredWidth = Math.min(maxWidth, computeModifierDefinedWidth() - mMarginLeft - mMarginRight); @@ -87,7 +121,7 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl } else { hasWrap = false; } - if (mWidthModifier.isFill()) { + if (isInHorizontalFill()) { measuredWidth = insetMaxWidth; } else if (mWidthModifier.hasWeight()) { measuredWidth = Math.max(measuredWidth, computeModifierDefinedWidth()); @@ -95,7 +129,7 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl measuredWidth = Math.max(measuredWidth, minWidth); measuredWidth = Math.min(measuredWidth, insetMaxWidth); } - if (mHeightModifier.isFill()) { + if (isInVerticalFill()) { measuredHeight = insetMaxHeight; } else if (mHeightModifier.hasWeight()) { measuredHeight = Math.max(measuredHeight, computeModifierDefinedHeight()); @@ -136,7 +170,7 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl /** basic layout of internal components */ @Override - public void layout(RemoteContext context, MeasurePass measure) { + public void layout(@NonNull RemoteContext context, @NonNull MeasurePass measure) { super.layout(context, measure); ComponentMeasure self = measure.get(this); @@ -153,7 +187,7 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl * @param context * @param measure */ - public void selfLayout(RemoteContext context, MeasurePass measure) { + public void selfLayout(@NonNull RemoteContext context, @NonNull MeasurePass measure) { super.layout(context, measure); ComponentMeasure self = measure.get(this); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/RowLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/RowLayout.java index b29a05c27e5f..a366dc804758 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/RowLayout.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/RowLayout.java @@ -18,6 +18,8 @@ package com.android.internal.widget.remotecompose.core.operations.layout.manager import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -85,6 +87,7 @@ public class RowLayout extends LayoutManager implements ComponentStartOperation spacedBy); } + @NonNull @Override public String toString() { return "ROW [" @@ -103,14 +106,24 @@ public class RowLayout extends LayoutManager implements ComponentStartOperation + mVisibility; } + @NonNull @Override protected String getSerializedName() { return "ROW"; } @Override + public boolean isInHorizontalFill() { + return super.isInHorizontalFill() || childrenHaveHorizontalWeights(); + } + + @Override public void computeWrapSize( - PaintContext context, float maxWidth, float maxHeight, MeasurePass measure, Size size) { + PaintContext context, + float maxWidth, + float maxHeight, + @NonNull MeasurePass measure, + @NonNull Size size) { DebugLog.s(() -> "COMPUTE WRAP SIZE in " + this + " (" + mComponentId + ")"); // int visibleChildrens = 0; for (Component c : mChildrenComponents) { @@ -135,7 +148,7 @@ public class RowLayout extends LayoutManager implements ComponentStartOperation float maxWidth, float minHeight, float maxHeight, - MeasurePass measure) { + @NonNull MeasurePass measure) { DebugLog.s(() -> "COMPUTE SIZE in " + this + " (" + mComponentId + ")"); float mw = maxWidth; for (Component child : mChildrenComponents) { @@ -149,7 +162,7 @@ public class RowLayout extends LayoutManager implements ComponentStartOperation } @Override - public void internalLayoutMeasure(PaintContext context, MeasurePass measure) { + public void internalLayoutMeasure(PaintContext context, @NonNull MeasurePass measure) { ComponentMeasure selfMeasure = measure.get(this); DebugLog.s( () -> @@ -305,6 +318,7 @@ public class RowLayout extends LayoutManager implements ComponentStartOperation DebugLog.e(); } + @NonNull public static String name() { return "RowLayout"; } @@ -314,7 +328,7 @@ public class RowLayout extends LayoutManager implements ComponentStartOperation } public static void apply( - WireBuffer buffer, + @NonNull WireBuffer buffer, int componentId, int animationId, int horizontalPositioning, @@ -328,7 +342,7 @@ public class RowLayout extends LayoutManager implements ComponentStartOperation buffer.writeFloat(spacedBy); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int componentId = buffer.readInt(); int animationId = buffer.readInt(); int horizontalPositioning = buffer.readInt(); @@ -344,7 +358,7 @@ public class RowLayout extends LayoutManager implements ComponentStartOperation spacedBy)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", id(), name()) .description( "Row layout implementation, positioning components one" @@ -377,7 +391,7 @@ public class RowLayout extends LayoutManager implements ComponentStartOperation } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply( buffer, mComponentId, diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/StateLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/StateLayout.java index b5c728135f76..e47ffdebb253 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/StateLayout.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/StateLayout.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations.layout.managers; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.CoreDocument; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; @@ -50,10 +52,10 @@ public class StateLayout extends LayoutManager implements ComponentStartOperatio // This keep track of all the components associated with a given Id, // (the key being the id), and the set of components corresponds to the set of states // TODO: we should be able to optimize this - public Map<Integer, Component[]> statePaintedComponents = new HashMap<>(); + @NonNull public Map<Integer, Component[]> statePaintedComponents = new HashMap<>(); public int MAX_CACHE_ELEMENTS = 16; - public int[] cacheListElementsId = new int[MAX_CACHE_ELEMENTS]; + @NonNull public int[] cacheListElementsId = new int[MAX_CACHE_ELEMENTS]; public boolean inTransition = false; @@ -168,7 +170,7 @@ public class StateLayout extends LayoutManager implements ComponentStartOperatio } @Override - public void layout(RemoteContext context, MeasurePass measure) { + public void layout(@NonNull RemoteContext context, @NonNull MeasurePass measure) { ComponentMeasure self = measure.get(this); super.selfLayout(context, measure); @@ -207,12 +209,12 @@ public class StateLayout extends LayoutManager implements ComponentStartOperatio @Override public void measure( - PaintContext context, + @NonNull PaintContext context, float minWidth, float maxWidth, float minHeight, float maxHeight, - MeasurePass measure) { + @NonNull MeasurePass measure) { // The general approach for this widget is to do most of the work/setup in measure. // layout and paint then simply use what's been setup in the measure phase. @@ -364,19 +366,20 @@ public class StateLayout extends LayoutManager implements ComponentStartOperatio } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { if (mIndexId != 0) { int newValue = context.getContext().mRemoteComposeState.getInteger(mIndexId); if (newValue != currentLayoutIndex) { previousLayoutIndex = currentLayoutIndex; currentLayoutIndex = newValue; inTransition = true; - System.out.println("currentLayout index is $currentLayoutIndex"); + // System.out.println("currentLayout index is $currentLayoutIndex"); // executeValueSetActions(getLayout(currentLayoutIndex)); invalidateMeasure(); } } - System.out.println("PAINTING LAYOUT STATELAYOUT, CURRENT INDEX " + currentLayoutIndex); + // System.out.println("PAINTING LAYOUT STATELAYOUT, CURRENT INDEX " + + // currentLayoutIndex); // Make sure to mark any components that are not in either the current or previous layout // as being GONE. int index = 0; @@ -529,6 +532,7 @@ public class StateLayout extends LayoutManager implements ComponentStartOperatio // } // } + @NonNull @Override public String toString() { return "STATE_LAYOUT"; @@ -539,7 +543,7 @@ public class StateLayout extends LayoutManager implements ComponentStartOperatio // } public static void apply( - WireBuffer buffer, + @NonNull WireBuffer buffer, int componentId, int animationId, int horizontalPositioning, @@ -553,7 +557,7 @@ public class StateLayout extends LayoutManager implements ComponentStartOperatio buffer.writeInt(indexId); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int componentId = buffer.readInt(); int animationId = buffer.readInt(); buffer.readInt(); // horizontalPositioning diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java index c1cabcd09c39..8aa7712635fc 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java @@ -18,6 +18,8 @@ package com.android.internal.widget.remotecompose.core.operations.layout.manager import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -44,22 +46,24 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation private int mFontStyle = 0; private float mFontWeight = 400f; private int mFontFamilyId = -1; + private int mTextAlign = -1; private int mType = -1; private float mTextX; private float mTextY; + private float mTextW; private String mCachedString = ""; @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { if (mTextId != -1) { context.listensTo(mTextId, this); } } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { mCachedString = context.getText(mTextId); if (mType == -1) { if (mFontFamilyId != -1) { @@ -97,7 +101,8 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation float fontSize, int fontStyle, float fontWeight, - int fontFamilyId) { + int fontFamilyId, + int textAlign) { super(parent, componentId, animationId, x, y, width, height); mTextId = textId; mColor = color; @@ -105,6 +110,7 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation mFontStyle = fontStyle; mFontWeight = fontWeight; mFontFamilyId = fontFamilyId; + mTextAlign = textAlign; } public TextLayout( @@ -116,7 +122,8 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation float fontSize, int fontStyle, float fontWeight, - int fontFamilyId) { + int fontFamilyId, + int textAlign) { this( parent, componentId, @@ -130,13 +137,14 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation fontSize, fontStyle, fontWeight, - fontFamilyId); + fontFamilyId, + textAlign); } - public PaintBundle mPaint = new PaintBundle(); + @NonNull public PaintBundle mPaint = new PaintBundle(); @Override - public void paintingComponent(PaintContext context) { + public void paintingComponent(@NonNull PaintContext context) { context.save(); context.translate(mX, mY); mComponentModifiers.paint(context); @@ -176,6 +184,7 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation context.restore(); } + @NonNull @Override public String toString() { return "TEXT_LAYOUT [" @@ -194,13 +203,14 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation + mVisibility; } + @NonNull @Override protected String getSerializedName() { return "TEXT_LAYOUT"; } @Override - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { serializer.append( indent, getSerializedName() @@ -228,7 +238,11 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation @Override public void computeWrapSize( - PaintContext context, float maxWidth, float maxHeight, MeasurePass measure, Size size) { + @NonNull PaintContext context, + float maxWidth, + float maxHeight, + MeasurePass measure, + @NonNull Size size) { context.savePaint(); mPaint.reset(); mPaint.setTextSize(mFontSize); @@ -244,8 +258,10 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation mTextX = -bounds[0]; size.setHeight(h); mTextY = -bounds[1]; + mTextW = w; } + @NonNull public static String name() { return "TextLayout"; } @@ -255,7 +271,7 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation } public static void apply( - WireBuffer buffer, + @NonNull WireBuffer buffer, int componentId, int animationId, int textId, @@ -263,7 +279,8 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation float fontSize, int fontStyle, float fontWeight, - int fontFamilyId) { + int fontFamilyId, + int textAlign) { buffer.start(id()); buffer.writeInt(componentId); buffer.writeInt(animationId); @@ -273,9 +290,10 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation buffer.writeInt(fontStyle); buffer.writeFloat(fontWeight); buffer.writeInt(fontFamilyId); + buffer.writeInt(textAlign); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int componentId = buffer.readInt(); int animationId = buffer.readInt(); int textId = buffer.readInt(); @@ -284,6 +302,7 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation int fontStyle = buffer.readInt(); float fontWeight = buffer.readFloat(); int fontFamilyId = buffer.readInt(); + int textAlign = buffer.readInt(); operations.add( new TextLayout( null, @@ -294,10 +313,11 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation fontSize, fontStyle, fontWeight, - fontFamilyId)); + fontFamilyId, + textAlign)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", id(), name()) .description("Text layout implementation.\n\n") .field(INT, "COMPONENT_ID", "unique id for this component") @@ -313,7 +333,7 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply( buffer, mComponentId, @@ -323,6 +343,7 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation mFontSize, mFontStyle, mFontWeight, - mFontFamilyId); + mFontFamilyId, + mTextAlign); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/ComponentMeasure.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/ComponentMeasure.java index 285425f99765..426e02337f5b 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/ComponentMeasure.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/ComponentMeasure.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations.layout.measure; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.operations.layout.Component; /** Encapsulate the result of a measure pass for a component */ @@ -80,7 +82,7 @@ public class ComponentMeasure { this(id, x, y, w, h, Component.Visibility.VISIBLE); } - public ComponentMeasure(Component component) { + public ComponentMeasure(@NonNull Component component) { this( component.getComponentId(), component.getX(), @@ -90,7 +92,7 @@ public class ComponentMeasure { component.mVisibility); } - public void copyFrom(ComponentMeasure m) { + public void copyFrom(@NonNull ComponentMeasure m) { mX = m.mX; mY = m.mY; mW = m.mW; @@ -98,7 +100,7 @@ public class ComponentMeasure { mVisibility = m.mVisibility; } - public boolean same(ComponentMeasure m) { + public boolean same(@NonNull ComponentMeasure m) { return mX == m.mX && mY == m.mY && mW == m.mW && mH == m.mH && mVisibility == m.mVisibility; } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/MeasurePass.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/MeasurePass.java index 8d01fea03690..112ab1b93474 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/MeasurePass.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/MeasurePass.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations.layout.measure; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.operations.layout.Component; import java.util.HashMap; @@ -24,13 +26,13 @@ import java.util.HashMap; * array vs the current hashmap */ public class MeasurePass { - HashMap<Integer, ComponentMeasure> mList = new HashMap<>(); + @NonNull HashMap<Integer, ComponentMeasure> mList = new HashMap<>(); public void clear() { mList.clear(); } - public void add(ComponentMeasure measure) throws Exception { + public void add(@NonNull ComponentMeasure measure) throws Exception { if (measure.mId == -1) { throw new Exception("Component has no id!"); } @@ -41,7 +43,7 @@ public class MeasurePass { return mList.containsKey(id); } - public ComponentMeasure get(Component c) { + public ComponentMeasure get(@NonNull Component c) { if (!mList.containsKey(c.getComponentId())) { ComponentMeasure measure = new ComponentMeasure( diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BackgroundModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BackgroundModifierOperation.java index 64e40f7c591c..76a97ca0eb51 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BackgroundModifierOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BackgroundModifierOperation.java @@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.operations.layout.modifie import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -42,7 +44,7 @@ public class BackgroundModifierOperation extends DecoratorModifierOperation { float mA; int mShapeType = ShapeType.RECTANGLE; - public PaintBundle mPaint = new PaintBundle(); + @NonNull public PaintBundle mPaint = new PaintBundle(); public BackgroundModifierOperation( float x, @@ -66,12 +68,12 @@ public class BackgroundModifierOperation extends DecoratorModifierOperation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mX, mY, mWidth, mHeight, mR, mG, mB, mA, mShapeType); } @Override - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { serializer.append( indent, "BACKGROUND = [" @@ -101,11 +103,13 @@ public class BackgroundModifierOperation extends DecoratorModifierOperation { this.mHeight = height; } + @NonNull @Override public String toString() { return "BackgroundModifierOperation(" + mWidth + " x " + mHeight + ")"; } + @NonNull public static String name() { return CLASS_NAME; } @@ -115,7 +119,7 @@ public class BackgroundModifierOperation extends DecoratorModifierOperation { } public static void apply( - WireBuffer buffer, + @NonNull WireBuffer buffer, float x, float y, float width, @@ -138,7 +142,7 @@ public class BackgroundModifierOperation extends DecoratorModifierOperation { buffer.writeInt(shapeType); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { float x = buffer.readFloat(); float y = buffer.readFloat(); float width = buffer.readFloat(); @@ -153,7 +157,7 @@ public class BackgroundModifierOperation extends DecoratorModifierOperation { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.savePaint(); mPaint.reset(); mPaint.setStyle(PaintBundle.STYLE_FILL); @@ -167,7 +171,7 @@ public class BackgroundModifierOperation extends DecoratorModifierOperation { context.restorePaint(); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Modifier Operations", OP_CODE, CLASS_NAME) .description("define the Background Modifier") .field(FLOAT, "x", "") diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BorderModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BorderModifierOperation.java index 92c0a733d8a1..d48a9c732cd5 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BorderModifierOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BorderModifierOperation.java @@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.operations.layout.modifie import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -45,7 +47,7 @@ public class BorderModifierOperation extends DecoratorModifierOperation { float mA; int mShapeType = ShapeType.RECTANGLE; - public PaintBundle paint = new PaintBundle(); + @NonNull public PaintBundle paint = new PaintBundle(); public BorderModifierOperation( float x, @@ -73,7 +75,7 @@ public class BorderModifierOperation extends DecoratorModifierOperation { } @Override - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { serializer.append( indent, "BORDER = [" @@ -105,7 +107,7 @@ public class BorderModifierOperation extends DecoratorModifierOperation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply( buffer, mX, @@ -127,6 +129,7 @@ public class BorderModifierOperation extends DecoratorModifierOperation { this.mHeight = height; } + @NonNull @Override public String toString() { return "BorderModifierOperation(" @@ -152,6 +155,7 @@ public class BorderModifierOperation extends DecoratorModifierOperation { + ")"; } + @NonNull public static String name() { return CLASS_NAME; } @@ -161,7 +165,7 @@ public class BorderModifierOperation extends DecoratorModifierOperation { } public static void apply( - WireBuffer buffer, + @NonNull WireBuffer buffer, float x, float y, float width, @@ -188,7 +192,7 @@ public class BorderModifierOperation extends DecoratorModifierOperation { buffer.writeInt(shapeType); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { float x = buffer.readFloat(); float y = buffer.readFloat(); float width = buffer.readFloat(); @@ -206,7 +210,7 @@ public class BorderModifierOperation extends DecoratorModifierOperation { } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.savePaint(); paint.reset(); paint.setColor(mR, mG, mB, mA); @@ -225,7 +229,7 @@ public class BorderModifierOperation extends DecoratorModifierOperation { context.restorePaint(); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Modifier Operations", OP_CODE, CLASS_NAME) .description("define the Border Modifier") .field(FLOAT, "x", "") diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ClipRectModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ClipRectModifierOperation.java index 0d8aeaa2f06a..78b51c3f83aa 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ClipRectModifierOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ClipRectModifierOperation.java @@ -15,14 +15,14 @@ */ package com.android.internal.widget.remotecompose.core.operations.layout.modifiers; -import com.android.internal.widget.remotecompose.core.CoreDocument; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; import com.android.internal.widget.remotecompose.core.RemoteContext; import com.android.internal.widget.remotecompose.core.WireBuffer; import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; -import com.android.internal.widget.remotecompose.core.operations.layout.Component; import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; import java.util.List; @@ -35,7 +35,7 @@ public class ClipRectModifierOperation extends DecoratorModifierOperation { float mHeight; @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.clipRect(0f, 0f, mWidth, mHeight); } @@ -46,21 +46,16 @@ public class ClipRectModifierOperation extends DecoratorModifierOperation { } @Override - public void onClick( - RemoteContext context, CoreDocument document, Component component, float x, float y) { - // nothing - } - - @Override - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { serializer.append(indent, "CLIP_RECT = [" + mWidth + ", " + mHeight + "]"); } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer); } + @NonNull public static String name() { return CLASS_NAME; } @@ -69,15 +64,15 @@ public class ClipRectModifierOperation extends DecoratorModifierOperation { return OP_CODE; } - public static void apply(WireBuffer buffer) { + public static void apply(@NonNull WireBuffer buffer) { buffer.start(OP_CODE); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(WireBuffer buffer, @NonNull List<Operation> operations) { operations.add(new ClipRectModifierOperation()); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Canvas Operations", OP_CODE, CLASS_NAME) .description("Draw the specified round-rect"); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentModifiers.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentModifiers.java index 95786a8b62b0..011d7edd18c8 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentModifiers.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentModifiers.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations.layout.modifiers; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.CoreDocument; import com.android.internal.widget.remotecompose.core.PaintContext; import com.android.internal.widget.remotecompose.core.PaintOperation; @@ -22,29 +24,34 @@ import com.android.internal.widget.remotecompose.core.RemoteContext; import com.android.internal.widget.remotecompose.core.WireBuffer; import com.android.internal.widget.remotecompose.core.operations.MatrixRestore; import com.android.internal.widget.remotecompose.core.operations.MatrixSave; +import com.android.internal.widget.remotecompose.core.operations.layout.ClickHandler; import com.android.internal.widget.remotecompose.core.operations.layout.ClickModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.Component; import com.android.internal.widget.remotecompose.core.operations.layout.DecoratorComponent; +import com.android.internal.widget.remotecompose.core.operations.layout.TouchHandler; import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; import java.util.ArrayList; /** Maintain a list of modifiers */ -public class ComponentModifiers extends PaintOperation implements DecoratorComponent { - ArrayList<ModifierOperation> mList = new ArrayList<>(); +public class ComponentModifiers extends PaintOperation + implements DecoratorComponent, ClickHandler, TouchHandler { + @NonNull ArrayList<ModifierOperation> mList = new ArrayList<>(); + @NonNull public ArrayList<ModifierOperation> getList() { return mList; } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { super.apply(context); for (ModifierOperation op : mList) { op.apply(context); } } + @NonNull @Override public String toString() { String str = "ComponentModifiers \n"; @@ -59,7 +66,7 @@ public class ComponentModifiers extends PaintOperation implements DecoratorCompo // nothing } - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { serializer.append(indent, "MODIFIERS"); for (ModifierOperation m : mList) { m.serializeToString(indent + 1, serializer); @@ -75,7 +82,7 @@ public class ComponentModifiers extends PaintOperation implements DecoratorCompo } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { float tx = 0f; float ty = 0f; for (ModifierOperation op : mList) { @@ -127,8 +134,38 @@ public class ComponentModifiers extends PaintOperation implements DecoratorCompo public void onClick( RemoteContext context, CoreDocument document, Component component, float x, float y) { for (ModifierOperation op : mList) { - if (op instanceof DecoratorComponent) { - ((DecoratorComponent) op).onClick(context, document, component, x, y); + if (op instanceof ClickHandler) { + ((ClickHandler) op).onClick(context, document, component, x, y); + } + } + } + + @Override + public void onTouchDown( + RemoteContext context, CoreDocument document, Component component, float x, float y) { + for (ModifierOperation op : mList) { + if (op instanceof TouchHandler) { + ((TouchHandler) op).onTouchDown(context, document, component, x, y); + } + } + } + + @Override + public void onTouchUp( + RemoteContext context, CoreDocument document, Component component, float x, float y) { + for (ModifierOperation op : mList) { + if (op instanceof TouchHandler) { + ((TouchHandler) op).onTouchUp(context, document, component, x, y); + } + } + } + + @Override + public void onTouchCancel( + RemoteContext context, CoreDocument document, Component component, float x, float y) { + for (ModifierOperation op : mList) { + if (op instanceof TouchHandler) { + ((TouchHandler) op).onTouchCancel(context, document, component, x, y); } } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentVisibilityOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentVisibilityOperation.java index 312d016029fb..26e737b32027 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentVisibilityOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentVisibilityOperation.java @@ -17,7 +17,9 @@ package com.android.internal.widget.remotecompose.core.operations.layout.modifie import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; -import com.android.internal.widget.remotecompose.core.CoreDocument; +import android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -37,49 +39,52 @@ public class ComponentVisibilityOperation private static final int OP_CODE = Operations.MODIFIER_VISIBILITY; int mVisibilityId; - Component.Visibility mVisibility = Component.Visibility.VISIBLE; + @NonNull Component.Visibility mVisibility = Component.Visibility.VISIBLE; private LayoutComponent mParent; public ComponentVisibilityOperation(int id) { mVisibilityId = id; } + @NonNull @Override public String toString() { return "ComponentVisibilityOperation(" + mVisibilityId + ")"; } + @NonNull public String serializedName() { return "COMPONENT_VISIBILITY"; } @Override - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { serializer.append(indent, serializedName() + " = " + mVisibilityId); } @Override public void apply(RemoteContext context) {} + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@Nullable String indent) { return (indent != null ? indent : "") + toString(); } @Override public void write(WireBuffer buffer) {} - public static void apply(WireBuffer buffer, int valueId) { + public static void apply(@NonNull WireBuffer buffer, int valueId) { buffer.start(OP_CODE); buffer.writeInt(valueId); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int valueId = buffer.readInt(); operations.add(new ComponentVisibilityOperation(valueId)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", OP_CODE, "ComponentVisibility") .description( "This operation allows setting a component" @@ -88,12 +93,12 @@ public class ComponentVisibilityOperation } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { context.listensTo(mVisibilityId, this); } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { int visibility = context.getInteger(mVisibilityId); if (visibility == Component.Visibility.VISIBLE.ordinal()) { mVisibility = Component.Visibility.VISIBLE; @@ -115,8 +120,4 @@ public class ComponentVisibilityOperation @Override public void layout(RemoteContext context, float width, float height) {} - - @Override - public void onClick( - RemoteContext context, CoreDocument document, Component component, float x, float y) {} } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/DecoratorModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/DecoratorModifierOperation.java index 41e18cbafbe6..b4c4108802ee 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/DecoratorModifierOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/DecoratorModifierOperation.java @@ -15,10 +15,7 @@ */ package com.android.internal.widget.remotecompose.core.operations.layout.modifiers; -import com.android.internal.widget.remotecompose.core.CoreDocument; import com.android.internal.widget.remotecompose.core.PaintOperation; -import com.android.internal.widget.remotecompose.core.RemoteContext; -import com.android.internal.widget.remotecompose.core.operations.layout.Component; import com.android.internal.widget.remotecompose.core.operations.layout.DecoratorComponent; /** @@ -26,11 +23,4 @@ import com.android.internal.widget.remotecompose.core.operations.layout.Decorato * output (background, border...) */ public abstract class DecoratorModifierOperation extends PaintOperation - implements ModifierOperation, DecoratorComponent { - - @Override - public void onClick( - RemoteContext context, CoreDocument document, Component component, float x, float y) { - // nothing - } -} + implements ModifierOperation, DecoratorComponent {} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/DimensionModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/DimensionModifierOperation.java index 408bebcfb7d9..3c2d85cfee5b 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/DimensionModifierOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/DimensionModifierOperation.java @@ -15,6 +15,9 @@ */ package com.android.internal.widget.remotecompose.core.operations.layout.modifiers; +import android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.RemoteContext; import com.android.internal.widget.remotecompose.core.VariableSupport; import com.android.internal.widget.remotecompose.core.operations.Utils; @@ -29,8 +32,10 @@ public abstract class DimensionModifierOperation implements ModifierOperation, V WRAP, WEIGHT, INTRINSIC_MIN, - INTRINSIC_MAX; + INTRINSIC_MAX, + EXACT_DP; + @NonNull static Type fromInt(int value) { switch (value) { case 0: @@ -45,6 +50,8 @@ public abstract class DimensionModifierOperation implements ModifierOperation, V return INTRINSIC_MIN; case 5: return INTRINSIC_MAX; + case 6: + return EXACT_DP; } return EXACT; } @@ -68,19 +75,32 @@ public abstract class DimensionModifierOperation implements ModifierOperation, V } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { if (mType == Type.EXACT) { mOutValue = Float.isNaN(mValue) ? context.getFloat(Utils.idFromNan(mValue)) : mValue; } + if (mType == Type.EXACT_DP) { + float pre = mOutValue; + mOutValue = Float.isNaN(mValue) ? context.getFloat(Utils.idFromNan(mValue)) : mValue; + mOutValue *= context.getDensity(); + if (pre != mOutValue) { + context.getDocument().getRootLayoutComponent().invalidateMeasure(); + } + } } @Override - public void registerListening(RemoteContext context) { + public void registerListening(@NonNull RemoteContext context) { if (mType == Type.EXACT) { if (Float.isNaN(mValue)) { context.listensTo(Utils.idFromNan(mValue), this); } } + if (mType == Type.EXACT_DP) { + if (Float.isNaN(mValue)) { + context.listensTo(Utils.idFromNan(mValue), this); + } + } } public boolean hasWeight() { @@ -107,25 +127,31 @@ public abstract class DimensionModifierOperation implements ModifierOperation, V mOutValue = mValue = value; } + @NonNull public String serializedName() { return "DIMENSION"; } @Override - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { if (mType == Type.EXACT) { serializer.append(indent, serializedName() + " = " + mValue); } + if (mType == Type.EXACT_DP) { + serializer.append(indent, serializedName() + " = " + mValue + " dp"); + } } @Override public void apply(RemoteContext context) {} + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@Nullable String indent) { return (indent != null ? indent : "") + toString(); } + @NonNull @Override public String toString() { return "DimensionModifierOperation(" + mValue + ")"; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/GraphicsLayerModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/GraphicsLayerModifierOperation.java new file mode 100644 index 000000000000..2b3038281d57 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/GraphicsLayerModifierOperation.java @@ -0,0 +1,302 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations.layout.modifiers; + +import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT; +import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; + +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.RemoteContext; +import com.android.internal.widget.remotecompose.core.WireBuffer; +import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; +import com.android.internal.widget.remotecompose.core.operations.layout.AnimatableValue; +import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; + +import java.util.List; + +/** + * Represents a padding modifier. Padding modifiers can be chained and will impact following + * modifiers. + */ +public class GraphicsLayerModifierOperation extends DecoratorModifierOperation { + private static final int OP_CODE = Operations.MODIFIER_GRAPHICS_LAYER; + public static final String CLASS_NAME = "GraphicsLayerModifierOperation"; + + AnimatableValue mScaleX; + AnimatableValue mScaleY; + AnimatableValue mRotationX; + AnimatableValue mRotationY; + AnimatableValue mRotationZ; + AnimatableValue mTransformOriginX; + AnimatableValue mTransformOriginY; + AnimatableValue mShadowElevation; + AnimatableValue mAlpha; + AnimatableValue mCameraDistance; + int mBlendMode; + int mSpotShadowColorId; + int mAmbientShadowColorId; + int mColorFilterId; + int mRenderEffectId; + + public GraphicsLayerModifierOperation( + float scaleX, + float scaleY, + float rotationX, + float rotationY, + float rotationZ, + float shadowElevation, + float transformOriginX, + float transformOriginY, + float alpha, + float cameraDistance, + int blendMode, + int spotShadowColorId, + int ambientShadowColorId, + int colorFilterId, + int renderEffectId) { + mScaleX = new AnimatableValue(scaleX); + mScaleY = new AnimatableValue(scaleY); + mRotationX = new AnimatableValue(rotationX); + mRotationY = new AnimatableValue(rotationY); + mRotationZ = new AnimatableValue(rotationZ); + mShadowElevation = new AnimatableValue(shadowElevation); + mTransformOriginX = new AnimatableValue(transformOriginX); + mTransformOriginY = new AnimatableValue(transformOriginY); + mAlpha = new AnimatableValue(alpha); + mCameraDistance = new AnimatableValue(cameraDistance); + mBlendMode = blendMode; + mSpotShadowColorId = spotShadowColorId; + mAmbientShadowColorId = ambientShadowColorId; + mColorFilterId = colorFilterId; + mRenderEffectId = renderEffectId; + } + + public float getScaleX() { + return mScaleX.getValue(); + } + + public float getScaleY() { + return mScaleY.getValue(); + } + + public float getRotationX() { + return mRotationX.getValue(); + } + + public float getRotationY() { + return mRotationY.getValue(); + } + + public float getRotationZ() { + return mRotationZ.getValue(); + } + + public float getShadowElevation() { + return mShadowElevation.getValue(); + } + + public float getTransformOriginX() { + return mTransformOriginX.getValue(); + } + + public float getTransformOriginY() { + return mTransformOriginY.getValue(); + } + + public float getAlpha() { + return mAlpha.getValue(); + } + + public float getCameraDistance() { + return mCameraDistance.getValue(); + } + + // TODO: add implementation for blendmode + public int getBlendModeId() { + return mBlendMode; + } + + // TODO: add implementation for shadow + public int getSpotShadowColorId() { + return mSpotShadowColorId; + } + + public int getAmbientShadowColorId() { + return mAmbientShadowColorId; + } + + // TODO: add implementation for color filters + public int getColorFilterId() { + return mColorFilterId; + } + + public int getRenderEffectId() { + return mRenderEffectId; + } + + @Override + public void write(WireBuffer buffer) { + apply( + buffer, + mScaleX.getValue(), + mScaleY.getValue(), + mRotationX.getValue(), + mRotationY.getValue(), + mRotationZ.getValue(), + mShadowElevation.getValue(), + mTransformOriginX.getValue(), + mTransformOriginY.getValue(), + mAlpha.getValue(), + mCameraDistance.getValue(), + mBlendMode, + mSpotShadowColorId, + mAmbientShadowColorId, + mColorFilterId, + mRenderEffectId); + } + + @Override + public void serializeToString(int indent, StringSerializer serializer) { + serializer.append(indent, "GRAPHICS_LAYER = [" + mScaleX + ", " + mScaleY + "]"); + } + + @Override + public String deepToString(String indent) { + return (indent != null ? indent : "") + toString(); + } + + @Override + public void paint(PaintContext context) { + mScaleX.evaluate(context); + mScaleY.evaluate(context); + mRotationX.evaluate(context); + mRotationY.evaluate(context); + mRotationZ.evaluate(context); + mTransformOriginX.evaluate(context); + mTransformOriginY.evaluate(context); + mShadowElevation.evaluate(context); + mAlpha.evaluate(context); + mCameraDistance.evaluate(context); + } + + @Override + public String toString() { + return "GraphicsLayerModifierOperation(" + mScaleX + ", " + mScaleY + ")"; + } + + public static String name() { + return CLASS_NAME; + } + + public static int id() { + return OP_CODE; + } + + public static void apply( + WireBuffer buffer, + float scaleX, + float scaleY, + float rotationX, + float rotationY, + float rotationZ, + float shadowElevation, + float transformOriginX, + float transformOriginY, + float alpha, + float cameraDistance, + int blendMode, + int spotShadowColorId, + int ambientShadowColorId, + int colorFilterId, + int renderEffectId) { + buffer.start(OP_CODE); + buffer.writeFloat(scaleX); + buffer.writeFloat(scaleY); + buffer.writeFloat(rotationX); + buffer.writeFloat(rotationY); + buffer.writeFloat(rotationZ); + buffer.writeFloat(shadowElevation); + buffer.writeFloat(transformOriginX); + buffer.writeFloat(transformOriginY); + buffer.writeFloat(alpha); + buffer.writeFloat(cameraDistance); + buffer.writeInt(blendMode); + buffer.writeInt(spotShadowColorId); + buffer.writeInt(ambientShadowColorId); + buffer.writeInt(colorFilterId); + buffer.writeInt(renderEffectId); + } + + public static void read(WireBuffer buffer, List<Operation> operations) { + float scaleX = buffer.readFloat(); + float scaleY = buffer.readFloat(); + float rotationX = buffer.readFloat(); + float rotationY = buffer.readFloat(); + float rotationZ = buffer.readFloat(); + float shadowElevation = buffer.readFloat(); + float transformOriginX = buffer.readFloat(); + float transformOriginY = buffer.readFloat(); + float alpha = buffer.readFloat(); + float cameraDistance = buffer.readFloat(); + int blendMode = buffer.readInt(); + int spotShadowColorId = buffer.readInt(); + int ambientShadowColorId = buffer.readInt(); + int colorFilterId = buffer.readInt(); + int renderEffectId = buffer.readInt(); + operations.add( + new GraphicsLayerModifierOperation( + scaleX, + scaleY, + rotationX, + rotationY, + rotationZ, + shadowElevation, + transformOriginX, + transformOriginY, + alpha, + cameraDistance, + blendMode, + spotShadowColorId, + ambientShadowColorId, + colorFilterId, + renderEffectId)); + } + + public static void documentation(DocumentationBuilder doc) { + doc.operation("Modifier Operations", OP_CODE, CLASS_NAME) + .description("define the GraphicsLayer Modifier") + .field(FLOAT, "scaleX", "") + .field(FLOAT, "scaleY", "") + .field(FLOAT, "rotationX", "") + .field(FLOAT, "rotationY", "") + .field(FLOAT, "rotationZ", "") + .field(FLOAT, "shadowElevation", "") + .field(FLOAT, "transformOriginX", "") + .field(FLOAT, "transformOriginY", "") + .field(FLOAT, "alpha", "") + .field(FLOAT, "cameraDistance", "") + .field(INT, "blendMode", "") + .field(INT, "spotShadowColorId", "") + .field(INT, "ambientShadowColorId", "") + .field(INT, "colorFilterId", "") + .field(INT, "renderEffectId", ""); + } + + @Override + public void layout(RemoteContext context, float width, float height) {} +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HeightModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HeightModifierOperation.java index d3613f844981..97c76c0aedf7 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HeightModifierOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HeightModifierOperation.java @@ -18,6 +18,8 @@ package com.android.internal.widget.remotecompose.core.operations.layout.modifie import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.WireBuffer; @@ -30,6 +32,7 @@ public class HeightModifierOperation extends DimensionModifierOperation { private static final int OP_CODE = Operations.MODIFIER_HEIGHT; public static final String CLASS_NAME = "HeightModifierOperation"; + @NonNull public static String name() { return CLASS_NAME; } @@ -38,13 +41,13 @@ public class HeightModifierOperation extends DimensionModifierOperation { return OP_CODE; } - public static void apply(WireBuffer buffer, int type, float value) { + public static void apply(@NonNull WireBuffer buffer, int type, float value) { buffer.start(OP_CODE); buffer.writeInt(type); buffer.writeFloat(value); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { Type type = Type.fromInt(buffer.readInt()); float value = buffer.readFloat(); Operation op = new HeightModifierOperation(type, value); @@ -52,7 +55,7 @@ public class HeightModifierOperation extends DimensionModifierOperation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mType.ordinal(), mValue); } @@ -68,17 +71,19 @@ public class HeightModifierOperation extends DimensionModifierOperation { super(value); } + @NonNull @Override public String toString() { - return "Height(" + mValue + ")"; + return "Height(" + mType + ", " + mValue + ")"; } + @NonNull @Override public String serializedName() { return "HEIGHT"; } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Modifier Operations", OP_CODE, CLASS_NAME) .description("define the animation") .field(INT, "type", "") diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostActionOperation.java index ac42470a6f8f..836321fff8e6 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostActionOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostActionOperation.java @@ -17,6 +17,9 @@ package com.android.internal.widget.remotecompose.core.operations.layout.modifie import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; +import android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.CoreDocument; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; @@ -39,6 +42,7 @@ public class HostActionOperation implements ActionOperation { mActionId = id; } + @NonNull @Override public String toString() { return "HostActionOperation(" + mActionId + ")"; @@ -48,20 +52,22 @@ public class HostActionOperation implements ActionOperation { return mActionId; } + @NonNull public String serializedName() { return "HOST_ACTION"; } @Override - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { serializer.append(indent, serializedName() + " = " + mActionId); } @Override public void apply(RemoteContext context) {} + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@Nullable String indent) { return (indent != null ? indent : "") + toString(); } @@ -70,21 +76,25 @@ public class HostActionOperation implements ActionOperation { @Override public void runAction( - RemoteContext context, CoreDocument document, Component component, float x, float y) { + @NonNull RemoteContext context, + CoreDocument document, + Component component, + float x, + float y) { context.runAction(mActionId, ""); } - public static void apply(WireBuffer buffer, int actionId) { + public static void apply(@NonNull WireBuffer buffer, int actionId) { buffer.start(OP_CODE); buffer.writeInt(actionId); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int actionId = buffer.readInt(); operations.add(new HostActionOperation(actionId)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", OP_CODE, "HostAction") .description("Host action. This operation represents a host action") .field(INT, "ACTION_ID", "Host Action ID"); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostNamedActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostNamedActionOperation.java index b674a582fc14..e97e89784a23 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostNamedActionOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostNamedActionOperation.java @@ -17,6 +17,9 @@ package com.android.internal.widget.remotecompose.core.operations.layout.modifie import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; +import android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.CoreDocument; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; @@ -33,31 +36,47 @@ import java.util.List; public class HostNamedActionOperation implements ActionOperation { private static final int OP_CODE = Operations.HOST_NAMED_ACTION; + public static final int FLOAT_TYPE = 0; + public static final int INT_TYPE = 1; + public static final int STRING_TYPE = 2; + public static final int NONE_TYPE = -1; + int mTextId = -1; + int mType = NONE_TYPE; + int mValueId = -1; - public HostNamedActionOperation(int id) { + public HostNamedActionOperation(int id, int type, int valueId) { mTextId = id; + mType = type; + mValueId = valueId; } + @NonNull @Override public String toString() { - return "HostNamedActionOperation(" + mTextId + ")"; + return "HostNamedActionOperation(" + mTextId + " : " + mValueId + ")"; } + @NonNull public String serializedName() { return "HOST_NAMED_ACTION"; } @Override - public void serializeToString(int indent, StringSerializer serializer) { - serializer.append(indent, serializedName() + " = " + mTextId); + public void serializeToString(int indent, @NonNull StringSerializer serializer) { + if (mValueId != -1) { + serializer.append(indent, serializedName() + " = " + mTextId + " : " + mValueId); + } else { + serializer.append(indent, serializedName() + " = " + mTextId); + } } @Override public void apply(RemoteContext context) {} + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@Nullable String indent) { return (indent != null ? indent : "") + toString(); } @@ -66,23 +85,42 @@ public class HostNamedActionOperation implements ActionOperation { @Override public void runAction( - RemoteContext context, CoreDocument document, Component component, float x, float y) { - context.runNamedAction(mTextId); + @NonNull RemoteContext context, + CoreDocument document, + Component component, + float x, + float y) { + Object value = null; + if (mValueId != -1) { + if (mType == INT_TYPE) { + value = context.mRemoteComposeState.getInteger(mValueId); + } else if (mType == STRING_TYPE) { + value = context.mRemoteComposeState.getFromId(mValueId); + } else if (mType == FLOAT_TYPE) { + value = context.mRemoteComposeState.getFloat(mValueId); + } + } + context.runNamedAction(mTextId, value); } - public static void apply(WireBuffer buffer, int textId) { + public static void apply(@NonNull WireBuffer buffer, int textId, int type, int valueId) { buffer.start(OP_CODE); buffer.writeInt(textId); + buffer.writeInt(type); + buffer.writeInt(valueId); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int textId = buffer.readInt(); - operations.add(new HostNamedActionOperation(textId)); + int type = buffer.readInt(); + int valueId = buffer.readInt(); + operations.add(new HostNamedActionOperation(textId, type, valueId)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", OP_CODE, "HostNamedAction") .description("Host Named action. This operation represents a host action") - .field(INT, "TEXT_ID", "Named Host Action Text ID"); + .field(INT, "TEXT_ID", "Named Host Action Text ID") + .field(INT, "VALUE_ID", "Named Host Action Value ID"); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/OffsetModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/OffsetModifierOperation.java new file mode 100644 index 000000000000..65fe345ac920 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/OffsetModifierOperation.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations.layout.modifiers; + +import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT; + +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.RemoteContext; +import com.android.internal.widget.remotecompose.core.WireBuffer; +import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; +import com.android.internal.widget.remotecompose.core.operations.Utils; +import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; + +import java.util.List; + +/** Represents an offset modifier. */ +public class OffsetModifierOperation extends DecoratorModifierOperation { + private static final int OP_CODE = Operations.MODIFIER_OFFSET; + public static final String CLASS_NAME = "OffsetModifierOperation"; + + float mX; + float mY; + + public OffsetModifierOperation(float x, float y) { + this.mX = x; + this.mY = y; + } + + public float getX() { + return mX; + } + + public float getY() { + return mY; + } + + public void setX(float x) { + this.mX = x; + } + + public void setY(float y) { + this.mY = y; + } + + @Override + public void write(WireBuffer buffer) { + apply(buffer, mX, mY); + } + + // @Override + public void serializeToString(int indent, StringSerializer serializer) { + serializer.append(indent, "OFFSET = [" + mX + ", " + mY + "]"); + } + + @Override + public String deepToString(String indent) { + return (indent != null ? indent : "") + toString(); + } + + @Override + public void paint(PaintContext context) { + float x = context.getContext().mRemoteComposeState.getFloat(Utils.idFromNan(mX)); + float y = context.getContext().mRemoteComposeState.getFloat(Utils.idFromNan(mY)); + float density = context.getContext().getDensity(); + x *= density; + y *= density; + context.translate(x, y); + } + + @Override + public String toString() { + return "OffsetModifierOperation(" + mX + ", " + mY + ")"; + } + + public static String name() { + return CLASS_NAME; + } + + public static int id() { + return OP_CODE; + } + + public static void apply(WireBuffer buffer, float x, float y) { + buffer.start(OP_CODE); + buffer.writeFloat(x); + buffer.writeFloat(y); + } + + public static void read(WireBuffer buffer, List<Operation> operations) { + float x = buffer.readFloat(); + float y = buffer.readFloat(); + operations.add(new OffsetModifierOperation(x, y)); + } + + public static void documentation(DocumentationBuilder doc) { + doc.operation("Modifier Operations", OP_CODE, CLASS_NAME) + .description("define the Offset Modifier") + .field(FLOAT, "x", "") + .field(FLOAT, "y", ""); + } + + @Override + public void layout(RemoteContext context, float width, float height) {} +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/PaddingModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/PaddingModifierOperation.java index e0ec1a60ef7e..ed5522ea865f 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/PaddingModifierOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/PaddingModifierOperation.java @@ -17,6 +17,9 @@ package com.android.internal.widget.remotecompose.core.operations.layout.modifie import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT; +import android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -78,12 +81,12 @@ public class PaddingModifierOperation implements ModifierOperation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mLeft, mTop, mRight, mBottom); } @Override - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { serializer.append( indent, "PADDING = [" + mLeft + ", " + mTop + ", " + mRight + ", " + mBottom + "]"); } @@ -91,11 +94,13 @@ public class PaddingModifierOperation implements ModifierOperation { @Override public void apply(RemoteContext context) {} + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@Nullable String indent) { return (indent != null ? indent : "") + toString(); } + @NonNull @Override public String toString() { return "PaddingModifierOperation(" @@ -109,6 +114,7 @@ public class PaddingModifierOperation implements ModifierOperation { + ")"; } + @NonNull public static String name() { return CLASS_NAME; } @@ -117,7 +123,8 @@ public class PaddingModifierOperation implements ModifierOperation { return Operations.MODIFIER_PADDING; } - public static void apply(WireBuffer buffer, float left, float top, float right, float bottom) { + public static void apply( + @NonNull WireBuffer buffer, float left, float top, float right, float bottom) { buffer.start(Operations.MODIFIER_PADDING); buffer.writeFloat(left); buffer.writeFloat(top); @@ -125,7 +132,7 @@ public class PaddingModifierOperation implements ModifierOperation { buffer.writeFloat(bottom); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { float left = buffer.readFloat(); float top = buffer.readFloat(); float right = buffer.readFloat(); @@ -133,7 +140,7 @@ public class PaddingModifierOperation implements ModifierOperation { operations.add(new PaddingModifierOperation(left, top, right, bottom)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Modifier Operations", OP_CODE, CLASS_NAME) .description("define the Padding Modifier") .field(FLOAT, "left", "") diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RoundedClipRectModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RoundedClipRectModifierOperation.java index dc95fe7774aa..6218dd5f3311 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RoundedClipRectModifierOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RoundedClipRectModifierOperation.java @@ -17,7 +17,8 @@ package com.android.internal.widget.remotecompose.core.operations.layout.modifie import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT; -import com.android.internal.widget.remotecompose.core.CoreDocument; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; @@ -25,7 +26,6 @@ import com.android.internal.widget.remotecompose.core.RemoteContext; import com.android.internal.widget.remotecompose.core.WireBuffer; import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; import com.android.internal.widget.remotecompose.core.operations.DrawBase4; -import com.android.internal.widget.remotecompose.core.operations.layout.Component; import com.android.internal.widget.remotecompose.core.operations.layout.DecoratorComponent; import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; @@ -37,7 +37,7 @@ public class RoundedClipRectModifierOperation extends DrawBase4 public static final int OP_CODE = Operations.MODIFIER_ROUNDED_CLIP_RECT; public static final String CLASS_NAME = "RoundedClipRectModifierOperation"; - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { Maker m = RoundedClipRectModifierOperation::new; read(m, buffer, operations); } @@ -46,16 +46,17 @@ public class RoundedClipRectModifierOperation extends DrawBase4 return OP_CODE; } + @NonNull public static String name() { return CLASS_NAME; } @Override - protected void write(WireBuffer buffer, float v1, float v2, float v3, float v4) { + protected void write(@NonNull WireBuffer buffer, float v1, float v2, float v3, float v4) { apply(buffer, v1, v2, v3, v4); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Modifier Operations", id(), "RoundedClipRectModifierOperation") .description("clip with rectangle") .field( @@ -90,7 +91,7 @@ public class RoundedClipRectModifierOperation extends DrawBase4 } @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { context.roundedClipRect(mWidth, mHeight, mX1, mY1, mX2, mY2); } @@ -101,13 +102,7 @@ public class RoundedClipRectModifierOperation extends DrawBase4 } @Override - public void onClick( - RemoteContext context, CoreDocument document, Component component, float x, float y) { - // nothing - } - - @Override - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { serializer.append( indent, "ROUNDED_CLIP_RECT = [" @@ -135,7 +130,11 @@ public class RoundedClipRectModifierOperation extends DrawBase4 * @param bottomEnd bottomEnd radius */ public static void apply( - WireBuffer buffer, float topStart, float topEnd, float bottomStart, float bottomEnd) { + @NonNull WireBuffer buffer, + float topStart, + float topEnd, + float bottomStart, + float bottomEnd) { write(buffer, OP_CODE, topStart, topEnd, bottomStart, bottomEnd); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatChangeActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatChangeActionOperation.java new file mode 100644 index 000000000000..29ec82810a7c --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatChangeActionOperation.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations.layout.modifiers; + +import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT; +import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; + +import com.android.internal.widget.remotecompose.core.CoreDocument; +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.RemoteContext; +import com.android.internal.widget.remotecompose.core.WireBuffer; +import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; +import com.android.internal.widget.remotecompose.core.operations.layout.ActionOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.Component; +import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; + +import java.util.List; + +/** Apply a value change on an float variable. */ +public class ValueFloatChangeActionOperation implements ActionOperation { + private static final int OP_CODE = Operations.VALUE_FLOAT_CHANGE_ACTION; + + int mTargetValueId = -1; + float mValue = -1; + + public ValueFloatChangeActionOperation(int id, float value) { + mTargetValueId = id; + mValue = value; + } + + @Override + public String toString() { + return "ValueFloatChangeActionOperation(" + mTargetValueId + ")"; + } + + public String serializedName() { + return "VALUE_FLOAT_CHANGE"; + } + + @Override + public void serializeToString(int indent, StringSerializer serializer) { + serializer.append(indent, serializedName() + " = " + mTargetValueId + " -> " + mValue); + } + + @Override + public void apply(RemoteContext context) {} + + @Override + public String deepToString(String indent) { + return (indent != null ? indent : "") + toString(); + } + + @Override + public void write(WireBuffer buffer) {} + + @Override + public void runAction( + RemoteContext context, CoreDocument document, Component component, float x, float y) { + System.out.println("OVERRIDE " + mTargetValueId + " TO " + mValue); + context.overrideFloat(mTargetValueId, mValue); + } + + public static void apply(WireBuffer buffer, int valueId, float value) { + buffer.start(OP_CODE); + buffer.writeInt(valueId); + buffer.writeFloat(value); + } + + public static void read(WireBuffer buffer, List<Operation> operations) { + int valueId = buffer.readInt(); + float value = buffer.readFloat(); + operations.add(new ValueFloatChangeActionOperation(valueId, value)); + } + + public static void documentation(DocumentationBuilder doc) { + doc.operation("Layout Operations", OP_CODE, "ValueFloatChangeActionOperation") + .description( + "ValueIntegerChange action. " + + " This operation represents a value change for the given id") + .field(INT, "TARGET_VALUE_ID", "Value ID") + .field(FLOAT, "VALUE", "float value to be assigned to the target"); + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerChangeActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerChangeActionOperation.java index 8876720c9990..d7ce8acc72bf 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerChangeActionOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerChangeActionOperation.java @@ -17,6 +17,9 @@ package com.android.internal.widget.remotecompose.core.operations.layout.modifie import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; +import android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.CoreDocument; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; @@ -41,25 +44,28 @@ public class ValueIntegerChangeActionOperation implements ActionOperation { mValue = value; } + @NonNull @Override public String toString() { return "ValueChangeActionOperation(" + mTargetValueId + ")"; } + @NonNull public String serializedName() { return "VALUE_INTEGER_CHANGE"; } @Override - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { serializer.append(indent, serializedName() + " = " + mTargetValueId + " -> " + mValue); } @Override public void apply(RemoteContext context) {} + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@Nullable String indent) { return (indent != null ? indent : "") + toString(); } @@ -68,23 +74,27 @@ public class ValueIntegerChangeActionOperation implements ActionOperation { @Override public void runAction( - RemoteContext context, CoreDocument document, Component component, float x, float y) { + @NonNull RemoteContext context, + CoreDocument document, + Component component, + float x, + float y) { context.overrideInteger(mTargetValueId, mValue); } - public static void apply(WireBuffer buffer, int valueId, int value) { + public static void apply(@NonNull WireBuffer buffer, int valueId, int value) { buffer.start(OP_CODE); buffer.writeInt(valueId); buffer.writeInt(value); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int valueId = buffer.readInt(); int value = buffer.readInt(); operations.add(new ValueIntegerChangeActionOperation(valueId, value)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", OP_CODE, "ValueIntegerChangeActionOperation") .description( "ValueIntegerChange action. " diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerExpressionChangeActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerExpressionChangeActionOperation.java index fb5e911e8bc6..75d13e785d4c 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerExpressionChangeActionOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerExpressionChangeActionOperation.java @@ -17,6 +17,9 @@ package com.android.internal.widget.remotecompose.core.operations.layout.modifie import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; +import android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.CoreDocument; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; @@ -41,17 +44,19 @@ public class ValueIntegerExpressionChangeActionOperation implements ActionOperat mValueExpressionId = value; } + @NonNull @Override public String toString() { return "ValueIntegerExpressionChangeActionOperation(" + mTargetValueId + ")"; } + @NonNull public String serializedName() { return "VALUE_INTEGER_EXPRESSION_CHANGE"; } @Override - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { serializer.append( indent, serializedName() + " = " + mTargetValueId + " -> " + mValueExpressionId); } @@ -59,8 +64,9 @@ public class ValueIntegerExpressionChangeActionOperation implements ActionOperat @Override public void apply(RemoteContext context) {} + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@Nullable String indent) { return (indent != null ? indent : "") + toString(); } @@ -69,23 +75,27 @@ public class ValueIntegerExpressionChangeActionOperation implements ActionOperat @Override public void runAction( - RemoteContext context, CoreDocument document, Component component, float x, float y) { + @NonNull RemoteContext context, + @NonNull CoreDocument document, + Component component, + float x, + float y) { document.evaluateIntExpression(mValueExpressionId, (int) mTargetValueId, context); } - public static void apply(WireBuffer buffer, long valueId, long value) { + public static void apply(@NonNull WireBuffer buffer, long valueId, long value) { buffer.start(OP_CODE); buffer.writeLong(valueId); buffer.writeLong(value); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { long valueId = buffer.readLong(); long value = buffer.readLong(); operations.add(new ValueIntegerExpressionChangeActionOperation(valueId, value)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", OP_CODE, "ValueIntegerExpressionChangeActionOperation") .description( "ValueIntegerExpressionChange action. " diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueStringChangeActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueStringChangeActionOperation.java index a64a492a8cc1..26d7244eee8c 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueStringChangeActionOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueStringChangeActionOperation.java @@ -17,6 +17,9 @@ package com.android.internal.widget.remotecompose.core.operations.layout.modifie import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; +import android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.CoreDocument; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; @@ -41,6 +44,7 @@ public class ValueStringChangeActionOperation implements ActionOperation { mValueId = value; } + @NonNull @Override public String toString() { return "ValueChangeActionOperation(" + mTargetValueId + ")"; @@ -50,20 +54,22 @@ public class ValueStringChangeActionOperation implements ActionOperation { return mTargetValueId; } + @NonNull public String serializedName() { return "VALUE_CHANGE"; } @Override - public void serializeToString(int indent, StringSerializer serializer) { + public void serializeToString(int indent, @NonNull StringSerializer serializer) { serializer.append(indent, serializedName() + " = " + mTargetValueId + " -> " + mValueId); } @Override public void apply(RemoteContext context) {} + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@Nullable String indent) { return (indent != null ? indent : "") + toString(); } @@ -72,23 +78,27 @@ public class ValueStringChangeActionOperation implements ActionOperation { @Override public void runAction( - RemoteContext context, CoreDocument document, Component component, float x, float y) { + @NonNull RemoteContext context, + CoreDocument document, + Component component, + float x, + float y) { context.overrideText(mTargetValueId, mValueId); } - public static void apply(WireBuffer buffer, int valueId, int value) { + public static void apply(@NonNull WireBuffer buffer, int valueId, int value) { buffer.start(OP_CODE); buffer.writeInt(valueId); buffer.writeInt(value); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int valueId = buffer.readInt(); int value = buffer.readInt(); operations.add(new ValueStringChangeActionOperation(valueId, value)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", OP_CODE, "ValueStringChangeActionOperation") .description( "ValueStrin gChange action. " diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/WidthModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/WidthModifierOperation.java index 62403b3e5e7e..e2f899ce2b46 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/WidthModifierOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/WidthModifierOperation.java @@ -18,6 +18,8 @@ package com.android.internal.widget.remotecompose.core.operations.layout.modifie import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.WireBuffer; @@ -30,6 +32,7 @@ public class WidthModifierOperation extends DimensionModifierOperation { private static final int OP_CODE = Operations.MODIFIER_WIDTH; public static final String CLASS_NAME = "WidthModifierOperation"; + @NonNull public static String name() { return CLASS_NAME; } @@ -38,13 +41,13 @@ public class WidthModifierOperation extends DimensionModifierOperation { return OP_CODE; } - public static void apply(WireBuffer buffer, int type, float value) { + public static void apply(@NonNull WireBuffer buffer, int type, float value) { buffer.start(OP_CODE); buffer.writeInt(type); buffer.writeFloat(value); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { Type type = Type.fromInt(buffer.readInt()); float value = buffer.readFloat(); Operation op = new WidthModifierOperation(type, value); @@ -56,7 +59,7 @@ public class WidthModifierOperation extends DimensionModifierOperation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mType.ordinal(), mValue); } @@ -68,17 +71,19 @@ public class WidthModifierOperation extends DimensionModifierOperation { super(value); } + @NonNull @Override public String toString() { - return "Width(" + mValue + ")"; + return "Width(" + mType + ", " + mValue + ")"; } + @NonNull @Override public String serializedName() { return "WIDTH"; } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Modifier Operations", OP_CODE, CLASS_NAME) .description("define the animation") .field(INT, "type", "") diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ZIndexModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ZIndexModifierOperation.java new file mode 100644 index 000000000000..aa20e0388d31 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ZIndexModifierOperation.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations.layout.modifiers; + +import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT; + +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.RemoteContext; +import com.android.internal.widget.remotecompose.core.WireBuffer; +import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; +import com.android.internal.widget.remotecompose.core.operations.Utils; +import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; + +import java.util.List; + +/** Represents a ZIndex modifier, allowing to change the z-index of a component. */ +public class ZIndexModifierOperation extends DecoratorModifierOperation { + private static final int OP_CODE = Operations.MODIFIER_ZINDEX; + public static final String CLASS_NAME = "ZIndexModifierOperation"; + float mValue; + float mCurrentValue; + + public ZIndexModifierOperation(float value) { + this.mValue = value; + } + + public float getValue() { + return mCurrentValue; + } + + public void setmValue(float value) { + this.mValue = value; + } + + @Override + public void write(WireBuffer buffer) { + apply(buffer, mValue); + } + + // @Override + public void serializeToString(int indent, StringSerializer serializer) { + serializer.append(indent, "ZINDEX = [" + mValue + "]"); + } + + @Override + public String deepToString(String indent) { + return (indent != null ? indent : "") + toString(); + } + + @Override + public void paint(PaintContext context) { + mCurrentValue = mValue; + if (Utils.isVariable(mValue)) { + mCurrentValue = + context.getContext().mRemoteComposeState.getFloat(Utils.idFromNan(mValue)); + } + } + + @Override + public String toString() { + return "ZIndexModifierOperation(" + mValue + ")"; + } + + public static String name() { + return CLASS_NAME; + } + + public static int id() { + return OP_CODE; + } + + public static void apply(WireBuffer buffer, float value) { + buffer.start(OP_CODE); + buffer.writeFloat(value); + } + + public static void read(WireBuffer buffer, List<Operation> operations) { + float value = buffer.readFloat(); + operations.add(new ZIndexModifierOperation(value)); + } + + public static void documentation(DocumentationBuilder doc) { + doc.operation("Modifier Operations", OP_CODE, CLASS_NAME) + .description("define the Z-Index Modifier") + .field(FLOAT, "value", ""); + } + + @Override + public void layout(RemoteContext context, float width, float height) {} +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/utils/DebugLog.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/utils/DebugLog.java index 4849b12c65b1..d8e49b0a9ccd 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/utils/DebugLog.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/utils/DebugLog.java @@ -15,6 +15,9 @@ */ package com.android.internal.widget.remotecompose.core.operations.layout.utils; +import android.annotation.NonNull; +import android.annotation.Nullable; + import java.util.ArrayList; /** Internal utility debug class */ @@ -23,12 +26,12 @@ public class DebugLog { public static final boolean DEBUG_LAYOUT_ON = false; public static class Node { - public Node parent; + @Nullable public Node parent; public String name; public String endString; - public ArrayList<Node> list = new ArrayList<>(); + @NonNull public ArrayList<Node> list = new ArrayList<>(); - public Node(Node parent, String name) { + public Node(@Nullable Node parent, String name) { this.parent = parent; this.name = name; this.endString = name + " DONE"; @@ -48,21 +51,21 @@ public class DebugLog { } } - public static Node node = new Node(null, "Root"); - public static Node currentNode = node; + @NonNull public static Node node = new Node(null, "Root"); + @NonNull public static Node currentNode = node; public static void clear() { node = new Node(null, "Root"); currentNode = node; } - public static void s(StringValueSupplier valueSupplier) { + public static void s(@NonNull StringValueSupplier valueSupplier) { if (DEBUG_LAYOUT_ON) { currentNode = new Node(currentNode, valueSupplier.getString()); } } - public static void log(StringValueSupplier valueSupplier) { + public static void log(@NonNull StringValueSupplier valueSupplier) { if (DEBUG_LAYOUT_ON) { new LogNode(currentNode, valueSupplier.getString()); } @@ -78,7 +81,7 @@ public class DebugLog { } } - public static void e(StringValueSupplier valueSupplier) { + public static void e(@NonNull StringValueSupplier valueSupplier) { if (DEBUG_LAYOUT_ON) { currentNode.endString = valueSupplier.getString(); if (currentNode.parent != null) { @@ -89,7 +92,7 @@ public class DebugLog { } } - public static void printNode(int indent, Node node, StringBuilder builder) { + public static void printNode(int indent, @NonNull Node node, @NonNull StringBuilder builder) { if (DEBUG_LAYOUT_ON) { StringBuilder indentationBuilder = new StringBuilder(); for (int i = 0; i < indent; i++) { diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/Painter.java b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/Painter.java index 9a3cd54c3f85..a808cf0e17b3 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/Painter.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/Painter.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations.paint; +import android.annotation.NonNull; + /** Provides a Builder pattern for a PaintBundle */ class Painter { PaintBundle mPaint; @@ -24,16 +26,19 @@ class Painter { return mPaint; } + @NonNull public Painter setAntiAlias(boolean aa) { mPaint.setAntiAlias(aa); return this; } + @NonNull public Painter setColor(int color) { mPaint.setColor(color); return this; } + @NonNull public Painter setColorId(int colorId) { mPaint.setColorId(colorId); return this; @@ -44,6 +49,7 @@ class Painter { * * @param join set the paint's Join, used whenever the paint's style is Stroke or StrokeAndFill. */ + @NonNull public Painter setStrokeJoin(int join) { mPaint.setStrokeJoin(join); return this; @@ -56,6 +62,7 @@ class Painter { * @param width set the paint's stroke width, used whenever the paint's style is Stroke or * StrokeAndFill. */ + @NonNull public Painter setStrokeWidth(float width) { mPaint.setStrokeWidth(width); return this; @@ -67,6 +74,7 @@ class Painter { * * @param style The new style to set in the paint */ + @NonNull public Painter setStyle(int style) { mPaint.setStyle(style); return this; @@ -78,6 +86,7 @@ class Painter { * @param cap set the paint's line cap style, used whenever the paint's style is Stroke or * StrokeAndFill. */ + @NonNull public Painter setStrokeCap(int cap) { mPaint.setStrokeCap(cap); return this; @@ -90,6 +99,7 @@ class Painter { * @param miter set the miter limit on the paint, used whenever the paint's style is Stroke or * StrokeAndFill. */ + @NonNull public Painter setStrokeMiter(float miter) { mPaint.setStrokeMiter(miter); return this; @@ -101,6 +111,7 @@ class Painter { * * @param alpha set the alpha component [0..1.0] of the paint's color. */ + @NonNull public Painter setAlpha(float alpha) { mPaint.setAlpha((alpha > 2) ? alpha / 255f : alpha); return this; @@ -112,6 +123,7 @@ class Painter { * @param color The ARGB source color used with the specified Porter-Duff mode * @param mode The porter-duff mode that is applied */ + @NonNull public Painter setPorterDuffColorFilter(int color, int mode) { mPaint.setColorFilter(color, mode); return this; @@ -130,6 +142,7 @@ class Painter { * line. * @param tileMode The Shader tiling mode */ + @NonNull public Painter setLinearGradient( float startX, float startY, @@ -155,6 +168,7 @@ class Painter { * circle. * @param tileMode The Shader tiling mode */ + @NonNull public Painter setRadialGradient( float centerX, float centerY, @@ -178,6 +192,7 @@ class Painter { * may produce unexpected results. If positions is NULL, then the colors are automatically * spaced evenly. */ + @NonNull public Painter setSweepGradient(float centerX, float centerY, int[] colors, float[] positions) { mPaint.setSweepGradient(colors, 0, positions, centerX, centerY); return this; @@ -188,6 +203,7 @@ class Painter { * * @param size set the paint's text size in pixel units. */ + @NonNull public Painter setTextSize(float size) { mPaint.setTextSize(size); return this; @@ -215,16 +231,19 @@ class Painter { * @param weight The desired weight to be drawn. * @param italic {@code true} if italic style is desired to be drawn. Otherwise, {@code false} */ + @NonNull public Painter setTypeface(int fontType, int weight, boolean italic) { mPaint.setTextStyle(fontType, weight, italic); return this; } + @NonNull public Painter setFilterBitmap(boolean filter) { mPaint.setFilterBitmap(filter); return this; } + @NonNull public Painter setShader(int id) { mPaint.setShader(id); return this; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/AnimatedFloatExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/AnimatedFloatExpression.java index 1d673c4c5ab6..b25f4cd3c530 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/AnimatedFloatExpression.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/AnimatedFloatExpression.java @@ -15,11 +15,12 @@ */ package com.android.internal.widget.remotecompose.core.operations.utilities; -/** - * high performance floating point expression evaluator used in animation - */ +import android.annotation.NonNull; +import android.annotation.Nullable; + +/** high performance floating point expression evaluator used in animation */ public class AnimatedFloatExpression { - static IntMap<String> sNames = new IntMap<>(); + @NonNull static IntMap<String> sNames = new IntMap<>(); public static final int OFFSET = 0x310_000; public static final float ADD = asNan(OFFSET + 1); public static final float SUB = asNan(OFFSET + 2); @@ -74,7 +75,7 @@ public class AnimatedFloatExpression { private static final float FP_TO_DEG = 0.017453292f; // 180/PI float[] mStack; - float[] mLocalStack = new float[128]; + @NonNull float[] mLocalStack = new float[128]; float[] mVar; CollectionsAccess mCollectionsAccess; @@ -201,7 +202,7 @@ public class AnimatedFloatExpression { * @param var * @return */ - public float eval(float[] exp, int len, float... var) { + public float eval(@NonNull float[] exp, int len, float... var) { System.arraycopy(exp, 0, mLocalStack, 0, len); mStack = mLocalStack; mVar = var; @@ -224,7 +225,7 @@ public class AnimatedFloatExpression { * @param var * @return */ - public float evalDB(float[] exp, float... var) { + public float evalDB(@NonNull float[] exp, float... var) { mStack = exp; mVar = var; int sp = -1; @@ -240,195 +241,281 @@ public class AnimatedFloatExpression { return mStack[sp]; } - Op[] mOps = { + @NonNull Op[] mOps; + + { + Op mADD = + (sp) -> { // ADD + mStack[sp - 1] = mStack[sp - 1] + mStack[sp]; + return sp - 1; + }; + Op mSUB = + (sp) -> { // SUB + mStack[sp - 1] = mStack[sp - 1] - mStack[sp]; + return sp - 1; + }; + Op mMUL = + (sp) -> { // MUL + mStack[sp - 1] = mStack[sp - 1] * mStack[sp]; + return sp - 1; + }; + Op mDIV = + (sp) -> { // DIV + mStack[sp - 1] = mStack[sp - 1] / mStack[sp]; + return sp - 1; + }; + Op mMOD = + (sp) -> { // MOD + mStack[sp - 1] = mStack[sp - 1] % mStack[sp]; + return sp - 1; + }; + Op mMIN = + (sp) -> { // MIN + mStack[sp - 1] = (float) Math.min(mStack[sp - 1], mStack[sp]); + return sp - 1; + }; + Op mMAX = + (sp) -> { // MAX + mStack[sp - 1] = (float) Math.max(mStack[sp - 1], mStack[sp]); + return sp - 1; + }; + Op mPOW = + (sp) -> { // POW + mStack[sp - 1] = (float) Math.pow(mStack[sp - 1], mStack[sp]); + return sp - 1; + }; + Op mSQRT = + (sp) -> { // SQRT + mStack[sp] = (float) Math.sqrt(mStack[sp]); + return sp; + }; + Op mABS = + (sp) -> { // ABS + mStack[sp] = (float) Math.abs(mStack[sp]); + return sp; + }; + Op mSIGN = + (sp) -> { // SIGN + mStack[sp] = (float) Math.signum(mStack[sp]); + return sp; + }; + Op mCOPY_SIGN = + (sp) -> { // copySign + mStack[sp - 1] = (float) Math.copySign(mStack[sp - 1], mStack[sp]); + return sp - 1; + }; + Op mEXP = + (sp) -> { // EXP + mStack[sp] = (float) Math.exp(mStack[sp]); + return sp; + }; + Op mFLOOR = + (sp) -> { // FLOOR + mStack[sp] = (float) Math.floor(mStack[sp]); + return sp; + }; + Op mLOG = + (sp) -> { // LOG + mStack[sp] = (float) Math.log10(mStack[sp]); + return sp; + }; + Op mLN = + (sp) -> { // LN + mStack[sp] = (float) Math.log(mStack[sp]); + return sp; + }; + Op mROUND = + (sp) -> { // ROUND + mStack[sp] = (float) Math.round(mStack[sp]); + return sp; + }; + Op mSIN = + (sp) -> { // SIN + mStack[sp] = (float) Math.sin(mStack[sp]); + return sp; + }; + Op mCOS = + (sp) -> { // COS + mStack[sp] = (float) Math.cos(mStack[sp]); + return sp; + }; + Op mTAN = + (sp) -> { // TAN + mStack[sp] = (float) Math.tan(mStack[sp]); + return sp; + }; + Op mASIN = + (sp) -> { // ASIN + mStack[sp] = (float) Math.asin(mStack[sp]); + return sp; + }; + Op mACOS = + (sp) -> { // ACOS + mStack[sp] = (float) Math.acos(mStack[sp]); + return sp; + }; + Op mATAN = + (sp) -> { // ATAN + mStack[sp] = (float) Math.atan(mStack[sp]); + return sp; + }; + Op mATAN2 = + (sp) -> { // ATAN2 + mStack[sp - 1] = (float) Math.atan2(mStack[sp - 1], mStack[sp]); + return sp - 1; + }; + Op mMAD = + (sp) -> { // MAD + mStack[sp - 2] = mStack[sp] + mStack[sp - 1] * mStack[sp - 2]; + return sp - 2; + }; + Op mTERNARY_CONDITIONAL = + (sp) -> { // TERNARY_CONDITIONAL + mStack[sp - 2] = (mStack[sp] > 0) ? mStack[sp - 1] : mStack[sp - 2]; + return sp - 2; + }; + Op mCLAMP = + (sp) -> { // CLAMP + mStack[sp - 2] = Math.min(Math.max(mStack[sp - 2], mStack[sp]), mStack[sp - 1]); + return sp - 2; + }; + Op mCBRT = + (sp) -> { // CBRT + mStack[sp] = (float) Math.pow(mStack[sp], 1 / 3.); + return sp; + }; + Op mDEG = + (sp) -> { // DEG + mStack[sp] = mStack[sp] * FP_TO_RAD; + return sp; + }; + Op mRAD = + (sp) -> { // RAD + mStack[sp] = mStack[sp] * FP_TO_DEG; + return sp; + }; + Op mCEIL = + (sp) -> { // CEIL + mStack[sp] = (float) Math.ceil(mStack[sp]); + return sp; + }; + Op mA_DEREF = + (sp) -> { // A_DEREF + int id = fromNaN(mStack[sp]); + mStack[sp - 1] = mCollectionsAccess.getFloatValue(id, (int) mStack[sp - 1]); + return sp - 1; + }; + Op mA_MAX = + (sp) -> { // A_MAX + int id = fromNaN(mStack[sp]); + float[] array = mCollectionsAccess.getFloats(id); + float max = array[0]; + for (int i = 1; i < array.length; i++) { + max = Math.max(max, array[i]); + } + mStack[sp] = max; + return sp; + }; + Op mA_MIN = + (sp) -> { // A_MIN + int id = fromNaN(mStack[sp]); + float[] array = mCollectionsAccess.getFloats(id); + float max = array[0]; + for (int i = 1; i < array.length; i++) { + max = Math.max(max, array[i]); + } + mStack[sp] = max; + return sp; + }; + Op mA_SUM = + (sp) -> { // A_SUM + int id = fromNaN(mStack[sp]); + float[] array = mCollectionsAccess.getFloats(id); + float sum = 0; + for (int i = 0; i < array.length; i++) { + sum += array[i]; + } + mStack[sp] = sum; + return sp; + }; + Op mA_AVG = + (sp) -> { // A_AVG + int id = fromNaN(mStack[sp]); + float[] array = mCollectionsAccess.getFloats(id); + float sum = 0; + for (int i = 0; i < array.length; i++) { + sum += array[i]; + } + mStack[sp] = sum / array.length; + return sp; + }; + Op mA_LEN = + (sp) -> { // A_LEN + int id = fromNaN(mStack[sp]); + mStack[sp] = mCollectionsAccess.getListLength(id); + return sp; + }; + Op mFIRST_VAR = + (sp) -> { // FIRST_VAR + mStack[sp] = mVar[0]; + return sp; + }; + Op mSECOND_VAR = + (sp) -> { // SECOND_VAR + mStack[sp] = mVar[1]; + return sp; + }; + Op mTHIRD_VAR = + (sp) -> { // THIRD_VAR + mStack[sp] = mVar[2]; + return sp; + }; + + Op[] ops = { null, - (sp) -> { // ADD - mStack[sp - 1] = mStack[sp - 1] + mStack[sp]; - return sp - 1; - }, - (sp) -> { // SUB - mStack[sp - 1] = mStack[sp - 1] - mStack[sp]; - return sp - 1; - }, - (sp) -> { // MUL - mStack[sp - 1] = mStack[sp - 1] * mStack[sp]; - return sp - 1; - }, - (sp) -> { // DIV - mStack[sp - 1] = mStack[sp - 1] / mStack[sp]; - return sp - 1; - }, - (sp) -> { // MOD - mStack[sp - 1] = mStack[sp - 1] % mStack[sp]; - return sp - 1; - }, - (sp) -> { // MIN - mStack[sp - 1] = (float) Math.min(mStack[sp - 1], mStack[sp]); - return sp - 1; - }, - (sp) -> { // MAX - mStack[sp - 1] = (float) Math.max(mStack[sp - 1], mStack[sp]); - return sp - 1; - }, - (sp) -> { // POW - mStack[sp - 1] = (float) Math.pow(mStack[sp - 1], mStack[sp]); - return sp - 1; - }, - (sp) -> { // SQRT - mStack[sp] = (float) Math.sqrt(mStack[sp]); - return sp; - }, - (sp) -> { // ABS - mStack[sp] = (float) Math.abs(mStack[sp]); - return sp; - }, - (sp) -> { // SIGN - mStack[sp] = (float) Math.signum(mStack[sp]); - return sp; - }, - (sp) -> { // copySign - mStack[sp - 1] = (float) Math.copySign(mStack[sp - 1], mStack[sp]); - return sp - 1; - }, - (sp) -> { // EXP - mStack[sp] = (float) Math.exp(mStack[sp]); - return sp; - }, - (sp) -> { // FLOOR - mStack[sp] = (float) Math.floor(mStack[sp]); - return sp; - }, - (sp) -> { // LOG - mStack[sp] = (float) Math.log10(mStack[sp]); - return sp; - }, - (sp) -> { // LN - mStack[sp] = (float) Math.log(mStack[sp]); - return sp; - }, - (sp) -> { // ROUND - mStack[sp] = (float) Math.round(mStack[sp]); - return sp; - }, - (sp) -> { // SIN - mStack[sp] = (float) Math.sin(mStack[sp]); - return sp; - }, - (sp) -> { // COS - mStack[sp] = (float) Math.cos(mStack[sp]); - return sp; - }, - (sp) -> { // TAN - mStack[sp] = (float) Math.tan(mStack[sp]); - return sp; - }, - (sp) -> { // ASIN - mStack[sp] = (float) Math.asin(mStack[sp]); - return sp; - }, - (sp) -> { // ACOS - mStack[sp] = (float) Math.acos(mStack[sp]); - return sp; - }, - (sp) -> { // ATAN - mStack[sp] = (float) Math.atan(mStack[sp]); - return sp; - }, - (sp) -> { // ATAN2 - mStack[sp - 1] = (float) Math.atan2(mStack[sp - 1], mStack[sp]); - return sp - 1; - }, - (sp) -> { // MAD - mStack[sp - 2] = mStack[sp] + mStack[sp - 1] * mStack[sp - 2]; - return sp - 2; - }, - (sp) -> { // Ternary conditional - mStack[sp - 2] = (mStack[sp] > 0) ? mStack[sp - 1] : mStack[sp - 2]; - return sp - 2; - }, - (sp) -> { // CLAMP(min,max, val) - mStack[sp - 2] = Math.min(Math.max(mStack[sp - 2], mStack[sp]), mStack[sp - 1]); - return sp - 2; - }, - (sp) -> { // CBRT cuberoot - mStack[sp] = (float) Math.pow(mStack[sp], 1 / 3.); - return sp; - }, - (sp) -> { // DEG - mStack[sp] = mStack[sp] * FP_TO_RAD; - return sp; - }, - (sp) -> { // RAD - mStack[sp] = mStack[sp] * FP_TO_DEG; - return sp; - }, - (sp) -> { // CEIL - mStack[sp] = (float) Math.ceil(mStack[sp]); - return sp; - }, - (sp) -> { // A_DEREF - int id = fromNaN(mStack[sp]); - mStack[sp] = mCollectionsAccess.getFloatValue(id, (int) mStack[sp - 1]); - return sp - 1; - }, - (sp) -> { // A_MAX - int id = fromNaN(mStack[sp]); - float[] array = mCollectionsAccess.getFloats(id); - float max = array[0]; - for (int i = 1; i < array.length; i++) { - max = Math.max(max, array[i]); - } - mStack[sp] = max; - return sp; - }, - (sp) -> { // A_MIN - int id = fromNaN(mStack[sp]); - float[] array = mCollectionsAccess.getFloats(id); - float max = array[0]; - for (int i = 1; i < array.length; i++) { - max = Math.max(max, array[i]); - } - mStack[sp] = max; - return sp; - }, - (sp) -> { // A_SUM - int id = fromNaN(mStack[sp]); - float[] array = mCollectionsAccess.getFloats(id); - float sum = 0; - for (int i = 0; i < array.length; i++) { - sum += array[i]; - } - mStack[sp] = sum; - return sp; - }, - (sp) -> { // A_AVG - int id = fromNaN(mStack[sp]); - float[] array = mCollectionsAccess.getFloats(id); - float sum = 0; - for (int i = 0; i < array.length; i++) { - sum += array[i]; - } - mStack[sp] = sum / array.length; - return sp; - }, - (sp) -> { // A_LEN - int id = fromNaN(mStack[sp]); - mStack[sp] = mCollectionsAccess.getListLength(id); - return sp; - }, - (sp) -> { // first var = - mStack[sp] = mVar[0]; - return sp; - }, - (sp) -> { // second var y? - mStack[sp] = mVar[1]; - return sp; - }, - (sp) -> { // 3rd var z? - mStack[sp] = mVar[2]; - return sp; - }, - }; + mADD, + mSUB, + mMUL, + mDIV, + mMOD, + mMIN, + mMAX, + mPOW, + mSQRT, + mABS, + mSIGN, + mCOPY_SIGN, + mEXP, + mFLOOR, + mLOG, + mLN, + mROUND, + mSIN, + mCOS, + mTAN, + mASIN, + mACOS, + mATAN, + mATAN2, + mMAD, + mTERNARY_CONDITIONAL, + mCLAMP, + mCBRT, + mDEG, + mRAD, + mCEIL, + mA_DEREF, + mA_MAX, + mA_MIN, + mA_SUM, + mA_AVG, + mA_LEN, + mFIRST_VAR, + mSECOND_VAR, + mTHIRD_VAR, + }; + mOps = ops; + } static { int k = 0; @@ -483,6 +570,7 @@ public class AnimatedFloatExpression { * @param f * @return */ + @Nullable public static String toMathName(float f) { int id = fromNaN(f) - OFFSET; return sNames.get(id); @@ -495,7 +583,8 @@ public class AnimatedFloatExpression { * @param labels * @return */ - public static String toString(float[] exp, String[] labels) { + @NonNull + public static String toString(@NonNull float[] exp, @Nullable String[] labels) { StringBuilder s = new StringBuilder(); for (int i = 0; i < exp.length; i++) { float v = exp[i]; @@ -525,7 +614,7 @@ public class AnimatedFloatExpression { return s.toString(); } - static String toString(float[] exp, int sp) { + static String toString(@NonNull float[] exp, int sp) { // String[] str = new String[exp.length]; if (Float.isNaN(exp[sp])) { int id = fromNaN(exp[sp]) - OFFSET; @@ -575,42 +664,42 @@ public class AnimatedFloatExpression { } static final int[] NO_OF_OPS = { - -1, // no op - 2, - 2, - 2, - 2, - 2, // + - * / % - 2, - 2, - 2, // min max, power - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, // sqrt,abs,CopySign,exp,floor,log,ln - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 2, // round,sin,cos,tan,asin,acos,atan,atan2 - 3, - 3, - 3, - 1, - 1, - 1, - 1, - 0, - 0, - 0 // mad, ?:, - // a[0],a[1],a[2] + -1, // no op + 2, + 2, + 2, + 2, + 2, // + - * / % + 2, + 2, + 2, // min max, power + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, // sqrt,abs,CopySign,exp,floor,log,ln + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, // round,sin,cos,tan,asin,acos,atan,atan2 + 3, + 3, + 3, + 1, + 1, + 1, + 1, + 0, + 0, + 0 // mad, ?:, + // a[0],a[1],a[2] }; /** diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/ImageScaling.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/ImageScaling.java index 00c87c1f9c80..e74b3350f427 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/ImageScaling.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/ImageScaling.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations.utilities; +import android.annotation.NonNull; + /** Implement the scaling logic for Compose Image or ImageView */ public class ImageScaling { @@ -97,6 +99,7 @@ public class ImageScaling { adjustDrawToType(); } + @NonNull static String str(float v) { String s = " " + (int) v; return s.substring(s.length() - 3); @@ -210,6 +213,7 @@ public class ImageScaling { } } + @NonNull public static String typeToString(int type) { String[] typeString = { "none", diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntMap.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntMap.java index 84e78431790a..749c0fe0dcc3 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntMap.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntMap.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations.utilities; +import android.annotation.Nullable; + import java.util.ArrayList; import java.util.Arrays; @@ -42,6 +44,7 @@ public class IntMap<T> { mSize = 0; } + @Nullable public T put(int key, T value) { if (key == NOT_PRESENT) throw new IllegalArgumentException("Key cannot be NOT_PRESENT"); if (mSize > mKeys.length * LOAD_FACTOR) { @@ -50,6 +53,7 @@ public class IntMap<T> { return insert(key, value); } + @Nullable public T get(int key) { int index = findKey(key); if (index == -1) { @@ -61,6 +65,7 @@ public class IntMap<T> { return mSize; } + @Nullable private T insert(int key, T value) { int index = hash(key) % mKeys.length; while (mKeys[index] != NOT_PRESENT && mKeys[index] != key) { diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntegerExpressionEvaluator.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntegerExpressionEvaluator.java index baa144d6b28d..8905431d14d7 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntegerExpressionEvaluator.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntegerExpressionEvaluator.java @@ -15,6 +15,9 @@ */ package com.android.internal.widget.remotecompose.core.operations.utilities; +import android.annotation.NonNull; +import android.annotation.Nullable; + /** * High performance Integer expression evaluator * @@ -22,7 +25,7 @@ package com.android.internal.widget.remotecompose.core.operations.utilities; * 0) */ public class IntegerExpressionEvaluator { - static IntMap<String> sNames = new IntMap<>(); + @NonNull static IntMap<String> sNames = new IntMap<>(); public static final int OFFSET = 0x10000; // add, sub, mul,div,mod,min,max, shl, shr, ushr, OR, AND , XOR, COPY_SIGN public static final int I_ADD = OFFSET + 1; @@ -57,7 +60,7 @@ public class IntegerExpressionEvaluator { public static final int I_VAR2 = OFFSET + 25; int[] mStack; - int[] mLocalStack = new int[128]; + @NonNull int[] mLocalStack = new int[128]; int[] mVar; interface Op { @@ -68,8 +71,8 @@ public class IntegerExpressionEvaluator { * Evaluate an integer expression * * @param mask bits that are operators - * @param exp rpn sequence of values and operators - * @param var variables if the expression is a function + * @param exp rpn sequence of values and operators + * @param var variables if the expression is a function * @return return the results of evaluating the expression */ public int eval(int mask, int[] exp, int... var) { @@ -91,12 +94,12 @@ public class IntegerExpressionEvaluator { * Evaluate a integer expression * * @param mask bits that are operators - * @param exp rpn sequence of values and operators - * @param len the number of values in the expression - * @param var variables if the expression is a function + * @param exp rpn sequence of values and operators + * @param len the number of values in the expression + * @param var variables if the expression is a function * @return return the results of evaluating the expression */ - public int eval(int mask, int[] exp, int len, int... var) { + public int eval(int mask, @NonNull int[] exp, int len, int... var) { System.arraycopy(exp, 0, mLocalStack, 0, len); mStack = mLocalStack; mVar = var; @@ -116,11 +119,11 @@ public class IntegerExpressionEvaluator { * Evaluate a int expression * * @param opMask bits that are operators - * @param exp rpn sequence of values and operators - * @param var variables if the expression is a function + * @param exp rpn sequence of values and operators + * @param var variables if the expression is a function * @return return the results of evaluating the expression */ - public int evalDB(int opMask, int[] exp, int... var) { + public int evalDB(int opMask, @NonNull int[] exp, int... var) { mStack = exp; mVar = var; int sp = -1; @@ -137,113 +140,172 @@ public class IntegerExpressionEvaluator { return mStack[sp]; } - Op[] mOps = { + @NonNull Op[] mOps; + + { + Op mADD = + (sp) -> { // ADD + mStack[sp - 1] = mStack[sp - 1] + mStack[sp]; + return sp - 1; + }; + Op mSUB = + (sp) -> { // SUB + mStack[sp - 1] = mStack[sp - 1] - mStack[sp]; + return sp - 1; + }; + Op mMUL = + (sp) -> { // MUL + mStack[sp - 1] = mStack[sp - 1] * mStack[sp]; + return sp - 1; + }; + Op mDIV = + (sp) -> { // DIV + mStack[sp - 1] = mStack[sp - 1] / mStack[sp]; + return sp - 1; + }; + Op mMOD = + (sp) -> { // MOD + mStack[sp - 1] = mStack[sp - 1] % mStack[sp]; + return sp - 1; + }; + Op mSHL = + (sp) -> { // SHL + mStack[sp - 1] = mStack[sp - 1] << mStack[sp]; + return sp - 1; + }; + Op mSHR = + (sp) -> { // SHR + mStack[sp - 1] = mStack[sp - 1] >> mStack[sp]; + return sp - 1; + }; + Op mUSHR = + (sp) -> { // USHR + mStack[sp - 1] = mStack[sp - 1] >>> mStack[sp]; + return sp - 1; + }; + Op mOR = + (sp) -> { // OR + mStack[sp - 1] = mStack[sp - 1] | mStack[sp]; + return sp - 1; + }; + Op mAND = + (sp) -> { // AND + mStack[sp - 1] = mStack[sp - 1] & mStack[sp]; + return sp - 1; + }; + Op mXOR = + (sp) -> { // XOR + mStack[sp - 1] = mStack[sp - 1] ^ mStack[sp]; + return sp - 1; + }; + Op mCOPY_SIGN = + (sp) -> { // COPY_SIGN + mStack[sp - 1] = (mStack[sp - 1] ^ (mStack[sp] >> 31)) - (mStack[sp] >> 31); + return sp - 1; + }; + Op mMIN = + (sp) -> { // MIN + mStack[sp - 1] = Math.min(mStack[sp - 1], mStack[sp]); + return sp - 1; + }; + Op mMAX = + (sp) -> { // MAX + mStack[sp - 1] = Math.max(mStack[sp - 1], mStack[sp]); + return sp - 1; + }; + Op mNEG = + (sp) -> { // NEG + mStack[sp] = -mStack[sp]; + return sp; + }; + Op mABS = + (sp) -> { // ABS + mStack[sp] = Math.abs(mStack[sp]); + return sp; + }; + Op mINCR = + (sp) -> { // INCR + mStack[sp] = mStack[sp] + 1; + return sp; + }; + Op mDECR = + (sp) -> { // DECR + mStack[sp] = mStack[sp] - 1; + return sp; + }; + Op mNOT = + (sp) -> { // NOT + mStack[sp] = ~mStack[sp]; + return sp; + }; + Op mSIGN = + (sp) -> { // SIGN + mStack[sp] = (mStack[sp] >> 31) | (-mStack[sp] >>> 31); + return sp; + }; + Op mCLAMP = + (sp) -> { // CLAMP + mStack[sp - 2] = Math.min(Math.max(mStack[sp - 2], mStack[sp]), mStack[sp - 1]); + return sp - 2; + }; + Op mTERNARY_CONDITIONAL = + (sp) -> { // TERNARY_CONDITIONAL + mStack[sp - 2] = (mStack[sp] > 0) ? mStack[sp - 1] : mStack[sp - 2]; + return sp - 2; + }; + Op mMAD = + (sp) -> { // MAD + mStack[sp - 2] = mStack[sp] + mStack[sp - 1] * mStack[sp - 2]; + return sp - 2; + }; + Op mFIRST_VAR = + (sp) -> { // FIRST_VAR + mStack[sp] = mVar[0]; + return sp; + }; + Op mSECOND_VAR = + (sp) -> { // SECOND_VAR + mStack[sp] = mVar[1]; + return sp; + }; + Op mTHIRD_VAR = + (sp) -> { // THIRD_VAR + mStack[sp] = mVar[2]; + return sp; + }; + + Op[] ops = { null, - (sp) -> { // ADD - mStack[sp - 1] = mStack[sp - 1] + mStack[sp]; - return sp - 1; - }, - (sp) -> { // SUB - mStack[sp - 1] = mStack[sp - 1] - mStack[sp]; - return sp - 1; - }, - (sp) -> { // MUL - mStack[sp - 1] = mStack[sp - 1] * mStack[sp]; - return sp - 1; - }, - (sp) -> { // DIV - mStack[sp - 1] = mStack[sp - 1] / mStack[sp]; - return sp - 1; - }, - (sp) -> { // MOD - mStack[sp - 1] = mStack[sp - 1] % mStack[sp]; - return sp - 1; - }, - (sp) -> { // SHL shift left - mStack[sp - 1] = mStack[sp - 1] << mStack[sp]; - return sp - 1; - }, - (sp) -> { // SHR shift right - mStack[sp - 1] = mStack[sp - 1] >> mStack[sp]; - return sp - 1; - }, - (sp) -> { // USHR unsigned shift right - mStack[sp - 1] = mStack[sp - 1] >>> mStack[sp]; - return sp - 1; - }, - (sp) -> { // OR operator - mStack[sp - 1] = mStack[sp - 1] | mStack[sp]; - return sp - 1; - }, - (sp) -> { // AND operator - mStack[sp - 1] = mStack[sp - 1] & mStack[sp]; - return sp - 1; - }, - (sp) -> { // XOR xor operator - mStack[sp - 1] = mStack[sp - 1] ^ mStack[sp]; - return sp - 1; - }, - (sp) -> { // COPY_SIGN copy the sing of (using bit magic) - mStack[sp - 1] = (mStack[sp - 1] ^ (mStack[sp] >> 31)) - (mStack[sp] >> 31); - return sp - 1; - }, - (sp) -> { // MIN - mStack[sp - 1] = Math.min(mStack[sp - 1], mStack[sp]); - return sp - 1; - }, - (sp) -> { // MAX - mStack[sp - 1] = Math.max(mStack[sp - 1], mStack[sp]); - return sp - 1; - }, - (sp) -> { // NEG - mStack[sp] = -mStack[sp]; - return sp; - }, - (sp) -> { // ABS - mStack[sp] = Math.abs(mStack[sp]); - return sp; - }, - (sp) -> { // INCR increment - mStack[sp] = mStack[sp] + 1; - return sp; - }, - (sp) -> { // DECR decrement - mStack[sp] = mStack[sp] - 1; - return sp; - }, - (sp) -> { // NOT Bit invert - mStack[sp] = ~mStack[sp]; - return sp; - }, - (sp) -> { // SIGN x<0 = -1,x==0 = 0 , x>0 = 1 - mStack[sp] = (mStack[sp] >> 31) | (-mStack[sp] >>> 31); - return sp; - }, - (sp) -> { // CLAMP(min,max, val) - mStack[sp - 2] = Math.min(Math.max(mStack[sp - 2], mStack[sp]), mStack[sp - 1]); - return sp - 2; - }, - (sp) -> { // Ternary conditional - mStack[sp - 2] = (mStack[sp] > 0) ? mStack[sp - 1] : mStack[sp - 2]; - return sp - 2; - }, - (sp) -> { // MAD - mStack[sp - 2] = mStack[sp] + mStack[sp - 1] * mStack[sp - 2]; - return sp - 2; - }, - (sp) -> { // first var = - mStack[sp] = mVar[0]; - return sp; - }, - (sp) -> { // second var y? - mStack[sp] = mVar[1]; - return sp; - }, - (sp) -> { // 3rd var z? - mStack[sp] = mVar[2]; - return sp; - }, - }; + mADD, + mSUB, + mMUL, + mDIV, + mMOD, + mSHL, + mSHR, + mUSHR, + mOR, + mAND, + mXOR, + mCOPY_SIGN, + mMIN, + mMAX, + mNEG, + mABS, + mINCR, + mDECR, + mNOT, + mSIGN, + mCLAMP, + mTERNARY_CONDITIONAL, + mMAD, + mFIRST_VAR, + mSECOND_VAR, + mTHIRD_VAR, + }; + + mOps = ops; + } static { int k = 0; @@ -283,6 +345,7 @@ public class IntegerExpressionEvaluator { * @param f the numerical value of the function + offset * @return the math name of the function */ + @Nullable public static String toMathName(int f) { int id = f - OFFSET; return sNames.get(id); @@ -292,11 +355,12 @@ public class IntegerExpressionEvaluator { * Convert an expression encoded as an array of ints int to a string * * @param opMask bits that are operators - * @param exp rpn sequence of values and operators + * @param exp rpn sequence of values and operators * @param labels String that represent the variable names * @return */ - public static String toString(int opMask, int[] exp, String[] labels) { + @NonNull + public static String toString(int opMask, @NonNull int[] exp, String[] labels) { StringBuilder s = new StringBuilder(); for (int i = 0; i < exp.length; i++) { int v = exp[i]; @@ -324,10 +388,11 @@ public class IntegerExpressionEvaluator { * Convert an expression encoded as an array of ints int ot a string * * @param opMask bit mask of operators vs commands - * @param exp rpn sequence of values and operators + * @param exp rpn sequence of values and operators * @return string representation of the expression */ - public static String toString(int opMask, int[] exp) { + @NonNull + public static String toString(int opMask, @NonNull int[] exp) { StringBuilder s = new StringBuilder(); s.append(Integer.toBinaryString(opMask)); s.append(" : "); @@ -355,13 +420,15 @@ public class IntegerExpressionEvaluator { * This creates an infix string expression * * @param opMask The bits that are operators - * @param exp the array of expressions + * @param exp the array of expressions * @return infix string */ - public static String toStringInfix(int opMask, int[] exp) { + @NonNull + public static String toStringInfix(int opMask, @NonNull int[] exp) { return toString(opMask, exp, exp.length - 1); } + @NonNull static String toString(int mask, int[] exp, int sp) { if (((1 << sp) & mask) != 0) { int id = exp[sp] - OFFSET; @@ -412,34 +479,34 @@ public class IntegerExpressionEvaluator { } static final int[] NO_OF_OPS = { - -1, // no op - 2, - 2, - 2, - 2, - 2, // + - * / % - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, // <<, >> , >>> , | , &, ^, min max - 1, - 1, - 1, - 1, - 1, - 1, // neg, abs, ++, -- , not , sign - 3, - 3, - 3, // clamp, ifElse, mad, - 0, - 0, - 0 // mad, ?:, - // a[0],a[1],a[2] + -1, // no op + 2, + 2, + 2, + 2, + 2, // + - * / % + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, // <<, >> , >>> , | , &, ^, min max + 1, + 1, + 1, + 1, + 1, + 1, // neg, abs, ++, -- , not , sign + 3, + 3, + 3, // clamp, ifElse, mad, + 0, + 0, + 0 // mad, ?:, + // a[0],a[1],a[2] }; /** @@ -456,7 +523,7 @@ public class IntegerExpressionEvaluator { * is it an id or operation * * @param opMask the bits that mark elements as an operation - * @param i the bit to check + * @param i the bit to check * @return true if the bit is 1 */ public static boolean isOperation(int opMask, int i) { diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/StringSerializer.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/StringSerializer.java index ab7576e12aa6..92127c12f401 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/StringSerializer.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/StringSerializer.java @@ -15,9 +15,14 @@ */ package com.android.internal.widget.remotecompose.core.operations.utilities; +import android.annotation.NonNull; +import android.annotation.Nullable; + /** Utility serializer maintaining an indent buffer */ public class StringSerializer { - StringBuffer mBuffer = new StringBuffer(); + @NonNull StringBuffer mBuffer = new StringBuffer(); + + @NonNull String mIndentBuffer = " "; /** @@ -26,7 +31,7 @@ public class StringSerializer { * @param indent the indentation level to use * @param content content to append */ - public void append(int indent, String content) { + public void append(int indent, @Nullable String content) { String indentation = mIndentBuffer.substring(0, indent); mBuffer.append(indentation); mBuffer.append(indentation); @@ -44,6 +49,7 @@ public class StringSerializer { * * @return string representation */ + @NonNull @Override public String toString() { return mBuffer.toString(); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/StringUtils.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/StringUtils.java index f2ccb401ea8f..a95a175d0edd 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/StringUtils.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/StringUtils.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations.utilities; +import android.annotation.NonNull; + import java.util.Arrays; /** Utilities for string manipulation */ @@ -30,6 +32,7 @@ public class StringUtils { * @param post character to pad width 0 = no pad typically ' ' or '0' * @return */ + @NonNull public static String floatToString( float value, int beforeDecimalPoint, int afterDecimalPoint, char pre, char post) { diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/CubicEasing.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/CubicEasing.java index 60a59cf464cd..1343345df6e5 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/CubicEasing.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/CubicEasing.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations.utilities.easing; +import android.annotation.NonNull; + class CubicEasing extends Easing { float mX1 = 0f; float mY1 = 0f; @@ -62,7 +64,7 @@ class CubicEasing extends Easing { mType = type; } - void setup(float[] values) { + void setup(@NonNull float[] values) { setup(values[0], values[1], values[2], values[3]); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java index a29b8af5fbd1..ebb22b6e98c5 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java @@ -15,6 +15,9 @@ */ package com.android.internal.widget.remotecompose.core.operations.utilities.easing; +import android.annotation.NonNull; +import android.annotation.Nullable; + /** Support Animation of the FloatExpression */ public class FloatAnimation extends Easing { float[] mSpec; @@ -31,6 +34,7 @@ public class FloatAnimation extends Easing { // private float mScale = 1; float mOffset = 0; + @NonNull @Override public String toString() { @@ -74,7 +78,7 @@ public class FloatAnimation extends Easing { * @return */ public static float[] packToFloatArray( - float duration, int type, float[] spec, float initialValue, float wrap) { + float duration, int type, @Nullable float[] spec, float initialValue, float wrap) { int count = 0; if (!Float.isNaN(initialValue)) { @@ -129,6 +133,90 @@ public class FloatAnimation extends Easing { } /** + * Useful to debug the packed form of an animation string + * + * @param description + * @return + */ + public static String unpackAnimationToString(float[] description) { + float[] mSpec = description; + float mDuration = (mSpec.length == 0) ? 1 : mSpec[0]; + int len = 0; + int type = 0; + float wrapValue = Float.NaN; + float initialValue = Float.NaN; + if (mSpec.length > 1) { + int num_type = Float.floatToRawIntBits(mSpec[1]); + type = num_type & 0xFF; + boolean wrap = ((num_type >> 8) & 0x1) > 0; + boolean init = ((num_type >> 8) & 0x2) > 0; + len = (num_type >> 16) & 0xFFFF; + int off = 2 + len; + if (init) { + initialValue = mSpec[off++]; + } + if (wrap) { + wrapValue = mSpec[off]; + } + } + float[] params = description; + int offset = 2; + + String typeStr = ""; + switch (type) { + case CUBIC_STANDARD: + typeStr = "CUBIC_STANDARD"; + break; + case CUBIC_ACCELERATE: + typeStr = "CUBIC_ACCELERATE"; + break; + case CUBIC_DECELERATE: + typeStr = "CUBIC_DECELERATE"; + break; + case CUBIC_LINEAR: + typeStr = "CUBIC_LINEAR"; + break; + case CUBIC_ANTICIPATE: + typeStr = "CUBIC_ANTICIPATE"; + break; + case CUBIC_OVERSHOOT: + typeStr = "CUBIC_OVERSHOOT"; + + break; + case CUBIC_CUSTOM: + typeStr = "CUBIC_CUSTOM ("; + typeStr += params[offset + 0] + " "; + typeStr += params[offset + 1] + " "; + typeStr += params[offset + 2] + " "; + typeStr += params[offset + 3] + " )"; + break; + case EASE_OUT_BOUNCE: + typeStr = "EASE_OUT_BOUNCE"; + + break; + case EASE_OUT_ELASTIC: + typeStr = "EASE_OUT_ELASTIC"; + break; + case SPLINE_CUSTOM: + typeStr = "SPLINE_CUSTOM ("; + for (int i = offset; i < offset + len; i++) { + typeStr += params[i] + " "; + } + typeStr += ")"; + break; + } + + String str = mDuration + " " + typeStr; + if (!Float.isNaN(initialValue)) { + str += " init =" + initialValue; + } + if (!Float.isNaN(wrapValue)) { + str += " wrap =" + wrapValue; + } + return str; + } + + /** * Create an animation based on a float encoding of the animation * * @param description @@ -208,21 +296,43 @@ public class FloatAnimation extends Easing { setScaleOffset(); } + private static float wrap(float wrap, float value) { + value = value % wrap; + if (value < 0) { + value += wrap; + } + return value; + } + + float wrapDistance(float wrap, float from, float to) { + float delta = (to - from) % 360; + if (delta < -wrap / 2) { + delta += wrap; + } else if (delta > wrap / 2) { + delta -= wrap; + } + return delta; + } + /** * Set the target value to interpolate to * * @param value */ public void setTargetValue(float value) { - if (Float.isNaN(mWrap)) { - mTargetValue = value; - } else { - if (Math.abs((value % mWrap) + mWrap - mInitialValue) - < Math.abs((value % mWrap) - mInitialValue)) { - mTargetValue = (value % mWrap) + mWrap; + mTargetValue = value; + if (!Float.isNaN(mWrap)) { + mInitialValue = wrap(mWrap, mInitialValue); + mTargetValue = wrap(mWrap, mTargetValue); + if (Float.isNaN(mInitialValue)) { + mInitialValue = mTargetValue; + } - } else { - mTargetValue = value % mWrap; + float dist = wrapDistance(mWrap, mInitialValue, mTargetValue); + if ((dist > 0) && (mTargetValue < mInitialValue)) { + mTargetValue += mWrap; + } else if ((dist < 0) && (mTargetValue > mInitialValue)) { + mTargetValue -= mWrap; } } setScaleOffset(); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/GeneralEasing.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/GeneralEasing.java index 75a60324aa3c..90b65bf2353a 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/GeneralEasing.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/GeneralEasing.java @@ -15,10 +15,12 @@ */ package com.android.internal.widget.remotecompose.core.operations.utilities.easing; +import android.annotation.NonNull; + /** Provides and interface to create easing functions */ public class GeneralEasing extends Easing { float[] mEasingData = new float[0]; - Easing mEasingCurve = new CubicEasing(CUBIC_STANDARD); + @NonNull Easing mEasingCurve = new CubicEasing(CUBIC_STANDARD); /** * Set the curve based on the float encoding of it diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/MonotonicCurveFit.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/MonotonicCurveFit.java index 9355cacde4ad..f540e7008471 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/MonotonicCurveFit.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/MonotonicCurveFit.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations.utilities.easing; +import android.annotation.NonNull; + import java.util.Arrays; /** This performs a spline interpolation in multiple dimensions */ @@ -32,7 +34,7 @@ public class MonotonicCurveFit { * @param time the point along the curve * @param y the parameter at those points */ - public MonotonicCurveFit(double[] time, double[][] y) { + public MonotonicCurveFit(@NonNull double[] time, @NonNull double[][] y) { final int n = time.length; final int dim = y[0].length; mSlopeTemp = new double[dim]; @@ -331,7 +333,8 @@ public class MonotonicCurveFit { } /** This builds a monotonic spline to be used as a wave function */ - public static MonotonicCurveFit buildWave(String configString) { + @NonNull + public static MonotonicCurveFit buildWave(@NonNull String configString) { // done this way for efficiency String str = configString; double[] values = new double[str.length() / 2]; @@ -350,7 +353,8 @@ public class MonotonicCurveFit { return buildWave(Arrays.copyOf(values, count)); } - private static MonotonicCurveFit buildWave(double[] values) { + @NonNull + private static MonotonicCurveFit buildWave(@NonNull double[] values) { int length = values.length * 3 - 2; int len = values.length - 1; double gap = 1.0 / len; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/StepCurve.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/StepCurve.java index b4596897a44f..c7be3cab4c0b 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/StepCurve.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/StepCurve.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations.utilities.easing; +import android.annotation.NonNull; + /** * This class translates a series of floating point values into a continuous curve for use in an * easing function including quantize functions it is used with the "spline(0,0.3,0.3,0.5,...0.9,1)" @@ -28,6 +30,7 @@ public class StepCurve extends Easing { mCurveFit = genSpline(params, offset, len); } + @NonNull private static MonotonicCurveFit genSpline(float[] values, int off, int arrayLen) { int length = arrayLen * 3 - 2; int len = arrayLen - 1; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/touch/VelocityEasing.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/touch/VelocityEasing.java new file mode 100644 index 000000000000..3e24372f9b8c --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/touch/VelocityEasing.java @@ -0,0 +1,341 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations.utilities.touch; + +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +public class VelocityEasing { + private float mStartPos = 0; + private float mStartV = 0; + private float mEndPos = 0; + private float mDuration = 0; + + private Stage[] mStage = {new Stage(1), new Stage(2), new Stage(3)}; + private int mNumberOfStages = 0; + private Easing mEasing; + private double mEasingAdapterDistance = 0; + private double mEasingAdapterA = 0; + private double mEasingAdapterB = 0; + private boolean mOneDimension = true; + private float mTotalEasingDuration = 0; + + public float getDuration() { + if (mEasing != null) { + return mTotalEasingDuration; + } + return mDuration; + } + + public float getV(float t) { + if (mEasing == null) { + for (int i = 0; i < mNumberOfStages; i++) { + if (mStage[i].mEndTime > t) { + return mStage[i].getVel(t); + } + } + return 0f; + } + int lastStages = mNumberOfStages - 1; + for (int i = 0; i < lastStages; i++) { + if (mStage[i].mEndTime > t) { + return mStage[i].getVel(t); + } + } + return (float) getEasingDiff((t - mStage[lastStages].mStartTime)); + } + + public float getPos(float t) { + if (mEasing == null) { + for (int i = 0; i < mNumberOfStages; i++) { + if (mStage[i].mEndTime > t) { + return mStage[i].getPos(t); + } + } + return mEndPos; + } + int lastStages = mNumberOfStages - 1; + for (int i = 0; i < lastStages; i++) { + if (mStage[i].mEndTime > t) { + return mStage[i].getPos(t); + } + } + var ret = (float) getEasing((t - mStage[lastStages].mStartTime)); + ret += mStage[lastStages].mStartPos; + return ret; + } + + public String toString() { + var s = " "; + for (int i = 0; i < mNumberOfStages; i++) { + Stage stage = mStage[i]; + s += " $i $stage"; + } + return s; + } + + public void config( + float currentPos, + float destination, + float currentVelocity, + float maxTime, + float maxAcceleration, + float maxVelocity, + Easing easing) { + float pos = currentPos; + float velocity = currentVelocity; + if (pos == destination) { + pos += 1f; + } + mStartPos = pos; + mEndPos = destination; + if (easing != null) { + this.mEasing = easing.clone(); + } + float dir = Math.signum(destination - pos); + float maxV = maxVelocity * dir; + float maxA = maxAcceleration * dir; + if (velocity == 0.0) { + velocity = 0.0001f * dir; + } + mStartV = velocity; + if (!rampDown(pos, destination, velocity, maxTime)) { + if (!(mOneDimension + && cruseThenRampDown(pos, destination, velocity, maxTime, maxA, maxV))) { + if (!rampUpRampDown(pos, destination, velocity, maxA, maxV, maxTime)) { + rampUpCruseRampDown(pos, destination, velocity, maxA, maxV, maxTime); + } + } + } + if (mOneDimension) { + configureEasingAdapter(); + } + } + + private boolean rampDown( + float currentPos, float destination, float currentVelocity, float maxTime) { + float timeToDestination = 2 * ((destination - currentPos) / currentVelocity); + if (timeToDestination > 0 && timeToDestination <= maxTime) { // hit the brakes + mNumberOfStages = 1; + mStage[0].setUp(currentVelocity, currentPos, 0f, 0f, destination, timeToDestination); + mDuration = timeToDestination; + return true; + } + return false; + } + + private boolean cruseThenRampDown( + float currentPos, + float destination, + float currentVelocity, + float maxTime, + float maxA, + float maxV) { + float timeToBreak = currentVelocity / maxA; + float brakeDist = currentVelocity * timeToBreak / 2; + float cruseDist = destination - currentPos - brakeDist; + float cruseTime = cruseDist / currentVelocity; + float totalTime = cruseTime + timeToBreak; + if (totalTime > 0 && totalTime < maxTime) { + mNumberOfStages = 2; + mStage[0].setUp(currentVelocity, currentPos, 0f, currentVelocity, cruseDist, cruseTime); + mStage[1].setUp( + currentVelocity, + currentPos + cruseDist, + cruseTime, + 0f, + destination, + cruseTime + timeToBreak); + mDuration = cruseTime + timeToBreak; + return true; + } + return false; + } + + private boolean rampUpRampDown( + float currentPos, + float destination, + float currentVelocity, + float maxA, + float maxVelocity, + float maxTime) { + float peak_v = + Math.signum(maxA) + * (float) + Math.sqrt( + (maxA * (destination - currentPos) + + currentVelocity * currentVelocity / 2)); + if (maxVelocity / peak_v > 1) { + float t1 = (peak_v - currentVelocity) / maxA; + float d1 = (peak_v + currentVelocity) * t1 / 2 + currentPos; + float t2 = peak_v / maxA; + mNumberOfStages = 2; + mStage[0].setUp(currentVelocity, currentPos, 0f, peak_v, d1, t1); + mStage[1].setUp(peak_v, d1, t1, 0f, destination, t2 + t1); + mDuration = t2 + t1; + if (mDuration > maxTime) { + return false; + } + if (mDuration < maxTime / 2) { + t1 = mDuration / 2; + t2 = t1; + peak_v = (2 * (destination - currentPos) / t1 - currentVelocity) / 2; + d1 = (peak_v + currentVelocity) * t1 / 2 + currentPos; + mNumberOfStages = 2; + mStage[0].setUp(currentVelocity, currentPos, 0f, peak_v, d1, t1); + mStage[1].setUp(peak_v, d1, t1, 0f, destination, t2 + t1); + mDuration = t2 + t1; + if (mDuration > maxTime) { + System.out.println(" fail "); + return false; + } + } + return true; + } + return false; + } + + private void rampUpCruseRampDown( + float currentPos, + float destination, + float currentVelocity, + float maxA, + float maxV, + float maxTime) { + float t1 = maxTime / 3; + float t2 = t1 * 2; + float distance = destination - currentPos; + float dt2 = t2 - t1; + float dt3 = maxTime - t2; + float v1 = (2 * distance - currentVelocity * t1) / (t1 + 2 * dt2 + dt3); + mDuration = maxTime; + float d1 = (currentVelocity + v1) * t1 / 2; + float d2 = (v1 + v1) * (t2 - t1) / 2; + mNumberOfStages = 3; + float acc = (v1 - currentVelocity) / t1; + float dec = v1 / dt3; + mStage[0].setUp(currentVelocity, currentPos, 0f, v1, currentPos + d1, t1); + mStage[1].setUp(v1, currentPos + d1, t1, v1, currentPos + d1 + d2, t2); + mStage[2].setUp(v1, currentPos + d1 + d2, t2, 0f, destination, maxTime); + mDuration = maxTime; + } + + double getEasing(double t) { + double gx = t * t * mEasingAdapterA + t * mEasingAdapterB; + if (gx > 1) { + return mEasingAdapterDistance; + } else { + return mEasing.get(gx) * mEasingAdapterDistance; + } + } + + private double getEasingDiff(double t) { + double gx = t * t * mEasingAdapterA + t * mEasingAdapterB; + if (gx > 1) { + return 0.0; + } else { + return mEasing.getDiff(gx) + * mEasingAdapterDistance + * (t * mEasingAdapterA + mEasingAdapterB); + } + } + + protected void configureEasingAdapter() { + if (mEasing == null) { + return; + } + int last = mNumberOfStages - 1; + float initialVelocity = mStage[last].mStartV; + float distance = mStage[last].mEndPos - mStage[last].mStartPos; + float duration = mStage[last].mEndTime - mStage[last].mStartTime; + double baseVel = mEasing.getDiff(0.0); + mEasingAdapterB = initialVelocity / (baseVel * distance); + mEasingAdapterA = 1 - mEasingAdapterB; + mEasingAdapterDistance = distance; + double easingDuration = + (Math.sqrt(4 * mEasingAdapterA + mEasingAdapterB * mEasingAdapterB) + - mEasingAdapterB) + / (2 * mEasingAdapterA); + mTotalEasingDuration = (float) (easingDuration + mStage[last].mStartTime); + } + + interface Easing { + double get(double t); + + double getDiff(double t); + + Easing clone(); + } + + class Stage { + private float mStartV = 0; + private float mStartPos = 0; + private float mStartTime = 0; + private float mEndV = 0; + private float mEndPos = 0; + private float mEndTime = 0; + private float mDeltaV = 0; + private float mDeltaT = 0; + final int mStage; + + Stage(int n) { + mStage = n; + } + + void setUp( + float startV, + float startPos, + float startTime, + float endV, + float endPos, + float endTime) { + this.mStartV = startV; + this.mStartPos = startPos; + this.mStartTime = startTime; + this.mEndV = endV; + this.mEndTime = endTime; + this.mEndPos = endPos; + mDeltaV = this.mEndV - this.mStartV; + mDeltaT = this.mEndTime - this.mStartTime; + } + + float getPos(float t) { + float dt = t - mStartTime; + float pt = dt / mDeltaT; + float v = mStartV + mDeltaV * pt; + return dt * (mStartV + v) / 2 + mStartPos; + } + + float getVel(float t) { + float dt = t - mStartTime; + float pt = dt / (mEndTime - mStartTime); + return mStartV + mDeltaV * pt; + } + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/types/BooleanConstant.java b/core/java/com/android/internal/widget/remotecompose/core/types/BooleanConstant.java index 57a804284f0d..3fba8acf8bca 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/types/BooleanConstant.java +++ b/core/java/com/android/internal/widget/remotecompose/core/types/BooleanConstant.java @@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.types; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.BYTE; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -47,23 +49,26 @@ public class BooleanConstant implements Operation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mId, mValue); } @Override public void apply(RemoteContext context) {} + @NonNull @Override public String deepToString(String indent) { return toString(); } + @NonNull @Override public String toString() { return "BooleanConstant[" + mId + "] = " + mValue + ""; } + @NonNull public static String name() { return "OrigamiBoolean"; } @@ -79,20 +84,20 @@ public class BooleanConstant implements Operation { * @param id * @param value */ - public static void apply(WireBuffer buffer, int id, boolean value) { + public static void apply(@NonNull WireBuffer buffer, int id, boolean value) { buffer.start(OP_CODE); buffer.writeInt(id); buffer.writeBoolean(value); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int id = buffer.readInt(); boolean value = buffer.readBoolean(); operations.add(new BooleanConstant(id, value)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Expressions Operations", OP_CODE, "BooleanConstant") .description("A boolean and its associated id") .field(DocumentedOperation.INT, "id", "id of Int") diff --git a/core/java/com/android/internal/widget/remotecompose/core/types/IntegerConstant.java b/core/java/com/android/internal/widget/remotecompose/core/types/IntegerConstant.java index 3ef9db9de915..79f2a8d8dec5 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/types/IntegerConstant.java +++ b/core/java/com/android/internal/widget/remotecompose/core/types/IntegerConstant.java @@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.types; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -37,25 +39,28 @@ public class IntegerConstant implements Operation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mId, mValue); } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { context.loadInteger(mId, mValue); } + @NonNull @Override public String deepToString(String indent) { return toString(); } + @NonNull @Override public String toString() { return "IntegerConstant[" + mId + "] = " + mValue + ""; } + @NonNull public static String name() { return "IntegerConstant"; } @@ -71,20 +76,20 @@ public class IntegerConstant implements Operation { * @param textId * @param value */ - public static void apply(WireBuffer buffer, int textId, int value) { + public static void apply(@NonNull WireBuffer buffer, int textId, int value) { buffer.start(Operations.DATA_INT); buffer.writeInt(textId); buffer.writeInt(value); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int id = buffer.readInt(); int value = buffer.readInt(); operations.add(new IntegerConstant(id, value)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Expressions Operations", id(), "IntegerConstant") .description("A integer and its associated id") .field(DocumentedOperation.INT, "id", "id of Int") diff --git a/core/java/com/android/internal/widget/remotecompose/core/types/LongConstant.java b/core/java/com/android/internal/widget/remotecompose/core/types/LongConstant.java index 6d51d194708f..01672b469728 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/types/LongConstant.java +++ b/core/java/com/android/internal/widget/remotecompose/core/types/LongConstant.java @@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.types; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.LONG; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -47,7 +49,7 @@ public class LongConstant implements Operation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mId, mValue); } @@ -56,11 +58,13 @@ public class LongConstant implements Operation { context.putObject(mId, this); } + @NonNull @Override public String deepToString(String indent) { return toString(); } + @NonNull @Override public String toString() { return "LongConstant[" + mId + "] = " + mValue + ""; @@ -73,20 +77,20 @@ public class LongConstant implements Operation { * @param id * @param value */ - public static void apply(WireBuffer buffer, int id, long value) { + public static void apply(@NonNull WireBuffer buffer, int id, long value) { buffer.start(OP_CODE); buffer.writeInt(id); buffer.writeLong(value); } - public static void read(WireBuffer buffer, List<Operation> operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { int id = buffer.readInt(); long value = buffer.readLong(); operations.add(new LongConstant(id, value)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Expressions Operations", OP_CODE, "LongConstant") .description("A boolean and its associated id") .field(DocumentedOperation.INT, "id", "id of Int") diff --git a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposeDocument.java b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposeDocument.java index 906282c1dde3..aaee9c565fbb 100644 --- a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposeDocument.java +++ b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposeDocument.java @@ -112,6 +112,16 @@ public class RemoteComposeDocument { } /** + * Gets a array of Names of the named variables of a specific type defined in the doc. + * + * @param type the type of variable NamedVariable.COLOR_TYPE, STRING_TYPE, etc + * @return array of name or null + */ + public String[] getNamedVariables(int type) { + return mDocument.getNamedVariables(type); + } + + /** * Return a component associated with id * * @param id the component id diff --git a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java index 06bf4cdb0a0d..cc74b119866d 100644 --- a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java +++ b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java @@ -21,11 +21,14 @@ import android.graphics.Color; import android.util.AttributeSet; import android.util.Log; import android.util.TypedValue; +import android.view.HapticFeedbackConstants; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.HorizontalScrollView; import android.widget.ScrollView; +import com.android.internal.widget.remotecompose.core.CoreDocument; +import com.android.internal.widget.remotecompose.core.operations.NamedVariable; import com.android.internal.widget.remotecompose.core.operations.RootContentBehavior; import com.android.internal.widget.remotecompose.player.platform.RemoteComposeCanvas; @@ -57,11 +60,7 @@ public class RemoteComposePlayer extends FrameLayout { * @param debugFlags 1 to set debug on */ public void setDebug(int debugFlags) { - if (debugFlags == 1) { - mInner.setDebug(true); - } else { - mInner.setDebug(false); - } + mInner.setDebug(debugFlags); } public RemoteComposeDocument getDocument() { @@ -82,6 +81,14 @@ public class RemoteComposePlayer extends FrameLayout { mInner.setDocument(null); } mapColors(); + mInner.setHapticEngine( + new CoreDocument.HapticEngine() { + + @Override + public void haptic(int type) { + provideHapticFeedback(type); + } + }); } /** @@ -259,13 +266,40 @@ public class RemoteComposePlayer extends FrameLayout { /** * This returns a list of colors that have names in the Document. * - * @return + * @return the names of named Strings or null */ public String[] getNamedColors() { return mInner.getNamedColors(); } /** + * This returns a list of floats that have names in the Document. + * + * @return return the names of named floats in the document + */ + public String[] getNamedFloats() { + return mInner.getNamedVariables(NamedVariable.FLOAT_TYPE); + } + + /** + * This returns a list of string name that have names in the Document. + * + * @return the name of named string (not the string itself) + */ + public String[] getNamedStrings() { + return mInner.getNamedVariables(NamedVariable.STRING_TYPE); + } + + /** + * This returns a list of images that have names in the Document. + * + * @return + */ + public String[] getNamedImages() { + return mInner.getNamedVariables(NamedVariable.IMAGE_TYPE); + } + + /** * This sets a color based on its name. Overriding the color set in the document. * * @param colorName Name of the color @@ -481,4 +515,32 @@ public class RemoteComposePlayer extends FrameLayout { return color; } } + + private static int[] sHapticTable = { + HapticFeedbackConstants.NO_HAPTICS, + HapticFeedbackConstants.LONG_PRESS, + HapticFeedbackConstants.VIRTUAL_KEY, + HapticFeedbackConstants.KEYBOARD_TAP, + HapticFeedbackConstants.CLOCK_TICK, + HapticFeedbackConstants.CONTEXT_CLICK, + HapticFeedbackConstants.KEYBOARD_PRESS, + HapticFeedbackConstants.KEYBOARD_RELEASE, + HapticFeedbackConstants.VIRTUAL_KEY_RELEASE, + HapticFeedbackConstants.TEXT_HANDLE_MOVE, + HapticFeedbackConstants.GESTURE_START, + HapticFeedbackConstants.GESTURE_END, + HapticFeedbackConstants.CONFIRM, + HapticFeedbackConstants.REJECT, + HapticFeedbackConstants.TOGGLE_ON, + HapticFeedbackConstants.TOGGLE_OFF, + HapticFeedbackConstants.GESTURE_THRESHOLD_ACTIVATE, + HapticFeedbackConstants.GESTURE_THRESHOLD_DEACTIVATE, + HapticFeedbackConstants.DRAG_START, + HapticFeedbackConstants.SEGMENT_TICK, + HapticFeedbackConstants.SEGMENT_FREQUENT_TICK, + }; + + private void provideHapticFeedback(int type) { + performHapticFeedback(sHapticTable[type % sHapticTable.length]); + } } diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java index f59a0d3fa015..0b650a93c9db 100644 --- a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java +++ b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java @@ -26,6 +26,8 @@ import android.graphics.PorterDuffColorFilter; import android.graphics.RadialGradient; import android.graphics.Rect; import android.graphics.RectF; +import android.graphics.RenderEffect; +import android.graphics.RenderNode; import android.graphics.RuntimeShader; import android.graphics.Shader; import android.graphics.SweepGradient; @@ -51,6 +53,8 @@ public class AndroidPaintContext extends PaintContext { List<Paint> mPaintList = new ArrayList<>(); Canvas mCanvas; Rect mTmpRect = new Rect(); // use in calculation of bounds + RenderNode mNode = null; + Canvas mPreviousCanvas = null; public AndroidPaintContext(RemoteContext context, Canvas canvas) { super(context); @@ -122,6 +126,53 @@ public class AndroidPaintContext extends PaintContext { } @Override + public void startGraphicsLayer(int w, int h) { + mNode = new RenderNode("layer"); + mNode.setPosition(0, 0, w, h); + mPreviousCanvas = mCanvas; + mCanvas = mNode.beginRecording(); + } + + @Override + public void setGraphicsLayer( + float scaleX, + float scaleY, + float rotationX, + float rotationY, + float rotationZ, + float shadowElevation, + float transformOriginX, + float transformOriginY, + float alpha, + int renderEffectId) { + if (mNode == null) { + return; + } + mNode.setScaleX(scaleX); + mNode.setScaleY(scaleY); + mNode.setRotationX(rotationX); + mNode.setRotationY(rotationY); + mNode.setRotationZ(rotationZ); + mNode.setPivotX(transformOriginX * mNode.getWidth()); + mNode.setPivotY(transformOriginY * mNode.getHeight()); + mNode.setAlpha(alpha); + if (renderEffectId == 1) { + + RenderEffect effect = RenderEffect.createBlurEffect(8f, 8f, Shader.TileMode.CLAMP); + mNode.setRenderEffect(effect); + } + } + + @Override + public void endGraphicsLayer() { + mNode.endRecording(); + mCanvas = mPreviousCanvas; + mCanvas.drawRenderNode(mNode); + // node.discardDisplayList(); + mNode = null; + } + + @Override public void translate(float translateX, float translateY) { mCanvas.translate(translateX, translateY); } @@ -241,6 +292,8 @@ public class AndroidPaintContext extends PaintContext { if (start != 0) { textToPaint = textToPaint.substring(start); } + } else if (end > textToPaint.length()) { + textToPaint = textToPaint.substring(start); } else { textToPaint = textToPaint.substring(start, end); } diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPlatformServices.java b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPlatformServices.java index f9b22a25ceab..f28e85a44c1b 100644 --- a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPlatformServices.java +++ b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPlatformServices.java @@ -18,6 +18,7 @@ package com.android.internal.widget.remotecompose.player.platform; import android.graphics.Bitmap; import android.graphics.Path; import android.graphics.PathIterator; +import android.util.Log; import com.android.internal.widget.remotecompose.core.Platform; import com.android.internal.widget.remotecompose.core.operations.PathData; @@ -27,6 +28,8 @@ import java.util.Arrays; /** Services that are needed to be provided by the platform during encoding. */ public class AndroidPlatformServices implements Platform { + private static final String LOG_TAG = "RemoteCompose"; + @Override public byte[] imageToByteArray(Object image) { if (image instanceof Bitmap) { @@ -67,6 +70,24 @@ public class AndroidPlatformServices implements Platform { return null; } + @Override + public void log(LogCategory category, String message) { + switch (category) { + case DEBUG: + Log.d(LOG_TAG, message); + break; + case INFO: + Log.i(LOG_TAG, message); + break; + case WARN: + Log.w(LOG_TAG, message); + break; + default: + Log.e(LOG_TAG, message); + break; + } + } + private float[] androidPathToFloatArray(Path path) { PathIterator i = path.getPathIterator(); int estimatedSize = 0; diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java index e7c0cc8a915d..7a7edba160c8 100644 --- a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java +++ b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java @@ -20,6 +20,7 @@ import android.graphics.BitmapFactory; import android.graphics.Canvas; import com.android.internal.widget.remotecompose.core.RemoteContext; +import com.android.internal.widget.remotecompose.core.TouchListener; import com.android.internal.widget.remotecompose.core.VariableSupport; import com.android.internal.widget.remotecompose.core.operations.FloatExpression; import com.android.internal.widget.remotecompose.core.operations.ShaderData; @@ -143,9 +144,9 @@ class AndroidRemoteContext extends RemoteContext { } @Override - public void runNamedAction(int id) { + public void runNamedAction(int id, Object value) { String text = getText(id); - mDocument.runNamedAction(text); + mDocument.runNamedAction(text, value); } /** @@ -200,6 +201,11 @@ class AndroidRemoteContext extends RemoteContext { } @Override + public void overrideFloat(int id, float value) { + mRemoteComposeState.overrideFloat(id, value); + } + + @Override public void loadInteger(int id, int value) { mRemoteComposeState.updateInteger(id, value); } @@ -268,6 +274,11 @@ class AndroidRemoteContext extends RemoteContext { return (ShaderData) mRemoteComposeState.getFromId(id); } + @Override + public void addTouchListener(TouchListener touchExpression) { + mDocument.addTouchListener(touchExpression); + } + /////////////////////////////////////////////////////////////////////////////////////////////// // Click handling /////////////////////////////////////////////////////////////////////////////////////////////// @@ -285,4 +296,8 @@ class AndroidRemoteContext extends RemoteContext { String metadata = (String) mRemoteComposeState.getFromId(metadataId); mDocument.addClickArea(id, contentDescription, left, top, right, bottom, metadata); } + + public void hapticEffect(int type) { + mDocument.haptic(type); + } } diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java b/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java index 7de6988157b7..b54ed8a77ec5 100644 --- a/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java +++ b/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java @@ -21,6 +21,7 @@ import android.graphics.Color; import android.graphics.Point; import android.util.AttributeSet; import android.view.MotionEvent; +import android.view.VelocityTracker; import android.view.View; import android.widget.FrameLayout; @@ -38,7 +39,7 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta RemoteComposeDocument mDocument = null; int mTheme = Theme.LIGHT; boolean mInActionDown = false; - boolean mDebug = false; + int mDebug = 0; boolean mHasClickAreas = false; Point mActionDownPoint = new Point(0, 0); AndroidRemoteContext mARContext = new AndroidRemoteContext(); @@ -65,14 +66,14 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta } } - public void setDebug(boolean value) { + public void setDebug(int value) { if (mDebug != value) { mDebug = value; if (USE_VIEW_AREA_CLICK) { for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); if (child instanceof ClickAreaView) { - ((ClickAreaView) child).setDebug(mDebug); + ((ClickAreaView) child).setDebug(mDebug == 1); } } } @@ -107,7 +108,7 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta ClickAreaView viewArea = new ClickAreaView( getContext(), - mDebug, + mDebug == 1, area.getId(), area.getContentDescription(), area.getMetadata()); @@ -128,6 +129,10 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta } } + public void setHapticEngine(CoreDocument.HapticEngine engine) { + mDocument.getDocument().setHapticEngine(engine); + } + @Override public void onViewDetachedFromWindow(View view) { removeAllViews(); @@ -138,6 +143,16 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta } /** + * Gets a array of Names of the named variables of a specific type defined in the loaded doc. + * + * @param type the type of variable NamedVariable.COLOR_TYPE, STRING_TYPE, etc + * @return array of name or null + */ + public String[] getNamedVariables(int type) { + return mDocument.getNamedVariables(type); + } + + /** * set the color associated with this name. * * @param colorName Name of color typically "android.xxx" @@ -198,7 +213,12 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta this.mTheme = theme; } + private VelocityTracker mVelocityTracker = null; + public boolean onTouchEvent(MotionEvent event) { + int index = event.getActionIndex(); + int action = event.getActionMasked(); + int pointerId = event.getPointerId(index); if (USE_VIEW_AREA_CLICK && mHasClickAreas) { return super.onTouchEvent(event); } @@ -207,15 +227,51 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta mActionDownPoint.x = (int) event.getX(); mActionDownPoint.y = (int) event.getY(); mInActionDown = true; + CoreDocument doc = mDocument.getDocument(); + if (doc.hasTouchListener()) { + if (mVelocityTracker == null) { + mVelocityTracker = VelocityTracker.obtain(); + } else { + mVelocityTracker.clear(); + } + mVelocityTracker.addMovement(event); + doc.touchDown(mARContext, event.getX(), event.getY()); + } return true; + case MotionEvent.ACTION_CANCEL: mInActionDown = false; + doc = mDocument.getDocument(); + if (doc.hasTouchListener()) { + mVelocityTracker.computeCurrentVelocity(1000); + float dx = mVelocityTracker.getXVelocity(pointerId); + float dy = mVelocityTracker.getYVelocity(pointerId); + doc.touchCancel(mARContext, event.getX(), event.getY(), dx, dy); + } return true; case MotionEvent.ACTION_UP: mInActionDown = false; performClick(); + doc = mDocument.getDocument(); + if (doc.hasTouchListener()) { + mVelocityTracker.computeCurrentVelocity(1000); + float dx = mVelocityTracker.getXVelocity(pointerId); + float dy = mVelocityTracker.getYVelocity(pointerId); + doc.touchUp(mARContext, event.getX(), event.getY(), dx, dy); + } return true; + case MotionEvent.ACTION_MOVE: + if (mInActionDown) { + if (mVelocityTracker != null) { + mVelocityTracker.addMovement(event); + doc = mDocument.getDocument(); + boolean repaint = doc.touchDrag(mARContext, event.getX(), event.getY()); + if (repaint) { + invalidate(); + } + } + } } return false; } @@ -292,7 +348,7 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta mARContext.mWidth = getWidth(); mARContext.mHeight = getHeight(); mDocument.paint(mARContext, mTheme); - if (mDebug) { + if (mDebug == 1) { mCount++; if (System.nanoTime() - mTime > 1000000000L) { System.out.println(" count " + mCount + " fps"); diff --git a/core/res/res/values/stoppable_fgs_system_apps.xml b/core/res/res/values/stoppable_fgs_system_apps.xml new file mode 100644 index 000000000000..165ff61c7b3e --- /dev/null +++ b/core/res/res/values/stoppable_fgs_system_apps.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources> + <!-- A list of system apps whose FGS can be stopped in the task manager. --> + <string-array translatable="false" name="stoppable_fgs_system_apps"> + </string-array> + <!-- stoppable_fgs_system_apps which is supposed to be overridden by vendor --> + <string-array translatable="false" name="vendor_stoppable_fgs_system_apps"> + </string-array> +</resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index aa08d5e2313e..db81a3be440f 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1306,6 +1306,8 @@ <java-symbol type="array" name="vendor_policy_exempt_apps" /> <java-symbol type="array" name="cloneable_apps" /> <java-symbol type="array" name="config_securityStatePackages" /> + <java-symbol type="array" name="stoppable_fgs_system_apps" /> + <java-symbol type="array" name="vendor_stoppable_fgs_system_apps" /> <java-symbol type="drawable" name="default_wallpaper" /> <java-symbol type="drawable" name="default_lock_wallpaper" /> diff --git a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java index 31a4f16553a0..911b7ce22741 100644 --- a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java +++ b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java @@ -120,7 +120,8 @@ public class ClientTransactionListenerControllerTest { doReturn(newDisplayInfo).when(mIDisplayManager).getDisplayInfo(123); mDisplayManager.registerDisplayListener(mListener, mHandler, - DisplayManager.EVENT_FLAG_DISPLAY_CHANGED, null /* packageName */); + DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CHANGED, + null /* packageName */); mController.onDisplayChanged(123); mHandler.runWithScissors(() -> { }, 0); diff --git a/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java b/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java index 5a0dacb38865..9552c887443b 100644 --- a/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java +++ b/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java @@ -55,9 +55,10 @@ import org.mockito.MockitoAnnotations; @RunWith(AndroidJUnit4.class) public class DisplayManagerGlobalTest { - private static final long ALL_DISPLAY_EVENTS = DisplayManager.EVENT_FLAG_DISPLAY_ADDED - | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED - | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED; + private static final long ALL_DISPLAY_EVENTS = + DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED + | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CHANGED + | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REMOVED; @Mock private IDisplayManager mDisplayManager; @@ -127,19 +128,22 @@ public class DisplayManagerGlobalTest { int displayId = 1; mDisplayManagerGlobal.registerDisplayListener(mListener, mHandler, - ALL_DISPLAY_EVENTS & ~DisplayManager.EVENT_FLAG_DISPLAY_ADDED, null); + ALL_DISPLAY_EVENTS + & ~DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED, null); callback.onDisplayEvent(displayId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED); waitForHandler(); Mockito.verifyZeroInteractions(mListener); mDisplayManagerGlobal.registerDisplayListener(mListener, mHandler, - ALL_DISPLAY_EVENTS & ~DisplayManager.EVENT_FLAG_DISPLAY_CHANGED, null); + ALL_DISPLAY_EVENTS + & ~DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CHANGED, null); callback.onDisplayEvent(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED); waitForHandler(); Mockito.verifyZeroInteractions(mListener); mDisplayManagerGlobal.registerDisplayListener(mListener, mHandler, - ALL_DISPLAY_EVENTS & ~DisplayManager.EVENT_FLAG_DISPLAY_REMOVED, null); + ALL_DISPLAY_EVENTS + & ~DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REMOVED, null); callback.onDisplayEvent(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED); waitForHandler(); Mockito.verifyZeroInteractions(mListener); @@ -162,22 +166,25 @@ public class DisplayManagerGlobalTest { public void testDisplayManagerGlobalRegistersWithDisplayManager_WhenThereAreListeners() throws RemoteException { mDisplayManagerGlobal.registerDisplayListener(mListener, mHandler, - DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS, null); + DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_BRIGHTNESS_CHANGED, + null); InOrder inOrder = Mockito.inOrder(mDisplayManager); inOrder.verify(mDisplayManager) .registerCallbackWithEventMask(mCallbackCaptor.capture(), - eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS)); + eq(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_BRIGHTNESS_CHANGED)); mDisplayManagerGlobal.registerNativeChoreographerForRefreshRateCallbacks(); inOrder.verify(mDisplayManager) .registerCallbackWithEventMask(mCallbackCaptor.capture(), - eq(ALL_DISPLAY_EVENTS | DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS)); + eq(ALL_DISPLAY_EVENTS + | DisplayManagerGlobal + .INTERNAL_EVENT_FLAG_DISPLAY_BRIGHTNESS_CHANGED)); mDisplayManagerGlobal.unregisterNativeChoreographerForRefreshRateCallbacks(); inOrder.verify(mDisplayManager) .registerCallbackWithEventMask(mCallbackCaptor.capture(), - eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS)); + eq(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_BRIGHTNESS_CHANGED)); mDisplayManagerGlobal.unregisterDisplayListener(mListener); inOrder.verify(mDisplayManager) @@ -196,10 +203,12 @@ public class DisplayManagerGlobalTest { // One listener listens on add/remove, and the other one listens on change. mDisplayManagerGlobal.registerDisplayListener(mListener, mHandler, - DisplayManager.EVENT_FLAG_DISPLAY_ADDED - | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED, null /* packageName */); + DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED + | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REMOVED, + null /* packageName */); mDisplayManagerGlobal.registerDisplayListener(mListener2, mHandler, - DisplayManager.EVENT_FLAG_DISPLAY_CHANGED, null /* packageName */); + DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CHANGED, + null /* packageName */); mDisplayManagerGlobal.handleDisplayChangeFromWindowManager(321); waitForHandler(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java index b9a305062b46..c92a2786e49b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java @@ -21,6 +21,7 @@ import static android.view.RemoteAnimationTarget.MODE_CLOSING; import static android.view.RemoteAnimationTarget.MODE_OPENING; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CLOSE_PREPARE_BACK_NAVIGATION; +import static android.window.BackEvent.EDGE_NONE; import static android.window.TransitionInfo.FLAG_BACK_GESTURE_ANIMATED; import static android.window.TransitionInfo.FLAG_IS_WALLPAPER; import static android.window.TransitionInfo.FLAG_MOVED_TO_TOP; @@ -533,7 +534,15 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont if (keyAction == MotionEvent.ACTION_DOWN) { if (!mBackGestureStarted) { - mShouldStartOnNextMoveEvent = true; + if (swipeEdge == EDGE_NONE) { + // start animation immediately for non-gestural sources (without ACTION_MOVE + // events) + mThresholdCrossed = true; + onGestureStarted(touchX, touchY, swipeEdge); + mShouldStartOnNextMoveEvent = false; + } else { + mShouldStartOnNextMoveEvent = true; + } } } else if (keyAction == MotionEvent.ACTION_MOVE) { if (!mBackGestureStarted && mShouldStartOnNextMoveEvent) { @@ -1074,6 +1083,11 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont mCurrentTracker.updateStartLocation(); BackMotionEvent startEvent = mCurrentTracker.createStartEvent(mApps[0]); dispatchOnBackStarted(mActiveCallback, startEvent); + // TODO(b/373544911): onBackStarted is dispatched here so that + // WindowOnBackInvokedDispatcher knows about the back navigation and intercepts touch + // events while it's active. It would be cleaner and safer to disable multitouch + // altogether (same as in gesture-nav). + dispatchOnBackStarted(mBackNavigationInfo.getOnBackInvokedCallback(), startEvent); } } diff --git a/nfc/java/android/nfc/INfcAdapter.aidl b/nfc/java/android/nfc/INfcAdapter.aidl index 1346bd34e760..40fd0683f465 100644 --- a/nfc/java/android/nfc/INfcAdapter.aidl +++ b/nfc/java/android/nfc/INfcAdapter.aidl @@ -119,4 +119,5 @@ interface INfcAdapter boolean getSettingStatus(); boolean isTagPresent(); List<Entry> getRoutingTableEntryList(); + void indicateDataMigration(boolean inProgress, String pkg); } diff --git a/nfc/java/android/nfc/NfcAdapter.java b/nfc/java/android/nfc/NfcAdapter.java index d9fd42fd4f7a..c5d8191b22e6 100644 --- a/nfc/java/android/nfc/NfcAdapter.java +++ b/nfc/java/android/nfc/NfcAdapter.java @@ -2795,11 +2795,8 @@ public final class NfcAdapter { @IntRange(from = 0, to = 15) int gid, @IntRange(from = 0) int oid, @NonNull byte[] payload) { Objects.requireNonNull(payload, "Payload must not be null"); - try { - return sService.sendVendorNciMessage(mt, gid, oid, payload); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return callServiceReturn(() -> sService.sendVendorNciMessage(mt, gid, oid, payload), + SEND_VENDOR_NCI_STATUS_FAILED); } /** @@ -2873,6 +2870,18 @@ public final class NfcAdapter { } /** + * Used by data migration to indicate data migration is in progrerss or not. + * + * Note: This is @hide intentionally since the client is inside the NFC apex. + * @param inProgress true if migration is in progress, false once done. + * @hide + */ + @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) + public void indicateDataMigration(boolean inProgress) { + callService(() -> sService.indicateDataMigration(inProgress, mContext.getPackageName())); + } + + /** * Returns an instance of {@link NfcOemExtension} associated with {@link NfcAdapter} instance. * @hide */ diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java index 4f315a2a2486..76aa5bf3334c 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java @@ -75,6 +75,24 @@ public final class InputRouteManager { @Override public void onAudioDevicesAdded(@NonNull AudioDeviceInfo[] addedDevices) { applyDefaultSelectedTypeToAllPresets(); + + // Activate the last hot plugged valid input device, to match the output device + // behavior. + @AudioDeviceType int deviceTypeToActivate = mSelectedInputDeviceType; + for (AudioDeviceInfo info : addedDevices) { + if (InputMediaDevice.isSupportedInputDevice(info.getType())) { + deviceTypeToActivate = info.getType(); + } + } + + // Only activate if we find a different valid input device. e.g. if none of the + // addedDevices is supported input device, we don't need to activate anything. + if (mSelectedInputDeviceType != deviceTypeToActivate) { + mSelectedInputDeviceType = deviceTypeToActivate; + AudioDeviceAttributes deviceAttributes = + createInputDeviceAttributes(mSelectedInputDeviceType); + setPreferredDeviceForAllPresets(deviceAttributes); + } } @Override diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputRouteManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputRouteManagerTest.java index 782cee23fb42..d808a25ebc04 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputRouteManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputRouteManagerTest.java @@ -24,6 +24,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -138,6 +139,18 @@ public class InputRouteManagerTest { /* address= */ ""); } + private AudioDeviceAttributes getUsbHeadsetDeviceAttributes() { + return new AudioDeviceAttributes( + AudioDeviceAttributes.ROLE_INPUT, + AudioDeviceInfo.TYPE_USB_HEADSET, + /* address= */ ""); + } + + private AudioDeviceAttributes getHdmiDeviceAttributes() { + return new AudioDeviceAttributes( + AudioDeviceAttributes.ROLE_INPUT, AudioDeviceInfo.TYPE_HDMI, /* address= */ ""); + } + private void onPreferredDevicesForCapturePresetChanged(InputRouteManager inputRouteManager) { final List<AudioDeviceAttributes> audioDeviceAttributesList = new ArrayList<AudioDeviceAttributes>(); @@ -303,21 +316,47 @@ public class InputRouteManagerTest { } @Test - public void onAudioDevicesAdded_shouldApplyDefaultSelectedDeviceToAllPresets() { + public void onAudioDevicesAdded_shouldActivateAddedDevice() { final AudioManager audioManager = mock(AudioManager.class); - AudioDeviceAttributes wiredHeadsetDeviceAttributes = getWiredHeadsetDeviceAttributes(); - when(audioManager.getDevicesForAttributes(INPUT_ATTRIBUTES)) - .thenReturn(Collections.singletonList(wiredHeadsetDeviceAttributes)); - InputRouteManager inputRouteManager = new InputRouteManager(mContext, audioManager); AudioDeviceInfo[] devices = {mockWiredHeadsetInfo()}; inputRouteManager.mAudioDeviceCallback.onAudioDevicesAdded(devices); - // Called twice, one after initiation, the other after onAudioDevicesAdded call. - verify(audioManager, atLeast(2)).getDevicesForAttributes(INPUT_ATTRIBUTES); + // The only added wired headset will be activated. for (@MediaRecorder.Source int preset : PRESETS) { - verify(audioManager, atLeast(2)) - .setPreferredDeviceForCapturePreset(preset, wiredHeadsetDeviceAttributes); + verify(audioManager, atLeast(1)) + .setPreferredDeviceForCapturePreset(preset, getWiredHeadsetDeviceAttributes()); + } + } + + @Test + public void onAudioDevicesAdded_shouldActivateLastAddedDevice() { + final AudioManager audioManager = mock(AudioManager.class); + InputRouteManager inputRouteManager = new InputRouteManager(mContext, audioManager); + AudioDeviceInfo[] devices = {mockWiredHeadsetInfo(), mockUsbHeadsetInfo()}; + inputRouteManager.mAudioDeviceCallback.onAudioDevicesAdded(devices); + + // When adding multiple valid input devices, the last added device (usb headset in this + // case) will be activated. + for (@MediaRecorder.Source int preset : PRESETS) { + verify(audioManager, never()) + .setPreferredDeviceForCapturePreset(preset, getWiredHeadsetDeviceAttributes()); + verify(audioManager, atLeast(1)) + .setPreferredDeviceForCapturePreset(preset, getUsbHeadsetDeviceAttributes()); + } + } + + @Test + public void onAudioDevicesAdded_doNotActivateInvalidAddedDevice() { + final AudioManager audioManager = mock(AudioManager.class); + InputRouteManager inputRouteManager = new InputRouteManager(mContext, audioManager); + AudioDeviceInfo[] devices = {mockHdmiInfo()}; + inputRouteManager.mAudioDeviceCallback.onAudioDevicesAdded(devices); + + // Do not activate since HDMI is not a valid input device. + for (@MediaRecorder.Source int preset : PRESETS) { + verify(audioManager, never()) + .setPreferredDeviceForCapturePreset(preset, getHdmiDeviceAttributes()); } } diff --git a/packages/SystemUI/accessibility/accessibilitymenu/TEST_MAPPING b/packages/SystemUI/accessibility/accessibilitymenu/TEST_MAPPING index 1820f39bb180..1903d22c93cc 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/TEST_MAPPING +++ b/packages/SystemUI/accessibility/accessibilitymenu/TEST_MAPPING @@ -1,8 +1,7 @@ { - // TODO: b/324945360 - Re-enable on presubmit after fixing failures "postsubmit": [ { "name": "AccessibilityMenuServiceTests" } ] -}
\ No newline at end of file +} diff --git a/packages/SystemUI/aconfig/accessibility.aconfig b/packages/SystemUI/aconfig/accessibility.aconfig index 52512464cb30..b5eba08c8f87 100644 --- a/packages/SystemUI/aconfig/accessibility.aconfig +++ b/packages/SystemUI/aconfig/accessibility.aconfig @@ -118,3 +118,10 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "floating_menu_hearing_device_status_icon" + namespace: "accessibility" + description: "Update hearing device icon in floating menu according to the connection status." + bug: "357882387" +} diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig index 3bf3e24a2ba6..87ea2a7ab2ae 100644 --- a/packages/SystemUI/aconfig/systemui.aconfig +++ b/packages/SystemUI/aconfig/systemui.aconfig @@ -1743,3 +1743,13 @@ flag { description: "An implementation of shortcut customizations through shortcut helper." bug: "365064144" } + +flag { + name: "stoppable_fgs_system_app" + namespace: "systemui" + description: "System app with foreground service can opt in to be stoppable." + bug: "376564917" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryExt.kt b/packages/SystemUI/compose/features/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryExt.kt index e9b7335197b0..d58e1bfbda83 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryExt.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryExt.kt @@ -98,19 +98,20 @@ fun SystemUIDialogFactory.create( theme: Int = SystemUIDialog.DEFAULT_THEME, dismissOnDeviceLock: Boolean = SystemUIDialog.DEFAULT_DISMISS_ON_DEVICE_LOCK, @GravityInt dialogGravity: Int? = null, + dialogDelegate: DialogDelegate<SystemUIDialog> = + object : DialogDelegate<SystemUIDialog> { + override fun onCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) { + super.onCreate(dialog, savedInstanceState) + dialogGravity?.let { dialog.window?.setGravity(it) } + } + }, content: @Composable (SystemUIDialog) -> Unit, ): ComponentSystemUIDialog { return create( context = context, theme = theme, dismissOnDeviceLock = dismissOnDeviceLock, - delegate = - object : DialogDelegate<SystemUIDialog> { - override fun onCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) { - super.onCreate(dialog, savedInstanceState) - dialogGravity?.let { dialog.window?.setGravity(it) } - } - }, + delegate = dialogDelegate, content = content, ) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/data/repository/ScreenBrightnessDisplayManagerRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/data/repository/ScreenBrightnessDisplayManagerRepositoryTest.kt index 09831059a4b3..f4cffc5d962a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/data/repository/ScreenBrightnessDisplayManagerRepositoryTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/data/repository/ScreenBrightnessDisplayManagerRepositoryTest.kt @@ -20,7 +20,7 @@ import android.hardware.display.BrightnessInfo import android.hardware.display.BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE import android.hardware.display.BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF import android.hardware.display.DisplayManager -import android.hardware.display.DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS +import android.hardware.display.DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS import android.view.Display import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest @@ -119,7 +119,8 @@ class ScreenBrightnessDisplayManagerRepositoryTest : SysuiTestCase() { .registerDisplayListener( capture(listenerCaptor), eq(null), - eq(EVENT_FLAG_DISPLAY_BRIGHTNESS), + eq(0), + eq(PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS), ) val newBrightness = BrightnessInfo(0.6f, 0.3f, 0.9f) @@ -157,7 +158,8 @@ class ScreenBrightnessDisplayManagerRepositoryTest : SysuiTestCase() { .registerDisplayListener( capture(listenerCaptor), eq(null), - eq(EVENT_FLAG_DISPLAY_BRIGHTNESS), + eq(0), + eq(PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS), ) changeBrightnessInfoAndNotify( diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt index cd8b2e12a3d5..e6e5665e7694 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt @@ -540,7 +540,8 @@ class DisplayRepositoryTest : SysuiTestCase() { .registerDisplayListener( connectedDisplayListener.capture(), eq(testHandler), - eq(DisplayManager.EVENT_FLAG_DISPLAY_CONNECTION_CHANGED), + eq(0), + eq(DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED), ) return flowValue } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperDialogStarterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperDialogStarterTest.kt index d1431eecfc68..1580ea5c1272 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperDialogStarterTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperDialogStarterTest.kt @@ -22,6 +22,7 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.keyboard.shortcut.data.source.FakeKeyboardShortcutGroupsSource import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts +import com.android.systemui.keyboard.shortcut.shortcutCustomizationDialogStarterFactory import com.android.systemui.keyboard.shortcut.shortcutHelperAppCategoriesShortcutsSource import com.android.systemui.keyboard.shortcut.shortcutHelperCurrentAppShortcutsSource import com.android.systemui.keyboard.shortcut.shortcutHelperInputShortcutsSource @@ -71,7 +72,13 @@ class ShortcutHelperDialogStarterTest : SysuiTestCase() { private val starter: ShortcutHelperDialogStarter = with(kosmos) { - ShortcutHelperDialogStarter(coroutineScope, viewModel, dialogFactory, activityStarter) + ShortcutHelperDialogStarter( + coroutineScope, + viewModel, + shortcutCustomizationDialogStarterFactory, + dialogFactory, + activityStarter, + ) } @Before diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/FgsManagerControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/FgsManagerControllerTest.java index 16ae4662c2d4..0356422bda04 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/FgsManagerControllerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/FgsManagerControllerTest.java @@ -42,6 +42,7 @@ import android.content.pm.UserInfo; import android.os.Binder; import android.os.RemoteException; import android.os.UserHandle; +import android.platform.test.annotations.EnableFlags; import android.provider.DeviceConfig; import android.testing.TestableLooper; @@ -49,6 +50,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; +import com.android.systemui.Flags; import com.android.systemui.SysuiTestCase; import com.android.systemui.animation.DialogTransitionAnimator; import com.android.systemui.broadcast.BroadcastDispatcher; @@ -315,13 +317,36 @@ public class FgsManagerControllerTest extends SysuiTestCase { } @Test + @EnableFlags(Flags.FLAG_STOPPABLE_FGS_SYSTEM_APP) + public void testButtonVisibilityOfStoppableApps() throws Exception { + setUserProfiles(0); + setBackgroundRestrictionExemptionReason("pkg", 12345, REASON_ALLOWLISTED_PACKAGE); + setBackgroundRestrictionExemptionReason("vendor_pkg", 67890, REASON_ALLOWLISTED_PACKAGE); + + // Same as above, but apps are opt-in to be stoppable + setStoppableApps(new String[] {"pkg"}, /* vendor */ false); + setStoppableApps(new String[] {"vendor_pkg"}, /* vendor */ true); + + final Binder binder = new Binder(); + setShowStopButtonForUserAllowlistedApps(true); + // Both are foreground. + mIForegroundServiceObserver.onForegroundStateChanged(binder, "pkg", 0, true); + mIForegroundServiceObserver.onForegroundStateChanged(binder, "vendor_pkg", 0, true); + Assert.assertEquals(2, mFmc.visibleButtonsCount()); + + // The vendor package is no longer foreground. Only `pkg` remains. + mIForegroundServiceObserver.onForegroundStateChanged(binder, "vendor_pkg", 0, false); + Assert.assertEquals(1, mFmc.visibleButtonsCount()); + } + + @Test public void testShowUserVisibleJobsOnCreation() { // Test when the default is on. mDeviceConfigProxyFake.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, SystemUiDeviceConfigFlags.TASK_MANAGER_SHOW_USER_VISIBLE_JOBS, "true", false); FgsManagerController fmc = new FgsManagerControllerImpl( - mContext, + mContext.getResources(), mMainExecutor, mBackgroundExecutor, mSystemClock, @@ -348,7 +373,7 @@ public class FgsManagerControllerTest extends SysuiTestCase { SystemUiDeviceConfigFlags.TASK_MANAGER_SHOW_USER_VISIBLE_JOBS, "false", false); fmc = new FgsManagerControllerImpl( - mContext, + mContext.getResources(), mMainExecutor, mBackgroundExecutor, mSystemClock, @@ -446,6 +471,11 @@ public class FgsManagerControllerTest extends SysuiTestCase { .getBackgroundRestrictionExemptionReason(uid); } + private void setStoppableApps(String[] packageNames, boolean vendor) throws Exception { + overrideResource(vendor ? com.android.internal.R.array.vendor_stoppable_fgs_system_apps + : com.android.internal.R.array.stoppable_fgs_system_apps, packageNames); + } + FgsManagerController createFgsManagerController() throws RemoteException { ArgumentCaptor<IForegroundServiceObserver> iForegroundServiceObserverArgumentCaptor = ArgumentCaptor.forClass(IForegroundServiceObserver.class); @@ -455,7 +485,7 @@ public class FgsManagerControllerTest extends SysuiTestCase { ArgumentCaptor.forClass(BroadcastReceiver.class); FgsManagerController result = new FgsManagerControllerImpl( - mContext, + mContext.getResources(), mMainExecutor, mBackgroundExecutor, mSystemClock, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt index 740abf359e92..76390fddc529 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt @@ -18,12 +18,13 @@ package com.android.systemui.statusbar.notification.icon.ui.viewmodel import android.content.res.mainResources import android.platform.test.annotations.DisableFlags -import androidx.test.ext.junit.runners.AndroidJUnit4 +import android.platform.test.flag.junit.FlagsParameterization import androidx.test.filters.SmallTest import com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.flags.Flags +import com.android.systemui.flags.andSceneContainer import com.android.systemui.flags.fakeFeatureFlagsClassic import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository @@ -51,17 +52,20 @@ import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import platform.test.runner.parameterized.ParameterizedAndroidJunit4 +import platform.test.runner.parameterized.Parameters @OptIn(ExperimentalCoroutinesApi::class) @SmallTest -@RunWith(AndroidJUnit4::class) -class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() { +@RunWith(ParameterizedAndroidJunit4::class) +class NotificationIconContainerAlwaysOnDisplayViewModelTest(flags: FlagsParameterization) : + SysuiTestCase() { private val kosmos = testKosmos().apply { fakeFeatureFlagsClassic.apply { set(Flags.FULL_SCREEN_USER_SWITCHER, value = false) } } - val underTest = + val underTest by lazy { NotificationIconContainerAlwaysOnDisplayViewModel( kosmos.testDispatcher, kosmos.alwaysOnDisplayNotificationIconsInteractor, @@ -70,11 +74,24 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() { kosmos.mainResources, kosmos.shadeInteractor, ) + } val testScope = kosmos.testScope val keyguardRepository = kosmos.fakeKeyguardRepository val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository val powerRepository = kosmos.fakePowerRepository + companion object { + @JvmStatic + @Parameters(name = "{0}") + fun getParams(): List<FlagsParameterization> { + return FlagsParameterization.allCombinationsOf().andSceneContainer() + } + } + + init { + mSetFlagsRule.setFlagsParameterization(flags) + } + @Before fun setup() { keyguardRepository.setKeyguardShowing(true) diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 5a8417d7db9d..d30f73f6e2a1 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -3743,6 +3743,11 @@ is a component that shows the user which keyboard shortcuts they can use. [CHAR LIMIT=NONE] --> <string name="shortcut_helper_customize_mode_title">Customize keyboard shortcuts</string> + <!-- Sub title at the top of the keyboard shortcut helper customization dialog. Explains to the + user what action they need to take in the customization dialog to assign a new custom shortcut. + The helper is a component that shows the user which keyboard shortcuts they can use. + [CHAR LIMIT=NONE] --> + <string name="shortcut_helper_customize_mode_sub_title">Press key to assign shortcut</string> <!-- Placeholder text shown in the search box of the keyboard shortcut helper, when the user hasn't typed in anything in the search box yet. The helper is a component that shows the user which keyboard shortcuts they can use. [CHAR LIMIT=NONE] --> @@ -3754,6 +3759,16 @@ use. The helper shows shortcuts in categories, which can be collapsed or expanded. [CHAR LIMIT=NONE] --> <string name="shortcut_helper_content_description_collapse_icon">Collapse icon</string> + <!-- Content description of the Meta key (also called Action Key) icon that prompts users to + press some key combination starting with meta key to assign new key combination to shortcut + in shortcut helper customization dialog. The helper is a component that shows the user + which keyboard shortcuts they can use. [CHAR LIMIT=NONE] --> + <string name="shortcut_helper_content_description_meta_key">Action or Meta key icon</string> + <!-- Content description of the plus icon after the meta key icon prompts users to + press some key combination starting with meta key to assign new key combination to shortcut + in shortcut helper customization dialog. The helper is a component that shows the user + which keyboard shortcuts they can use. [CHAR LIMIT=NONE] --> + <string name="shortcut_helper_content_description_plus_icon">Plus icon</string> <!-- Description text of the button that allows user to customize shortcuts in keyboard shortcut helper The helper is a component that shows the user which keyboard shortcuts they can use. [CHAR LIMIT=NONE] --> @@ -3784,6 +3799,24 @@ open keyboard settings while in shortcut helper. The helper is a component that shows the user which keyboard shortcuts they can use. [CHAR LIMIT=NONE] --> <string name="shortcut_helper_keyboard_settings_buttons_label">Keyboard Settings</string> + <!-- Label on the set shortcut button in keyboard shortcut helper customize dialog, that allows user to + confirm and assign key combination to selected shortcut. The helper is a component that + shows the user which keyboard shortcuts they can use. [CHAR LIMIT=NONE] --> + <string name="shortcut_helper_customize_dialog_set_shortcut_button_label">Set shortcut</string> + <!-- Label on the cancel button in keyboard shortcut helper customize dialog, that allows user to + cancel and exit shortcut customization dialog, returning to the main shortcut helper page. + The helper is a component that shows the user which keyboard shortcuts they can use. + [CHAR LIMIT=NONE] --> + <string name="shortcut_helper_customize_dialog_cancel_button_label">Cancel</string> + <!-- Placeholder text, prompting user to Press key combination assign to shortcut. This is shown + in shortcut helper's "Add Custom Shortcut" Dialog text field when user hasn't pressed + any key yet. The helper is a component that shows the user which keyboard shortcuts + they can use. [CHAR LIMIT=NONE] --> + <string name="shortcut_helper_add_shortcut_dialog_placeholder">Press key</string> + <!-- Error message displayed when the user select a key combination that is already in use while + assigning a new custom key combination to a shortcut in shortcut helper. The helper is a + component that shows the user which keyboard shortcuts they can use. [CHAR LIMIT=NONE] --> + <string name="shortcut_helper_customize_dialog_error_message">Key combination already in use. Try another key.</string> <!-- Keyboard touchpad tutorial scheduler--> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl index 6209ed82a0ad..e332280bc31a 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl @@ -21,6 +21,7 @@ import android.graphics.Insets; import android.graphics.Rect; import android.os.Bundle; import android.os.UserHandle; +import android.view.KeyEvent; import android.view.MotionEvent; import com.android.internal.util.ScreenshotRequest; @@ -102,9 +103,9 @@ interface ISystemUiProxy { oneway void expandNotificationPanel() = 29; /** - * Notifies SystemUI to invoke Back. + * Notifies SystemUI of a back KeyEvent. */ - oneway void onBackPressed() = 44; + oneway void onBackEvent(in KeyEvent keyEvent) = 44; /** Sets home rotation enabled. */ oneway void setHomeRotationEnabled(boolean enabled) = 45; diff --git a/packages/SystemUI/src/com/android/systemui/brightness/data/repository/ScreenBrightnessRepository.kt b/packages/SystemUI/src/com/android/systemui/brightness/data/repository/ScreenBrightnessRepository.kt index 06d391704870..3270c71057b6 100644 --- a/packages/SystemUI/src/com/android/systemui/brightness/data/repository/ScreenBrightnessRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/brightness/data/repository/ScreenBrightnessRepository.kt @@ -19,6 +19,7 @@ package com.android.systemui.brightness.data.repository import android.annotation.SuppressLint import android.hardware.display.BrightnessInfo import android.hardware.display.DisplayManager +import com.android.app.tracing.coroutines.launchTraced as launch import com.android.systemui.brightness.shared.model.BrightnessLog import com.android.systemui.brightness.shared.model.LinearBrightness import com.android.systemui.brightness.shared.model.formatBrightness @@ -46,7 +47,6 @@ import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn -import com.android.app.tracing.coroutines.launchTraced as launch import kotlinx.coroutines.withContext /** @@ -90,10 +90,7 @@ constructor( @Background private val backgroundContext: CoroutineContext, ) : ScreenBrightnessRepository { - private val apiQueue = - Channel<SetBrightnessMethod>( - capacity = UNLIMITED, - ) + private val apiQueue = Channel<SetBrightnessMethod>(capacity = UNLIMITED) init { applicationScope.launch(context = backgroundContext) { @@ -132,7 +129,8 @@ constructor( displayManager.registerDisplayListener( listener, null, - DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS, + /* eventFlags */ 0, + DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS, ) awaitClose { displayManager.unregisterDisplayListener(listener) } @@ -190,8 +188,10 @@ constructor( private sealed interface SetBrightnessMethod { val value: LinearBrightness + @JvmInline value class Temporary(override val value: LinearBrightness) : SetBrightnessMethod + @JvmInline value class Permanent(override val value: LinearBrightness) : SetBrightnessMethod } @@ -201,7 +201,7 @@ constructor( LOG_BUFFER_BRIGHTNESS_CHANGE_TAG, if (permanent) LogLevel.DEBUG else LogLevel.VERBOSE, { str1 = value.formatBrightness() }, - { "Change requested: $str1" } + { "Change requested: $str1" }, ) } diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt index 034cb31dbc74..1fa829a675ec 100644 --- a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt @@ -264,7 +264,8 @@ constructor( displayManager.registerDisplayListener( callback, backgroundHandler, - DisplayManager.EVENT_FLAG_DISPLAY_CONNECTION_CHANGED, + /* eventFlags */ 0, + DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED, ) awaitClose { displayManager.unregisterDisplayListener(callback) } } diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutCustomizationInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutCustomizationInteractor.kt new file mode 100644 index 000000000000..85d22144f201 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutCustomizationInteractor.kt @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyboard.shortcut.domain.interactor + +import android.view.KeyEvent.META_META_ON +import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperKeys +import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey +import javax.inject.Inject + +class ShortcutCustomizationInteractor @Inject constructor() { + fun getDefaultCustomShortcutModifierKey(): ShortcutKey.Icon.ResIdIcon { + return ShortcutKey.Icon.ResIdIcon(ShortcutHelperKeys.keyIcons[META_META_ON]!!) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt new file mode 100644 index 000000000000..e4ccc2c553fa --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyboard.shortcut.shared.model + +data class ShortcutInfo( + val label: String, + val categoryType: ShortcutCategoryType, + val subCategoryLabel: String, +) diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogDelegate.kt new file mode 100644 index 000000000000..c98472ef7bda --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogDelegate.kt @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyboard.shortcut.ui + +import android.os.Bundle +import android.view.Gravity +import android.view.WindowManager +import com.android.systemui.statusbar.phone.DialogDelegate +import com.android.systemui.statusbar.phone.SystemUIDialog + +class ShortcutCustomizationDialogDelegate : DialogDelegate<SystemUIDialog> { + + override fun onCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) { + super.onCreate(dialog, savedInstanceState) + dialog.window?.apply { setGravity(Gravity.CENTER) } + } + + override fun getWidth(dialog: SystemUIDialog): Int { + return WindowManager.LayoutParams.WRAP_CONTENT + } + + override fun getHeight(dialog: SystemUIDialog): Int { + return WindowManager.LayoutParams.WRAP_CONTENT + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt new file mode 100644 index 000000000000..02e206e09bc7 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyboard.shortcut.ui + +import android.app.Dialog +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.android.systemui.keyboard.shortcut.shared.model.ShortcutInfo +import com.android.systemui.keyboard.shortcut.ui.composable.AssignNewShortcutDialog +import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiState +import com.android.systemui.keyboard.shortcut.ui.viewmodel.ShortcutCustomizationViewModel +import com.android.systemui.lifecycle.ExclusiveActivatable +import com.android.systemui.statusbar.phone.SystemUIDialogFactory +import com.android.systemui.statusbar.phone.create +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject + +class ShortcutCustomizationDialogStarter +@AssistedInject +constructor( + viewModelFactory: ShortcutCustomizationViewModel.Factory, + private val dialogFactory: SystemUIDialogFactory, +) : ExclusiveActivatable() { + + private var dialog: Dialog? = null + private val viewModel = viewModelFactory.create() + + override suspend fun onActivated(): Nothing { + viewModel.shortcutCustomizationUiState.collect { uiState -> + if ( + uiState is ShortcutCustomizationUiState.AddShortcutDialog && + !uiState.isDialogShowing + ) { + dialog = createAddShortcutDialog().also { it.show() } + viewModel.onAddShortcutDialogShown() + } else if (uiState is ShortcutCustomizationUiState.Inactive) { + dialog?.dismiss() + dialog = null + } + } + } + + fun onAddShortcutDialogRequested(shortcutBeingCustomized: ShortcutInfo) { + viewModel.onAddShortcutDialogRequested(shortcutBeingCustomized) + } + + private fun createAddShortcutDialog(): Dialog { + return dialogFactory.create(dialogDelegate = ShortcutCustomizationDialogDelegate()) { dialog + -> + val uiState by viewModel.shortcutCustomizationUiState.collectAsStateWithLifecycle() + AssignNewShortcutDialog( + uiState = uiState, + modifier = Modifier.width(364.dp).wrapContentHeight().padding(vertical = 24.dp), + onKeyPress = { viewModel.onKeyPressed(it) }, + onCancel = { dialog.dismiss() }, + ) + dialog.setOnDismissListener { viewModel.onAddShortcutDialogDismissed() } + } + } + + @AssistedFactory + interface Factory { + fun create(): ShortcutCustomizationDialogStarter + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperDialogStarter.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperDialogStarter.kt index d33ab2acc8fb..807c70bbc225 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperDialogStarter.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperDialogStarter.kt @@ -24,6 +24,7 @@ import android.os.UserHandle import android.provider.Settings import androidx.annotation.VisibleForTesting import androidx.compose.foundation.layout.width +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -47,15 +48,18 @@ class ShortcutHelperDialogStarter @Inject constructor( @Application private val applicationScope: CoroutineScope, - private val viewModel: ShortcutHelperViewModel, + private val shortcutHelperViewModel: ShortcutHelperViewModel, + shortcutCustomizationDialogStarterFactory: ShortcutCustomizationDialogStarter.Factory, private val dialogFactory: SystemUIDialogFactory, private val activityStarter: ActivityStarter, ) : CoreStartable { @VisibleForTesting var dialog: Dialog? = null + private val shortcutCustomizationDialogStarter = + shortcutCustomizationDialogStarterFactory.create() override fun start() { - viewModel.shouldShow + shortcutHelperViewModel.shouldShow .map { shouldShow -> if (shouldShow) { dialog = createShortcutHelperDialog().also { it.show() } @@ -69,16 +73,21 @@ constructor( private fun createShortcutHelperDialog(): Dialog { return dialogFactory.createBottomSheet( content = { dialog -> - val shortcutsUiState by viewModel.shortcutsUiState.collectAsStateWithLifecycle() + val shortcutsUiState by + shortcutHelperViewModel.shortcutsUiState.collectAsStateWithLifecycle() + LaunchedEffect(Unit) { shortcutCustomizationDialogStarter.activate() } ShortcutHelper( modifier = Modifier.width(getWidth()), shortcutsUiState = shortcutsUiState, onKeyboardSettingsClicked = { onKeyboardSettingsClicked(dialog) }, - onSearchQueryChanged = { viewModel.onSearchQueryChanged(it) }, + onSearchQueryChanged = { shortcutHelperViewModel.onSearchQueryChanged(it) }, + onCustomizationRequested = { + shortcutCustomizationDialogStarter.onAddShortcutDialogRequested(it) + }, ) - dialog.setOnDismissListener { viewModel.onViewClosed() } + dialog.setOnDismissListener { shortcutHelperViewModel.onViewClosed() } }, - maxWidth = ShortcutHelperBottomSheet.LargeScreenWidthLandscape + maxWidth = ShortcutHelperBottomSheet.LargeScreenWidthLandscape, ) } diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt new file mode 100644 index 000000000000..43f0f200ab23 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyboard.shortcut.ui.composable + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.interaction.collectIsFocusedAsState +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.sizeIn +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Add +import androidx.compose.material.icons.filled.ErrorOutline +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.key.KeyEvent +import androidx.compose.ui.input.key.onPreviewKeyEvent +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey +import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiState +import com.android.systemui.res.R + +@Composable +fun AssignNewShortcutDialog( + uiState: ShortcutCustomizationUiState, + modifier: Modifier = Modifier, + onKeyPress: (KeyEvent) -> Boolean, + onCancel: () -> Unit, +) { + if (uiState is ShortcutCustomizationUiState.AddShortcutDialog) { + Column(modifier = modifier) { + Title( + uiState.shortcutLabel, + modifier = Modifier.padding(horizontal = 24.dp).width(316.dp), + ) + Description( + modifier = Modifier.padding(top = 24.dp, start = 24.dp, end = 24.dp).width(316.dp) + ) + PromptShortcutModifier( + modifier = + Modifier.padding(top = 24.dp, start = 116.5.dp, end = 116.5.dp) + .width(131.dp) + .height(48.dp), + defaultModifierKey = uiState.defaultCustomShortcutModifierKey, + ) + SelectedKeyCombinationContainer( + shouldShowErrorMessage = uiState.shouldShowErrorMessage, + onKeyPress = onKeyPress, + ) + KeyCombinationAlreadyInUseErrorMessage(uiState.shouldShowErrorMessage) + DialogButtons(onCancel, isValidKeyCombination = uiState.isValidKeyCombination) + } + } +} + +@Composable +fun DialogButtons(onCancel: () -> Unit, isValidKeyCombination: Boolean) { + Row( + modifier = + Modifier.padding(top = 24.dp, start = 24.dp, end = 24.dp) + .sizeIn(minWidth = 316.dp, minHeight = 48.dp), + verticalAlignment = Alignment.Bottom, + horizontalArrangement = Arrangement.End, + ) { + ShortcutHelperButton( + shape = RoundedCornerShape(50.dp), + onClick = onCancel, + color = Color.Transparent, + width = 80.dp, + contentColor = MaterialTheme.colorScheme.primary, + text = stringResource(R.string.shortcut_helper_customize_dialog_cancel_button_label), + ) + Spacer(modifier = Modifier.width(8.dp)) + ShortcutHelperButton( + onClick = {}, + color = MaterialTheme.colorScheme.primary, + width = 116.dp, + contentColor = MaterialTheme.colorScheme.onPrimary, + text = + stringResource(R.string.shortcut_helper_customize_dialog_set_shortcut_button_label), + enabled = isValidKeyCombination, + ) + } +} + +@Composable +fun KeyCombinationAlreadyInUseErrorMessage(shouldShowErrorMessage: Boolean) { + if (shouldShowErrorMessage) { + Box(modifier = Modifier.padding(horizontal = 16.dp).width(332.dp).height(40.dp)) { + Text( + text = stringResource(R.string.shortcut_helper_customize_dialog_error_message), + style = MaterialTheme.typography.bodyMedium, + fontSize = 14.sp, + lineHeight = 20.sp, + fontWeight = FontWeight.W500, + color = MaterialTheme.colorScheme.error, + modifier = Modifier.padding(start = 24.dp).width(252.dp), + ) + } + } +} + +@Composable +fun SelectedKeyCombinationContainer( + keyCombination: String = + stringResource(R.string.shortcut_helper_add_shortcut_dialog_placeholder), + shouldShowErrorMessage: Boolean, + onKeyPress: (KeyEvent) -> Boolean, +) { + val interactionSource = remember { MutableInteractionSource() } + val isFocused by interactionSource.collectIsFocusedAsState() + val outlineColor = + if (!isFocused) MaterialTheme.colorScheme.outline + else if (shouldShowErrorMessage) MaterialTheme.colorScheme.error + else MaterialTheme.colorScheme.primary + + ClickableShortcutSurface( + onClick = {}, + color = Color.Transparent, + shape = RoundedCornerShape(50.dp), + modifier = + Modifier.padding(all = 16.dp) + .sizeIn(minWidth = 332.dp, minHeight = 56.dp) + .border(width = 2.dp, color = outlineColor, shape = RoundedCornerShape(50.dp)) + .onPreviewKeyEvent { onKeyPress(it) }, + interactionSource = interactionSource, + ) { + Row( + modifier = Modifier.padding(start = 24.dp, top = 16.dp, end = 16.dp, bottom = 16.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + text = keyCombination, + style = MaterialTheme.typography.headlineSmall, + fontSize = 16.sp, + lineHeight = 24.sp, + fontWeight = FontWeight.W500, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.width(252.dp), + ) + Spacer(modifier = Modifier.weight(1f)) + if (shouldShowErrorMessage) { + Icon( + imageVector = Icons.Default.ErrorOutline, + contentDescription = null, + modifier = Modifier.size(20.dp), + tint = MaterialTheme.colorScheme.error, + ) + } + } + } +} + +@Composable +private fun Title(title: String, modifier: Modifier = Modifier) { + Text( + text = title, + style = MaterialTheme.typography.headlineSmall, + fontSize = 24.sp, + modifier = modifier.wrapContentSize(Alignment.Center), + color = MaterialTheme.colorScheme.onSurface, + lineHeight = 32.sp, + ) +} + +@Composable +private fun Description(modifier: Modifier = Modifier) { + Text( + text = stringResource(id = R.string.shortcut_helper_customize_mode_sub_title), + style = MaterialTheme.typography.bodyMedium, + fontSize = 14.sp, + lineHeight = 20.sp, + modifier = modifier.wrapContentSize(Alignment.Center), + color = MaterialTheme.colorScheme.onSurfaceVariant, + ) +} + +@Composable +private fun PromptShortcutModifier( + modifier: Modifier, + defaultModifierKey: ShortcutKey.Icon.ResIdIcon, +) { + Row(modifier = modifier, horizontalArrangement = Arrangement.spacedBy(2.dp)) { + ActionKeyContainer(defaultModifierKey) + PlusIconContainer() + } +} + +@Composable +private fun ActionKeyContainer(defaultModifierKey: ShortcutKey.Icon.ResIdIcon) { + Row( + modifier = + Modifier.height(48.dp) + .width(105.dp) + .background( + color = MaterialTheme.colorScheme.surface, + shape = RoundedCornerShape(16.dp), + ) + .padding(all = 12.dp), + horizontalArrangement = Arrangement.spacedBy(8.dp), + ) { + ActionKeyIcon(defaultModifierKey) + ActionKeyText() + } +} + +@Composable +fun ActionKeyText() { + Text( + text = "Action", + style = MaterialTheme.typography.titleMedium, + fontSize = 16.sp, + lineHeight = 24.sp, + modifier = Modifier.wrapContentSize(Alignment.Center), + color = MaterialTheme.colorScheme.onSurface, + ) +} + +@Composable +private fun ActionKeyIcon(defaultModifierKey: ShortcutKey.Icon.ResIdIcon) { + Icon( + painter = painterResource(id = defaultModifierKey.drawableResId), + contentDescription = stringResource(R.string.shortcut_helper_content_description_meta_key), + modifier = Modifier.size(24.dp).wrapContentSize(Alignment.Center), + ) +} + +@Composable +private fun PlusIconContainer() { + Icon( + tint = MaterialTheme.colorScheme.onSurface, + imageVector = Icons.Default.Add, + contentDescription = + stringResource(id = R.string.shortcut_helper_content_description_plus_icon), + modifier = Modifier.padding(vertical = 12.dp).size(24.dp).wrapContentSize(Alignment.Center), + ) +} diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt index abddc7059ece..13934ea38233 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt @@ -110,6 +110,7 @@ import com.android.systemui.keyboard.shortcut.shared.model.Shortcut as ShortcutM import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCommand import com.android.systemui.keyboard.shortcut.shared.model.ShortcutIcon +import com.android.systemui.keyboard.shortcut.shared.model.ShortcutInfo import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey import com.android.systemui.keyboard.shortcut.shared.model.ShortcutSubCategory import com.android.systemui.keyboard.shortcut.ui.model.IconSource @@ -124,6 +125,7 @@ fun ShortcutHelper( modifier: Modifier = Modifier, shortcutsUiState: ShortcutsUiState, useSinglePane: @Composable () -> Boolean = { shouldUseSinglePane() }, + onCustomizationRequested: (ShortcutInfo) -> Unit = {}, ) { when (shortcutsUiState) { is ShortcutsUiState.Active -> { @@ -133,6 +135,7 @@ fun ShortcutHelper( onSearchQueryChanged, modifier, onKeyboardSettingsClicked, + onCustomizationRequested, ) } else -> { @@ -148,6 +151,7 @@ private fun ActiveShortcutHelper( onSearchQueryChanged: (String) -> Unit, modifier: Modifier, onKeyboardSettingsClicked: () -> Unit, + onCustomizationRequested: (ShortcutInfo) -> Unit = {}, ) { var selectedCategoryType by remember(shortcutsUiState.defaultSelectedCategory) { @@ -173,6 +177,7 @@ private fun ActiveShortcutHelper( onCategorySelected = { selectedCategoryType = it }, onKeyboardSettingsClicked, shortcutsUiState.isShortcutCustomizerFlagEnabled, + onCustomizationRequested, ) } } @@ -362,6 +367,7 @@ private fun ShortcutHelperTwoPane( onCategorySelected: (ShortcutCategoryType?) -> Unit, onKeyboardSettingsClicked: () -> Unit, isShortcutCustomizerFlagEnabled: Boolean, + onCustomizationRequested: (ShortcutInfo) -> Unit = {}, ) { val selectedCategory = categories.fastFirstOrNull { it.type == selectedCategoryType } var isCustomizeModeEntered by remember { mutableStateOf(false) } @@ -400,6 +406,7 @@ private fun ShortcutHelperTwoPane( Modifier.fillMaxSize().padding(top = 8.dp), selectedCategory, isCustomizing = isCustomizing, + onCustomizationRequested = onCustomizationRequested, ) } } @@ -434,6 +441,7 @@ private fun EndSidePanel( modifier: Modifier, category: ShortcutCategoryUi?, isCustomizing: Boolean, + onCustomizationRequested: (ShortcutInfo) -> Unit = {}, ) { val listState = rememberLazyListState() LaunchedEffect(key1 = category) { if (category != null) listState.animateScrollToItem(0) } @@ -447,6 +455,15 @@ private fun EndSidePanel( searchQuery = searchQuery, subCategory = subcategory, isCustomizing = isCustomizing, + onCustomizationRequested = { label, subCategoryLabel -> + onCustomizationRequested( + ShortcutInfo( + label = label, + subCategoryLabel = subCategoryLabel, + categoryType = category.type, + ) + ) + }, ) Spacer(modifier = Modifier.height(8.dp)) } @@ -476,6 +493,7 @@ private fun SubCategoryContainerDualPane( searchQuery: String, subCategory: ShortcutSubCategory, isCustomizing: Boolean, + onCustomizationRequested: (String, String) -> Unit = { _: String, _: String -> }, ) { Surface( modifier = Modifier.fillMaxWidth(), @@ -497,6 +515,7 @@ private fun SubCategoryContainerDualPane( searchQuery = searchQuery, shortcut = shortcut, isCustomizing = isCustomizing, + onCustomizationRequested = { onCustomizationRequested(it, subCategory.label) }, ) } } @@ -518,6 +537,7 @@ private fun Shortcut( searchQuery: String, shortcut: ShortcutModel, isCustomizing: Boolean = false, + onCustomizationRequested: (String) -> Unit = {}, ) { val interactionSource = remember { MutableInteractionSource() } val isFocused by interactionSource.collectIsFocusedAsState() @@ -541,7 +561,12 @@ private fun Shortcut( ShortcutDescriptionText(searchQuery = searchQuery, shortcut = shortcut) } Spacer(modifier = Modifier.width(24.dp)) - ShortcutKeyCombinations(modifier = Modifier.weight(1f), shortcut = shortcut, isCustomizing) + ShortcutKeyCombinations( + modifier = Modifier.weight(1f), + shortcut = shortcut, + isCustomizing = isCustomizing, + onAddShortcutClicked = { onCustomizationRequested(shortcut.label) }, + ) } } @@ -569,6 +594,7 @@ private fun ShortcutKeyCombinations( modifier: Modifier = Modifier, shortcut: ShortcutModel, isCustomizing: Boolean = false, + onAddShortcutClicked: () -> Unit = {}, ) { FlowRow( modifier = modifier, @@ -590,7 +616,7 @@ private fun ShortcutKeyCombinations( color = MaterialTheme.colorScheme.outline, shape = CircleShape, ), - onClick = {}, + onClick = { onAddShortcutClicked() }, color = Color.Transparent, width = 32.dp, height = 32.dp, diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt index 435968ee79ca..e761c7313ff3 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt @@ -44,6 +44,7 @@ import androidx.compose.material3.LocalAbsoluteTonalElevation import androidx.compose.material3.LocalContentColor import androidx.compose.material3.LocalTonalElevationEnabled import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.contentColorFor import androidx.compose.material3.minimumInteractiveComponentSize @@ -283,6 +284,108 @@ fun ShortcutHelperButton( } @Composable +fun ShortcutHelperButton( + modifier: Modifier = Modifier, + onClick: () -> Unit, + shape: Shape = RoundedCornerShape(360.dp), + color: Color, + width: Dp, + height: Dp = 40.dp, + iconSource: IconSource = IconSource(), + text: String? = null, + contentColor: Color, + contentPaddingHorizontal: Dp = 16.dp, + contentPaddingVertical: Dp = 10.dp, + enabled: Boolean = true, +) { + ShortcutHelperButtonSurface( + onClick = onClick, + shape = shape, + color = color, + modifier = modifier, + enabled = enabled, + width = width, + height = height, + ) { + Row( + modifier = + Modifier.padding( + horizontal = contentPaddingHorizontal, + vertical = contentPaddingVertical, + ), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center, + ) { + if (iconSource.imageVector != null) { + Icon( + tint = contentColor, + imageVector = iconSource.imageVector, + contentDescription = + null, // TODO this probably should not be null for accessibility. + modifier = Modifier.size(20.dp).wrapContentSize(Alignment.Center), + ) + } + + if (iconSource.imageVector != null && text != null) + Spacer(modifier = Modifier.weight(1f)) + + if (text != null) { + Text( + text, + color = contentColor, + fontSize = 14.sp, + style = MaterialTheme.typography.labelLarge, + modifier = Modifier.wrapContentSize(Alignment.Center), + ) + } + } + } +} + +@Composable +fun ShortcutHelperButtonSurface( + onClick: () -> Unit, + shape: Shape, + color: Color, + modifier: Modifier = Modifier, + enabled: Boolean, + width: Dp, + height: Dp, + content: @Composable () -> Unit, +) { + if (enabled) { + ClickableShortcutSurface( + onClick = onClick, + shape = shape, + color = color, + modifier = modifier.semantics { role = Role.Button }.width(width).height(height), + interactionsConfig = + InteractionsConfig( + hoverOverlayColor = MaterialTheme.colorScheme.onSurface, + hoverOverlayAlpha = 0.11f, + pressedOverlayColor = MaterialTheme.colorScheme.onSurface, + pressedOverlayAlpha = 0.15f, + focusOutlineColor = MaterialTheme.colorScheme.secondary, + focusOutlineStrokeWidth = 3.dp, + focusOutlinePadding = 2.dp, + surfaceCornerRadius = 28.dp, + focusOutlineCornerRadius = 33.dp, + ), + ) { + content() + } + } else { + Surface( + shape = shape, + color = color.copy(0.38f), + modifier = modifier.semantics { role = Role.Button }.width(width).height(height), + ) { + content() + } + } +} + +@Composable private fun surfaceColorAtElevation(color: Color, elevation: Dp): Color { return MaterialTheme.colorScheme.applyTonalElevation(color, elevation) } diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCustomizationUiState.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCustomizationUiState.kt new file mode 100644 index 000000000000..e9f2a3b8e5b3 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCustomizationUiState.kt @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyboard.shortcut.ui.model + +import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey + +sealed interface ShortcutCustomizationUiState { + data class AddShortcutDialog( + val shortcutLabel: String, + val shouldShowErrorMessage: Boolean, + val isValidKeyCombination: Boolean, + val defaultCustomShortcutModifierKey: ShortcutKey.Icon.ResIdIcon, + val isDialogShowing: Boolean, + ) : ShortcutCustomizationUiState + + data object Inactive : ShortcutCustomizationUiState +} diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt new file mode 100644 index 000000000000..b9253878ba0d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyboard.shortcut.ui.viewmodel + +import androidx.compose.runtime.mutableStateOf +import androidx.compose.ui.input.key.KeyEvent +import com.android.systemui.keyboard.shortcut.domain.interactor.ShortcutCustomizationInteractor +import com.android.systemui.keyboard.shortcut.shared.model.ShortcutInfo +import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiState +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update + +class ShortcutCustomizationViewModel +@AssistedInject +constructor(private val shortcutCustomizationInteractor: ShortcutCustomizationInteractor) { + private val _shortcutBeingCustomized = mutableStateOf<ShortcutInfo?>(null) + + private val _shortcutCustomizationUiState = + MutableStateFlow<ShortcutCustomizationUiState>(ShortcutCustomizationUiState.Inactive) + + val shortcutCustomizationUiState = _shortcutCustomizationUiState.asStateFlow() + + fun onAddShortcutDialogRequested(shortcutBeingCustomized: ShortcutInfo) { + _shortcutCustomizationUiState.value = + ShortcutCustomizationUiState.AddShortcutDialog( + shortcutLabel = shortcutBeingCustomized.label, + shouldShowErrorMessage = false, + isValidKeyCombination = false, + defaultCustomShortcutModifierKey = + shortcutCustomizationInteractor.getDefaultCustomShortcutModifierKey(), + isDialogShowing = false, + ) + + _shortcutBeingCustomized.value = shortcutBeingCustomized + } + + fun onAddShortcutDialogShown() { + _shortcutCustomizationUiState.update { uiState -> + (uiState as? ShortcutCustomizationUiState.AddShortcutDialog) + ?.let { it.copy(isDialogShowing = true) } + ?: uiState + } + } + + fun onAddShortcutDialogDismissed() { + _shortcutBeingCustomized.value = null + _shortcutCustomizationUiState.value = ShortcutCustomizationUiState.Inactive + } + + fun onKeyPressed(keyEvent: KeyEvent): Boolean { + // TODO Not yet implemented b/373638584 + return false + } + + @AssistedFactory + interface Factory { + fun create(): ShortcutCustomizationViewModel + } +} diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java index 53177de89733..f49693a8700b 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java @@ -1191,11 +1191,13 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack } private void pilferPointers() { - // Capture inputs - mInputMonitor.pilferPointers(); - // Notify FalsingManager that an intentional gesture has occurred. - mFalsingManager.isFalseTouch(BACK_GESTURE); - mInputEventReceiver.setBatchingEnabled(true); + if (mInputMonitor != null) { + // Capture inputs + mInputMonitor.pilferPointers(); + // Notify FalsingManager that an intentional gesture has occurred. + mFalsingManager.isFalseTouch(BACK_GESTURE); + mInputEventReceiver.setBatchingEnabled(true); + } } private boolean isButtonPressFromTrackpad(MotionEvent ev) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt index a1071907cd3d..2a5ffc6cc391 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt @@ -27,6 +27,7 @@ import android.content.Intent import android.content.IntentFilter import android.content.pm.PackageManager import android.content.pm.UserInfo +import android.content.res.Resources import android.graphics.drawable.Drawable import android.os.IBinder import android.os.PowerExemptionManager @@ -54,6 +55,7 @@ import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.TASK_MANAGER_ import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.TASK_MANAGER_SHOW_USER_VISIBLE_JOBS import com.android.internal.jank.InteractionJankMonitor import com.android.systemui.Dumpable +import com.android.systemui.Flags; import com.android.systemui.res.R import com.android.systemui.animation.DialogCuj import com.android.systemui.animation.DialogTransitionAnimator @@ -137,7 +139,7 @@ interface FgsManagerController { @SysUISingleton class FgsManagerControllerImpl @Inject constructor( - private val context: Context, + @Main private val resources: Resources, @Main private val mainExecutor: Executor, @Background private val backgroundExecutor: Executor, private val systemClock: SystemClock, @@ -223,6 +225,14 @@ class FgsManagerControllerImpl @Inject constructor( private val userVisibleJobObserver = UserVisibleJobObserver() + private val stoppableApps by lazy { resources + .getStringArray(com.android.internal.R.array.stoppable_fgs_system_apps) + } + + private val vendorStoppableApps by lazy { resources + .getStringArray(com.android.internal.R.array.vendor_stoppable_fgs_system_apps) + } + override fun init() { synchronized(lock) { if (initialized) { @@ -725,9 +735,22 @@ class FgsManagerControllerImpl @Inject constructor( } else -> UIControl.NORMAL } + // If the app wants to be a good citizen by being stoppable, even if the category it + // belongs to is exempted for background restriction, let it be stoppable by user. + if (Flags.stoppableFgsSystemApp()) { + if (isStoppableApp(packageName)) { + uiControl = UIControl.NORMAL + } + } + uiControlInitialized = true } + fun isStoppableApp(packageName: String): Boolean { + return stoppableApps.contains(packageName) || + vendorStoppableApps.contains(packageName) + } + override fun equals(other: Any?): Boolean { if (other !is UserPackage) { return false diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index ce9c441654bf..a5eb92b10239 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -24,7 +24,10 @@ import static android.view.MotionEvent.ACTION_CANCEL; import static android.view.MotionEvent.ACTION_DOWN; import static android.view.MotionEvent.ACTION_UP; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; +import static android.window.BackEvent.EDGE_NONE; +import static com.android.window.flags.Flags.predictiveBackSwipeEdgeNoneApi; +import static com.android.window.flags.Flags.predictiveBackThreeButtonNav; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNFOLD_ANIMATION_FORWARDER; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER; @@ -41,6 +44,7 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_V import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_WAKEFULNESS_TRANSITION; import android.annotation.FloatRange; +import android.annotation.Nullable; import android.app.ActivityTaskManager; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -114,6 +118,7 @@ import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.phone.StatusBarWindowCallback; import com.android.systemui.statusbar.policy.CallbackController; import com.android.systemui.unfold.progress.UnfoldTransitionProgressForwarder; +import com.android.wm.shell.back.BackAnimation; import com.android.wm.shell.shared.desktopmode.DesktopModeStatus; import com.android.wm.shell.sysui.ShellInterface; @@ -174,6 +179,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis private Region mActiveNavBarRegion; private final BroadcastDispatcher mBroadcastDispatcher; + private final BackAnimation mBackAnimation; private IOverviewProxy mOverviewProxy; private int mConnectionBackoffAttempts; @@ -287,11 +293,18 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis } @Override - public void onBackPressed() { - verifyCallerAndClearCallingIdentityPostMain("onBackPressed", () -> { - sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK); - sendEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK); - }); + public void onBackEvent(@Nullable KeyEvent keyEvent) throws RemoteException { + if (predictiveBackThreeButtonNav() && predictiveBackSwipeEdgeNoneApi() + && mBackAnimation != null && keyEvent != null) { + mBackAnimation.setTriggerBack(!keyEvent.isCanceled()); + mBackAnimation.onBackMotion(/* touchX */ 0, /* touchY */ 0, keyEvent.getAction(), + EDGE_NONE); + } else { + verifyCallerAndClearCallingIdentityPostMain("onBackPressed", () -> { + sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK); + sendEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK); + }); + } } @Override @@ -657,7 +670,8 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis AssistUtils assistUtils, DumpManager dumpManager, Optional<UnfoldTransitionProgressForwarder> unfoldTransitionProgressForwarder, - BroadcastDispatcher broadcastDispatcher + BroadcastDispatcher broadcastDispatcher, + Optional<BackAnimation> backAnimation ) { // b/241601880: This component should only be running for primary users or // secondaryUsers when visibleBackgroundUsers are supported. @@ -695,6 +709,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis mDisplayTracker = displayTracker; mUnfoldTransitionProgressForwarder = unfoldTransitionProgressForwarder; mBroadcastDispatcher = broadcastDispatcher; + mBackAnimation = backAnimation.orElse(null); if (!KeyguardWmStateRefactor.isEnabled()) { mSysuiUnlockAnimationController = sysuiUnlockAnimationController; diff --git a/packages/SystemUI/src/com/android/systemui/settings/DisplayTrackerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/DisplayTrackerImpl.kt index 2ef27a8df117..60ed2de5c532 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/DisplayTrackerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/settings/DisplayTrackerImpl.kt @@ -17,7 +17,7 @@ package com.android.systemui.settings import android.hardware.display.DisplayManager -import android.hardware.display.DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS +import android.hardware.display.DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS import android.os.Handler import android.view.Display import androidx.annotation.GuardedBy @@ -32,7 +32,7 @@ import java.util.concurrent.Executor class DisplayTrackerImpl internal constructor( val displayManager: DisplayManager, - @Background val backgroundHandler: Handler + @Background val backgroundHandler: Handler, ) : DisplayTracker { override val defaultDisplayId: Int = Display.DEFAULT_DISPLAY override val allDisplays: Array<Display> @@ -47,27 +47,21 @@ internal constructor( val displayChangedListener: DisplayManager.DisplayListener = object : DisplayManager.DisplayListener { override fun onDisplayAdded(displayId: Int) { - traceSection( - "DisplayTrackerImpl.displayChangedDisplayListener#onDisplayAdded", - ) { + traceSection("DisplayTrackerImpl.displayChangedDisplayListener#onDisplayAdded") { val list = synchronized(displayCallbacks) { displayCallbacks.toList() } onDisplayAdded(displayId, list) } } override fun onDisplayRemoved(displayId: Int) { - traceSection( - "DisplayTrackerImpl.displayChangedDisplayListener#onDisplayRemoved", - ) { + traceSection("DisplayTrackerImpl.displayChangedDisplayListener#onDisplayRemoved") { val list = synchronized(displayCallbacks) { displayCallbacks.toList() } onDisplayRemoved(displayId, list) } } override fun onDisplayChanged(displayId: Int) { - traceSection( - "DisplayTrackerImpl.displayChangedDisplayListener#onDisplayChanged", - ) { + traceSection("DisplayTrackerImpl.displayChangedDisplayListener#onDisplayChanged") { val list = synchronized(displayCallbacks) { displayCallbacks.toList() } onDisplayChanged(displayId, list) } @@ -83,7 +77,7 @@ internal constructor( override fun onDisplayChanged(displayId: Int) { traceSection( - "DisplayTrackerImpl.displayBrightnessChangedDisplayListener#onDisplayChanged", + "DisplayTrackerImpl.displayBrightnessChangedDisplayListener#onDisplayChanged" ) { val list = synchronized(brightnessCallbacks) { brightnessCallbacks.toList() } onDisplayChanged(displayId, list) @@ -102,14 +96,15 @@ internal constructor( override fun addBrightnessChangeCallback( callback: DisplayTracker.Callback, - executor: Executor + executor: Executor, ) { synchronized(brightnessCallbacks) { if (brightnessCallbacks.isEmpty()) { displayManager.registerDisplayListener( displayBrightnessChangedListener, backgroundHandler, - EVENT_FLAG_DISPLAY_BRIGHTNESS + /* eventFlags */ 0, + PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS, ) } brightnessCallbacks.add(DisplayTrackerDataItem(WeakReference(callback), executor)) @@ -159,7 +154,7 @@ internal constructor( private inline fun notifySubscribers( crossinline action: DisplayTracker.Callback.() -> Unit, - list: List<DisplayTrackerDataItem> + list: List<DisplayTrackerDataItem>, ) { list.forEach { if (it.callback.get() != null) { @@ -170,7 +165,7 @@ internal constructor( private data class DisplayTrackerDataItem( val callback: WeakReference<DisplayTracker.Callback>, - val executor: Executor + val executor: Executor, ) { fun sameOrEmpty(other: DisplayTracker.Callback): Boolean { return callback.get()?.equals(other) ?: true diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index 3d9eb53d436a..a39ca5de787d 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -103,6 +103,7 @@ import android.os.PowerManager; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; +import android.platform.test.annotations.EnableFlags; import android.platform.test.flag.junit.FlagsParameterization; import android.service.dreams.IDreamManager; import android.service.trust.TrustAgentService; @@ -129,6 +130,7 @@ import com.android.keyguard.KeyguardUpdateMonitor.BiometricAuthenticated; import com.android.keyguard.logging.KeyguardUpdateMonitorLogger; import com.android.keyguard.logging.SimLogger; import com.android.settingslib.fuelgauge.BatteryStatus; +import com.android.systemui.Flags; import com.android.systemui.SysuiTestCase; import com.android.systemui.biometrics.AuthController; import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider; @@ -190,6 +192,7 @@ import platform.test.runner.parameterized.Parameters; @SmallTest @RunWith(ParameterizedAndroidJunit4.class) @TestableLooper.RunWithLooper +@EnableFlags(Flags.FLAG_USER_ENCRYPTED_SOURCE) public class KeyguardUpdateMonitorTest extends SysuiTestCase { private static final String PKG_ALLOWING_FP_LISTEN_ON_OCCLUDING_ACTIVITY = "test_app_fp_listen_on_occluding_activity"; @@ -1292,12 +1295,15 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { @Test public void testIsUserUnlocked() { + when(mUserManager.isUserUnlocked(mSelectedUserInteractor.getSelectedUserId())).thenReturn( + true); // mUserManager will report the user as unlocked on @Before assertThat( mKeyguardUpdateMonitor.isUserUnlocked(mSelectedUserInteractor.getSelectedUserId())) .isTrue(); // Invalid user should not be unlocked. int randomUser = 99; + when(mUserManager.isUserUnlocked(randomUser)).thenReturn(false); assertThat(mKeyguardUpdateMonitor.isUserUnlocked(randomUser)).isFalse(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt index 3bfde68def50..909680866d20 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt @@ -59,6 +59,7 @@ import com.android.systemui.unfold.progress.UnfoldTransitionProgressForwarder import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.android.systemui.util.time.FakeSystemClock +import com.android.wm.shell.back.BackAnimation import com.android.wm.shell.sysui.ShellInterface import com.google.common.util.concurrent.MoreExecutors import java.util.Optional @@ -120,6 +121,7 @@ class OverviewProxyServiceTest : SysuiTestCase() { private lateinit var unfoldTransitionProgressForwarder: Optional<UnfoldTransitionProgressForwarder> @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher + @Mock private lateinit var backAnimation: Optional<BackAnimation> @Before fun setUp() { @@ -289,6 +291,7 @@ class OverviewProxyServiceTest : SysuiTestCase() { dumpManager, unfoldTransitionProgressForwarder, broadcastDispatcher, + backAnimation, ) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/DisplayTrackerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/DisplayTrackerImplTest.kt index ae976a0ea703..9fb752a11f56 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/settings/DisplayTrackerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/settings/DisplayTrackerImplTest.kt @@ -17,7 +17,7 @@ package com.android.systemui.settings import android.hardware.display.DisplayManager -import android.hardware.display.DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS +import android.hardware.display.DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS import android.hardware.display.DisplayManagerGlobal import android.os.Handler import android.testing.AndroidTestingRunner @@ -59,14 +59,14 @@ class DisplayTrackerImplTest : SysuiTestCase() { DisplayManagerGlobal.getInstance(), Display.DEFAULT_DISPLAY, DisplayInfo(), - DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS + DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS, ) mSecondaryDisplay = Display( DisplayManagerGlobal.getInstance(), Display.DEFAULT_DISPLAY + 1, DisplayInfo(), - DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS + DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS, ) `when`(displayManager.displays).thenReturn(arrayOf(mDefaultDisplay, mSecondaryDisplay)) @@ -94,7 +94,12 @@ class DisplayTrackerImplTest : SysuiTestCase() { fun registerBrightnessCallback_registersDisplayListener() { tracker.addBrightnessChangeCallback(TestCallback(), executor) verify(displayManager) - .registerDisplayListener(any(), any(), eq(EVENT_FLAG_DISPLAY_BRIGHTNESS)) + .registerDisplayListener( + any(), + any(), + eq(0L), + eq(PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS), + ) } @Test diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt index c41493eaa9c7..8022e6e86a49 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt @@ -31,8 +31,11 @@ import com.android.systemui.keyboard.shortcut.data.source.InputShortcutsSource import com.android.systemui.keyboard.shortcut.data.source.KeyboardShortcutGroupsSource import com.android.systemui.keyboard.shortcut.data.source.MultitaskingShortcutsSource import com.android.systemui.keyboard.shortcut.data.source.SystemShortcutsSource +import com.android.systemui.keyboard.shortcut.domain.interactor.ShortcutCustomizationInteractor import com.android.systemui.keyboard.shortcut.domain.interactor.ShortcutHelperCategoriesInteractor import com.android.systemui.keyboard.shortcut.domain.interactor.ShortcutHelperStateInteractor +import com.android.systemui.keyboard.shortcut.ui.ShortcutCustomizationDialogStarter +import com.android.systemui.keyboard.shortcut.ui.viewmodel.ShortcutCustomizationViewModel import com.android.systemui.keyboard.shortcut.ui.viewmodel.ShortcutHelperViewModel import com.android.systemui.keyguard.data.repository.fakeCommandQueue import com.android.systemui.kosmos.Kosmos @@ -42,6 +45,7 @@ import com.android.systemui.kosmos.testScope import com.android.systemui.model.sysUiState import com.android.systemui.settings.displayTracker import com.android.systemui.settings.userTracker +import com.android.systemui.statusbar.phone.systemUIDialogFactory var Kosmos.shortcutHelperAppCategoriesShortcutsSource: KeyboardShortcutGroupsSource by Kosmos.Fixture { AppCategoriesShortcutsSource(windowManager, testDispatcher) } @@ -121,3 +125,26 @@ val Kosmos.shortcutHelperViewModel by shortcutHelperCategoriesInteractor, ) } + +val Kosmos.shortcutCustomizationDialogStarterFactory by + Kosmos.Fixture { + object : ShortcutCustomizationDialogStarter.Factory { + override fun create(): ShortcutCustomizationDialogStarter { + return ShortcutCustomizationDialogStarter( + shortcutCustomizationViewModelFactory, + systemUIDialogFactory, + ) + } + } + } + +val Kosmos.shortcutCustomizationInteractor by Kosmos.Fixture { ShortcutCustomizationInteractor() } + +val Kosmos.shortcutCustomizationViewModelFactory by + Kosmos.Fixture { + object : ShortcutCustomizationViewModel.Factory { + override fun create(): ShortcutCustomizationViewModel { + return ShortcutCustomizationViewModel(shortcutCustomizationInteractor) + } + } + } diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp index 4731cfbfc935..0c2ce8dcb698 100644 --- a/ravenwood/Android.bp +++ b/ravenwood/Android.bp @@ -376,6 +376,7 @@ filegroup { ":ravenwood-empty-res", ":framework-platform-compat-config", ":services-platform-compat-config", + "texts/ravenwood-build.prop", ], device_first_srcs: [ ":apex_icu.dat", diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java index e61a054c4c39..678a97be60a2 100644 --- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java +++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java @@ -22,7 +22,6 @@ import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_INST_R import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_RESOURCE_APK; import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_VERBOSE_LOGGING; import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_VERSION_JAVA_SYSPROP; -import static com.android.ravenwood.common.RavenwoodCommonUtils.getRavenwoodRuntimePath; import static org.junit.Assert.assertThrows; import static org.mockito.ArgumentMatchers.any; @@ -95,8 +94,6 @@ public class RavenwoodRuntimeEnvironmentController { private static final String LIBRAVENWOOD_INITIALIZER_NAME = "ravenwood_initializer"; private static final String RAVENWOOD_NATIVE_SYSPROP_NAME = "ravenwood_sysprop"; private static final String RAVENWOOD_NATIVE_RUNTIME_NAME = "ravenwood_runtime"; - private static final String RAVENWOOD_BUILD_PROP = - getRavenwoodRuntimePath() + "ravenwood-data/build.prop"; /** * When enabled, attempt to dump all thread stacks just before we hit the @@ -209,7 +206,7 @@ public class RavenwoodRuntimeEnvironmentController { System.load(RavenwoodCommonUtils.getJniLibraryPath(RAVENWOOD_NATIVE_RUNTIME_NAME)); // Do the basic set up for the android sysprops. - RavenwoodSystemProperties.initialize(RAVENWOOD_BUILD_PROP); + RavenwoodSystemProperties.initialize(); setSystemProperties(null); // Do this after loading RAVENWOOD_NATIVE_RUNTIME_NAME (which backs Os.setenv()), diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java index 9bc45bee1775..3e4619f55c6d 100644 --- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java +++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java @@ -16,21 +16,30 @@ package android.platform.test.ravenwood; -import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_SYSPROP; +import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_VERBOSE_LOGGING; +import static com.android.ravenwood.common.RavenwoodCommonUtils.getRavenwoodRuntimePath; -import com.android.ravenwood.common.RavenwoodCommonUtils; +import android.util.Log; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; public class RavenwoodSystemProperties { private static final String TAG = "RavenwoodSystemProperties"; + /** We pull in propeties from this file. */ + private static final String RAVENWOOD_BUILD_PROP = "ravenwood-data/ravenwood-build.prop"; + + /** This is the actual build.prop we use to build the device (contents depends on lunch). */ + private static final String DEVICE_BUILD_PROP = "ravenwood-data/build.prop"; + + /** The default values. */ private static final Map<String, String> sDefaultValues = new HashMap<>(); private static final String[] PARTITIONS = { @@ -43,52 +52,54 @@ public class RavenwoodSystemProperties { "vendor_dlkm", }; - /** - * More info about property file loading: system/core/init/property_service.cpp - * In the following logic, the only partition we would need to consider is "system", - * since we only read from system-build.prop - */ - static void initialize(String propFile) { - // Load all properties from build.prop + private static Map<String, String> readProperties(String propFile) { + // Use an ordered map just for cleaner dump log. + final Map<String, String> ret = new LinkedHashMap<>(); try { Files.readAllLines(Path.of(propFile)).stream() .map(String::trim) .filter(s -> !s.startsWith("#")) .map(s -> s.split("\\s*=\\s*", 2)) .filter(a -> a.length == 2) - .forEach(a -> sDefaultValues.put(a[0], a[1])); + .forEach(a -> ret.put(a[0], a[1])); } catch (IOException e) { throw new RuntimeException(e); } + return ret; + } - // If ro.product.${name} is not set, derive from ro.product.${partition}.${name} - // If ro.product.cpu.abilist* is not set, derive from ro.${partition}.product.cpu.abilist* - for (var entry : Set.copyOf(sDefaultValues.entrySet())) { - final String key; - if (entry.getKey().startsWith("ro.product.system.")) { - var name = entry.getKey().substring(18); - key = "ro.product." + name; - - } else if (entry.getKey().startsWith("ro.system.product.cpu.abilist")) { - var name = entry.getKey().substring(22); - key = "ro.product.cpu." + name; + /** + * Load default sysprops from {@link #RAVENWOOD_BUILD_PROP}. We also pull in + * certain properties from the acutual device's build.prop {@link #DEVICE_BUILD_PROP} too. + * + * More info about property file loading: system/core/init/property_service.cpp + * In the following logic, the only partition we would need to consider is "system", + * since we only read from system-build.prop + */ + static void initialize() { + var path = getRavenwoodRuntimePath(); + var ravenwoodProps = readProperties(path + RAVENWOOD_BUILD_PROP); + var deviceProps = readProperties(path + DEVICE_BUILD_PROP); + + Log.i(TAG, "Default system properties:"); + ravenwoodProps.forEach((key, origValue) -> { + final String value; + + // If a value starts with "$$$", then this is a reference to the device-side value. + if (origValue.startsWith("$$$")) { + var deviceKey = origValue.substring(3); + var deviceValue = deviceProps.get(deviceKey); + if (deviceValue == null) { + throw new RuntimeException("Failed to initialize system properties. Key '" + + deviceKey + "' doesn't exist in the device side build.prop"); + } + value = deviceValue; } else { - continue; - } - if (!sDefaultValues.containsKey(key)) { - sDefaultValues.put(key, entry.getValue()); + value = origValue; } - } - - // Some other custom values - sDefaultValues.put("ro.board.first_api_level", "1"); - sDefaultValues.put("ro.product.first_api_level", "1"); - sDefaultValues.put("ro.soc.manufacturer", "Android"); - sDefaultValues.put("ro.soc.model", "Ravenwood"); - sDefaultValues.put(RAVENWOOD_SYSPROP, "1"); - - // Log all values - sDefaultValues.forEach((key, value) -> RavenwoodCommonUtils.log(TAG, key + "=" + value)); + Log.i(TAG, key + "=" + value); + sDefaultValues.put(key, value); + }); // Copy ro.product.* and ro.build.* to all partitions, just in case // We don't want to log these because these are just a lot of duplicate values @@ -104,6 +115,13 @@ public class RavenwoodSystemProperties { } } } + if (RAVENWOOD_VERBOSE_LOGGING) { + // Dump all properties for local debugging. + Log.v(TAG, "All system properties:"); + for (var key : sDefaultValues.keySet().stream().sorted().toList()) { + Log.v(TAG, "" + key + "=" + sDefaultValues.get(key)); + } + } } private volatile boolean mIsImmutable; diff --git a/ravenwood/scripts/run-ravenwood-tests.sh b/ravenwood/scripts/run-ravenwood-tests.sh index 1910100a7f5d..fe2269a8dc38 100755 --- a/ravenwood/scripts/run-ravenwood-tests.sh +++ b/ravenwood/scripts/run-ravenwood-tests.sh @@ -33,7 +33,7 @@ include_re="" exclude_re="" smoke_exclude_re="" dry_run="" -while getopts "sx:f:d" opt; do +while getopts "sx:f:dt" opt; do case "$opt" in s) # Remove slow tests. @@ -51,6 +51,9 @@ case "$opt" in # Dry run dry_run="echo" ;; + t) + export RAVENWOOD_LOG_OUT=$(tty) + ;; '?') exit 1 ;; diff --git a/ravenwood/texts/build.prop-sample-cuttlefish b/ravenwood/texts/build.prop-sample-cuttlefish new file mode 100644 index 000000000000..f78b727f5779 --- /dev/null +++ b/ravenwood/texts/build.prop-sample-cuttlefish @@ -0,0 +1,132 @@ +# This is file is generated with `aosp_cf_x86_64_phone-trunk_staging-eng` on 2024-11-06. +# We have this file here only as a reference. We don't actually use this file anywhere. + +#################################### +# from generate_common_build_props +# These properties identify this partition image. +#################################### +ro.product.system.brand=Android +ro.product.system.device=generic +ro.product.system.manufacturer=Android +ro.product.system.model=mainline +ro.product.system.name=mainline +ro.system.product.cpu.abilist=x86_64,x86,arm64-v8a,armeabi-v7a,armeabi +ro.system.product.cpu.abilist32=x86,armeabi-v7a,armeabi +ro.system.product.cpu.abilist64=x86_64,arm64-v8a +ro.system.build.date=Tue Nov 5 13:25:43 PST 2024 +ro.system.build.date.utc=1730841943 +ro.system.build.fingerprint=generic/aosp_cf_x86_64_phone/vsoc_x86_64:Baklava/MAIN/eng.omakot:eng/test-keys +ro.system.build.id=MAIN +ro.system.build.tags=test-keys +ro.system.build.type=eng +ro.system.build.version.incremental=eng.omakot +ro.system.build.version.release=15 +ro.system.build.version.release_or_codename=Baklava +ro.system.build.version.sdk=35 +#################################### +# from gen_build_prop.py:generate_build_info +#################################### +# begin build properties +ro.build.legacy.id=MAIN +ro.build.display.id=aosp_cf_x86_64_phone-eng Baklava MAIN eng.omakot test-keys +ro.build.version.incremental=eng.omakot +ro.build.version.sdk=35 +ro.build.version.preview_sdk=1 +ro.build.version.preview_sdk_fingerprint=2ef06129940d459014cf4dede3950d71 +ro.build.version.codename=Baklava +ro.build.version.all_codenames=Baklava +ro.build.version.known_codenames=Base,Base11,Cupcake,Donut,Eclair,Eclair01,EclairMr1,Froyo,Gingerbread,GingerbreadMr1,Honeycomb,HoneycombMr1,HoneycombMr2,IceCreamSandwich,IceCreamSandwichMr1,JellyBean,JellyBeanMr1,JellyBeanMr2,Kitkat,KitkatWatch,Lollipop,LollipopMr1,M,N,NMr1,O,OMr1,P,Q,R,S,Sv2,Tiramisu,UpsideDownCake,VanillaIceCream,Baklava +ro.build.version.release=15 +ro.build.version.release_or_codename=Baklava +ro.build.version.release_or_preview_display=Baklava +ro.build.version.security_patch=2024-08-05 +ro.build.version.base_os= +ro.build.version.min_supported_target_sdk=28 +ro.build.date=Tue Nov 5 13:25:43 PST 2024 +ro.build.date.utc=1730841943 +ro.build.type=eng +ro.build.user=omakoto +ro.build.host=omakoto-ct1.c.googlers.com +ro.build.tags=test-keys +ro.build.flavor=aosp_cf_x86_64_phone-eng +# ro.product.cpu.abi and ro.product.cpu.abi2 are obsolete, +# use ro.product.cpu.abilist instead. +ro.product.cpu.abi=x86_64 +ro.product.locale=en-US +ro.wifi.channels= +# ro.build.product is obsolete; use ro.product.device +ro.build.product=vsoc_x86_64 +# Do not try to parse description or thumbprint +ro.build.description=aosp_cf_x86_64_phone-eng Baklava MAIN eng.omakot test-keys +# end build properties +#################################### +# from variable ADDITIONAL_SYSTEM_PROPERTIES +#################################### +ro.treble.enabled=true +ro.llndk.api_level=202504 +ro.actionable_compatible_property.enabled=true +persist.debug.dalvik.vm.core_platform_api_policy=just-warn +ro.postinstall.fstab.prefix=/system +ro.kernel.android.checkjni=1 +ro.secure=0 +ro.allow.mock.location=1 +dalvik.vm.lockprof.threshold=500 +ro.debuggable=1 +dalvik.vm.image-dex2oat-filter=extract +init.svc_debug.no_fatal.zygote=true +net.bt.name=Android +ro.force.debuggable=0 +#################################### +# from variable PRODUCT_SYSTEM_PROPERTIES +#################################### +debug.atrace.tags.enableflags=0 +persist.traced.enable=1 +dalvik.vm.image-dex2oat-Xms=64m +dalvik.vm.image-dex2oat-Xmx=64m +dalvik.vm.dex2oat-Xms=64m +dalvik.vm.dex2oat-Xmx=512m +dalvik.vm.usejit=true +dalvik.vm.dexopt.secondary=true +dalvik.vm.dexopt.thermal-cutoff=2 +dalvik.vm.appimageformat=lz4 +ro.dalvik.vm.native.bridge=0 +pm.dexopt.post-boot=verify +pm.dexopt.first-boot=verify +pm.dexopt.boot-after-ota=verify +pm.dexopt.boot-after-mainline-update=verify +pm.dexopt.install=speed-profile +pm.dexopt.install-fast=skip +pm.dexopt.install-bulk=speed-profile +pm.dexopt.install-bulk-secondary=verify +pm.dexopt.install-bulk-downgraded=verify +pm.dexopt.install-bulk-secondary-downgraded=verify +pm.dexopt.bg-dexopt=speed-profile +pm.dexopt.ab-ota=speed-profile +pm.dexopt.inactive=verify +pm.dexopt.cmdline=verify +pm.dexopt.shared=speed +dalvik.vm.disable-art-service-dexopt=true +dalvik.vm.disable-odrefresh=true +dalvik.vm.dex2oat-resolve-startup-strings=true +dalvik.vm.dex2oat-max-image-block-size=524288 +dalvik.vm.minidebuginfo=true +dalvik.vm.dex2oat-minidebuginfo=true +dalvik.vm.madvise.vdexfile.size=104857600 +dalvik.vm.madvise.odexfile.size=104857600 +dalvik.vm.madvise.artfile.size=4294967295 +dalvik.vm.usap_pool_enabled=false +dalvik.vm.usap_refill_threshold=1 +dalvik.vm.usap_pool_size_max=3 +dalvik.vm.usap_pool_size_min=1 +dalvik.vm.usap_pool_refill_delay_ms=3000 +dalvik.vm.useartservice=true +dalvik.vm.enable_pr_dexopt=true +ro.cp_system_other_odex=1 +ro.apex.updatable=true +ro.launcher.depth.widget=0 +#################################### +# from variable PRODUCT_SYSTEM_DEFAULT_PROPERTIES +#################################### +# Auto-added by post_process_props.py +persist.sys.usb.config=adb +# end of file diff --git a/ravenwood/texts/ravenwood-build.prop b/ravenwood/texts/ravenwood-build.prop new file mode 100644 index 000000000000..93a18cffec50 --- /dev/null +++ b/ravenwood/texts/ravenwood-build.prop @@ -0,0 +1,44 @@ +# This file contains system properties used on ravenwood. + +ro.is_on_ravenwood=1 + +ro.board.first_api_level=1 +ro.product.first_api_level=1 +ro.soc.manufacturer=Android +ro.soc.model=Ravenwood +ro.debuggable=1 + +# The ones starting with "ro.product" or "ro.bild" will be copied to all "partitions" too. +# See RavenwoodSystemProperties. +ro.product.brand=Android +ro.product.device=Ravenwood +ro.product.manufacturer=Android +ro.product.model=Ravenwood +ro.product.name=Ravenwood +ro.product.cpu.abilist=x86_64 +ro.product.cpu.abilist32= +ro.product.cpu.abilist64=x86_64 + +ro.build.date=Thu Jan 01 00:00:00 GMT 2024 +ro.build.date.utc=1704092400 +ro.build.id=MAIN +ro.build.tags=dev-keys +ro.build.type=userdebug +ro.build.version.incremental=userdebug.ravenwood.20240101 + +# These are what we used to use on Ravenwood, copied here as a reference. +#ro.build.version.codename=REL +#ro.build.version.all_codenames=REL +#ro.build.version.known_codenames=REL +#ro.build.version.release=14 +#ro.build.version.release_or_codename=VanillaIceCream +#ro.build.version.sdk=34 + +# We pull in the following values from the real build.prop file. +ro.build.version.codename=$$$ro.build.version.codename +ro.build.version.all_codenames=$$$ro.build.version.codename +ro.build.version.known_codenames=$$$ro.build.version.codename +ro.build.version.release=$$$ro.build.version.release +ro.build.version.release_or_codename=$$$ro.build.version.release_or_codename +ro.build.version.release_or_preview_display=$$$ro.build.version.release_or_preview_display +ro.build.version.sdk=$$$ro.build.version.sdk diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java index 78bc658d49c7..3dcca1433dec 100644 --- a/services/core/java/com/android/server/BatteryService.java +++ b/services/core/java/com/android/server/BatteryService.java @@ -22,6 +22,9 @@ import static android.os.Flags.stateOfHealthPublic; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent; import static com.android.server.health.Utils.copyV1Battery; +import static java.lang.Math.abs; + +import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.app.ActivityManager; @@ -48,6 +51,7 @@ import android.os.FileUtils; import android.os.Handler; import android.os.IBatteryPropertiesRegistrar; import android.os.IBinder; +import android.os.Looper; import android.os.OsProtoEnums; import android.os.PowerManager; import android.os.RemoteException; @@ -67,6 +71,7 @@ import android.util.EventLog; import android.util.Slog; import android.util.proto.ProtoOutputStream; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IBatteryStats; import com.android.internal.logging.MetricsLogger; import com.android.internal.os.SomeArgs; @@ -84,6 +89,7 @@ import java.io.PrintWriter; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.NoSuchElementException; +import java.util.Objects; import java.util.concurrent.CopyOnWriteArraySet; /** @@ -149,19 +155,112 @@ public final class BatteryService extends SystemService { private HealthInfo mHealthInfo; private final HealthInfo mLastHealthInfo = new HealthInfo(); private boolean mBatteryLevelCritical; - private int mLastBatteryStatus; - private int mLastBatteryHealth; - private boolean mLastBatteryPresent; - private int mLastBatteryLevel; - private int mLastBatteryVoltage; - private int mLastBatteryTemperature; - private boolean mLastBatteryLevelCritical; - private int mLastMaxChargingCurrent; - private int mLastMaxChargingVoltage; - private int mLastChargeCounter; - private int mLastBatteryCycleCount; - private int mLastChargingState; - private int mLastBatteryCapacityLevel; + + /** + * {@link HealthInfo#batteryStatus} value when {@link Intent#ACTION_BATTERY_CHANGED} + * broadcast was sent last. + * Note: This value may be used for internal operations and/or to determine whether to trigger + * the {@link Intent#ACTION_BATTERY_CHANGED} broadcast or not. + */ + private int mLastBroadcastBatteryStatus; + /** + * {@link HealthInfo#batteryHealth} value when {@link Intent#ACTION_BATTERY_CHANGED} + * broadcast was sent last. + * Note: This value may be used for internal operations and/or to determine whether to trigger + * the {@link Intent#ACTION_BATTERY_CHANGED} broadcast or not. + */ + private int mLastBroadcastBatteryHealth; + /** + * {@link HealthInfo#batteryPresent} value when {@link Intent#ACTION_BATTERY_CHANGED} + * broadcast was sent last. + * Note: This value may be used for internal operations and/or to determine whether to trigger + * the {@link Intent#ACTION_BATTERY_CHANGED} broadcast or not. + */ + private boolean mLastBroadcastBatteryPresent; + /** + * {@link HealthInfo#batteryLevel} value when {@link Intent#ACTION_BATTERY_CHANGED} + * broadcast was sent last. + * Note: This value may be used for internal operations and/or to determine whether to trigger + * the {@link Intent#ACTION_BATTERY_CHANGED} broadcast or not. + */ + private int mLastBroadcastBatteryLevel; + /** + * {@link HealthInfo#batteryVoltageMillivolts} value when {@link Intent#ACTION_BATTERY_CHANGED} + * broadcast was sent last. + * Note: This value may be used for internal operations and/or to determine whether to trigger + * the {@link Intent#ACTION_BATTERY_CHANGED} broadcast or not. + */ + private int mLastBroadcastBatteryVoltage; + /** + * {@link HealthInfo#batteryTemperatureTenthsCelsius} value when + * {@link Intent#ACTION_BATTERY_CHANGED} broadcast was sent last. + * Note: This value may be used for internal operations and/or to determine whether to trigger + * the {@link Intent#ACTION_BATTERY_CHANGED} broadcast or not. + */ + private int mLastBroadcastBatteryTemperature; + /** + * {@link #mBatteryLevelCritical} value when {@link Intent#ACTION_BATTERY_CHANGED} + * broadcast was sent last. + * Note: These values may be used for internal operations and/or to determine whether to trigger + * the broadcast or not. + */ + private boolean mLastBroadcastBatteryLevelCritical; + /** + * {@link HealthInfo#maxChargingCurrentMicroamps} value when + * {@link Intent#ACTION_BATTERY_CHANGED} broadcast was sent last. + * Note: This value may be used for internal operations and/or to determine whether to trigger + * the {@link Intent#ACTION_BATTERY_CHANGED} broadcast or not. + */ + private int mLastBroadcastMaxChargingCurrent; + /** + * {@link HealthInfo#maxChargingVoltageMicrovolts} value when + * {@link Intent#ACTION_BATTERY_CHANGED} broadcast was sent last. + * Note: This value may be used for internal operations and/or to determine whether to trigger + * the {@link Intent#ACTION_BATTERY_CHANGED} broadcast or not. + */ + private int mLastBroadcastMaxChargingVoltage; + /** + * {@link HealthInfo#batteryChargeCounterUah} value when {@link Intent#ACTION_BATTERY_CHANGED} + * broadcast was sent last. + * Note: This value may be used for internal operations and/or to determine whether to trigger + * the {@link Intent#ACTION_BATTERY_CHANGED} broadcast or not. + */ + private int mLastBroadcastChargeCounter; + /** + * {@link HealthInfo#batteryCycleCount} value when {@link Intent#ACTION_BATTERY_CHANGED} + * broadcast was sent last. + * Note: This value may be used for internal operations and/or to determine whether to trigger + * the {@link Intent#ACTION_BATTERY_CHANGED} broadcast or not. + */ + private int mLastBroadcastBatteryCycleCount; + /** + * {@link HealthInfo#chargingState} value when {@link Intent#ACTION_BATTERY_CHANGED} + * broadcast was sent last. + * Note: This value may be used for internal operations and/or to determine whether to trigger + * the {@link Intent#ACTION_BATTERY_CHANGED} broadcast or not. + */ + private int mLastBroadcastChargingState; + /** + * {@link HealthInfo#batteryCapacityLevel} value when {@link Intent#ACTION_BATTERY_CHANGED} + * broadcast was sent last. + * Note: This value may be used for internal operations and/or to determine whether to trigger + * the {@link Intent#ACTION_BATTERY_CHANGED} broadcast or not. + */ + private int mLastBroadcastBatteryCapacityLevel; + /** + * {@link #mPlugType} value when {@link Intent#ACTION_BATTERY_CHANGED} + * broadcast was sent last. + * Note: These values may be used for internal operations and/or to determine whether to trigger + * the broadcast or not. + */ + private int mLastBroadcastPlugType = -1; // Extra state so we can detect first run + /** + * {@link #mInvalidCharger} value when {@link Intent#ACTION_BATTERY_CHANGED} + * broadcast was sent last. + * Note: These values may be used for internal operations and/or to determine whether to trigger + * the broadcast or not. + */ + private int mLastBroadcastInvalidCharger; /** * The last seen charging policy. This requires the * {@link android.Manifest.permission#BATTERY_STATS} permission and should therefore not be @@ -172,7 +271,6 @@ public final class BatteryService extends SystemService { private int mSequence = 1; private int mInvalidCharger; - private int mLastInvalidCharger; private int mLowBatteryWarningLevel; private int mLastLowBatteryWarningLevel; @@ -184,7 +282,6 @@ public final class BatteryService extends SystemService { private static String sSystemUiPackage; private int mPlugType; - private int mLastPlugType = -1; // Extra state so we can detect first run private boolean mBatteryLevelLow; @@ -197,6 +294,16 @@ public final class BatteryService extends SystemService { private boolean mUpdatesStopped; private boolean mBatteryInputSuspended; + /** + * Time when the voltage was updated last by HAL and we sent the + * {@link Intent#ACTION_BATTERY_CHANGED} broadcast. + * Note: This value is used to rate limit the {@link Intent#ACTION_BATTERY_CHANGED} broadcast + * so it is possible that voltage was updated but we did not send the broadcast so in that + * case we do not update the time. + */ + @VisibleForTesting + public long mLastBroadcastVoltageUpdateTime; + private Led mLed; private boolean mSentLowBatteryBroadcast = false; @@ -211,7 +318,8 @@ public final class BatteryService extends SystemService { private final CopyOnWriteArraySet<BatteryManagerInternal.ChargingPolicyChangeListener> mChargingPolicyChangeListeners = new CopyOnWriteArraySet<>(); - private static final Bundle BATTERY_CHANGED_OPTIONS = BroadcastOptions.makeBasic() + @VisibleForTesting + public static final Bundle BATTERY_CHANGED_OPTIONS = BroadcastOptions.makeBasic() .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT) .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE) .toBundle(); @@ -234,6 +342,25 @@ public final class BatteryService extends SystemService { private static final int MSG_BROADCAST_POWER_CONNECTION_CHANGED = 2; private static final int MSG_BROADCAST_BATTERY_LOW_OKAY = 3; + /** + * This value is used to rate limit the {@link Intent#ACTION_BATTERY_CHANGED} broadcast. We + * only send the broadcast and update the temperature value when the temp change is greater or + * equals to 1 degree celsius. + */ + private static final int ABSOLUTE_DECI_CELSIUS_DIFF_FOR_TEMP_UPDATE = 10; + /** + * This value is used to rate limit the {@link Intent#ACTION_BATTERY_CHANGED} broadcast. We + * only send the broadcast if the last voltage was updated at least 20s seconds back and has a + * fluctuation of at least 1%. + */ + private static final int TIME_DIFF_FOR_VOLTAGE_UPDATE_MS = 20000; + /** + * The value is used to rate limit the {@link Intent#ACTION_BATTERY_CHANGED} broadcast. We + * only send the broadcast if the last voltage was updated at least 20s seconds back and has a + * fluctuation of at least 1%. + */ + private static final float BASE_POINT_DIFF_FOR_VOLTAGE_UPDATE = 0.01f; + private final Handler.Callback mLocalCallback = msg -> { switch (msg.what) { case MSG_BROADCAST_BATTERY_CHANGED: { @@ -283,10 +410,19 @@ public final class BatteryService extends SystemService { }; public BatteryService(Context context) { + this(context, Objects.requireNonNull(Looper.myLooper(), + "BatteryService uses handler!! Can't create handler inside thread that has not " + + "called Looper.prepare()")); + } + + @VisibleForTesting + public BatteryService(Context context, @NonNull Looper looper) { super(context); + Objects.requireNonNull(looper); + mContext = context; - mHandler = new Handler(mLocalCallback, true /*async*/); + mHandler = new Handler(looper, mLocalCallback, true /*async*/); mLed = new Led(context, getLocalService(LightsManager.class)); mBatteryStats = BatteryStatsService.getService(); mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); @@ -436,7 +572,7 @@ public final class BatteryService extends SystemService { private boolean shouldSendBatteryLowLocked() { final boolean plugged = mPlugType != BATTERY_PLUGGED_NONE; - final boolean oldPlugged = mLastPlugType != BATTERY_PLUGGED_NONE; + final boolean oldPlugged = mLastBroadcastPlugType != BATTERY_PLUGGED_NONE; /* The ACTION_BATTERY_LOW broadcast is sent in these situations: * - is just un-plugged (previously was plugged) and battery level is @@ -447,7 +583,7 @@ public final class BatteryService extends SystemService { return !plugged && mHealthInfo.batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN && mHealthInfo.batteryLevel <= mLowBatteryWarningLevel - && (oldPlugged || mLastBatteryLevel > mLowBatteryWarningLevel + && (oldPlugged || mLastBroadcastBatteryLevel > mLowBatteryWarningLevel || mHealthInfo.batteryLevel > mLastLowBatteryWarningLevel); } @@ -515,7 +651,13 @@ public final class BatteryService extends SystemService { } } - private void update(android.hardware.health.HealthInfo info) { + /** + * Updates the healthInfo and triggers the broadcast. + * + * @param info the new health info + */ + @VisibleForTesting + public void update(android.hardware.health.HealthInfo info) { traceBegin("HealthInfoUpdate"); Trace.traceCounter( @@ -556,8 +698,8 @@ public final class BatteryService extends SystemService { long dischargeDuration = 0; mBatteryLevelCritical = - mHealthInfo.batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN - && mHealthInfo.batteryLevel <= mCriticalBatteryLevel; + mHealthInfo.batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN + && mHealthInfo.batteryLevel <= mCriticalBatteryLevel; mPlugType = plugType(mHealthInfo); if (DEBUG) { @@ -591,24 +733,28 @@ public final class BatteryService extends SystemService { mHandler.post(this::notifyChargingPolicyChanged); } + final boolean includeChargeCounter = + !com.android.server.flags.Flags.rateLimitBatteryChangedBroadcast() + && mHealthInfo.batteryChargeCounterUah != mLastBroadcastChargeCounter; + if (force - || (mHealthInfo.batteryStatus != mLastBatteryStatus - || mHealthInfo.batteryHealth != mLastBatteryHealth - || mHealthInfo.batteryPresent != mLastBatteryPresent - || mHealthInfo.batteryLevel != mLastBatteryLevel - || mPlugType != mLastPlugType - || mHealthInfo.batteryVoltageMillivolts != mLastBatteryVoltage - || mHealthInfo.batteryTemperatureTenthsCelsius != mLastBatteryTemperature - || mHealthInfo.maxChargingCurrentMicroamps != mLastMaxChargingCurrent - || mHealthInfo.maxChargingVoltageMicrovolts != mLastMaxChargingVoltage - || mHealthInfo.batteryChargeCounterUah != mLastChargeCounter - || mInvalidCharger != mLastInvalidCharger - || mHealthInfo.batteryCycleCount != mLastBatteryCycleCount - || mHealthInfo.chargingState != mLastChargingState - || mHealthInfo.batteryCapacityLevel != mLastBatteryCapacityLevel)) { - - if (mPlugType != mLastPlugType) { - if (mLastPlugType == BATTERY_PLUGGED_NONE) { + || (mHealthInfo.batteryStatus != mLastBroadcastBatteryStatus + || mHealthInfo.batteryHealth != mLastBroadcastBatteryHealth + || mHealthInfo.batteryPresent != mLastBroadcastBatteryPresent + || mHealthInfo.batteryLevel != mLastBroadcastBatteryLevel + || mPlugType != mLastBroadcastPlugType + || mHealthInfo.batteryVoltageMillivolts != mLastBroadcastBatteryVoltage + || mHealthInfo.batteryTemperatureTenthsCelsius != mLastBroadcastBatteryTemperature + || mHealthInfo.maxChargingCurrentMicroamps != mLastBroadcastMaxChargingCurrent + || mHealthInfo.maxChargingVoltageMicrovolts != mLastBroadcastMaxChargingVoltage + || includeChargeCounter + || mInvalidCharger != mLastBroadcastInvalidCharger + || mHealthInfo.batteryCycleCount != mLastBroadcastBatteryCycleCount + || mHealthInfo.chargingState != mLastBroadcastChargingState + || mHealthInfo.batteryCapacityLevel != mLastBroadcastBatteryCapacityLevel)) { + + if (mPlugType != mLastBroadcastPlugType) { + if (mLastBroadcastPlugType == BATTERY_PLUGGED_NONE) { // discharging -> charging mChargeStartLevel = mHealthInfo.batteryLevel; mChargeStartTime = SystemClock.elapsedRealtime(); @@ -622,7 +768,8 @@ public final class BatteryService extends SystemService { // There's no value in this data unless we've discharged at least once and the // battery level has changed; so don't log until it does. - if (mDischargeStartTime != 0 && mDischargeStartLevel != mHealthInfo.batteryLevel) { + if (mDischargeStartTime != 0 + && mDischargeStartLevel != mHealthInfo.batteryLevel) { dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime; logOutlier = true; EventLog.writeEvent(EventLogTags.BATTERY_DISCHARGE, dischargeDuration, @@ -639,7 +786,7 @@ public final class BatteryService extends SystemService { if (mChargeStartTime != 0 && chargeDuration != 0) { final LogMaker builder = new LogMaker(MetricsEvent.ACTION_CHARGE); builder.setType(MetricsEvent.TYPE_DISMISS); - builder.addTaggedData(MetricsEvent.FIELD_PLUG_TYPE, mLastPlugType); + builder.addTaggedData(MetricsEvent.FIELD_PLUG_TYPE, mLastBroadcastPlugType); builder.addTaggedData(MetricsEvent.FIELD_CHARGING_DURATION_MILLIS, chargeDuration); builder.addTaggedData(MetricsEvent.FIELD_BATTERY_LEVEL_START, @@ -651,19 +798,20 @@ public final class BatteryService extends SystemService { mChargeStartTime = 0; } } - if (mHealthInfo.batteryStatus != mLastBatteryStatus || - mHealthInfo.batteryHealth != mLastBatteryHealth || - mHealthInfo.batteryPresent != mLastBatteryPresent || - mPlugType != mLastPlugType) { + if (mHealthInfo.batteryStatus != mLastBroadcastBatteryStatus + || mHealthInfo.batteryHealth != mLastBroadcastBatteryHealth + || mHealthInfo.batteryPresent != mLastBroadcastBatteryPresent + || mPlugType != mLastBroadcastPlugType) { EventLog.writeEvent(EventLogTags.BATTERY_STATUS, - mHealthInfo.batteryStatus, mHealthInfo.batteryHealth, mHealthInfo.batteryPresent ? 1 : 0, + mHealthInfo.batteryStatus, mHealthInfo.batteryHealth, + mHealthInfo.batteryPresent ? 1 : 0, mPlugType, mHealthInfo.batteryTechnology); SystemProperties.set( "debug.tracing.battery_status", Integer.toString(mHealthInfo.batteryStatus)); SystemProperties.set("debug.tracing.plug_type", Integer.toString(mPlugType)); } - if (mHealthInfo.batteryLevel != mLastBatteryLevel) { + if (mHealthInfo.batteryLevel != mLastBroadcastBatteryLevel) { // Don't do this just from voltage or temperature changes, that is // too noisy. EventLog.writeEvent( @@ -672,8 +820,8 @@ public final class BatteryService extends SystemService { mHealthInfo.batteryVoltageMillivolts, mHealthInfo.batteryTemperatureTenthsCelsius); } - if (mBatteryLevelCritical && !mLastBatteryLevelCritical && - mPlugType == BATTERY_PLUGGED_NONE) { + if (mBatteryLevelCritical && !mLastBroadcastBatteryLevelCritical + && mPlugType == BATTERY_PLUGGED_NONE) { // We want to make sure we log discharge cycle outliers // if the battery is about to die. dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime; @@ -684,7 +832,7 @@ public final class BatteryService extends SystemService { // Should we now switch in to low battery mode? if (mPlugType == BATTERY_PLUGGED_NONE && mHealthInfo.batteryStatus != - BatteryManager.BATTERY_STATUS_UNKNOWN + BatteryManager.BATTERY_STATUS_UNKNOWN && mHealthInfo.batteryLevel <= mLowBatteryWarningLevel) { mBatteryLevelLow = true; } @@ -692,7 +840,7 @@ public final class BatteryService extends SystemService { // Should we now switch out of low battery mode? if (mPlugType != BATTERY_PLUGGED_NONE) { mBatteryLevelLow = false; - } else if (mHealthInfo.batteryLevel >= mLowBatteryCloseWarningLevel) { + } else if (mHealthInfo.batteryLevel >= mLowBatteryCloseWarningLevel) { mBatteryLevelLow = false; } else if (force && mHealthInfo.batteryLevel >= mLowBatteryWarningLevel) { // If being forced, the previous state doesn't matter, we will just @@ -706,7 +854,7 @@ public final class BatteryService extends SystemService { // Separate broadcast is sent for power connected / not connected // since the standard intent will not wake any applications and some // applications may want to have smart behavior based on this. - if (mPlugType != 0 && mLastPlugType == 0) { + if (mPlugType != 0 && mLastBroadcastPlugType == 0) { final Intent statusIntent = new Intent(Intent.ACTION_POWER_CONNECTED); statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence); @@ -726,8 +874,7 @@ public final class BatteryService extends SystemService { } }); } - } - else if (mPlugType == 0 && mLastPlugType != 0) { + } else if (mPlugType == 0 && mLastBroadcastPlugType != 0) { final Intent statusIntent = new Intent(Intent.ACTION_POWER_DISCONNECTED); statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence); @@ -797,8 +944,14 @@ public final class BatteryService extends SystemService { // We are doing this after sending the above broadcasts, so anything processing // them will get the new sequence number at that point. (See for example how testing // of JobScheduler's BatteryController works.) - sendBatteryChangedIntentLocked(force); - if (mLastBatteryLevel != mHealthInfo.batteryLevel || mLastPlugType != mPlugType) { + + boolean rateLimitBatteryChangedBroadcast = rateLimitBatteryChangedBroadcast(force); + + if (!rateLimitBatteryChangedBroadcast) { + sendBatteryChangedIntentLocked(force); + } + if (mLastBroadcastBatteryLevel != mHealthInfo.batteryLevel + || mLastBroadcastPlugType != mPlugType) { sendBatteryLevelChangedIntentLocked(); } @@ -811,21 +964,24 @@ public final class BatteryService extends SystemService { logOutlierLocked(dischargeDuration); } - mLastBatteryStatus = mHealthInfo.batteryStatus; - mLastBatteryHealth = mHealthInfo.batteryHealth; - mLastBatteryPresent = mHealthInfo.batteryPresent; - mLastBatteryLevel = mHealthInfo.batteryLevel; - mLastPlugType = mPlugType; - mLastBatteryVoltage = mHealthInfo.batteryVoltageMillivolts; - mLastBatteryTemperature = mHealthInfo.batteryTemperatureTenthsCelsius; - mLastMaxChargingCurrent = mHealthInfo.maxChargingCurrentMicroamps; - mLastMaxChargingVoltage = mHealthInfo.maxChargingVoltageMicrovolts; - mLastChargeCounter = mHealthInfo.batteryChargeCounterUah; - mLastBatteryLevelCritical = mBatteryLevelCritical; - mLastInvalidCharger = mInvalidCharger; - mLastBatteryCycleCount = mHealthInfo.batteryCycleCount; - mLastChargingState = mHealthInfo.chargingState; - mLastBatteryCapacityLevel = mHealthInfo.batteryCapacityLevel; + // Only update the values when we send the broadcast + if (!rateLimitBatteryChangedBroadcast) { + mLastBroadcastBatteryStatus = mHealthInfo.batteryStatus; + mLastBroadcastBatteryHealth = mHealthInfo.batteryHealth; + mLastBroadcastBatteryPresent = mHealthInfo.batteryPresent; + mLastBroadcastBatteryLevel = mHealthInfo.batteryLevel; + mLastBroadcastPlugType = mPlugType; + mLastBroadcastBatteryVoltage = mHealthInfo.batteryVoltageMillivolts; + mLastBroadcastBatteryTemperature = mHealthInfo.batteryTemperatureTenthsCelsius; + mLastBroadcastMaxChargingCurrent = mHealthInfo.maxChargingCurrentMicroamps; + mLastBroadcastMaxChargingVoltage = mHealthInfo.maxChargingVoltageMicrovolts; + mLastBroadcastChargeCounter = mHealthInfo.batteryChargeCounterUah; + mLastBroadcastBatteryLevelCritical = mBatteryLevelCritical; + mLastBroadcastInvalidCharger = mInvalidCharger; + mLastBroadcastBatteryCycleCount = mHealthInfo.batteryCycleCount; + mLastBroadcastChargingState = mHealthInfo.chargingState; + mLastBroadcastBatteryCapacityLevel = mHealthInfo.batteryCapacityLevel; + } } } @@ -1089,6 +1245,74 @@ public final class BatteryService extends SystemService { } } + /** + * Rate limit's the broadcast based on the changes in temp, voltage and chargeCounter. + */ + private boolean rateLimitBatteryChangedBroadcast(boolean forceUpdate) { + if (!com.android.server.flags.Flags.rateLimitBatteryChangedBroadcast()) { + return false; + } + if (mLastBroadcastBatteryVoltage == 0 || mLastBroadcastBatteryTemperature == 0) { + mLastBroadcastVoltageUpdateTime = SystemClock.elapsedRealtime(); + return false; + } + + final boolean voltageUpdated = + mLastBroadcastBatteryVoltage != mHealthInfo.batteryVoltageMillivolts; + final boolean temperatureUpdated = + mLastBroadcastBatteryTemperature != mHealthInfo.batteryTemperatureTenthsCelsius; + final boolean otherStatesUpdated = forceUpdate + || mHealthInfo.batteryStatus != mLastBroadcastBatteryStatus + || mHealthInfo.batteryHealth != mLastBroadcastBatteryHealth + || mHealthInfo.batteryPresent != mLastBroadcastBatteryPresent + || mHealthInfo.batteryLevel != mLastBroadcastBatteryLevel + || mPlugType != mLastBroadcastPlugType + || mHealthInfo.maxChargingCurrentMicroamps != mLastBroadcastMaxChargingCurrent + || mHealthInfo.maxChargingVoltageMicrovolts != mLastBroadcastMaxChargingVoltage + || mInvalidCharger != mLastBroadcastInvalidCharger + || mHealthInfo.batteryCycleCount != mLastBroadcastBatteryCycleCount + || mHealthInfo.chargingState != mLastBroadcastChargingState + || mHealthInfo.batteryCapacityLevel != mLastBroadcastBatteryCapacityLevel; + + // We only rate limit based on changes in the temp, voltage. + if (otherStatesUpdated) { + + if (voltageUpdated) { + mLastBroadcastVoltageUpdateTime = SystemClock.elapsedRealtime(); + } + return false; + } + + final float basePointDiff = + (float) (mLastBroadcastBatteryVoltage - mHealthInfo.batteryVoltageMillivolts) + / mLastBroadcastBatteryVoltage; + + // We only send the broadcast if voltage change is greater than 1% and last voltage + // update was sent at least 20 seconds back. + if (voltageUpdated + && abs(basePointDiff) >= BASE_POINT_DIFF_FOR_VOLTAGE_UPDATE + && SystemClock.elapsedRealtime() - mLastBroadcastVoltageUpdateTime + >= TIME_DIFF_FOR_VOLTAGE_UPDATE_MS) { + mLastBroadcastVoltageUpdateTime = SystemClock.elapsedRealtime(); + + return false; + } + + // Only send the broadcast if the temperature update is greater than 1 degree celsius. + if (temperatureUpdated + && abs( + mLastBroadcastBatteryTemperature - mHealthInfo.batteryTemperatureTenthsCelsius) + >= ABSOLUTE_DECI_CELSIUS_DIFF_FOR_TEMP_UPDATE) { + + if (voltageUpdated) { + mLastBroadcastVoltageUpdateTime = SystemClock.elapsedRealtime(); + } + return false; + } + + return true; + } + class Shell extends ShellCommand { @Override public int onCommand(String cmd) { @@ -1399,6 +1623,10 @@ public final class BatteryService extends SystemService { pw.println(" level: " + mHealthInfo.batteryLevel); pw.println(" scale: " + BATTERY_SCALE); pw.println(" voltage: " + mHealthInfo.batteryVoltageMillivolts); + pw.println(" Time when the latest updated value of the voltage was sent via " + + "battery changed broadcast: " + mLastBroadcastVoltageUpdateTime); + pw.println(" The last voltage value sent via the battery changed broadcast: " + + mLastBroadcastBatteryVoltage); pw.println(" temperature: " + mHealthInfo.batteryTemperatureTenthsCelsius); pw.println(" technology: " + mHealthInfo.batteryTechnology); pw.println(" Charging state: " + mHealthInfo.chargingState); @@ -1457,6 +1685,11 @@ public final class BatteryService extends SystemService { Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); } + @VisibleForTesting + public Handler getHandlerForTest() { + return mHandler; + } + @SuppressLint("AndroidFrameworkRequiresPermission") private static void sendBroadcastToAllUsers(Context context, Intent intent, Bundle options) { diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index 08632fe09b19..c0676623a1e9 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -514,27 +514,11 @@ public class OomAdjuster { mLogger = new OomAdjusterDebugLogger(this, mService.mConstants); mProcessGroupHandler = new Handler(adjusterThread.getLooper(), msg -> { - final int pid = msg.arg1; - final int group = msg.arg2; - if (pid == ActivityManagerService.MY_PID) { - // Skip setting the process group for system_server, keep it as default. - return true; - } - final boolean traceEnabled = Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER); - if (traceEnabled) { - Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "setProcessGroup " - + msg.obj + " to " + group); - } - try { - android.os.Process.setProcessGroup(pid, group); - } catch (Exception e) { - if (DEBUG_ALL) { - Slog.w(TAG, "Failed setting process group of " + pid + " to " + group, e); - } - } finally { - if (traceEnabled) { - Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); - } + final int group = msg.what; + final ProcessRecord app = (ProcessRecord) msg.obj; + setProcessGroup(app.getPid(), group, app.processName); + if (Flags.phantomProcessesFix()) { + mService.mPhantomProcessList.setProcessGroupForPhantomProcessOfApp(app, group); } return true; }); @@ -545,8 +529,31 @@ public class OomAdjuster { } void setProcessGroup(int pid, int group, String processName) { + if (pid == ActivityManagerService.MY_PID) { + // Skip setting the process group for system_server, keep it as default. + return; + } + final boolean traceEnabled = Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER); + if (traceEnabled) { + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "setProcessGroup " + + processName + " to " + group); + } + try { + android.os.Process.setProcessGroup(pid, group); + } catch (Exception e) { + if (DEBUG_ALL) { + Slog.w(TAG, "Failed setting process group of " + pid + " to " + group, e); + } + } finally { + if (traceEnabled) { + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); + } + } + } + + void setAppAndChildProcessGroup(ProcessRecord app, int group) { mProcessGroupHandler.sendMessage(mProcessGroupHandler.obtainMessage( - 0 /* unused */, pid, group, processName)); + group, app)); } void initSettings() { @@ -3503,8 +3510,7 @@ public class OomAdjuster { processGroup = THREAD_GROUP_DEFAULT; break; } - setProcessGroup(app.getPid(), processGroup, app.processName); - mService.mPhantomProcessList.setProcessGroupForPhantomProcessOfApp(app, processGroup); + setAppAndChildProcessGroup(app, processGroup); try { final int renderThreadTid = app.getRenderThreadTid(); if (curSchedGroup == SCHED_GROUP_TOP_APP) { diff --git a/services/core/java/com/android/server/am/PhantomProcessList.java b/services/core/java/com/android/server/am/PhantomProcessList.java index bfdced77a1b3..123780fb7567 100644 --- a/services/core/java/com/android/server/am/PhantomProcessList.java +++ b/services/core/java/com/android/server/am/PhantomProcessList.java @@ -548,6 +548,7 @@ public final class PhantomProcessList { */ void setProcessGroupForPhantomProcessOfApp(final ProcessRecord app, final int group) { synchronized (mLock) { + lookForPhantomProcessesLocked(app); final SparseArray<PhantomProcessRecord> array = getPhantomProcessOfAppLocked(app); if (array == null) { return; diff --git a/services/core/java/com/android/server/am/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig index 7b4d6c7fff82..5d5b35b8c4fb 100644 --- a/services/core/java/com/android/server/am/flags.aconfig +++ b/services/core/java/com/android/server/am/flags.aconfig @@ -250,4 +250,14 @@ flag { is_fixed_read_only: true description: "Add +X to the prev scores according to their positions in the process LRU list" bug: "359912586" -}
\ No newline at end of file +} + +flag { + name: "phantom_processes_fix" + namespace: "backstage_power" + description: "Make sure setProcessGroupForPhantomProcessOfApp deals with phantom processes properly" + bug: "375058190" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index f5a75c7d1c38..0e77040187e1 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -25,7 +25,7 @@ import static android.Manifest.permission.MANAGE_DISPLAYS; import static android.Manifest.permission.RESTRICT_DISPLAY_MODES; import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_CACHED; import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE; -import static android.hardware.display.DisplayManager.EventFlag; +import static android.hardware.display.DisplayManagerGlobal.InternalEventFlag; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD; @@ -1390,16 +1390,16 @@ public final class DisplayManagerService extends SystemService { } private void registerCallbackInternal(IDisplayManagerCallback callback, int callingPid, - int callingUid, @EventFlag long eventFlagsMask) { + int callingUid, @InternalEventFlag long internalEventFlagsMask) { synchronized (mSyncRoot) { CallbackRecord record = mCallbacks.get(callingPid); if (record != null) { - record.updateEventFlagsMask(eventFlagsMask); + record.updateEventFlagsMask(internalEventFlagsMask); return; } - record = new CallbackRecord(callingPid, callingUid, callback, eventFlagsMask); + record = new CallbackRecord(callingPid, callingUid, callback, internalEventFlagsMask); try { IBinder binder = callback.asBinder(); binder.linkToDeath(record, 0); @@ -4009,7 +4009,7 @@ public final class DisplayManagerService extends SystemService { public final int mPid; public final int mUid; private final IDisplayManagerCallback mCallback; - private @DisplayManager.EventFlag AtomicLong mEventFlagsMask; + private @InternalEventFlag AtomicLong mInternalEventFlagsMask; private final String mPackageName; public boolean mWifiDisplayScanRequested; @@ -4030,11 +4030,11 @@ public final class DisplayManagerService extends SystemService { private boolean mFrozen; CallbackRecord(int pid, int uid, @NonNull IDisplayManagerCallback callback, - @EventFlag long eventFlagsMask) { + @InternalEventFlag long internalEventFlagsMask) { mPid = pid; mUid = uid; mCallback = callback; - mEventFlagsMask = new AtomicLong(eventFlagsMask); + mInternalEventFlagsMask = new AtomicLong(internalEventFlagsMask); mCached = false; mFrozen = false; @@ -4056,8 +4056,8 @@ public final class DisplayManagerService extends SystemService { mPackageName = packageNames == null ? null : packageNames[0]; } - public void updateEventFlagsMask(@EventFlag long eventFlag) { - mEventFlagsMask.set(eventFlag); + public void updateEventFlagsMask(@InternalEventFlag long internalEventFlag) { + mInternalEventFlagsMask.set(internalEventFlag); } /** @@ -4121,13 +4121,13 @@ public final class DisplayManagerService extends SystemService { if (!shouldSendEvent(event)) { if (extraLogging(mPackageName)) { Slog.i(TAG, - "Not sending displayEvent: " + event + " due to flag:" - + mEventFlagsMask); + "Not sending displayEvent: " + event + " due to mask:" + + mInternalEventFlagsMask); } if (Trace.isTagEnabled(Trace.TRACE_TAG_POWER)) { Trace.instant(Trace.TRACE_TAG_POWER, - "notifyDisplayEventAsync#notSendingEvent=" + event + ",mEventsFlag=" - + mEventFlagsMask); + "notifyDisplayEventAsync#notSendingEvent=" + event + + ",mInternalEventFlagsMask=" + mInternalEventFlagsMask); } // The client is not interested in this event, so do nothing. return true; @@ -4173,22 +4173,29 @@ public final class DisplayManagerService extends SystemService { * Return true if the client is interested in this event. */ private boolean shouldSendEvent(@DisplayEvent int event) { - final long flag = mEventFlagsMask.get(); + final long mask = mInternalEventFlagsMask.get(); switch (event) { case DisplayManagerGlobal.EVENT_DISPLAY_ADDED: - return (flag & DisplayManager.EVENT_FLAG_DISPLAY_ADDED) != 0; + return (mask & DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED) != 0; case DisplayManagerGlobal.EVENT_DISPLAY_CHANGED: - return (flag & DisplayManager.EVENT_FLAG_DISPLAY_CHANGED) != 0; + return (mask & DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CHANGED) != 0; case DisplayManagerGlobal.EVENT_DISPLAY_BRIGHTNESS_CHANGED: - return (flag & DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS) != 0; + return (mask + & DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_BRIGHTNESS_CHANGED) + != 0; case DisplayManagerGlobal.EVENT_DISPLAY_REMOVED: - return (flag & DisplayManager.EVENT_FLAG_DISPLAY_REMOVED) != 0; + return (mask & DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REMOVED) != 0; case DisplayManagerGlobal.EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED: - return (flag & DisplayManager.EVENT_FLAG_HDR_SDR_RATIO_CHANGED) != 0; + return (mask + & DisplayManagerGlobal + .INTERNAL_EVENT_FLAG_DISPLAY_HDR_SDR_RATIO_CHANGED) + != 0; case DisplayManagerGlobal.EVENT_DISPLAY_CONNECTED: // fallthrough case DisplayManagerGlobal.EVENT_DISPLAY_DISCONNECTED: - return (flag & DisplayManager.EVENT_FLAG_DISPLAY_CONNECTION_CHANGED) != 0; + return (mask + & DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED) + != 0; default: // This should never happen. Slog.e(TAG, "Unknown display event " + event); @@ -4374,15 +4381,16 @@ public final class DisplayManagerService extends SystemService { @Override // Binder call public void registerCallback(IDisplayManagerCallback callback) { - registerCallbackWithEventMask(callback, DisplayManager.EVENT_FLAG_DISPLAY_ADDED - | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED - | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED); + registerCallbackWithEventMask(callback, + DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED + | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CHANGED + | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REMOVED); } @Override // Binder call @SuppressLint("AndroidFrameworkRequiresPermission") // Permission only required sometimes public void registerCallbackWithEventMask(IDisplayManagerCallback callback, - @EventFlag long eventFlagsMask) { + @InternalEventFlag long internalEventFlagsMask) { if (callback == null) { throw new IllegalArgumentException("listener must not be null"); } @@ -4391,7 +4399,9 @@ public final class DisplayManagerService extends SystemService { final int callingUid = Binder.getCallingUid(); if (mFlags.isConnectedDisplayManagementEnabled()) { - if ((eventFlagsMask & DisplayManager.EVENT_FLAG_DISPLAY_CONNECTION_CHANGED) != 0) { + if ((internalEventFlagsMask + & DisplayManagerGlobal + .INTERNAL_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED) != 0) { mContext.enforceCallingOrSelfPermission(MANAGE_DISPLAYS, "Permission required to get signals about connection events."); } @@ -4399,7 +4409,7 @@ public final class DisplayManagerService extends SystemService { final long token = Binder.clearCallingIdentity(); try { - registerCallbackInternal(callback, callingPid, callingUid, eventFlagsMask); + registerCallbackInternal(callback, callingPid, callingUid, internalEventFlagsMask); } finally { Binder.restoreCallingIdentity(token); } diff --git a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java index 88562ab9ba2d..8423e1911764 100644 --- a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java +++ b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java @@ -2077,8 +2077,8 @@ public class DisplayModeDirector { mDeviceConfigDisplaySettings.startListening(); mInjector.registerDisplayListener(this, mHandler, - DisplayManager.EVENT_FLAG_DISPLAY_CHANGED - | DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS); + DisplayManager.EVENT_FLAG_DISPLAY_CHANGED, + DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS); } private void setLoggingEnabled(boolean loggingEnabled) { @@ -2878,8 +2878,8 @@ public class DisplayModeDirector { } mDisplayManagerInternal = mInjector.getDisplayManagerInternal(); mInjector.registerDisplayListener(this, mHandler, - DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS - | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED); + DisplayManager.EVENT_FLAG_DISPLAY_REMOVED, + DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS); } /** @@ -3108,6 +3108,9 @@ public class DisplayModeDirector { void registerDisplayListener(@NonNull DisplayManager.DisplayListener listener, Handler handler, long flags); + void registerDisplayListener(@NonNull DisplayManager.DisplayListener listener, + Handler handler, long flags, long privateFlags); + Display getDisplay(int displayId); Display[] getDisplays(); @@ -3175,6 +3178,12 @@ public class DisplayModeDirector { } @Override + public void registerDisplayListener(DisplayManager.DisplayListener listener, + Handler handler, long flags, long privateFlags) { + getDisplayManager().registerDisplayListener(listener, handler, flags, privateFlags); + } + + @Override public Display getDisplay(int displayId) { return getDisplayManager().getDisplay(displayId); } diff --git a/services/core/java/com/android/server/flags/services.aconfig b/services/core/java/com/android/server/flags/services.aconfig index 69ba785b3b4f..eea5c982c537 100644 --- a/services/core/java/com/android/server/flags/services.aconfig +++ b/services/core/java/com/android/server/flags/services.aconfig @@ -67,3 +67,14 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + namespace: "backstage_power" + name: "rate_limit_battery_changed_broadcast" + description: "Optimize the delivery of the battery changed broadcast by rate limiting the frequency of the updates" + bug: "362337621" + is_fixed_read_only: true + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 5fc3e332b95c..05bc69a9f1f0 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -1015,7 +1015,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { permission, attributionSource, message, forDataDelivery, startDataDelivery, fromDatasource, attributedOp); // Finish any started op if some step in the attribution chain failed. - if (startDataDelivery && result != PermissionChecker.PERMISSION_GRANTED) { + if (startDataDelivery && result != PermissionChecker.PERMISSION_GRANTED + && result != PermissionChecker.PERMISSION_SOFT_DENIED) { if (attributedOp == AppOpsManager.OP_NONE) { finishDataDelivery(AppOpsManager.permissionToOpCode(permission), attributionSource.asState(), fromDatasource); @@ -1244,6 +1245,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { final boolean hasChain = attributionChainId != ATTRIBUTION_CHAIN_ID_NONE; AttributionSource current = attributionSource; AttributionSource next = null; + AttributionSource prev = null; // We consider the chain trusted if the start node has UPDATE_APP_OPS_STATS, and // every attributionSource in the chain is registered with the system. final boolean isChainStartTrusted = !hasChain || checkPermission(context, @@ -1310,6 +1312,22 @@ public class PermissionManagerService extends IPermissionManager.Stub { selfAccess, singleReceiverFromDatasource, attributedOp, proxyAttributionFlags, proxiedAttributionFlags, attributionChainId); + if (startDataDelivery && opMode != AppOpsManager.MODE_ALLOWED) { + // Current failed the perm check, so if we are part-way through an attr chain, + // we need to clean up the already started proxy op higher up the chain. Note, + // proxy ops are verified two by two, which means we have to clear the 2nd next + // from the previous iteration (since it is actually curr.next which failed + // to pass the perm check). + if (prev != null) { + final var cutAttrSourceState = prev.asState(); + if (cutAttrSourceState.next.length > 0) { + cutAttrSourceState.next[0].next = new AttributionSourceState[0]; + } + finishDataDelivery(context, attributedOp, + cutAttrSourceState, fromDatasource); + } + } + switch (opMode) { case AppOpsManager.MODE_ERRORED: { if (permission.equals(Manifest.permission.BLUETOOTH_CONNECT)) { @@ -1335,6 +1353,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { return PermissionChecker.PERMISSION_GRANTED; } + // an attribution we have already possibly started an op for + prev = current; current = next; } } diff --git a/services/core/java/com/android/server/vcn/VcnContext.java b/services/core/java/com/android/server/vcn/VcnContext.java index 6ce868540070..9213d96ad4ca 100644 --- a/services/core/java/com/android/server/vcn/VcnContext.java +++ b/services/core/java/com/android/server/vcn/VcnContext.java @@ -74,10 +74,6 @@ public class VcnContext { return mFeatureFlags; } - public boolean isFlagSafeModeTimeoutConfigEnabled() { - return mFeatureFlags.safeModeTimeoutConfig(); - } - /** * Verifies that the caller is running on the VcnContext Thread. * diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java index 2d3bc84debff..2325f358e301 100644 --- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java +++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java @@ -1263,7 +1263,7 @@ public class VcnGatewayConnection extends StateMachine { final PersistableBundleWrapper carrierConfig = snapshot.getCarrierConfigForSubGrp(subGrp); int resultSeconds = defaultSeconds; - if (vcnContext.isFlagSafeModeTimeoutConfigEnabled() && carrierConfig != null) { + if (carrierConfig != null) { resultSeconds = carrierConfig.getInt( VcnManager.VCN_SAFE_MODE_TIMEOUT_SECONDS_KEY, defaultSeconds); diff --git a/services/tests/displayservicetests/src/com/android/server/display/BrightnessSynchronizerTest.java b/services/tests/displayservicetests/src/com/android/server/display/BrightnessSynchronizerTest.java index 06f1b27410ff..a8708f9f9e6e 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/BrightnessSynchronizerTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/BrightnessSynchronizerTest.java @@ -223,7 +223,8 @@ public class BrightnessSynchronizerTest { mIntRangeUserPerceptionEnabled); mSynchronizer.startSynchronizing(); verify(mDisplayManagerMock).registerDisplayListener(mDisplayListenerCaptor.capture(), - isA(Handler.class), eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS)); + isA(Handler.class), eq(0L), + eq(DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS)); mDisplayListener = mDisplayListenerCaptor.getValue(); verify(mContentResolverSpy).registerContentObserver(eq(BRIGHTNESS_URI), eq(false), diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java index b917af4d796e..c741cae1c135 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java @@ -203,11 +203,13 @@ public class DisplayManagerServiceTest { private static final String VIRTUAL_DISPLAY_NAME = "Test Virtual Display"; private static final String PACKAGE_NAME = "com.android.frameworks.displayservicetests"; - private static final long STANDARD_DISPLAY_EVENTS = DisplayManager.EVENT_FLAG_DISPLAY_ADDED - | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED - | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED; + private static final long STANDARD_DISPLAY_EVENTS = + DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED + | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CHANGED + | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REMOVED; private static final long STANDARD_AND_CONNECTION_DISPLAY_EVENTS = - STANDARD_DISPLAY_EVENTS | DisplayManager.EVENT_FLAG_DISPLAY_CONNECTION_CHANGED; + STANDARD_DISPLAY_EVENTS + | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED; private static final String EVENT_DISPLAY_ADDED = "EVENT_DISPLAY_ADDED"; private static final String EVENT_DISPLAY_REMOVED = "EVENT_DISPLAY_REMOVED"; @@ -2379,7 +2381,7 @@ public class DisplayManagerServiceTest { // register display listener callback FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback(); long allEventsExceptDisplayAdded = STANDARD_DISPLAY_EVENTS - & ~DisplayManager.EVENT_FLAG_DISPLAY_ADDED; + & ~DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED; displayManagerBinderService.registerCallbackWithEventMask(callback, allEventsExceptDisplayAdded); @@ -2450,7 +2452,7 @@ public class DisplayManagerServiceTest { FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback(); long allEventsExceptDisplayRemoved = STANDARD_DISPLAY_EVENTS - & ~DisplayManager.EVENT_FLAG_DISPLAY_REMOVED; + & ~DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REMOVED; displayManagerBinderService.registerCallbackWithEventMask(callback, allEventsExceptDisplayRemoved); diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java index 58f0ab4411bc..f3fc6d747d78 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java @@ -1225,8 +1225,8 @@ public class DisplayModeDirectorTest { ArgumentCaptor.forClass(DisplayListener.class); verify(mInjector).registerDisplayListener(displayListenerCaptor.capture(), any(Handler.class), - eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED - | DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS)); + eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED), + eq(DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS)); DisplayListener displayListener = displayListenerCaptor.getValue(); setBrightness(10, 10, displayListener); @@ -1256,8 +1256,8 @@ public class DisplayModeDirectorTest { ArgumentCaptor.forClass(DisplayListener.class); verify(mInjector).registerDisplayListener(displayListenerCaptor.capture(), any(Handler.class), - eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED - | DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS)); + eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED), + eq(DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS)); DisplayListener displayListener = displayListenerCaptor.getValue(); setBrightness(10, 10, displayListener); @@ -1291,8 +1291,8 @@ public class DisplayModeDirectorTest { ArgumentCaptor.forClass(DisplayListener.class); verify(mInjector).registerDisplayListener(displayListenerCaptor.capture(), any(Handler.class), - eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED - | DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS)); + eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED), + eq(DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS)); DisplayListener displayListener = displayListenerCaptor.getValue(); setBrightness(10, 10, displayListener); @@ -1325,8 +1325,8 @@ public class DisplayModeDirectorTest { ArgumentCaptor.forClass(DisplayListener.class); verify(mInjector).registerDisplayListener(displayListenerCaptor.capture(), any(Handler.class), - eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED - | DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS)); + eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED), + eq(DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS)); DisplayListener displayListener = displayListenerCaptor.getValue(); ArgumentCaptor<SensorEventListener> sensorListenerCaptor = @@ -1404,8 +1404,8 @@ public class DisplayModeDirectorTest { ArgumentCaptor.forClass(DisplayListener.class); verify(mInjector).registerDisplayListener(displayListenerCaptor.capture(), any(Handler.class), - eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED - | DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS)); + eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED), + eq(DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS)); DisplayListener displayListener = displayListenerCaptor.getValue(); ArgumentCaptor<SensorEventListener> sensorListenerCaptor = @@ -1464,8 +1464,8 @@ public class DisplayModeDirectorTest { ArgumentCaptor.forClass(DisplayListener.class); verify(mInjector).registerDisplayListener(displayListenerCaptor.capture(), any(Handler.class), - eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED - | DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS)); + eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED), + eq(DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS)); DisplayListener displayListener = displayListenerCaptor.getValue(); ArgumentCaptor<SensorEventListener> listenerCaptor = @@ -1630,8 +1630,8 @@ public class DisplayModeDirectorTest { ArgumentCaptor.forClass(DisplayListener.class); verify(mInjector).registerDisplayListener(displayListenerCaptor.capture(), any(Handler.class), - eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED - | DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS)); + eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED), + eq(DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS)); DisplayListener displayListener = displayListenerCaptor.getValue(); // Get the sensor listener so that we can give it new light sensor events @@ -1730,8 +1730,8 @@ public class DisplayModeDirectorTest { ArgumentCaptor.forClass(DisplayListener.class); verify(mInjector).registerDisplayListener(displayListenerCaptor.capture(), any(Handler.class), - eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED - | DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS)); + eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED), + eq(DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS)); DisplayListener displayListener = displayListenerCaptor.getValue(); // Get the sensor listener so that we can give it new light sensor events @@ -2877,8 +2877,8 @@ public class DisplayModeDirectorTest { ArgumentCaptor<DisplayListener> captor = ArgumentCaptor.forClass(DisplayListener.class); verify(mInjector).registerDisplayListener(captor.capture(), any(Handler.class), - eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS - | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED)); + eq(DisplayManager.EVENT_FLAG_DISPLAY_REMOVED), + eq(DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS)); DisplayListener listener = captor.getValue(); // Specify Limitation @@ -3000,8 +3000,8 @@ public class DisplayModeDirectorTest { ArgumentCaptor<DisplayListener> captor = ArgumentCaptor.forClass(DisplayListener.class); verify(mInjector).registerDisplayListener(captor.capture(), any(Handler.class), - eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS - | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED)); + eq(DisplayManager.EVENT_FLAG_DISPLAY_REMOVED), + eq(DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS)); DisplayListener listener = captor.getValue(); final int initialRefreshRate = 60; @@ -3075,8 +3075,8 @@ public class DisplayModeDirectorTest { ArgumentCaptor<DisplayListener> captor = ArgumentCaptor.forClass(DisplayListener.class); verify(mInjector).registerDisplayListener(captor.capture(), any(Handler.class), - eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS - | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED)); + eq(DisplayManager.EVENT_FLAG_DISPLAY_REMOVED), + eq(DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS)); DisplayListener listener = captor.getValue(); // Specify Limitation for different display @@ -3115,8 +3115,8 @@ public class DisplayModeDirectorTest { ArgumentCaptor<DisplayListener> captor = ArgumentCaptor.forClass(DisplayListener.class); verify(mInjector).registerDisplayListener(captor.capture(), any(Handler.class), - eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS - | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED)); + eq(DisplayManager.EVENT_FLAG_DISPLAY_REMOVED), + eq(DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS)); DisplayListener listener = captor.getValue(); // Specify Limitation @@ -3200,8 +3200,8 @@ public class DisplayModeDirectorTest { ArgumentCaptor<DisplayListener> captor = ArgumentCaptor.forClass(DisplayListener.class); verify(mInjector).registerDisplayListener(captor.capture(), any(Handler.class), - eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS - | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED)); + eq(DisplayManager.EVENT_FLAG_DISPLAY_REMOVED), + eq(DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS)); DisplayListener listener = captor.getValue(); // Specify Sunlight limitations @@ -3239,8 +3239,8 @@ public class DisplayModeDirectorTest { ArgumentCaptor<DisplayListener> captor = ArgumentCaptor.forClass(DisplayListener.class); verify(mInjector).registerDisplayListener(captor.capture(), any(Handler.class), - eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS - | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED)); + eq(DisplayManager.EVENT_FLAG_DISPLAY_REMOVED), + eq(DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS)); DisplayListener listener = captor.getValue(); // Specify Limitation for different display @@ -3897,7 +3897,12 @@ public class DisplayModeDirectorTest { public void registerDisplayListener(DisplayListener listener, Handler handler) {} @Override - public void registerDisplayListener(DisplayListener listener, Handler handler, long flag) {} + public void registerDisplayListener(DisplayListener listener, Handler handler, + long flags) {} + + @Override + public void registerDisplayListener(DisplayListener listener, Handler handler, long flag, + long privateFlag) {} @Override public Display getDisplay(int displayId) { diff --git a/services/tests/mockingservicestests/src/com/android/server/BatteryServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/BatteryServiceTest.java new file mode 100644 index 000000000000..5e2f80bf8311 --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/BatteryServiceTest.java @@ -0,0 +1,338 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server; + +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; + +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.when; + +import android.app.ActivityManager; +import android.app.ActivityManagerInternal; +import android.app.AppOpsManager; +import android.content.Context; +import android.hardware.health.HealthInfo; +import android.os.HandlerThread; +import android.os.SystemClock; +import android.os.SystemProperties; +import android.os.UserHandle; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; + +import com.android.dx.mockito.inline.extended.ExtendedMockito; +import com.android.internal.R; +import com.android.internal.app.IBatteryStats; +import com.android.modules.utils.testing.ExtendedMockitoRule; +import com.android.server.am.BatteryStatsService; +import com.android.server.flags.Flags; +import com.android.server.lights.LightsManager; +import com.android.server.lights.LogicalLight; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +@RunWith(AndroidJUnit4.class) +public class BatteryServiceTest { + + private static final int CURRENT_BATTERY_VOLTAGE = 3000; + private static final int VOLTAGE_LESS_THEN_ONE_PERCENT = 3029; + private static final int VOLTAGE_MORE_THEN_ONE_PERCENT = 3030; + private static final int CURRENT_BATTERY_TEMP = 300; + private static final int TEMP_LESS_THEN_ONE_DEGREE_CELSIUS = 305; + private static final int TEMP_MORE_THEN_ONE_DEGREE_CELSIUS = 310; + private static final int CURRENT_BATTERY_HEALTH = 2; + private static final int UPDATED_BATTERY_HEALTH = 3; + private static final int CURRENT_CHARGE_COUNTER = 4680000; + private static final int UPDATED_CHARGE_COUNTER = 4218000; + private static final int HANDLER_IDLE_TIME_MS = 5000; + @Rule + public final ExtendedMockitoRule mExtendedMockitoRule = new ExtendedMockitoRule.Builder(this) + .mockStatic(SystemProperties.class) + .mockStatic(ActivityManager.class) + .mockStatic(BatteryStatsService.class) + .build(); + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + @Mock + private Context mContextMock; + @Mock + private LightsManager mLightsManagerMock; + @Mock + private ActivityManagerInternal mActivityManagerInternalMock; + @Mock + private IBatteryStats mIBatteryStatsMock; + + private BatteryService mBatteryService; + private String mSystemUiPackage; + + /** + * Creates a mock and registers it to {@link LocalServices}. + */ + private static <T> void addLocalServiceMock(Class<T> clazz, T mock) { + LocalServices.removeServiceForTest(clazz); + LocalServices.addService(clazz, mock); + } + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + mSystemUiPackage = InstrumentationRegistry.getInstrumentation().getTargetContext() + .getResources().getString(R.string.config_systemUi); + + when(mLightsManagerMock.getLight(anyInt())).thenReturn(mock(LogicalLight.class)); + when(mActivityManagerInternalMock.isSystemReady()).thenReturn(true); + when(mContextMock.getResources()).thenReturn( + InstrumentationRegistry.getInstrumentation().getTargetContext().getResources()); + ExtendedMockito.when(BatteryStatsService.getService()).thenReturn(mIBatteryStatsMock); + + doNothing().when(mIBatteryStatsMock).setBatteryState(anyInt(), anyInt(), anyInt(), anyInt(), + anyInt(), anyInt(), anyInt(), anyInt(), anyLong()); + doNothing().when(() -> SystemProperties.set(anyString(), anyString())); + doNothing().when(() -> ActivityManager.broadcastStickyIntent(any(), + eq(new String[]{mSystemUiPackage}), eq(AppOpsManager.OP_NONE), + eq(BatteryService.BATTERY_CHANGED_OPTIONS), eq(UserHandle.USER_ALL))); + + addLocalServiceMock(LightsManager.class, mLightsManagerMock); + addLocalServiceMock(ActivityManagerInternal.class, mActivityManagerInternalMock); + + createBatteryService(); + } + + @Test + public void createBatteryService_withNullLooper_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> new BatteryService(mContextMock)); + } + + @Test + @EnableFlags(Flags.FLAG_RATE_LIMIT_BATTERY_CHANGED_BROADCAST) + public void onlyVoltageUpdated_lessThenOnePercent_broadcastNotSent() { + mBatteryService.update(createHealthInfo(VOLTAGE_LESS_THEN_ONE_PERCENT, CURRENT_BATTERY_TEMP, + CURRENT_CHARGE_COUNTER, CURRENT_BATTERY_HEALTH)); + + waitForHandlerToExecute(); + + verifyNumberOfTimesBroadcastSent(0); + } + + @Test + @EnableFlags(Flags.FLAG_RATE_LIMIT_BATTERY_CHANGED_BROADCAST) + public void onlyVoltageUpdated_beforeTwentySeconds_broadcastNotSent() { + mBatteryService.update( + createHealthInfo(VOLTAGE_MORE_THEN_ONE_PERCENT, CURRENT_BATTERY_TEMP, + CURRENT_CHARGE_COUNTER, + CURRENT_BATTERY_HEALTH)); + + waitForHandlerToExecute(); + + verifyNumberOfTimesBroadcastSent(0); + } + + @Test + @EnableFlags(Flags.FLAG_RATE_LIMIT_BATTERY_CHANGED_BROADCAST) + public void onlyVoltageUpdated_broadcastSent() { + mBatteryService.mLastBroadcastVoltageUpdateTime = SystemClock.elapsedRealtime() - 20000; + mBatteryService.update(createHealthInfo(VOLTAGE_MORE_THEN_ONE_PERCENT, CURRENT_BATTERY_TEMP, + CURRENT_CHARGE_COUNTER, CURRENT_BATTERY_HEALTH)); + + waitForHandlerToExecute(); + + verifyNumberOfTimesBroadcastSent(1); + } + + @Test + @EnableFlags(Flags.FLAG_RATE_LIMIT_BATTERY_CHANGED_BROADCAST) + public void onlyTempUpdated_lessThenOneDegreeCelsius_broadcastNotSent() { + mBatteryService.update( + createHealthInfo(CURRENT_BATTERY_VOLTAGE, TEMP_LESS_THEN_ONE_DEGREE_CELSIUS, + CURRENT_CHARGE_COUNTER, CURRENT_BATTERY_HEALTH)); + + waitForHandlerToExecute(); + + verifyNumberOfTimesBroadcastSent(0); + } + + @Test + @EnableFlags(Flags.FLAG_RATE_LIMIT_BATTERY_CHANGED_BROADCAST) + public void tempUpdated_broadcastSent() { + long lastVoltageUpdateTime = mBatteryService.mLastBroadcastVoltageUpdateTime; + mBatteryService.update( + createHealthInfo(VOLTAGE_LESS_THEN_ONE_PERCENT, TEMP_MORE_THEN_ONE_DEGREE_CELSIUS, + UPDATED_CHARGE_COUNTER, CURRENT_BATTERY_HEALTH)); + + waitForHandlerToExecute(); + + assertTrue(lastVoltageUpdateTime < mBatteryService.mLastBroadcastVoltageUpdateTime); + verifyNumberOfTimesBroadcastSent(1); + } + + @Test + @EnableFlags(Flags.FLAG_RATE_LIMIT_BATTERY_CHANGED_BROADCAST) + public void batteryHealthUpdated_voltageAndTempConst_broadcastSent() { + mBatteryService.update( + createHealthInfo(CURRENT_BATTERY_VOLTAGE, CURRENT_BATTERY_TEMP, + CURRENT_CHARGE_COUNTER, + UPDATED_BATTERY_HEALTH)); + + waitForHandlerToExecute(); + + verifyNumberOfTimesBroadcastSent(1); + + // updating counter just after the health update does not triggers broadcast. + mBatteryService.update( + createHealthInfo(CURRENT_BATTERY_VOLTAGE, CURRENT_BATTERY_TEMP, + UPDATED_CHARGE_COUNTER, + UPDATED_BATTERY_HEALTH)); + + waitForHandlerToExecute(); + + verifyNumberOfTimesBroadcastSent(1); + } + + @Test + @DisableFlags(Flags.FLAG_RATE_LIMIT_BATTERY_CHANGED_BROADCAST) + public void voltageUpdated_lessThanOnePercent_flagDisabled_broadcastSent() { + mBatteryService.update(createHealthInfo(VOLTAGE_LESS_THEN_ONE_PERCENT, CURRENT_BATTERY_TEMP, + CURRENT_CHARGE_COUNTER, CURRENT_BATTERY_HEALTH)); + + waitForHandlerToExecute(); + + verifyNumberOfTimesBroadcastSent(1); + } + + @Test + @EnableFlags(Flags.FLAG_RATE_LIMIT_BATTERY_CHANGED_BROADCAST) + public void onlyChargeCounterUpdated_broadcastNotSent() { + mBatteryService.update( + createHealthInfo(CURRENT_BATTERY_VOLTAGE, CURRENT_BATTERY_TEMP, + UPDATED_CHARGE_COUNTER, + CURRENT_BATTERY_HEALTH)); + + waitForHandlerToExecute(); + + verifyNumberOfTimesBroadcastSent(0); + } + + @Test + @EnableFlags(Flags.FLAG_RATE_LIMIT_BATTERY_CHANGED_BROADCAST) + public void chargeCounterUpdated_tempUpdatedLessThanOneDegree_broadcastNotSent() { + mBatteryService.update( + createHealthInfo(CURRENT_BATTERY_VOLTAGE, TEMP_LESS_THEN_ONE_DEGREE_CELSIUS, + UPDATED_CHARGE_COUNTER, + CURRENT_BATTERY_HEALTH)); + + waitForHandlerToExecute(); + + verifyNumberOfTimesBroadcastSent(0); + } + + @Test + @DisableFlags(Flags.FLAG_RATE_LIMIT_BATTERY_CHANGED_BROADCAST) + public void onlyChargeCounterUpdated_broadcastSent() { + mBatteryService.update( + createHealthInfo(CURRENT_BATTERY_VOLTAGE, CURRENT_BATTERY_TEMP, + UPDATED_CHARGE_COUNTER, + CURRENT_BATTERY_HEALTH)); + + waitForHandlerToExecute(); + + verifyNumberOfTimesBroadcastSent(1); + } + + private HealthInfo createHealthInfo( + int batteryVoltage, + int batteryTemperature, + int batteryChargeCounter, + int batteryHealth) { + HealthInfo h = new HealthInfo(); + h.batteryVoltageMillivolts = batteryVoltage; + h.batteryTemperatureTenthsCelsius = batteryTemperature; + h.batteryChargeCounterUah = batteryChargeCounter; + h.batteryStatus = 5; + h.batteryHealth = batteryHealth; + h.batteryPresent = true; + h.batteryLevel = 100; + h.maxChargingCurrentMicroamps = 298125; + h.batteryCurrentAverageMicroamps = -2812; + h.batteryCurrentMicroamps = 298125; + h.maxChargingVoltageMicrovolts = 3000; + h.batteryCycleCount = 50; + h.chargingState = 4; + h.batteryCapacityLevel = 100; + return h; + } + + // Creates a new battery service objects and sets the initial values. + private void createBatteryService() throws InterruptedException { + final HandlerThread handlerThread = new HandlerThread("BatteryServiceTest"); + handlerThread.start(); + + mBatteryService = new BatteryService(mContextMock, handlerThread.getLooper()); + + // trigger the update to set the initial values. + mBatteryService.update( + createHealthInfo(CURRENT_BATTERY_VOLTAGE, CURRENT_BATTERY_TEMP, + CURRENT_CHARGE_COUNTER, + CURRENT_BATTERY_HEALTH)); + + waitForHandlerToExecute(); + } + + private void waitForHandlerToExecute() { + final CountDownLatch latch = new CountDownLatch(1); + mBatteryService.getHandlerForTest().post(latch::countDown); + boolean isExecutionComplete = false; + + try { + isExecutionComplete = latch.await(HANDLER_IDLE_TIME_MS, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + fail("Handler interrupted before executing the message " + e); + } + + assertTrue("Timed out while waiting for Handler to execute.", isExecutionComplete); + } + + private void verifyNumberOfTimesBroadcastSent(int numberOfTimes) { + // Increase the numberOfTimes by 1 as one broadcast was sent initially during the test + // setUp. + verify(() -> ActivityManager.broadcastStickyIntent(any(), + eq(new String[]{mSystemUiPackage}), eq(AppOpsManager.OP_NONE), + eq(BatteryService.BATTERY_CHANGED_OPTIONS), eq(UserHandle.USER_ALL)), + times(++numberOfTimes)); + } +} diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java index 49665f7a3304..613b92616707 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java @@ -360,12 +360,10 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { private void verifyGetSafeModeTimeoutMs( boolean isInTestMode, - boolean isConfigTimeoutSupported, PersistableBundleWrapper carrierConfig, long expectedTimeoutMs) throws Exception { doReturn(isInTestMode).when(mVcnContext).isInTestMode(); - doReturn(isConfigTimeoutSupported).when(mVcnContext).isFlagSafeModeTimeoutConfigEnabled(); final TelephonySubscriptionSnapshot snapshot = mock(TelephonySubscriptionSnapshot.class); doReturn(carrierConfig).when(snapshot).getCarrierConfigForSubGrp(TEST_SUB_GRP); @@ -377,16 +375,7 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { } @Test - public void testGetSafeModeTimeoutMs_configTimeoutUnsupported() throws Exception { - verifyGetSafeModeTimeoutMs( - false /* isInTestMode */, - false /* isConfigTimeoutSupported */, - null /* carrierConfig */, - TimeUnit.SECONDS.toMillis(SAFEMODE_TIMEOUT_SECONDS)); - } - - @Test - public void testGetSafeModeTimeoutMs_configTimeoutSupported() throws Exception { + public void testGetSafeModeTimeoutMs() throws Exception { final int carrierConfigTimeoutSeconds = 20; final PersistableBundleWrapper carrierConfig = mock(PersistableBundleWrapper.class); doReturn(carrierConfigTimeoutSeconds) @@ -395,17 +384,14 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { verifyGetSafeModeTimeoutMs( false /* isInTestMode */, - true /* isConfigTimeoutSupported */, carrierConfig, TimeUnit.SECONDS.toMillis(carrierConfigTimeoutSeconds)); } @Test - public void testGetSafeModeTimeoutMs_configTimeoutSupported_carrierConfigNull() - throws Exception { + public void testGetSafeModeTimeoutMs_carrierConfigNull() throws Exception { verifyGetSafeModeTimeoutMs( false /* isInTestMode */, - true /* isConfigTimeoutSupported */, null /* carrierConfig */, TimeUnit.SECONDS.toMillis(SAFEMODE_TIMEOUT_SECONDS)); } @@ -420,7 +406,6 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { verifyGetSafeModeTimeoutMs( true /* isInTestMode */, - true /* isConfigTimeoutSupported */, carrierConfig, TimeUnit.SECONDS.toMillis(carrierConfigTimeoutSeconds)); } diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index 4c7b25aaa7c3..8374fd944568 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -222,7 +222,6 @@ public class VcnGatewayConnectionTestBase { doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper(); doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider(); doReturn(mFeatureFlags).when(mVcnContext).getFeatureFlags(); - doReturn(true).when(mVcnContext).isFlagSafeModeTimeoutConfigEnabled(); doReturn(mUnderlyingNetworkController) .when(mDeps) |