You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
403 lines
13 KiB
403 lines
13 KiB
# 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()
|