aboutsummaryrefslogtreecommitdiffstats
path: root/java/org
diff options
context:
space:
mode:
authorPo Lu2023-01-19 22:19:06 +0800
committerPo Lu2023-01-19 22:19:06 +0800
commita496509cedb17109d0e6297a74e2ff8ed526333c (patch)
tree46f3db2be263de7074675a5188796e25f21d4888 /java/org
parent6253e7e74249c7cdfa86723f0b91a1d207cb143e (diff)
downloademacs-a496509cedb17109d0e6297a74e2ff8ed526333c.tar.gz
emacs-a496509cedb17109d0e6297a74e2ff8ed526333c.zip
Update Android port
* .gitignore: Add new files. * INSTALL.android: Explain how to build Emacs for ancient versions of Android. * admin/merge-gnulib (GNULIB_MODULES): Add getdelim. * build-aux/config.guess (timestamp, version): * build-aux/config.sub (timestamp, version): Autoupdate. * configure.ac (BUILD_DETAILS, ANDROID_MIN_SDK): (ANDROID_STUBIFY): Allow specifying CFLAGS via ANDROID_CFLAGS. Add new configure tests for Android API version when not explicitly specified. * doc/emacs/android.texi (Android): Add reference to ``Other Input Devices''. (Android File System): Remove restrictions on directory-files on the assets directory. * doc/emacs/emacs.texi (Top): Add Other Input Devices to menu. * doc/emacs/input.texi (Other Input Devices): New node. * doc/lispref/commands.texi (Touchscreen Events): Document changes to touchscreen input events. * doc/lispref/frames.texi (Pop-Up Menus): Likewise. * etc/NEWS: Announce changes. * java/Makefile.in: Use lib-src/asset-directory-tool to generate an `directory-tree' file placed in /assets. * java/debug.sh: Large adjustments to support Android 2.2 and later. * java/org/gnu/emacs/EmacsContextMenu.java (inflateMenuItems): * java/org/gnu/emacs/EmacsCopyArea.java (perform): * java/org/gnu/emacs/EmacsDialog.java (toAlertDialog): * java/org/gnu/emacs/EmacsDrawLine.java (perform): * java/org/gnu/emacs/EmacsDrawRectangle.java (perform): * java/org/gnu/emacs/EmacsDrawable.java (EmacsDrawable): * java/org/gnu/emacs/EmacsFillPolygon.java (perform): * java/org/gnu/emacs/EmacsFillRectangle.java (perform): * java/org/gnu/emacs/EmacsGC.java (EmacsGC): * java/org/gnu/emacs/EmacsPixmap.java (EmacsPixmap): (destroyHandle): * java/org/gnu/emacs/EmacsSdk7FontDriver.java (draw): Avoid redundant canvas saves and restores. * java/org/gnu/emacs/EmacsService.java (run): * java/org/gnu/emacs/EmacsView.java (EmacsView): (handleDirtyBitmap): * java/org/gnu/emacs/EmacsWindow.java (changeWindowBackground) (EmacsWindow): Make compatible with Android 2.2 and later. * lib-src/Makefile.in (DONT_INSTALL): Add asset-directory-tool on Android.:(asset-directory-tool{EXEEXT}): New target. * lib-src/asset-directory-tool.c (struct directory_tree, xmalloc) (main_1, main_2, main): New file. * lib, m4: Merge from gnulib. This will be reverted before merging to master. * lisp/button.el (button-map): (push-button): * lisp/frame.el (display-popup-menus-p): Improve touchscreen support. * lisp/subr.el (event-start): (event-end): Handle touchscreen events. * lisp/touch-screen.el (touch-screen-handle-timeout): (touch-screen-handle-point-update): (touch-screen-handle-point-up): (touch-screen-track-tap): (touch-screen-track-drag): (touch-screen-drag-mode-line-1): (touch-screen-drag-mode-line): New functions. ([mode-line touchscreen-begin]): ([bottom-divider touchscreen-begin]): Bind new events. * lisp/wid-edit.el (widget-event-point): (widget-keymap): (widget-event-start): (widget-button--check-and-call-button): (widget-button-click): Improve touchscreen support. * src/alloc.c (make_lisp_symbol): Avoid ICE on Android NDK GCC. (mark_pinned_symbols): Likewise. * src/android.c (struct android_emacs_window): New struct. (window_class): New variable. (android_run_select_thread): Add workaround for Android platform bug. (android_extract_long, android_scan_directory_tree): New functions. (android_file_access_p): Use those functions instead. (android_init_emacs_window): New function. (android_init_emacs_gc_class): Update signature of `markDirty'. (android_change_gc, android_set_clip_rectangles): Tell the GC whether or not clip rects were dirtied. (android_swap_buffers): Do not look up method every time. (struct android_dir): Adjust for new directory tree lookup. (android_opendir, android_readdir, android_closedir): Likewise. (android_four_corners_bilinear): Fix coding style. (android_ftruncate): New function. * src/android.h: Update prototypes. Replace ftruncate with android_ftruncate when necessary. * src/androidterm.c (handle_one_android_event): Pacify GCC. Fix touch screen tool bar bug. * src/emacs.c (using_utf8): Fix compilation error. * src/fileio.c (Ffile_system_info): Return Qnil when fsusage.o is not built. * src/filelock.c (BOOT_TIME_FILE): Fix definition for Android. * src/frame.c (Fx_parse_geometry): Fix uninitialized variable uses. * src/keyboard.c (lispy_function_keys): Fix `back'. * src/menu.c (x_popup_menu_1): Handle touch screen events. (Fx_popup_menu): Document changes. * src/sfnt.c (main): Improve tests. * src/sfntfont-android.c (sfntfont_android_put_glyphs): Fix minor problem. (init_sfntfont_android): Check for HAVE_DECL_ANDROID_GET_DEVICE_API_LEVEL. * src/sfntfont.c (struct sfnt_font_desc): New fields `adstyle' and `languages'. (sfnt_parse_style): Append tokens to adstyle. (sfnt_parse_languages): New function. (sfnt_enum_font_1): Parse supported languages and adstyle. (sfntfont_list_1): Handle new fields. (sfntfont_text_extents): Fix uninitialized variable use. (syms_of_sfntfont, mark_sfntfont): Adjust accordingly.
Diffstat (limited to 'java/org')
-rw-r--r--java/org/gnu/emacs/EmacsContextMenu.java20
-rw-r--r--java/org/gnu/emacs/EmacsCopyArea.java11
-rw-r--r--java/org/gnu/emacs/EmacsDialog.java3
-rw-r--r--java/org/gnu/emacs/EmacsDrawLine.java11
-rw-r--r--java/org/gnu/emacs/EmacsDrawRectangle.java45
-rw-r--r--java/org/gnu/emacs/EmacsDrawable.java2
-rw-r--r--java/org/gnu/emacs/EmacsFillPolygon.java11
-rw-r--r--java/org/gnu/emacs/EmacsFillRectangle.java12
-rw-r--r--java/org/gnu/emacs/EmacsGC.java33
-rw-r--r--java/org/gnu/emacs/EmacsPixmap.java77
-rw-r--r--java/org/gnu/emacs/EmacsSdk7FontDriver.java11
-rw-r--r--java/org/gnu/emacs/EmacsService.java7
-rw-r--r--java/org/gnu/emacs/EmacsView.java34
-rw-r--r--java/org/gnu/emacs/EmacsWindow.java80
14 files changed, 212 insertions, 145 deletions
diff --git a/java/org/gnu/emacs/EmacsContextMenu.java b/java/org/gnu/emacs/EmacsContextMenu.java
index 00e204c9949..ac67ebe4aa0 100644
--- a/java/org/gnu/emacs/EmacsContextMenu.java
+++ b/java/org/gnu/emacs/EmacsContextMenu.java
@@ -168,10 +168,22 @@ public class EmacsContextMenu
168 { 168 {
169 if (item.subMenu != null) 169 if (item.subMenu != null)
170 { 170 {
171 /* This is a submenu. Create the submenu and add the 171 try
172 contents of the menu to it. */ 172 {
173 submenu = menu.addSubMenu (item.itemName); 173 /* This is a submenu. On versions of Android which
174 item.subMenu.inflateMenuItems (submenu); 174 support doing so, create the submenu and add the
175 contents of the menu to it. */
176 submenu = menu.addSubMenu (item.itemName);
177 }
178 catch (UnsupportedOperationException exception)
179 {
180 /* This version of Android has a restriction
181 preventing submenus from being added to submenus.
182 Inflate everything into the parent menu
183 instead. */
184 item.subMenu.inflateMenuItems (menu);
185 continue;
186 }
175 187
176 /* This is still needed to set wasSubmenuSelected. */ 188 /* This is still needed to set wasSubmenuSelected. */
177 menuItem = submenu.getItem (); 189 menuItem = submenu.getItem ();
diff --git a/java/org/gnu/emacs/EmacsCopyArea.java b/java/org/gnu/emacs/EmacsCopyArea.java
index 5d72a7860c8..7a97d706794 100644
--- a/java/org/gnu/emacs/EmacsCopyArea.java
+++ b/java/org/gnu/emacs/EmacsCopyArea.java
@@ -66,19 +66,11 @@ public class EmacsCopyArea
66 66
67 paint = gc.gcPaint; 67 paint = gc.gcPaint;
68 68
69 canvas = destination.lockCanvas (); 69 canvas = destination.lockCanvas (gc);
70 70
71 if (canvas == null) 71 if (canvas == null)
72 return; 72 return;
73 73
74 canvas.save ();
75
76 if (gc.real_clip_rects != null)
77 {
78 for (i = 0; i < gc.real_clip_rects.length; ++i)
79 canvas.clipRect (gc.real_clip_rects[i]);
80 }
81
82 /* A copy must be created or drawBitmap could end up overwriting 74 /* A copy must be created or drawBitmap could end up overwriting
83 itself. */ 75 itself. */
84 srcBitmap = source.getBitmap (); 76 srcBitmap = source.getBitmap ();
@@ -189,7 +181,6 @@ public class EmacsCopyArea
189 maskBitmap.recycle (); 181 maskBitmap.recycle ();
190 } 182 }
191 183
192 canvas.restore ();
193 destination.damageRect (rect); 184 destination.damageRect (rect);
194 } 185 }
195} 186}
diff --git a/java/org/gnu/emacs/EmacsDialog.java b/java/org/gnu/emacs/EmacsDialog.java
index 5bc8efa5978..7d88a23c58f 100644
--- a/java/org/gnu/emacs/EmacsDialog.java
+++ b/java/org/gnu/emacs/EmacsDialog.java
@@ -168,9 +168,6 @@ public class EmacsDialog implements DialogInterface.OnDismissListener
168 button = buttons.get (1); 168 button = buttons.get (1);
169 dialog.setButton (DialogInterface.BUTTON_NEUTRAL, 169 dialog.setButton (DialogInterface.BUTTON_NEUTRAL,
170 button.name, button); 170 button.name, button);
171 buttonView
172 = dialog.getButton (DialogInterface.BUTTON_NEUTRAL);
173 buttonView.setEnabled (button.enabled);
174 } 171 }
175 172
176 if (size >= 3) 173 if (size >= 3)
diff --git a/java/org/gnu/emacs/EmacsDrawLine.java b/java/org/gnu/emacs/EmacsDrawLine.java
index 8941d4c217f..827feb96dfb 100644
--- a/java/org/gnu/emacs/EmacsDrawLine.java
+++ b/java/org/gnu/emacs/EmacsDrawLine.java
@@ -49,19 +49,11 @@ public class EmacsDrawLine
49 Math.min (y, y2 + 1), 49 Math.min (y, y2 + 1),
50 Math.max (x2 + 1, x), 50 Math.max (x2 + 1, x),
51 Math.max (y2 + 1, y)); 51 Math.max (y2 + 1, y));
52 canvas = drawable.lockCanvas (); 52 canvas = drawable.lockCanvas (gc);
53 53
54 if (canvas == null) 54 if (canvas == null)
55 return; 55 return;
56 56
57 canvas.save ();
58
59 if (gc.real_clip_rects != null)
60 {
61 for (i = 0; i < gc.real_clip_rects.length; ++i)
62 canvas.clipRect (gc.real_clip_rects[i]);
63 }
64
65 paint.setStyle (Paint.Style.STROKE); 57 paint.setStyle (Paint.Style.STROKE);
66 58
67 if (gc.clip_mask == null) 59 if (gc.clip_mask == null)
@@ -71,7 +63,6 @@ public class EmacsDrawLine
71 63
72 /* DrawLine with clip mask not implemented; it is not used by 64 /* DrawLine with clip mask not implemented; it is not used by
73 Emacs. */ 65 Emacs. */
74 canvas.restore ();
75 drawable.damageRect (rect); 66 drawable.damageRect (rect);
76 } 67 }
77} 68}
diff --git a/java/org/gnu/emacs/EmacsDrawRectangle.java b/java/org/gnu/emacs/EmacsDrawRectangle.java
index c29d413f66e..695a8c6ea44 100644
--- a/java/org/gnu/emacs/EmacsDrawRectangle.java
+++ b/java/org/gnu/emacs/EmacsDrawRectangle.java
@@ -23,6 +23,7 @@ import android.graphics.Bitmap;
23import android.graphics.Canvas; 23import android.graphics.Canvas;
24import android.graphics.Paint; 24import android.graphics.Paint;
25import android.graphics.Rect; 25import android.graphics.Rect;
26import android.graphics.RectF;
26 27
27import android.util.Log; 28import android.util.Log;
28 29
@@ -36,51 +37,31 @@ public class EmacsDrawRectangle
36 Paint maskPaint, paint; 37 Paint maskPaint, paint;
37 Canvas maskCanvas; 38 Canvas maskCanvas;
38 Bitmap maskBitmap; 39 Bitmap maskBitmap;
40 Rect rect;
39 Rect maskRect, dstRect; 41 Rect maskRect, dstRect;
40 Canvas canvas; 42 Canvas canvas;
41 Bitmap clipBitmap; 43 Bitmap clipBitmap;
42 Rect clipRect;
43 44
44 /* TODO implement stippling. */ 45 /* TODO implement stippling. */
45 if (gc.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED) 46 if (gc.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
46 return; 47 return;
47 48
48 canvas = drawable.lockCanvas (); 49 canvas = drawable.lockCanvas (gc);
49 50
50 if (canvas == null) 51 if (canvas == null)
51 return; 52 return;
52 53
53 canvas.save ();
54
55 if (gc.real_clip_rects != null)
56 {
57 for (i = 0; i < gc.real_clip_rects.length; ++i)
58 canvas.clipRect (gc.real_clip_rects[i]);
59 }
60
61 /* Clip to the clipRect because some versions of Android draw an
62 overly wide line. */
63 clipRect = new Rect (x, y, x + width + 1,
64 y + height + 1);
65 canvas.clipRect (clipRect);
66
67 paint = gc.gcPaint; 54 paint = gc.gcPaint;
55 paint.setStyle (Paint.Style.STROKE);
56 rect = new Rect (x, y, x + width, y + height);
68 57
69 if (gc.clip_mask == null) 58 if (gc.clip_mask == null)
70 { 59 /* Use canvas.drawRect with a RectF. That seems to reliably
71 /* canvas.drawRect just doesn't work on Android, producing 60 get PostScript behavior. */
72 different results on various devices. Do a 5 point 61 canvas.drawRect (new RectF (x + 0.5f, y + 0.5f,
73 PolyLine instead. */ 62 x + width + 0.5f,
74 canvas.drawLine ((float) x, (float) y, (float) x + width, 63 y + height + 0.5f),
75 (float) y, paint); 64 paint);
76 canvas.drawLine ((float) x + width, (float) y,
77 (float) x + width, (float) y + height,
78 paint);
79 canvas.drawLine ((float) x + width, (float) y + height,
80 (float) x, (float) y + height, paint);
81 canvas.drawLine ((float) x, (float) y + height,
82 (float) x, (float) y, paint);
83 }
84 else 65 else
85 { 66 {
86 /* Drawing with a clip mask involves calculating the 67 /* Drawing with a clip mask involves calculating the
@@ -137,7 +118,7 @@ public class EmacsDrawRectangle
137 maskBitmap.recycle (); 118 maskBitmap.recycle ();
138 } 119 }
139 120
140 canvas.restore (); 121 drawable.damageRect (new Rect (x, y, x + width + 1,
141 drawable.damageRect (clipRect); 122 y + height + 1));
142 } 123 }
143} 124}
diff --git a/java/org/gnu/emacs/EmacsDrawable.java b/java/org/gnu/emacs/EmacsDrawable.java
index 6a6199ff214..f2f8885e976 100644
--- a/java/org/gnu/emacs/EmacsDrawable.java
+++ b/java/org/gnu/emacs/EmacsDrawable.java
@@ -25,7 +25,7 @@ import android.graphics.Canvas;
25 25
26public interface EmacsDrawable 26public interface EmacsDrawable
27{ 27{
28 public Canvas lockCanvas (); 28 public Canvas lockCanvas (EmacsGC gc);
29 public void damageRect (Rect damageRect); 29 public void damageRect (Rect damageRect);
30 public Bitmap getBitmap (); 30 public Bitmap getBitmap ();
31 public boolean isDestroyed (); 31 public boolean isDestroyed ();
diff --git a/java/org/gnu/emacs/EmacsFillPolygon.java b/java/org/gnu/emacs/EmacsFillPolygon.java
index 42b73886dff..22e2dd0d8a9 100644
--- a/java/org/gnu/emacs/EmacsFillPolygon.java
+++ b/java/org/gnu/emacs/EmacsFillPolygon.java
@@ -41,21 +41,13 @@ public class EmacsFillPolygon
41 RectF rectF; 41 RectF rectF;
42 int i; 42 int i;
43 43
44 canvas = drawable.lockCanvas (); 44 canvas = drawable.lockCanvas (gc);
45 45
46 if (canvas == null) 46 if (canvas == null)
47 return; 47 return;
48 48
49 paint = gc.gcPaint; 49 paint = gc.gcPaint;
50 50
51 canvas.save ();
52
53 if (gc.real_clip_rects != null)
54 {
55 for (i = 0; i < gc.real_clip_rects.length; ++i)
56 canvas.clipRect (gc.real_clip_rects[i]);
57 }
58
59 /* Build the path from the given array of points. */ 51 /* Build the path from the given array of points. */
60 path = new Path (); 52 path = new Path ();
61 53
@@ -83,7 +75,6 @@ public class EmacsFillPolygon
83 if (gc.clip_mask == null) 75 if (gc.clip_mask == null)
84 canvas.drawPath (path, paint); 76 canvas.drawPath (path, paint);
85 77
86 canvas.restore ();
87 drawable.damageRect (rect); 78 drawable.damageRect (rect);
88 79
89 /* FillPolygon with clip mask not implemented; it is not used by 80 /* FillPolygon with clip mask not implemented; it is not used by
diff --git a/java/org/gnu/emacs/EmacsFillRectangle.java b/java/org/gnu/emacs/EmacsFillRectangle.java
index 7cc55d3db96..aed0a540c8f 100644
--- a/java/org/gnu/emacs/EmacsFillRectangle.java
+++ b/java/org/gnu/emacs/EmacsFillRectangle.java
@@ -32,7 +32,6 @@ public class EmacsFillRectangle
32 perform (EmacsDrawable drawable, EmacsGC gc, 32 perform (EmacsDrawable drawable, EmacsGC gc,
33 int x, int y, int width, int height) 33 int x, int y, int width, int height)
34 { 34 {
35 int i;
36 Paint maskPaint, paint; 35 Paint maskPaint, paint;
37 Canvas maskCanvas; 36 Canvas maskCanvas;
38 Bitmap maskBitmap; 37 Bitmap maskBitmap;
@@ -45,19 +44,11 @@ public class EmacsFillRectangle
45 if (gc.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED) 44 if (gc.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
46 return; 45 return;
47 46
48 canvas = drawable.lockCanvas (); 47 canvas = drawable.lockCanvas (gc);
49 48
50 if (canvas == null) 49 if (canvas == null)
51 return; 50 return;
52 51
53 canvas.save ();
54
55 if (gc.real_clip_rects != null)
56 {
57 for (i = 0; i < gc.real_clip_rects.length; ++i)
58 canvas.clipRect (gc.real_clip_rects[i]);
59 }
60
61 paint = gc.gcPaint; 52 paint = gc.gcPaint;
62 rect = new Rect (x, y, x + width, y + height); 53 rect = new Rect (x, y, x + width, y + height);
63 54
@@ -120,7 +111,6 @@ public class EmacsFillRectangle
120 maskBitmap.recycle (); 111 maskBitmap.recycle ();
121 } 112 }
122 113
123 canvas.restore ();
124 drawable.damageRect (rect); 114 drawable.damageRect (rect);
125 } 115 }
126} 116}
diff --git a/java/org/gnu/emacs/EmacsGC.java b/java/org/gnu/emacs/EmacsGC.java
index c579625f3f7..bdc27a1ca5b 100644
--- a/java/org/gnu/emacs/EmacsGC.java
+++ b/java/org/gnu/emacs/EmacsGC.java
@@ -47,6 +47,14 @@ public class EmacsGC extends EmacsHandleObject
47 public EmacsPixmap clip_mask, stipple; 47 public EmacsPixmap clip_mask, stipple;
48 public Paint gcPaint; 48 public Paint gcPaint;
49 49
50 /* ID incremented every time the clipping rectangles of any GC
51 changes. */
52 private static long clip_serial;
53
54 /* The value of clipRectID after the last time this GCs clip
55 rectangles changed. 0 if there are no clip rectangles. */
56 public long clipRectID;
57
50 static 58 static
51 { 59 {
52 xorAlu = new PorterDuffXfermode (Mode.XOR); 60 xorAlu = new PorterDuffXfermode (Mode.XOR);
@@ -75,23 +83,28 @@ public class EmacsGC extends EmacsHandleObject
75 recompute real_clip_rects. */ 83 recompute real_clip_rects. */
76 84
77 public void 85 public void
78 markDirty () 86 markDirty (boolean clipRectsChanged)
79 { 87 {
80 int i; 88 int i;
81 89
82 if ((ts_origin_x != 0 || ts_origin_y != 0) 90 if (clipRectsChanged)
83 && clip_rects != null)
84 { 91 {
85 real_clip_rects = new Rect[clip_rects.length]; 92 if ((ts_origin_x != 0 || ts_origin_y != 0)
86 93 && clip_rects != null)
87 for (i = 0; i < clip_rects.length; ++i)
88 { 94 {
89 real_clip_rects[i] = new Rect (clip_rects[i]); 95 real_clip_rects = new Rect[clip_rects.length];
90 real_clip_rects[i].offset (ts_origin_x, ts_origin_y); 96
97 for (i = 0; i < clip_rects.length; ++i)
98 {
99 real_clip_rects[i] = new Rect (clip_rects[i]);
100 real_clip_rects[i].offset (ts_origin_x, ts_origin_y);
101 }
91 } 102 }
103 else
104 real_clip_rects = clip_rects;
105
106 clipRectID = ++clip_serial;
92 } 107 }
93 else
94 real_clip_rects = clip_rects;
95 108
96 gcPaint.setStrokeWidth (1f); 109 gcPaint.setStrokeWidth (1f);
97 gcPaint.setColor (foreground | 0xff000000); 110 gcPaint.setColor (foreground | 0xff000000);
diff --git a/java/org/gnu/emacs/EmacsPixmap.java b/java/org/gnu/emacs/EmacsPixmap.java
index 85931c2abd4..a83d8f25542 100644
--- a/java/org/gnu/emacs/EmacsPixmap.java
+++ b/java/org/gnu/emacs/EmacsPixmap.java
@@ -42,6 +42,14 @@ public class EmacsPixmap extends EmacsHandleObject
42 /* The canvas used to draw to BITMAP. */ 42 /* The canvas used to draw to BITMAP. */
43 public Canvas canvas; 43 public Canvas canvas;
44 44
45 /* Whether or not GC should be explicitly triggered upon
46 release. */
47 private boolean needCollect;
48
49 /* ID used to determine whether or not the GC clip rects
50 changed. */
51 private long gcClipRectID;
52
45 public 53 public
46 EmacsPixmap (short handle, int colors[], int width, 54 EmacsPixmap (short handle, int colors[], int width,
47 int height, int depth) 55 int height, int depth)
@@ -83,18 +91,41 @@ public class EmacsPixmap extends EmacsHandleObject
83 switch (depth) 91 switch (depth)
84 { 92 {
85 case 1: 93 case 1:
86 bitmap = Bitmap.createBitmap (width, height, 94 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
87 Bitmap.Config.ALPHA_8, 95 bitmap = Bitmap.createBitmap (width, height,
88 false); 96 Bitmap.Config.ALPHA_8,
97 false);
98 else
99 bitmap = Bitmap.createBitmap (width, height,
100 Bitmap.Config.ALPHA_8);
89 break; 101 break;
90 102
91 case 24: 103 case 24:
92 bitmap = Bitmap.createBitmap (width, height, 104
93 Bitmap.Config.ARGB_8888, 105 /* Emacs doesn't just use the first kind of `createBitmap'
94 false); 106 because the latter allows specifying that the pixmap is
107 always opaque, which really increases efficiency. */
108 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
109 bitmap = Bitmap.createBitmap (width, height,
110 Bitmap.Config.ARGB_8888);
111 else
112 bitmap = Bitmap.createBitmap (width, height,
113 Bitmap.Config.ARGB_8888,
114 false);
95 break; 115 break;
96 } 116 }
97 117
118 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB_MR1)
119 /* On these old versions of Android, Bitmap.recycle frees bitmap
120 contents immediately. */
121 needCollect = false;
122 else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT)
123 needCollect = (bitmap.getByteCount ()
124 >= 1024 * 512);
125 else
126 needCollect = (bitmap.getAllocationByteCount ()
127 >= 1024 * 512);
128
98 bitmap.eraseColor (0xff000000); 129 bitmap.eraseColor (0xff000000);
99 130
100 this.width = width; 131 this.width = width;
@@ -104,11 +135,32 @@ public class EmacsPixmap extends EmacsHandleObject
104 135
105 @Override 136 @Override
106 public Canvas 137 public Canvas
107 lockCanvas () 138 lockCanvas (EmacsGC gc)
108 { 139 {
140 int i;
141
109 if (canvas == null) 142 if (canvas == null)
110 canvas = new Canvas (bitmap); 143 {
144 canvas = new Canvas (bitmap);
145 canvas.save ();
146 }
111 147
148 /* Now see if clipping has to be redone. */
149 if (gc.clipRectID == gcClipRectID)
150 return canvas;
151
152 /* It does have to be redone. Reapply gc.real_clip_rects. */
153 canvas.restore ();
154 canvas.save ();
155
156 if (gc.real_clip_rects != null)
157 {
158 for (i = 0; i < gc.real_clip_rects.length; ++i)
159 canvas.clipRect (gc.real_clip_rects[i]);
160 }
161
162 /* Save the clip rect ID again. */
163 gcClipRectID = gc.clipRectID;
112 return canvas; 164 return canvas;
113 } 165 }
114 166
@@ -130,15 +182,6 @@ public class EmacsPixmap extends EmacsHandleObject
130 public void 182 public void
131 destroyHandle () 183 destroyHandle ()
132 { 184 {
133 boolean needCollect;
134
135 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT)
136 needCollect = (bitmap.getByteCount ()
137 >= 1024 * 512);
138 else
139 needCollect = (bitmap.getAllocationByteCount ()
140 >= 1024 * 512);
141
142 bitmap.recycle (); 185 bitmap.recycle ();
143 bitmap = null; 186 bitmap = null;
144 187
diff --git a/java/org/gnu/emacs/EmacsSdk7FontDriver.java b/java/org/gnu/emacs/EmacsSdk7FontDriver.java
index c0f24c7433a..a964cadb74c 100644
--- a/java/org/gnu/emacs/EmacsSdk7FontDriver.java
+++ b/java/org/gnu/emacs/EmacsSdk7FontDriver.java
@@ -510,20 +510,12 @@ public class EmacsSdk7FontDriver extends EmacsFontDriver
510 backgroundRect.right = x + backgroundWidth; 510 backgroundRect.right = x + backgroundWidth;
511 backgroundRect.bottom = y + sdk7FontObject.descent; 511 backgroundRect.bottom = y + sdk7FontObject.descent;
512 512
513 canvas = drawable.lockCanvas (); 513 canvas = drawable.lockCanvas (gc);
514 514
515 if (canvas == null) 515 if (canvas == null)
516 return 0; 516 return 0;
517 517
518 canvas.save ();
519 paint = gc.gcPaint; 518 paint = gc.gcPaint;
520
521 if (gc.real_clip_rects != null)
522 {
523 for (i = 0; i < gc.real_clip_rects.length; ++i)
524 canvas.clipRect (gc.real_clip_rects[i]);
525 }
526
527 paint.setStyle (Paint.Style.FILL); 519 paint.setStyle (Paint.Style.FILL);
528 520
529 if (withBackground) 521 if (withBackground)
@@ -538,7 +530,6 @@ public class EmacsSdk7FontDriver extends EmacsFontDriver
538 paint.setAntiAlias (true); 530 paint.setAntiAlias (true);
539 canvas.drawText (charsArray, 0, chars.length, x, y, paint); 531 canvas.drawText (charsArray, 0, chars.length, x, y, paint);
540 532
541 canvas.restore ();
542 bounds = new Rect (); 533 bounds = new Rect ();
543 paint.getTextBounds (charsArray, 0, chars.length, bounds); 534 paint.getTextBounds (charsArray, 0, chars.length, bounds);
544 bounds.offset (x, y); 535 bounds.offset (x, y);
diff --git a/java/org/gnu/emacs/EmacsService.java b/java/org/gnu/emacs/EmacsService.java
index ca38f93dc98..bcf8d9ff6e8 100644
--- a/java/org/gnu/emacs/EmacsService.java
+++ b/java/org/gnu/emacs/EmacsService.java
@@ -175,7 +175,12 @@ public class EmacsService extends Service
175 { 175 {
176 view.thing = new EmacsView (window); 176 view.thing = new EmacsView (window);
177 view.thing.setVisibility (visibility); 177 view.thing.setVisibility (visibility);
178 view.thing.setFocusedByDefault (isFocusedByDefault); 178
179 /* The following function is only present on Android 26
180 or later. */
181 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
182 view.thing.setFocusedByDefault (isFocusedByDefault);
183
179 notify (); 184 notify ();
180 } 185 }
181 } 186 }
diff --git a/java/org/gnu/emacs/EmacsView.java b/java/org/gnu/emacs/EmacsView.java
index 6137fd74a7f..82f44acaebe 100644
--- a/java/org/gnu/emacs/EmacsView.java
+++ b/java/org/gnu/emacs/EmacsView.java
@@ -83,6 +83,9 @@ public class EmacsView extends ViewGroup
83 /* The last measured width and height. */ 83 /* The last measured width and height. */
84 private int measuredWidth, measuredHeight; 84 private int measuredWidth, measuredHeight;
85 85
86 /* The serial of the last clip rectangle change. */
87 private long lastClipSerial;
88
86 public 89 public
87 EmacsView (EmacsWindow window) 90 EmacsView (EmacsWindow window)
88 { 91 {
@@ -105,10 +108,6 @@ public class EmacsView extends ViewGroup
105 on Android? */ 108 on Android? */
106 setChildrenDrawingOrderEnabled (true); 109 setChildrenDrawingOrderEnabled (true);
107 110
108 /* Get rid of the foreground and background tint. */
109 setBackgroundTintList (null);
110 setForegroundTintList (null);
111
112 /* Get rid of the default focus highlight. */ 111 /* Get rid of the default focus highlight. */
113 if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O) 112 if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O)
114 setDefaultFocusHighlightEnabled (false); 113 setDefaultFocusHighlightEnabled (false);
@@ -145,6 +144,11 @@ public class EmacsView extends ViewGroup
145 144
146 /* And canvases. */ 145 /* And canvases. */
147 canvas = new Canvas (bitmap); 146 canvas = new Canvas (bitmap);
147 canvas.save ();
148
149 /* Since the clip rectangles have been cleared, clear the clip
150 rectangle ID. */
151 lastClipSerial = 0;
148 152
149 /* Copy over the contents of the old bitmap. */ 153 /* Copy over the contents of the old bitmap. */
150 if (oldBitmap != null) 154 if (oldBitmap != null)
@@ -177,11 +181,31 @@ public class EmacsView extends ViewGroup
177 } 181 }
178 182
179 public synchronized Canvas 183 public synchronized Canvas
180 getCanvas () 184 getCanvas (EmacsGC gc)
181 { 185 {
186 int i;
187
182 if (bitmapDirty || bitmap == null) 188 if (bitmapDirty || bitmap == null)
183 handleDirtyBitmap (); 189 handleDirtyBitmap ();
184 190
191 if (canvas == null)
192 return null;
193
194 /* Update clip rectangles if necessary. */
195 if (gc.clipRectID != lastClipSerial)
196 {
197 canvas.restore ();
198 canvas.save ();
199
200 if (gc.real_clip_rects != null)
201 {
202 for (i = 0; i < gc.real_clip_rects.length; ++i)
203 canvas.clipRect (gc.real_clip_rects[i]);
204 }
205
206 lastClipSerial = gc.clipRectID;
207 }
208
185 return canvas; 209 return canvas;
186 } 210 }
187 211
diff --git a/java/org/gnu/emacs/EmacsWindow.java b/java/org/gnu/emacs/EmacsWindow.java
index f5b50f11f14..c5b1522086c 100644
--- a/java/org/gnu/emacs/EmacsWindow.java
+++ b/java/org/gnu/emacs/EmacsWindow.java
@@ -164,7 +164,7 @@ public class EmacsWindow extends EmacsHandleObject
164 { 164 {
165 /* scratchGC is used as the argument to a FillRectangles req. */ 165 /* scratchGC is used as the argument to a FillRectangles req. */
166 scratchGC.foreground = pixel; 166 scratchGC.foreground = pixel;
167 scratchGC.markDirty (); 167 scratchGC.markDirty (false);
168 } 168 }
169 169
170 public Rect 170 public Rect
@@ -466,9 +466,9 @@ public class EmacsWindow extends EmacsHandleObject
466 466
467 @Override 467 @Override
468 public Canvas 468 public Canvas
469 lockCanvas () 469 lockCanvas (EmacsGC gc)
470 { 470 {
471 return view.getCanvas (); 471 return view.getCanvas (gc);
472 } 472 }
473 473
474 @Override 474 @Override
@@ -512,37 +512,75 @@ public class EmacsWindow extends EmacsHandleObject
512 public void 512 public void
513 onKeyDown (int keyCode, KeyEvent event) 513 onKeyDown (int keyCode, KeyEvent event)
514 { 514 {
515 int state; 515 int state, state_1;
516 516
517 state = event.getModifiers (); 517 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2)
518 state &= ~(KeyEvent.META_ALT_MASK | KeyEvent.META_CTRL_MASK); 518 state = event.getModifiers ();
519 else
520 {
521 /* Replace this with getMetaState and manual
522 normalization. */
523 state = event.getMetaState ();
524
525 /* Normalize the state by setting the generic modifier bit if
526 either a left or right modifier is pressed. */
527
528 if ((state & KeyEvent.META_ALT_LEFT_ON) != 0
529 || (state & KeyEvent.META_ALT_RIGHT_ON) != 0)
530 state |= KeyEvent.META_ALT_MASK;
531
532 if ((state & KeyEvent.META_CTRL_LEFT_ON) != 0
533 || (state & KeyEvent.META_CTRL_RIGHT_ON) != 0)
534 state |= KeyEvent.META_CTRL_MASK;
535 }
536
537 /* Ignore meta-state understood by Emacs for now, or Ctrl+C will
538 not be recognized as an ASCII key press event. */
539 state_1
540 = state & ~(KeyEvent.META_ALT_MASK | KeyEvent.META_CTRL_MASK);
519 541
520 EmacsNative.sendKeyPress (this.handle, 542 EmacsNative.sendKeyPress (this.handle,
521 event.getEventTime (), 543 event.getEventTime (),
522 event.getModifiers (), 544 state, keyCode,
523 keyCode, 545 event.getUnicodeChar (state_1));
524 /* Ignore meta-state understood by Emacs 546 lastModifiers = state;
525 for now, or Ctrl+C will not be
526 recognized as an ASCII key press
527 event. */
528 event.getUnicodeChar (state));
529 lastModifiers = event.getModifiers ();
530 } 547 }
531 548
532 public void 549 public void
533 onKeyUp (int keyCode, KeyEvent event) 550 onKeyUp (int keyCode, KeyEvent event)
534 { 551 {
535 int state; 552 int state, state_1;
553
554 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2)
555 state = event.getModifiers ();
556 else
557 {
558 /* Replace this with getMetaState and manual
559 normalization. */
560 state = event.getMetaState ();
561
562 /* Normalize the state by setting the generic modifier bit if
563 either a left or right modifier is pressed. */
564
565 if ((state & KeyEvent.META_ALT_LEFT_ON) != 0
566 || (state & KeyEvent.META_ALT_RIGHT_ON) != 0)
567 state |= KeyEvent.META_ALT_MASK;
568
569 if ((state & KeyEvent.META_CTRL_LEFT_ON) != 0
570 || (state & KeyEvent.META_CTRL_RIGHT_ON) != 0)
571 state |= KeyEvent.META_CTRL_MASK;
572 }
536 573
537 state = event.getModifiers (); 574 /* Ignore meta-state understood by Emacs for now, or Ctrl+C will
538 state &= ~(KeyEvent.META_ALT_MASK | KeyEvent.META_CTRL_MASK); 575 not be recognized as an ASCII key press event. */
576 state_1
577 = state & ~(KeyEvent.META_ALT_MASK | KeyEvent.META_CTRL_MASK);
539 578
540 EmacsNative.sendKeyRelease (this.handle, 579 EmacsNative.sendKeyRelease (this.handle,
541 event.getEventTime (), 580 event.getEventTime (),
542 event.getModifiers (), 581 state, keyCode,
543 keyCode, 582 event.getUnicodeChar (state_1));
544 event.getUnicodeChar (state)); 583 lastModifiers = state;
545 lastModifiers = event.getModifiers ();
546 } 584 }
547 585
548 public void 586 public void