//
// Copyright 2009 ZXing authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package com.google.zxing.integration.android;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
/**
* <p>
* A utility class which helps ease integration with Barcode Scanner via
* {@link Intent}s. This is a simple way to invoke barcode scanning and receive
* the result, without any need to integrate, modify, or learn the project's
* source code.
* </p>
* <h2>Initiating a barcode scan</h2>
* <p>
* Integration is essentially as easy as calling {@link #initiateScan(Activity)}
* and waiting for the result in your app.
* </p>
* <p>
* It does require that the Barcode Scanner application is installed. The
* {@link #initiateScan(Activity)} method will prompt the user to download the
* application, if needed.
* </p>
* <p>
* There are a few steps to using this integration. First, your {@link Activity}
* must implement the method {@link Activity#onActivityResult(int, int, Intent)}
* and include a line of code like this:
* </p>
*
* <pre>
* {@code
* public void onActivityResult(int requestCode, int resultCode, Intent intent) {
* IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
* if (scanResult != null) {
* // handle scan result
* }
* // else continue with any other code you need in the method
* ...
* }
* }
* </pre>
* <p>
* This is where you will handle a scan result. Second, just call this in
* response to a user action somewhere to begin the scan process:
* </p>
*
* <pre>
* {@code IntentIntegrator.initiateScan(yourActivity);}
* </pre>
* <p>
* You can use
* {@link #initiateScan(Activity, CharSequence, CharSequence, CharSequence, CharSequence)}
* or {@link #initiateScan(Activity, int, int, int, int)} to customize the
* download prompt with different text labels.
* </p>
* <p>
* Note that {@link #initiateScan(Activity)} returns an {@link AlertDialog}
* which is non-null if the user was prompted to download the application. This
* lets the calling app potentially manage the dialog. In particular, ideally,
* the app dismisses the dialog if it's still active in its
* {@link Activity#onPause()} method.
* </p>
* <h2>Sharing text via barcode</h2>
* <p>
* To share text, encoded as a QR Code on-screen, similarly, see
* {@link #shareText(Activity, CharSequence)}.
* </p>
* <p>
* Some code, particularly download integration, was contributed from the
* Anobiit application.
* </p>
*
* @author Sean Owen
* @author Fred Lin
* @author Isaac Potoczny-Jones
* @author Brad Drehmer
* @author gcstang
*/
public final class IntentIntegrator {
public static final int REQUEST_CODE = 0x0ba7c0de; // get it?
public static final String DEFAULT_TITLE = "Install Barcode Scanner?";
public static final String DEFAULT_MESSAGE = "This application requires Barcode Scanner. Would you like to install it?";
public static final String DEFAULT_YES = "Yes";
public static final String DEFAULT_NO = "No";
private static final String PACKAGE = "com.google.zxing.client.android";
// supported barcode formats
public static final String PRODUCT_CODE_TYPES = "UPC_A,UPC_E,EAN_8,EAN_13";
public static final String ONE_D_CODE_TYPES = PRODUCT_CODE_TYPES
+ ",CODE_39,CODE_93,CODE_128";
public static final String QR_CODE_TYPES = "QR_CODE";
public static final String ALL_CODE_TYPES = null;
private IntentIntegrator() {
}
/**
* See
* {@link #initiateScan(Activity, CharSequence, CharSequence, CharSequence, CharSequence)}
* -- same, but uses default English labels.
*/
public static AlertDialog initiateScan(Activity activity) {
return initiateScan(activity, DEFAULT_TITLE, DEFAULT_MESSAGE,
DEFAULT_YES, DEFAULT_NO);
}
/**
* See
* {@link #initiateScan(Activity, CharSequence, CharSequence, CharSequence, CharSequence)}
* -- same, but takes string IDs which refer to the {@link Activity}'s
* resource bundle entries.
*/
public static AlertDialog initiateScan(Activity activity, int stringTitle,
int stringMessage, int stringButtonYes, int stringButtonNo) {
return initiateScan(activity, activity.getString(stringTitle),
activity.getString(stringMessage),
activity.getString(stringButtonYes),
activity.getString(stringButtonNo));
}
/**
* See
* {@link #initiateScan(Activity, CharSequence, CharSequence, CharSequence, CharSequence, CharSequence)}
* -- same, but scans for all supported barcode types.
*
* @param stringTitle
* title of dialog prompting user to download Barcode Scanner
* @param stringMessage
* text of dialog prompting user to download Barcode Scanner
* @param stringButtonYes
* text of button user clicks when agreeing to download Barcode
* Scanner (e.g. "Yes")
* @param stringButtonNo
* text of button user clicks when declining to download Barcode
* Scanner (e.g. "No")
* @return an {@link AlertDialog} if the user was prompted to download the
* app, null otherwise
*/
public static AlertDialog initiateScan(Activity activity,
CharSequence stringTitle, CharSequence stringMessage,
CharSequence stringButtonYes, CharSequence stringButtonNo) {
return initiateScan(activity, stringTitle, stringMessage,
stringButtonYes, stringButtonNo, ALL_CODE_TYPES);
}
/**
* Invokes scanning.
*
* @param stringTitle
* title of dialog prompting user to download Barcode Scanner
* @param stringMessage
* text of dialog prompting user to download Barcode Scanner
* @param stringButtonYes
* text of button user clicks when agreeing to download Barcode
* Scanner (e.g. "Yes")
* @param stringButtonNo
* text of button user clicks when declining to download Barcode
* Scanner (e.g. "No")
* @param stringDesiredBarcodeFormats
* a comma separated list of codes you would like to scan for.
* @return an {@link AlertDialog} if the user was prompted to download the
* app, null otherwise
* @throws InterruptedException
* if timeout expires before a scan completes
*/
public static AlertDialog initiateScan(Activity activity,
CharSequence stringTitle, CharSequence stringMessage,
CharSequence stringButtonYes, CharSequence stringButtonNo,
CharSequence stringDesiredBarcodeFormats) {
Intent intentScan = new Intent(PACKAGE + ".SCAN");
intentScan.setPackage(PACKAGE);
intentScan.addCategory(Intent.CATEGORY_DEFAULT);
// check which types of codes to scan for
if (stringDesiredBarcodeFormats != null) {
// set the desired barcode types
intentScan.putExtra("SCAN_FORMATS", stringDesiredBarcodeFormats);
}
try {
activity.startActivityForResult(intentScan, REQUEST_CODE);
return null;
} catch (ActivityNotFoundException e) {
return showDownloadDialog(activity, stringTitle, stringMessage,
stringButtonYes, stringButtonNo);
}
}
private static AlertDialog showDownloadDialog(final Activity activity,
CharSequence stringTitle, CharSequence stringMessage,
CharSequence stringButtonYes, CharSequence stringButtonNo) {
AlertDialog.Builder downloadDialog = new AlertDialog.Builder(activity);
downloadDialog.setTitle(stringTitle);
downloadDialog.setMessage(stringMessage);
downloadDialog.setPositiveButton(stringButtonYes,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogInterface, int i) {
Uri uri = Uri.parse("market://search?q=pname:"
+ PACKAGE);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
activity.startActivity(intent);
}
});
downloadDialog.setNegativeButton(stringButtonNo,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogInterface, int i) {
}
});
return downloadDialog.show();
}
/**
* <p>
* Call this from your {@link Activity}'s
* {@link Activity#onActivityResult(int, int, Intent)} method.
* </p>
*
* @return null if the event handled here was not related to this class, or
* else an {@link IntentResult} containing the result of the scan.
* If the user cancelled scanning, the fields will be null.
*/
public static IntentResult parseActivityResult(int requestCode,
int resultCode, Intent intent) {
if (requestCode == REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK) {
String contents = intent.getStringExtra("SCAN_RESULT");
String formatName = intent.getStringExtra("SCAN_RESULT_FORMAT");
return new IntentResult(contents, formatName);
} else {
return new IntentResult(null, null);
}
}
return null;
}
/**
* See
* {@link #shareText(Activity, CharSequence, CharSequence, CharSequence, CharSequence, CharSequence)}
* -- same, but uses default English labels.
*/
public static void shareText(Activity activity, CharSequence text) {
shareText(activity, text, DEFAULT_TITLE, DEFAULT_MESSAGE, DEFAULT_YES,
DEFAULT_NO);
}
/**
* See
* {@link #shareText(Activity, CharSequence, CharSequence, CharSequence, CharSequence, CharSequence)}
* -- same, but takes string IDs which refer to the {@link Activity}'s
* resource bundle entries.
*/
public static void shareText(Activity activity, CharSequence text,
int stringTitle, int stringMessage, int stringButtonYes,
int stringButtonNo) {
shareText(activity, text, activity.getString(stringTitle),
activity.getString(stringMessage),
activity.getString(stringButtonYes),
activity.getString(stringButtonNo));
}
/**
* Shares the given text by encoding it as a barcode, such that another user
* can scan the text off the screen of the device.
*
* @param text
* the text string to encode as a barcode
* @param stringTitle
* title of dialog prompting user to download Barcode Scanner
* @param stringMessage
* text of dialog prompting user to download Barcode Scanner
* @param stringButtonYes
* text of button user clicks when agreeing to download Barcode
* Scanner (e.g. "Yes")
* @param stringButtonNo
* text of button user clicks when declining to download Barcode
* Scanner (e.g. "No")
*/
public static void shareText(Activity activity, CharSequence text,
CharSequence stringTitle, CharSequence stringMessage,
CharSequence stringButtonYes, CharSequence stringButtonNo) {
Intent intent = new Intent();
intent.setAction(PACKAGE + ".ENCODE");
intent.setPackage(PACKAGE);
intent.putExtra("ENCODE_TYPE", "TEXT_TYPE");
intent.putExtra("ENCODE_DATA", text);
try {
activity.startActivity(intent);
} catch (ActivityNotFoundException e) {
showDownloadDialog(activity, stringTitle, stringMessage,
stringButtonYes, stringButtonNo);
}
}
}