Android-ElectricSheep-Automator

 view release on metacpan or  search on metacpan

lib/Android/ElectricSheep/Automator.pm  view on Meta::CPAN

# or
#  use param 'device-object' => <device object>
#        (of type Android::ElectricSheep::Automator::ADB::Device)
# or after instantiation with $obj->connect_device(...);
# and similarly for disconnect_device()
# NOTE: without connecting to a device you can not use e.g. open_app(), swipe() etc.
sub new {
	my $class = ref($_[0]) || $_[0]; # aka proto
	my $params = $_[1] // {};

        my $parent = ( caller(1) )[3] || "N/A";
        my $whoami = ( caller(0) )[3];

	my $self = {
		'_private' => {
			'confighash' => undef,
			'configfile' => '', # this should never be undef
			'Android::ADB' => undef,
			'debug' => {
				'verbosity' => 0,
				'cleanup' => 1,
			},

lib/Android/ElectricSheep/Automator.pm  view on Meta::CPAN

#     as returned by any item of $self->adb->devices()
# However, if there is ONLY ONE device connected to the desktop, then
# you do not need to specify a device, use this method without arguments
#
# It returns the device object (Android::ADB::Device) on success
# or undef on failure
sub connect_device {
	my ($self, $params) = @_;
	$params //= {};

	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];

	my $log = $self->log();
	my $verbosity = $self->verbosity;

	my ($what_device, $m);

	if( exists($params->{'serial'}) && defined($m=$params->{'serial'}) ){
		my $devs = $self->devices();
		
		for (@$devs){

lib/Android/ElectricSheep/Automator.pm  view on Meta::CPAN

# optionally saving it to the specified file
# It returns undef on failure.
# On success, it returns a hash with 2 keys:
#   'raw' : contains the raw XML content (as a string)
#   'XML::LibXML' : contains an XML::LibXML object with the parsed
#                  XML string, ready to do XPath queries
# it needs that connect_device() to have been called prior to this call
sub dump_current_screen_ui {
	my ($self, $params) = @_;

	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];

	my $log = $self->log();
	my $verbosity = $self->verbosity;

	if( ! $self->is_device_connected() ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, you need to connect a device to the desktop and ALSO explicitly call ".'device_connected()'." before calling this."); return undef }

	my $filename = exists($params->{'filename'}) && defined($params->{'filename'}) ? $params->{'filename'} : undef;

	my $FH;
	if( ! defined $filename ){

lib/Android/ElectricSheep/Automator.pm  view on Meta::CPAN

# It swipes the screen as per the 'direction'
# or full spec (x1,y1,x2,y2) (e.g. from x1 to x2 etc.)
# optional parameter 'dt' is the milliseconds to take for the swipe
# small is fast. Some speed is needed for certain gestures, so
# this is important parameter. E.g. for swiping to another screen.
# it needs that connect_device() to have been called prior to this call
sub swipe {
	my ($self, $params) = @_;
	$params //= {};

	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];
	my $log = $self->log();
	my $verbosity = $self->verbosity();

	if( ! $self->is_device_connected() ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, you need to connect a device to the desktop and ALSO explicitly call ".'connect_device()'." before calling this."); return 1 }

	my $w = $self->device_properties->get('w');
	my $h = $self->device_properties->get('h');

	my @fullspec;
	for ('x1', 'y1', 'x2', 'y2', 'dt'){

lib/Android/ElectricSheep/Automator.pm  view on Meta::CPAN

#  WARNING: the 2nd step if called for all the installed apps can take some
#           time as it is done for each installed app.
#           Perhaps a better approach is to lazily find apps by
#           specifying the name of the app with the input parameter
#             'packages' => [...]
#           This will append to apps() the result.
sub find_installed_apps {
	my ($self, $params) = @_;
	$params //= {};

	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];
	my $log = $self->log();
	my $verbosity = $self->verbosity();

	if( ! $self->is_device_connected() ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, you need to connect a device to the desktop and ALSO explicitly call ".'connect_device()'." before calling this."); return undef }

	# optionally caller can specify a list of app names to enquire
	# either as exact package name (string), a Regexp object (qr//)
	# an ARRAY of package names or a HASH of package names:
	my $packages = exists($params->{'packages'}) && defined($params->{'packages'}) ? $params->{'packages'} : undef;
	my $rr = ref $packages;

lib/Android/ElectricSheep/Automator.pm  view on Meta::CPAN

# It returns the found packages (full package name (which is a key in $self->{'apps'}))
# as a HASHref if any found, or {} if none found.
# the key to the returned hash is the full package name and the value
# will be AppProperties object or undef if not instantiated for that app
# because of lazy=1
# It returns undef on failure.
sub search_app {
	my ($self, $params) = @_;
	$params //= {};

	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];
	my $log = $self->log();
	my $verbosity = $self->verbosity();

	my $package;
	if( ! exists($params->{'package'}) || ! defined($package=$params->{'package'}) ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, input parameter 'package' was not specified, it must be a package name or a compiled regex (e.g. via "...
	if( (ref($package)ne'') && (ref($package)ne'Regexp') ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, the type of input parameter 'package' must be a scalar string (the package name) or a Regexp object (compiled regex via ".'qr//'...

	my $force_reload = (exists($params->{'force-reload-apps-list'}) && defined($params->{'force-reload-apps-list'})) ? $params->{'force-reload-apps-list'} : 0;
	my $lazy = (exists($params->{'lazy'}) && defined($params->{'lazy'})) ? $params->{'lazy'} : 1;

lib/Android/ElectricSheep/Automator.pm  view on Meta::CPAN

#     THIS APPLIES ONLY TO THE MATCHED 'package'
# On success it returns a hash of {appname => appproperties} of the opened app
#    (which will be created if not existing). It may return {} if no match
#    was found for the specified 'package' name.
# On failure it returns undef
# it needs that connect_device() to have been called prior to this call
sub open_app {
	my ($self, $params) = @_;
	$params //= {};

	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];
	my $log = $self->log();
	my $verbosity = $self->verbosity();

	if( ! $self->is_device_connected() ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, you need to connect a device to the desktop and ALSO explicitly call ".'connect_device()'." before calling this."); return undef }

	my ($package);
	if( ! exists($params->{'package'}) || ! defined($package=$params->{'package'}) ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, input parameter 'package' is required."); return undef }
	if( (ref($package)ne'') && (ref($package)ne'Regexp') ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, the type of input parameter 'package' must be a scalar string (the package name) or a Regexp object (compiled regex via ".'qr//'...

	# optional activity, else we will see if we find one

lib/Android/ElectricSheep/Automator.pm  view on Meta::CPAN

#     Default is force-reload-apps-list=>0
#     THIS APPLIES ONLY TO THE MATCHED 'package'
# On success it returns the a hash of {appname => appproperties} of the closed app
#    (which will be created if not existing). It may return {} if no match.
# On failure it returns undef
# it needs that connect_device() to have been called prior to this call
sub close_app {
	my ($self, $params) = @_;
	$params //= {};

	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];
	my $log = $self->log();
	my $verbosity = $self->verbosity();

	if( ! $self->is_device_connected() ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, you need to connect a device to the desktop and ALSO explicitly call ".'connect_device()'." before calling this."); return undef }

	my ($package);
	if( ! exists($params->{'package'}) || ! defined($package=$params->{'package'}) ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, input parameter 'package' is required."); return undef }
	if( (ref($package)ne'') && (ref($package)ne'Regexp') ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, the type of input parameter 'package' must be a scalar string (the package name) or a Regexp object (compiled regex via ".'qr//'...

	# optional activity, else we will see if we find one

lib/Android/ElectricSheep/Automator.pm  view on Meta::CPAN

# or
# 'bounds' => [ [topleftX,topleftY], [bottomrightX, bottomrightY] ]
# in which case, the tap position will be the mid-point of the 'bounds'
# rectangle.
# It returns 1 on failure, 0 on success
# it needs that connect_device() to have been called prior to this call
sub tap {
	my ($self, $params) = @_;
	$params //= {};

	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];
	my $log = $self->log();
	my $verbosity = $self->verbosity();

	if( ! $self->is_device_connected() ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, you need to connect a device to the desktop and ALSO explicitly call ".'connect_device()'." before calling this."); return undef }

	my (@position, $m);
	if( exists($params->{'position'}) && defined($m=$params->{'position'}) ){ 
		@position = ($m->[0], $m->[1]);
	} elsif( exists($params->{'bounds'}) && defined($m=$params->{'bounds'}) ){
		@position = ( int(($m->[1]->[0] + $m->[0]->[0])/2), int(($m->[1]->[1] + $m->[0]->[1])/2) );

lib/Android/ElectricSheep/Automator.pm  view on Meta::CPAN


	return 0; # success
}

# returns 1 on failure, 0 on success
# it needs that connect_device() to have been called prior to this call
sub input_text {
	my ($self, $params) = @_;
	$params //= {};

	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];
	my $log = $self->log();
	my $verbosity = $self->verbosity();

	if( ! $self->is_device_connected() ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, you need to connect a device to the desktop and ALSO explicitly call ".'connect_device()'." before calling this."); return undef }

	my (@position, $m);
	if( exists($params->{'position'}) && defined($m=$params->{'position'}) ){ 
		@position = ($m->[0], $m->[1]);
	} elsif( exists($params->{'bounds'}) && defined($m=$params->{'bounds'}) ){
		@position = ( int(($m->[1]->[0] + $m->[0]->[0])/2), int(($m->[1]->[1] + $m->[0]->[1])/2) );

lib/Android/ElectricSheep/Automator.pm  view on Meta::CPAN


	return 0; # success
}

# returns 1 on failure, 0 on success
# it needs that connect_device() to have been called prior to this call
sub clear_input_field {
	my ($self, $params) = @_;
	$params //= {};

	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];
	my $log = $self->log();
	my $verbosity = $self->verbosity();

	if( ! $self->is_device_connected() ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, you need to connect a device to the desktop and ALSO explicitly call ".'connect_device()'." before calling this."); return undef }

	my (@position, $m);
	if( exists($params->{'position'}) && defined($m=$params->{'position'}) ){ 
		@position = ($m->[0], $m->[1]);
	} elsif( exists($params->{'bounds'}) && defined($m=$params->{'bounds'}) ){
		@position = ( int(($m->[1]->[0] + $m->[0]->[0])/2), int(($m->[1]->[1] + $m->[0]->[1])/2) );

lib/Android/ElectricSheep/Automator.pm  view on Meta::CPAN

#           each process
#           is represented by a hashref of items, e.g. %CPU
#           (basically all the items from the header of the `ps` command)
#           keyed on the full process command and its arguments (verbatim from `ps` output).
#   'json': the above perl data structure converted to JSON.
# NOTE: it uses _ps_parse_output() which is copied verbatim from System::Process
#       I wish they would load ps info from a string rather than running their own `ps`
sub list_running_processes {
	my ($self, $params) = @_;

	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];

	my $log = $self->log();
	my $verbosity = $self->verbosity;

	if( ! $self->is_device_connected() ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, you need to connect a device to the desktop and ALSO explicitly call ".'device_connected()'." before calling this."); return undef }

	my $filename = exists($params->{'filename'}) && defined($params->{'filename'}) ? $params->{'filename'} : undef;
	my $extrafields = exists($params->{'extra-fields'}) && defined($params->{'extra-fields'}) ? $params->{'extra-fields'} : [];

	my ($FH, $tmpfilename) = tempfile(CLEANUP=>$self->cleanup);

lib/Android/ElectricSheep/Automator.pm  view on Meta::CPAN

}

# ONLY FOR EMULATORS, it fixes the Geolocation to the
# specified coordinates (with 'latitude' and 'longitude').
# returns 1 on failure, 0 on success
# it needs that connect_device() to have been called prior to this call
sub geofix {
	my ($self, $params) = @_;
	$params //= {};

	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];
	my $log = $self->log();
	my $verbosity = $self->verbosity();

	if( ! $self->is_device_connected() ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, you need to connect a device to the desktop and ALSO explicitly call ".'connect_device()'." before calling this."); return undef }

	for ('latitude', 'longitude'){
		if( ! exists $params->{$_} ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, input parameter '$_' was not specified (as [x,y])."); return 1 }
	}

	my @cmd = ('emu', 'geo', 'fix', $params->{'longitude'}, $params->{'latitude'});

lib/Android/ElectricSheep/Automator.pm  view on Meta::CPAN

# the provider provided including lat/lon
# It returns undef undef on failure or the above hash on success.
# NOTE: some providers may exist but have the Location[...] string as null
# meaning not available (e.g. 'network provider' when no internet exists)
# in this case lat,lon etc. will be '<na>' and the strings will be 'null'.
# it needs that connect_device() to have been called prior to this call
sub dump_current_location {
	my ($self, $params) = @_;
	$params //= {};

	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];
	my $log = $self->log();
	my $verbosity = $self->verbosity();

	if( ! $self->is_device_connected() ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, you need to connect a device to the desktop and ALSO explicitly call ".'connect_device()'." before calling this."); return undef }

	my @cmd = ('dumpsys', 'location');
	if( $verbosity > 0 ){ $log->info("${whoami} (via $parent), line ".__LINE__." : sending command to adb: @cmd") }
	my $res = $self->adb->shell(@cmd);
	if( ! defined $res ){ $log->error(join(" ", @cmd)."\n${whoami} (via $parent), line ".__LINE__." : error, above shell command has failed, got undefined result, most likely shell command did not run at all, this should not be happening."); return 1 }
	if( $res->[0] != 0 ){ $log->error(join(" ", @cmd)."\n${whoami} (via $parent), line ".__LINE__." : error, above shell command has failed, with:\nSTDOUT:\n".$res->[1]."\n\nSTDERR:\n".$res->[2]."\nEND."); return 1 }

lib/Android/ElectricSheep/Automator.pm  view on Meta::CPAN

}

# It lists the IDs of all the physical displays connected to the
# device, including the main one and returns these back as a HASH
# keyed on display ID.
# it needs that connect_device() to have been called prior to this call
sub list_physical_displays {
	my ($self, $params) = @_;
	$params //= {};

	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];
	my $log = $self->log();
	my $verbosity = $self->verbosity();

	if( ! $self->is_device_connected() ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, you need to connect a device to the desktop and ALSO explicitly call ".'connect_device()'." before calling this."); return undef }

	my @cmd = ('dumpsys', 'SurfaceFlinger', '--display-id');
	if( $verbosity > 0 ){ $log->info("${whoami} (via $parent), line ".__LINE__." : sending command to adb: @cmd") }
	my $res = $self->adb->shell(@cmd);
	if( ! defined $res ){ $log->error(join(" ", @cmd)."\n${whoami} (via $parent), line ".__LINE__." : error, above shell command has failed, got undefined result, most likely shell command did not run at all, this should not be happening."); return 1 }
	if( $res->[0] != 0 ){ $log->error(join(" ", @cmd)."\n${whoami} (via $parent), line ".__LINE__." : error, above shell command has failed, with:\nSTDOUT:\n".$res->[1]."\n\nSTDERR:\n".$res->[2]."\nEND."); return 1 }

lib/Android/ElectricSheep/Automator.pm  view on Meta::CPAN


# It takes a screendump of current screen on device and returns it as
# a Image::PNG object, optionally saving it to the specified file.
# it needs that connect_device() to have been called prior to this call
# It returns undef on failure or the screenshot as an Image::PNG object
# on success.
# it needs that connect_device() to have been called prior to this call
sub dump_current_screen_shot {
	my ($self, $params) = @_;

	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];

	my $log = $self->log();
	my $verbosity = $self->verbosity;

	if( ! $self->is_device_connected() ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, you need to connect a device to the desktop and ALSO explicitly call ".'device_connected()'." before calling this."); return undef }

	my $filename = exists($params->{'filename'}) && defined($params->{'filename'}) ? $params->{'filename'} : undef;

	my $FH;
	if( ! defined $filename ){

lib/Android/ElectricSheep/Automator.pm  view on Meta::CPAN

# Optionally specify 'bit-rate'.
# Optionally specify %size = ('width' => ..., 'height' => ...)
# Optionally specify if $bugreport==1, then Android will overlay debug info on movie.
# Optionally specify 'display-id'.
# Output format of recording is MP4.
# It returns 1 on failure, 0 on success.
# it needs that connect_device() to have been called prior to this call
sub dump_current_screen_video {
	my ($self, $params) = @_;

	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];

	my $log = $self->log();
	my $verbosity = $self->verbosity;

	if( ! $self->is_device_connected() ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, you need to connect a device to the desktop and ALSO explicitly call ".'device_connected()'." before calling this."); return 1 }

	my $filename = exists($params->{'filename'}) && defined($params->{'filename'}) ? $params->{'filename'} : undef;
	if( ! defined $filename ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, input parameter 'filename' is not specified, an output filename must be specified."); return 1 }

	my @options;

lib/Android/ElectricSheep/Automator.pm  view on Meta::CPAN


	return 0; # success
}

# returns 1 on failure, 0 on success
# it needs that connect_device() to have been called prior to this call
sub wake_up {
	my ($self, $params) = @_;
	$params //= {};

	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];
	my $log = $self->log();
	my $verbosity = $self->verbosity();

	if( ! $self->is_device_connected() ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, you need to connect a device to the desktop and ALSO explicitly call ".'connect_device()'." before calling this."); return undef }

	my @cmd = qw/input keyevent KEYCODE_WAKEUP/;
	if( $verbosity > 0 ){ $log->info("${whoami} (via $parent), line ".__LINE__." : sending command to adb: @cmd") }
	my $res = $self->adb->shell(@cmd);
	if( ! defined $res ){ $log->error(join(" ", @cmd)."\n${whoami} (via $parent), line ".__LINE__." : error, above shell command has failed, got undefined result, most likely shell command did not run at all, this should not be happening."); return unde...
	if( $res->[0] != 0 ){ $log->error(join(" ", @cmd)."\n${whoami} (via $parent), line ".__LINE__." : error, above shell command has failed, with:\nSTDOUT:\n".$res->[1]."\n\nSTDERR:\n".$res->[2]."\nEND."); return undef }

	return 0; # success
}
# goes to the home screen
# returns 1 on success, 0 on failure
# it needs that connect_device() to have been called prior to this call
sub home_screen {
	my ($self, $params) = @_;
	$params //= {};

	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];
	my $log = $self->log();
	my $verbosity = $self->verbosity();

	if( ! $self->is_device_connected() ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, you need to connect a device to the desktop and ALSO explicitly call ".'connect_device()'." before calling this."); return undef }

	$self->wake_up();

	my @cmd = qw/am start -a android.intent.action.MAIN -c android.intent.category.HOME/;
	if( $verbosity > 0 ){ $log->info("${whoami} (via $parent), line ".__LINE__." : sending command to adb: @cmd") }
	my $res = $self->adb->shell(@cmd);

lib/Android/ElectricSheep/Automator.pm  view on Meta::CPAN


	return 0; # success
}
# It swipes right basically
# it returns 0 on success, 1 on failure
# it needs that connect_device() to have been called prior to this call
sub	next_screen {
	my ($self, $params) = @_;
	$params //= {};

	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];
	my $log = $self->log();
	my $verbosity = $self->verbosity();

	if( ! $self->is_device_connected() ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, you need to connect a device to the desktop and ALSO explicitly call ".'connect_device()'." before calling this."); return undef }

	if( $self->swipe({'direction' => 'right', dt => 100}) ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, call to ".'swipe()'." has failed."); return undef }

	return 0; # success
}

# It swipes left basically
# it returns 0 on success, 1 on failure
# it needs that connect_device() to have been called prior to this call
sub	previous_screen {
	my ($self, $params) = @_;
	$params //= {};

	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];
	my $log = $self->log();
	my $verbosity = $self->verbosity();

	if( ! $self->is_device_connected() ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, you need to connect a device to the desktop and ALSO explicitly call ".'connect_device()'." before calling this."); return undef }

	if( $self->swipe({'direction' => 'left', dt => 100}) ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, call to ".'swipe()'." has failed."); return undef }

	return 0; # success
}

# it returns 0 on success, 1 on failure
# it needs that connect_device() to have been called prior to this call
# the left-triangle button (see http://developer.android.com/reference/android/view/KeyEvent.html)
sub	navigation_menu_back_button {
	my ($self, $params) = @_;
	$params //= {};

	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];
	my $log = $self->log();
	my $verbosity = $self->verbosity();

	if( ! $self->is_device_connected() ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, you need to connect a device to the desktop and ALSO explicitly call ".'connect_device()'." before calling this."); return undef }

	my @cmd = ('input', 'keyevent', 'KEYCODE_BACK');
	if( $verbosity > 0 ){ $log->info("${whoami} (via $parent), line ".__LINE__." : sending command to adb: @cmd") }
	my $res = $self->adb->shell(@cmd);
	if( ! defined $res ){ $log->error(join(" ", @cmd)."\n${whoami} (via $parent), line ".__LINE__." : error, above shell command has failed, got undefined result, most likely shell command did not run at all, this should not be happening."); return unde...
	if( $res->[0] != 0 ){ $log->error(join(" ", @cmd)."\n${whoami} (via $parent), line ".__LINE__." : error, above shell command has failed, with:\nSTDOUT:\n".$res->[1]."\n\nSTDERR:\n".$res->[2]."\nEND."); return undef }

lib/Android/ElectricSheep/Automator.pm  view on Meta::CPAN

	return 0; # success
}

# it returns 0 on success, 1 on failure
# it needs that connect_device() to have been called prior to this call
# the round button, it goes to home (see http://developer.android.com/reference/android/view/KeyEvent.html)
sub	navigation_menu_home_button {
	my ($self, $params) = @_;
	$params //= {};

	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];
	my $log = $self->log();
	my $verbosity = $self->verbosity();

	if( ! $self->is_device_connected() ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, you need to connect a device to the desktop and ALSO explicitly call ".'connect_device()'." before calling this."); return undef }

	my @cmd = ('input', 'keyevent', 'KEYCODE_HOME');
	if( $verbosity > 0 ){ $log->info("${whoami} (via $parent), line ".__LINE__." : sending command to adb: @cmd") }
	my $res = $self->adb->shell(@cmd);
	if( ! defined $res ){ $log->error(join(" ", @cmd)."\n${whoami} (via $parent), line ".__LINE__." : error, above shell command has failed, got undefined result, most likely shell command did not run at all, this should not be happening."); return unde...
	if( $res->[0] != 0 ){ $log->error(join(" ", @cmd)."\n${whoami} (via $parent), line ".__LINE__." : error, above shell command has failed, with:\nSTDOUT:\n".$res->[1]."\n\nSTDERR:\n".$res->[2]."\nEND."); return undef }

lib/Android/ElectricSheep/Automator.pm  view on Meta::CPAN

}

# it returns 0 on success, 1 on failure
# it needs that connect_device() to have been called prior to this call
# the square button, aka overview, shows all apps running in some sort of gallery view
# (see http://developer.android.com/reference/android/view/KeyEvent.html)
sub	navigation_menu_overview_button {
	my ($self, $params) = @_;
	$params //= {};

	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];
	my $log = $self->log();
	my $verbosity = $self->verbosity();

	if( ! $self->is_device_connected() ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, you need to connect a device to the desktop and ALSO explicitly call ".'connect_device()'." before calling this."); return undef }

	my @cmd = ('input', 'keyevent', 'KEYCODE_APP_SWITCH');
	if( $verbosity > 0 ){ $log->info("${whoami} (via $parent), line ".__LINE__." : sending command to adb: @cmd") }
	my $res = $self->adb->shell(@cmd);
	if( ! defined $res ){ $log->error(join(" ", @cmd)."\n${whoami} (via $parent), line ".__LINE__." : error, above shell command has failed, got undefined result, most likely shell command did not run at all, this should not be happening."); return unde...
	if( $res->[0] != 0 ){ $log->error(join(" ", @cmd)."\n${whoami} (via $parent), line ".__LINE__." : error, above shell command has failed, with:\nSTDOUT:\n".$res->[1]."\n\nSTDERR:\n".$res->[2]."\nEND."); return undef }

lib/Android/ElectricSheep/Automator.pm  view on Meta::CPAN


# it swipes up and lists all the apps found in that "drawer"
# with their icon bounds (which is where you "tap").
# It returns undef on failure
# It returns a hashref of all the apps found with their name as key and bounds content etc.
# it needs that connect_device() to have been called prior to this call
sub find_all_apps_roundabout_way {
	my ($self, $params) = @_;
	$params //= {};

	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];
	my $log = $self->log();
	my $verbosity = $self->verbosity();

	if( ! $self->is_device_connected() ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, you need to connect a device to the desktop and ALSO explicitly call ".'connect_device()'." before calling this."); return undef }

	# go to home, swipe up and all apps will be revealed
	# then dump the UI
	# then swipe down
	if( $self->home_screen() ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, call to ".'home_screen()'." has failed."); return undef }
	usleep(300);

lib/Android/ElectricSheep/Automator.pm  view on Meta::CPAN

	return $apps; # success
}

# It opens the specified (by 'name' or 'bounds' - for tapping) app
# and returns the a hashref with appname (only if name was specified) and bounds
# it needs that connect_device() to have been called prior to this call
sub open_app_roundabout_way {
	my ($self, $params) = @_;
	$params //= {};

	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];
	my $log = $self->log();
	my $verbosity = $self->verbosity();

	if( ! $self->is_device_connected() ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, you need to connect a device to the desktop and ALSO explicitly call ".'connect_device()'." before calling this."); return undef }

	my $apps = $self->apps_roundabout_way();
	if( (! defined($apps))
	 || (exists($params->{'force-reload-apps-list'}) && defined($params->{'force-reload-apps-list'}) && ($params->{'force-reload-apps-list'}>0))
	){
		if( ! defined $self->find_all_apps_roundabout_way() ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, failed to load list of installed apps, call to ".'find_all_apps_roundabout_way()'." has failed."); return undef }

lib/Android/ElectricSheep/Automator.pm  view on Meta::CPAN

sub apps_roundabout_way { return $_[0]->{'apps-roundabout-way'} }
sub adb { return $_[0]->{'_private'}->{'Android::ADB'} }
sub log { return $_[0]->{'_private'}->{'log'}->{'logger-object'} }
# returns the current verbosity level optionally setting its value
# Value must be an integer >= 0
# setting a verbosity level will also spawn a chain of other debug subs,
sub verbosity {
	my ($self, $m) = @_;
	my $log = $self->log();
	if( defined $m ){
		my $parent = ( caller(1) )[3] || "N/A";
		my $whoami = ( caller(0) )[3];
		$self->{'_private'}->{'debug'}->{'verbosity'} = $m;
		if( defined $self->adb ){ $self->adb->{'verbosity'} = $m }
	}
	return $self->{'_private'}->{'debug'}->{'verbosity'}
}
sub cleanup {
	my ($self, $m) = @_;
	my $log = $self->log();
	if( defined $m ){
		my $parent = ( caller(1) )[3] || "N/A";
		my $whoami = ( caller(0) )[3];
		$self->{'_private'}->{'debug'}->{'cleanup'} = $m;
	}
	return $self->{'_private'}->{'debug'}->{'cleanup'}
}

# return configfile or read+check+set a configfile,
# returns undef on failure or the configfile on success
sub configfile {
	my ($self, $infile) = @_;

	return $self->{'_private'}->{'configfile'} unless defined $infile;

	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];

	# this can be called before the logger is created, so create a temp logger for this
	my $log = $self->log() // Mojo::Log->new();

	my $ch = parse_configfile($infile, $log);
	if( ! defined $ch ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, call to ".'parse_configfile()'." has failed for configuration file '$infile'."); return undef }

	# set it in self, it will also do checks on required keys
	if( ! defined $self->confighash($ch) ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, failed to load specified confighash, , there must be errors in the configuration."); return undef }

	$self->{'_private'}->{'configfile'} = $infile;

	return $infile #success
}

# return configfile or read+check+set a configfile,
# returns undef on failure or the configfile on success
sub parse_configfile {
	my ($infile, $log) = @_;

	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];

	# this can be called before the logger is created, so create a temp logger for this
	$log //= Mojo::Log->new();

	my $ch = Config::JSON::Enhanced::config2perl({
		'filename' => $infile,
		'commentstyle' => 'custom(</*)(*/>)',
		'tags' => ['<%','%>'],
		'variable-substitutions' => {
			'SCRIPTDIR' => Cwd::abs_path($FindBin::Bin),

lib/Android/ElectricSheep/Automator.pm  view on Meta::CPAN

# returns the confighash stored or if one is supplied
# it checks it and sets it and returns it
# or it returns undef on failure
# NOTE, if param is specified then we assume we do not have any configuration,
#       we do not have a logger yet, we have no configuration, no verbosity, etc.
sub confighash {
	my ($self, $m) = @_;

	if( ! defined $m ){ return $self->{'_private'}->{'confighash'} }

	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];

	#print STDOUT "${whoami} (via $parent), line ".__LINE__." : called ...\n";

	# we are storing specified confighash but first check it for some fields
	# required fields:
	for ('adb', 'debug', 'logger'){
		if( ! exists($m->{$_}) || ! defined($m->{$_}) ){ print STDERR "${whoami} (via $parent), line ".__LINE__." : error, configuration does not have key '$_'.\n"; return undef }
	}

	my $x;

lib/Android/ElectricSheep/Automator.pm  view on Meta::CPAN

	# ok!
	$self->{'_private'}->{'confighash'} = $m;
	return $m
}

# initialises
# do the verbositys
# returns 1 on failure, 0 on success
sub init {
	my ($self, $params) = @_;
	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];

	# Confighash
	# first see if either user specified a config file or the default is present and read it,
	# then we will overwrite with user-specified params if any
	my ($configfile, $confighash);
	if( exists($params->{'configfile'}) && defined($configfile=$params->{'configfile'}) ){
		if( ! -f $configfile ){ print STDERR __PACKAGE__."${whoami} (via $parent), line ".__LINE__." : error, specified configfile '$configfile' does not exist or it is not a file.\n"; return 1 }
		# this reads, creates confighash and calls confighash() which will do all the tests
		if( ! defined $self->configfile($configfile) ){ print STDERR __PACKAGE__."${whoami} (via $parent), line ".__LINE__." : error, call to ".'configfile()'." has failed for configfile '$configfile'.\n"; return 1 }
		$confighash = $self->confighash();

lib/Android/ElectricSheep/Automator.pm  view on Meta::CPAN

	}
	if( $self->cleanup($v) < 0 ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, call to 'cleanup()' has failed for value '$v'."); return 1 }

	return 0 # success
}

# initialises module-specific things, no need to copy this to other modules
# returns 1 on failure, 0 on success
sub init_module_specific {
	my ($self, $params) = @_;
	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];
	my $log = $self->log();
	my $verbosity = $self->verbosity();
	my $confighash = $self->confighash();
	if( $verbosity > 0 ){ $log->info("${whoami} (via $parent), line ".__LINE__." : called ...") }

	# set or create the Android::ADB object
	if( exists($params->{'adb'}) && defined($params->{'adb'}) ){
		# caller supplied an existing ADB object
		$self->{'_private'}->{'Android::ADB'} = $params->{'adb'}
	} else {

lib/Android/ElectricSheep/Automator.pm  view on Meta::CPAN

		if( $verbosity > 0 ){ $log->info($devobj."\n${whoami} (via $parent), line ".__LINE__." : device set as above.") }
	}

	# done
	if( $verbosity > 0 ){ $log->info("${whoami} (via $parent), line ".__LINE__." : ".__PACKAGE__." has been initialised ...") }
	return 0 # success
}

sub disconnect_device {
	my ($self, $params) = @_;
	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];
	my $log = $self->log();
	my $verbosity = $self->verbosity();

	if( $verbosity > 0 ){ $log->info("${whoami} (via $parent), line ".__LINE__." : called ...") }

	$self->{'device-properties'} = undef;
	$self->{'device-object'} = undef;

	if( $verbosity > 0 ){ $log->info("${whoami} (via $parent), line ".__LINE__." : done.") }
	return 0; # success

lib/Android/ElectricSheep/Automator.pm  view on Meta::CPAN

sub is_device_connected { return defined($_[0]->{'device-properties'}) ? 1 : 0 }

# enquire screen properties (e.g. w, h) and save them to our $self
# if already exists a DeviceProperties object, then we just return that
# and do nothing UNLESS param 'force' => 1
# On failure it returns undef
# On success it creates a new DeviceProperties Object which is saved in $self
# and also returned to caller
sub find_current_device_properties {
	my ($self, $params) = @_;
	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];
	my $log = $self->log();
	my $verbosity = $self->verbosity();
	my $confighash = $self->confighash();
	if( $verbosity > 0 ){ $log->info("${whoami} (via $parent), line ".__LINE__." : called ...") }

	my $sl;
	if( defined($sl=$self->device_properties())
	 || (
		   exists($params->{'force'})
		&& defined($params->{'force'})

lib/Android/ElectricSheep/Automator/AppProperties.pm  view on Meta::CPAN

use XML::LibXML;

use Data::Roundtrip qw/perl2dump no-unicode-escape-permanently/;

use overload ( '""'  => \&toString );

sub new {
	my $class = $_[0];
	my $params = $_[1] // {};

        my $parent = ( caller(1) )[3] || "N/A";
        my $whoami = ( caller(0) )[3];

	my $self = {
		'_private' => {
			'logger-object' => undef,
			'verbosity' => 0,
			'mother' => 0,
		},
		'data' => {
			# both are extracted from pkg=Package{3d33653 com.viber.voip}
			'packageName' => '',

lib/Android/ElectricSheep/Automator/AppProperties.pm  view on Meta::CPAN

#   So either specify lazy=0 for getting info on all packages installed (takes some time!)
#   or set 'packages' to include those package names you want non-lazy, letting all other lazy.
# It returns undef on failure
# It returns %{ AppProperties objects } keyed on the app name (packageName),
#   on success. The values of the hash can be undef if lazy>0
#   meaning that they will be left to be enquired when someone needs them
#   e.g. in an open_app() call.
sub enquire_installed_apps_factory {
	my $params = $_[0] // {};

        my $parent = ( caller(1) )[3] || "N/A";
        my $whoami = ( caller(0) )[3];

	# we need a mother object (Android::ElectricSheep::Automator)
	if( (! exists $params->{'mother'})
	 || (! defined $params->{'mother'})
	 || (! defined $params->{'mother'}->adb())
	){ print STDERR "${whoami} (via $parent), line ".__LINE__." : error, input parameter 'mother' with our parent Android::ElectricSheep::Automator object was not specified.\n"; return undef }
	my $mother = $params->{'mother'};
	# we now have a mother

	my $log = $mother->log;

lib/Android/ElectricSheep/Automator/AppProperties.pm  view on Meta::CPAN

	return \%apps;
}

# does a adb shell dumpsys and reads various things from it
# it may also do a adb shell wm density
# returns 0 on success, 1 on failure
sub enquire {
	my ($self, $params) = @_;
	$params //= {};

        my $parent = ( caller(1) )[3] || "N/A";
        my $whoami = ( caller(0) )[3];
	my $log = $self->log;
	my $verbosity = $self->verbosity;

	# NOTE
	#   dumpsys package packages
	# and 
	#   dumpsys package com.example.xyz 
	# will yield different things for the package com.example.xyz 
	# we need to enquire twice, 1 for all the package names
	# 2 for the full content of the package info, including activities

lib/Android/ElectricSheep/Automator/DeviceProperties.pm  view on Meta::CPAN

use XML::LibXML;

use Data::Roundtrip qw/perl2dump no-unicode-escape-permanently/;

use overload ( '""'  => \&toString );

sub new {
	my $class = $_[0];
	my $params = $_[1] // {};

        my $parent = ( caller(1) )[3] || "N/A";
        my $whoami = ( caller(0) )[3];

	my $self = {
		'_private' => {
			'logger-object' => undef,
			'verbosity' => 0,
			'mother' => 0,
		},
		'data' => {
			# corresponds to dumpsys->RawSurfaceWidth,RawSurfaceHeight
			'w' => 0,

lib/Android/ElectricSheep/Automator/DeviceProperties.pm  view on Meta::CPAN

	return $self;
}

# does a adb shell dumpsys and reads various things from it
# it may also do a adb shell wm density
# returns 0 on success, 1 on failure
sub enquire {
	my ($self, $params) = @_;
	$params //= {};

        my $parent = ( caller(1) )[3] || "N/A";
        my $whoami = ( caller(0) )[3];

	my $log = $self->log;
	my $verbosity = $self->verbosity;

	# first get the serial of the device
	my @cmd = ('get-serialno');
	my $res = $self->adb->run(@cmd);
	if( ! defined $res ){ $log->error(join(" ", @cmd)."\n${whoami} (via $parent), line ".__LINE__." : error, above shell command has failed, got undefined result, most likely shell command did not run at all, this should not be happening."); return 1 }
	if( $res->[0] != 0 ){ $log->error(join(" ", @cmd)."\n${whoami} (via $parent), line ".__LINE__." : error, above shell command has failed, with:\nsSTDOUT:\n".$res->[1]."\n\nSTDERR:\n".$res->[2]."\nEND."); return 1 }
	$self->set('serial', $res->[1]=~s/\s*$//gmr); # it has a newline at the end

lib/Android/ElectricSheep/Automator/Plugins/Base.pm  view on Meta::CPAN

	},
	"Android::ElectricSheep::Automator::Plugins::Viber" : {
	}
}
EODC

sub new {
	my $class = ref($_[0]) || $_[0];
	my $params = $_[1] // {};

	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];

	my $self = {
		'_private' => {
			'child-class' => $class,
			'mother' => undef, # the Android::ElectricSheep::Automator object
			'confighash' => undef,
			'configfile' => '', # this should never be undef
		},
	};
	bless $self => $class;

lib/Android/ElectricSheep/Automator/Plugins/Base.pm  view on Meta::CPAN

sub mother { return $_[0]->{'_private'}->{'mother'} }
sub child_class { return $_[0]->{'_private'}->{'child-class'} }

# returns the current verbosity level optionally setting its value
# Value must be an integer >= 0
# setting a verbosity level will also spawn a chain of other debug subs,
sub verbosity {
	my ($self, $m) = @_;
	my $log = $self->log();
	if( defined $m ){
		my $parent = ( caller(1) )[3] || "N/A";
		my $whoami = ( caller(0) )[3];
		$self->{'_private'}->{'debug'}->{'verbosity'} = $m;
		if( defined $self->adb ){ $self->adb->{'verbosity'} = $m }
	}
	return $self->{'_private'}->{'debug'}->{'verbosity'}
}
sub cleanup {
	my ($self, $m) = @_;
	my $log = $self->log();
	if( defined $m ){
		my $parent = ( caller(1) )[3] || "N/A";
		my $whoami = ( caller(0) )[3];
		$self->{'_private'}->{'debug'}->{'cleanup'} = $m;
	}
	return $self->{'_private'}->{'debug'}->{'cleanup'}
}

# return configfile or read+check+set a configfile,
# returns undef on failure or the configfile on success
sub configfile {
	my ($self, $infile) = @_;

	return $self->{'_private'}->{'configfile'} unless defined $infile;

	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];
	my $log = $self->log();

	my $ch = Android::ElectricSheep::Automator::parse_configfile($infile, $log);
	if( ! defined $ch ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, call to ".'Config::JSON::Enhanced::config2perl()'." has failed for configuration file '$infile'."); return undef }

	# set it in self, it will also do checks on required keys
	if( ! defined $self->confighash($ch) ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, failed to load specified confighash, , there must be errors in the configuration."); return undef }

	$self->{'_private'}->{'configfile'} = $infile;

lib/Android/ElectricSheep/Automator/Plugins/Base.pm  view on Meta::CPAN

# returns the confighash stored or if one is supplied
# it checks it and sets it and returns it
# or it returns undef on failure
# NOTE, if param is specified then we assume we do not have any configuration,
#       we do not have a logger yet, we have no configuration, no verbosity, etc.
sub confighash {
	my ($self, $m) = @_;

	if( ! defined $m ){ return $self->{'_private'}->{'confighash'} }

	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];

	print STDOUT "${whoami} (via $parent), line ".__LINE__." : called ...\n";

	# the confighash must contain a mother section: 'Android::ElectricSheep::Automator'
	# and a child section,
	# e.g. 'Android::ElectricSheep::Automator::Plugins::Viber'
	# check for both here:
	for ('Android::ElectricSheep::Automator', $self->child_class){
		if( ! exists($m->{$_}) || ! defined($m->{$_}) || (ref($m->{$_})ne'HASH') ){ print STDERR perl2dump($m)."${whoami} (via $parent), line ".__LINE__." : error, configuration (see above) does not have key '$_' or its value is not a HASHref.\n"; return u...
	}

lib/Android/ElectricSheep/Automator/Plugins/Base.pm  view on Meta::CPAN


	# ok!
	$self->{'_private'}->{'confighash'} = $m;
	return $m
}

# initialises
# returns 1 on failure, 0 on success
sub init {
	my ($self, $params) = @_;
	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];

	# we don't have a log yet

	if( exists($params->{'child-class'}) && defined($params->{'child-class'}) ){
		$self->{'_private'}->{'child-class'} = $params->{'child-class'};
	} else {  print STDERR "${whoami} (via $parent), line ".__LINE__." : error, input parameter 'child-class' was not specified, this is the Plugin class calling us, e.g. 'Android::ElectricSheep::Automator::Plugins::Viber'. At the moment this is not ext...

	return 0 # success
}

# initialises module-specific things
# by now we already have read confighash and have logger, verbosity etc.
# returns 1 on failure, 0 on success
sub init_module_specific {
	my ($self, $params) = @_;
	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];

	# Confighash
	# first see if either user specified a config file or the default is present and read it,
	# then we will overwrite with user-specified params if any
	my ($configfile, $confighash);

	if( exists($params->{'configfile'}) && defined($configfile=$params->{'configfile'}) ){
		if( ! -f $configfile ){ print STDERR __PACKAGE__." (via ".$self->child_class.") : ${whoami} (via $parent), line ".__LINE__." : error, specified configfile '$configfile' does not exist or it is not a file.\n"; return 1 }
		# this reads, creates confighash and calls confighash() which will do all the tests
		if( ! defined $self->configfile($configfile) ){ print STDERR __PACKAGE__." (via ".$self->child_class.") : ${whoami} (via $parent), line ".__LINE__." : error, call to ".'configfile()'." has failed for configfile '$configfile'.\n"; return 1 }

lib/Android/ElectricSheep/Automator/Plugins/Viber.pm  view on Meta::CPAN

		%$params,
		'child-class' => $class,
	});
	$self->{'_private'}->{'appname'} = 'com.viber.voip';

	return $self;
}
sub appname { return $_[0]->{'_private'}->{'appname'} }
sub open_viber_app {
	my ($self, $params) = @_;
	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];
	my $log = $self->log();
	my $verbosity = $self->verbosity();

	my $packagename = $self->appname;
	my $ret = $self->mother->open_app({'package' => $packagename});
	if( ! defined $ret ){
		my $instapps = $self->mother->find_installed_apps();
		if( defined $instapps ){
			$log->error("All installed apps on current device:\n".join("\n  ".$_, sort keys %$instapps)."\n\n");
		}
		$log->error("${whoami} (via $parent), line ".__LINE__." : failed to open app '$packagename'.");
		return undef
	}
	if( $verbosity > 0 ){ $log->info("${whoami} (via $parent), line ".__LINE__." : app '$packagename' is now opening ...") }
	return $ret;
}

sub close_viber_app {
	my ($self, $params) = @_;
	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];
	my $log = $self->log();
	my $verbosity = $self->verbosity();

	my $packagename = $self->appname;
	my $ret = $self->mother->close_app({'package' => $packagename});
	if( ! defined $ret ){ $log->error("${whoami} (via $parent), line ".__LINE__." : failed to close app '$packagename'."); return undef }
	if( $verbosity > 0 ){ $log->info("${whoami} (via $parent), line ".__LINE__." : app '$packagename' is now closing ...") }
	return $ret;
}

# keeps pressing the back-arrow at the top of the app to hopefully
# arrive at the main activity of the app,
# TODO: is there a way to tell it to go to main activity ? WelcomeActivity does not seem to work
# returns 1 on failure, 0 on success.
sub navigate_to_viber_home_activity {
	my ($self, $params) = @_;
	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];
	my $log = $self->log();
	my $verbosity = $self->verbosity();

	my ($outbase, $outfile);
	# for debugging purposes, save each UI we get here
	$outbase = exists($params->{'outbase'}) ? $params->{'outbase'} : undef;

	my ($ui, $dom, $xc, $asel, @nodes, $N, $node, $boundstr, $bounds);

	my $repeats = 3;

lib/Android/ElectricSheep/Automator/Plugins/Viber.pm  view on Meta::CPAN

		if( $self->mother->tap({'bounds' => $bounds}) ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, failed to tap on $bounds."); return 1 }
		usleep(0.75);
	}

	if( $verbosity > 0 ){ $log->info("${whoami} (via $parent), line ".__LINE__." : hopefully we are now at the very first screen of the app.") }
	return 0 # success
}

sub send_message {
	my ($self, $params) = @_;
	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];
	my $log = $self->log();
	my $verbosity = $self->verbosity();

	my ($recipient, $message, $outbase, $outfile);
	if( ! exists($params->{'recipient'}) || ! defined($recipient=$params->{'recipient'}) ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, input parameter 'recipient' was not specified."); return undef }
	if( ! exists($params->{'message'}) || ! defined($message=$params->{'message'}) ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, input parameter 'message' was not specified."); return undef }
	# for debugging purposes, save each UI we get here
	$outbase = exists($params->{'outbase'}) ? $params->{'outbase'} : undef;
	# do everything except clicking the send button
	my $mock = exists($params->{'mock'}) ? $params->{'mock'} : 0;

lib/Android/ElectricSheep/Automator/ScreenLayout.pm  view on Meta::CPAN

use XML::LibXML;

use Data::Roundtrip qw/perl2dump no-unicode-escape-permanently/;

use overload ( '""'  => \&toString );

sub new {
	my $class = $_[0];
	my $params = $_[1] // {};

        my $parent = ( caller(1) )[3] || "N/A";
        my $whoami = ( caller(0) )[3];

	my $self = {
		'_private' => {
			'xml' => undef,
			'logger-object' => undef,
			'verbosity' => 0,
		},
		'data' => {
			'w' => 0,
			'h' => 0,

lib/Android/ElectricSheep/Automator/ScreenLayout.pm  view on Meta::CPAN

# will not be found here.
#   my $xmlstring = $self->dump_current_screen_ui();
#   my $sl = Android::ElectricSheep::Automator::ScreenLayout->new({'xml-string' => $xmlstring});
# will call fromXML();
# Or make it yourself: adb shell uiautomator dump outfile
# or adb exec-out uiautomator dump /dev/tty | awk '{gsub("UI hierchary dumped to: /dev/tty", "");print}'
sub fromXML {
	my ($self, $params) = @_;
	$params //= {};

        my $parent = ( caller(1) )[3] || "N/A";
        my $whoami = ( caller(0) )[3];

	my $log = $self->log;
	my $verbosity = $self->verbosity;

	my $doc;
	if( exists $params->{'xml-filename'} ){
		$doc = XML::LibXML->load_xml(location => $params->{'xml-filename'});
	} elsif( exists $params->{'xml-string'} ){
		$doc = XML::LibXML->load_xml(string => $params->{'xml-string'});
	}

lib/Android/ElectricSheep/Automator/XMLParsers.pm  view on Meta::CPAN

#   my $ret = Android::ElectricSheep::Automator::XMLParsers::XMLParser_find_all_apps(
#    {'xml-string' => $xmlstring}
#   );
# will call fromXML();
# Or make it yourself: adb shell uiautomator dump outfile
# or adb exec-out uiautomator dump /dev/tty | awk '{gsub("UI hierchary dumped to: /dev/tty", "");print}'
sub XMLParser_find_all_apps {
	my $params = $_[0];
	$params //= {};

        my $parent = ( caller(1) )[3] || "N/A";
        my $whoami = ( caller(0) )[3];

	my $log = (exists($params->{'log'}) && defined($params->{'log'})) ? $params->{'log'} : Mojo::Log->new;
	my $verbosity = (exists($params->{'verbosity'}) && defined($params->{'verbosity'})) ? $params->{'verbosity'} : 0;

	my $doc;
	if( exists($params->{'xml-filename'}) && defined($params->{'xml-filename'}) ){
		$doc = eval { XML::LibXML->load_xml(location => $params->{'xml-filename'}) };
		if( $@ || (! defined $doc) ){ $log->error("${whoami} (via $parent), line ".__LINE__." : error, call to ".'XML::LibXML->load_xml()'." has failed for file '".$params->{'xml-filename'}."' : $@"); return undef }
	} elsif( exists($params->{'xml-string'}) && defined($params->{'xml-string'}) ){
		$doc = eval { XML::LibXML->load_xml(string => $params->{'xml-string'}) };



( run in 0.379 second using v1.01-cache-2.11-cpan-26ccb49234f )