diff options
| author | Po Lu | 2023-03-04 15:55:09 +0800 |
|---|---|---|
| committer | Po Lu | 2023-03-04 15:55:09 +0800 |
| commit | 2634765bc382c27e2d11dc14174ca80d9cf41e15 (patch) | |
| tree | 3ef522e33fec01fbe0447dfc10306e6e58e17d8d /java | |
| parent | 39a7e6b79fdeafc539a36f6831d922a2622cb679 (diff) | |
| download | emacs-2634765bc382c27e2d11dc14174ca80d9cf41e15.tar.gz emacs-2634765bc382c27e2d11dc14174ca80d9cf41e15.zip | |
Improve context menus on old versions of Android
* java/org/gnu/emacs/EmacsActivity.java (EmacsActivity): New
field `lastClosedMenu'.
(onContextMenuClosed): Don't send event if a menu is closed
twice in a row. Also, clear wasSubmenuSelected immediately.
* java/org/gnu/emacs/EmacsContextMenu.java: Display submenus
manually in Android 6.0 and earlier.
* java/org/gnu/emacs/EmacsView.java (onCreateContextMenu)
(popupMenu): Adjust accordingly.
Diffstat (limited to 'java')
| -rw-r--r-- | java/org/gnu/emacs/EmacsActivity.java | 17 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsContextMenu.java | 81 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsView.java | 9 |
3 files changed, 76 insertions, 31 deletions
diff --git a/java/org/gnu/emacs/EmacsActivity.java b/java/org/gnu/emacs/EmacsActivity.java index 62bef33fab3..13002d5d0e5 100644 --- a/java/org/gnu/emacs/EmacsActivity.java +++ b/java/org/gnu/emacs/EmacsActivity.java | |||
| @@ -65,6 +65,9 @@ public class EmacsActivity extends Activity | |||
| 65 | /* Whether or not this activity is fullscreen. */ | 65 | /* Whether or not this activity is fullscreen. */ |
| 66 | private boolean isFullscreen; | 66 | private boolean isFullscreen; |
| 67 | 67 | ||
| 68 | /* The last context menu to be closed. */ | ||
| 69 | private Menu lastClosedMenu; | ||
| 70 | |||
| 68 | static | 71 | static |
| 69 | { | 72 | { |
| 70 | focusedActivities = new ArrayList<EmacsActivity> (); | 73 | focusedActivities = new ArrayList<EmacsActivity> (); |
| @@ -308,9 +311,19 @@ public class EmacsActivity extends Activity | |||
| 308 | Log.d (TAG, "onContextMenuClosed: " + menu); | 311 | Log.d (TAG, "onContextMenuClosed: " + menu); |
| 309 | 312 | ||
| 310 | /* See the comment inside onMenuItemClick. */ | 313 | /* See the comment inside onMenuItemClick. */ |
| 314 | |||
| 311 | if (EmacsContextMenu.wasSubmenuSelected | 315 | if (EmacsContextMenu.wasSubmenuSelected |
| 312 | && menu.toString ().contains ("ContextMenuBuilder")) | 316 | || menu == lastClosedMenu) |
| 313 | return; | 317 | { |
| 318 | EmacsContextMenu.wasSubmenuSelected = false; | ||
| 319 | lastClosedMenu = menu; | ||
| 320 | return; | ||
| 321 | } | ||
| 322 | |||
| 323 | /* lastClosedMenu is set because Android apparently calls this | ||
| 324 | function twice. */ | ||
| 325 | |||
| 326 | lastClosedMenu = null; | ||
| 314 | 327 | ||
| 315 | /* Send a context menu event given that no menu item has already | 328 | /* Send a context menu event given that no menu item has already |
| 316 | been selected. */ | 329 | been selected. */ |
diff --git a/java/org/gnu/emacs/EmacsContextMenu.java b/java/org/gnu/emacs/EmacsContextMenu.java index a1bca98daa0..d1a624e68d9 100644 --- a/java/org/gnu/emacs/EmacsContextMenu.java +++ b/java/org/gnu/emacs/EmacsContextMenu.java | |||
| @@ -58,6 +58,7 @@ public final class EmacsContextMenu | |||
| 58 | public String itemName, tooltip; | 58 | public String itemName, tooltip; |
| 59 | public EmacsContextMenu subMenu; | 59 | public EmacsContextMenu subMenu; |
| 60 | public boolean isEnabled, isCheckable, isChecked; | 60 | public boolean isEnabled, isCheckable, isChecked; |
| 61 | public EmacsView inflatedView; | ||
| 61 | 62 | ||
| 62 | @Override | 63 | @Override |
| 63 | public boolean | 64 | public boolean |
| @@ -67,6 +68,34 @@ public final class EmacsContextMenu | |||
| 67 | 68 | ||
| 68 | if (subMenu != null) | 69 | if (subMenu != null) |
| 69 | { | 70 | { |
| 71 | /* Android 6.0 and earlier don't support nested submenus | ||
| 72 | properly, so display the submenu popup by hand. */ | ||
| 73 | |||
| 74 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) | ||
| 75 | { | ||
| 76 | Log.d (TAG, "onMenuItemClick: displaying submenu " + subMenu); | ||
| 77 | |||
| 78 | /* Still set wasSubmenuSelected -- if not set, the | ||
| 79 | dismissal of this context menu will result in a | ||
| 80 | context menu event being sent. */ | ||
| 81 | wasSubmenuSelected = true; | ||
| 82 | |||
| 83 | /* Running a popup menu from inside a click handler | ||
| 84 | doesn't work, so make sure it is displayed | ||
| 85 | outside. */ | ||
| 86 | |||
| 87 | inflatedView.post (new Runnable () { | ||
| 88 | @Override | ||
| 89 | public void | ||
| 90 | run () | ||
| 91 | { | ||
| 92 | inflatedView.popupMenu (subMenu, 0, 0, true); | ||
| 93 | } | ||
| 94 | }); | ||
| 95 | |||
| 96 | return true; | ||
| 97 | } | ||
| 98 | |||
| 70 | /* After opening a submenu within a submenu, Android will | 99 | /* After opening a submenu within a submenu, Android will |
| 71 | send onContextMenuClosed for a ContextMenuBuilder. This | 100 | send onContextMenuClosed for a ContextMenuBuilder. This |
| 72 | will normally confuse Emacs into thinking that the | 101 | will normally confuse Emacs into thinking that the |
| @@ -164,10 +193,11 @@ public final class EmacsContextMenu | |||
| 164 | return item.subMenu; | 193 | return item.subMenu; |
| 165 | } | 194 | } |
| 166 | 195 | ||
| 167 | /* Add the contents of this menu to MENU. */ | 196 | /* Add the contents of this menu to MENU. Assume MENU will be |
| 197 | displayed in INFLATEDVIEW. */ | ||
| 168 | 198 | ||
| 169 | private void | 199 | private void |
| 170 | inflateMenuItems (Menu menu) | 200 | inflateMenuItems (Menu menu, EmacsView inflatedView) |
| 171 | { | 201 | { |
| 172 | Intent intent; | 202 | Intent intent; |
| 173 | MenuItem menuItem; | 203 | MenuItem menuItem; |
| @@ -177,26 +207,26 @@ public final class EmacsContextMenu | |||
| 177 | { | 207 | { |
| 178 | if (item.subMenu != null) | 208 | if (item.subMenu != null) |
| 179 | { | 209 | { |
| 180 | try | 210 | /* This is a submenu. On versions of Android which |
| 211 | support doing so, create the submenu and add the | ||
| 212 | contents of the menu to it. | ||
| 213 | |||
| 214 | Note that Android 4.0 and later technically supports | ||
| 215 | having multiple layers of nested submenus, but if they | ||
| 216 | are used, onContextMenuClosed becomes unreliable. */ | ||
| 217 | |||
| 218 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) | ||
| 181 | { | 219 | { |
| 182 | /* This is a submenu. On versions of Android which | ||
| 183 | support doing so, create the submenu and add the | ||
| 184 | contents of the menu to it. */ | ||
| 185 | submenu = menu.addSubMenu (item.itemName); | 220 | submenu = menu.addSubMenu (item.itemName); |
| 186 | item.subMenu.inflateMenuItems (submenu); | 221 | item.subMenu.inflateMenuItems (submenu, inflatedView); |
| 187 | } | 222 | |
| 188 | catch (UnsupportedOperationException exception) | 223 | /* This is still needed to set wasSubmenuSelected. */ |
| 189 | { | 224 | menuItem = submenu.getItem (); |
| 190 | /* This version of Android has a restriction | ||
| 191 | preventing submenus from being added to submenus. | ||
| 192 | Inflate everything into the parent menu | ||
| 193 | instead. */ | ||
| 194 | item.subMenu.inflateMenuItems (menu); | ||
| 195 | continue; | ||
| 196 | } | 225 | } |
| 226 | else | ||
| 227 | menuItem = menu.add (item.itemName); | ||
| 197 | 228 | ||
| 198 | /* This is still needed to set wasSubmenuSelected. */ | 229 | item.inflatedView = inflatedView; |
| 199 | menuItem = submenu.getItem (); | ||
| 200 | menuItem.setOnMenuItemClickListener (item); | 230 | menuItem.setOnMenuItemClickListener (item); |
| 201 | } | 231 | } |
| 202 | else | 232 | else |
| @@ -227,16 +257,14 @@ public final class EmacsContextMenu | |||
| 227 | } | 257 | } |
| 228 | } | 258 | } |
| 229 | 259 | ||
| 230 | /* Enter the items in this context menu to MENU. Create each menu | 260 | /* Enter the items in this context menu to MENU. |
| 231 | item with an Intent containing a Bundle, where the key | 261 | Assume that MENU will be displayed in VIEW; this may lead to |
| 232 | "emacs:menu_item_hi" maps to the high 16 bits of the | 262 | popupMenu being called on VIEW if a submenu is selected. */ |
| 233 | corresponding item ID, and the key "emacs:menu_item_low" maps to | ||
| 234 | the low 16 bits of the item ID. */ | ||
| 235 | 263 | ||
| 236 | public void | 264 | public void |
| 237 | expandTo (Menu menu) | 265 | expandTo (Menu menu, EmacsView view) |
| 238 | { | 266 | { |
| 239 | inflateMenuItems (menu); | 267 | inflateMenuItems (menu, view); |
| 240 | } | 268 | } |
| 241 | 269 | ||
| 242 | /* Return the parent or NULL. */ | 270 | /* Return the parent or NULL. */ |
| @@ -260,7 +288,8 @@ public final class EmacsContextMenu | |||
| 260 | /* No submenu has been selected yet. */ | 288 | /* No submenu has been selected yet. */ |
| 261 | wasSubmenuSelected = false; | 289 | wasSubmenuSelected = false; |
| 262 | 290 | ||
| 263 | return window.view.popupMenu (this, xPosition, yPosition); | 291 | return window.view.popupMenu (this, xPosition, yPosition, |
| 292 | false); | ||
| 264 | } | 293 | } |
| 265 | 294 | ||
| 266 | /* Display this context menu on WINDOW, at xPosition and | 295 | /* Display this context menu on WINDOW, at xPosition and |
diff --git a/java/org/gnu/emacs/EmacsView.java b/java/org/gnu/emacs/EmacsView.java index d2330494bc7..617836d8811 100644 --- a/java/org/gnu/emacs/EmacsView.java +++ b/java/org/gnu/emacs/EmacsView.java | |||
| @@ -464,19 +464,22 @@ public final class EmacsView extends ViewGroup | |||
| 464 | if (contextMenu == null) | 464 | if (contextMenu == null) |
| 465 | return; | 465 | return; |
| 466 | 466 | ||
| 467 | contextMenu.expandTo (menu); | 467 | contextMenu.expandTo (menu, this); |
| 468 | } | 468 | } |
| 469 | 469 | ||
| 470 | public boolean | 470 | public boolean |
| 471 | popupMenu (EmacsContextMenu menu, int xPosition, | 471 | popupMenu (EmacsContextMenu menu, int xPosition, |
| 472 | int yPosition) | 472 | int yPosition, boolean force) |
| 473 | { | 473 | { |
| 474 | if (popupActive) | 474 | if (popupActive && !force) |
| 475 | return false; | 475 | return false; |
| 476 | 476 | ||
| 477 | contextMenu = menu; | 477 | contextMenu = menu; |
| 478 | popupActive = true; | 478 | popupActive = true; |
| 479 | 479 | ||
| 480 | Log.d (TAG, "popupMenu: " + menu + " @" + xPosition | ||
| 481 | + ", " + yPosition + " " + force); | ||
| 482 | |||
| 480 | /* Use showContextMenu (float, float) on N to get actual popup | 483 | /* Use showContextMenu (float, float) on N to get actual popup |
| 481 | behavior. */ | 484 | behavior. */ |
| 482 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) | 485 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) |