X-Git-Url: http://git.rot13.org/?p=zxing.git;a=blobdiff_plain;f=android%2Fsrc%2Fcom%2Fgoogle%2Fzxing%2Fclient%2Fandroid%2Fresult%2FResultHandler.java;h=db9e2352696114508bb288891204d87d4ed4c89e;hp=af0ab9c452cbfd1f359648fd8fb5470f83a6ec2a;hb=df9df215c09a6787961d0200de2638d169991af4;hpb=96659a17aec334f4cf0df76914c229b079705acc diff --git a/android/src/com/google/zxing/client/android/result/ResultHandler.java b/android/src/com/google/zxing/client/android/result/ResultHandler.java index af0ab9c4..db9e2352 100644 --- a/android/src/com/google/zxing/client/android/result/ResultHandler.java +++ b/android/src/com/google/zxing/client/android/result/ResultHandler.java @@ -16,38 +16,90 @@ package com.google.zxing.client.android.result; -import android.app.Activity; -import android.content.Intent; -import android.net.Uri; -import android.provider.Contacts; +import com.google.zxing.Result; +import com.google.zxing.client.android.Contents; import com.google.zxing.client.android.Intents; -import com.google.zxing.client.android.R; -import com.google.zxing.client.android.SearchBookContentsActivity; import com.google.zxing.client.android.LocaleManager; -import com.google.zxing.client.android.Contents; +import com.google.zxing.client.android.PreferencesActivity; +import com.google.zxing.client.android.R; +import com.google.zxing.client.android.book.SearchBookContentsActivity; +import com.google.zxing.client.android.wifi.WifiActivity; import com.google.zxing.client.result.ParsedResult; import com.google.zxing.client.result.ParsedResultType; +import com.google.zxing.client.result.WifiParsedResult; +import android.app.Activity; +import android.app.AlertDialog; +import android.app.SearchManager; +import android.content.ActivityNotFoundException; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.preference.PreferenceManager; +import android.provider.Contacts; + +import java.text.DateFormat; import java.text.ParsePosition; import java.text.SimpleDateFormat; import java.util.Calendar; -import java.text.DateFormat; import java.util.Date; import java.util.GregorianCalendar; +/** + * A base class for the Android-specific barcode handlers. These allow the app to polymorphically + * suggest the appropriate actions for each data type. + * + * This class also contains a bunch of utility methods to take common actions like opening a URL. + * They could easily be moved into a helper object, but it can't be static because the Activity + * instance is needed to launch an intent. + * + * @author dswitkin@google.com (Daniel Switkin) + */ public abstract class ResultHandler { - private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMdd"); private static final DateFormat DATE_TIME_FORMAT = new SimpleDateFormat("yyyyMMdd'T'HHmmss"); + private static final String GOOGLE_SHOPPER_PACKAGE = "com.google.android.apps.shopper"; + private static final String GOOGLE_SHOPPER_ACTIVITY = GOOGLE_SHOPPER_PACKAGE + + ".results.SearchResultsActivity"; + private static final String MARKET_URI_PREFIX = "market://search?q=pname:"; + private static final String MARKET_REFERRER_SUFFIX = + "&referrer=utm_source%3Dbarcodescanner%26utm_medium%3Dapps%26utm_campaign%3Dscan"; + public static final int MAX_BUTTON_COUNT = 4; - protected final ParsedResult mResult; - private final Activity mActivity; + private final ParsedResult result; + private final Activity activity; + private final Result rawResult; + private final String customProductSearch; - protected ResultHandler(Activity activity, ParsedResult result) { - mResult = result; - mActivity = activity; + private final DialogInterface.OnClickListener shopperMarketListener = + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialogInterface, int which) { + launchIntent(new Intent(Intent.ACTION_VIEW, Uri.parse(MARKET_URI_PREFIX + + GOOGLE_SHOPPER_PACKAGE + MARKET_REFERRER_SUFFIX))); + } + }; + + ResultHandler(Activity activity, ParsedResult result) { + this(activity, result, null); + } + + ResultHandler(Activity activity, ParsedResult result, Result rawResult) { + this.result = result; + this.activity = activity; + this.rawResult = rawResult; + this.customProductSearch = parseCustomSearchURL(); + } + + ParsedResult getResult() { + return result; + } + + boolean hasCustomProductSearch() { + return customProductSearch != null; } /** @@ -79,7 +131,7 @@ public abstract class ResultHandler { * @return The text to be displayed. */ public CharSequence getDisplayContents() { - String contents = mResult.getDisplayResult(); + String contents = result.getDisplayResult(); return contents.replace("\r", ""); } @@ -96,7 +148,7 @@ public abstract class ResultHandler { * @return The parsed type, e.g. URI or ISBN */ public final ParsedResultType getType() { - return mResult.getType(); + return result.getType(); } /** @@ -106,16 +158,27 @@ public abstract class ResultHandler { * @param summary A description of the event * @param start The start time as yyyyMMdd or yyyyMMdd'T'HHmmss or yyyyMMdd'T'HHmmss'Z' * @param end The end time as yyyyMMdd or yyyyMMdd'T'HHmmss or yyyyMMdd'T'HHmmss'Z' + * @param location a text description of the event location + * @param description a text description of the event itself */ - public final void addCalendarEvent(String summary, String start, String end) { + final void addCalendarEvent(String summary, + String start, + String end, + String location, + String description) { Intent intent = new Intent(Intent.ACTION_EDIT); intent.setType("vnd.android.cursor.item/event"); intent.putExtra("beginTime", calculateMilliseconds(start)); if (start.length() == 8) { intent.putExtra("allDay", true); } + if (end == null) { + end = start; + } intent.putExtra("endTime", calculateMilliseconds(end)); intent.putExtra("title", summary); + intent.putExtra("eventLocation", location); + intent.putExtra("description", description); launchIntent(intent); } @@ -136,19 +199,19 @@ public abstract class ResultHandler { long milliseconds = date.getTime(); if (when.length() == 16 && when.charAt(15) == 'Z') { Calendar calendar = new GregorianCalendar(); - int offset = (calendar.get(java.util.Calendar.ZONE_OFFSET) + - calendar.get(java.util.Calendar.DST_OFFSET)); + int offset = calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET); milliseconds += offset; } return milliseconds; } } - public final void addContact(String[] names, String[] phoneNumbers, String[] emails, String note, + final void addContact(String[] names, String[] phoneNumbers, String[] emails, String note, String address, String org, String title) { + // Only use the first name in the array, if present. Intent intent = new Intent(Contacts.Intents.Insert.ACTION, Contacts.People.CONTENT_URI); - putExtra(intent, Contacts.Intents.Insert.NAME, names); + putExtra(intent, Contacts.Intents.Insert.NAME, names != null ? names[0] : null); int phoneCount = Math.min((phoneNumbers != null) ? phoneNumbers.length : 0, Contents.PHONE_KEYS.length); @@ -168,30 +231,36 @@ public abstract class ResultHandler { launchIntent(intent); } - public final void shareByEmail(String contents) { - sendEmailFromUri("mailto:", mActivity.getString(R.string.msg_share_subject_line), contents); + final void shareByEmail(String contents) { + sendEmailFromUri("mailto:", null, activity.getString(R.string.msg_share_subject_line), contents); } - public final void sendEmail(String address, String subject, String body) { - sendEmailFromUri("mailto:" + address, subject, body); + final void sendEmail(String address, String subject, String body) { + sendEmailFromUri("mailto:" + address, address, subject, body); } - public final void sendEmailFromUri(String uri, String subject, String body) { - Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.parse(uri)); - putExtra(intent, "subject", subject); - putExtra(intent, "body", body); + // Use public Intent fields rather than private GMail app fields to specify subject and body. + final void sendEmailFromUri(String uri, String email, String subject, String body) { + Intent intent = new Intent(Intent.ACTION_SEND, Uri.parse(uri)); + if (email != null) { + intent.putExtra(Intent.EXTRA_EMAIL, new String[] {email}); + } + putExtra(intent, Intent.EXTRA_SUBJECT, subject); + putExtra(intent, Intent.EXTRA_TEXT, body); + intent.setType("text/plain"); launchIntent(intent); } - public final void shareBySMS(String contents) { - sendSMSFromUri("smsto:", mActivity.getString(R.string.msg_share_subject_line) + ":\n" + contents); + final void shareBySMS(String contents) { + sendSMSFromUri("smsto:", activity.getString(R.string.msg_share_subject_line) + ":\n" + + contents); } - public final void sendSMS(String phoneNumber, String body) { + final void sendSMS(String phoneNumber, String body) { sendSMSFromUri("smsto:" + phoneNumber, body); } - public final void sendSMSFromUri(String uri, String body) { + final void sendSMSFromUri(String uri, String body) { Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.parse(uri)); putExtra(intent, "sms_body", body); // Exit the app once the SMS is sent @@ -199,15 +268,15 @@ public abstract class ResultHandler { launchIntent(intent); } - public final void sendMMS(String phoneNumber, String subject, String body) { + final void sendMMS(String phoneNumber, String subject, String body) { sendMMSFromUri("mmsto:" + phoneNumber, subject, body); } - public final void sendMMSFromUri(String uri, String subject, String body) { + final void sendMMSFromUri(String uri, String subject, String body) { Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.parse(uri)); // The Messaging app needs to see a valid subject or else it will treat this an an SMS. if (subject == null || subject.length() == 0) { - putExtra(intent, "subject", mActivity.getString(R.string.msg_default_mms_subject)); + putExtra(intent, "subject", activity.getString(R.string.msg_default_mms_subject)); } else { putExtra(intent, "subject", subject); } @@ -216,15 +285,15 @@ public abstract class ResultHandler { launchIntent(intent); } - public final void dialPhone(String phoneNumber) { + final void dialPhone(String phoneNumber) { launchIntent(new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + phoneNumber))); } - public final void dialPhoneFromUri(String uri) { + final void dialPhoneFromUri(String uri) { launchIntent(new Intent(Intent.ACTION_DIAL, Uri.parse(uri))); } - public final void openMap(String geoURI) { + final void openMap(String geoURI) { launchIntent(new Intent(Intent.ACTION_VIEW, Uri.parse(geoURI))); } @@ -234,7 +303,7 @@ public abstract class ResultHandler { * @param address The address to find * @param title An optional title, e.g. the name of the business at this address */ - public final void searchMap(String address, String title) { + final void searchMap(String address, String title) { String query = address; if (title != null && title.length() > 0) { query = query + " (" + title + ')'; @@ -242,42 +311,82 @@ public abstract class ResultHandler { launchIntent(new Intent(Intent.ACTION_VIEW, Uri.parse("geo:0,0?q=" + Uri.encode(query)))); } - public final void getDirections(float latitude, float longitude) { + final void getDirections(double latitude, double longitude) { launchIntent(new Intent(Intent.ACTION_VIEW, Uri.parse("http://maps.google." + LocaleManager.getCountryTLD() + "/maps?f=d&daddr=" + latitude + ',' + longitude))); } - public final void openProductSearch(String upc) { - Uri uri = Uri.parse("http://www.google." + LocaleManager.getCountryTLD() + "/products?q=" + upc); + // Uses the mobile-specific version of Product Search, which is formatted for small screens. + final void openProductSearch(String upc) { + Uri uri = Uri.parse("http://www.google." + LocaleManager.getProductSearchCountryTLD() + + "/m/products?q=" + upc + "&source=zxing"); launchIntent(new Intent(Intent.ACTION_VIEW, uri)); } - public final void openBookSearch(String isbn) { - Uri uri = Uri.parse("http://books.google." + LocaleManager.getCountryTLD() + "/books?vid=isbn" + - isbn); + final void openBookSearch(String isbn) { + Uri uri = Uri.parse("http://books.google." + LocaleManager.getBookSearchCountryTLD() + + "/books?vid=isbn" + isbn); launchIntent(new Intent(Intent.ACTION_VIEW, uri)); } - public final void searchBookContents(String isbn) { + final void searchBookContents(String isbn) { Intent intent = new Intent(Intents.SearchBookContents.ACTION); - intent.setClassName(mActivity, SearchBookContentsActivity.class.getName()); + intent.setClassName(activity, SearchBookContentsActivity.class.getName()); putExtra(intent, Intents.SearchBookContents.ISBN, isbn); launchIntent(intent); } - public final void openURL(String url) { + final void wifiConnect(WifiParsedResult wifiResult) { + Intent intent = new Intent(Intents.WifiConnect.ACTION); + intent.setClassName(activity, WifiActivity.class.getName()); + putExtra(intent, Intents.WifiConnect.SSID, wifiResult.getSsid()); + putExtra(intent, Intents.WifiConnect.TYPE, wifiResult.getNetworkEncryption()); + putExtra(intent, Intents.WifiConnect.PASSWORD, wifiResult.getPassword()); + launchIntent(intent); + } + + final void openURL(String url) { launchIntent(new Intent(Intent.ACTION_VIEW, Uri.parse(url))); } - public final void webSearch(String query) { + final void webSearch(String query) { Intent intent = new Intent(Intent.ACTION_WEB_SEARCH); intent.putExtra("query", query); launchIntent(intent); } - private void launchIntent(Intent intent) { + final void openGoogleShopper(String query) { + try { + activity.getPackageManager().getPackageInfo(GOOGLE_SHOPPER_PACKAGE, 0); + // If we didn't throw, Shopper is installed, so launch it. + Intent intent = new Intent(Intent.ACTION_SEARCH); + intent.setClassName(GOOGLE_SHOPPER_PACKAGE, GOOGLE_SHOPPER_ACTIVITY); + intent.putExtra(SearchManager.QUERY, query); + activity.startActivity(intent); + } catch (PackageManager.NameNotFoundException e) { + // Otherwise offer to install it from Market. + AlertDialog.Builder builder = new AlertDialog.Builder(activity); + builder.setTitle(R.string.msg_google_shopper_missing); + builder.setMessage(R.string.msg_install_google_shopper); + builder.setIcon(R.drawable.shopper_icon); + builder.setPositiveButton(R.string.button_ok, shopperMarketListener); + builder.setNegativeButton(R.string.button_cancel, null); + builder.show(); + } + } + + void launchIntent(Intent intent) { if (intent != null) { - mActivity.startActivity(intent); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); + try { + activity.startActivity(intent); + } catch (ActivityNotFoundException e) { + AlertDialog.Builder builder = new AlertDialog.Builder(activity); + builder.setTitle(R.string.app_name); + builder.setMessage(R.string.msg_intent_failed); + builder.setPositiveButton(R.string.button_ok, null); + builder.show(); + } } } @@ -287,11 +396,36 @@ public abstract class ResultHandler { } } - // TODO: This is only used by the names field, and only the first name will be taken. - private static void putExtra(Intent intent, String key, String[] value) { - if (value != null && value.length > 0) { - putExtra(intent, key, value[0]); + protected void showNotOurResults(int index, AlertDialog.OnClickListener proceedListener) { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity); + if (prefs.getBoolean(PreferencesActivity.KEY_NOT_OUR_RESULTS_SHOWN, false)) { + // already seen it, just proceed + proceedListener.onClick(null, index); + } else { + // note the user has seen it + prefs.edit().putBoolean(PreferencesActivity.KEY_NOT_OUR_RESULTS_SHOWN, true).commit(); + AlertDialog.Builder builder = new AlertDialog.Builder(activity); + builder.setMessage(R.string.msg_not_our_results); + builder.setPositiveButton(R.string.button_ok, proceedListener); + builder.show(); + } + } + + private String parseCustomSearchURL() { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity); + String customProductSearch = prefs.getString(PreferencesActivity.KEY_CUSTOM_PRODUCT_SEARCH, null); + if (customProductSearch != null && customProductSearch.trim().length() == 0) { + return null; + } + return customProductSearch; + } + + String fillInCustomSearchURL(String text) { + String url = customProductSearch.replace("%s", text); + if (rawResult != null) { + url = url.replace("%f", rawResult.getBarcodeFormat().toString()); } + return url; } -} +} \ No newline at end of file