aboutsummaryrefslogtreecommitdiffstats
path: root/java/README
diff options
context:
space:
mode:
authorPo Lu2023-01-25 18:44:47 +0800
committerPo Lu2023-01-25 18:44:47 +0800
commit0900bfbcc57c555909cb75c38eb0ed26fb6964ef (patch)
tree9a2fa4328defab79f1cb3dcfac4f3c071bf0a633 /java/README
parent6f9a2a8f29c7faf13d0d86001b140746efc455b5 (diff)
downloademacs-0900bfbcc57c555909cb75c38eb0ed26fb6964ef.tar.gz
emacs-0900bfbcc57c555909cb75c38eb0ed26fb6964ef.zip
Update Android port
* doc/emacs/android.texi (Android Startup, Android Environment): Document that restrictions on starting Emacs have been lifted. * java/README: Document Java for Emacs developers and how the Android port works. * java/org/gnu/emacs/EmacsApplication.java (EmacsApplication) (findDumpFile): New function. (onCreate): Factor out dump file finding functions to there. * java/org/gnu/emacs/EmacsNative.java (EmacsNative): Update function declarations. * java/org/gnu/emacs/EmacsNoninteractive.java (EmacsNoninteractive): New class. * java/org/gnu/emacs/EmacsService.java (EmacsService, getApkFile) (onCreate): Pass classpath to setEmacsParams. * java/org/gnu/emacs/EmacsThread.java (EmacsThread): Make run an override. * lisp/loadup.el: Don't dump on Android when noninteractive. * lisp/shell.el (shell--command-completion-data): Handle inaccessible directories. * src/Makefile.in (android-emacs): Link with gnulib. * src/android-emacs.c (main): Implement to launch app-process and then EmacsNoninteractive. * src/android.c (setEmacsParams): New argument `class_path'. Don't set stuff up when running noninteractive. * src/android.h (initEmacs): Likewise. * src/androidfont.c (init_androidfont): * src/androidselect.c (init_androidselect): Don't initialize when running noninteractive. * src/emacs.c (load_pdump): New argument `dump_file'. (android_emacs_init): Give new argument `dump_file' to `load_pdump'. * src/sfntfont-android.c (init_sfntfont_android): Don't initialize when running noninteractive.
Diffstat (limited to 'java/README')
-rw-r--r--java/README824
1 files changed, 824 insertions, 0 deletions
diff --git a/java/README b/java/README
index 05edf7744de..44f5a415162 100644
--- a/java/README
+++ b/java/README
@@ -10,3 +10,827 @@ to install different builds of Emacs on top of each other.
10Please keep the Java code indented with tabs and formatted according 10Please keep the Java code indented with tabs and formatted according
11to the rules for C code in the GNU coding standards. Always use 11to the rules for C code in the GNU coding standards. Always use
12C-style comments. 12C-style comments.
13
14======================================================================
15
16OVERVIEW OF JAVA
17
18Emacs developers do not know Java, and there is no reason they should
19have to. Thus, the code in this directory is confined to what is
20strictly necessary to support Emacs, and only uses a subset of Java
21written in a way that is easily understandable to C programmers.
22
23Java is required because the entire Android runtime is based around
24Java, and there is no way to write an Android program which runs
25without Java.
26
27This text exists to prime other Emacs developers, already familar with
28C, on the basic architecture of the Android port, and to teach them
29how to read and write the Java code found in this directory.
30
31Java is an object oriented language with automatic memory management
32compiled down to bytecode, which is then subject to interpretation by
33a Java virtual machine.
34
35What that means, is that:
36
37struct emacs_window
38{
39 int some_fields;
40 int of_emacs_window;
41};
42
43static void
44do_something_with_emacs_window (struct emacs_window *a, int n)
45{
46 a->some_fields = a->of_emacs_window + n;
47}
48
49would be written:
50
51public class EmacsWindow
52{
53 public int someFields;
54 public int ofEmacsWindow;
55
56 public void
57 doSomething (int n)
58 {
59 someFields = ofEmacsWindow + n;
60 }
61}
62
63and instead of doing:
64
65do_something_with_emacs_window (my_window, 1);
66
67you say:
68
69myWindow.doSomething (1);
70
71In addition to functions associated with an object of a given class
72(such as EmacsWindow), Java also has two other kinds of functions.
73
74The first are so-called ``static'' functions (the static means
75something entirely different from what it does in C.)
76
77A static function, while still having to be defined within a class,
78can be called without any object. Instead of the object, you write
79the name of the Java class within which it is defined. For example,
80the following C code:
81
82int
83multiply_a_with_b_and_then_add_c (int a, int b, int c)
84{
85 return a * b + c;
86}
87
88would be:
89
90public class EmacsSomething
91{
92 public static int
93 multiplyAWithBAndThenAddC (int a, int b, int c)
94 {
95 return a * b + c;
96 }
97};
98
99Then, instead of calling:
100
101int foo;
102
103foo = multiply_a_with_b_then_add_c (1, 2, 3);
104
105you say:
106
107int foo;
108
109foo = EmacsSomething.multiplyAWithBAndThenAddC (1, 2, 3);
110
111In Java, ``static'' does not mean that the function is only used
112within its compilation unit! Instead, the ``private'' qualifier is
113used to mean more or less the same thing:
114
115static void
116this_procedure_is_only_used_within_this_file (void)
117{
118 do_something ();
119}
120
121becomes
122
123public class EmacsSomething
124{
125 private static void
126 thisProcedureIsOnlyUsedWithinThisClass ()
127 {
128
129 }
130}
131
132the other kind are called ``constructors''. They are functions that
133must be called to allocate memory to hold a class:
134
135public class EmacsFoo
136{
137 int bar;
138
139 public
140 EmacsFoo (int tokenA, int tokenB)
141 {
142 bar = tokenA + tokenB;
143 }
144}
145
146now, the following statement:
147
148EmacsFoo foo;
149
150foo = new EmacsFoo (1, 2);
151
152becomes more or less equivalent to the following C code:
153
154struct emacs_foo
155{
156 int bar;
157};
158
159struct emacs_foo *
160make_emacs_foo (int token_a, int token_b)
161{
162 struct emacs_foo *foo;
163
164 foo = xmalloc (sizeof *foo);
165 foo->bar = token_a + token_b;
166
167 return foo;
168}
169
170/* ... */
171
172struct emacs_foo *foo;
173
174foo = make_emacs_foo (1, 2);
175
176A class may have any number of constructors, or no constructors at
177all, in which case the compiler inserts an empty constructor.
178
179
180
181Sometimes, you will see Java code that looks like this:
182
183 allFiles = filesDirectory.listFiles (new FileFilter () {
184 @Override
185 public boolean
186 accept (File file)
187 {
188 return (!file.isDirectory ()
189 && file.getName ().endsWith (".pdmp"));
190 }
191 });
192
193This is Java's version of GCC's nested function extension. The major
194difference is that the nested function may still be called even after
195it goes out of scope, and always retains a reference to the class and
196local variables around where it was called.
197
198Being an object-oriented language, Java also allows defining that a
199class ``extends'' another class. The following C code:
200
201struct a
202{
203 long thirty_two;
204};
205
206struct b
207{
208 struct a a;
209 long long sixty_four;
210};
211
212extern void do_something (struct a *);
213
214void
215my_function (struct b *b)
216{
217 do_something (&b->a);
218}
219
220is roughly equivalent to the following Java code, split into two
221files:
222
223 A.java
224
225public class A
226{
227 int thirtyTwo;
228
229 public void
230 doSomething ()
231 {
232 etcEtcEtc ();
233 }
234};
235
236 B.java
237
238public class B extends A
239{
240 long sixty_four;
241
242 public static void
243 myFunction (B b)
244 {
245 b.doSomething ();
246 }
247}
248
249the Java runtime has transformed the call to ``b.doSomething'' to
250``((A) b).doSomething''.
251
252However, Java also allows overriding this behavior, by specifying the
253@Override keyword:
254
255public class B extends A
256{
257 long sixty_four;
258
259 @Override
260 public void
261 doSomething ()
262 {
263 Something.doSomethingTwo ();
264 super.doSomething ();
265 }
266}
267
268now, any call to ``doSomething'' on a ``B'' created using ``new B ()''
269will end up calling ``Something.doSomethingTwo'', before calling back
270to ``A.doSomething''. This override also applies in reverse; that is
271to say, even if you write:
272
273 ((A) b).doSomething ();
274
275B's version of doSomething will still be called, if ``b'' was created
276using ``new B ()''.
277
278This mechanism is used extensively throughout the Java language and
279Android windowing APIs.
280
281Elsewhere, you will encounter Java code that defines arrays:
282
283public class EmacsFrobinicator
284{
285 public static void
286 emacsFrobinicate (int something)
287 {
288 int[] primesFromSomething;
289
290 primesFromSomething = new int[numberOfPrimes];
291 /* ... */
292 }
293}
294
295Java arrays are similar to C arrays in that they can not grow. But
296they are very much unlike C arrays in that they are always references
297(as opposed to decaying into pointers in various situations), and
298contain information about their length.
299
300If another function named ``frobinicate1'' takes an array as an
301argument, then it need not take the length of the array.
302
303Instead, it simply iterates over the array like so:
304
305int i, k;
306
307for (i = 0; i < array.length; ++i)
308 {
309 k = array[i];
310
311 Whatever.doSomethingWithK (k);
312 }
313
314The syntax used to define arrays is also slightly different. As
315arrays are always references, there is no way for you to tell the
316runtime to allocate an array of size N in a structure (class.)
317
318Instead, if you need an array of that size, you must declare a field
319with the type of the array, and allocate the array inside the class's
320constructor, like so:
321
322public class EmacsArrayContainer
323{
324 public int[] myArray;
325
326 public
327 EmacsArrayContainer ()
328 {
329 myArray = new array[10];
330 }
331}
332
333while in C, you could just have written:
334
335struct emacs_array_container
336{
337 int my_array[10];
338};
339
340or, possibly even better,
341
342typedef int my_array[10];
343
344Alas, Java has no equivalent of `typedef'.
345
346JAVA NATIVE INTERFACE
347
348Java also provides an interface for C code to interface with Java.
349
350C functions exported from a shared library become static Java
351functions within a class, like so:
352
353public class EmacsNative
354{
355 /* Obtain the fingerprint of this build of Emacs. The fingerprint
356 can be used to determine the dump file name. */
357 public static native String getFingerprint ();
358
359 /* Set certain parameters before initializing Emacs.
360
361 assetManager must be the asset manager associated with the
362 context that is loading Emacs. It is saved and remains for the
363 remainder the lifetime of the Emacs process.
364
365 filesDir must be the package's data storage location for the
366 current Android user.
367
368 libDir must be the package's data storage location for native
369 libraries. It is used as PATH.
370
371 cacheDir must be the package's cache directory. It is used as
372 the `temporary-file-directory'.
373
374 pixelDensityX and pixelDensityY are the DPI values that will be
375 used by Emacs.
376
377 classPath must be the classpath of this app_process process, or
378 NULL.
379
380 emacsService must be the EmacsService singleton, or NULL. */
381 public static native void setEmacsParams (AssetManager assetManager,
382 String filesDir,
383 String libDir,
384 String cacheDir,
385 float pixelDensityX,
386 float pixelDensityY,
387 String classPath,
388 EmacsService emacsService);
389}
390
391Where the corresponding C functions are located in android.c, and
392loaded by the special invocation:
393
394 static
395 {
396 System.loadLibrary ("emacs");
397 };
398
399
400See http://docs.oracle.com/en/java/javase/19/docs/specs/jni/intro.html
401for more details.
402
403
404
405OVERVIEW OF ANDROID
406
407When the Android system starts an application, it does not actually
408call the application's ``main'' function. It may not even start the
409application's process if one is already running.
410
411Instead, Android is organized around components. When the user opens
412the ``Emacs'' icon, the Android system looks up and starts the
413component associated with the ``Emacs'' icon. In this case, the
414component is called an activity, and is declared in
415the AndroidManifest.xml in this directory:
416
417 <activity android:name="org.gnu.emacs.EmacsActivity"
418 android:launchMode="singleTop"
419 android:windowSoftInputMode="adjustResize"
420 android:exported="true"
421 android:configChanges="orientation|screenSize|screenLayout|keyboardHidden">
422 <intent-filter>
423 <action android:name="android.intent.action.MAIN" />
424 <category android:name="android.intent.category.DEFAULT" />
425 <category android:name="android.intent.category.LAUNCHER" />
426 </intent-filter>
427 </activity>
428
429This tells Android to start the activity defined in ``EmacsActivity''
430(defined in org/gnu/emacs/EmacsActivity.java), a class extending the
431Android class ``Activity''.
432
433To do so, the Android system creates an instance of ``EmacsActivity''
434and the window system window associated with it, and eventually calls:
435
436 Activity activity;
437
438 activity.onCreate (...);
439
440But which ``onCreate'' is really called?
441It is actually the ``onCreate'' defined in EmacsActivity.java, as
442it overrides the ``onCreate'' defined in Android's own Activity class:
443
444 @Override
445 public void
446 onCreate (Bundle savedInstanceState)
447 {
448 FrameLayout.LayoutParams params;
449 Intent intent;
450
451Then, this is what happens step-by-step within the ``onCreate''
452function:
453
454 /* See if Emacs should be started with -Q. */
455 intent = getIntent ();
456 EmacsService.needDashQ
457 = intent.getBooleanExtra ("org.gnu.emacs.START_DASH_Q",
458 false);
459
460Here, Emacs obtains the intent (a request to start a component) which
461was used to start Emacs, and sets a special flag if it contains a
462request for Emacs to start with the ``-Q'' command-line argument.
463
464 /* Set the theme to one without a title bar. */
465
466 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
467 setTheme (android.R.style.Theme_DeviceDefault_NoActionBar);
468 else
469 setTheme (android.R.style.Theme_NoTitleBar);
470
471Next, Emacs sets an appropriate theme for the activity's associated
472window decorations.
473
474 params = new FrameLayout.LayoutParams (LayoutParams.MATCH_PARENT,
475 LayoutParams.MATCH_PARENT);
476
477 /* Make the frame layout. */
478 layout = new FrameLayout (this);
479 layout.setLayoutParams (params);
480
481 /* Set it as the content view. */
482 setContentView (layout);
483
484Then, Emacs creates a ``FrameLayout'', a widget that holds a single
485other widget, and makes it the activity's ``content view''.
486
487The activity itself is a ``FrameLayout'', so the ``layout parameters''
488here apply to the FrameLayout itself, and not its children.
489
490 /* Maybe start the Emacs service if necessary. */
491 EmacsService.startEmacsService (this);
492
493And after that, Emacs calls the static function ``startEmacsService'',
494defined in the class ``EmacsService''. This starts the Emacs service
495component if necessary.
496
497 /* Add this activity to the list of available activities. */
498 EmacsWindowAttachmentManager.MANAGER.registerWindowConsumer (this);
499
500 super.onCreate (savedInstanceState);
501
502Finally, Emacs registers that this activity is now ready to receive
503top-level frames (windows) created from Lisp.
504
505Activities come and go, but Emacs has to stay running in the mean
506time. Thus, Emacs also defines a ``service'', which is a long-running
507component that the Android system allows to run in the background.
508
509Let us go back and review the definition of ``startEmacsService'':
510
511 public static void
512 startEmacsService (Context context)
513 {
514 if (EmacsService.SERVICE == null)
515 {
516 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
517 /* Start the Emacs service now. */
518 context.startService (new Intent (context,
519 EmacsService.class));
520 else
521 /* Display the permanant notification and start Emacs as a
522 foreground service. */
523 context.startForegroundService (new Intent (context,
524 EmacsService.class));
525 }
526 }
527
528If ``EmacsService.SERVICE'' does not yet exist, what this does is to
529tell the ``context'' (the equivalent of an Xlib Display *) to start a
530service defined by the class ``EmacsService''. Eventually, this
531results in ``EmacsService.onCreate'' being called:
532
533 @Override
534 public void
535 onCreate ()
536 {
537 AssetManager manager;
538 Context app_context;
539 String filesDir, libDir, cacheDir, classPath;
540 double pixelDensityX;
541 double pixelDensityY;
542
543Here is what this function does, step-by-step:
544
545 SERVICE = this;
546
547First, it sets the special static variable ``SERVICE'' to ``this'',
548which is a pointer to the ``EmacsService' object that was created.
549
550 handler = new Handler (Looper.getMainLooper ());
551
552Next, it creates a ``Handler'' object for the ``main looper''.
553This is a helper structure which allows executing code on the Android
554user interface thread.
555
556 manager = getAssets ();
557 app_context = getApplicationContext ();
558 metrics = getResources ().getDisplayMetrics ();
559 pixelDensityX = metrics.xdpi;
560 pixelDensityY = metrics.ydpi;
561
562Finally, it obtains:
563
564 - the asset manager, which is used to retrieve assets packaged
565 into the Emacs application package.
566
567 - the application context, used to obtain application specific
568 information.
569
570 - the display metrics, and from them, the X and Y densities in dots
571 per inch.
572
573Then, inside a ``try'' block:
574
575 try
576 {
577 /* Configure Emacs with the asset manager and other necessary
578 parameters. */
579 filesDir = app_context.getFilesDir ().getCanonicalPath ();
580 libDir = getLibraryDirectory ();
581 cacheDir = app_context.getCacheDir ().getCanonicalPath ();
582
583It obtains the names of the Emacs home, shared library, and temporary
584file directories.
585
586 /* Now provide this application's apk file, so a recursive
587 invocation of app_process (through android-emacs) can
588 find EmacsNoninteractive. */
589 classPath = getApkFile ();
590
591The name of the Emacs application package.
592
593 Log.d (TAG, "Initializing Emacs, where filesDir = " + filesDir
594 + ", libDir = " + libDir + ", and classPath = " + classPath);
595
596Prints a debug message to the Android system log with this
597information.
598
599 EmacsNative.setEmacsParams (manager, filesDir, libDir,
600 cacheDir, (float) pixelDensityX,
601 (float) pixelDensityY,
602 classPath, this);
603
604And calls the native function ``setEmacsParams'' (defined in
605android.c) to configure Emacs with this information.
606
607 /* Start the thread that runs Emacs. */
608 thread = new EmacsThread (this, needDashQ);
609 thread.start ();
610
611Then, it allocates an ``EmacsThread'' object, and starts that thread.
612Inside that thread is where Emacs's C code runs.
613
614 }
615 catch (IOException exception)
616 {
617 EmacsNative.emacsAbort ();
618 return;
619
620And here is the purpose of the ``try'' block. Functions related to
621file names in Java will signal errors of various types upon failure.
622
623This ``catch'' block means that the Java virtual machine will abort
624execution of the contents of the ``try'' block as soon as an error of
625type ``IOException'' is encountered, and begin executing the contents
626of the ``catch'' block.
627
628Any failure of that type here is a crash, and
629``EmacsNative.emacsAbort'' is called to quickly abort the process to
630get a useful backtrace.
631 }
632 }
633
634Now, let us look at the definition of the class ``EmacsThread'', found
635in org/gnu/emacs/EmacsThread.java:
636
637public class EmacsThread extends Thread
638{
639 /* Whether or not Emacs should be started -Q. */
640 private boolean startDashQ;
641
642 public
643 EmacsThread (EmacsService service, boolean startDashQ)
644 {
645 super ("Emacs main thread");
646 this.startDashQ = startDashQ;
647 }
648
649 @Override
650 public void
651 run ()
652 {
653 String args[];
654
655 if (!startDashQ)
656 args = new String[] { "libandroid-emacs.so", };
657 else
658 args = new String[] { "libandroid-emacs.so", "-Q", };
659
660 /* Run the native code now. */
661 EmacsNative.initEmacs (args, EmacsApplication.dumpFileName);
662 }
663};
664
665The class itself defines a single field, ``startDashQ'', a constructor
666with an unused argument of the type ``EmacsService'' (which is useful
667while debugging) and a flag ``startDashQ'', and a single function
668``run'', overriding the same function in the class ``Thread''.
669
670When ``thread.start'' is called, the Java virtual machine creates a
671new thread, and then calls the function ``run'' within that thread.
672
673This function then computes a suitable argument vector, and calls
674``EmacsNative.initEmacs'' (defined in android.c), which then calls a
675modified version of the regular Emacs ``main'' function.
676
677At that point, Emacs initialization proceeds as usual:
678Vinitial_window_system is set, loadup.el calls `normal-top-level',
679which calls `command-line', and finally
680`window-system-initialization', which initializes the `android'
681terminal interface as usual.
682
683What happens here is the same as on other platforms. Now, here is
684what happens when the initial frame is created: Fx_create_frame calls
685`android_create_frame_window' to create a top level window:
686
687static void
688android_create_frame_window (struct frame *f)
689{
690 struct android_set_window_attributes attributes;
691 enum android_window_value_mask attribute_mask;
692
693 attributes.background_pixel = FRAME_BACKGROUND_PIXEL (f);
694 attribute_mask = ANDROID_CW_BACK_PIXEL;
695
696 block_input ();
697 FRAME_ANDROID_WINDOW (f)
698 = android_create_window (FRAME_DISPLAY_INFO (f)->root_window,
699 f->left_pos,
700 f->top_pos,
701 FRAME_PIXEL_WIDTH (f),
702 FRAME_PIXEL_HEIGHT (f),
703 attribute_mask, &attributes);
704 unblock_input ();
705}
706
707This calls the function `android_create_window' with some arguments
708whose meanings are identical to the arguments to `XCreateWindow'.
709
710Here is the definition of `android_create_window', in android.c:
711
712android_window
713android_create_window (android_window parent, int x, int y,
714 int width, int height,
715 enum android_window_value_mask value_mask,
716 struct android_set_window_attributes *attrs)
717{
718 static jclass class;
719 static jmethodID constructor;
720 jobject object, parent_object, old;
721 android_window window;
722 android_handle prev_max_handle;
723 bool override_redirect;
724
725What does it do? First, some context:
726
727At any time, there can be at most 65535 Java objects referred to by
728the rest of Emacs through the Java native interface. Each such object
729is assigned a ``handle'' (similar to an XID on X) and given a unique
730type. The function `android_resolve_handle' returns the JNI `jobject'
731associated with a given handle.
732
733 parent_object = android_resolve_handle (parent, ANDROID_HANDLE_WINDOW);
734
735Here, it is being used to look up the `jobject' associated with the
736`parent' handle.
737
738 prev_max_handle = max_handle;
739 window = android_alloc_id ();
740
741Next, `max_handle' is saved, and a new handle is allocated for
742`window'.
743
744 if (!window)
745 error ("Out of window handles!");
746
747An error is signalled if Emacs runs out of available handles.
748
749 if (!class)
750 {
751 class = (*android_java_env)->FindClass (android_java_env,
752 "org/gnu/emacs/EmacsWindow");
753 assert (class != NULL);
754
755Then, if this initialization has not yet been completed, Emacs
756proceeds to find the Java class named ``EmacsWindow''.
757
758 constructor
759 = (*android_java_env)->GetMethodID (android_java_env, class, "<init>",
760 "(SLorg/gnu/emacs/EmacsWindow;"
761 "IIIIZ)V");
762 assert (constructor != NULL);
763
764And it tries to look up the constructor, which should take seven
765arguments:
766
767 S - a short. (the handle ID)
768 Lorg/gnu/Emacs/EmacsWindow; - an instance of the EmacsWindow
769 class. (the parent)
770 IIII - four ints. (the window geometry.)
771 Z - a boolean. (whether or not the
772 window is override-redirect; see
773 XChangeWindowAttributes.)
774
775 old = class;
776 class = (*android_java_env)->NewGlobalRef (android_java_env, class);
777 (*android_java_env)->ExceptionClear (android_java_env);
778 ANDROID_DELETE_LOCAL_REF (old);
779
780Next, it saves a global reference to the class and deletes the local
781reference. Global references will never be deallocated by the Java
782virtual machine as long as they still exist.
783
784 if (!class)
785 memory_full (0);
786 }
787
788 /* N.B. that ANDROID_CW_OVERRIDE_REDIRECT can only be set at window
789 creation time. */
790 override_redirect = ((value_mask
791 & ANDROID_CW_OVERRIDE_REDIRECT)
792 && attrs->override_redirect);
793
794 object = (*android_java_env)->NewObject (android_java_env, class,
795 constructor, (jshort) window,
796 parent_object, (jint) x, (jint) y,
797 (jint) width, (jint) height,
798 (jboolean) override_redirect);
799
800Then, it creates an instance of the ``EmacsWindow'' class with the
801appropriate arguments and previously determined constructor.
802
803 if (!object)
804 {
805 (*android_java_env)->ExceptionClear (android_java_env);
806
807 max_handle = prev_max_handle;
808 memory_full (0);
809
810If creating the object fails, Emacs clears the ``pending exception''
811and signals that it is out of memory.
812 }
813
814 android_handles[window].type = ANDROID_HANDLE_WINDOW;
815 android_handles[window].handle
816 = (*android_java_env)->NewGlobalRef (android_java_env,
817 object);
818 (*android_java_env)->ExceptionClear (android_java_env);
819 ANDROID_DELETE_LOCAL_REF (object);
820
821Otherwise, it associates a new global reference to the object with the
822handle, and deletes the local reference returned from the JNI
823NewObject function.
824
825 if (!android_handles[window].handle)
826 memory_full (0);
827
828If allocating the global reference fails, Emacs signals that it is out
829of memory.
830
831 android_change_window_attributes (window, value_mask, attrs);
832 return window;
833
834Otherwise, it applies the specified window attributes and returns the
835handle of the new window.
836}