aboutsummaryrefslogtreecommitdiffstats
path: root/admin/notes/java
diff options
context:
space:
mode:
authorPo Lu2023-09-03 10:04:44 +0800
committerPo Lu2023-09-03 10:05:15 +0800
commit4debb110d70691a405a50272b3ca5d0a264e0010 (patch)
treeb6b3fa743030a6b31e1f15beaf246d78d85418bb /admin/notes/java
parent8ecc73f47a7d5473d0e3f070d85051fc85580f9d (diff)
downloademacs-4debb110d70691a405a50272b3ca5d0a264e0010.tar.gz
emacs-4debb110d70691a405a50272b3ca5d0a264e0010.zip
Move Android port internals documentation to admin/notes
* admin/notes/java: New file. Move most of its contents from README, and introduce a section on compatibility. * java/README: Move internals to admin/notes/java.
Diffstat (limited to 'admin/notes/java')
-rw-r--r--admin/notes/java1097
1 files changed, 1097 insertions, 0 deletions
diff --git a/admin/notes/java b/admin/notes/java
new file mode 100644
index 00000000000..125ac0aad67
--- /dev/null
+++ b/admin/notes/java
@@ -0,0 +1,1097 @@
1Installation instructions for Android
2Copyright (C) 2023 Free Software Foundation, Inc.
3See the end of the file for license conditions.
4
5
6
7OVERVIEW OF JAVA
8
9Emacs developers do not know Java, and there is no reason they should
10have to. Thus, the code in this directory is confined to what is
11strictly necessary to support Emacs, and only uses a subset of Java
12written in a way that is easily understandable to C programmers.
13
14Java is required because the entire Android runtime is based around
15Java, and there is no way to write an Android program which runs
16without Java.
17
18This text exists to prime other Emacs developers, already familar with
19C, on the basic architecture of the Android port, and to teach them
20how to read and write the Java code found in this directory.
21
22Java is an object oriented language with automatic memory management
23compiled down to bytecode, which is then subject to interpretation by
24a Java virtual machine.
25
26What that means, is that:
27
28struct emacs_window
29{
30 int some_fields;
31 int of_emacs_window;
32};
33
34static void
35do_something_with_emacs_window (struct emacs_window *a, int n)
36{
37 a->some_fields = a->of_emacs_window + n;
38}
39
40would be written:
41
42public class EmacsWindow
43{
44 public int someFields;
45 public int ofEmacsWindow;
46
47 public void
48 doSomething (int n)
49 {
50 someFields = ofEmacsWindow + n;
51 }
52}
53
54and instead of doing:
55
56do_something_with_emacs_window (my_window, 1);
57
58you say:
59
60myWindow.doSomething (1);
61
62In addition to functions associated with an object of a given class
63(such as EmacsWindow), Java also has two other kinds of functions.
64
65The first are so-called ``static'' functions (the static means
66something entirely different from what it does in C.)
67
68A static function, while still having to be defined within a class,
69can be called without any object. Instead of the object, you write
70the name of the Java class within which it is defined. For example,
71the following C code:
72
73int
74multiply_a_with_b_and_then_add_c (int a, int b, int c)
75{
76 return a * b + c;
77}
78
79would be:
80
81public class EmacsSomething
82{
83 public static int
84 multiplyAWithBAndThenAddC (int a, int b, int c)
85 {
86 return a * b + c;
87 }
88};
89
90Then, instead of calling:
91
92int foo;
93
94foo = multiply_a_with_b_then_add_c (1, 2, 3);
95
96you say:
97
98int foo;
99
100foo = EmacsSomething.multiplyAWithBAndThenAddC (1, 2, 3);
101
102In Java, ``static'' does not mean that the function is only used
103within its compilation unit! Instead, the ``private'' qualifier is
104used to mean more or less the same thing:
105
106static void
107this_procedure_is_only_used_within_this_file (void)
108{
109 do_something ();
110}
111
112becomes
113
114public class EmacsSomething
115{
116 private static void
117 thisProcedureIsOnlyUsedWithinThisClass ()
118 {
119
120 }
121}
122
123the other kind are called ``constructors''. They are functions that
124must be called to allocate memory to hold a class:
125
126public class EmacsFoo
127{
128 int bar;
129
130 public
131 EmacsFoo (int tokenA, int tokenB)
132 {
133 bar = tokenA + tokenB;
134 }
135}
136
137now, the following statement:
138
139EmacsFoo foo;
140
141foo = new EmacsFoo (1, 2);
142
143becomes more or less equivalent to the following C code:
144
145struct emacs_foo
146{
147 int bar;
148};
149
150struct emacs_foo *
151make_emacs_foo (int token_a, int token_b)
152{
153 struct emacs_foo *foo;
154
155 foo = xmalloc (sizeof *foo);
156 foo->bar = token_a + token_b;
157
158 return foo;
159}
160
161/* ... */
162
163struct emacs_foo *foo;
164
165foo = make_emacs_foo (1, 2);
166
167A class may have any number of constructors, or no constructors at
168all, in which case the compiler inserts an empty constructor.
169
170
171
172Sometimes, you will see Java code that looks like this:
173
174 allFiles = filesDirectory.listFiles (new FileFilter () {
175 @Override
176 public boolean
177 accept (File file)
178 {
179 return (!file.isDirectory ()
180 && file.getName ().endsWith (".pdmp"));
181 }
182 });
183
184This is Java's version of GCC's nested function extension. The major
185difference is that the nested function may still be called even after
186it goes out of scope, and always retains a reference to the class and
187local variables around where it was called.
188
189Being an object-oriented language, Java also allows defining that a
190class ``extends'' another class. The following C code:
191
192struct a
193{
194 long thirty_two;
195};
196
197struct b
198{
199 struct a a;
200 long long sixty_four;
201};
202
203extern void do_something (struct a *);
204
205void
206my_function (struct b *b)
207{
208 do_something (&b->a);
209}
210
211is roughly equivalent to the following Java code, split into two
212files:
213
214 A.java
215
216public class A
217{
218 int thirtyTwo;
219
220 public void
221 doSomething ()
222 {
223 etcEtcEtc ();
224 }
225};
226
227 B.java
228
229public class B extends A
230{
231 long sixty_four;
232
233 public static void
234 myFunction (B b)
235 {
236 b.doSomething ();
237 }
238}
239
240the Java runtime has transformed the call to ``b.doSomething'' to
241``((A) b).doSomething''.
242
243However, Java also allows overriding this behavior, by specifying the
244@Override keyword:
245
246public class B extends A
247{
248 long sixty_four;
249
250 @Override
251 public void
252 doSomething ()
253 {
254 Something.doSomethingTwo ();
255 super.doSomething ();
256 }
257}
258
259now, any call to ``doSomething'' on a ``B'' created using ``new B ()''
260will end up calling ``Something.doSomethingTwo'', before calling back
261to ``A.doSomething''. This override also applies in reverse; that is
262to say, even if you write:
263
264 ((A) b).doSomething ();
265
266B's version of doSomething will still be called, if ``b'' was created
267using ``new B ()''.
268
269This mechanism is used extensively throughout the Java language and
270Android windowing APIs.
271
272Elsewhere, you will encounter Java code that defines arrays:
273
274public class EmacsFrobinicator
275{
276 public static void
277 emacsFrobinicate (int something)
278 {
279 int[] primesFromSomething;
280
281 primesFromSomething = new int[numberOfPrimes];
282 /* ... */
283 }
284}
285
286Java arrays are similar to C arrays in that they can not grow. But
287they are very much unlike C arrays in that they are always references
288(as opposed to decaying into pointers in only some situations), and
289contain information about their length.
290
291If another function named ``frobinicate1'' takes an array as an
292argument, then it need not take the length of the array.
293
294Instead, it may simply iterate over the array like so:
295
296int i, k;
297
298for (i = 0; i < array.length; ++i)
299 {
300 k = array[i];
301
302 Whatever.doSomethingWithK (k);
303 }
304
305The syntax used to define arrays is also slightly different. As
306arrays are always references, there is no way for you to tell the
307runtime to allocate an array of size N in a structure (class.)
308
309Instead, if you need an array of that size, you must declare a field
310with the type of the array, and allocate the array inside the class's
311constructor, like so:
312
313public class EmacsArrayContainer
314{
315 public int[] myArray;
316
317 public
318 EmacsArrayContainer ()
319 {
320 myArray = new array[10];
321 }
322}
323
324while in C, you could just have written:
325
326struct emacs_array_container
327{
328 int my_array[10];
329};
330
331or, possibly even better,
332
333typedef int emacs_array_container[10];
334
335Alas, Java has no equivalent of `typedef'.
336
337Like in C, Java string literals are delimited by double quotes.
338Unlike C, however, strings are not NULL-terminated arrays of
339characters, but a distinct type named ``String''. They store their
340own length, characters in Java's 16-bit ``char'' type, and are capable
341of holding NULL bytes.
342
343Instead of writing:
344
345wchar_t character;
346extern char *s;
347size_t s;
348
349 for (/* determine n, s in a loop. */)
350 s += mbstowc (&character, s, n);
351
352or:
353
354const char *byte;
355
356for (byte = my_string; *byte; ++byte)
357 /* do something with *byte. */;
358
359or perhaps even:
360
361size_t length, i;
362char foo;
363
364length = strlen (my_string);
365
366for (i = 0; i < length; ++i)
367 foo = my_string[i];
368
369you write:
370
371char foo;
372int i;
373
374for (i = 0; i < myString.length (); ++i)
375 foo = myString.charAt (0);
376
377Java also has stricter rules on what can be used as a truth value in a
378conditional. While in C, any non-zero value is true, Java requires
379that every truth value be of the boolean type ``boolean''.
380
381What this means is that instead of simply writing:
382
383 if (foo || bar)
384
385where foo can either be 1 or 0, and bar can either be NULL or a
386pointer to something, you must explicitly write:
387
388 if (foo != 0 || bar != null)
389
390in Java.
391
392JAVA NATIVE INTERFACE
393
394Java also provides an interface for C code to interface with Java.
395
396C functions exported from a shared library become static Java
397functions within a class, like so:
398
399public class EmacsNative
400{
401 /* Obtain the fingerprint of this build of Emacs. The fingerprint
402 can be used to determine the dump file name. */
403 public static native String getFingerprint ();
404
405 /* Set certain parameters before initializing Emacs.
406
407 assetManager must be the asset manager associated with the
408 context that is loading Emacs. It is saved and remains for the
409 remainder the lifetime of the Emacs process.
410
411 filesDir must be the package's data storage location for the
412 current Android user.
413
414 libDir must be the package's data storage location for native
415 libraries. It is used as PATH.
416
417 cacheDir must be the package's cache directory. It is used as
418 the `temporary-file-directory'.
419
420 pixelDensityX and pixelDensityY are the DPI values that will be
421 used by Emacs.
422
423 classPath must be the classpath of this app_process process, or
424 NULL.
425
426 emacsService must be the EmacsService singleton, or NULL. */
427 public static native void setEmacsParams (AssetManager assetManager,
428 String filesDir,
429 String libDir,
430 String cacheDir,
431 float pixelDensityX,
432 float pixelDensityY,
433 String classPath,
434 EmacsService emacsService);
435}
436
437Where the corresponding C functions are located in android.c, and
438loaded by the special invocation:
439
440 static
441 {
442 System.loadLibrary ("emacs");
443 };
444
445where ``static'' defines a section of code which will be run upon the
446object (containing class) being loaded. This is like:
447
448 __attribute__((constructor))
449
450on systems where shared object constructors are supported.
451
452See http://docs.oracle.com/en/java/javase/19/docs/specs/jni/intro.html
453for more details.
454
455
456
457OVERVIEW OF ANDROID
458
459When the Android system starts an application, it does not actually
460call the application's ``main'' function. It may not even start the
461application's process if one is already running.
462
463Instead, Android is organized around components. When the user opens
464the ``Emacs'' icon, the Android system looks up and starts the
465component associated with the ``Emacs'' icon. In this case, the
466component is called an activity, and is declared in
467the AndroidManifest.xml in this directory:
468
469 <activity android:name="org.gnu.emacs.EmacsActivity"
470 android:launchMode="singleTop"
471 android:windowSoftInputMode="adjustResize"
472 android:exported="true"
473 android:configChanges="orientation|screenSize|screenLayout|keyboardHidden">
474 <intent-filter>
475 <action android:name="android.intent.action.MAIN" />
476 <category android:name="android.intent.category.DEFAULT" />
477 <category android:name="android.intent.category.LAUNCHER" />
478 </intent-filter>
479 </activity>
480
481This tells Android to start the activity defined in ``EmacsActivity''
482(defined in org/gnu/emacs/EmacsActivity.java), a class extending the
483Android class ``Activity''.
484
485To do so, the Android system creates an instance of ``EmacsActivity''
486and the window system window associated with it, and eventually calls:
487
488 Activity activity;
489
490 activity.onCreate (...);
491
492But which ``onCreate'' is really called?
493It is actually the ``onCreate'' defined in EmacsActivity.java, as
494it overrides the ``onCreate'' defined in Android's own Activity class:
495
496 @Override
497 public void
498 onCreate (Bundle savedInstanceState)
499 {
500 FrameLayout.LayoutParams params;
501 Intent intent;
502
503Then, this is what happens step-by-step within the ``onCreate''
504function:
505
506 /* See if Emacs should be started with -Q. */
507 intent = getIntent ();
508 EmacsService.needDashQ
509 = intent.getBooleanExtra ("org.gnu.emacs.START_DASH_Q",
510 false);
511
512Here, Emacs obtains the intent (a request to start a component) which
513was used to start Emacs, and sets a special flag if it contains a
514request for Emacs to start with the ``-Q'' command-line argument.
515
516 /* Set the theme to one without a title bar. */
517
518 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
519 setTheme (android.R.style.Theme_DeviceDefault_NoActionBar);
520 else
521 setTheme (android.R.style.Theme_NoTitleBar);
522
523Next, Emacs sets an appropriate theme for the activity's associated
524window decorations.
525
526 params = new FrameLayout.LayoutParams (LayoutParams.MATCH_PARENT,
527 LayoutParams.MATCH_PARENT);
528
529 /* Make the frame layout. */
530 layout = new FrameLayout (this);
531 layout.setLayoutParams (params);
532
533 /* Set it as the content view. */
534 setContentView (layout);
535
536Then, Emacs creates a ``FrameLayout'', a widget that holds a single
537other widget, and makes it the activity's ``content view''.
538
539The activity itself is a ``FrameLayout'', so the ``layout parameters''
540here apply to the FrameLayout itself, and not its children.
541
542 /* Maybe start the Emacs service if necessary. */
543 EmacsService.startEmacsService (this);
544
545And after that, Emacs calls the static function ``startEmacsService'',
546defined in the class ``EmacsService''. This starts the Emacs service
547component if necessary.
548
549 /* Add this activity to the list of available activities. */
550 EmacsWindowAttachmentManager.MANAGER.registerWindowConsumer (this);
551
552 super.onCreate (savedInstanceState);
553
554Finally, Emacs registers that this activity is now ready to receive
555top-level frames (windows) created from Lisp.
556
557Activities come and go, but Emacs has to stay running in the mean
558time. Thus, Emacs also defines a ``service'', which is a long-running
559component that the Android system allows to run in the background.
560
561Let us go back and review the definition of ``startEmacsService'':
562
563 public static void
564 startEmacsService (Context context)
565 {
566 if (EmacsService.SERVICE == null)
567 {
568 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
569 /* Start the Emacs service now. */
570 context.startService (new Intent (context,
571 EmacsService.class));
572 else
573 /* Display the permanant notification and start Emacs as a
574 foreground service. */
575 context.startForegroundService (new Intent (context,
576 EmacsService.class));
577 }
578 }
579
580If ``EmacsService.SERVICE'' does not yet exist, what this does is to
581tell the ``context'' (the equivalent of an Xlib Display *) to start a
582service defined by the class ``EmacsService''. Eventually, this
583results in ``EmacsService.onCreate'' being called:
584
585 @Override
586 public void
587 onCreate ()
588 {
589 AssetManager manager;
590 Context app_context;
591 String filesDir, libDir, cacheDir, classPath;
592 double pixelDensityX;
593 double pixelDensityY;
594
595Here is what this function does, step-by-step:
596
597 SERVICE = this;
598
599First, it sets the special static variable ``SERVICE'' to ``this'',
600which is a pointer to the ``EmacsService' object that was created.
601
602 handler = new Handler (Looper.getMainLooper ());
603
604Next, it creates a ``Handler'' object for the ``main looper''.
605This is a helper structure which allows executing code on the Android
606user interface thread.
607
608 manager = getAssets ();
609 app_context = getApplicationContext ();
610 metrics = getResources ().getDisplayMetrics ();
611 pixelDensityX = metrics.xdpi;
612 pixelDensityY = metrics.ydpi;
613
614Finally, it obtains:
615
616 - the asset manager, which is used to retrieve assets packaged
617 into the Emacs application package.
618
619 - the application context, used to obtain application specific
620 information.
621
622 - the display metrics, and from them, the X and Y densities in dots
623 per inch.
624
625Then, inside a ``try'' block:
626
627 try
628 {
629 /* Configure Emacs with the asset manager and other necessary
630 parameters. */
631 filesDir = app_context.getFilesDir ().getCanonicalPath ();
632 libDir = getLibraryDirectory ();
633 cacheDir = app_context.getCacheDir ().getCanonicalPath ();
634
635It obtains the names of the Emacs home, shared library, and temporary
636file directories.
637
638 /* Now provide this application's apk file, so a recursive
639 invocation of app_process (through android-emacs) can
640 find EmacsNoninteractive. */
641 classPath = getApkFile ();
642
643The name of the Emacs application package.
644
645 Log.d (TAG, "Initializing Emacs, where filesDir = " + filesDir
646 + ", libDir = " + libDir + ", and classPath = " + classPath);
647
648Prints a debug message to the Android system log with this
649information.
650
651 EmacsNative.setEmacsParams (manager, filesDir, libDir,
652 cacheDir, (float) pixelDensityX,
653 (float) pixelDensityY,
654 classPath, this);
655
656And calls the native function ``setEmacsParams'' (defined in
657android.c) to configure Emacs with this information.
658
659 /* Start the thread that runs Emacs. */
660 thread = new EmacsThread (this, needDashQ);
661 thread.start ();
662
663Then, it allocates an ``EmacsThread'' object, and starts that thread.
664Inside that thread is where Emacs's C code runs.
665
666 }
667 catch (IOException exception)
668 {
669 EmacsNative.emacsAbort ();
670 return;
671
672And here is the purpose of the ``try'' block. Functions related to
673file names in Java will signal errors of various types upon failure.
674
675This ``catch'' block means that the Java virtual machine will abort
676execution of the contents of the ``try'' block as soon as an error of
677type ``IOException'' is encountered, and begin executing the contents
678of the ``catch'' block.
679
680Any failure of that type here is a crash, and
681``EmacsNative.emacsAbort'' is called to quickly abort the process to
682get a useful backtrace.
683 }
684 }
685
686Now, let us look at the definition of the class ``EmacsThread'', found
687in org/gnu/emacs/EmacsThread.java:
688
689public class EmacsThread extends Thread
690{
691 /* Whether or not Emacs should be started -Q. */
692 private boolean startDashQ;
693
694 public
695 EmacsThread (EmacsService service, boolean startDashQ)
696 {
697 super ("Emacs main thread");
698 this.startDashQ = startDashQ;
699 }
700
701 @Override
702 public void
703 run ()
704 {
705 String args[];
706
707 if (!startDashQ)
708 args = new String[] { "libandroid-emacs.so", };
709 else
710 args = new String[] { "libandroid-emacs.so", "-Q", };
711
712 /* Run the native code now. */
713 EmacsNative.initEmacs (args, EmacsApplication.dumpFileName);
714 }
715};
716
717The class itself defines a single field, ``startDashQ'', a constructor
718with an unused argument of the type ``EmacsService'' (which is useful
719while debugging) and a flag ``startDashQ'', and a single function
720``run'', overriding the same function in the class ``Thread''.
721
722When ``thread.start'' is called, the Java virtual machine creates a
723new thread, and then calls the function ``run'' within that thread.
724
725This function then computes a suitable argument vector, and calls
726``EmacsNative.initEmacs'' (defined in android.c), which then calls a
727modified version of the regular Emacs ``main'' function.
728
729At that point, Emacs initialization proceeds as usual:
730Vinitial_window_system is set, loadup.el calls `normal-top-level',
731which calls `command-line', and finally
732`window-system-initialization', which initializes the `android'
733terminal interface as usual.
734
735What happens here is the same as on other platforms. Now, here is
736what happens when the initial frame is created: Fx_create_frame calls
737`android_create_frame_window' to create a top level window:
738
739static void
740android_create_frame_window (struct frame *f)
741{
742 struct android_set_window_attributes attributes;
743 enum android_window_value_mask attribute_mask;
744
745 attributes.background_pixel = FRAME_BACKGROUND_PIXEL (f);
746 attribute_mask = ANDROID_CW_BACK_PIXEL;
747
748 block_input ();
749 FRAME_ANDROID_WINDOW (f)
750 = android_create_window (FRAME_DISPLAY_INFO (f)->root_window,
751 f->left_pos,
752 f->top_pos,
753 FRAME_PIXEL_WIDTH (f),
754 FRAME_PIXEL_HEIGHT (f),
755 attribute_mask, &attributes);
756 unblock_input ();
757}
758
759This calls the function `android_create_window' with some arguments
760whose meanings are identical to the arguments to `XCreateWindow'.
761
762Here is the definition of `android_create_window', in android.c:
763
764android_window
765android_create_window (android_window parent, int x, int y,
766 int width, int height,
767 enum android_window_value_mask value_mask,
768 struct android_set_window_attributes *attrs)
769{
770 static jclass class;
771 static jmethodID constructor;
772 jobject object, parent_object, old;
773 android_window window;
774 android_handle prev_max_handle;
775 bool override_redirect;
776
777What does it do? First, some context:
778
779At any time, there can be at most 65535 Java objects referred to by
780the rest of Emacs through the Java native interface. Each such object
781is assigned a ``handle'' (similar to an XID on X) and given a unique
782type. The function `android_resolve_handle' returns the JNI `jobject'
783associated with a given handle.
784
785 parent_object = android_resolve_handle (parent, ANDROID_HANDLE_WINDOW);
786
787Here, it is being used to look up the `jobject' associated with the
788`parent' handle.
789
790 prev_max_handle = max_handle;
791 window = android_alloc_id ();
792
793Next, `max_handle' is saved, and a new handle is allocated for
794`window'.
795
796 if (!window)
797 error ("Out of window handles!");
798
799An error is signalled if Emacs runs out of available handles.
800
801 if (!class)
802 {
803 class = (*android_java_env)->FindClass (android_java_env,
804 "org/gnu/emacs/EmacsWindow");
805 assert (class != NULL);
806
807Then, if this initialization has not yet been completed, Emacs
808proceeds to find the Java class named ``EmacsWindow''.
809
810 constructor
811 = (*android_java_env)->GetMethodID (android_java_env, class, "<init>",
812 "(SLorg/gnu/emacs/EmacsWindow;"
813 "IIIIZ)V");
814 assert (constructor != NULL);
815
816And it tries to look up the constructor, which should take seven
817arguments:
818
819 S - a short. (the handle ID)
820 Lorg/gnu/Emacs/EmacsWindow; - an instance of the EmacsWindow
821 class. (the parent)
822 IIII - four ints. (the window geometry.)
823 Z - a boolean. (whether or not the
824 window is override-redirect; see
825 XChangeWindowAttributes.)
826
827 old = class;
828 class = (*android_java_env)->NewGlobalRef (android_java_env, class);
829 (*android_java_env)->ExceptionClear (android_java_env);
830 ANDROID_DELETE_LOCAL_REF (old);
831
832Next, it saves a global reference to the class and deletes the local
833reference. Global references will never be deallocated by the Java
834virtual machine as long as they still exist.
835
836 if (!class)
837 memory_full (0);
838 }
839
840 /* N.B. that ANDROID_CW_OVERRIDE_REDIRECT can only be set at window
841 creation time. */
842 override_redirect = ((value_mask
843 & ANDROID_CW_OVERRIDE_REDIRECT)
844 && attrs->override_redirect);
845
846 object = (*android_java_env)->NewObject (android_java_env, class,
847 constructor, (jshort) window,
848 parent_object, (jint) x, (jint) y,
849 (jint) width, (jint) height,
850 (jboolean) override_redirect);
851
852Then, it creates an instance of the ``EmacsWindow'' class with the
853appropriate arguments and previously determined constructor.
854
855 if (!object)
856 {
857 (*android_java_env)->ExceptionClear (android_java_env);
858
859 max_handle = prev_max_handle;
860 memory_full (0);
861
862If creating the object fails, Emacs clears the ``pending exception''
863and signals that it is out of memory.
864 }
865
866 android_handles[window].type = ANDROID_HANDLE_WINDOW;
867 android_handles[window].handle
868 = (*android_java_env)->NewGlobalRef (android_java_env,
869 object);
870 (*android_java_env)->ExceptionClear (android_java_env);
871 ANDROID_DELETE_LOCAL_REF (object);
872
873Otherwise, it associates a new global reference to the object with the
874handle, and deletes the local reference returned from the JNI
875NewObject function.
876
877 if (!android_handles[window].handle)
878 memory_full (0);
879
880If allocating the global reference fails, Emacs signals that it is out
881of memory.
882
883 android_change_window_attributes (window, value_mask, attrs);
884 return window;
885
886Otherwise, it applies the specified window attributes and returns the
887handle of the new window.
888}
889
890
891
892DRAWABLES, CURSORS AND HANDLES
893
894Each widget created by Emacs corresponds to a single ``window'', which
895has its own backing store. This arrangement is quite similar to X.
896
897C code does not directly refer to the EmacsView widgets that implement
898the UI logic behind windows. Instead, its handles refer to
899EmacsWindow structures, which contain the state necessary to interact
900with the widgets in an orderly and synchronized manner.
901
902Like X, both pixmaps and windows are drawable resources, and the same
903graphics operations can be applied to both. Thus, a separate
904EmacsPixmap structure is used to wrap around Android Bitmap resources,
905and the Java-level graphics operation functions are capable of
906operating on them both.
907
908Finally, graphics contexts are maintained on both the C and Java
909levels; the C state recorded in `struct android_gc' is kept in sync
910with the Java state in the GContext handle's corresponding EmacsGC
911structure, and cursors are used through handles that refer to
912EmacsCursor structures that hold system PointerIcons.
913
914In all cases, the interfaces provided are identical to X.
915
916
917
918EVENT LOOP
919
920In a typical Android application, the event loop is managed by the
921operating system, and callbacks (implemented through overriding
922separate functions in widgets) are run by the event loop wherever
923necessary. The thread which runs the event loop is also the only
924thread capable of creating and manipulating widgets and activities,
925and is referred to as the ``UI thread''.
926
927These callbacks are used by Emacs to write representations of X-like
928events to a separate event queue, which are then read from Emacs's own
929event loop running in a separate thread. This is accomplished through
930replacing `select' by a function which waits for the event queue to be
931occupied, in addition to any file descriptors that `select' would
932normally wait for.
933
934Conversely, Emacs's event loop sometimes needs to send events to the
935UI thread. These events are implemented as tiny fragments of code,
936which are run as they are received by the main thread.
937
938A typical example is `displayToast', which is implemented in
939EmacsService.java:
940
941 public void
942 displayToast (final String string)
943 {
944 runOnUiThread (new Runnable () {
945 @Override
946 public void
947 run ()
948 {
949 Toast toast;
950
951 toast = Toast.makeText (getApplicationContext (),
952 string, Toast.LENGTH_SHORT);
953 toast.show ();
954 }
955 });
956 }
957
958Here, the variable `string' is used by a nested function. This nested
959function contains a copy of that variable, and is run on the main
960thread using the function `runOnUiThread', in order to display a short
961status message on the display.
962
963When Emacs needs to wait for the nested function to finish, it uses a
964mechanism implemented in `syncRunnable'. This mechanism first calls a
965deadlock avoidance mechanism, then runs a nested function on the UI
966thread, which is expected to signal itself as a condition variable
967upon completion. It is typically used to allocate resources that can
968only be allocated from the UI thread, or to obtain non-thread-safe
969information. The following function is an example; it returns a new
970EmacsView widget corresponding to the provided window:
971
972 public EmacsView
973 getEmacsView (final EmacsWindow window, final int visibility,
974 final boolean isFocusedByDefault)
975 {
976 Runnable runnable;
977 final EmacsHolder<EmacsView> view;
978
979 view = new EmacsHolder<EmacsView> ();
980
981 runnable = new Runnable () {
982 public void
983 run ()
984 {
985 synchronized (this)
986 {
987 view.thing = new EmacsView (window);
988 view.thing.setVisibility (visibility);
989
990 /* The following function is only present on Android 26
991 or later. */
992 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
993 view.thing.setFocusedByDefault (isFocusedByDefault);
994
995 notify ();
996 }
997 }
998 };
999
1000 syncRunnable (runnable);
1001 return view.thing;
1002 }
1003
1004As no value can be directly returned from the nested function, a
1005separate container object is used to hold the result after the
1006function finishes execution. Note the type name inside the angle
1007brackets: this type is substituted into the class definition as it is
1008used; a definition such as:
1009
1010public class Foo<T>
1011{
1012 T bar;
1013};
1014
1015can not be used alone:
1016
1017 Foo holder; /* Error! */
1018
1019but must have a type specified:
1020
1021 Foo<Object> holder;
1022
1023in which case the effective definition is:
1024
1025public class Foo
1026{
1027 Object bar;
1028};
1029
1030
1031
1032COMPATIBILITY
1033
1034There are three variables set within every Android application that
1035extert influence over the set of Android systems it supports, and the
1036measures it must take to function faithfully on each of those systems:
1037the minimum API level, compile SDK version and target API level.
1038
1039The minimum API level is the earliest version of Android that is
1040permitted to install and run the application. For Emacs, this is
1041established by detecting the __ANDROID_API__ preprocessor macro
1042defined within the Android C compiler.
1043
1044Before Java code executes any Android API calls that are not present
1045within Android 2.2 (API level 8), the lowest API level supported by
1046Emacs as a whole, it must first check the value of the:
1047
1048 Build.VERSION.SDK_INT
1049
1050variable, which is always set to the API level of the system Emacs is
1051presently installed within. For example, before calling
1052`dispatchKeyEventFromInputMethod', a function absent from Android 6.0
1053(API level 23) or earlier, check:
1054
1055 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
1056 view.imManager.dispatchKeyEventFromInputMethod (view, key);
1057 else
1058 {
1059
1060where `N' is a constant defined to 24.
1061
1062The compile SDK version is the version of the Android SDK headers Java
1063code is compiled against. Because Java does not provide conditional
1064compilation constructs, Emacs can't be compiled with any version of
1065these headers other than the version mentioned in `java/INSTALL', but
1066the headers used do not affect the set of supported systems provided
1067that the version checks illustrated above are performed where
1068necessary.
1069
1070The target API level is a number within java/AndroidManifest.xml.in
1071the system refers to when deciding whether to enable
1072backwards-incompatible modifications to the behavior of various system
1073APIs. For any given Android version, backwards incompatible changes
1074in that version will be disabled for applications whose target API
1075levels don't exceed its own.
1076
1077The target API should nevertheless be updated to match every major
1078Android update, as Google has stated their intentions to prohibit
1079users from installing applications targeting ``out-of-date'' versions
1080of Android, though this threat has hitherto been made good on.
1081
1082
1083
1084This file is part of GNU Emacs.
1085
1086GNU Emacs is free software: you can redistribute it and/or modify
1087it under the terms of the GNU General Public License as published by
1088the Free Software Foundation, either version 3 of the License, or
1089(at your option) any later version.
1090
1091GNU Emacs is distributed in the hope that it will be useful,
1092but WITHOUT ANY WARRANTY; without even the implied warranty of
1093MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1094GNU General Public License for more details.
1095
1096You should have received a copy of the GNU General Public License
1097along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.