diff --git a/.gitignore b/.gitignore index 8eda113..b87b685 100644 --- a/.gitignore +++ b/.gitignore @@ -4,8 +4,10 @@ **/__pycache__/ androidtv.egg-info -# Build files +# Build / development files .eggs/ +.vs/ +.vscode/ build/ dist/ diff --git a/androidtv/basetv/basetv.py b/androidtv/basetv/basetv.py index aa988a1..faa400a 100644 --- a/androidtv/basetv/basetv.py +++ b/androidtv/basetv/basetv.py @@ -213,6 +213,9 @@ def _cmd_launch_app(self, app): ): return constants.CMD_LAUNCH_APP_GOOGLE_TV.format(app) + if self.DEVICE_ENUM == constants.DeviceEnum.FIRETV: + return constants.CMD_LAUNCH_APP_FIRETV.format(app) + return constants.CMD_LAUNCH_APP.format(app) def _cmd_running_apps(self): diff --git a/androidtv/constants.py b/androidtv/constants.py index f9889aa..5b6d20a 100644 --- a/androidtv/constants.py +++ b/androidtv/constants.py @@ -31,7 +31,8 @@ class DeviceEnum(IntEnum): # Intents -INTENT_LAUNCH = "android.intent.category.LAUNCHER" +INTENT_LAUNCH = "android.intent.category.LEANBACK_LAUNCHER" +INTENT_LAUNCH_FIRETV = "android.intent.category.LAUNCHER" INTENT_HOME = "android.intent.category.HOME" # Customizable commands @@ -106,11 +107,21 @@ class DeviceEnum(IntEnum): "if [ $CURRENT_APP != '{0}' ]; then monkey -p {0} -c " + INTENT_LAUNCH + " --pct-syskeys 0 1; fi" ) +#: Launch an app if it is not already the current app (assumes the variable ``CURRENT_APP`` has already been set) on a Fire TV +CMD_LAUNCH_APP_CONDITION_FIRETV = ( + "if [ $CURRENT_APP != '{0}' ]; then monkey -p {0} -c " + INTENT_LAUNCH_FIRETV + " --pct-syskeys 0 1; fi" +) + #: Launch an app if it is not already the current app CMD_LAUNCH_APP = ( CMD_DEFINE_CURRENT_APP_VARIABLE.replace("{", "{{").replace("}", "}}") + " && " + CMD_LAUNCH_APP_CONDITION ) +#: Launch an app on a Fire TV device +CMD_LAUNCH_APP_FIRETV = ( + CMD_DEFINE_CURRENT_APP_VARIABLE.replace("{", "{{").replace("}", "}}") + " && " + CMD_LAUNCH_APP_CONDITION_FIRETV +) + #: Launch an app on a Google TV device CMD_LAUNCH_APP_GOOGLE_TV = ( CMD_DEFINE_CURRENT_APP_VARIABLE_GOOGLE_TV.replace("{", "{{").replace("}", "}}") + " && " + CMD_LAUNCH_APP_CONDITION @@ -403,10 +414,10 @@ class DeviceEnum(IntEnum): APP_NOS = "nl.nos.app" APP_NPO = "nl.uitzendinggemist" APP_OCS = "com.orange.ocsgo" -APP_PLAY_GAMES = "com.google.android.games" +APP_PLAY_GAMES = "com.google.android.play.games" APP_PLAY_MUSIC = "com.google.android.music" APP_PLAY_STORE = "com.android.vending" -APP_PLAY_VIDEOS = "com.android.videos" +APP_PLAY_VIDEOS = "com.google.android.videos" APP_PLEX = "com.plexapp.android" APP_PRIME_VIDEO = "com.amazon.amazonvideo.livingroom" APP_PRIME_VIDEO_FIRETV = "com.amazon.firebat" diff --git a/tests/generate_test_constants.py b/tests/generate_test_constants.py index f7aff0e..5158c74 100644 --- a/tests/generate_test_constants.py +++ b/tests/generate_test_constants.py @@ -14,6 +14,7 @@ "CMD_DEFINE_CURRENT_APP_VARIABLE", "CMD_DEFINE_CURRENT_APP_VARIABLE_GOOGLE_TV", "CMD_LAUNCH_APP_CONDITION", + "CMD_LAUNCH_APP_CONDITION_FIRETV", } diff --git a/tests/test_androidtv_async.py b/tests/test_androidtv_async.py index 98fbc37..700ee3d 100644 --- a/tests/test_androidtv_async.py +++ b/tests/test_androidtv_async.py @@ -93,6 +93,35 @@ async def test_start_intent(self): getattr(self.atv._adb, self.ADB_ATTR).shell_cmd, "am start -a android.intent.action.VIEW -d TEST" ) + @awaiter + async def test_send_intent(self): + """Test that the ``_send_intent`` method works correctly.""" + with async_patchers.patch_shell("output\r\nretcode")[self.PATCH_KEY]: + result = await self.atv._send_intent("TEST", constants.INTENT_LAUNCH) + self.assertEqual( + getattr(self.atv._adb, self.ADB_ATTR).shell_cmd, + "monkey -p TEST -c android.intent.category.LEANBACK_LAUNCHER 1; echo $?", + ) + self.assertDictEqual(result, {"output": "output", "retcode": "retcode"}) + + with async_patchers.patch_connect(True)[self.PATCH_KEY], async_patchers.patch_shell(None)[self.PATCH_KEY]: + result = await self.atv._send_intent("TEST", constants.INTENT_LAUNCH) + self.assertEqual( + getattr(self.atv._adb, self.ADB_ATTR).shell_cmd, + "monkey -p TEST -c android.intent.category.LEANBACK_LAUNCHER 1; echo $?", + ) + self.assertDictEqual(result, {}) + + @awaiter + async def test_launch_app_stop_app(self): + """Test that the ``AndroidTVAsync.launch_app`` and ``AndroidTVAsync.stop_app`` methods work correctly.""" + with async_patchers.patch_shell("")[self.PATCH_KEY]: + await self.atv.launch_app("TEST") + self.assertEqual(getattr(self.atv._adb, self.ADB_ATTR).shell_cmd, constants.CMD_LAUNCH_APP.format("TEST")) + + await self.atv.stop_app("TEST") + self.assertEqual(getattr(self.atv._adb, self.ADB_ATTR).shell_cmd, "am force-stop TEST") + @awaiter async def test_running_apps(self): """Check that the ``running_apps`` property works correctly.""" diff --git a/tests/test_androidtv_sync.py b/tests/test_androidtv_sync.py index b87a60b..3aa22d5 100644 --- a/tests/test_androidtv_sync.py +++ b/tests/test_androidtv_sync.py @@ -123,6 +123,33 @@ def test_start_intent(self): getattr(self.atv._adb, self.ADB_ATTR).shell_cmd, "am start -a android.intent.action.VIEW -d TEST" ) + def test_send_intent(self): + """Test that the ``_send_intent`` method works correctly.""" + with patchers.patch_connect(True)[self.PATCH_KEY], patchers.patch_shell("output\r\nretcode")[self.PATCH_KEY]: + result = self.atv._send_intent("TEST", constants.INTENT_LAUNCH) + self.assertEqual( + getattr(self.atv._adb, self.ADB_ATTR).shell_cmd, + "monkey -p TEST -c android.intent.category.LEANBACK_LAUNCHER 1; echo $?", + ) + self.assertDictEqual(result, {"output": "output", "retcode": "retcode"}) + + with patchers.patch_connect(True)[self.PATCH_KEY], patchers.patch_shell(None)[self.PATCH_KEY]: + result = self.atv._send_intent("TEST", constants.INTENT_LAUNCH) + self.assertEqual( + getattr(self.atv._adb, self.ADB_ATTR).shell_cmd, + "monkey -p TEST -c android.intent.category.LEANBACK_LAUNCHER 1; echo $?", + ) + self.assertDictEqual(result, {}) + + def test_launch_app_stop_app(self): + """Test that the ``AndroidTVSync.launch_app`` and ``AndroidTVSync.stop_app`` methods work correctly.""" + with patchers.patch_connect(True)[self.PATCH_KEY], patchers.patch_shell(None)[self.PATCH_KEY]: + self.atv.launch_app("TEST") + self.assertEqual(getattr(self.atv._adb, self.ADB_ATTR).shell_cmd, constants.CMD_LAUNCH_APP.format("TEST")) + + self.atv.stop_app("TEST") + self.assertEqual(getattr(self.atv._adb, self.ADB_ATTR).shell_cmd, "am force-stop TEST") + def test_running_apps(self): """Check that the ``running_apps`` property works correctly.""" with patchers.patch_shell(None)[self.PATCH_KEY]: diff --git a/tests/test_constants.py b/tests/test_constants.py index 44891e3..0a46cfa 100644 --- a/tests/test_constants.py +++ b/tests/test_constants.py @@ -113,13 +113,19 @@ def test_constants(self): # CMD_LAUNCH_APP self.assertCommand( constants.CMD_LAUNCH_APP, + r"CURRENT_APP=$(dumpsys window windows | grep -E 'mCurrentFocus|mFocusedApp') && CURRENT_APP=${{CURRENT_APP#*ActivityRecord{{* * }} && CURRENT_APP=${{CURRENT_APP#*{{* * }} && CURRENT_APP=${{CURRENT_APP%%/*}} && CURRENT_APP=${{CURRENT_APP%\}}*}} && if [ $CURRENT_APP != '{0}' ]; then monkey -p {0} -c android.intent.category.LEANBACK_LAUNCHER --pct-syskeys 0 1; fi", + ) + + # CMD_LAUNCH_APP_FIRETV + self.assertCommand( + constants.CMD_LAUNCH_APP_FIRETV, r"CURRENT_APP=$(dumpsys window windows | grep -E 'mCurrentFocus|mFocusedApp') && CURRENT_APP=${{CURRENT_APP#*ActivityRecord{{* * }} && CURRENT_APP=${{CURRENT_APP#*{{* * }} && CURRENT_APP=${{CURRENT_APP%%/*}} && CURRENT_APP=${{CURRENT_APP%\}}*}} && if [ $CURRENT_APP != '{0}' ]; then monkey -p {0} -c android.intent.category.LAUNCHER --pct-syskeys 0 1; fi", ) # CMD_LAUNCH_APP_GOOGLE_TV self.assertCommand( constants.CMD_LAUNCH_APP_GOOGLE_TV, - r"CURRENT_APP=$(dumpsys activity a . | grep mResumedActivity) && CURRENT_APP=${{CURRENT_APP#*ActivityRecord{{* * }} && CURRENT_APP=${{CURRENT_APP#*{{* * }} && CURRENT_APP=${{CURRENT_APP%%/*}} && CURRENT_APP=${{CURRENT_APP%\}}*}} && if [ $CURRENT_APP != '{0}' ]; then monkey -p {0} -c android.intent.category.LAUNCHER --pct-syskeys 0 1; fi", + r"CURRENT_APP=$(dumpsys activity a . | grep mResumedActivity) && CURRENT_APP=${{CURRENT_APP#*ActivityRecord{{* * }} && CURRENT_APP=${{CURRENT_APP#*{{* * }} && CURRENT_APP=${{CURRENT_APP%%/*}} && CURRENT_APP=${{CURRENT_APP%\}}*}} && if [ $CURRENT_APP != '{0}' ]; then monkey -p {0} -c android.intent.category.LEANBACK_LAUNCHER --pct-syskeys 0 1; fi", ) # CMD_MAC_ETH0 diff --git a/tests/test_firetv_async.py b/tests/test_firetv_async.py index 90fc000..b0aac7a 100644 --- a/tests/test_firetv_async.py +++ b/tests/test_firetv_async.py @@ -46,7 +46,7 @@ async def test_turn_on_off(self): async def test_send_intent(self): """Test that the ``_send_intent`` method works correctly.""" with async_patchers.patch_shell("output\r\nretcode")[self.PATCH_KEY]: - result = await self.ftv._send_intent("TEST", constants.INTENT_LAUNCH) + result = await self.ftv._send_intent("TEST", constants.INTENT_LAUNCH_FIRETV) self.assertEqual( getattr(self.ftv._adb, self.ADB_ATTR).shell_cmd, "monkey -p TEST -c android.intent.category.LAUNCHER 1; echo $?", @@ -54,7 +54,7 @@ async def test_send_intent(self): self.assertDictEqual(result, {"output": "output", "retcode": "retcode"}) with async_patchers.patch_connect(True)[self.PATCH_KEY], async_patchers.patch_shell(None)[self.PATCH_KEY]: - result = await self.ftv._send_intent("TEST", constants.INTENT_LAUNCH) + result = await self.ftv._send_intent("TEST", constants.INTENT_LAUNCH_FIRETV) self.assertEqual( getattr(self.ftv._adb, self.ADB_ATTR).shell_cmd, "monkey -p TEST -c android.intent.category.LAUNCHER 1; echo $?", @@ -66,7 +66,9 @@ async def test_launch_app_stop_app(self): """Test that the ``FireTVAsync.launch_app`` and ``FireTVAsync.stop_app`` methods work correctly.""" with async_patchers.patch_shell("")[self.PATCH_KEY]: await self.ftv.launch_app("TEST") - self.assertEqual(getattr(self.ftv._adb, self.ADB_ATTR).shell_cmd, constants.CMD_LAUNCH_APP.format("TEST")) + self.assertEqual( + getattr(self.ftv._adb, self.ADB_ATTR).shell_cmd, constants.CMD_LAUNCH_APP_FIRETV.format("TEST") + ) await self.ftv.stop_app("TEST") self.assertEqual(getattr(self.ftv._adb, self.ADB_ATTR).shell_cmd, "am force-stop TEST") diff --git a/tests/test_firetv_sync.py b/tests/test_firetv_sync.py index 7dc61c0..f5f9906 100644 --- a/tests/test_firetv_sync.py +++ b/tests/test_firetv_sync.py @@ -64,7 +64,7 @@ def test_turn_on_off(self): def test_send_intent(self): """Test that the ``_send_intent`` method works correctly.""" with patchers.patch_connect(True)[self.PATCH_KEY], patchers.patch_shell("output\r\nretcode")[self.PATCH_KEY]: - result = self.ftv._send_intent("TEST", constants.INTENT_LAUNCH) + result = self.ftv._send_intent("TEST", constants.INTENT_LAUNCH_FIRETV) self.assertEqual( getattr(self.ftv._adb, self.ADB_ATTR).shell_cmd, "monkey -p TEST -c android.intent.category.LAUNCHER 1; echo $?", @@ -72,7 +72,7 @@ def test_send_intent(self): self.assertDictEqual(result, {"output": "output", "retcode": "retcode"}) with patchers.patch_connect(True)[self.PATCH_KEY], patchers.patch_shell(None)[self.PATCH_KEY]: - result = self.ftv._send_intent("TEST", constants.INTENT_LAUNCH) + result = self.ftv._send_intent("TEST", constants.INTENT_LAUNCH_FIRETV) self.assertEqual( getattr(self.ftv._adb, self.ADB_ATTR).shell_cmd, "monkey -p TEST -c android.intent.category.LAUNCHER 1; echo $?", @@ -83,7 +83,9 @@ def test_launch_app_stop_app(self): """Test that the ``FireTVSync.launch_app`` and ``FireTVSync.stop_app`` methods work correctly.""" with patchers.patch_connect(True)[self.PATCH_KEY], patchers.patch_shell(None)[self.PATCH_KEY]: self.ftv.launch_app("TEST") - self.assertEqual(getattr(self.ftv._adb, self.ADB_ATTR).shell_cmd, constants.CMD_LAUNCH_APP.format("TEST")) + self.assertEqual( + getattr(self.ftv._adb, self.ADB_ATTR).shell_cmd, constants.CMD_LAUNCH_APP_FIRETV.format("TEST") + ) self.ftv.stop_app("TEST") self.assertEqual(getattr(self.ftv._adb, self.ADB_ATTR).shell_cmd, "am force-stop TEST")