5c150feae6be0ba6bf90f4ddfd0ea987b946090b
[zxing.git] / android / src / com / google / zxing / client / android / result / ResultHandler.java
1 /*
2  * Copyright (C) 2008 ZXing authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.google.zxing.client.android.result;
18
19 import android.app.Activity;
20 import android.app.AlertDialog;
21 import android.content.ActivityNotFoundException;
22 import android.content.Intent;
23 import android.net.Uri;
24 import android.provider.Contacts;
25 import com.google.zxing.client.android.Intents;
26 import com.google.zxing.client.android.R;
27 import com.google.zxing.client.android.SearchBookContentsActivity;
28 import com.google.zxing.client.android.LocaleManager;
29 import com.google.zxing.client.android.Contents;
30 import com.google.zxing.client.result.ParsedResult;
31 import com.google.zxing.client.result.ParsedResultType;
32
33 import java.text.ParsePosition;
34 import java.text.SimpleDateFormat;
35 import java.util.Calendar;
36 import java.text.DateFormat;
37 import java.util.Date;
38 import java.util.GregorianCalendar;
39
40 public abstract class ResultHandler {
41
42   private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMdd");
43   private static final DateFormat DATE_TIME_FORMAT = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
44
45   public static final int MAX_BUTTON_COUNT = 4;
46
47   protected final ParsedResult mResult;
48   private final Activity mActivity;
49
50   protected ResultHandler(Activity activity, ParsedResult result) {
51     mResult = result;
52     mActivity = activity;
53   }
54
55   /**
56    * Indicates how many buttons the derived class wants shown.
57    *
58    * @return The integer button count.
59    */
60   public abstract int getButtonCount();
61
62   /**
63    * The text of the nth action button.
64    *
65    * @param index From 0 to getButtonCount() - 1
66    * @return The button text as a resource ID
67    */
68   public abstract int getButtonText(int index);
69
70
71   /**
72    * Execute the action which corresponds to the nth button.
73    *
74    * @param index The button that was clicked.
75    */
76   public abstract void handleButtonPress(int index);
77
78   /**
79    * Create a possibly styled string for the contents of the current barcode.
80    *
81    * @return The text to be displayed.
82    */
83   public CharSequence getDisplayContents() {
84     String contents = mResult.getDisplayResult();
85     return contents.replace("\r", "");
86   }
87
88   /**
89    * A string describing the kind of barcode that was found, e.g. "Found contact info".
90    *
91    * @return The resource ID of the string.
92    */
93   public abstract int getDisplayTitle();
94
95   /**
96    * A convenience method to get the parsed type. Should not be overridden.
97    *
98    * @return The parsed type, e.g. URI or ISBN
99    */
100   public final ParsedResultType getType() {
101     return mResult.getType();
102   }
103
104   /**
105    * Sends an intent to create a new calendar event by prepopulating the Add Event UI. Older
106    * versions of the system have a bug where the event title will not be filled out.
107    *
108    * @param summary A description of the event
109    * @param start   The start time as yyyyMMdd or yyyyMMdd'T'HHmmss or yyyyMMdd'T'HHmmss'Z'
110    * @param end     The end time as yyyyMMdd or yyyyMMdd'T'HHmmss or yyyyMMdd'T'HHmmss'Z'
111    */
112   public final void addCalendarEvent(String summary, String start, String end) {
113     Intent intent = new Intent(Intent.ACTION_EDIT);
114     intent.setType("vnd.android.cursor.item/event");
115     intent.putExtra("beginTime", calculateMilliseconds(start));
116     if (start.length() == 8) {
117       intent.putExtra("allDay", true);
118     }
119     intent.putExtra("endTime", calculateMilliseconds(end));
120     intent.putExtra("title", summary);
121     launchIntent(intent);
122   }
123
124   private static long calculateMilliseconds(String when) {
125     if (when.length() == 8) {
126       // Only contains year/month/day
127       Date date;
128       synchronized (DATE_FORMAT) {
129         date = DATE_FORMAT.parse(when, new ParsePosition(0));
130       }
131       return date.getTime();
132     } else {
133       // The when string can be local time, or UTC if it ends with a Z
134       Date date;
135       synchronized (DATE_TIME_FORMAT) {
136        date = DATE_TIME_FORMAT.parse(when.substring(0, 15), new ParsePosition(0));
137       }
138       long milliseconds = date.getTime();
139       if (when.length() == 16 && when.charAt(15) == 'Z') {
140         Calendar calendar = new GregorianCalendar();
141         int offset = (calendar.get(java.util.Calendar.ZONE_OFFSET) +
142             calendar.get(java.util.Calendar.DST_OFFSET));
143         milliseconds += offset;
144       }
145       return milliseconds;
146     }
147   }
148
149   public final void addContact(String[] names, String[] phoneNumbers, String[] emails, String note,
150                          String address, String org, String title) {
151
152     // Only use the first name in the array, if present.
153     Intent intent = new Intent(Contacts.Intents.Insert.ACTION, Contacts.People.CONTENT_URI);
154     putExtra(intent, Contacts.Intents.Insert.NAME, names != null ? names[0] : null);
155
156     int phoneCount = Math.min((phoneNumbers != null) ? phoneNumbers.length : 0,
157         Contents.PHONE_KEYS.length);
158     for (int x = 0; x < phoneCount; x++) {
159       putExtra(intent, Contents.PHONE_KEYS[x], phoneNumbers[x]);
160     }
161
162     int emailCount = Math.min((emails != null) ? emails.length : 0, Contents.EMAIL_KEYS.length);
163     for (int x = 0; x < emailCount; x++) {
164       putExtra(intent, Contents.EMAIL_KEYS[x], emails[x]);
165     }
166
167     putExtra(intent, Contacts.Intents.Insert.NOTES, note);
168     putExtra(intent, Contacts.Intents.Insert.POSTAL, address);
169     putExtra(intent, Contacts.Intents.Insert.COMPANY, org);
170     putExtra(intent, Contacts.Intents.Insert.JOB_TITLE, title);
171     launchIntent(intent);
172   }
173
174   public final void shareByEmail(String contents) {
175     sendEmailFromUri("mailto:", mActivity.getString(R.string.msg_share_subject_line), contents);
176   }
177
178   public final void sendEmail(String address, String subject, String body) {
179     sendEmailFromUri("mailto:" + address, subject, body);
180   }
181
182   // Use public Intent fields rather than private GMail app fields to specify subject and body.
183   public final void sendEmailFromUri(String uri, String subject, String body) {
184     Intent intent = new Intent(Intent.ACTION_SEND, Uri.parse(uri));
185     putExtra(intent, Intent.EXTRA_SUBJECT, subject);
186     putExtra(intent, Intent.EXTRA_TEXT, body);
187     intent.setType("text/plain");
188     launchIntent(intent);
189   }
190
191   public final void shareBySMS(String contents) {
192     sendSMSFromUri("smsto:", mActivity.getString(R.string.msg_share_subject_line) + ":\n" +
193         contents);
194   }
195
196   public final void sendSMS(String phoneNumber, String body) {
197     sendSMSFromUri("smsto:" + phoneNumber, body);
198   }
199
200   public final void sendSMSFromUri(String uri, String body) {
201     Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.parse(uri));
202     putExtra(intent, "sms_body", body);
203     // Exit the app once the SMS is sent
204     intent.putExtra("compose_mode", true);
205     launchIntent(intent);
206   }
207
208   public final void sendMMS(String phoneNumber, String subject, String body) {
209     sendMMSFromUri("mmsto:" + phoneNumber, subject, body);
210   }
211
212   public final void sendMMSFromUri(String uri, String subject, String body) {
213     Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.parse(uri));
214     // The Messaging app needs to see a valid subject or else it will treat this an an SMS.
215     if (subject == null || subject.length() == 0) {
216       putExtra(intent, "subject", mActivity.getString(R.string.msg_default_mms_subject));
217     } else {
218       putExtra(intent, "subject", subject);
219     }
220     putExtra(intent, "sms_body", body);
221     intent.putExtra("compose_mode", true);
222     launchIntent(intent);
223   }
224
225   public final void dialPhone(String phoneNumber) {
226     launchIntent(new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + phoneNumber)));
227   }
228
229   public final void dialPhoneFromUri(String uri) {
230     launchIntent(new Intent(Intent.ACTION_DIAL, Uri.parse(uri)));
231   }
232
233   public final void openMap(String geoURI) {
234     launchIntent(new Intent(Intent.ACTION_VIEW, Uri.parse(geoURI)));
235   }
236
237   /**
238    * Do a geo search using the address as the query.
239    *
240    * @param address The address to find
241    * @param title An optional title, e.g. the name of the business at this address
242    */
243   public final void searchMap(String address, String title) {
244     String query = address;
245     if (title != null && title.length() > 0) {
246       query = query + " (" + title + ')';
247     }
248     launchIntent(new Intent(Intent.ACTION_VIEW, Uri.parse("geo:0,0?q=" + Uri.encode(query))));
249   }
250
251   public final void getDirections(double latitude, double longitude) {
252     launchIntent(new Intent(Intent.ACTION_VIEW, Uri.parse("http://maps.google." +
253         LocaleManager.getCountryTLD() + "/maps?f=d&daddr=" + latitude + ',' + longitude)));
254   }
255
256   // Uses the mobile-specific version of Product Search, which is formatted for small screens.
257   public final void openProductSearch(String upc) {
258     Uri uri = Uri.parse("http://www.google." + LocaleManager.getProductSearchCountryTLD() +
259         "/m/products?q=" + upc + "&source=zxing");
260     launchIntent(new Intent(Intent.ACTION_VIEW, uri));
261   }
262
263   public final void openBookSearch(String isbn) {
264     Uri uri = Uri.parse("http://books.google." + LocaleManager.getCountryTLD() + "/books?vid=isbn" +
265         isbn);
266     launchIntent(new Intent(Intent.ACTION_VIEW, uri));
267   }
268
269   public final void searchBookContents(String isbn) {
270     Intent intent = new Intent(Intents.SearchBookContents.ACTION);
271     intent.setClassName(mActivity, SearchBookContentsActivity.class.getName());
272     putExtra(intent, Intents.SearchBookContents.ISBN, isbn);
273     launchIntent(intent);
274   }
275
276   public final void openURL(String url) {
277     launchIntent(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
278   }
279
280   public final void webSearch(String query) {
281     Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
282     intent.putExtra("query", query);
283     launchIntent(intent);
284   }
285
286   private void launchIntent(Intent intent) {
287     if (intent != null) {
288       try {
289         mActivity.startActivity(intent);
290       } catch (ActivityNotFoundException e) {
291         AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
292         builder.setTitle(mActivity.getString(R.string.app_name));
293         builder.setMessage(mActivity.getString(R.string.msg_intent_failed));
294         builder.setPositiveButton(R.string.button_ok, null);
295         builder.show();
296       }
297     }
298   }
299
300   private static void putExtra(Intent intent, String key, String value) {
301     if (value != null && value.length() > 0) {
302       intent.putExtra(key, value);
303     }
304   }
305
306 }