From e9cf5e7002cb576581db0552d179b849fbe31800 Mon Sep 17 00:00:00 2001 From: Julian Winkler Date: Wed, 27 Nov 2024 14:59:37 +0100 Subject: [PATCH] API stubs and fixes for composeUI --- .../graphics/android_graphics_GskCanvas.c | 3 + src/api-impl-jni/util.c | 2 + src/api-impl-jni/util.h | 2 + src/api-impl-jni/widgets/WrapperWidget.c | 6 +- src/api-impl/android/content/Context.java | 2 + .../android/content/pm/PackageManager.java | 25 +- .../android/content/pm/PackageParser.java | 15 +- .../android/content/pm/ResolveInfo.java | 1 + src/api-impl/android/graphics/Canvas.java | 21 ++ src/api-impl/android/graphics/Outline.java | 10 + src/api-impl/android/graphics/Paint.java | 6 + src/api-impl/android/graphics/Typeface.java | 4 + .../android/graphics/drawable/Drawable.java | 2 + .../graphics/drawable/RippleDrawable.java | 2 + .../android/media/AudioAttributes.java | 8 + .../media/session/MediaController.java | 4 + .../android/media/session/MediaSession.java | 5 +- src/api-impl/android/os/Binder.java | 8 +- src/api-impl/android/os/IBinder.java | 6 +- src/api-impl/android/os/Parcel.java | 12 + src/api-impl/android/os/Parcelable.java | 4 + src/api-impl/android/provider/Settings.java | 5 + src/api-impl/android/text/BoringLayout.java | 10 + src/api-impl/android/text/Layout.java | 30 ++ .../android/text/TextDirectionHeuristic.java | 4 +- .../android/text/TextDirectionHeuristics.java | 14 +- src/api-impl/android/text/TextPaint.java | 4 + .../android/util/SparseLongArray.java | 259 ++++++++++++++++++ src/api-impl/android/view/MotionEvent.java | 6 +- src/api-impl/android/view/View.java | 67 ++++- src/api-impl/android/view/ViewGroup.java | 14 + .../accessibility/AccessibilityManager.java | 6 + .../AccessibilityNodeProvider.java | 4 + .../view/inputmethod/CursorAnchorInfo.java | 7 + src/api-impl/meson.build | 5 + 35 files changed, 559 insertions(+), 24 deletions(-) create mode 100644 src/api-impl/android/graphics/Outline.java create mode 100644 src/api-impl/android/text/BoringLayout.java create mode 100644 src/api-impl/android/util/SparseLongArray.java create mode 100644 src/api-impl/android/view/accessibility/AccessibilityNodeProvider.java create mode 100644 src/api-impl/android/view/inputmethod/CursorAnchorInfo.java diff --git a/src/api-impl-jni/graphics/android_graphics_GskCanvas.c b/src/api-impl-jni/graphics/android_graphics_GskCanvas.c index b19b67bd..2074a381 100644 --- a/src/api-impl-jni/graphics/android_graphics_GskCanvas.c +++ b/src/api-impl-jni/graphics/android_graphics_GskCanvas.c @@ -85,6 +85,9 @@ JNIEXPORT void JNICALL Java_android_graphics_GskCanvas_native_1restore(JNIEnv *e JNIEXPORT void JNICALL Java_android_graphics_GskCanvas_native_1drawLine(JNIEnv *env, jclass this_class, jlong snapshot_ptr, jfloat x0, jfloat y0, jfloat x1, jfloat y1, jlong paint_ptr) { + if (isnan(x0) || isnan(y0) || isnan(x1) || isnan(y1)) { + return; + } GdkSnapshot *snapshot = GTK_SNAPSHOT(_PTR(snapshot_ptr)); sk_paint_t *paint = (sk_paint_t *)_PTR(paint_ptr); GdkRGBA gdk_color; diff --git a/src/api-impl-jni/util.c b/src/api-impl-jni/util.c index 9bed4d1f..d8728f15 100644 --- a/src/api-impl-jni/util.c +++ b/src/api-impl-jni/util.c @@ -119,6 +119,7 @@ void set_up_handle_cache(JNIEnv *env) if((*env)->ExceptionCheck(env)) (*env)->ExceptionDescribe(env); handle_cache.view.onDraw = _METHOD(handle_cache.view.class, "onDraw", "(Landroid/graphics/Canvas;)V"); + handle_cache.view.dispatchDraw = _METHOD(handle_cache.view.class, "dispatchDraw", "(Landroid/graphics/Canvas;)V"); handle_cache.view.draw = _METHOD(handle_cache.view.class, "draw", "(Landroid/graphics/Canvas;)V"); handle_cache.view.onMeasure = _METHOD(handle_cache.view.class, "onMeasure", "(II)V"); handle_cache.view.onLayout = _METHOD(handle_cache.view.class, "onLayout", "(ZIIII)V"); @@ -133,6 +134,7 @@ void set_up_handle_cache(JNIEnv *env) handle_cache.view.getScrollY = _METHOD(handle_cache.view.class, "getScrollY", "()I"); handle_cache.view.performClick = _METHOD(handle_cache.view.class, "performClick", "()Z"); handle_cache.view.onTouchEvent = _METHOD(handle_cache.view.class, "onTouchEvent", "(Landroid/view/MotionEvent;)Z"); + handle_cache.view.dispatchTouchEvent = _METHOD(handle_cache.view.class, "dispatchTouchEvent", "(Landroid/view/MotionEvent;)Z"); handle_cache.view.onInterceptTouchEvent = _METHOD(handle_cache.view.class, "onInterceptTouchEvent", "(Landroid/view/MotionEvent;)Z"); handle_cache.view.layoutInternal = _METHOD(handle_cache.view.class, "layoutInternal", "(II)V"); handle_cache.view.measure = _METHOD(handle_cache.view.class, "measure", "(II)V"); diff --git a/src/api-impl-jni/util.h b/src/api-impl-jni/util.h index 5776d4e3..dff95a46 100644 --- a/src/api-impl-jni/util.h +++ b/src/api-impl-jni/util.h @@ -65,6 +65,7 @@ struct handle_cache { jclass class; jmethodID setLayoutParams; jmethodID onDraw; + jmethodID dispatchDraw; jmethodID draw; jmethodID onMeasure; jmethodID onLayout; @@ -79,6 +80,7 @@ struct handle_cache { jmethodID getScrollY; jmethodID performClick; jmethodID onTouchEvent; + jmethodID dispatchTouchEvent; jmethodID onInterceptTouchEvent; jmethodID layoutInternal; jmethodID measure; diff --git a/src/api-impl-jni/widgets/WrapperWidget.c b/src/api-impl-jni/widgets/WrapperWidget.c index ca8d1bb8..e7581585 100644 --- a/src/api-impl-jni/widgets/WrapperWidget.c +++ b/src/api-impl-jni/widgets/WrapperWidget.c @@ -279,8 +279,9 @@ void wrapper_widget_set_jobject(WrapperWidget *wrapper, JNIEnv *env, jobject job wrapper->jvm = jvm; wrapper->jobj = _WEAK_REF(jobj); jmethodID on_draw_method = _METHOD(_CLASS(jobj), "onDraw", "(Landroid/graphics/Canvas;)V"); + jmethodID dispatch_draw_method = _METHOD(_CLASS(jobj), "dispatchDraw", "(Landroid/graphics/Canvas;)V"); jmethodID draw_method = _METHOD(_CLASS(jobj), "draw", "(Landroid/graphics/Canvas;)V"); - if (on_draw_method != handle_cache.view.onDraw || draw_method != handle_cache.view.draw) { + if (on_draw_method != handle_cache.view.onDraw || draw_method != handle_cache.view.draw || dispatch_draw_method != handle_cache.view.dispatchDraw) { wrapper->draw_method = draw_method; jclass canvas_class = (*env)->FindClass(env, "android/graphics/GskCanvas"); jmethodID canvas_constructor = _METHOD(canvas_class, "", "(J)V"); @@ -289,7 +290,8 @@ void wrapper_widget_set_jobject(WrapperWidget *wrapper, JNIEnv *env, jobject job } jmethodID ontouchevent_method = _METHOD(_CLASS(jobj), "onTouchEvent", "(Landroid/view/MotionEvent;)Z"); - if (ontouchevent_method != handle_cache.view.onTouchEvent) { + jmethodID dispatchtouchevent_method = _METHOD(_CLASS(jobj), "dispatchTouchEvent", "(Landroid/view/MotionEvent;)Z"); + if (ontouchevent_method != handle_cache.view.onTouchEvent || dispatchtouchevent_method != handle_cache.view.dispatchTouchEvent) { _setOnTouchListener(env, jobj, GTK_WIDGET(wrapper)); } diff --git a/src/api-impl/android/content/Context.java b/src/api-impl/android/content/Context.java index 3a58e3de..80837a7a 100644 --- a/src/api-impl/android/content/Context.java +++ b/src/api-impl/android/content/Context.java @@ -478,6 +478,8 @@ public class Context extends Object { public void registerComponentCallbacks(ComponentCallbacks callbacks) {} + public void unregisterComponentCallbacks(ComponentCallbacks callbacks) {} + public boolean bindService(final Intent intent, final ServiceConnection serviceConnection, int dummy3) { if (intent.getComponent() == null) { Slog.w(TAG, "Context.bindService: intent.getComponent() is null"); diff --git a/src/api-impl/android/content/pm/PackageManager.java b/src/api-impl/android/content/pm/PackageManager.java index 071d3e70..ed3e5618 100644 --- a/src/api-impl/android/content/pm/PackageManager.java +++ b/src/api-impl/android/content/pm/PackageManager.java @@ -16,6 +16,12 @@ package android.content.pm; +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; + import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.content.ComponentName; @@ -23,6 +29,8 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.IntentSender; +import android.content.pm.PackageParser.Service; +import android.content.pm.PackageParser.ServiceIntentInfo; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.graphics.drawable.Drawable; @@ -32,11 +40,6 @@ import android.os.UserHandle; import android.util.AndroidException; import android.util.DisplayMetrics; import android.util.Slog; -import java.io.File; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; class IPackageInstallObserver {} class VerificationParams {} @@ -2321,7 +2324,17 @@ public class PackageManager { */ public List queryIntentServices(Intent intent, int flags) { - return new ArrayList(); + List list = new ArrayList(1); + for (Service s: Context.pkg.services) { + for (ServiceIntentInfo intentinfo: s.intents) { + if (s.getComponentName().equals(intent.getComponent()) || intentinfo.matchAction(intent.getAction())) { + ResolveInfo ri = new ResolveInfo(); + ri.serviceInfo = s.info; + list.add(ri); + } + } + } + return list; } /** diff --git a/src/api-impl/android/content/pm/PackageParser.java b/src/api-impl/android/content/pm/PackageParser.java index 83fedadf..59015493 100644 --- a/src/api-impl/android/content/pm/PackageParser.java +++ b/src/api-impl/android/content/pm/PackageParser.java @@ -3031,7 +3031,20 @@ public class PackageParser { continue; } - if (parser.getName().equals("meta-data")) { + if (parser.getName().equals("intent-filter")) { + ServiceIntentInfo intent = new ServiceIntentInfo(s); + if (!parseIntent(res, parser, attrs, true /*allowGlobs*/, true /*allowAutoVerify*/, + intent, outError)) { + return null; + } + if (intent.countActions() == 0) { + Slog.w(TAG, "No actions in intent filter at " + + mArchiveSourcePath + " " + + parser.getPositionDescription()); + } else { + s.intents.add(intent); + } + } else if (parser.getName().equals("meta-data")) { if ((s.metaData = parseMetaData(res, parser, attrs, s.metaData, outError)) == null) { return null; diff --git a/src/api-impl/android/content/pm/ResolveInfo.java b/src/api-impl/android/content/pm/ResolveInfo.java index 252eac1c..7ba07794 100644 --- a/src/api-impl/android/content/pm/ResolveInfo.java +++ b/src/api-impl/android/content/pm/ResolveInfo.java @@ -2,6 +2,7 @@ package android.content.pm; public class ResolveInfo { public ActivityInfo activityInfo = new ActivityInfo(); + public ServiceInfo serviceInfo = new ServiceInfo(); public static class DisplayNameComparator { diff --git a/src/api-impl/android/graphics/Canvas.java b/src/api-impl/android/graphics/Canvas.java index 65661a52..262fa315 100644 --- a/src/api-impl/android/graphics/Canvas.java +++ b/src/api-impl/android/graphics/Canvas.java @@ -470,6 +470,27 @@ public class Canvas { return false; } + public boolean clipRect(float left, float top, float right, float bottom) { + return false; + } + + public boolean isHardwareAccelerated() { + return false; + } + + public boolean clipRect(float left, float top, float right, float bottom, Region.Op op) { + return false; + } + + public void drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean includeCenter, Paint paint) {} + + public void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, Paint paint) {} + + public boolean getClipBounds(Rect outRect) { + outRect.set(0, 0, 100, 100); + return false; + } + private static native long native_canvas_from_bitmap(long pixbuf); private static native void native_save(long skia_canvas, long widget); diff --git a/src/api-impl/android/graphics/Outline.java b/src/api-impl/android/graphics/Outline.java new file mode 100644 index 00000000..50075376 --- /dev/null +++ b/src/api-impl/android/graphics/Outline.java @@ -0,0 +1,10 @@ +package android.graphics; + +public class Outline { + + public void setAlpha(float alpha) {} + + public void setEmpty() {} + + public void setRoundRect(int left, int top, int right, int bottom, float r) {} +} diff --git a/src/api-impl/android/graphics/Paint.java b/src/api-impl/android/graphics/Paint.java index eaa36369..9416ed10 100644 --- a/src/api-impl/android/graphics/Paint.java +++ b/src/api-impl/android/graphics/Paint.java @@ -284,6 +284,12 @@ public class Paint { public void set(Paint paint) {} + public boolean isFilterBitmap() { return false; } + + public Cap getStrokeCap() { return Cap.BUTT; } + + public Join getStrokeJoin() { return Join.MITER; } + private native long native_constructor(); private native void native_set_antialias(long skia_paint, boolean aa); private native void native_set_color(long skia_paint, int color); diff --git a/src/api-impl/android/graphics/Typeface.java b/src/api-impl/android/graphics/Typeface.java index 71838c94..e27f55f5 100644 --- a/src/api-impl/android/graphics/Typeface.java +++ b/src/api-impl/android/graphics/Typeface.java @@ -59,4 +59,8 @@ public class Typeface { public int getStyle() { return 0; } + + public static Typeface defaultFromStyle(int style) { + return create((String)null, style); + } } diff --git a/src/api-impl/android/graphics/drawable/Drawable.java b/src/api-impl/android/graphics/drawable/Drawable.java index 8c95331d..3bc8fc23 100644 --- a/src/api-impl/android/graphics/drawable/Drawable.java +++ b/src/api-impl/android/graphics/drawable/Drawable.java @@ -299,6 +299,8 @@ public class Drawable { return false; } + public void setHotspot(float x, float y) {} + protected static native long native_paintable_from_path(String path); protected native long native_constructor(); protected native void native_invalidate(long paintable); diff --git a/src/api-impl/android/graphics/drawable/RippleDrawable.java b/src/api-impl/android/graphics/drawable/RippleDrawable.java index 04d4d472..1a2b9589 100644 --- a/src/api-impl/android/graphics/drawable/RippleDrawable.java +++ b/src/api-impl/android/graphics/drawable/RippleDrawable.java @@ -8,4 +8,6 @@ public class RippleDrawable extends LayerDrawable { super(drawable == null ? new Drawable[] {} : new Drawable[] {drawable}); } + public void setColor(ColorStateList colorStateList) {} + } diff --git a/src/api-impl/android/media/AudioAttributes.java b/src/api-impl/android/media/AudioAttributes.java index 884c30cb..ec820f08 100644 --- a/src/api-impl/android/media/AudioAttributes.java +++ b/src/api-impl/android/media/AudioAttributes.java @@ -16,6 +16,14 @@ public class AudioAttributes { return this; } + public Builder setFlags(int flags) { + return this; + } + + public Builder setLegacyStreamType(int legacy_stream_type) { + return this; + } + public AudioAttributes build() { return new AudioAttributes(); } diff --git a/src/api-impl/android/media/session/MediaController.java b/src/api-impl/android/media/session/MediaController.java index 9e5fa67f..457462d6 100644 --- a/src/api-impl/android/media/session/MediaController.java +++ b/src/api-impl/android/media/session/MediaController.java @@ -10,4 +10,8 @@ public class MediaController { public MediaMetadata getMetadata() { return new MediaMetadata(); } + + public CharSequence getQueueTitle() { + return null; + } } diff --git a/src/api-impl/android/media/session/MediaSession.java b/src/api-impl/android/media/session/MediaSession.java index 7f616710..4d698f63 100644 --- a/src/api-impl/android/media/session/MediaSession.java +++ b/src/api-impl/android/media/session/MediaSession.java @@ -4,6 +4,7 @@ import java.util.List; import android.app.PendingIntent; import android.content.Context; +import android.media.AudioAttributes; import android.media.MediaDescription; import android.media.MediaMetadata; import android.os.Handler; @@ -54,7 +55,7 @@ public class MediaSession { if (item.id == state.activeQueueItemId) { title = item.description.title.toString(); subTitle = item.description.subtitle.toString(); - artUrl = item.description.iconUri.toString(); + artUrl = item.description.iconUri == null ? null : item.description.iconUri.toString(); break; } } @@ -69,6 +70,8 @@ public class MediaSession { public void release() {} + public void setPlaybackToLocal(AudioAttributes audioAttributes) {} + protected native void nativeSetState(int state, long actions, long position, long updateTime, String title, String subTitle, String artUrl); protected native void nativeSetCallback(Callback callback); } diff --git a/src/api-impl/android/os/Binder.java b/src/api-impl/android/os/Binder.java index 1fd2bb27..5475f69f 100644 --- a/src/api-impl/android/os/Binder.java +++ b/src/api-impl/android/os/Binder.java @@ -1,6 +1,6 @@ package android.os; -public class Binder extends IBinder { +public class Binder implements IBinder { public void attachInterface(IInterface owner, String descriptor) {} @@ -9,4 +9,10 @@ public class Binder extends IBinder { public static long clearCallingIdentity() { return 0; } public static void restoreCallingIdentity(long identityToken) {} + + @Override + public IInterface queryLocalInterface(String descriptor) { return null; } + + @Override + public boolean transact(int code, Parcel data, Parcel reply, int flags) { return false; } } diff --git a/src/api-impl/android/os/IBinder.java b/src/api-impl/android/os/IBinder.java index 460593fc..4372dd2b 100644 --- a/src/api-impl/android/os/IBinder.java +++ b/src/api-impl/android/os/IBinder.java @@ -1,6 +1,10 @@ package android.os; -public class IBinder { +public interface IBinder { public interface DeathRecipient {} + + public IInterface queryLocalInterface(String descriptor); + + public boolean transact(int code, Parcel data, Parcel reply, int flags); } diff --git a/src/api-impl/android/os/Parcel.java b/src/api-impl/android/os/Parcel.java index 16333cca..6e378e5c 100644 --- a/src/api-impl/android/os/Parcel.java +++ b/src/api-impl/android/os/Parcel.java @@ -43,4 +43,16 @@ public class Parcel { public void writeParcelable(Parcelable p, int flags) { System.out.println("Parcel.writeParcelable(" + p + ", " + flags + ")"); } + + public void writeInterfaceToken(String s) { + System.out.println("Parcel.writeInterfaceToken(" + s + ")"); + } + + public void writeStrongInterface(IInterface i) { + System.out.println("Parcel.writeStrongInterface(" + i + ")"); + } + + public int dataSize() { + return 0; + } } diff --git a/src/api-impl/android/os/Parcelable.java b/src/api-impl/android/os/Parcelable.java index f562f4d8..bd4ee232 100644 --- a/src/api-impl/android/os/Parcelable.java +++ b/src/api-impl/android/os/Parcelable.java @@ -6,4 +6,8 @@ public interface Parcelable { } public static interface ClassLoaderCreator extends Creator {} + + public default void writeToParcel(Parcel dest, int flags) { + System.out.println("Parcelable.writeToParcel(" + this + ", " + dest + ", " + flags + ")"); + } } diff --git a/src/api-impl/android/provider/Settings.java b/src/api-impl/android/provider/Settings.java index 63f55a8e..2d58ecf5 100644 --- a/src/api-impl/android/provider/Settings.java +++ b/src/api-impl/android/provider/Settings.java @@ -65,6 +65,7 @@ public class Settings { } public static final class Global { + public static final Uri CONTENT_URI = Uri.parse("content://settings/global"); public static int getInt(ContentResolver cr, String key, int def) { switch (key) { @@ -89,6 +90,10 @@ public class Settings { return "STRING_FROM_SETTINGS_GLOBAL_WITH_KEY_" + key; } } + + public static Uri getUriFor(String name) { + return Uri.withAppendedPath(CONTENT_URI, name); + } } public static class SettingNotFoundException extends AndroidException {} diff --git a/src/api-impl/android/text/BoringLayout.java b/src/api-impl/android/text/BoringLayout.java new file mode 100644 index 00000000..fe74f0a6 --- /dev/null +++ b/src/api-impl/android/text/BoringLayout.java @@ -0,0 +1,10 @@ +package android.text; + +public class BoringLayout extends Layout { + + public static class Metrics {}; + + public static Metrics isBoring(CharSequence source, TextPaint paint, Metrics metrics) { + return metrics; + } +} diff --git a/src/api-impl/android/text/Layout.java b/src/api-impl/android/text/Layout.java index dc58fbb6..0bd88162 100644 --- a/src/api-impl/android/text/Layout.java +++ b/src/api-impl/android/text/Layout.java @@ -29,4 +29,34 @@ public class Layout { public void draw(Canvas canvas) {} public int getParagraphDirection(int line) {return 0;} + + public static float getDesiredWidth(CharSequence source, int start, int end, TextPaint paint) { + return 10; + } + + public int getLineEnd(int line) {return 100;} + + public int getLineStart(int line) {return 0;} + + public int getLineAscent(int line) {return 0;} + + public int getLineDescent(int line) {return 0;} + + public int getTopPadding() {return 0;} + + public int getBottomPadding() {return 0;} + + public float getLineLeft(int line) {return 0;} + + public int getLineBottom(int line) {return 0;} + + public int getLineBaseline(int line) {return 0;} + + public boolean isRtlCharAt(int offset) {return false;} + + public float getSecondaryHorizontal(int line) {return 0;} + + public int getLineForVertical(int y) {return 0;} + + public int getOffsetForHorizontal(int line, float x) {return 0;} } diff --git a/src/api-impl/android/text/TextDirectionHeuristic.java b/src/api-impl/android/text/TextDirectionHeuristic.java index 937a1143..aaff1978 100644 --- a/src/api-impl/android/text/TextDirectionHeuristic.java +++ b/src/api-impl/android/text/TextDirectionHeuristic.java @@ -1,4 +1,6 @@ package android.text; -public class TextDirectionHeuristic { +public interface TextDirectionHeuristic { + + public boolean isRtl(CharSequence text, int start, int end); } diff --git a/src/api-impl/android/text/TextDirectionHeuristics.java b/src/api-impl/android/text/TextDirectionHeuristics.java index 531cb9c5..22b3c21d 100644 --- a/src/api-impl/android/text/TextDirectionHeuristics.java +++ b/src/api-impl/android/text/TextDirectionHeuristics.java @@ -2,7 +2,17 @@ package android.text; public class TextDirectionHeuristics { - public static final TextDirectionHeuristic LTR = new TextDirectionHeuristic(); + public static final TextDirectionHeuristic LTR = new TextDirectionHeuristic() { + @Override + public boolean isRtl(CharSequence text, int start, int end) { + return false; + } + }; - public static final TextDirectionHeuristic RTL = new TextDirectionHeuristic(); + public static final TextDirectionHeuristic RTL = new TextDirectionHeuristic() { + @Override + public boolean isRtl(CharSequence text, int start, int end) { + return true; + } + }; } diff --git a/src/api-impl/android/text/TextPaint.java b/src/api-impl/android/text/TextPaint.java index 17fbf3e5..d6706bfe 100644 --- a/src/api-impl/android/text/TextPaint.java +++ b/src/api-impl/android/text/TextPaint.java @@ -79,4 +79,8 @@ public class TextPaint extends Paint { underlineColor = color; underlineThickness = thickness; } + + public float getLetterSpacing() { + return 1.0f; + } } diff --git a/src/api-impl/android/util/SparseLongArray.java b/src/api-impl/android/util/SparseLongArray.java new file mode 100644 index 00000000..79ea26df --- /dev/null +++ b/src/api-impl/android/util/SparseLongArray.java @@ -0,0 +1,259 @@ +/* + * Copyright (C) 2011 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 android.util; + +import com.android.internal.util.ArrayUtils; +import com.android.internal.util.GrowingArrayUtils; + +import libcore.util.EmptyArray; + +/** + * SparseLongArrays map integers to longs. Unlike a normal array of longs, + * there can be gaps in the indices. It is intended to be more memory efficient + * than using a HashMap to map Integers to Longs, both because it avoids + * auto-boxing keys and values and its data structure doesn't rely on an extra entry object + * for each mapping. + * + *

Note that this container keeps its mappings in an array data structure, + * using a binary search to find keys. The implementation is not intended to be appropriate for + * data structures + * that may contain large numbers of items. It is generally slower than a traditional + * HashMap, since lookups require a binary search and adds and removes require inserting + * and deleting entries in the array. For containers holding up to hundreds of items, + * the performance difference is not significant, less than 50%.

+ * + *

It is possible to iterate over the items in this container using + * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using + * keyAt(int) with ascending values of the index will return the + * keys in ascending order, or the values corresponding to the keys in ascending + * order in the case of valueAt(int).

+ */ +public class SparseLongArray implements Cloneable { + private int[] mKeys; + private long[] mValues; + private int mSize; + + /** + * Creates a new SparseLongArray containing no mappings. + */ + public SparseLongArray() { + this(10); + } + + /** + * Creates a new SparseLongArray containing no mappings that will not + * require any additional memory allocation to store the specified + * number of mappings. If you supply an initial capacity of 0, the + * sparse array will be initialized with a light-weight representation + * not requiring any additional array allocations. + */ + public SparseLongArray(int initialCapacity) { + if (initialCapacity == 0) { + mKeys = EmptyArray.INT; + mValues = EmptyArray.LONG; + } else { + mValues = ArrayUtils.newUnpaddedLongArray(initialCapacity); + mKeys = new int[mValues.length]; + } + mSize = 0; + } + + @Override + public SparseLongArray clone() { + SparseLongArray clone = null; + try { + clone = (SparseLongArray) super.clone(); + clone.mKeys = mKeys.clone(); + clone.mValues = mValues.clone(); + } catch (CloneNotSupportedException cnse) { + /* ignore */ + } + return clone; + } + + /** + * Gets the long mapped from the specified key, or 0 + * if no such mapping has been made. + */ + public long get(int key) { + return get(key, 0); + } + + /** + * Gets the long mapped from the specified key, or the specified value + * if no such mapping has been made. + */ + public long get(int key, long valueIfKeyNotFound) { + int i = ContainerHelpers.binarySearch(mKeys, mSize, key); + + if (i < 0) { + return valueIfKeyNotFound; + } else { + return mValues[i]; + } + } + + /** + * Removes the mapping from the specified key, if there was any. + */ + public void delete(int key) { + int i = ContainerHelpers.binarySearch(mKeys, mSize, key); + + if (i >= 0) { + removeAt(i); + } + } + + /** + * Removes the mapping at the given index. + */ + public void removeAt(int index) { + System.arraycopy(mKeys, index + 1, mKeys, index, mSize - (index + 1)); + System.arraycopy(mValues, index + 1, mValues, index, mSize - (index + 1)); + mSize--; + } + + /** + * Adds a mapping from the specified key to the specified value, + * replacing the previous mapping from the specified key if there + * was one. + */ + public void put(int key, long value) { + int i = ContainerHelpers.binarySearch(mKeys, mSize, key); + + if (i >= 0) { + mValues[i] = value; + } else { + i = ~i; + + mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key); + mValues = GrowingArrayUtils.insert(mValues, mSize, i, value); + mSize++; + } + } + + /** + * Returns the number of key-value mappings that this SparseIntArray + * currently stores. + */ + public int size() { + return mSize; + } + + /** + * Given an index in the range 0...size()-1, returns + * the key from the indexth key-value mapping that this + * SparseLongArray stores. + * + *

The keys corresponding to indices in ascending order are guaranteed to + * be in ascending order, e.g., keyAt(0) will return the + * smallest key and keyAt(size()-1) will return the largest + * key.

+ */ + public int keyAt(int index) { + return mKeys[index]; + } + + /** + * Given an index in the range 0...size()-1, returns + * the value from the indexth key-value mapping that this + * SparseLongArray stores. + * + *

The values corresponding to indices in ascending order are guaranteed + * to be associated with keys in ascending order, e.g., + * valueAt(0) will return the value associated with the + * smallest key and valueAt(size()-1) will return the value + * associated with the largest key.

+ */ + public long valueAt(int index) { + return mValues[index]; + } + + /** + * Returns the index for which {@link #keyAt} would return the + * specified key, or a negative number if the specified + * key is not mapped. + */ + public int indexOfKey(int key) { + return ContainerHelpers.binarySearch(mKeys, mSize, key); + } + + /** + * Returns an index for which {@link #valueAt} would return the + * specified key, or a negative number if no keys map to the + * specified value. + * Beware that this is a linear search, unlike lookups by key, + * and that multiple keys can map to the same value and this will + * find only one of them. + */ + public int indexOfValue(long value) { + for (int i = 0; i < mSize; i++) + if (mValues[i] == value) + return i; + + return -1; + } + + /** + * Removes all key-value mappings from this SparseIntArray. + */ + public void clear() { + mSize = 0; + } + + /** + * Puts a key/value pair into the array, optimizing for the case where + * the key is greater than all existing keys in the array. + */ + public void append(int key, long value) { + if (mSize != 0 && key <= mKeys[mSize - 1]) { + put(key, value); + return; + } + + mKeys = GrowingArrayUtils.append(mKeys, mSize, key); + mValues = GrowingArrayUtils.append(mValues, mSize, value); + mSize++; + } + + /** + * {@inheritDoc} + * + *

This implementation composes a string by iterating over its mappings. + */ + @Override + public String toString() { + if (size() <= 0) { + return "{}"; + } + + StringBuilder buffer = new StringBuilder(mSize * 28); + buffer.append('{'); + for (int i=0; i 0) { + buffer.append(", "); + } + int key = keyAt(i); + buffer.append(key); + buffer.append('='); + long value = valueAt(i); + buffer.append(value); + } + buffer.append('}'); + return buffer.toString(); + } +} diff --git a/src/api-impl/android/view/MotionEvent.java b/src/api-impl/android/view/MotionEvent.java index 3459b37c..95ca705b 100644 --- a/src/api-impl/android/view/MotionEvent.java +++ b/src/api-impl/android/view/MotionEvent.java @@ -2213,7 +2213,8 @@ public final class MotionEvent extends InputEvent { * @see KeyEvent#getMetaState() */ public final int getMetaState() { - return nativeGetMetaState(mNativePtr); + // return nativeGetMetaState(mNativePtr); + return 0; } /** @@ -2228,7 +2229,8 @@ public final class MotionEvent extends InputEvent { * @see #BUTTON_BACK */ public final int getButtonState() { - return nativeGetButtonState(mNativePtr); + // return nativeGetButtonState(mNativePtr); + return BUTTON_PRIMARY; } /** diff --git a/src/api-impl/android/view/View.java b/src/api-impl/android/view/View.java index 2d5cad42..1e756c91 100644 --- a/src/api-impl/android/view/View.java +++ b/src/api-impl/android/view/View.java @@ -14,6 +14,7 @@ import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; +import android.os.Binder; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -624,7 +625,8 @@ public class View implements Drawable.Callback { } public interface OnAttachStateChangeListener { - // TODO + public void onViewAttachedToWindow(View v); + public void onViewDetachedFromWindow(View v); } public interface OnGenericMotionListener { @@ -1061,10 +1063,12 @@ public class View implements Drawable.Callback { private OnTouchListener on_touch_listener = null; public boolean onTouchEvent(MotionEvent event) { + boolean handled = false; if (on_touch_listener != null) - return on_touch_listener.onTouch(this, event); - else - return false; + handled = on_touch_listener.onTouch(this, event); + if (!handled) + handled = dispatchTouchEvent(event); + return handled; } public void setOnTouchListener(OnTouchListener l) { @@ -1173,6 +1177,8 @@ public class View implements Drawable.Callback { /* TODO */ } + public void unscheduleDrawable(Drawable drawable) {} + public void invalidate(Rect dirty) { nativeInvalidate(widget); } @@ -1290,14 +1296,16 @@ public class View implements Drawable.Callback { public void setOnGenericMotionListener(View.OnGenericMotionListener l) {} public IBinder getWindowToken() { - return new IBinder(); + return new Binder(); } public void getLocationInWindow(int[] location) { getLocationOnScreen(location); } - public void addOnAttachStateChangeListener(OnAttachStateChangeListener l) {} + public void addOnAttachStateChangeListener(OnAttachStateChangeListener l) { + onAttachStateChangeListener = l; + } public Context getContext() { return this.context; @@ -1843,9 +1851,15 @@ public class View implements Drawable.Callback { protected void onAttachedToWindow () { attachedToWindow = true; + if (onAttachStateChangeListener != null) { + onAttachStateChangeListener.onViewAttachedToWindow(this); + } } protected void onDetachedFromWindow() { attachedToWindow = false; + if (onAttachStateChangeListener != null) { + onAttachStateChangeListener.onViewDetachedFromWindow(this); + } } public void attachToWindowInternal() { onAttachedToWindow(); @@ -1892,7 +1906,12 @@ public class View implements Drawable.Callback { }); } - public void removeOnAttachStateChangeListener(OnAttachStateChangeListener listener) {} + private OnAttachStateChangeListener onAttachStateChangeListener; + public void removeOnAttachStateChangeListener(OnAttachStateChangeListener listener) { + if (onAttachStateChangeListener == listener) { + onAttachStateChangeListener = null; + } + } public boolean onInterceptTouchEvent(MotionEvent event) {return false;} @@ -2028,4 +2047,38 @@ public class View implements Drawable.Callback { public void setDefaultFocusHighlightEnabled(boolean enabled) {} public void setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled) {} + + public Handler getHandler() { + return new Handler(Looper.getMainLooper()); + } + + public boolean isHardwareAccelerated() { + return false; + } + + public void setClipBounds(Rect clipBounds) {} + + public boolean getClipToOutline() {return false;} + + public void setLeft(int left) { + layout(left, top, right, bottom); + } + + public void setTop(int top) { + layout(left, top, right, bottom); + } + + public void setRight(int right) { + layout(left, top, right, bottom); + } + + public void setBottom(int bottom) { + layout(left, top, right, bottom); + } + + public void setCameraDistance(float distance) {} + + public boolean requestRectangleOnScreen(Rect rectangle, boolean immediate) {return false;} + + public boolean requestRectangleOnScreen(Rect rectangle) {return false;} } diff --git a/src/api-impl/android/view/ViewGroup.java b/src/api-impl/android/view/ViewGroup.java index 2f64f93c..7dbfa47b 100644 --- a/src/api-impl/android/view/ViewGroup.java +++ b/src/api-impl/android/view/ViewGroup.java @@ -4,6 +4,7 @@ import android.R; import android.animation.LayoutTransition; import android.content.Context; import android.content.res.TypedArray; +import android.graphics.Canvas; import android.util.AttributeSet; import java.util.ArrayList; import java.util.Iterator; @@ -84,6 +85,11 @@ public class ViewGroup extends View implements ViewParent, ViewManager { return true; } + protected boolean addViewInLayout(View child, int index, LayoutParams params, boolean preventRequestLayout) { + addViewInternal(child, index, params); + return true; + } + // This internal method is used to share code between removeView and removeViewInLayout. // Reusing removeView in removeViewInLayout is not possible, because e.g. // ViewPager overrides removeView to call removeViewInLayout @@ -385,6 +391,14 @@ public class ViewGroup extends View implements ViewParent, ViewManager { this.transition = transition; } + public boolean drawChild(Canvas canvas, View child, long drawingTime) { + return false; + } + + protected void cleanupLayoutState(View child) {} + + public boolean shouldDelayChildPressedState() { return false; } + public static class LayoutParams { public static final int FILL_PARENT = -1; public static final int MATCH_PARENT = -1; diff --git a/src/api-impl/android/view/accessibility/AccessibilityManager.java b/src/api-impl/android/view/accessibility/AccessibilityManager.java index 4f7d491b..a7f0feed 100644 --- a/src/api-impl/android/view/accessibility/AccessibilityManager.java +++ b/src/api-impl/android/view/accessibility/AccessibilityManager.java @@ -7,6 +7,8 @@ public class AccessibilityManager { public interface AccessibilityStateChangeListener {} + public interface TouchExplorationStateChangeListener {} + public boolean isTouchExplorationEnabled() {return false;} public boolean isEnabled() {return false;} @@ -19,4 +21,8 @@ public class AccessibilityManager { return false; } + public boolean addTouchExplorationStateChangeListener(TouchExplorationStateChangeListener listener) { + return false; + } + } diff --git a/src/api-impl/android/view/accessibility/AccessibilityNodeProvider.java b/src/api-impl/android/view/accessibility/AccessibilityNodeProvider.java new file mode 100644 index 00000000..74997022 --- /dev/null +++ b/src/api-impl/android/view/accessibility/AccessibilityNodeProvider.java @@ -0,0 +1,4 @@ +package android.view.accessibility; + +public class AccessibilityNodeProvider { +} diff --git a/src/api-impl/android/view/inputmethod/CursorAnchorInfo.java b/src/api-impl/android/view/inputmethod/CursorAnchorInfo.java new file mode 100644 index 00000000..d427571c --- /dev/null +++ b/src/api-impl/android/view/inputmethod/CursorAnchorInfo.java @@ -0,0 +1,7 @@ +package android.view.inputmethod; + +public class CursorAnchorInfo { + + public static class Builder {} + +} diff --git a/src/api-impl/meson.build b/src/api-impl/meson.build index e0665452..ad071bda 100644 --- a/src/api-impl/meson.build +++ b/src/api-impl/meson.build @@ -184,6 +184,7 @@ hax_jar = jar('hax', [ 'android/graphics/GskCanvas.java', 'android/graphics/LinearGradient.java', 'android/graphics/Matrix.java', + 'android/graphics/Outline.java', 'android/graphics/Paint.java', 'android/graphics/Path.java', 'android/graphics/PathEffect.java', @@ -332,6 +333,7 @@ hax_jar = jar('hax', [ 'android/telephony/PhoneStateListener.java', 'android/telephony/SubscriptionManager.java', 'android/telephony/TelephonyManager.java', + 'android/text/BoringLayout.java', 'android/text/ClipboardManager.java', 'android/text/Editable.java', 'android/text/GetChars.java', @@ -421,6 +423,7 @@ hax_jar = jar('hax', [ 'android/util/SparseArray.java', 'android/util/SparseBooleanArray.java', 'android/util/SparseIntArray.java', + 'android/util/SparseLongArray.java', 'android/util/StateSet.java', 'android/util/TypedValue.java', 'android/util/Xml.java', @@ -468,6 +471,7 @@ hax_jar = jar('hax', [ 'android/view/WindowManagerImpl.java', 'android/view/accessibility/AccessibilityManager.java', 'android/view/accessibility/AccessibilityNodeInfo.java', + 'android/view/accessibility/AccessibilityNodeProvider.java', 'android/view/accessibility/CaptioningManager.java', 'android/view/animation/AccelerateDecelerateInterpolator.java', 'android/view/animation/AccelerateInterpolator.java', @@ -484,6 +488,7 @@ hax_jar = jar('hax', [ 'android/view/animation/ScaleAnimation.java', 'android/view/animation/TranslateAnimation.java', 'android/view/inputmethod/BaseInputConnection.java', + 'android/view/inputmethod/CursorAnchorInfo.java', 'android/view/inputmethod/InputConnection.java', 'android/view/inputmethod/InputMethodManager.java', 'android/view/textservice/TextServicesManager.java',