We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
iOS App has no attribute 'hide_cursor'
**Describe the bug**
Calling the method `hide_cursor()` on a `toga.App` causes the app to crash with:
```
2021-03-28 13:35:22.700314-0700 Find [938:323815] AttributeError: 'App' object has no attribute 'hide_cursor'
```

**To Reproduce**
Steps to reproduce the behavior:
1. Create a simple iOS App
2. inside the main method of your application class (derived from `toga.App`) call: `self.hide_cursor()`
3. App crashes with stacktrace
4. See error

```
 Error in long running handler: 'App' object has no attribute 'hide_cursor'
 Traceback (most recent call last):
   File "/private/var/containers/Bundle/Application/75DCDE12-8E7D-4D0A-97D1-B999813DBD9B/Find.app/Library/Application Support/app_packages/toga/handlers.py", line 13, in long_running_task
     delay = next(generator)
   File "/private/var/containers/Bundle/Application/75DCDE12-8E7D-4D0A-97D1-B999813DBD9B/Find.app/Library/Application Support/app/find/app.py", line 84, in select_distance_task
     self.hide_cursor()
   File "/private/var/containers/Bundle/Application/75DCDE12-8E7D-4D0A-97D1-B999813DBD9B/Find.app/Library/Application Support/app_packages/toga/app.py", line 412, in hide_cursor
     self._impl.hide_cursor()
 AttributeError: 'App' object has no attribute 'hide_cursor'
```

**Expected behavior**
The method is documented [here](https://toga.readthedocs.io/en/latest/reference/api/app.html#toga.app.App.hide_cursor)

Not sure what to expect, really, (the description, rather tautologically, says "hides cursors") but at the very least not to crash?

What I was really trying to achieve was to hide the keyboard from view (also because the `focus()` method on non-input fields seems to be a no-op?).

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Environment:**
 - Operating System: iOS 14.4
 - Python version: 3.8
 - Software versions:
 toga==0.2.15
toga-cocoa==0.2.15
toga-core==0.2.15

**Additional context**

It would be good to have a way to make the "soft" keyboard disappear in iOS, as it obscures half the screen, and Toga does not appear to have a means to achieve that.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `iOS/src/toga_iOS/app.py`
Content:
```
1 import asyncio
2 
3 from rubicon.objc import objc_method
4 from rubicon.objc.eventloop import EventLoopPolicy, iOSLifecycle
5 
6 from toga_iOS.libs import UIResponder
7 from toga_iOS.window import Window
8 
9 
10 class MainWindow(Window):
11     pass
12 
13 
14 class PythonAppDelegate(UIResponder):
15     @objc_method
16     def applicationDidBecomeActive_(self, application) -> None:
17         print("App became active.")
18 
19     @objc_method
20     def applicationWillResignActive_(self, application) -> None:
21         print("App about to leave foreground.", flush=True)
22 
23     @objc_method
24     def applicationDidEnterBackground_(self, application) -> None:
25         print("App entered background.")
26 
27     @objc_method
28     def applicationWillEnterForeground_(self, application) -> None:
29         print("App about to enter foreground.")
30 
31     @objc_method
32     def application_didFinishLaunchingWithOptions_(
33         self, application, launchOptions
34     ) -> bool:
35         print("App finished launching.")
36         App.app.native = application
37         App.app.create()
38         return True
39 
40     @objc_method
41     def applicationWillTerminate_(self, application) -> None:
42         print("App about to Terminate.")
43 
44     @objc_method
45     def application_didChangeStatusBarOrientation_(
46         self, application, oldStatusBarOrientation: int
47     ) -> None:
48         """This callback is invoked when rotating the device from landscape to portrait
49         and vice versa."""
50         App.app.interface.main_window.content.refresh()
51 
52 
53 class App:
54     def __init__(self, interface):
55         self.interface = interface
56         self.interface._impl = self
57         # Native instance doesn't exist until the lifecycle completes.
58         self.native = None
59 
60         # Add a reference for the PythonAppDelegate class to use.
61         App.app = self
62 
63         asyncio.set_event_loop_policy(EventLoopPolicy())
64         self.loop = asyncio.new_event_loop()
65 
66     def create(self):
67         """Calls the startup method on the interface."""
68         self.interface._startup()
69 
70     def open_document(self, fileURL):
71         """Add a new document to this app."""
72         pass
73 
74     def main_loop(self):
75         # Main loop is non-blocking on iOS. The app loop is integrated with the
76         # main iOS event loop, so this call will return; however, it will leave
77         # the app in a state such that asyncio events will be scheduled on the
78         # iOS event loop.
79         self.loop.run_forever_cooperatively(lifecycle=iOSLifecycle())
80 
81     def set_main_window(self, window):
82         pass
83 
84     def show_about_dialog(self):
85         self.interface.factory.not_implemented("App.show_about_dialog()")
86 
87     def beep(self):
88         self.interface.factory.not_implemented("App.beep()")
89 
90     def exit(self):
91         pass
92
```

Path: `android/src/toga_android/app.py`
Content:
```
1 import asyncio
2 
3 from rubicon.java import android_events
4 
5 import toga
6 from toga.command import Group
7 
8 from .libs.activity import IPythonApp, MainActivity
9 from .libs.android.graphics import Drawable
10 from .libs.android.view import Menu, MenuItem
11 from .window import Window
12 
13 # `MainWindow` is defined here in `app.py`, not `window.py`, to mollify the test suite.
14 MainWindow = Window
15 
16 
17 class TogaApp(IPythonApp):
18     last_intent_requestcode = (
19         -1
20     )  # always increment before using it for invoking new Intents
21     running_intents = {}  # dictionary for currently running Intents
22     menuitem_mapping = {}  # dictionary for mapping menuitems to commands
23 
24     def __init__(self, app):
25         super().__init__()
26         self._impl = app
27         MainActivity.setPythonApp(self)
28         print("Python app launched & stored in Android Activity class")
29 
30     def onCreate(self):
31         print("Toga app: onCreate")
32 
33     def onStart(self):
34         print("Toga app: onStart")
35 
36     def onResume(self):
37         print("Toga app: onResume")
38 
39     def onPause(self):
40         print("Toga app: onPause")
41 
42     def onStop(self):
43         print("Toga app: onStop")
44 
45     def onDestroy(self):
46         print("Toga app: onDestroy")
47 
48     def onRestart(self):
49         print("Toga app: onRestart")
50 
51     def onActivityResult(self, requestCode, resultCode, resultData):
52         """Callback method, called from MainActivity when an Intent ends.
53 
54         :param int requestCode: The integer request code originally supplied to startActivityForResult(),
55                                 allowing you to identify who this result came from.
56         :param int resultCode: The integer result code returned by the child activity through its setResult().
57         :param Intent resultData: An Intent, which can return result data to the caller (various data can be attached
58                                   to Intent "extras").
59         """
60         print(
61             f"Toga app: onActivityResult, requestCode={requestCode}, resultData={resultData}"
62         )
63         try:
64             # remove Intent from the list of running Intents,
65             # and set the result of the intent.
66             result_future = self.running_intents.pop(requestCode)
67             result_future.set_result(
68                 {"resultCode": resultCode, "resultData": resultData}
69             )
70         except KeyError:
71             print("No intent matching request code {requestCode}")
72 
73     def onConfigurationChanged(self, new_config):
74         pass
75 
76     def onOptionsItemSelected(self, menuitem):
77         consumed = False
78         try:
79             cmd = self.menuitem_mapping[menuitem.getItemId()]
80             consumed = True
81             if cmd.action is not None:
82                 cmd.action(menuitem)
83         except KeyError:
84             print("menu item id not found in menuitem_mapping dictionary!")
85         return consumed
86 
87     def onPrepareOptionsMenu(self, menu):
88         menu.clear()
89         itemid = 0
90         menulist = {}  # dictionary with all menus
91         self.menuitem_mapping.clear()
92 
93         # create option menu
94         for cmd in self._impl.interface.commands:
95             if cmd == toga.SECTION_BREAK or cmd == toga.GROUP_BREAK:
96                 continue
97             if cmd in self._impl.interface.main_window.toolbar:
98                 continue  # do not show toolbar commands in the option menu (except when overflowing)
99 
100             grouppath = cmd.group.path
101             if grouppath[0] != Group.COMMANDS:
102                 # only the Commands group (and its subgroups) are supported
103                 # other groups should eventually go into the navigation drawer
104                 continue
105             if cmd.group.key in menulist:
106                 menugroup = menulist[cmd.group.key]
107             else:
108                 # create all missing submenus
109                 parentmenu = menu
110                 for group in grouppath:
111                     groupkey = group.key
112                     if groupkey in menulist:
113                         menugroup = menulist[groupkey]
114                     else:
115                         if group.text == toga.Group.COMMANDS.text:
116                             menulist[groupkey] = menu
117                             menugroup = menu
118                         else:
119                             itemid += 1
120                             order = Menu.NONE if group.order is None else group.order
121                             menugroup = parentmenu.addSubMenu(
122                                 Menu.NONE, itemid, order, group.text
123                             )  # groupId, itemId, order, title
124                             menulist[groupkey] = menugroup
125                     parentmenu = menugroup
126             # create menu item
127             itemid += 1
128             order = Menu.NONE if cmd.order is None else cmd.order
129             menuitem = menugroup.add(
130                 Menu.NONE, itemid, order, cmd.text
131             )  # groupId, itemId, order, title
132             menuitem.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_NEVER)
133             menuitem.setEnabled(cmd.enabled)
134             self.menuitem_mapping[
135                 itemid
136             ] = cmd  # store itemid for use in onOptionsItemSelected
137 
138         # create toolbar actions
139         if self._impl.interface.main_window:
140             for cmd in self._impl.interface.main_window.toolbar:
141                 if cmd == toga.SECTION_BREAK or cmd == toga.GROUP_BREAK:
142                     continue
143                 itemid += 1
144                 order = Menu.NONE if cmd.order is None else cmd.order
145                 menuitem = menu.add(
146                     Menu.NONE, itemid, order, cmd.text
147                 )  # groupId, itemId, order, title
148                 menuitem.setShowAsActionFlags(
149                     MenuItem.SHOW_AS_ACTION_IF_ROOM
150                 )  # toolbar button / item in options menu on overflow
151                 menuitem.setEnabled(cmd.enabled)
152                 if cmd.icon:
153                     icon = Drawable.createFromPath(str(cmd.icon._impl.path))
154                     if icon:
155                         menuitem.setIcon(icon)
156                     else:
157                         print("Could not create icon: " + str(cmd.icon._impl.path))
158                 self.menuitem_mapping[
159                     itemid
160                 ] = cmd  # store itemid for use in onOptionsItemSelected
161 
162         return True
163 
164     @property
165     def native(self):
166         # We access `MainActivity.singletonThis` freshly each time, rather than
167         # storing a reference in `__init__()`, because it's not safe to use the
168         # same reference over time because `rubicon-java` creates a JNI local
169         # reference.
170         return MainActivity.singletonThis
171 
172 
173 class App:
174     def __init__(self, interface):
175         self.interface = interface
176         self.interface._impl = self
177         self._listener = None
178 
179         self.loop = android_events.AndroidEventLoop()
180 
181     @property
182     def native(self):
183         return self._listener.native if self._listener else None
184 
185     def create(self):
186         # The `_listener` listens for activity event callbacks. For simplicity,
187         # the app's `.native` is the listener's native Java class.
188         self._listener = TogaApp(self)
189         # Call user code to populate the main window
190         self.interface._startup()
191 
192     def open_document(self, fileURL):
193         print("Can't open document %s (yet)" % fileURL)
194 
195     def main_loop(self):
196         # In order to support user asyncio code, start the Python/Android cooperative event loop.
197         self.loop.run_forever_cooperatively()
198 
199         # On Android, Toga UI integrates automatically into the main Android event loop by virtue
200         # of the Android Activity system.
201         self.create()
202 
203     def set_main_window(self, window):
204         pass
205 
206     def show_about_dialog(self):
207         self.interface.factory.not_implemented("App.show_about_dialog()")
208 
209     def beep(self):
210         self.interface.factory.not_implemented("App.beep()")
211 
212     def exit(self):
213         pass
214 
215     async def intent_result(self, intent):
216         """Calls an Intent and waits for its result.
217 
218         A RuntimeError will be raised when the Intent cannot be invoked.
219 
220         :param Intent intent: The Intent to call
221         :returns: A Dictionary containing "resultCode" (int) and "resultData" (Intent or None)
222         :rtype: dict
223         """
224         try:
225             self._listener.last_intent_requestcode += 1
226             code = self._listener.last_intent_requestcode
227 
228             result_future = asyncio.Future()
229             self._listener.running_intents[code] = result_future
230 
231             self.native.startActivityForResult(intent, code)
232             await result_future
233             return result_future.result()
234         except AttributeError:
235             raise RuntimeError("No appropriate Activity found to handle this intent.")
236
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/android/src/toga_android/app.py b/android/src/toga_android/app.py
--- a/android/src/toga_android/app.py
+++ b/android/src/toga_android/app.py
@@ -233,3 +233,9 @@
             return result_future.result()
         except AttributeError:
             raise RuntimeError("No appropriate Activity found to handle this intent.")
+
+    def hide_cursor(self):
+        pass
+
+    def show_cursor(self):
+        pass
diff --git a/iOS/src/toga_iOS/app.py b/iOS/src/toga_iOS/app.py
--- a/iOS/src/toga_iOS/app.py
+++ b/iOS/src/toga_iOS/app.py
@@ -89,3 +89,9 @@
 
     def exit(self):
         pass
+
+    def hide_cursor(self):
+        pass
+
+    def show_cursor(self):
+        pass

{"golden_diff": "diff --git a/android/src/toga_android/app.py b/android/src/toga_android/app.py\n--- a/android/src/toga_android/app.py\n+++ b/android/src/toga_android/app.py\n@@ -233,3 +233,9 @@\n             return result_future.result()\n         except AttributeError:\n             raise RuntimeError(\"No appropriate Activity found to handle this intent.\")\n+\n+    def hide_cursor(self):\n+        pass\n+\n+    def show_cursor(self):\n+        pass\ndiff --git a/iOS/src/toga_iOS/app.py b/iOS/src/toga_iOS/app.py\n--- a/iOS/src/toga_iOS/app.py\n+++ b/iOS/src/toga_iOS/app.py\n@@ -89,3 +89,9 @@\n \n     def exit(self):\n         pass\n+\n+    def hide_cursor(self):\n+        pass\n+\n+    def show_cursor(self):\n+        pass\n", "issue": "iOS App has no attribute 'hide_cursor'\n**Describe the bug**\r\nCalling the method `hide_cursor()` on a `toga.App` causes the app to crash with:\r\n```\r\n2021-03-28 13:35:22.700314-0700 Find [938:323815] AttributeError: 'App' object has no attribute 'hide_cursor'\r\n```\r\n\r\n**To Reproduce**\r\nSteps to reproduce the behavior:\r\n1. Create a simple iOS App\r\n2. inside the main method of your application class (derived from `toga.App`) call: `self.hide_cursor()`\r\n3. App crashes with stacktrace\r\n4. See error\r\n\r\n```\r\n Error in long running handler: 'App' object has no attribute 'hide_cursor'\r\n Traceback (most recent call last):\r\n   File \"/private/var/containers/Bundle/Application/75DCDE12-8E7D-4D0A-97D1-B999813DBD9B/Find.app/Library/Application Support/app_packages/toga/handlers.py\", line 13, in long_running_task\r\n     delay = next(generator)\r\n   File \"/private/var/containers/Bundle/Application/75DCDE12-8E7D-4D0A-97D1-B999813DBD9B/Find.app/Library/Application Support/app/find/app.py\", line 84, in select_distance_task\r\n     self.hide_cursor()\r\n   File \"/private/var/containers/Bundle/Application/75DCDE12-8E7D-4D0A-97D1-B999813DBD9B/Find.app/Library/Application Support/app_packages/toga/app.py\", line 412, in hide_cursor\r\n     self._impl.hide_cursor()\r\n AttributeError: 'App' object has no attribute 'hide_cursor'\r\n```\r\n\r\n**Expected behavior**\r\nThe method is documented [here](https://toga.readthedocs.io/en/latest/reference/api/app.html#toga.app.App.hide_cursor)\r\n\r\nNot sure what to expect, really, (the description, rather tautologically, says \"hides cursors\") but at the very least not to crash?\r\n\r\nWhat I was really trying to achieve was to hide the keyboard from view (also because the `focus()` method on non-input fields seems to be a no-op?).\r\n\r\n**Screenshots**\r\nIf applicable, add screenshots to help explain your problem.\r\n\r\n**Environment:**\r\n - Operating System: iOS 14.4\r\n - Python version: 3.8\r\n - Software versions:\r\n toga==0.2.15\r\ntoga-cocoa==0.2.15\r\ntoga-core==0.2.15\r\n\r\n**Additional context**\r\n\r\nIt would be good to have a way to make the \"soft\" keyboard disappear in iOS, as it obscures half the screen, and Toga does not appear to have a means to achieve that.\r\n\n", "before_files": [{"content": "import asyncio\n\nfrom rubicon.objc import objc_method\nfrom rubicon.objc.eventloop import EventLoopPolicy, iOSLifecycle\n\nfrom toga_iOS.libs import UIResponder\nfrom toga_iOS.window import Window\n\n\nclass MainWindow(Window):\n    pass\n\n\nclass PythonAppDelegate(UIResponder):\n    @objc_method\n    def applicationDidBecomeActive_(self, application) -> None:\n        print(\"App became active.\")\n\n    @objc_method\n    def applicationWillResignActive_(self, application) -> None:\n        print(\"App about to leave foreground.\", flush=True)\n\n    @objc_method\n    def applicationDidEnterBackground_(self, application) -> None:\n        print(\"App entered background.\")\n\n    @objc_method\n    def applicationWillEnterForeground_(self, application) -> None:\n        print(\"App about to enter foreground.\")\n\n    @objc_method\n    def application_didFinishLaunchingWithOptions_(\n        self, application, launchOptions\n    ) -> bool:\n        print(\"App finished launching.\")\n        App.app.native = application\n        App.app.create()\n        return True\n\n    @objc_method\n    def applicationWillTerminate_(self, application) -> None:\n        print(\"App about to Terminate.\")\n\n    @objc_method\n    def application_didChangeStatusBarOrientation_(\n        self, application, oldStatusBarOrientation: int\n    ) -> None:\n        \"\"\"This callback is invoked when rotating the device from landscape to portrait\n        and vice versa.\"\"\"\n        App.app.interface.main_window.content.refresh()\n\n\nclass App:\n    def __init__(self, interface):\n        self.interface = interface\n        self.interface._impl = self\n        # Native instance doesn't exist until the lifecycle completes.\n        self.native = None\n\n        # Add a reference for the PythonAppDelegate class to use.\n        App.app = self\n\n        asyncio.set_event_loop_policy(EventLoopPolicy())\n        self.loop = asyncio.new_event_loop()\n\n    def create(self):\n        \"\"\"Calls the startup method on the interface.\"\"\"\n        self.interface._startup()\n\n    def open_document(self, fileURL):\n        \"\"\"Add a new document to this app.\"\"\"\n        pass\n\n    def main_loop(self):\n        # Main loop is non-blocking on iOS. The app loop is integrated with the\n        # main iOS event loop, so this call will return; however, it will leave\n        # the app in a state such that asyncio events will be scheduled on the\n        # iOS event loop.\n        self.loop.run_forever_cooperatively(lifecycle=iOSLifecycle())\n\n    def set_main_window(self, window):\n        pass\n\n    def show_about_dialog(self):\n        self.interface.factory.not_implemented(\"App.show_about_dialog()\")\n\n    def beep(self):\n        self.interface.factory.not_implemented(\"App.beep()\")\n\n    def exit(self):\n        pass\n", "path": "iOS/src/toga_iOS/app.py"}, {"content": "import asyncio\n\nfrom rubicon.java import android_events\n\nimport toga\nfrom toga.command import Group\n\nfrom .libs.activity import IPythonApp, MainActivity\nfrom .libs.android.graphics import Drawable\nfrom .libs.android.view import Menu, MenuItem\nfrom .window import Window\n\n# `MainWindow` is defined here in `app.py`, not `window.py`, to mollify the test suite.\nMainWindow = Window\n\n\nclass TogaApp(IPythonApp):\n    last_intent_requestcode = (\n        -1\n    )  # always increment before using it for invoking new Intents\n    running_intents = {}  # dictionary for currently running Intents\n    menuitem_mapping = {}  # dictionary for mapping menuitems to commands\n\n    def __init__(self, app):\n        super().__init__()\n        self._impl = app\n        MainActivity.setPythonApp(self)\n        print(\"Python app launched & stored in Android Activity class\")\n\n    def onCreate(self):\n        print(\"Toga app: onCreate\")\n\n    def onStart(self):\n        print(\"Toga app: onStart\")\n\n    def onResume(self):\n        print(\"Toga app: onResume\")\n\n    def onPause(self):\n        print(\"Toga app: onPause\")\n\n    def onStop(self):\n        print(\"Toga app: onStop\")\n\n    def onDestroy(self):\n        print(\"Toga app: onDestroy\")\n\n    def onRestart(self):\n        print(\"Toga app: onRestart\")\n\n    def onActivityResult(self, requestCode, resultCode, resultData):\n        \"\"\"Callback method, called from MainActivity when an Intent ends.\n\n        :param int requestCode: The integer request code originally supplied to startActivityForResult(),\n                                allowing you to identify who this result came from.\n        :param int resultCode: The integer result code returned by the child activity through its setResult().\n        :param Intent resultData: An Intent, which can return result data to the caller (various data can be attached\n                                  to Intent \"extras\").\n        \"\"\"\n        print(\n            f\"Toga app: onActivityResult, requestCode={requestCode}, resultData={resultData}\"\n        )\n        try:\n            # remove Intent from the list of running Intents,\n            # and set the result of the intent.\n            result_future = self.running_intents.pop(requestCode)\n            result_future.set_result(\n                {\"resultCode\": resultCode, \"resultData\": resultData}\n            )\n        except KeyError:\n            print(\"No intent matching request code {requestCode}\")\n\n    def onConfigurationChanged(self, new_config):\n        pass\n\n    def onOptionsItemSelected(self, menuitem):\n        consumed = False\n        try:\n            cmd = self.menuitem_mapping[menuitem.getItemId()]\n            consumed = True\n            if cmd.action is not None:\n                cmd.action(menuitem)\n        except KeyError:\n            print(\"menu item id not found in menuitem_mapping dictionary!\")\n        return consumed\n\n    def onPrepareOptionsMenu(self, menu):\n        menu.clear()\n        itemid = 0\n        menulist = {}  # dictionary with all menus\n        self.menuitem_mapping.clear()\n\n        # create option menu\n        for cmd in self._impl.interface.commands:\n            if cmd == toga.SECTION_BREAK or cmd == toga.GROUP_BREAK:\n                continue\n            if cmd in self._impl.interface.main_window.toolbar:\n                continue  # do not show toolbar commands in the option menu (except when overflowing)\n\n            grouppath = cmd.group.path\n            if grouppath[0] != Group.COMMANDS:\n                # only the Commands group (and its subgroups) are supported\n                # other groups should eventually go into the navigation drawer\n                continue\n            if cmd.group.key in menulist:\n                menugroup = menulist[cmd.group.key]\n            else:\n                # create all missing submenus\n                parentmenu = menu\n                for group in grouppath:\n                    groupkey = group.key\n                    if groupkey in menulist:\n                        menugroup = menulist[groupkey]\n                    else:\n                        if group.text == toga.Group.COMMANDS.text:\n                            menulist[groupkey] = menu\n                            menugroup = menu\n                        else:\n                            itemid += 1\n                            order = Menu.NONE if group.order is None else group.order\n                            menugroup = parentmenu.addSubMenu(\n                                Menu.NONE, itemid, order, group.text\n                            )  # groupId, itemId, order, title\n                            menulist[groupkey] = menugroup\n                    parentmenu = menugroup\n            # create menu item\n            itemid += 1\n            order = Menu.NONE if cmd.order is None else cmd.order\n            menuitem = menugroup.add(\n                Menu.NONE, itemid, order, cmd.text\n            )  # groupId, itemId, order, title\n            menuitem.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_NEVER)\n            menuitem.setEnabled(cmd.enabled)\n            self.menuitem_mapping[\n                itemid\n            ] = cmd  # store itemid for use in onOptionsItemSelected\n\n        # create toolbar actions\n        if self._impl.interface.main_window:\n            for cmd in self._impl.interface.main_window.toolbar:\n                if cmd == toga.SECTION_BREAK or cmd == toga.GROUP_BREAK:\n                    continue\n                itemid += 1\n                order = Menu.NONE if cmd.order is None else cmd.order\n                menuitem = menu.add(\n                    Menu.NONE, itemid, order, cmd.text\n                )  # groupId, itemId, order, title\n                menuitem.setShowAsActionFlags(\n                    MenuItem.SHOW_AS_ACTION_IF_ROOM\n                )  # toolbar button / item in options menu on overflow\n                menuitem.setEnabled(cmd.enabled)\n                if cmd.icon:\n                    icon = Drawable.createFromPath(str(cmd.icon._impl.path))\n                    if icon:\n                        menuitem.setIcon(icon)\n                    else:\n                        print(\"Could not create icon: \" + str(cmd.icon._impl.path))\n                self.menuitem_mapping[\n                    itemid\n                ] = cmd  # store itemid for use in onOptionsItemSelected\n\n        return True\n\n    @property\n    def native(self):\n        # We access `MainActivity.singletonThis` freshly each time, rather than\n        # storing a reference in `__init__()`, because it's not safe to use the\n        # same reference over time because `rubicon-java` creates a JNI local\n        # reference.\n        return MainActivity.singletonThis\n\n\nclass App:\n    def __init__(self, interface):\n        self.interface = interface\n        self.interface._impl = self\n        self._listener = None\n\n        self.loop = android_events.AndroidEventLoop()\n\n    @property\n    def native(self):\n        return self._listener.native if self._listener else None\n\n    def create(self):\n        # The `_listener` listens for activity event callbacks. For simplicity,\n        # the app's `.native` is the listener's native Java class.\n        self._listener = TogaApp(self)\n        # Call user code to populate the main window\n        self.interface._startup()\n\n    def open_document(self, fileURL):\n        print(\"Can't open document %s (yet)\" % fileURL)\n\n    def main_loop(self):\n        # In order to support user asyncio code, start the Python/Android cooperative event loop.\n        self.loop.run_forever_cooperatively()\n\n        # On Android, Toga UI integrates automatically into the main Android event loop by virtue\n        # of the Android Activity system.\n        self.create()\n\n    def set_main_window(self, window):\n        pass\n\n    def show_about_dialog(self):\n        self.interface.factory.not_implemented(\"App.show_about_dialog()\")\n\n    def beep(self):\n        self.interface.factory.not_implemented(\"App.beep()\")\n\n    def exit(self):\n        pass\n\n    async def intent_result(self, intent):\n        \"\"\"Calls an Intent and waits for its result.\n\n        A RuntimeError will be raised when the Intent cannot be invoked.\n\n        :param Intent intent: The Intent to call\n        :returns: A Dictionary containing \"resultCode\" (int) and \"resultData\" (Intent or None)\n        :rtype: dict\n        \"\"\"\n        try:\n            self._listener.last_intent_requestcode += 1\n            code = self._listener.last_intent_requestcode\n\n            result_future = asyncio.Future()\n            self._listener.running_intents[code] = result_future\n\n            self.native.startActivityForResult(intent, code)\n            await result_future\n            return result_future.result()\n        except AttributeError:\n            raise RuntimeError(\"No appropriate Activity found to handle this intent.\")\n", "path": "android/src/toga_android/app.py"}], "after_files": [{"content": "import asyncio\n\nfrom rubicon.objc import objc_method\nfrom rubicon.objc.eventloop import EventLoopPolicy, iOSLifecycle\n\nfrom toga_iOS.libs import UIResponder\nfrom toga_iOS.window import Window\n\n\nclass MainWindow(Window):\n    pass\n\n\nclass PythonAppDelegate(UIResponder):\n    @objc_method\n    def applicationDidBecomeActive_(self, application) -> None:\n        print(\"App became active.\")\n\n    @objc_method\n    def applicationWillResignActive_(self, application) -> None:\n        print(\"App about to leave foreground.\", flush=True)\n\n    @objc_method\n    def applicationDidEnterBackground_(self, application) -> None:\n        print(\"App entered background.\")\n\n    @objc_method\n    def applicationWillEnterForeground_(self, application) -> None:\n        print(\"App about to enter foreground.\")\n\n    @objc_method\n    def application_didFinishLaunchingWithOptions_(\n        self, application, launchOptions\n    ) -> bool:\n        print(\"App finished launching.\")\n        App.app.native = application\n        App.app.create()\n        return True\n\n    @objc_method\n    def applicationWillTerminate_(self, application) -> None:\n        print(\"App about to Terminate.\")\n\n    @objc_method\n    def application_didChangeStatusBarOrientation_(\n        self, application, oldStatusBarOrientation: int\n    ) -> None:\n        \"\"\"This callback is invoked when rotating the device from landscape to portrait\n        and vice versa.\"\"\"\n        App.app.interface.main_window.content.refresh()\n\n\nclass App:\n    def __init__(self, interface):\n        self.interface = interface\n        self.interface._impl = self\n        # Native instance doesn't exist until the lifecycle completes.\n        self.native = None\n\n        # Add a reference for the PythonAppDelegate class to use.\n        App.app = self\n\n        asyncio.set_event_loop_policy(EventLoopPolicy())\n        self.loop = asyncio.new_event_loop()\n\n    def create(self):\n        \"\"\"Calls the startup method on the interface.\"\"\"\n        self.interface.startup()\n\n    def open_document(self, fileURL):\n        \"\"\"Add a new document to this app.\"\"\"\n        pass\n\n    def main_loop(self):\n        # Main loop is non-blocking on iOS. The app loop is integrated with the\n        # main iOS event loop, so this call will return; however, it will leave\n        # the app in a state such that asyncio events will be scheduled on the\n        # iOS event loop.\n        self.loop.run_forever_cooperatively(lifecycle=iOSLifecycle())\n\n    def set_main_window(self, window):\n        pass\n\n    def show_about_dialog(self):\n        self.interface.factory.not_implemented(\"App.show_about_dialog()\")\n\n    def beep(self):\n        self.interface.factory.not_implemented(\"App.beep()\")\n\n    def exit(self):\n        pass\n\n    def hide_cursor(self):\n        pass\n\n    def show_cursor(self):\n        pass\n", "path": "iOS/src/toga_iOS/app.py"}, {"content": "import asyncio\n\nfrom rubicon.java import android_events\n\nimport toga\nfrom toga.command import Group\n\nfrom .libs.activity import IPythonApp, MainActivity\nfrom .libs.android.graphics import Drawable\nfrom .libs.android.view import Menu, MenuItem\nfrom .window import Window\n\n# `MainWindow` is defined here in `app.py`, not `window.py`, to mollify the test suite.\nMainWindow = Window\n\n\nclass TogaApp(IPythonApp):\n    last_intent_requestcode = (\n        -1\n    )  # always increment before using it for invoking new Intents\n    running_intents = {}  # dictionary for currently running Intents\n    menuitem_mapping = {}  # dictionary for mapping menuitems to commands\n\n    def __init__(self, app):\n        super().__init__()\n        self._impl = app\n        MainActivity.setPythonApp(self)\n        print(\"Python app launched & stored in Android Activity class\")\n\n    def onCreate(self):\n        print(\"Toga app: onCreate\")\n\n    def onStart(self):\n        print(\"Toga app: onStart\")\n\n    def onResume(self):\n        print(\"Toga app: onResume\")\n\n    def onPause(self):\n        print(\"Toga app: onPause\")\n\n    def onStop(self):\n        print(\"Toga app: onStop\")\n\n    def onDestroy(self):\n        print(\"Toga app: onDestroy\")\n\n    def onRestart(self):\n        print(\"Toga app: onRestart\")\n\n    def onActivityResult(self, requestCode, resultCode, resultData):\n        \"\"\"Callback method, called from MainActivity when an Intent ends.\n\n        :param int requestCode: The integer request code originally supplied to startActivityForResult(),\n                                allowing you to identify who this result came from.\n        :param int resultCode: The integer result code returned by the child activity through its setResult().\n        :param Intent resultData: An Intent, which can return result data to the caller (various data can be attached\n                                  to Intent \"extras\").\n        \"\"\"\n        print(\n            f\"Toga app: onActivityResult, requestCode={requestCode}, resultData={resultData}\"\n        )\n        try:\n            # remove Intent from the list of running Intents,\n            # and set the result of the intent.\n            result_future = self.running_intents.pop(requestCode)\n            result_future.set_result(\n                {\"resultCode\": resultCode, \"resultData\": resultData}\n            )\n        except KeyError:\n            print(\"No intent matching request code {requestCode}\")\n\n    def onConfigurationChanged(self, new_config):\n        pass\n\n    def onOptionsItemSelected(self, menuitem):\n        consumed = False\n        try:\n            cmd = self.menuitem_mapping[menuitem.getItemId()]\n            consumed = True\n            if cmd.action is not None:\n                cmd.action(menuitem)\n        except KeyError:\n            print(\"menu item id not found in menuitem_mapping dictionary!\")\n        return consumed\n\n    def onPrepareOptionsMenu(self, menu):\n        menu.clear()\n        itemid = 0\n        menulist = {}  # dictionary with all menus\n        self.menuitem_mapping.clear()\n\n        # create option menu\n        for cmd in self._impl.interface.commands:\n            if cmd == toga.SECTION_BREAK or cmd == toga.GROUP_BREAK:\n                continue\n            if cmd in self._impl.interface.main_window.toolbar:\n                continue  # do not show toolbar commands in the option menu (except when overflowing)\n\n            grouppath = cmd.group.path\n            if grouppath[0] != Group.COMMANDS:\n                # only the Commands group (and its subgroups) are supported\n                # other groups should eventually go into the navigation drawer\n                continue\n            if cmd.group.key in menulist:\n                menugroup = menulist[cmd.group.key]\n            else:\n                # create all missing submenus\n                parentmenu = menu\n                for group in grouppath:\n                    groupkey = group.key\n                    if groupkey in menulist:\n                        menugroup = menulist[groupkey]\n                    else:\n                        if group.text == toga.Group.COMMANDS.text:\n                            menulist[groupkey] = menu\n                            menugroup = menu\n                        else:\n                            itemid += 1\n                            order = Menu.NONE if group.order is None else group.order\n                            menugroup = parentmenu.addSubMenu(\n                                Menu.NONE, itemid, order, group.text\n                            )  # groupId, itemId, order, title\n                            menulist[groupkey] = menugroup\n                    parentmenu = menugroup\n            # create menu item\n            itemid += 1\n            order = Menu.NONE if cmd.order is None else cmd.order\n            menuitem = menugroup.add(\n                Menu.NONE, itemid, order, cmd.text\n            )  # groupId, itemId, order, title\n            menuitem.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_NEVER)\n            menuitem.setEnabled(cmd.enabled)\n            self.menuitem_mapping[\n                itemid\n            ] = cmd  # store itemid for use in onOptionsItemSelected\n\n        # create toolbar actions\n        if self._impl.interface.main_window:\n            for cmd in self._impl.interface.main_window.toolbar:\n                if cmd == toga.SECTION_BREAK or cmd == toga.GROUP_BREAK:\n                    continue\n                itemid += 1\n                order = Menu.NONE if cmd.order is None else cmd.order\n                menuitem = menu.add(\n                    Menu.NONE, itemid, order, cmd.text\n                )  # groupId, itemId, order, title\n                menuitem.setShowAsActionFlags(\n                    MenuItem.SHOW_AS_ACTION_IF_ROOM\n                )  # toolbar button / item in options menu on overflow\n                menuitem.setEnabled(cmd.enabled)\n                if cmd.icon:\n                    icon = Drawable.createFromPath(str(cmd.icon._impl.path))\n                    if icon:\n                        menuitem.setIcon(icon)\n                    else:\n                        print(\"Could not create icon: \" + str(cmd.icon._impl.path))\n                self.menuitem_mapping[\n                    itemid\n                ] = cmd  # store itemid for use in onOptionsItemSelected\n\n        return True\n\n    @property\n    def native(self):\n        # We access `MainActivity.singletonThis` freshly each time, rather than\n        # storing a reference in `__init__()`, because it's not safe to use the\n        # same reference over time because `rubicon-java` creates a JNI local\n        # reference.\n        return MainActivity.singletonThis\n\n\nclass App:\n    def __init__(self, interface):\n        self.interface = interface\n        self.interface._impl = self\n        self._listener = None\n\n        self.loop = android_events.AndroidEventLoop()\n\n    @property\n    def native(self):\n        return self._listener.native if self._listener else None\n\n    def create(self):\n        # The `_listener` listens for activity event callbacks. For simplicity,\n        # the app's `.native` is the listener's native Java class.\n        self._listener = TogaApp(self)\n        # Call user code to populate the main window\n        self.interface.startup()\n\n    def open_document(self, fileURL):\n        print(\"Can't open document %s (yet)\" % fileURL)\n\n    def main_loop(self):\n        # In order to support user asyncio code, start the Python/Android cooperative event loop.\n        self.loop.run_forever_cooperatively()\n\n        # On Android, Toga UI integrates automatically into the main Android event loop by virtue\n        # of the Android Activity system.\n        self.create()\n\n    def set_main_window(self, window):\n        pass\n\n    def show_about_dialog(self):\n        self.interface.factory.not_implemented(\"App.show_about_dialog()\")\n\n    def beep(self):\n        self.interface.factory.not_implemented(\"App.beep()\")\n\n    def exit(self):\n        pass\n\n    async def intent_result(self, intent):\n        \"\"\"Calls an Intent and waits for its result.\n\n        A RuntimeError will be raised when the Intent cannot be invoked.\n\n        :param Intent intent: The Intent to call\n        :returns: A Dictionary containing \"resultCode\" (int) and \"resultData\" (Intent or None)\n        :rtype: dict\n        \"\"\"\n        try:\n            self._listener.last_intent_requestcode += 1\n            code = self._listener.last_intent_requestcode\n\n            result_future = asyncio.Future()\n            self._listener.running_intents[code] = result_future\n\n            self.native.startActivityForResult(intent, code)\n            await result_future\n            return result_future.result()\n        except AttributeError:\n            raise RuntimeError(\"No appropriate Activity found to handle this intent.\")\n\n    def hide_cursor(self):\n        pass\n\n    def show_cursor(self):\n        pass\n", "path": "android/src/toga_android/app.py"}]}