diff options
| author | Po Lu | 2023-01-15 15:45:29 +0800 |
|---|---|---|
| committer | Po Lu | 2023-01-15 15:45:29 +0800 |
| commit | da9ae10636b84b88e9eb9c827b03cdaabd1611d1 (patch) | |
| tree | ca5b14036c7771accabfd87dd72e1fc147bf9914 /java | |
| parent | a336fd98a1ed1f97d69652cade46f99868f7c7fb (diff) | |
| download | emacs-da9ae10636b84b88e9eb9c827b03cdaabd1611d1.tar.gz emacs-da9ae10636b84b88e9eb9c827b03cdaabd1611d1.zip | |
Implement submenus on Android
* java/org/gnu/emacs/EmacsActivity.java (onCreate): Set the
default theme to Theme.DeviceDefault.NoActionBar if possible.
(onContextMenuClosed): Add hack for Android bug.
* java/org/gnu/emacs/EmacsContextMenu.java (EmacsContextMenu)
(onMenuItemClick): Set flag upon submenu selection.
(inflateMenuItems): Set onClickListener for submenus as well.
(display1): Clear new flag.
* java/org/gnu/emacs/EmacsDrawRectangle.java (perform): Fix
rectangle bounds.
* java/org/gnu/emacs/EmacsNative.java (EmacsNative):
* java/org/gnu/emacs/EmacsService.java (onCreate): Pass cache
directory.
(sync): New function.
* src/android.c (struct android_emacs_service): New method
`sync'.
(setEmacsParams, initEmacs): Handle cache directory.
(android_init_emacs_service): Initialize new method `sync'.
(android_sync): New function.
* src/androidfns.c (Fx_show_tip): Call both functions.
* src/androidgui.h: Update prototypes.
* src/androidmenu.c (struct android_menu_subprefix)
(android_free_subprefixes, android_menu_show): Handle submenu
prefixes correctly.
* src/androidterm.c (handle_one_android_event): Clear help echo
on MotionNotify like on X.
* src/menu.c (single_menu_item): Enable submenus on Android.
Diffstat (limited to 'java')
| -rw-r--r-- | java/org/gnu/emacs/EmacsActivity.java | 12 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsContextMenu.java | 31 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsDrawRectangle.java | 2 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsNative.java | 4 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsService.java | 36 |
5 files changed, 78 insertions, 7 deletions
diff --git a/java/org/gnu/emacs/EmacsActivity.java b/java/org/gnu/emacs/EmacsActivity.java index 4b96a376987..79c0991a5d3 100644 --- a/java/org/gnu/emacs/EmacsActivity.java +++ b/java/org/gnu/emacs/EmacsActivity.java | |||
| @@ -27,6 +27,7 @@ import android.app.Activity; | |||
| 27 | import android.content.Context; | 27 | import android.content.Context; |
| 28 | import android.content.Intent; | 28 | import android.content.Intent; |
| 29 | import android.os.Bundle; | 29 | import android.os.Bundle; |
| 30 | import android.os.Build; | ||
| 30 | import android.util.Log; | 31 | import android.util.Log; |
| 31 | import android.widget.FrameLayout; | 32 | import android.widget.FrameLayout; |
| 32 | import android.widget.FrameLayout.LayoutParams; | 33 | import android.widget.FrameLayout.LayoutParams; |
| @@ -162,7 +163,11 @@ public class EmacsActivity extends Activity | |||
| 162 | FrameLayout.LayoutParams params; | 163 | FrameLayout.LayoutParams params; |
| 163 | 164 | ||
| 164 | /* Set the theme to one without a title bar. */ | 165 | /* Set the theme to one without a title bar. */ |
| 165 | setTheme (android.R.style.Theme_NoTitleBar); | 166 | |
| 167 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) | ||
| 168 | setTheme (android.R.style.Theme_DeviceDefault_NoActionBar); | ||
| 169 | else | ||
| 170 | setTheme (android.R.style.Theme_NoTitleBar); | ||
| 166 | 171 | ||
| 167 | params = new FrameLayout.LayoutParams (LayoutParams.MATCH_PARENT, | 172 | params = new FrameLayout.LayoutParams (LayoutParams.MATCH_PARENT, |
| 168 | LayoutParams.MATCH_PARENT); | 173 | LayoutParams.MATCH_PARENT); |
| @@ -235,6 +240,11 @@ public class EmacsActivity extends Activity | |||
| 235 | { | 240 | { |
| 236 | Log.d (TAG, "onContextMenuClosed: " + menu); | 241 | Log.d (TAG, "onContextMenuClosed: " + menu); |
| 237 | 242 | ||
| 243 | /* See the comment inside onMenuItemClick. */ | ||
| 244 | if (EmacsContextMenu.wasSubmenuSelected | ||
| 245 | && menu.toString ().contains ("ContextMenuBuilder")) | ||
| 246 | return; | ||
| 247 | |||
| 238 | /* Send a context menu event given that no menu item has already | 248 | /* Send a context menu event given that no menu item has already |
| 239 | been selected. */ | 249 | been selected. */ |
| 240 | if (!EmacsContextMenu.itemAlreadySelected) | 250 | if (!EmacsContextMenu.itemAlreadySelected) |
diff --git a/java/org/gnu/emacs/EmacsContextMenu.java b/java/org/gnu/emacs/EmacsContextMenu.java index 02dd1c7efa9..00e204c9949 100644 --- a/java/org/gnu/emacs/EmacsContextMenu.java +++ b/java/org/gnu/emacs/EmacsContextMenu.java | |||
| @@ -30,6 +30,7 @@ import android.os.Bundle; | |||
| 30 | import android.view.Menu; | 30 | import android.view.Menu; |
| 31 | import android.view.MenuItem; | 31 | import android.view.MenuItem; |
| 32 | import android.view.View; | 32 | import android.view.View; |
| 33 | import android.view.SubMenu; | ||
| 33 | 34 | ||
| 34 | import android.util.Log; | 35 | import android.util.Log; |
| 35 | 36 | ||
| @@ -47,6 +48,9 @@ public class EmacsContextMenu | |||
| 47 | /* Whether or not an item was selected. */ | 48 | /* Whether or not an item was selected. */ |
| 48 | public static boolean itemAlreadySelected; | 49 | public static boolean itemAlreadySelected; |
| 49 | 50 | ||
| 51 | /* Whether or not a submenu was selected. */ | ||
| 52 | public static boolean wasSubmenuSelected; | ||
| 53 | |||
| 50 | private class Item implements MenuItem.OnMenuItemClickListener | 54 | private class Item implements MenuItem.OnMenuItemClickListener |
| 51 | { | 55 | { |
| 52 | public int itemID; | 56 | public int itemID; |
| @@ -60,6 +64,20 @@ public class EmacsContextMenu | |||
| 60 | { | 64 | { |
| 61 | Log.d (TAG, "onMenuItemClick: " + itemName + " (" + itemID + ")"); | 65 | Log.d (TAG, "onMenuItemClick: " + itemName + " (" + itemID + ")"); |
| 62 | 66 | ||
| 67 | if (subMenu != null) | ||
| 68 | { | ||
| 69 | /* After opening a submenu within a submenu, Android will | ||
| 70 | send onContextMenuClosed for a ContextMenuBuilder. This | ||
| 71 | will normally confuse Emacs into thinking that the | ||
| 72 | context menu has been dismissed. Wrong! | ||
| 73 | |||
| 74 | Setting this flag makes EmacsActivity to only handle | ||
| 75 | SubMenuBuilder being closed, which always means the menu | ||
| 76 | has actually been dismissed. */ | ||
| 77 | wasSubmenuSelected = true; | ||
| 78 | return false; | ||
| 79 | } | ||
| 80 | |||
| 63 | /* Send a context menu event. */ | 81 | /* Send a context menu event. */ |
| 64 | EmacsNative.sendContextMenu ((short) 0, itemID); | 82 | EmacsNative.sendContextMenu ((short) 0, itemID); |
| 65 | 83 | ||
| @@ -144,7 +162,7 @@ public class EmacsContextMenu | |||
| 144 | { | 162 | { |
| 145 | Intent intent; | 163 | Intent intent; |
| 146 | MenuItem menuItem; | 164 | MenuItem menuItem; |
| 147 | Menu submenu; | 165 | SubMenu submenu; |
| 148 | 166 | ||
| 149 | for (Item item : menuItems) | 167 | for (Item item : menuItems) |
| 150 | { | 168 | { |
| @@ -153,7 +171,11 @@ public class EmacsContextMenu | |||
| 153 | /* This is a submenu. Create the submenu and add the | 171 | /* This is a submenu. Create the submenu and add the |
| 154 | contents of the menu to it. */ | 172 | contents of the menu to it. */ |
| 155 | submenu = menu.addSubMenu (item.itemName); | 173 | submenu = menu.addSubMenu (item.itemName); |
| 156 | inflateMenuItems (submenu); | 174 | item.subMenu.inflateMenuItems (submenu); |
| 175 | |||
| 176 | /* This is still needed to set wasSubmenuSelected. */ | ||
| 177 | menuItem = submenu.getItem (); | ||
| 178 | menuItem.setOnMenuItemClickListener (item); | ||
| 157 | } | 179 | } |
| 158 | else | 180 | else |
| 159 | { | 181 | { |
| @@ -184,7 +206,7 @@ public class EmacsContextMenu | |||
| 184 | public EmacsContextMenu | 206 | public EmacsContextMenu |
| 185 | parent () | 207 | parent () |
| 186 | { | 208 | { |
| 187 | return parent; | 209 | return this.parent; |
| 188 | } | 210 | } |
| 189 | 211 | ||
| 190 | /* Like display, but does the actual work and runs in the main | 212 | /* Like display, but does the actual work and runs in the main |
| @@ -197,6 +219,9 @@ public class EmacsContextMenu | |||
| 197 | send 0 in response to the context menu being closed. */ | 219 | send 0 in response to the context menu being closed. */ |
| 198 | itemAlreadySelected = false; | 220 | itemAlreadySelected = false; |
| 199 | 221 | ||
| 222 | /* No submenu has been selected yet. */ | ||
| 223 | wasSubmenuSelected = false; | ||
| 224 | |||
| 200 | return window.view.popupMenu (this, xPosition, yPosition); | 225 | return window.view.popupMenu (this, xPosition, yPosition); |
| 201 | } | 226 | } |
| 202 | 227 | ||
diff --git a/java/org/gnu/emacs/EmacsDrawRectangle.java b/java/org/gnu/emacs/EmacsDrawRectangle.java index 84ff498847b..b42e9556e8c 100644 --- a/java/org/gnu/emacs/EmacsDrawRectangle.java +++ b/java/org/gnu/emacs/EmacsDrawRectangle.java | |||
| @@ -59,7 +59,7 @@ public class EmacsDrawRectangle | |||
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | paint = gc.gcPaint; | 61 | paint = gc.gcPaint; |
| 62 | rect = new Rect (x + 1, y + 1, x + width, y + height); | 62 | rect = new Rect (x, y, x + width, y + height); |
| 63 | 63 | ||
| 64 | paint.setStyle (Paint.Style.STROKE); | 64 | paint.setStyle (Paint.Style.STROKE); |
| 65 | 65 | ||
diff --git a/java/org/gnu/emacs/EmacsNative.java b/java/org/gnu/emacs/EmacsNative.java index 4a80f88edcf..2f3a732ea7c 100644 --- a/java/org/gnu/emacs/EmacsNative.java +++ b/java/org/gnu/emacs/EmacsNative.java | |||
| @@ -38,6 +38,9 @@ public class EmacsNative | |||
| 38 | libDir must be the package's data storage location for native | 38 | libDir must be the package's data storage location for native |
| 39 | libraries. It is used as PATH. | 39 | libraries. It is used as PATH. |
| 40 | 40 | ||
| 41 | cacheDir must be the package's cache directory. It is used as | ||
| 42 | the `temporary-file-directory'. | ||
| 43 | |||
| 41 | pixelDensityX and pixelDensityY are the DPI values that will be | 44 | pixelDensityX and pixelDensityY are the DPI values that will be |
| 42 | used by Emacs. | 45 | used by Emacs. |
| 43 | 46 | ||
| @@ -45,6 +48,7 @@ public class EmacsNative | |||
| 45 | public static native void setEmacsParams (AssetManager assetManager, | 48 | public static native void setEmacsParams (AssetManager assetManager, |
| 46 | String filesDir, | 49 | String filesDir, |
| 47 | String libDir, | 50 | String libDir, |
| 51 | String cacheDir, | ||
| 48 | float pixelDensityX, | 52 | float pixelDensityX, |
| 49 | float pixelDensityY, | 53 | float pixelDensityY, |
| 50 | EmacsService emacsService); | 54 | EmacsService emacsService); |
diff --git a/java/org/gnu/emacs/EmacsService.java b/java/org/gnu/emacs/EmacsService.java index f935b63fa0d..ca38f93dc98 100644 --- a/java/org/gnu/emacs/EmacsService.java +++ b/java/org/gnu/emacs/EmacsService.java | |||
| @@ -108,7 +108,7 @@ public class EmacsService extends Service | |||
| 108 | { | 108 | { |
| 109 | AssetManager manager; | 109 | AssetManager manager; |
| 110 | Context app_context; | 110 | Context app_context; |
| 111 | String filesDir, libDir; | 111 | String filesDir, libDir, cacheDir; |
| 112 | double pixelDensityX; | 112 | double pixelDensityX; |
| 113 | double pixelDensityY; | 113 | double pixelDensityY; |
| 114 | 114 | ||
| @@ -126,12 +126,13 @@ public class EmacsService extends Service | |||
| 126 | parameters. */ | 126 | parameters. */ |
| 127 | filesDir = app_context.getFilesDir ().getCanonicalPath (); | 127 | filesDir = app_context.getFilesDir ().getCanonicalPath (); |
| 128 | libDir = getLibraryDirectory (); | 128 | libDir = getLibraryDirectory (); |
| 129 | cacheDir = app_context.getCacheDir ().getCanonicalPath (); | ||
| 129 | 130 | ||
| 130 | Log.d (TAG, "Initializing Emacs, where filesDir = " + filesDir | 131 | Log.d (TAG, "Initializing Emacs, where filesDir = " + filesDir |
| 131 | + " and libDir = " + libDir); | 132 | + " and libDir = " + libDir); |
| 132 | 133 | ||
| 133 | EmacsNative.setEmacsParams (manager, filesDir, libDir, | 134 | EmacsNative.setEmacsParams (manager, filesDir, libDir, |
| 134 | (float) pixelDensityX, | 135 | cacheDir, (float) pixelDensityX, |
| 135 | (float) pixelDensityY, | 136 | (float) pixelDensityY, |
| 136 | this); | 137 | this); |
| 137 | 138 | ||
| @@ -407,4 +408,35 @@ public class EmacsService extends Service | |||
| 407 | { | 408 | { |
| 408 | return KeyEvent.keyCodeToString (keysym); | 409 | return KeyEvent.keyCodeToString (keysym); |
| 409 | } | 410 | } |
| 411 | |||
| 412 | public void | ||
| 413 | sync () | ||
| 414 | { | ||
| 415 | Runnable runnable; | ||
| 416 | |||
| 417 | runnable = new Runnable () { | ||
| 418 | public void | ||
| 419 | run () | ||
| 420 | { | ||
| 421 | synchronized (this) | ||
| 422 | { | ||
| 423 | notify (); | ||
| 424 | } | ||
| 425 | } | ||
| 426 | }; | ||
| 427 | |||
| 428 | synchronized (runnable) | ||
| 429 | { | ||
| 430 | runOnUiThread (runnable); | ||
| 431 | |||
| 432 | try | ||
| 433 | { | ||
| 434 | runnable.wait (); | ||
| 435 | } | ||
| 436 | catch (InterruptedException e) | ||
| 437 | { | ||
| 438 | EmacsNative.emacsAbort (); | ||
| 439 | } | ||
| 440 | } | ||
| 441 | } | ||
| 410 | }; | 442 | }; |