Skip to content

Commit

Permalink
Added 'gps_send_message.pl' and 'sms_search.pl' to the examples direc…
Browse files Browse the repository at this point in the history
…tory for future reference. It should be noted that 'sms_search.pl' is currently broken while utf8.pm is missing. This is a known issue and is being discussed here: http://code.google.com/p/android-scripting/issues/detail?id=108
  • Loading branch information
alexeld committed May 29, 2010
1 parent be25e55 commit aab6067
Show file tree
Hide file tree
Showing 2 changed files with 304 additions and 0 deletions.
210 changes: 210 additions & 0 deletions examples/gps_send_message.pl
@@ -0,0 +1,210 @@
#!/data/data/com.google.ase/perl/perl
#
# Copyright 2010 Alex Elder (http://www.alexelder.co.uk)
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
#
# A simple Perl script designed to run under the Android Scripting Environment:
# http://code.google.com/p/android-scripting. Designed to dispatch a text
# message when the phone's position matches the position entered by the user.
# For best results, start this program as a service.
#
# Text messages support 'tags' which are substituted for values before the
# message is sent. Currently supported tags are:
#
# admin_area
# country_code
# country_name
# feature_name
# locality
# postal_code
# thoroughfare
# sub_admin_area
# map_link
#
# All tags must start and end with a '%' (percentage) sign. For example,
# if you would like to send a message as soon as you entered Cheshire to a
# chosen contact, and within that message you'd like to embed your current
# county and a Google Maps link, you could enter something similar to:
#
# "Hi, I'm just entering %admin_area% now; link: %map_link%. See you soon!"
#
# The tags in the above example would be substituted for their actual values:
#
# "Hi, I'm just entering Cheshire now; link:
# http://maps.google.com/maps?q=53.800651,-4.064941. See you soon!"
#
use strict;
use warnings;

use Android;
use Carp;

use constant {
LOOP_DELAY => 180, # seconds to sleep between checking GPS position
MAX_ATTEMPTS => 250, # number of match-loop iterations before giving up
SPEAK_ON_SEND => 1, # speak using TTS when the message is sent
MAP_LINK => 'http://maps.google.com/maps?q=%s,%s', # map link (message 'tag')
};

my $droid = Android->new();

$droid->makeToast('Select a contact');

my $contact;

# Select a contact
$contact = $droid->pickPhone();

if ( ! defined $contact->{result} ) {

$droid->makeToast('Please select a contact');
$contact = $droid->pickPhone();

exit if defined $contact->{error};
}

$contact = $contact->{result};

# Enter a message for the chosen contact
my $message_to_contact = $droid->getInput('Message', 'Message to selected contact');

if ( defined $message_to_contact->{error} || ! defined $message_to_contact->{result} ) {

$droid->makeToast('No message entered. Please enter a message.');
$message_to_contact = $droid->getInput('Message', 'Message to be sent to contact upon arrival');

exit if defined $message_to_contact->{error} || ! defined $message_to_contact->{result};
}

$message_to_contact = $message_to_contact->{result};

# Message authors can embed 'tags' that are substituted before a message is sent
# to the chosen contact. The tag start and end markers are '%' and '%'
# respectively.
my @gps_keys = qw/
admin_area
country_code
country_name
feature_name
locality
postal_code
thoroughfare
sub_admin_area
/;

# Create a dialog and present it to the user. They need to select which area
# they'd like their location matched against. This is a potential 'non-slick' as
# it'd be much nicer to use a Maps instance and geocode a screen tap, rather
# than asking for someone to enter text. However, seems the Map application
# starts itself in a new task when launched, making is *very* hard to get the
# return value. For more information, please read: http://bit.ly/a7krNU.

# Create a UI component and force the user to select a GPS zone to match on:
$droid->dialogCreateAlert('Match location using...');
$droid->dialogSetItems(\@gps_keys);
$droid->dialogShow();

my $match_key = $droid->dialogGetResponse();

exit if ! defined $match_key->{result}->{item};

if ( $match_key->{result}->{item} >= 0 && $match_key->{result}->{item} <= scalar @gps_keys ) {
$match_key = $gps_keys[$match_key->{result}->{item}];
}
else {
# use the first element in the allowed tags list as the default matching method
$match_key = $gps_keys[0];
}

# Add the 'map_link' here, rather than above because the map link isn't a GPS
# result - however it is a valid substitution tag, used for inserting a Google
# Maps URI.
push @gps_keys, 'map_link';

# Enter destination
my $destination = $droid->getInput('Destination', 'Please enter your destination');

if ( defined $destination->{error} || ! defined $destination->{result} ) {

$droid->makeToast('No destination entered. Please enter a destination.');
$destination = $droid->getInput('Destination', 'Please enter your destination');

exit if defined $destination->{error} || ! defined $destination->{result};
}

$destination = $destination->{result};

# When using the selected text input, the input keyboard will often suggest a
# word and add a space after the selected word, so remove any trailing whitespace
# here for convenience.
$destination =~ s/\s+$//;

# Keep a count of how many times the script's looped around while attempting to
# find a match.
my $attempts = 0;

my ($location, $longitude, $latitude, $geocode);

$droid->startLocating();

# give the GPS sensor a chance to wake up
sleep 15;

CHECK_LOCATION:
while ( $attempts++ <= MAX_ATTEMPTS ) {

$location = $droid->readLocation() || $droid->getLastKnownLocation();

if ( defined $location->{error} ) {

print STDERR "location error: $location->{error}\n";
next CHECK_LOCATION;
}

$longitude = $location->{result}->{network}->{longitude};
$latitude = $location->{result}->{network}->{latitude};

$geocode = $droid->geocode($latitude, $longitude);

if ( defined $geocode->{error} ) {

print STDERR "geocode error: $geocode->{error}\n";
next CHECK_LOCATION;
}

foreach my $address ( @{ $geocode->{result} } ) {

if ( $address->{$match_key} =~ /$destination/i ) {

# add a maps link to the address hash
my $map_link = sprintf(MAP_LINK, $latitude, $longitude);
$address->{map_link} = $map_link;

# replace special tags in the input messages
$message_to_contact =~ s/%*$_*%/$address->{$_}/g for @gps_keys;

print "successfully matched $address->{$match_key} against $destination\n";
print "sending: '$message_to_contact' to contact $contact\n";

$droid->smsSend($contact, $message_to_contact);
$droid->speak("Message sent to contact after $attempts attempts.") if SPEAK_ON_SEND == 1;

last CHECK_LOCATION;
}
}

sleep LOOP_DELAY;
}

exit;
94 changes: 94 additions & 0 deletions examples/sms_search.pl
@@ -0,0 +1,94 @@
#!/data/data/com.google.ase/perl/perl
#
# Copyright 2010 Alex Elder (http://www.alexelder.co.uk)
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
#
# A simplistic example, demonstrating how to implement a simple search tool
# using ASE and Perl.
#
use strict;
use warnings;

use Android;
use Carp;
use Data::Dumper;

use constant {
INPUT_TITLE => 'Search String',
INPUT_MESSAGE => 'Enter a search string or Perl regex:',
};

my $droid = Android->new();
my $messages = $droid->smsGetMessages(0, 'inbox', ['body', 'thread_id']);

croak "Unable to retreive SMS messages" if defined $messages->{error};

my $search_string = $droid->getInput(INPUT_TITLE, INPUT_MESSAGE);

if ( defined $search_string->{error} ) {

$droid->makeToast('No search string entered; try again...');
$search_string = $droid->getInput(INPUT_TITLE, INPUT_MESSAGE);

exit if defined $search_string->{error};
}

$search_string = qr/$search_string->{result}/;

my @matches;

foreach my $message ( @{ $messages->{result} } ) {

if ( $message->{body} =~ $search_string ) {

push @matches, $message;
}
}

if ( ! @matches ) {

$droid->makeToast("No matches found for '$search_string'");
exit;
}
else {

$droid->makeToast("Found " . scalar @matches . " matches!");
}

# Extract just the body part from each message and display it on the UI using
# the index within @matches as the return ID from the UI component:
$droid->dialogCreateAlert('Search Results');
$droid->dialogSetItems([ map { $_->{body} } @matches ] );
$droid->dialogShow();

my $selected_search_result = $droid->dialogGetResponse();

if ( defined $selected_search_result->{error} ) {

$droid->makeToast('Invalid choice; exiting');
$droid->exit();
}
else {
$selected_search_result = $selected_search_result->{result}->{item};
}

my $sms_thread_id = $matches[$selected_search_result]->{thread_id};

# FIXME: This needs addressing. Currently, the below URI will navigate to the
# correct message thread, however it will not navigate to the correct message
# *within* the given thread. I'm not too sure how to do this, and it doesn't
# seem to be too well documented.
$droid->startActivity('android.intent.action.VIEW', "sms://view/conversations/$sms_thread_id");

$droid->exit();

0 comments on commit aab6067

Please sign in to comment.