This commit is contained in:
Mis012
2025-07-18 20:06:17 +02:00
parent 828f779c4f
commit 40b7833bad
25 changed files with 438 additions and 48 deletions

1
.gdb_history Normal file
View File

@@ -0,0 +1 @@
r

View File

@@ -1,4 +1,4 @@
project('android_translation_layer', ['c', 'java'], default_options: ['b_lundef=false'])
project('android_translation_layer', ['c', 'java'], default_options: ['c_std=gnu23', 'b_lundef=false'])
gnome = import('gnome')
fs = import('fs')
@@ -145,6 +145,7 @@ libtranslationlayer_so = shared_library('translation_layer_main', [
'src/api-impl-jni/views/AndroidLayout.c',
'src/api-impl-jni/views/android_view_View.c',
'src/api-impl-jni/views/android_view_ViewGroup.c',
'src/api-impl-jni/views/android_view_ViewTreeObserver.c',
'src/api-impl-jni/views/android_view_WindowManagerImpl.c',
'src/api-impl-jni/widgets/WrapperWidget.c',
'src/api-impl-jni/widgets/android_view_SurfaceView.c',
@@ -197,6 +198,7 @@ executable('android-translation-layer', [
'src/main-executable/actions.c',
'src/main-executable/back_button.c',
'src/main-executable/bionic_compat.c',
'src/main-executable/inspector_page.c',
'src/main-executable/libc_bio_path_overrides.c',
resources
],

View File

@@ -53,3 +53,8 @@ JNIEXPORT void JNICALL Java_android_view_Window_set_1layout(JNIEnv *env, jobject
if (width > 0 && height > 0)
gtk_window_set_default_size(gtk_window, width, height);
}
JNIEXPORT void JNICALL Java_android_view_Window_set_1jobject(JNIEnv *env, jclass this, jlong window, jobject window_jobj)
{
g_object_set_data(G_OBJECT(window), "jobject", _WEAK_REF(window_jobj));
}

View File

@@ -359,6 +359,14 @@ JNIEXPORT void JNICALL Java_android_view_View_nativeRequestFocus
JNIEXPORT void JNICALL Java_android_view_View_nativeSetFullscreen
(JNIEnv *, jobject, jlong, jboolean);
/*
* Class: android_view_View
* Method: native_get_window
* Signature: (J)Landroid/view/Window;
*/
JNIEXPORT jobject JNICALL Java_android_view_View_native_1get_1window
(JNIEnv *, jobject, jlong);
/*
* Class: android_view_View
* Method: nativeInvalidate

View File

@@ -0,0 +1,21 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class android_view_ViewTreeObserver */
#ifndef _Included_android_view_ViewTreeObserver
#define _Included_android_view_ViewTreeObserver
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: android_view_ViewTreeObserver
* Method: native_set_have_global_layout_listeners
* Signature: (Z)V
*/
JNIEXPORT void JNICALL Java_android_view_ViewTreeObserver_native_1set_1have_1global_1layout_1listeners
(JNIEnv *, jobject, jboolean);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -43,6 +43,14 @@ JNIEXPORT void JNICALL Java_android_view_Window_take_1input_1queue
JNIEXPORT void JNICALL Java_android_view_Window_set_1layout
(JNIEnv *, jobject, jlong, jint, jint);
/*
* Class: android_view_Window
* Method: set_jobject
* Signature: (JLandroid/view/Window;)V
*/
JNIEXPORT void JNICALL Java_android_view_Window_set_1jobject
(JNIEnv *, jclass, jlong, jobject);
#ifdef __cplusplus
}
#endif

View File

@@ -135,4 +135,7 @@ void set_up_handle_cache(JNIEnv *env)
handle_cache.uri.class = _REF((*env)->FindClass(env, "android/net/Uri"));
handle_cache.uri.parse = _STATIC_METHOD(handle_cache.uri.class, "parse", "(Ljava/lang/String;)Landroid/net/Uri;");
handle_cache.view_tree_observer.class = _REF((*env)->FindClass(env, "android/view/ViewTreeObserver"));
handle_cache.view_tree_observer.dispatchOnGlobalLayout = _METHOD(handle_cache.view_tree_observer.class, "dispatchOnGlobalLayout", "()V");
}

View File

@@ -145,6 +145,10 @@ struct handle_cache {
jclass class;
jmethodID parse;
} uri;
struct {
jclass class;
jmethodID dispatchOnGlobalLayout;
} view_tree_observer;
};
extern struct handle_cache handle_cache;

View File

@@ -19,6 +19,7 @@ static void location_updated (
JNIEnv *env;
(*jvm)->GetEnv(jvm, (void**)&env, JNI_VERSION_1_6);
jclass class = (*env)->FindClass(env, "android/location/LocationManager");
printf("XXLOCXX: latitude, longitude, heading: %lf %lf %lf\n", latitude, longitude, heading);
jlong timestamp = timestamp_s * 1000 + timestamp_ms;
(*env)->CallStaticVoidMethod(env, class, _STATIC_METHOD(class, "locationUpdated", "(DDDDDDJ)V"), latitude, longitude, altitude, accuracy, speed, heading, timestamp);
}
@@ -38,5 +39,6 @@ JNIEXPORT void JNICALL Java_android_location_LocationManager_nativeGetLocation(J
g_signal_connect(portal, "location-updated", G_CALLBACK(location_updated), jvm);
}
printf("XXLOCXX: Java_android_location_LocationManager_nativeGetLocation\n");
xdp_portal_location_monitor_start (portal, NULL, 0, 0, XDP_LOCATION_ACCURACY_EXACT, XDP_LOCATION_MONITOR_FLAG_NONE, NULL, NULL, NULL);
}

View File

@@ -18,6 +18,8 @@ static int make_measure_spec(int layout_size, int for_size)
return -1;
}
extern int snapshot_in_progress;
static void android_layout_measure(GtkLayoutManager *layout_manager, GtkWidget *widget, GtkOrientation orientation, int for_size, int *minimum, int *natural, int *minimum_baseline, int *natural_baseline)
{
int widthMeasureSpec = 0;
@@ -25,12 +27,16 @@ static void android_layout_measure(GtkLayoutManager *layout_manager, GtkWidget *
AndroidLayout *layout = ATL_ANDROID_LAYOUT(layout_manager);
JNIEnv *env = get_jni_env();
/* if we're inside a shanpshot, this must be getting called purely to make Gtk call gtk_widget_clear_resize_queued */
if(snapshot_in_progress)
return;
// If the parent widget is also an AndroidLayout, the measurement will already have happened in Java
if ((layout->width || layout->height) && !ATL_IS_ANDROID_LAYOUT(gtk_widget_get_layout_manager(gtk_widget_get_parent(gtk_widget_get_parent(widget))))) {
widthMeasureSpec = make_measure_spec(layout->width, orientation == GTK_ORIENTATION_VERTICAL ? for_size : -1);
heightMeasureSpec = make_measure_spec(layout->height, orientation == GTK_ORIENTATION_HORIZONTAL ? for_size : -1);
// if layout params say match_parent, but GTK doesnt specify the dimension, fallback to old specification if available
// if layout params say match_parent, but GTK doesn't specify the dimension, fall back to old specification if available
if (widthMeasureSpec == -1)
widthMeasureSpec = _GET_INT_FIELD(layout->view, "oldWidthMeasureSpec");
if (heightMeasureSpec == -1)

View File

@@ -307,8 +307,14 @@ void _setOnTouchListener(JNIEnv *env, jobject this, GtkWidget *widget)
gtk_widget_add_controller(widget, controller);
g_object_set_data(G_OBJECT(widget), "on_intercept_touch_listener", controller);
}
if (!wrapper->needs_allocation && (wrapper->layout_width || wrapper->layout_height))
gtk_widget_size_allocate(GTK_WIDGET(wrapper), &(GtkAllocation){.x = 0, .y = 0, .width = wrapper->layout_width, .height = wrapper->layout_height}, 0);
if(!wrapper->needs_allocation && wrapper->layout_width == -1 && wrapper->layout_height == -1)
printf("[%p] in _setOnTouchListener: [%d, %d]\n", wrapper->child, wrapper->real_width, wrapper->real_height);
if (!wrapper->needs_allocation && (wrapper->real_width || wrapper->real_height))
gtk_widget_size_allocate(GTK_WIDGET(wrapper), &(GtkAllocation){.x = 0, .y = 0, .width = wrapper->real_width, .height = wrapper->real_height}, 0);
wrapper->needs_allocation = true;
gtk_widget_set_overflow(GTK_WIDGET(wrapper), GTK_OVERFLOW_HIDDEN);
}
@@ -409,8 +415,6 @@ JNIEXPORT void JNICALL Java_android_view_View_native_1setLayoutParams(JNIEnv *en
}
if (weight > 0.f) {
printf(":::-: setting weight: %f\n", weight);
hexpand = TRUE;
vexpand = TRUE;
}
@@ -582,9 +586,10 @@ JNIEXPORT void JNICALL Java_android_view_View_native_1measure(JNIEnv *env, jobje
width = width_spec_size;
}
printf("[%p] in Java_android_view_View_native_1measure, calling setMeasuredDimension with [%d,%d]\n", _PTR(widget_ptr), width, height);
(*env)->CallVoidMethod(env, this, handle_cache.view.setMeasuredDimension, width, height);
}
void _gdb_force_java_stack_trace(void);
JNIEXPORT void JNICALL Java_android_view_View_native_1layout(JNIEnv *env, jobject this, jlong widget_ptr, jint l, jint t, jint r, jint b) {
GtkWidget *widget = gtk_widget_get_parent(GTK_WIDGET(_PTR(widget_ptr)));
@@ -605,6 +610,10 @@ JNIEXPORT void JNICALL Java_android_view_View_native_1layout(JNIEnv *env, jobjec
allocation.width = width;
allocation.height = height;
}
if(width == 540 && height == 0) {
printf("[%p] in Java_android_view_View_native_1layout, calling gtk_widget_size_allocate with [%d,%d]\n", _PTR(widget_ptr), width, height);
//_gdb_force_java_stack_trace();
}
gtk_widget_size_allocate(widget, &allocation, -1);
}
@@ -841,3 +850,9 @@ JNIEXPORT void JNICALL Java_android_view_View_native_1keep_1screen_1on(JNIEnv *e
g_object_set_data(G_OBJECT(widget), "keep-screen-on-cookie", GINT_TO_POINTER(cookie));
}
}
JNIEXPORT jobject JNICALL Java_android_view_View_native_1get_1window(JNIEnv *env, jobject this, jlong widget_ptr)
{
GtkWidget *widget = GTK_WIDGET(_PTR(widget_ptr));
return g_object_get_data(G_OBJECT(gtk_widget_get_root(widget)), "jobject");
}

View File

@@ -0,0 +1,38 @@
#include <gtk/gtk.h>
#include "../defines.h"
#include "../util.h"
#include "../generated_headers/android_view_ViewTreeObserver.h"
static void on_global_layout_callback(GdkFrameClock *clock, jobject view_tree_observer)
{
JNIEnv *env = get_jni_env();
(*env)->CallVoidMethod(env, view_tree_observer, handle_cache.view_tree_observer.dispatchOnGlobalLayout);
if((*env)->ExceptionCheck(env)) {
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
}
}
JNIEXPORT void JNICALL Java_android_view_ViewTreeObserver_native_1set_1have_1global_1layout_1listeners(JNIEnv *env, jobject this, jboolean have_listeners)
{
GtkWidget *window =_PTR(_GET_LONG_FIELD(this, "window"));
if(!window) {
/* FIXME: calling this on unrooted widgets may be valid */
fprintf(stderr, "in Java_android_view_ViewTreeObserver_native_1set_1have_1global_1layout_1listeners: no window\n");
return;
}
GdkFrameClock *clock = gtk_widget_get_frame_clock(window);
if(have_listeners) {
/* this adds our callback before the existing handler, which means we effectively execute before the paint phase (after layout) */
gulong signal_handle = g_signal_connect(G_OBJECT(clock), "paint", G_CALLBACK(on_global_layout_callback), _REF(this)); // FIXME: cleanup callback for _UNREF
_SET_LONG_FIELD(this, "onGlobalLayout_signal_handle", signal_handle);
} else {
gulong signal_handle = _GET_LONG_FIELD(this, "onGlobalLayout_signal_handle");
if (signal_handle)
g_signal_handler_disconnect(G_OBJECT(clock), signal_handle);
}
}

View File

@@ -10,7 +10,7 @@
G_DEFINE_TYPE(WrapperWidget, wrapper_widget, GTK_TYPE_WIDGET)
typedef enum { ATL_ID = 1, ATL_ID_NAME, ATL_CLASS_NAME, ATL_SUPER_CLASS_NAMES, N_PROPERTIES } WrapperWidgetProperty;
typedef enum { ATL_ID = 1, ATL_ID_NAME, ATL_CLASS_NAME, ATL_SUPER_CLASS_NAMES, ATL_REAL_WIDTH, ATL_REAL_HEIGHT, ATL_HAS_CUSTOM_DRAW, N_PROPERTIES } WrapperWidgetProperty;
static GParamSpec *wrapper_widget_properties[N_PROPERTIES] = { NULL, };
static void wrapper_widget_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
@@ -30,6 +30,10 @@ static void wrapper_widget_get_property(GObject *object, guint property_id, GVal
JNIEnv *env = get_jni_env();
jobject jobj = self->jobj;
if(!jobj) { /* FIXME */
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
return;
}
jclass class = _CLASS(jobj);
switch ((WrapperWidgetProperty) property_id)
@@ -85,6 +89,24 @@ static void wrapper_widget_get_property(GObject *object, guint property_id, GVal
}
case ATL_REAL_WIDTH:
{
g_value_set_int(value, self->real_width);
break;
}
case ATL_REAL_HEIGHT:
{
g_value_set_int(value, self->real_height);
break;
}
case ATL_HAS_CUSTOM_DRAW:
{
g_value_set_boolean(value, self->draw_method != NULL);
break;
}
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -232,6 +254,9 @@ static void wrapper_widget_class_init(WrapperWidgetClass *class)
wrapper_widget_properties[ATL_ID_NAME] = g_param_spec_string("ATL-id-name", "ATL: ID name", "Name of the ID of the component", "", G_PARAM_READABLE);
wrapper_widget_properties[ATL_CLASS_NAME] = g_param_spec_string("ATL-class-name", "ATL: Class name", "Name of the class of the component", "", G_PARAM_READABLE);
wrapper_widget_properties[ATL_SUPER_CLASS_NAMES] = g_param_spec_string("ATL-superclasses-names", "ATL: Super classes names", "Names of all the superclasses of the component class", "", G_PARAM_READABLE);
wrapper_widget_properties[ATL_REAL_WIDTH] = g_param_spec_int("ATL-real-width", "ATL: real width", "Real width of the widget", 0, INT32_MAX, 0, G_PARAM_READABLE);
wrapper_widget_properties[ATL_REAL_HEIGHT] = g_param_spec_int("ATL-real-height", "ATL: real height", "Real height of the widget", 0, INT32_MAX, 0, G_PARAM_READABLE);
wrapper_widget_properties[ATL_HAS_CUSTOM_DRAW] = g_param_spec_boolean("ATL-has-custom-draw", "ATL: has custom draw", "Indicates if the widget implements it's own drawing", FALSE, G_PARAM_READABLE);
g_object_class_install_properties (object_class, N_PROPERTIES, wrapper_widget_properties);
}

View File

@@ -66,7 +66,7 @@ public class Activity extends ContextThemeWrapper implements Window.Callback, La
Class<? extends Activity> cls = Class.forName(className).asSubclass(Activity.class);
Constructor<? extends Activity> constructor = cls.getConstructor();
Activity activity = constructor.newInstance();
activity.window.native_window = native_window;
activity.window.set_native_window(native_window);
activity.intent = intent;
activity.attachBaseContext(new Context());
activity.setTheme(themeResId);

View File

@@ -31,7 +31,7 @@ public class Dialog implements Window.Callback, DialogInterface {
this.context = context;
nativePtr = nativeInit();
window = new Window(context, this);
window.native_window = nativePtr;
window.set_native_window(nativePtr);
}
public Dialog(Context context) {

View File

@@ -139,7 +139,7 @@ public class Instrumentation {
Intent intent, ActivityInfo info, CharSequence title, Activity parent,
String id, Object lastNonConfigurationInstance) throws InstantiationException, IllegalAccessException {
Activity activity = (Activity)clazz.newInstance();
activity.getWindow().native_window = Context.this_application.native_window;
activity.getWindow().set_native_window(Context.this_application.native_window);
Slog.i(TAG, "activity.getWindow().native_window >"+activity.getWindow().native_window+"<");
return activity;
}
@@ -168,7 +168,7 @@ public class Instrumentation {
Constructor<? extends Activity> constructor = cls.getConstructor();
final Activity activity = constructor.newInstance();
activity.intent = intent;
activity.getWindow().native_window = Context.this_application.native_window;
activity.getWindow().set_native_window(Context.this_application.native_window);
runOnMainSync(new Runnable() {
@Override
public void run() {

View File

@@ -828,15 +828,18 @@ public class View implements Drawable.Callback {
private Context context;
private Map<Integer,Object> tags = new HashMap<>();
private Object tag;
int gravity = -1; // fallback gravity for layout childs
int gravity = -1; // fallback gravity for layout children
int measuredWidth = 0;
int measuredHeight = 0;
private int left;
private int top;
private int right;
private int bottom;
private int left = 0;
private int top = 0;
private int right = 0;
private int bottom = 0;
private float translationX = 0;
private float translationY = 0;
private int scrollX = 0;
private int scrollY = 0;
@@ -1067,13 +1070,23 @@ public class View implements Drawable.Callback {
native_setLayoutParams(widget, params.width, params.height, gravity, params.weight, leftMargin, topMargin, rightMargin, bottomMargin);
layout_params = params;
System.out.printf("[0x%x] [%s] in setLayoutParams [%d, %d]\n", this.widget, getIdName(), params.width, params.height);
if(params.width == -1 && params.height == 0)
try {throw new Exception("stack trace");} catch(Exception e) {e.printStackTrace();}
}
public ViewGroup.LayoutParams getLayoutParams() {
if(layout_params != null)
System.out.printf("[0x%x] [%s] in getLayoutParams [%d, %d]\n", this.widget, getIdName(), layout_params.width, layout_params.height);
return layout_params;
}
protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {
if("net.osmand.plus:id/list".equals(getIdName()))
try { throw new Exception("stack trace"); } catch (Exception e) { e.printStackTrace(); }
System.out.printf("[0x%x] [%s] in setMeasuredDimension [%d, %d]\n", this.widget, getIdName(), measuredWidth, measuredHeight);
this.measuredWidth = measuredWidth;
this.measuredHeight = measuredHeight;
}
@@ -1199,8 +1212,17 @@ public class View implements Drawable.Callback {
public void setSelected(boolean selected) {}
public native Window native_get_window(long widget);
public ViewTreeObserver getViewTreeObserver() {
return new ViewTreeObserver();
Window window = native_get_window(widget);
if (window != null) {
if (window.view_tree_observer == null)
window.view_tree_observer = new ViewTreeObserver(window);
return window.view_tree_observer;
} else {
/* FIXME: better handling of unrooted widgets? */
return new ViewTreeObserver(null);
}
}
protected void onFinishInflate() {}
@@ -1464,10 +1486,12 @@ public class View implements Drawable.Callback {
}
public final int getMeasuredWidth() {
System.out.printf("[0x%x] [%s] in getMeasuredWidth width: %d\n", this.widget, getIdName(), this.measuredWidth);
return this.measuredWidth & MEASURED_SIZE_MASK;
}
public final int getMeasuredHeight() {
System.out.printf("[0x%x] [%s] in getMeasuredHeight height: %d\n", this.widget, getIdName(), this.measuredHeight);
return this.measuredHeight & MEASURED_SIZE_MASK;
}
@@ -1659,13 +1683,31 @@ public class View implements Drawable.Callback {
return viewPropertyAnimator;
}
public float getTranslationX() {return 0.f;}
public float getTranslationY() {return 0.f;}
public void setTranslationX(float translationX) {}
public float getTranslationX() {
return translationX;
}
public float getTranslationY() {
return translationY;
}
/* this is probably slower than on AOSP, becuse it's supposed to bypass the layout phase
* and just schedule redraw (which we technically could do, but it wouldn't change the hitbox,
* which it's supposed to) */
public void setTranslationX(float translationX) {
this.translationX = translationX;
ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams)getLayoutParams();
lp.leftMargin += translationX;
setLayoutParams(lp);
requestLayout();
}
public void setTranslationY(float translationY) {
// CoordinatorLayout abuses this method to trigger a layout pass
if (getClass().getName().equals("androidx.coordinatorlayout.widget.CoordinatorLayout"))
native_queueAllocate(widget);
this.translationY = translationY;
ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams)getLayoutParams();
lp.topMargin += translationY;
setLayoutParams(lp);
requestLayout();
}
public void setX(float x) {
@@ -1972,6 +2014,9 @@ public class View implements Drawable.Callback {
}
public void forceLayout() {
if(Looper.myLooper() == Looper.getMainLooper()) {
requestLayout();
} else {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
@@ -1979,6 +2024,7 @@ public class View implements Drawable.Callback {
}
});
}
}
private OnAttachStateChangeListener onAttachStateChangeListener;
public void removeOnAttachStateChangeListener(OnAttachStateChangeListener listener) {
@@ -2103,8 +2149,6 @@ public class View implements Drawable.Callback {
public int getTextAlignment() {return 0;}
public float getY() {return 0.f;}
public View findViewWithTag(Object tag) {
if (Objects.equals(tag, this.tag))
return this;
@@ -2198,7 +2242,12 @@ public class View implements Drawable.Callback {
public boolean isDirty() { return false; }
public float getX() { return getLeft(); }
public float getX() {
return getLeft();
}
public float getY() {
return getTop();
}
public boolean getGlobalVisibleRect(Rect visibleRect, Point globalOffset) {
boolean result = native_getGlobalVisibleRect(widget, visibleRect);

View File

@@ -247,6 +247,7 @@ public class ViewGroup extends View implements ViewParent, ViewManager {
}
public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
System.out.printf("[static] in getChildMeasureSpec(%d, %d, %d)\n", spec, padding, childDimension);
int specMode = MeasureSpec.getMode(spec);
int specSize = MeasureSpec.getSize(spec);
int size = Math.max(0, specSize - padding);
@@ -307,6 +308,7 @@ public class ViewGroup extends View implements ViewParent, ViewManager {
break;
}
// noinspection ResourceType
System.out.printf("[static] in getChildMeasureSpec, calling MeasureSpec.makeMeasureSpec(%d, %d)\n", resultSize, resultMode);
return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
}

View File

@@ -51,6 +51,11 @@ public final class ViewTreeObserver {
private boolean mAlive = true;
// accessed from native code
private long onGlobalLayout_signal_handle;
private long window;
/**
* Interface definition for a callback to be invoked when the view hierarchy is
* attached to and detached from its window.
@@ -297,10 +302,9 @@ public final class ViewTreeObserver {
public void onComputeInternalInsets(InternalInsetsInfo inoutInfo);
}
/**
* Creates a new ViewTreeObserver. This constructor should not be called
*/
ViewTreeObserver() {
ViewTreeObserver(Window window) {
if(window != null)
this.window = window.native_window;
}
/**
@@ -493,18 +497,19 @@ public final class ViewTreeObserver {
if (mOnGlobalLayoutListeners == null) {
mOnGlobalLayoutListeners = new CopyOnWriteArray<OnGlobalLayoutListener>();
native_set_have_global_layout_listeners(true);
}
mOnGlobalLayoutListeners.add(listener);
// hack: many Applications wait for the global layout before doing anything
// so we dispatch the event immediately
new Handler(Looper.getMainLooper()).post(new Runnable() {
/*new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
listener.onGlobalLayout();
}
});
});*/
}
@@ -539,6 +544,9 @@ public final class ViewTreeObserver {
return;
}
mOnGlobalLayoutListeners.remove(victim);
if(mOnGlobalLayoutListeners.size() == 0)
native_set_have_global_layout_listeners(false);
}
/**
@@ -1038,4 +1046,6 @@ public final class ViewTreeObserver {
getArray().clear();
}
}
private native void native_set_have_global_layout_listeners(boolean have_listeners);
}

View File

@@ -10,6 +10,8 @@ public class Window {
public static final int FEATURE_OPTIONS_PANEL = 0;
public static final int FEATURE_NO_TITLE = 1;
public ViewTreeObserver view_tree_observer = null;
public static interface Callback {
public void onContentChanged();
@@ -42,6 +44,11 @@ public class Window {
decorView.onAttachedToWindow();
}
public void set_native_window(long native_window) {
this.native_window = native_window;
set_jobject(native_window, this);
}
public void addFlags(int flags) {}
public void setFlags(int flags, int mask) {}
public void clearFlags(int flags) {}
@@ -65,12 +72,6 @@ public class Window {
return decorView;
}
public native void set_widget_as_root(long native_window, long widget);
private native void set_title(long native_window, String title);
public native void take_input_queue(long native_window, InputQueue.Callback callback, InputQueue queue);
public native void set_layout(long native_window, int width, int height);
public void takeInputQueue(InputQueue.Callback callback) {
take_input_queue(native_window, callback, new InputQueue());
}
@@ -160,4 +161,10 @@ public class Window {
public void setReturnTransition(Transition transition) {}
public void setEnterTransition(Transition transition) {}
public native void set_widget_as_root(long native_window, long widget);
private native void set_title(long native_window, String title);
public native void take_input_queue(long native_window, InputQueue.Callback callback, InputQueue queue);
public native void set_layout(long native_window, int width, int height);
private static native void set_jobject(long ptr, Window obj);
}

Some files were not shown because too many files have changed in this diff Show More