2 * Copyright 2009 ZXing authors
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package org
.netxms
.ui
.android
.tools
;
19 import java
.util
.ArrayList
;
20 import java
.util
.Arrays
;
21 import java
.util
.Collection
;
22 import java
.util
.Collections
;
23 import java
.util
.List
;
25 import android
.app
.Activity
;
26 import android
.app
.AlertDialog
;
27 import android
.content
.ActivityNotFoundException
;
28 import android
.content
.DialogInterface
;
29 import android
.content
.Intent
;
30 import android
.content
.pm
.PackageManager
;
31 import android
.content
.pm
.ResolveInfo
;
32 import android
.net
.Uri
;
33 import android
.util
.Log
;
37 * A utility class which helps ease integration with Barcode Scanner via {@link Intent}s. This is a simple way to invoke barcode
38 * scanning and receive the result, without any need to integrate, modify, or learn the project's source code.
41 * <h2>Initiating a barcode scan</h2>
44 * To integrate, create an instance of {@code IntentIntegrator} and call {@link #initiateScan()} and wait for the result in your
49 * It does require that the Barcode Scanner (or work-alike) application is installed. The {@link #initiateScan()} method will prompt
50 * the user to download the application, if needed.
54 * There are a few steps to using this integration. First, your {@link Activity} must implement the method
55 * {@link Activity#onActivityResult(int, int, Intent)} and include a line of code like this:
60 * public void onActivityResult(int requestCode, int resultCode, Intent intent) {
61 * IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
62 * if (scanResult != null) {
63 * // handle scan result
65 * // else continue with any other code you need in the method
72 * This is where you will handle a scan result.
76 * Second, just call this in response to a user action somewhere to begin the scan process:
82 * IntentIntegrator integrator = new IntentIntegrator(yourActivity);
83 * integrator.initiateScan();
88 * Note that {@link #initiateScan()} returns an {@link AlertDialog} which is non-null if the user was prompted to download the
89 * application. This lets the calling app potentially manage the dialog. In particular, ideally, the app dismisses the dialog if
90 * it's still active in its {@link Activity#onPause()} method.
94 * You can use {@link #setTitle(String)} to customize the title of this download prompt dialog (or, use {@link #setTitleByID(int)}
95 * to set the title by string resource ID.) Likewise, the prompt message, and yes/no button labels can be changed.
99 * By default, this will only allow applications that are known to respond to this intent correctly do so. The apps that are allowed
100 * to response can be set with {@link #setTargetApplications(Collection)}. For example, set to {@link #TARGET_BARCODE_SCANNER_ONLY}
101 * to only target the Barcode Scanner app itself.
104 * <h2>Sharing text via barcode</h2>
107 * To share text, encoded as a QR Code on-screen, similarly, see {@link #shareText(CharSequence)}.
111 * Some code, particularly download integration, was contributed from the Anobiit application.
116 * @author Isaac Potoczny-Jones
117 * @author Brad Drehmer
120 public class BarcodeScannerIntegrator
123 public static final int REQUEST_CODE
= 0x0000c0de; // Only use bottom 16 bits
124 private static final String TAG
= BarcodeScannerIntegrator
.class.getSimpleName();
126 public static final String DEFAULT_TITLE
= "Install Barcode Scanner?";
127 public static final String DEFAULT_MESSAGE
= "This application requires Barcode Scanner. Would you like to install it?";
128 public static final String DEFAULT_YES
= "Yes";
129 public static final String DEFAULT_NO
= "No";
131 private static final String BS_PACKAGE
= "com.google.zxing.client.android";
133 // supported barcode formats
134 public static final Collection
<String
> PRODUCT_CODE_TYPES
= list("UPC_A", "UPC_E", "EAN_8", "EAN_13", "RSS_14");
135 public static final Collection
<String
> ONE_D_CODE_TYPES
= list("UPC_A", "UPC_E", "EAN_8", "EAN_13", "CODE_39", "CODE_93",
136 "CODE_128", "ITF", "RSS_14", "RSS_EXPANDED");
137 public static final Collection
<String
> QR_CODE_TYPES
= Collections
.singleton("QR_CODE");
138 public static final Collection
<String
> DATA_MATRIX_TYPES
= Collections
.singleton("DATA_MATRIX");
140 public static final Collection
<String
> ALL_CODE_TYPES
= null;
142 public static final Collection
<String
> TARGET_BARCODE_SCANNER_ONLY
= Collections
.singleton(BS_PACKAGE
);
143 public static final Collection
<String
> TARGET_ALL_KNOWN
= list(BS_PACKAGE
, // Barcode Scanner
144 "com.srowen.bs.android", // Barcode Scanner+
145 "com.srowen.bs.android.simple" // Barcode Scanner+ Simple
146 // TODO add more -- what else supports this intent?
149 private final Activity activity
;
150 private String title
;
151 private String message
;
152 private String buttonYes
;
153 private String buttonNo
;
154 private Collection
<String
> targetApplications
;
156 public BarcodeScannerIntegrator(Activity activity
)
158 this.activity
= activity
;
159 title
= DEFAULT_TITLE
;
160 message
= DEFAULT_MESSAGE
;
161 buttonYes
= DEFAULT_YES
;
162 buttonNo
= DEFAULT_NO
;
163 targetApplications
= TARGET_ALL_KNOWN
;
166 public String
getTitle()
171 public void setTitle(String title
)
176 public void setTitleByID(int titleID
)
178 title
= activity
.getString(titleID
);
181 public String
getMessage()
186 public void setMessage(String message
)
188 this.message
= message
;
191 public void setMessageByID(int messageID
)
193 message
= activity
.getString(messageID
);
196 public String
getButtonYes()
201 public void setButtonYes(String buttonYes
)
203 this.buttonYes
= buttonYes
;
206 public void setButtonYesByID(int buttonYesID
)
208 buttonYes
= activity
.getString(buttonYesID
);
211 public String
getButtonNo()
216 public void setButtonNo(String buttonNo
)
218 this.buttonNo
= buttonNo
;
221 public void setButtonNoByID(int buttonNoID
)
223 buttonNo
= activity
.getString(buttonNoID
);
226 public Collection
<String
> getTargetApplications()
228 return targetApplications
;
231 public void setTargetApplications(Collection
<String
> targetApplications
)
233 this.targetApplications
= targetApplications
;
236 public void setSingleTargetApplication(String targetApplication
)
238 this.targetApplications
= Collections
.singleton(targetApplication
);
242 * Initiates a scan for all known barcode types.
244 public AlertDialog
initiateScan()
246 List
<String
> formats
= new ArrayList
<String
>();
247 formats
.addAll(PRODUCT_CODE_TYPES
);
248 formats
.addAll(ONE_D_CODE_TYPES
);
249 formats
.addAll(QR_CODE_TYPES
);
250 formats
.addAll(DATA_MATRIX_TYPES
);
251 return initiateScan(formats
);
255 * Initiates a scan only for a certain set of barcode types, given as strings corresponding to their names in ZXing's
256 * {@code BarcodeFormat} class like "UPC_A". You can supply constants like {@link #PRODUCT_CODE_TYPES} for example.
258 public AlertDialog
initiateScan(Collection
<String
> desiredBarcodeFormats
)
260 Intent intentScan
= new Intent(BS_PACKAGE
+ ".SCAN");
261 intentScan
.addCategory(Intent
.CATEGORY_DEFAULT
);
263 // check which types of codes to scan for
264 if (desiredBarcodeFormats
!= null)
266 // set the desired barcode types
267 StringBuilder joinedByComma
= new StringBuilder();
268 for (String format
: desiredBarcodeFormats
)
270 if (joinedByComma
.length() > 0)
272 joinedByComma
.append(',');
274 joinedByComma
.append(format
);
276 intentScan
.putExtra("SCAN_FORMATS", joinedByComma
.toString());
279 String targetAppPackage
= findTargetAppPackage(intentScan
);
280 if (targetAppPackage
== null)
282 return showDownloadDialog();
284 intentScan
.setPackage(targetAppPackage
);
285 intentScan
.addFlags(Intent
.FLAG_ACTIVITY_CLEAR_TOP
);
286 intentScan
.addFlags(Intent
.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
);
287 intentScan
.putExtra("SCAN_MODE", "PRODUCT_MODE");
288 intentScan
.putExtra("RESULT_DISPLAY_DURATION_MS", 1000L);
289 startActivityForResult(intentScan
, REQUEST_CODE
);
294 * Start an activity.<br>
295 * This method is defined to allow different methods of activity starting for newer versions of Android and for compatibility
298 * @param intent Intent to start.
299 * @param code Request code for the activity
300 * @see android.app.Activity#startActivityForResult(Intent, int)
301 * @see android.app.Fragment#startActivityForResult(Intent, int)
303 protected void startActivityForResult(Intent intent
, int code
)
305 activity
.startActivityForResult(intent
, code
);
308 private String
findTargetAppPackage(Intent intent
)
310 PackageManager pm
= activity
.getPackageManager();
311 List
<ResolveInfo
> availableApps
= pm
.queryIntentActivities(intent
, PackageManager
.MATCH_DEFAULT_ONLY
);
312 if (availableApps
!= null)
314 for (ResolveInfo availableApp
: availableApps
)
316 String packageName
= availableApp
.activityInfo
.packageName
;
317 if (targetApplications
.contains(packageName
))
326 private AlertDialog
showDownloadDialog()
328 AlertDialog
.Builder downloadDialog
= new AlertDialog
.Builder(activity
);
329 downloadDialog
.setTitle(title
);
330 downloadDialog
.setMessage(message
);
331 downloadDialog
.setPositiveButton(buttonYes
, new DialogInterface
.OnClickListener()
334 public void onClick(DialogInterface dialogInterface
, int i
)
336 Uri uri
= Uri
.parse("market://details?id=" + BS_PACKAGE
);
337 Intent intent
= new Intent(Intent
.ACTION_VIEW
, uri
);
340 activity
.startActivity(intent
);
342 catch (ActivityNotFoundException anfe
)
344 // Hmm, market is not installed
345 Log
.e(TAG
, "Android Market is not installed; cannot install Barcode Scanner");
349 downloadDialog
.setNegativeButton(buttonNo
, new DialogInterface
.OnClickListener()
352 public void onClick(DialogInterface dialogInterface
, int i
)
356 return downloadDialog
.show();
361 * Call this from your {@link Activity}'s {@link Activity#onActivityResult(int, int, Intent)} method.
364 * @return null if the event handled here was not related to this class, or else an {@link BarcodeScannerIntentResult} containing
365 * the result of the scan. If the user cancelled scanning, the fields will be null.
367 public static BarcodeScannerIntentResult
parseActivityResult(int requestCode
, int resultCode
, Intent intent
)
369 if (requestCode
== REQUEST_CODE
)
371 if (resultCode
== Activity
.RESULT_OK
)
373 String contents
= intent
.getStringExtra("SCAN_RESULT");
374 String formatName
= intent
.getStringExtra("SCAN_RESULT_FORMAT");
375 byte[] rawBytes
= intent
.getByteArrayExtra("SCAN_RESULT_BYTES");
376 int intentOrientation
= intent
.getIntExtra("SCAN_RESULT_ORIENTATION", Integer
.MIN_VALUE
);
377 Integer orientation
= intentOrientation
== Integer
.MIN_VALUE ?
null : intentOrientation
;
378 String errorCorrectionLevel
= intent
.getStringExtra("SCAN_RESULT_ERROR_CORRECTION_LEVEL");
379 return new BarcodeScannerIntentResult(contents
, formatName
, rawBytes
, orientation
, errorCorrectionLevel
);
381 return new BarcodeScannerIntentResult();
387 * Shares the given text by encoding it as a barcode, such that another user can scan the text off the screen of the device.
389 * @param text the text string to encode as a barcode
391 public void shareText(CharSequence text
)
393 Intent intent
= new Intent();
394 intent
.addCategory(Intent
.CATEGORY_DEFAULT
);
395 intent
.setAction(BS_PACKAGE
+ ".ENCODE");
396 intent
.putExtra("ENCODE_TYPE", "TEXT_TYPE");
397 intent
.putExtra("ENCODE_DATA", text
);
398 String targetAppPackage
= findTargetAppPackage(intent
);
399 if (targetAppPackage
== null)
401 showDownloadDialog();
405 intent
.setPackage(targetAppPackage
);
406 intent
.addFlags(Intent
.FLAG_ACTIVITY_CLEAR_TOP
);
407 intent
.addFlags(Intent
.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
);
408 activity
.startActivity(intent
);
412 private static Collection
<String
> list(String
... values
)
414 return Collections
.unmodifiableCollection(Arrays
.asList(values
));