b92f86c74b63520e3c07d7507108cc6adb31ca23
[zxing.git] / android-integration / src / com / google / zxing / integration / android / IntentIntegrator.java
1 /*
2  * Copyright 2009 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.integration.android;
18
19 import android.app.AlertDialog;
20 import android.app.Activity;
21 import android.content.ActivityNotFoundException;
22 import android.content.DialogInterface;
23 import android.content.Intent;
24 import android.net.Uri;
25
26 /**
27  * <p>A utility class which helps ease integration with Barcode Scanner via {@link Intent}s. This is a simple
28  * way to invoke barcode scanning and receive the result, without any need to integrate, modify, or learn the
29  * project's source code.</p>
30  *
31  * <h2>Initiating a barcode scan</h2>
32  *
33  * <p>Integration is essentially as easy as calling {@link #initiateScan(Activity)} and waiting
34  * for the result in your app.</p>
35  *
36  * <p>It does require that the Barcode Scanner application is installed. The
37  * {@link #initiateScan(Activity)} method will prompt the user to download the application, if needed.</p>
38  *
39  * <p>There are a few steps to using this integration. First, your {@link Activity} must implement
40  * the method {@link Activity#onActivityResult(int, int, Intent)} and include a line of code like this:</p>
41  *
42  * <p>{@code
43  * public void onActivityResult(int requestCode, int resultCode, Intent intent) {
44  *   IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
45  *   if (scanResult != null) {
46  *     // handle scan result
47  *   }
48  *   // else continue with any other code you need in the method
49  *   ...
50  * }
51  * }</p>
52  *
53  * <p>This is where you will handle a scan result.
54  * Second, just call this in response to a user action somewhere to begin the scan process:</p>
55  *
56  * <p>{@code IntentIntegrator.initiateScan(yourActivity);}</p>
57  *
58  * <p>You can use {@link #initiateScan(Activity, CharSequence, CharSequence, CharSequence, CharSequence)} or
59  * {@link #initiateScan(Activity, int, int, int, int)} to customize the download prompt with
60  * different text labels.</p>
61  *
62  * <p>Note that {@link #initiateScan(Activity)} returns an {@link AlertDialog} which is non-null if the
63  * user was prompted to download the application. This lets the calling app potentially manage the dialog.
64  * In particular, ideally, the app dismisses the dialog if it's still active in its {@link Activity#onPause()}
65  * method.</p>
66  *
67  * <h2>Sharing text via barcode</h2>
68  *
69  * <p>To share text, encoded as a QR Code on-screen, similarly, see {@link #shareText(Activity, CharSequence)}.</p>
70  *
71  * <p>Some code, particularly download integration, was contributed from the Anobiit application.</p>
72  *
73  * @author Sean Owen
74  * @author Fred Lin
75  * @author Isaac Potoczny-Jones
76  * @author Brad Drehmer
77  */
78 public final class IntentIntegrator {
79
80   public static final int REQUEST_CODE = 0x0ba7c0de; // get it?
81
82   public static final String DEFAULT_TITLE = "Install Barcode Scanner?";
83   public static final String DEFAULT_MESSAGE =
84       "This application requires Barcode Scanner. Would you like to install it?";
85   public static final String DEFAULT_YES = "Yes";
86   public static final String DEFAULT_NO = "No";
87
88   // supported barcode formats
89   public static final String PRODUCT_CODE_TYPES = "UPC_A,UPC_E,EAN_8,EAN_13";
90   public static final String ONE_D_CODE_TYPES = PRODUCT_CODE_TYPES + ",CODE_39,CODE_128";
91   public static final String QR_CODE_TYPES = "QR_CODE";
92   public static final String ALL_CODE_TYPES = null;
93
94   private IntentIntegrator() {
95   }
96
97   /**
98    * See {@link #initiateScan(Activity, CharSequence, CharSequence, CharSequence, CharSequence)} --
99    * same, but uses default English labels.
100    */
101   public static AlertDialog initiateScan(Activity activity) {
102     return initiateScan(activity, DEFAULT_TITLE, DEFAULT_MESSAGE, DEFAULT_YES, DEFAULT_NO);
103   }
104
105   /**
106    * See {@link #initiateScan(Activity, CharSequence, CharSequence, CharSequence, CharSequence)} --
107    * same, but takes string IDs which refer
108    * to the {@link Activity}'s resource bundle entries.
109    */
110   public static AlertDialog initiateScan(Activity activity,
111                                          int stringTitle,
112                                          int stringMessage,
113                                          int stringButtonYes,
114                                          int stringButtonNo) {
115     return initiateScan(activity,
116                         activity.getString(stringTitle),
117                         activity.getString(stringMessage),
118                         activity.getString(stringButtonYes),
119                         activity.getString(stringButtonNo));
120   }
121
122   /**
123    * See {@link #initiateScan(Activity, CharSequence, CharSequence, CharSequence, CharSequence, CharSequence)} --
124    * same, but scans for all supported barcode types.
125    * @param stringTitle title of dialog prompting user to download Barcode Scanner
126    * @param stringMessage text of dialog prompting user to download Barcode Scanner
127    * @param stringButtonYes text of button user clicks when agreeing to download
128    *  Barcode Scanner (e.g. "Yes")
129    * @param stringButtonNo text of button user clicks when declining to download
130    *  Barcode Scanner (e.g. "No")
131    * @return an {@link AlertDialog} if the user was prompted to download the app,
132    *  null otherwise
133    */
134   public static AlertDialog initiateScan(Activity activity,
135                                          CharSequence stringTitle,
136                                          CharSequence stringMessage,
137                                          CharSequence stringButtonYes,
138                                          CharSequence stringButtonNo) {
139
140     return initiateScan(activity,
141                         stringTitle,
142                         stringMessage,
143                         stringButtonYes,
144                         stringButtonNo,
145                         ALL_CODE_TYPES);
146   }
147
148   /**
149    * Invokes scanning.
150    *
151    * @param stringTitle title of dialog prompting user to download Barcode Scanner
152    * @param stringMessage text of dialog prompting user to download Barcode Scanner
153    * @param stringButtonYes text of button user clicks when agreeing to download
154    *  Barcode Scanner (e.g. "Yes")
155    * @param stringButtonNo text of button user clicks when declining to download
156    *  Barcode Scanner (e.g. "No")
157    * @param stringDesiredBarcodeFormats a comma separated list of codes you would
158    *  like to scan for.
159    * @return an {@link AlertDialog} if the user was prompted to download the app,
160    *  null otherwise
161    * @throws InterruptedException if timeout expires before a scan completes
162    */
163   public static AlertDialog initiateScan(Activity activity,
164                                          CharSequence stringTitle,
165                                          CharSequence stringMessage,
166                                          CharSequence stringButtonYes,
167                                          CharSequence stringButtonNo,
168                                          CharSequence stringDesiredBarcodeFormats) {
169     Intent intentScan = new Intent("com.google.zxing.client.android.SCAN");
170     intentScan.addCategory(Intent.CATEGORY_DEFAULT);
171
172     // check which types of codes to scan for
173     if (stringDesiredBarcodeFormats != null) {
174       // set the desired barcode types
175       intentScan.putExtra("SCAN_FORMATS", stringDesiredBarcodeFormats);
176     }
177
178     try {
179       activity.startActivityForResult(intentScan, REQUEST_CODE);
180       return null;
181     } catch (ActivityNotFoundException e) {
182       return showDownloadDialog(activity, stringTitle, stringMessage, stringButtonYes, stringButtonNo);
183     }
184   }
185
186   private static AlertDialog showDownloadDialog(final Activity activity,
187                                                 CharSequence stringTitle,
188                                                 CharSequence stringMessage,
189                                                 CharSequence stringButtonYes,
190                                                 CharSequence stringButtonNo) {
191     AlertDialog.Builder downloadDialog = new AlertDialog.Builder(activity);
192     downloadDialog.setTitle(stringTitle);
193     downloadDialog.setMessage(stringMessage);
194     downloadDialog.setPositiveButton(stringButtonYes, new DialogInterface.OnClickListener() {
195       public void onClick(DialogInterface dialogInterface, int i) {
196         Uri uri = Uri.parse("market://search?q=pname:com.google.zxing.client.android");
197         Intent intent = new Intent(Intent.ACTION_VIEW, uri);
198         activity.startActivity(intent);
199       }
200     });
201     downloadDialog.setNegativeButton(stringButtonNo, new DialogInterface.OnClickListener() {
202       public void onClick(DialogInterface dialogInterface, int i) {}
203     });
204     return downloadDialog.show();
205   }
206
207
208   /**
209    * <p>Call this from your {@link Activity}'s
210    * {@link Activity#onActivityResult(int, int, Intent)} method.</p>
211    *
212    * @return null if the event handled here was not related to {@link IntentIntegrator}, or
213    *  else an {@link IntentResult} containing the result of the scan. If the user cancelled scanning,
214    *  the fields will be null.
215    */
216   public static IntentResult parseActivityResult(int requestCode, int resultCode, Intent intent) {
217     if (requestCode == REQUEST_CODE) {
218       if (resultCode == Activity.RESULT_OK) {
219         String contents = intent.getStringExtra("SCAN_RESULT");
220         String formatName = intent.getStringExtra("SCAN_RESULT_FORMAT");
221         return new IntentResult(contents, formatName);
222       } else {
223         return new IntentResult(null, null);
224       }
225     }
226     return null;
227   }
228
229   /**
230    * See {@link #shareText(Activity, CharSequence, CharSequence, CharSequence, CharSequence, CharSequence)} --
231    * same, but uses default English labels.
232    */
233   public static void shareText(Activity activity, CharSequence text) {
234     shareText(activity, text, DEFAULT_TITLE, DEFAULT_MESSAGE, DEFAULT_YES, DEFAULT_NO);
235   }
236
237   /**
238    * See {@link #shareText(Activity, CharSequence, CharSequence, CharSequence, CharSequence, CharSequence)} --
239    * same, but takes string IDs which refer to the {@link Activity}'s resource bundle entries.
240    */
241   public static void shareText(Activity activity,
242                                CharSequence text,
243                                int stringTitle,
244                                int stringMessage,
245                                int stringButtonYes,
246                                int stringButtonNo) {
247     shareText(activity,
248               text,
249               activity.getString(stringTitle),
250               activity.getString(stringMessage),
251               activity.getString(stringButtonYes),
252               activity.getString(stringButtonNo));
253   }
254
255   /**
256    * Shares the given text by encoding it as a barcode, such that another user can
257    * scan the text off the screen of the device.
258    *
259    * @param text the text string to encode as a barcode
260    * @param stringTitle title of dialog prompting user to download Barcode Scanner
261    * @param stringMessage text of dialog prompting user to download Barcode Scanner
262    * @param stringButtonYes text of button user clicks when agreeing to download
263    *  Barcode Scanner (e.g. "Yes")
264    * @param stringButtonNo text of button user clicks when declining to download
265    *  Barcode Scanner (e.g. "No")
266    */
267   public static void shareText(Activity activity,
268                                CharSequence text,
269                                CharSequence stringTitle,
270                                CharSequence stringMessage,
271                                CharSequence stringButtonYes,
272                                CharSequence stringButtonNo) {
273
274     Intent intent = new Intent();
275     intent.setAction("com.google.zxing.client.android.ENCODE");
276     intent.putExtra("ENCODE_TYPE", "TEXT_TYPE");
277     intent.putExtra("ENCODE_DATA", text);
278     try {
279       activity.startActivity(intent);
280     } catch (ActivityNotFoundException e) {
281       showDownloadDialog(activity, stringTitle, stringMessage, stringButtonYes, stringButtonNo);
282     }
283   }
284
285 }