diff --git a/AndroidManifest.xml b/AndroidManifest.xml
new file mode 100644
index 0000000..b9412ba
--- /dev/null
+++ b/AndroidManifest.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/drawable/icon.png b/res/drawable/icon.png
new file mode 100644
index 0000000..67d5d7b
Binary files /dev/null and b/res/drawable/icon.png differ
diff --git a/res/layout/about.xml b/res/layout/about.xml
new file mode 100644
index 0000000..dbce45d
--- /dev/null
+++ b/res/layout/about.xml
@@ -0,0 +1,11 @@
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/main.xml b/res/layout/main.xml
new file mode 100644
index 0000000..a31ec84
--- /dev/null
+++ b/res/layout/main.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
new file mode 100644
index 0000000..4ea0b65
--- /dev/null
+++ b/res/values/arrays.xml
@@ -0,0 +1,77 @@
+
+
+
+ - Search
+ - Web Snippets
+ - Local Search
+ - Local Movies
+ - Local Weather
+ - Airports
+ - Area Codes
+ - Calculator
+ - Currency Conversion
+ - Directions
+ - Flights
+ - Glossary
+ - METAR
+ - Maps
+ - Movies
+ - Products
+ - Q&A
+ - Sports
+ - Stocks
+ - Translation
+ - Weather
+ - Zip Codes
+
+
+
+ - %s
+ - web %s
+ - %s %l
+ - movies %%s %l
+ - weather %l
+ - %s airport
+ - area code %s
+ - %s
+ - %s
+ - directions %s
+ - flight %s
+ - define %s
+ - metar %s
+ - map %s
+ - movies %s
+ - price %s
+ - %s
+ - score %s
+ - stock %s
+ - translate %s
+ - weather %s
+ - zip code %s
+
+
+
+ - blockbuster seattle wa
+ - search terms, e.g.: t-mobile g1
+ - business listing, sushi, pizza, etc.
+ - No query or current movie name
+ - No query required
+ - airport code, e.g.: sfo
+ - area code, e.g.: 650
+ - 1 us pint in liters, 5+2/2, etc.
+ - 8 usd in yen
+ - pasadena ca to 94043
+ - aa 2111, ua 14, etc.
+ - word to define, e.g.: zenith
+ - ICAO airport code, e.g.: khio
+ - 5th avenue new york
+ - current movie name boston, ma
+ - ipod 40gb, UPC/ISBN, etc.
+ - india population
+ - NBA/NHL/MLB/NFL/NCAA team
+ - ticker symbol, e.g.: goog
+ - hello in french
+ - new york, ny
+ - 90210
+
+
diff --git a/res/values/strings.xml b/res/values/strings.xml
new file mode 100644
index 0000000..9156f9d
--- /dev/null
+++ b/res/values/strings.xml
@@ -0,0 +1,27 @@
+
+
+ Hello World, GoogSMS
+ GoogSMS
+ Query:
+ Type:
+ Send via SMS
+ Your message was sent.
+ Please enter a query...
+ Please set your location...
+ 466453
+ © 2008 Erik C. Thauvin\nAll Rights Reserved\n\nerik@thauvin.net\n\nhttp://mobile.thauvin.net
+ About
+ Preferences
+ OK
+ Preferences
+ Set Your Location...
+ Location
+ Your current city and state or zip.
+ e.g.: san francisco ca or 94123
+ Set SMS Number...
+ Google SMS
+ The short code or number of the Google SMS service.
+ e.g.: 466453
+ prefs_sms
+ prefs_loc
+
diff --git a/res/xml/prefs.xml b/res/xml/prefs.xml
new file mode 100644
index 0000000..c422559
--- /dev/null
+++ b/res/xml/prefs.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/screenshots/1.psd b/screenshots/1.psd
new file mode 100644
index 0000000..78a4f09
Binary files /dev/null and b/screenshots/1.psd differ
diff --git a/screenshots/2.psd b/screenshots/2.psd
new file mode 100644
index 0000000..52f6b7e
Binary files /dev/null and b/screenshots/2.psd differ
diff --git a/screenshots/googsms.gif b/screenshots/googsms.gif
new file mode 100644
index 0000000..4e6e6f8
Binary files /dev/null and b/screenshots/googsms.gif differ
diff --git a/sign.bat b/sign.bat
new file mode 100644
index 0000000..6809692
--- /dev/null
+++ b/sign.bat
@@ -0,0 +1,10 @@
+@echo off
+"%JAVA_HOME%\bin\jarsigner" -verbose -keystore "%USERPROFILE%\personal\android.keystore" "%1" android
+if errorlevel 1 goto ERROR
+"%JAVA_HOME%\bin\jarsigner" -verify "%1"
+if errorlevel 1 goto ERROR
+goto DONE
+:ERROR
+@pause
+:DONE
+@echo on
\ No newline at end of file
diff --git a/src/net/thauvin/erik/android/googsms/GoogSMS.java b/src/net/thauvin/erik/android/googsms/GoogSMS.java
new file mode 100644
index 0000000..534ca47
--- /dev/null
+++ b/src/net/thauvin/erik/android/googsms/GoogSMS.java
@@ -0,0 +1,390 @@
+/*
+ * @(#)GoogSMS.java
+ *
+ * Copyright (c) 2008, Erik C. Thauvin (http://erik.thauvin.net/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the authors nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ */
+package net.thauvin.erik.android.googsms;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Bundle;
+import android.telephony.gsm.SmsManager;
+import android.text.ClipboardManager;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.AutoCompleteTextView;
+import android.widget.Button;
+import android.widget.Spinner;
+import android.widget.Toast;
+
+/**
+ * The GoogSMS
class implements a simple front-end for Google SMS.
+ *
+ * @author Erik C. Thauvin
+ * @version $Revision$, $Date$
+ * @created Nov 2, 2008
+ * @since 1.0
+ */
+public class GoogSMS extends Activity
+{
+ private static final int MAX_HISTORY_SIZE = 15;
+ private static final int MENU_ABOUT = 0;
+ private static final int MENU_PREFS = 1;
+ private static final String PREFS_HISTORY = "history";
+
+ private final List mHistory = new ArrayList(MAX_HISTORY_SIZE);
+
+ private String mLocation;
+ private String mSmsNumber;
+
+ /**
+ * Adds to the history.
+ *
+ * @param entry The entry to add.
+ */
+ private void addHistory(String entry)
+ {
+ if (!mHistory.contains(entry))
+ {
+ if (mHistory.size() >= MAX_HISTORY_SIZE)
+ {
+ mHistory.remove(0);
+ }
+
+ mHistory.add(entry);
+
+ final SharedPreferences settings = getSharedPreferences(getString(R.string.app_name), Context.MODE_PRIVATE);
+ final SharedPreferences.Editor editor = settings.edit();
+ editor.putString(PREFS_HISTORY, TextUtils.join(",", mHistory));
+ editor.commit();
+ }
+ }
+
+ /**
+ * Returns the location.
+ *
+ * @return the location
+ */
+ private String getLocation()
+ {
+ return mLocation;
+ }
+
+ /**
+ * Returns the SMS service number.
+ *
+ * @return the SMS number
+ */
+ private String getSmsNumber()
+ {
+ return mSmsNumber;
+ }
+
+ /**
+ * Returns the current version number.
+ *
+ * @return The current version number or empty.
+ */
+ private String getVersionNumber()
+ {
+ try
+ {
+ return getPackageManager().getPackageInfo(getPackageName(), 0).versionName;
+ }
+ catch (final NameNotFoundException e)
+ {
+ return "";
+ }
+ }
+
+ /**
+ * Returns whether the location has been set.
+ *
+ * @return true
if set, false
otherwise.
+ */
+ private boolean hasLocation()
+ {
+ return !TextUtils.isEmpty(mLocation);
+ }
+
+ /**
+ * Initializes the various controls.
+ */
+ private void init()
+ {
+ loadPrefs();
+
+ final AutoCompleteTextView queryFld = (AutoCompleteTextView) findViewById(R.id.main_query_fld);
+ final Spinner typeSpin = (Spinner) findViewById(R.id.main_type_spin);
+ final Button sendBtn = (Button) findViewById(R.id.main_send_btn);
+
+ final SharedPreferences settings = getSharedPreferences(getString(R.string.app_name), Context.MODE_PRIVATE);
+ setHistory(settings.getString(PREFS_HISTORY, ""));
+ setAutoComplete(queryFld);
+
+ final ArrayAdapter typeAdapter = ArrayAdapter.createFromResource(this, R.array.main_type_array,
+ android.R.layout.simple_spinner_item);
+ typeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ typeSpin.setAdapter(typeAdapter);
+
+ final ClipboardManager clip = (ClipboardManager) getSystemService(android.content.Context.CLIPBOARD_SERVICE);
+ if (clip.hasText())
+ {
+ queryFld.setText(clip.getText());
+ }
+
+ final String[] hints = getResources().getStringArray(R.array.main_hint_array);
+ final String[] cmds = getResources().getStringArray(R.array.main_cmd_array);
+
+ typeSpin.setOnItemSelectedListener(new Spinner.OnItemSelectedListener()
+ {
+ @Override
+ public void onItemSelected(AdapterView> parent, View view, int position, long id)
+ {
+ queryFld.setHint(hints[position]);
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView> parent)
+ {
+ ; // do nothing
+ }
+ });
+
+ sendBtn.setOnClickListener(new Button.OnClickListener()
+ {
+ public void onClick(View view)
+ {
+ final String localToken = "%l";
+ final String searchToken = "%s";
+ final String optSearchToken = "%%s";
+
+ final String cmd = cmds[typeSpin.getSelectedItemPosition()];
+ final String query = queryFld.getText().toString();
+
+ final boolean isLocal = (cmd.indexOf(localToken) != -1);
+ final boolean isQuery = (cmd.indexOf(searchToken) != -1);
+ final boolean isOptQuery = (cmd.indexOf(optSearchToken) != -1);
+
+ if ((!isOptQuery) && TextUtils.isEmpty(query) && isQuery)
+ {
+ Toast.makeText(GoogSMS.this, R.string.main_query_err_txt, Toast.LENGTH_SHORT).show();
+ }
+ else if (!hasLocation() && isLocal)
+ {
+ Toast.makeText(GoogSMS.this, R.string.main_location_err_txt, Toast.LENGTH_SHORT).show();
+ launchPrefs();
+ }
+ else
+ {
+ final String s1;
+
+ if (isLocal)
+ {
+ s1 = cmd.replace(localToken, getLocation());
+ }
+ else
+ {
+ s1 = cmd;
+ }
+
+ final String s2;
+
+ if (isOptQuery)
+ {
+ if (TextUtils.isEmpty(query))
+ {
+ s2 = s1.replace(' ' + optSearchToken, "");
+ }
+ else
+ {
+ s2 = s1.replace(optSearchToken, query);
+ }
+ }
+ else if (isQuery)
+ {
+ s2 = s1.replace(searchToken, query);
+ }
+ else
+ {
+ s2 = s1;
+ }
+
+ final SmsManager sms = SmsManager.getDefault();
+ sms.sendTextMessage(getSmsNumber(), null, s2, null, null);
+
+ addHistory(query);
+ setAutoComplete(queryFld);
+
+ Toast.makeText(GoogSMS.this, R.string.main_sms_sent_txt, Toast.LENGTH_SHORT).show();
+
+ Log.v("SMS SENT: ", s2);
+ }
+ }
+
+ });
+ }
+
+ /**
+ * Launches the preferences screen.
+ */
+ private void launchPrefs()
+ {
+ startActivity(new Intent(this, PrefsScreen.class));
+ }
+
+ /**
+ * Loads the preferences.
+ *
+ * @param isFirst The first call flag.
+ */
+ public void loadPrefs()
+ {
+ final SharedPreferences settings = getSharedPreferences(getString(R.string.app_name), Context.MODE_PRIVATE);
+ setLocation(settings.getString(getString(R.string.prefs_key_loc), ""));
+ setSmsNumber(settings.getString(getString(R.string.prefs_key_sms), getString(R.string.default_google_sms)));
+ }
+
+ /** Called when the activity is first created. */
+ @Override
+ public void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main);
+ init();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu)
+ {
+ menu.add(0, MENU_ABOUT, 0, R.string.about_menu_txt).setIcon(android.R.drawable.ic_menu_info_details);
+ menu.add(0, MENU_PREFS, 0, R.string.prefs_menu_txt).setIcon(android.R.drawable.ic_menu_preferences);
+ return super.onCreateOptionsMenu(menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item)
+ {
+ if (item.getItemId() == MENU_ABOUT)
+ {
+ final LayoutInflater factory = LayoutInflater.from(this);
+ final View aboutView = factory.inflate(R.layout.about, null);
+
+ new AlertDialog.Builder(this).setView(aboutView).setIcon(android.R.drawable.ic_dialog_info).setTitle(
+ getString(R.string.app_name) + ' ' + getVersionNumber()).setPositiveButton(R.string.alert_dialog_ok,
+ new DialogInterface.OnClickListener()
+ {
+ public void onClick(DialogInterface dialog, int whichButton)
+ {
+ // do nothing
+ }
+ }).show();
+
+ return true;
+ }
+ else if (item.getItemId() == MENU_PREFS)
+ {
+ launchPrefs();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ protected void onResume()
+ {
+ super.onResume();
+
+ loadPrefs();
+ }
+
+ /**
+ * Sets the auto-complete values of the specified field.
+ *
+ * @param field The field to the auto-complete for.
+ */
+ private void setAutoComplete(AutoCompleteTextView field)
+ {
+ final ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_dropdown_item_1line, mHistory);
+ field.setAdapter(adapter);
+ }
+
+ /**
+ * Sets the history.
+ *
+ * @param history The comma-delimited history string.
+ */
+ private void setHistory(String history)
+ {
+ final String[] entries = TextUtils.split(history, ",");
+ for (final String entry : entries)
+ {
+ mHistory.add(entry);
+ }
+ }
+
+ /**
+ * Sets the location.
+ *
+ * @param location the location to set
+ */
+ private void setLocation(String location)
+ {
+ mLocation = location;
+ }
+
+ /**
+ * Sets the SMS service number.
+ *
+ * @param smsNumber the SMS number to set
+ */
+ private void setSmsNumber(String smsNumber)
+ {
+ mSmsNumber = smsNumber;
+ }
+}
\ No newline at end of file
diff --git a/src/net/thauvin/erik/android/googsms/PrefsScreen.java b/src/net/thauvin/erik/android/googsms/PrefsScreen.java
new file mode 100644
index 0000000..7b4618f
--- /dev/null
+++ b/src/net/thauvin/erik/android/googsms/PrefsScreen.java
@@ -0,0 +1,65 @@
+/*
+ * @(#)PrefsScreen.java
+ *
+ * Copyright (c) 2008, Erik C. Thauvin (http://erik.thauvin.net/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the authors nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ */
+package net.thauvin.erik.android.googsms;
+
+import android.os.Bundle;
+import android.preference.PreferenceActivity;
+import android.widget.TextView;
+
+/**
+ * The GoogSMS
class implements a the preferences screen for Google SMS.
+ *
+ * @author Erik C. Thauvin
+ * @version $Revision$, $Date$
+ * @created Nov 2, 2008
+ * @since 1.0
+ */
+public class PrefsScreen extends PreferenceActivity
+{
+ public TextView mLocationHint;
+
+ /**
+ * Called when the activity is first created.
+ */
+ @Override
+ public void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+ getPreferenceManager().setSharedPreferencesName(getString(R.string.app_name));
+ addPreferencesFromResource(R.xml.prefs);
+ }
+}
diff --git a/src/net/thauvin/erik/android/googsms/R.java b/src/net/thauvin/erik/android/googsms/R.java
new file mode 100644
index 0000000..7d16384
--- /dev/null
+++ b/src/net/thauvin/erik/android/googsms/R.java
@@ -0,0 +1,62 @@
+/* AUTO-GENERATED FILE. DO NOT MODIFY.
+ *
+ * This class was automatically generated by the
+ * aapt tool from the resource data it found. It
+ * should not be modified by hand.
+ */
+
+package net.thauvin.erik.android.googsms;
+
+public final class R {
+ public static final class array {
+ public static final int main_cmd_array=0x7f050001;
+ public static final int main_hint_array=0x7f050002;
+ public static final int main_type_array=0x7f050000;
+ }
+ public static final class attr {
+ }
+ public static final class drawable {
+ public static final int icon=0x7f020000;
+ }
+ public static final class id {
+ public static final int about_text_fld=0x7f070000;
+ public static final int main_query_fld=0x7f070002;
+ public static final int main_query_lbl=0x7f070001;
+ public static final int main_send_btn=0x7f070005;
+ public static final int main_type_lbl=0x7f070003;
+ public static final int main_type_spin=0x7f070004;
+ }
+ public static final class layout {
+ public static final int about=0x7f030000;
+ public static final int main=0x7f030001;
+ }
+ public static final class string {
+ public static final int about_menu_txt=0x7f06000a;
+ public static final int about_txt=0x7f060009;
+ public static final int alert_dialog_ok=0x7f06000c;
+ public static final int app_name=0x7f060001;
+ public static final int default_google_sms=0x7f060008;
+ public static final int hello=0x7f060000;
+ public static final int main_location_err_txt=0x7f060007;
+ public static final int main_query_err_txt=0x7f060006;
+ public static final int main_query_lbl_txt=0x7f060002;
+ public static final int main_send_btn_txt=0x7f060004;
+ public static final int main_sms_sent_txt=0x7f060005;
+ public static final int main_type_lbl_txt=0x7f060003;
+ public static final int prefs_dialog_title=0x7f06000d;
+ public static final int prefs_key_loc=0x7f060017;
+ public static final int prefs_key_sms=0x7f060016;
+ public static final int prefs_location_dialog_title=0x7f06000e;
+ public static final int prefs_location_hint=0x7f060011;
+ public static final int prefs_location_summary=0x7f060010;
+ public static final int prefs_location_title=0x7f06000f;
+ public static final int prefs_menu_txt=0x7f06000b;
+ public static final int prefs_sms_dialog_title=0x7f060012;
+ public static final int prefs_sms_hint=0x7f060015;
+ public static final int prefs_sms_summary=0x7f060014;
+ public static final int prefs_sms_title=0x7f060013;
+ }
+ public static final class xml {
+ public static final int prefs=0x7f040000;
+ }
+}