mirror of
https://github.com/home-assistant/core.git
synced 2025-07-21 12:17:07 +00:00
Use friendly app names for Fire TV sources (#28417)
* Use friendly app names for Fire TV sources * Remove debugging statement * Tests pass * Use 'blocking=True' to patch service calls * Remove parentheses
This commit is contained in:
parent
1012215709
commit
a71d852f16
@ -287,8 +287,11 @@ class ADBDevice(MediaPlayerDevice):
|
|||||||
"""Initialize the Android TV / Fire TV device."""
|
"""Initialize the Android TV / Fire TV device."""
|
||||||
self.aftv = aftv
|
self.aftv = aftv
|
||||||
self._name = name
|
self._name = name
|
||||||
self._apps = APPS.copy()
|
self._app_id_to_name = APPS.copy()
|
||||||
self._apps.update(apps)
|
self._app_id_to_name.update(apps)
|
||||||
|
self._app_name_to_id = {
|
||||||
|
value: key for key, value in self._app_id_to_name.items()
|
||||||
|
}
|
||||||
self._keys = KEYS
|
self._keys = KEYS
|
||||||
|
|
||||||
self._device_properties = self.aftv.device_properties
|
self._device_properties = self.aftv.device_properties
|
||||||
@ -328,7 +331,7 @@ class ADBDevice(MediaPlayerDevice):
|
|||||||
@property
|
@property
|
||||||
def app_name(self):
|
def app_name(self):
|
||||||
"""Return the friendly name of the current app."""
|
"""Return the friendly name of the current app."""
|
||||||
return self._apps.get(self._current_app, self._current_app)
|
return self._app_id_to_name.get(self._current_app, self._current_app)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def available(self):
|
def available(self):
|
||||||
@ -518,7 +521,7 @@ class FireTVDevice(ADBDevice):
|
|||||||
super().__init__(aftv, name, apps, turn_on_command, turn_off_command)
|
super().__init__(aftv, name, apps, turn_on_command, turn_off_command)
|
||||||
|
|
||||||
self._get_sources = get_sources
|
self._get_sources = get_sources
|
||||||
self._running_apps = None
|
self._sources = None
|
||||||
|
|
||||||
@adb_decorator(override_available=True)
|
@adb_decorator(override_available=True)
|
||||||
def update(self):
|
def update(self):
|
||||||
@ -538,23 +541,28 @@ class FireTVDevice(ADBDevice):
|
|||||||
return
|
return
|
||||||
|
|
||||||
# Get the `state`, `current_app`, and `running_apps`.
|
# Get the `state`, `current_app`, and `running_apps`.
|
||||||
state, self._current_app, self._running_apps = self.aftv.update(
|
state, self._current_app, running_apps = self.aftv.update(self._get_sources)
|
||||||
self._get_sources
|
|
||||||
)
|
|
||||||
|
|
||||||
self._state = ANDROIDTV_STATES.get(state)
|
self._state = ANDROIDTV_STATES.get(state)
|
||||||
if self._state is None:
|
if self._state is None:
|
||||||
self._available = False
|
self._available = False
|
||||||
|
|
||||||
|
if running_apps:
|
||||||
|
self._sources = [
|
||||||
|
self._app_id_to_name.get(app_id, app_id) for app_id in running_apps
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
self._sources = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def source(self):
|
def source(self):
|
||||||
"""Return the current app."""
|
"""Return the current app."""
|
||||||
return self._current_app
|
return self._app_id_to_name.get(self._current_app, self._current_app)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def source_list(self):
|
def source_list(self):
|
||||||
"""Return a list of running apps."""
|
"""Return a list of running apps."""
|
||||||
return self._running_apps
|
return self._sources
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def supported_features(self):
|
def supported_features(self):
|
||||||
@ -575,6 +583,7 @@ class FireTVDevice(ADBDevice):
|
|||||||
"""
|
"""
|
||||||
if isinstance(source, str):
|
if isinstance(source, str):
|
||||||
if not source.startswith("!"):
|
if not source.startswith("!"):
|
||||||
self.aftv.launch_app(source)
|
self.aftv.launch_app(self._app_name_to_id.get(source, source))
|
||||||
else:
|
else:
|
||||||
self.aftv.stop_app(source[1:].lstrip())
|
source_ = source[1:].lstrip()
|
||||||
|
self.aftv.stop_app(self._app_name_to_id.get(source_, source_))
|
||||||
|
@ -140,3 +140,15 @@ def isfile(filepath):
|
|||||||
|
|
||||||
PATCH_ISFILE = patch("os.path.isfile", isfile)
|
PATCH_ISFILE = patch("os.path.isfile", isfile)
|
||||||
PATCH_ACCESS = patch("os.access", return_value=True)
|
PATCH_ACCESS = patch("os.access", return_value=True)
|
||||||
|
|
||||||
|
|
||||||
|
def patch_firetv_update(state, current_app, running_apps):
|
||||||
|
"""Patch the `FireTV.update()` method."""
|
||||||
|
return patch(
|
||||||
|
"androidtv.firetv.FireTV.update",
|
||||||
|
return_value=(state, current_app, running_apps),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
PATCH_LAUNCH_APP = patch("androidtv.firetv.FireTV.launch_app")
|
||||||
|
PATCH_STOP_APP = patch("androidtv.firetv.FireTV.stop_app")
|
||||||
|
@ -6,15 +6,22 @@ from homeassistant.components.androidtv.media_player import (
|
|||||||
ANDROIDTV_DOMAIN,
|
ANDROIDTV_DOMAIN,
|
||||||
CONF_ADB_SERVER_IP,
|
CONF_ADB_SERVER_IP,
|
||||||
CONF_ADBKEY,
|
CONF_ADBKEY,
|
||||||
|
CONF_APPS,
|
||||||
|
)
|
||||||
|
from homeassistant.components.media_player.const import (
|
||||||
|
ATTR_INPUT_SOURCE,
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_SELECT_SOURCE,
|
||||||
)
|
)
|
||||||
from homeassistant.components.media_player.const import DOMAIN
|
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
|
ATTR_ENTITY_ID,
|
||||||
CONF_DEVICE_CLASS,
|
CONF_DEVICE_CLASS,
|
||||||
CONF_HOST,
|
CONF_HOST,
|
||||||
CONF_NAME,
|
CONF_NAME,
|
||||||
CONF_PLATFORM,
|
CONF_PLATFORM,
|
||||||
STATE_IDLE,
|
STATE_IDLE,
|
||||||
STATE_OFF,
|
STATE_OFF,
|
||||||
|
STATE_PLAYING,
|
||||||
STATE_UNAVAILABLE,
|
STATE_UNAVAILABLE,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -276,3 +283,108 @@ async def test_setup_with_adbkey(hass):
|
|||||||
state = hass.states.get(entity_id)
|
state = hass.states.get(entity_id)
|
||||||
assert state is not None
|
assert state is not None
|
||||||
assert state.state == STATE_OFF
|
assert state.state == STATE_OFF
|
||||||
|
|
||||||
|
|
||||||
|
async def test_firetv_sources(hass):
|
||||||
|
"""Test that sources (i.e., apps) are handled correctly for Fire TV devices."""
|
||||||
|
config = CONFIG_FIRETV_ADB_SERVER.copy()
|
||||||
|
config[DOMAIN][CONF_APPS] = {"com.app.test1": "TEST 1"}
|
||||||
|
patch_key, entity_id = _setup(hass, config)
|
||||||
|
|
||||||
|
with patchers.PATCH_ADB_DEVICE, patchers.patch_connect(True)[
|
||||||
|
patch_key
|
||||||
|
], patchers.patch_shell("")[patch_key]:
|
||||||
|
assert await async_setup_component(hass, DOMAIN, config)
|
||||||
|
await hass.helpers.entity_component.async_update_entity(entity_id)
|
||||||
|
state = hass.states.get(entity_id)
|
||||||
|
assert state is not None
|
||||||
|
assert state.state == STATE_OFF
|
||||||
|
|
||||||
|
with patchers.patch_firetv_update(
|
||||||
|
"playing", "com.app.test1", ["com.app.test1", "com.app.test2"]
|
||||||
|
):
|
||||||
|
await hass.helpers.entity_component.async_update_entity(entity_id)
|
||||||
|
state = hass.states.get(entity_id)
|
||||||
|
assert state is not None
|
||||||
|
assert state.state == STATE_PLAYING
|
||||||
|
assert state.attributes["source"] == "TEST 1"
|
||||||
|
assert state.attributes["source_list"] == ["TEST 1", "com.app.test2"]
|
||||||
|
|
||||||
|
with patchers.patch_firetv_update(
|
||||||
|
"playing", "com.app.test2", ["com.app.test2", "com.app.test1"]
|
||||||
|
):
|
||||||
|
await hass.helpers.entity_component.async_update_entity(entity_id)
|
||||||
|
state = hass.states.get(entity_id)
|
||||||
|
assert state is not None
|
||||||
|
assert state.state == STATE_PLAYING
|
||||||
|
assert state.attributes["source"] == "com.app.test2"
|
||||||
|
assert state.attributes["source_list"] == ["com.app.test2", "TEST 1"]
|
||||||
|
|
||||||
|
|
||||||
|
async def _test_firetv_select_source(hass, source, expected_arg, method_patch):
|
||||||
|
"""Test that the `FireTV.launch_app` and `FireTV.stop_app` methods are called with the right parameter."""
|
||||||
|
config = CONFIG_FIRETV_ADB_SERVER.copy()
|
||||||
|
config[DOMAIN][CONF_APPS] = {"com.app.test1": "TEST 1"}
|
||||||
|
patch_key, entity_id = _setup(hass, config)
|
||||||
|
|
||||||
|
with patchers.PATCH_ADB_DEVICE, patchers.patch_connect(True)[
|
||||||
|
patch_key
|
||||||
|
], patchers.patch_shell("")[patch_key]:
|
||||||
|
assert await async_setup_component(hass, DOMAIN, config)
|
||||||
|
await hass.helpers.entity_component.async_update_entity(entity_id)
|
||||||
|
state = hass.states.get(entity_id)
|
||||||
|
assert state is not None
|
||||||
|
assert state.state == STATE_OFF
|
||||||
|
|
||||||
|
with method_patch as method_patch_:
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_SELECT_SOURCE,
|
||||||
|
{ATTR_ENTITY_ID: entity_id, ATTR_INPUT_SOURCE: source},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
method_patch_.assert_called_with(expected_arg)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
async def test_firetv_select_source_launch_app_id(hass):
|
||||||
|
"""Test that an app can be launched using its app ID."""
|
||||||
|
assert await _test_firetv_select_source(
|
||||||
|
hass, "com.app.test1", "com.app.test1", patchers.PATCH_LAUNCH_APP
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_firetv_select_source_launch_app_name(hass):
|
||||||
|
"""Test that an app can be launched using its friendly name."""
|
||||||
|
assert await _test_firetv_select_source(
|
||||||
|
hass, "TEST 1", "com.app.test1", patchers.PATCH_LAUNCH_APP
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_firetv_select_source_launch_app_id_no_name(hass):
|
||||||
|
"""Test that an app can be launched using its app ID when it has no friendly name."""
|
||||||
|
assert await _test_firetv_select_source(
|
||||||
|
hass, "com.app.test2", "com.app.test2", patchers.PATCH_LAUNCH_APP
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_firetv_select_source_stop_app_id(hass):
|
||||||
|
"""Test that an app can be stopped using its app ID."""
|
||||||
|
assert await _test_firetv_select_source(
|
||||||
|
hass, "!com.app.test1", "com.app.test1", patchers.PATCH_STOP_APP
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_firetv_select_source_stop_app_name(hass):
|
||||||
|
"""Test that an app can be stopped using its friendly name."""
|
||||||
|
assert await _test_firetv_select_source(
|
||||||
|
hass, "!TEST 1", "com.app.test1", patchers.PATCH_STOP_APP
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_firetv_select_source_stop_app_id_no_name(hass):
|
||||||
|
"""Test that an app can be stopped using its app ID when it has no friendly name."""
|
||||||
|
assert await _test_firetv_select_source(
|
||||||
|
hass, "!com.app.test2", "com.app.test2", patchers.PATCH_STOP_APP
|
||||||
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user