blob: 22c29c6b40ee908441f8d2c2affafb43ffbedb89 [file] [log] [blame]
# Copyright 2016 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Resource manager to access the ARC-related functionality."""
import logging
import os
import pipes
import time
from autotest_lib.client.bin import utils
from autotest_lib.client.common_lib import error
from autotest_lib.client.common_lib.cros import arc
from autotest_lib.client.cros.multimedia import arc_resource_common
from autotest_lib.client.cros.input_playback import input_playback
def set_tag(tag):
"""Sets a tag file.
@param tag: Path to the tag file.
"""
open(tag, 'w').close()
def tag_exists(tag):
"""Checks if a tag exists.
@param tag: Path to the tag file.
"""
return os.path.exists(tag)
class ArcMicrophoneResourceException(Exception):
"""Exceptions in ArcResource."""
pass
class ArcMicrophoneResource(object):
"""Class to manage microphone app in container."""
_MICROPHONE_ACTIVITY = 'org.chromium.arc.testapp.microphone/.MainActivity'
_MICROPHONE_PACKAGE = 'org.chromium.arc.testapp.microphone'
_MICROPHONE_RECORD_PATH = '/storage/emulated/0/recorded.amr-nb'
_MICROPHONE_PERMISSIONS = ['RECORD_AUDIO', 'WRITE_EXTERNAL_STORAGE',
'READ_EXTERNAL_STORAGE']
def __init__(self):
"""Initializes a ArcMicrophoneResource."""
self._mic_app_start_time = None
def start_microphone_app(self):
"""Starts microphone app to start recording.
Starts microphone app. The app starts recorder itself after start up.
@raises: ArcMicrophoneResourceException if microphone app is not ready
yet.
"""
if not tag_exists(arc_resource_common.MicrophoneProps.READY_TAG_FILE):
raise ArcMicrophoneResourceException(
'Microphone app is not ready yet.')
if self._mic_app_start_time:
raise ArcMicrophoneResourceException(
'Microphone app is already started.')
# In case the permissions are cleared, set the permission again before
# each start of the app.
self._set_permission()
self._start_app()
self._mic_app_start_time = time.time()
def stop_microphone_app(self, dest_path):
"""Stops microphone app and gets recorded audio file from container.
Stops microphone app.
Copies the recorded file from container to Cros device.
Deletes the recorded file in container.
@param dest_path: Destination path of the recorded file on Cros device.
@raises: ArcMicrophoneResourceException if microphone app is not started
yet or is still recording.
"""
if not self._mic_app_start_time:
raise ArcMicrophoneResourceException(
'Recording is not started yet')
if self._is_recording():
raise ArcMicrophoneResourceException('Still recording')
self._stop_app()
self._get_file(dest_path)
self._delete_file()
self._mic_app_start_time = None
def _is_recording(self):
"""Checks if microphone app is recording audio.
We use the time stamp of app start up time to determine if app is still
recording audio.
@returns: True if microphone app is recording, False otherwise.
"""
if not self._mic_app_start_time:
return False
return (time.time() - self._mic_app_start_time <
(arc_resource_common.MicrophoneProps.RECORD_SECS +
arc_resource_common.MicrophoneProps.RECORD_FUZZ_SECS))
def _set_permission(self):
"""Grants permissions to microphone app."""
for permission in self._MICROPHONE_PERMISSIONS:
arc.adb_shell('pm grant %s android.permission.%s' % (
pipes.quote(self._MICROPHONE_PACKAGE),
pipes.quote(permission)))
def _start_app(self):
"""Starts microphone app."""
arc.adb_shell('am start -W %s' % pipes.quote(self._MICROPHONE_ACTIVITY))
def _stop_app(self):
"""Stops microphone app.
Stops the microphone app process.
"""
arc.adb_shell(
'am force-stop %s' % pipes.quote(self._MICROPHONE_PACKAGE))
def _get_file(self, dest_path):
"""Gets recorded audio file from container.
Copies the recorded file from container to Cros device.
@dest_path: Destination path of the recorded file on Cros device.
"""
arc.adb_cmd('pull %s %s' % (pipes.quote(self._MICROPHONE_RECORD_PATH),
pipes.quote(dest_path)))
def _delete_file(self):
"""Removes the recorded file in container."""
arc.adb_shell('rm %s' % pipes.quote(self._MICROPHONE_RECORD_PATH))
class ArcPlayMusicResourceException(Exception):
"""Exceptions in ArcPlayMusicResource."""
pass
class ArcPlayMusicResource(object):
"""Class to manage Play Music app in container."""
_PLAYMUSIC_PACKAGE = 'com.google.android.music'
_PLAYMUSIC_FILE_FOLDER = '/storage/emulated/0/'
_PLAYMUSIC_PERMISSIONS = ['WRITE_EXTERNAL_STORAGE', 'READ_EXTERNAL_STORAGE']
_PLAYMUSIC_ACTIVITY = '.AudioPreview'
_KEYCODE_MEDIA_STOP = 86
def __init__(self):
"""Initializes an ArcPlayMusicResource."""
self._files_pushed = []
def set_playback_file(self, file_path):
"""Copies file into container.
@param file_path: Path to the file to play on Cros host.
@returns: Path to the file in container.
"""
file_name = os.path.basename(file_path)
dest_path = os.path.join(self._PLAYMUSIC_FILE_FOLDER, file_name)
# pipes.quote is deprecated in 2.7 (but still available).
# It should be replaced by shlex.quote in python 3.3.
arc.adb_cmd('push %s %s' % (pipes.quote(file_path),
pipes.quote(dest_path)))
self._files_pushed.append(dest_path)
return dest_path
def start_playback(self, dest_path):
"""Starts Play Music app to play an audio file.
@param dest_path: The file path in container.
@raises ArcPlayMusicResourceException: Play Music app is not ready or
playback file is not set yet.
"""
if not tag_exists(arc_resource_common.PlayMusicProps.READY_TAG_FILE):
raise ArcPlayMusicResourceException(
'Play Music app is not ready yet.')
if dest_path not in self._files_pushed:
raise ArcPlayMusicResourceException(
'Playback file is not set yet')
# In case the permissions are cleared, set the permission again before
# each start of the app.
self._set_permission()
self._start_app(dest_path)
def _set_permission(self):
"""Grants permissions to Play Music app."""
for permission in self._PLAYMUSIC_PERMISSIONS:
arc.adb_shell('pm grant %s android.permission.%s' % (
pipes.quote(self._PLAYMUSIC_PACKAGE),
pipes.quote(permission)))
def _start_app(self, dest_path):
"""Starts Play Music app playing an audio file.
@param dest_path: Path to the file to play in container.
"""
ext = os.path.splitext(dest_path)[1]
command = ('am start -a android.intent.action.VIEW'
' -d "file://%s" -t "audio/%s"'
' -n "%s/%s"'% (
pipes.quote(dest_path), pipes.quote(ext),
pipes.quote(self._PLAYMUSIC_PACKAGE),
pipes.quote(self._PLAYMUSIC_ACTIVITY)))
logging.debug(command)
arc.adb_shell(command)
def stop_playback(self):
"""Stops Play Music app.
Stops the Play Music app by media key event.
"""
arc.send_keycode(self._KEYCODE_MEDIA_STOP)
def cleanup(self):
"""Removes the files to play in container."""
for path in self._files_pushed:
arc.adb_shell('rm %s' % pipes.quote(path))
self._files_pushed = []
class ArcPlayVideoResourceException(Exception):
"""Exceptions in ArcPlayVideoResource."""
pass
class ArcPlayVideoResource(object):
"""Class to manage Play Video app in container."""
_PLAYVIDEO_PACKAGE = 'org.chromium.arc.testapp.video'
_PLAYVIDEO_ACTIVITY = 'org.chromium.arc.testapp.video/.MainActivity'
_PLAYVIDEO_EXIT_TAG = "/mnt/sdcard/ArcVideoTest.tag"
_PLAYVIDEO_FILE_FOLDER = '/storage/emulated/0/'
_PLAYVIDEO_PERMISSIONS = ['WRITE_EXTERNAL_STORAGE', 'READ_EXTERNAL_STORAGE']
_KEYCODE_MEDIA_PLAY = 126
_KEYCODE_MEDIA_PAUSE = 127
_KEYCODE_MEDIA_STOP = 86
def __init__(self):
"""Initializes an ArcPlayVideoResource."""
self._files_pushed = []
def prepare_playback(self, file_path, fullscreen=True):
"""Copies file into the container and starts the video player app.
@param file_path: Path to the file to play on Cros host.
@param fullscreen: Plays the video in fullscreen.
"""
if not tag_exists(arc_resource_common.PlayVideoProps.READY_TAG_FILE):
raise ArcPlayVideoResourceException(
'Play Video app is not ready yet.')
file_name = os.path.basename(file_path)
dest_path = os.path.join(self._PLAYVIDEO_FILE_FOLDER, file_name)
# pipes.quote is deprecated in 2.7 (but still available).
# It should be replaced by shlex.quote in python 3.3.
arc.adb_cmd('push %s %s' % (pipes.quote(file_path),
pipes.quote(dest_path)))
# In case the permissions are cleared, set the permission again before
# each start of the app.
self._set_permission()
self._start_app(dest_path)
if fullscreen:
self.set_fullscreen()
def set_fullscreen(self):
"""Sends F4 keyevent to set fullscreen."""
with input_playback.InputPlayback() as input_player:
input_player.emulate(input_type='keyboard')
input_player.find_connected_inputs()
input_player.blocking_playback_of_default_file(
input_type='keyboard', filename='keyboard_f4')
def start_playback(self, blocking_secs=None):
"""Starts Play Video app to play a video file.
@param blocking_secs: A positive number indicates the timeout to wait
for the playback is finished. Set None to make
it non-blocking.
@raises ArcPlayVideoResourceException: Play Video app is not ready or
playback file is not set yet.
"""
arc.send_keycode(self._KEYCODE_MEDIA_PLAY)
if blocking_secs:
tag = lambda : arc.check_android_file_exists(
self._PLAYVIDEO_EXIT_TAG)
exception = error.TestFail('video playback timeout')
utils.poll_for_condition(tag, exception, blocking_secs)
def _set_permission(self):
"""Grants permissions to Play Video app."""
arc.grant_permissions(
self._PLAYVIDEO_PACKAGE, self._PLAYVIDEO_PERMISSIONS)
def _start_app(self, dest_path):
"""Starts Play Video app playing a video file.
@param dest_path: Path to the file to play in container.
"""
arc.adb_shell('am start --activity-clear-top '
'--es PATH {} {}'.format(
pipes.quote(dest_path), self._PLAYVIDEO_ACTIVITY))
def pause_playback(self):
"""Pauses Play Video app.
Pauses the Play Video app by media key event.
"""
arc.send_keycode(self._KEYCODE_MEDIA_PAUSE)
def stop_playback(self):
"""Stops Play Video app.
Stops the Play Video app by media key event.
"""
arc.send_keycode(self._KEYCODE_MEDIA_STOP)
def cleanup(self):
"""Removes the files to play in container."""
for path in self._files_pushed:
arc.adb_shell('rm %s' % pipes.quote(path))
self._files_pushed = []
class ArcResource(object):
"""Class to manage multimedia resource in container.
@properties:
microphone: The instance of ArcMicrophoneResource for microphone app.
play_music: The instance of ArcPlayMusicResource for music app.
play_video: The instance of ArcPlayVideoResource for video app.
"""
def __init__(self):
self.microphone = ArcMicrophoneResource()
self.play_music = ArcPlayMusicResource()
self.play_video = ArcPlayVideoResource()
def cleanup(self):
"""Clean up the resources."""
self.play_music.cleanup()
self.play_video.cleanup()