Search code examples
androidandroid-intentcordova-plugins

qrcode scanner a sample from zxing is not returning to onActivityResult after scanning


I am using the following code to create a qrcode scanner, got this code some one which refered to zxing library. The whole code works fine but when the scanner app close its not calling the onActivityResult after finshing the activity task. can somebody help me heres the code I am using .

My main activity

/**
 * PhoneGap is available under *either* the terms of the modified BSD license *or* the
 * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
 *
 * Copyright (c) Matt Kane 2010
 * Copyright (c) 2011, IBM Corporation
 * Copyright (c) 2013, Maciej Nux Jaros
 */


import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.content.Intent;
import android.util.Log;

import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.LOG;
import org.apache.cordova.PluginResult;

import android.util.Log;
import android.widget.Toast;

/**
 * This calls out to the ZXing barcode reader and returns the result.
 *
 * @sa https://github.com/apache/cordova-android/blob/master/framework/src/org/apache/cordova/CordovaPlugin.java
 */
public class BarcodeScanner extends CordovaPlugin {
    public static final int REQUEST_CODE = 0x0ba7c0de;

    private static final String SCAN = "scan";
    private static final String ENCODE = "encode";
    private static final String CANCELLED = "cancelled";
    private static final String FORMAT = "format";
    private static final String TEXT = "text";
    private static final String DATA = "data";
    private static final String TYPE = "type";



    private static final String SCAN_INTENT = "com.google.zxing.client.android.SCAN";
    private static final String ENCODE_DATA = "ENCODE_DATA";
    private static final String ENCODE_TYPE = "ENCODE_TYPE";
    private static final String ENCODE_INTENT = "com.MobileApp.BarcodeScanner.ENCODE";
    private static final String TEXT_TYPE = "TEXT_TYPE";
    private static final String EMAIL_TYPE = "EMAIL_TYPE";
    private static final String PHONE_TYPE = "PHONE_TYPE";
    private static final String SMS_TYPE = "SMS_TYPE";

    private static final String LOG_TAG = "BarcodeScanner";

    private CallbackContext callbackContext;

    /**
     * Constructor.
     */
    public BarcodeScanner() {
    }

    /**
     * Executes the request.
     *
     * This method is called from the WebView thread. To do a non-trivial amount of work, use:
     *     cordova.getThreadPool().execute(runnable);
     *
     * To run on the UI thread, use:
     *     cordova.getActivity().runOnUiThread(runnable);
     *
     * @param action          The action to execute.
     * @param args            The exec() arguments.
     * @param callbackContext The callback context used when calling back into JavaScript.
     * @return                Whether the action was valid.
     *
     * @sa https://github.com/apache/cordova-android/blob/master/framework/src/org/apache/cordova/CordovaPlugin.java
     */
    @Override
    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) {
        this.callbackContext = callbackContext;

        if (action.equals(ENCODE)) {
            JSONObject obj = args.optJSONObject(0);
            if (obj != null) {
                String type = obj.optString(TYPE);
                String data = obj.optString(DATA);

                // If the type is null then force the type to text
                if (type == null) {
                    type = TEXT_TYPE;
                }

                if (data == null) {
                    callbackContext.error("User did not specify data to encode");
                    return true;
                }

//                encode(type, data);

            } else {
                callbackContext.error("User did not specify data to encode");
                return true;
            }
        } else if (action.equals(SCAN)) {
            scan(args);
        } else {
            return false;
        }
        return true;
    }

    /**
     * Starts an intent to scan and decode a barcode.
     */
    public void scan(JSONArray args) {



        IntentIntegrator integrator = new IntentIntegrator(this.cordova.getActivity());
        integrator.initiateScan(); 


    }



    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        // TODO Auto-generated method stub
            String contantsString = null;
            IntentResult scanResult = IntentIntegrator.parseActivityResult(
                requestCode, resultCode, data);
            JSONObject obj = new JSONObject();
        if (scanResult != null) 
        {

            // handle scan result
            contantsString = scanResult.getContents() == null ? "0"
                    : scanResult.getContents();
            if (contantsString.equalsIgnoreCase("0")) 
                {
//                  Toast.makeText(this.cordova.getActivity(),
//                          "Problem to get the  contant Number", Toast.LENGTH_LONG)
//                          .show();
                Log.d(LOG_TAG, "Problem in reading the result possibly read string is 0");
                } 
            else 
                {
//                  Toast.makeText(this.cordova.getActivity(), contantsString,
//                      Toast.LENGTH_LONG).show();
                Log.d(LOG_TAG, "succesfully read the barcode");

                }

            try {
                obj.put(TEXT, contantsString);
                obj.put(FORMAT, contantsString);
                obj.put(CANCELLED, false);
            } catch (JSONException e) {
                Log.d(LOG_TAG, "This should never happen");
            }
        } else {
//                  Toast.makeText(this.cordova.getActivity(),
//                          "Problem to scan the barcode.", Toast.LENGTH_LONG).show();
            Log.d(LOG_TAG, "Problem in reading the result possibly read string is null");
                        try 
                        {
                            obj.put(TEXT, "");
                            obj.put(FORMAT, "");
                            obj.put(CANCELLED, false);
                        }
                        catch (JSONException e) {
                            Log.d(LOG_TAG, "This should never happen");
                        }
                }
    }



  }

IntentIntegrator class

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.util.Log;


public final class IntentIntegrator {

  public static final int REQUEST_CODE = 0x0000c0de; // Only use bottom 16 bits
  private static final String TAG = IntentIntegrator.class.getSimpleName();

  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 BS_PACKAGE = "com.google.zxing.client.android";

  // supported barcode formats
  public static final Collection<String> PRODUCT_CODE_TYPES = list("UPC_A", "UPC_E", "EAN_8", "EAN_13", "RSS_14");
  public static final Collection<String> ONE_D_CODE_TYPES =
      list("UPC_A", "UPC_E", "EAN_8", "EAN_13", "CODE_39", "CODE_93", "CODE_128",
           "ITF", "RSS_14", "RSS_EXPANDED");
  public static final Collection<String> QR_CODE_TYPES = Collections.singleton("QR_CODE");
  public static final Collection<String> DATA_MATRIX_TYPES = Collections.singleton("DATA_MATRIX");

  public static final Collection<String> ALL_CODE_TYPES = null;

  public static final Collection<String> TARGET_BARCODE_SCANNER_ONLY = Collections.singleton(BS_PACKAGE);
  public static final Collection<String> TARGET_ALL_KNOWN = list(
          BS_PACKAGE, // Barcode Scanner
          "com.srowen.bs.android", // Barcode Scanner+
          "com.srowen.bs.android.simple" // Barcode Scanner+ Simple
          // TODO add more -- what else supports this intent?
      );

  private final Activity activity;
  private String title;
  private String message;
  private String buttonYes;
  private String buttonNo;
  private Collection<String> targetApplications;

  public IntentIntegrator(Activity activity) {
    this.activity = activity;
    title = DEFAULT_TITLE;
    message = DEFAULT_MESSAGE;
    buttonYes = DEFAULT_YES;
    buttonNo = DEFAULT_NO;
    targetApplications = TARGET_ALL_KNOWN;
  }

  public String getTitle() {
    return title;
  }

  public void setTitle(String title) {
    this.title = title;
  }

  public void setTitleByID(int titleID) {
    title = activity.getString(titleID);
  }

  public String getMessage() {
    return message;
  }

  public void setMessage(String message) {
    this.message = message;
  }

  public void setMessageByID(int messageID) {
    message = activity.getString(messageID);
  }

  public String getButtonYes() {
    return buttonYes;
  }

  public void setButtonYes(String buttonYes) {
    this.buttonYes = buttonYes;
  }

  public void setButtonYesByID(int buttonYesID) {
    buttonYes = activity.getString(buttonYesID);
  }

  public String getButtonNo() {
    return buttonNo;
  }

  public void setButtonNo(String buttonNo) {
    this.buttonNo = buttonNo;
  }

  public void setButtonNoByID(int buttonNoID) {
    buttonNo = activity.getString(buttonNoID);
  }

  public Collection<String> getTargetApplications() {
    return targetApplications;
  }

  public void setTargetApplications(Collection<String> targetApplications) {
    this.targetApplications = targetApplications;
  }

  public void setSingleTargetApplication(String targetApplication) {
    this.targetApplications = Collections.singleton(targetApplication);
  }

  /**
   * Initiates a scan for all known barcode types.
   */
  public AlertDialog initiateScan() {
    return initiateScan(ALL_CODE_TYPES);
  }

  /**
   * Initiates a scan only for a certain set of barcode types, given as strings corresponding
   * to their names in ZXing's {@code BarcodeFormat} class like "UPC_A". You can supply constants
   * like {@link #PRODUCT_CODE_TYPES} for example.
   */
  public AlertDialog initiateScan(Collection<String> desiredBarcodeFormats) {
    Intent intentScan = new Intent(BS_PACKAGE + ".SCAN");
    intentScan.addCategory(Intent.CATEGORY_DEFAULT);

    // check which types of codes to scan for
    if (desiredBarcodeFormats != null) {
      // set the desired barcode types
      StringBuilder joinedByComma = new StringBuilder();
      for (String format : desiredBarcodeFormats) {
        if (joinedByComma.length() > 0) {
          joinedByComma.append(',');
        }
        joinedByComma.append(format);
      }
      intentScan.putExtra("SCAN_FORMATS", joinedByComma.toString());
    }

    String targetAppPackage = findTargetAppPackage(intentScan);
    if (targetAppPackage == null) {
      return showDownloadDialog();
    }
    intentScan.setPackage(targetAppPackage);
    intentScan.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    intentScan.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
    activity.startActivityForResult(intentScan, REQUEST_CODE);
    return null;
  }

  private String findTargetAppPackage(Intent intent) {
    PackageManager pm = activity.getPackageManager();
    List<ResolveInfo> availableApps = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
    if (availableApps != null) {
      for (ResolveInfo availableApp : availableApps) {
        String packageName = availableApp.activityInfo.packageName;
        if (targetApplications.contains(packageName)) {
          return packageName;
        }
      }
    }
    return null;
  }

  private AlertDialog showDownloadDialog() {
    AlertDialog.Builder downloadDialog = new AlertDialog.Builder(activity);
    downloadDialog.setTitle(title);
    downloadDialog.setMessage(message);
    downloadDialog.setPositiveButton(buttonYes, new DialogInterface.OnClickListener() {
      @Override
      public void onClick(DialogInterface dialogInterface, int i) {
        Uri uri = Uri.parse("market://details?id=" + BS_PACKAGE);
        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
        try {
          activity.startActivity(intent);
        } catch (ActivityNotFoundException anfe) {
          // Hmm, market is not installed
          Log.w(TAG, "Android Market is not installed; cannot install Barcode Scanner");
        }
      }
    });
    downloadDialog.setNegativeButton(buttonNo, new DialogInterface.OnClickListener() {
      @Override
      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");
        byte[] rawBytes = intent.getByteArrayExtra("SCAN_RESULT_BYTES");
        int intentOrientation = intent.getIntExtra("SCAN_RESULT_ORIENTATION", Integer.MIN_VALUE);
        Integer orientation = intentOrientation == Integer.MIN_VALUE ? null : intentOrientation;
        String errorCorrectionLevel = intent.getStringExtra("SCAN_RESULT_ERROR_CORRECTION_LEVEL");
        return new IntentResult(contents,
                                formatName,
                                rawBytes,
                                orientation,
                                errorCorrectionLevel);
      }
      return new IntentResult();
    }
    return null;
  }


  /**
   * 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
   */
  public void shareText(CharSequence text) {
    Intent intent = new Intent();
    intent.addCategory(Intent.CATEGORY_DEFAULT);
    intent.setAction(BS_PACKAGE + ".ENCODE");
    intent.putExtra("ENCODE_TYPE", "TEXT_TYPE");
    intent.putExtra("ENCODE_DATA", text);
    String targetAppPackage = findTargetAppPackage(intent);
    if (targetAppPackage == null) {
      showDownloadDialog();
    } else {
      intent.setPackage(targetAppPackage);
      intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
      intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
      activity.startActivity(intent);
    }
  }

  private static Collection<String> list(String... values) {
    return Collections.unmodifiableCollection(Arrays.asList(values));
  }

}

IntentResult class

public final class IntentResult {

    private final String contents;
    private final String formatName;
    private final byte[] rawBytes;
    private final Integer orientation;
    private final String errorCorrectionLevel;

    IntentResult() {
      this(null, null, null, null, null);
    }

    IntentResult(String contents,
                 String formatName,
                 byte[] rawBytes,
                 Integer orientation,
                 String errorCorrectionLevel) {
      this.contents = contents;
      this.formatName = formatName;
      this.rawBytes = rawBytes;
      this.orientation = orientation;
      this.errorCorrectionLevel = errorCorrectionLevel;
    }

    /**
     * @return raw content of barcode
     */
    public String getContents() {
      return contents;
    }

    /**
     * @return name of format, like "QR_CODE", "UPC_A". See {@code BarcodeFormat} for more format names.
     */
    public String getFormatName() {
      return formatName;
    }

    /**
     * @return raw bytes of the barcode content, if applicable, or null otherwise
     */
    public byte[] getRawBytes() {
      return rawBytes;
    }

    /**
     * @return rotation of the image, in degrees, which resulted in a successful scan. May be null.
     */
    public Integer getOrientation() {
      return orientation;
    }

    /**
     * @return name of the error correction level used in the barcode, if applicable
     */
    public String getErrorCorrectionLevel() {
      return errorCorrectionLevel;
    }

    @Override
    public String toString() {
      StringBuilder dialogText = new StringBuilder(100);
      dialogText.append("Format: ").append(formatName).append('\n');
      dialogText.append("Contents: ").append(contents).append('\n');
      int rawBytesLength = rawBytes == null ? 0 : rawBytes.length;
      dialogText.append("Raw bytes: (").append(rawBytesLength).append(" bytes)\n");
      dialogText.append("Orientation: ").append(orientation).append('\n');
      dialogText.append("EC level: ").append(errorCorrectionLevel).append('\n');
      return dialogText.toString();
    }

  }

app opens but when it scans the qrcode it doesn't return anything.


Solution

  • This code worked for me ... I broke the above code and used it into mine and it worked.

    /**
     * PhoneGap is available under *either* the terms of the modified BSD license *or* the
     * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
     *
     * Copyright (c) Matt Kane 2010
     * Copyright (c) 2011, IBM Corporation
     * Copyright (c) 2013, Maciej Nux Jaros
     */
    
    
    import java.util.List;
    
    import org.json.JSONArray;
    import org.json.JSONException;
    import org.json.JSONObject;
    
    import android.app.Activity;
    import android.app.AlertDialog;
    import android.content.ActivityNotFoundException;
    import android.content.DialogInterface;
    import android.content.Intent;
    import android.content.pm.PackageManager;
    import android.content.pm.ResolveInfo;
    import android.net.Uri;
    import android.util.Log;
    
    import org.apache.cordova.CordovaPlugin;
    import org.apache.cordova.CallbackContext;
    import org.apache.cordova.PluginResult;
    
    /**
     * This calls out to the ZXing barcode reader and returns the result.
     *
     * @sa https://github.com/apache/cordova-android/blob/master/framework/src/org/apache/cordova/CordovaPlugin.java
     */
    public class BarcodeScanner extends CordovaPlugin {
        public static final int REQUEST_CODE = 0x0ba7c0de;
    
        private static final String SCAN = "scan";
        private static final String ENCODE = "encode";
        private static final String CANCELLED = "cancelled";
        private static final String FORMAT = "format";
        private static final String TEXT = "text";
        private static final String DATA = "data";
        private static final String TYPE = "type";
        private static final String SCAN_INTENT = "com.google.zxing.client.android";
        private static final String ENCODE_DATA = "ENCODE_DATA";
        private static final String ENCODE_TYPE = "ENCODE_TYPE";
        private static final String ENCODE_INTENT = "com.phonegap.plugins.barcodescanner.ENCODE";
        private static final String TEXT_TYPE = "TEXT_TYPE";
        private static final String EMAIL_TYPE = "EMAIL_TYPE";
        private static final String PHONE_TYPE = "PHONE_TYPE";
        private static final String SMS_TYPE = "SMS_TYPE";
    
        private static final String LOG_TAG = "BarcodeScanner";
    
        private CallbackContext callbackContext;
    
        /**
         * Constructor.
         */
        public BarcodeScanner() {
        }
    
        /**
         * Executes the request.
         *
         * This method is called from the WebView thread. To do a non-trivial amount of work, use:
         *     cordova.getThreadPool().execute(runnable);
         *
         * To run on the UI thread, use:
         *     cordova.getActivity().runOnUiThread(runnable);
         *
         * @param action          The action to execute.
         * @param args            The exec() arguments.
         * @param callbackContext The callback context used when calling back into JavaScript.
         * @return                Whether the action was valid.
         *
         * @sa https://github.com/apache/cordova-android/blob/master/framework/src/org/apache/cordova/CordovaPlugin.java
         */
        @Override
        public boolean execute(String action, JSONArray args, CallbackContext callbackContext) {
            this.callbackContext = callbackContext;
    
            if (action.equals(ENCODE)) {
                JSONObject obj = args.optJSONObject(0);
                if (obj != null) {
                    String type = obj.optString(TYPE);
                    String data = obj.optString(DATA);
    
                    // If the type is null then force the type to text
                    if (type == null) {
                        type = TEXT_TYPE;
                    }
    
                    if (data == null) {
                        callbackContext.error("User did not specify data to encode");
                        return true;
                    }
    
                    encode(type, data);
                } else {
                    callbackContext.error("User did not specify data to encode");
                    return true;
                }
            } else if (action.equals(SCAN)) {
                scan();
            } else {
                return false;
            }
            return true;
        }
    
        /**
         * Starts an intent to scan and decode a barcode.
         */
        public AlertDialog scan() {
            Intent intentScan = new Intent(SCAN_INTENT+".SCAN");
            intentScan.addCategory(Intent.CATEGORY_DEFAULT);
    
            String targetAppPackage = findTargetAppPackage(intentScan);
            if (targetAppPackage == null) {
              return showDownloadDialog();
            }
    
    
    
            this.cordova.startActivityForResult((CordovaPlugin) this, intentScan, REQUEST_CODE);
            return null;
        }
    
        private String findTargetAppPackage(Intent intent) {
            PackageManager pm = this.cordova.getActivity().getPackageManager();
            List<ResolveInfo> availableApps = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
            if (availableApps != null) {
              for (ResolveInfo availableApp : availableApps) {
                String packageName = availableApp.activityInfo.packageName;
    //            if (targetApplications.contains(packageName)) {
    //              return packageName;
    //            }
    
                if (packageName!=null) {
                    return packageName;
                  }
              }
            }
            return null;
          }
    
        private AlertDialog showDownloadDialog() {
            AlertDialog.Builder downloadDialog = new AlertDialog.Builder(BarcodeScanner.this.cordova.getActivity());
            downloadDialog.setTitle("Install Barcode Scanner?");
            downloadDialog.setMessage("This application requires Barcode Scanner. Would you like to install it?");
            downloadDialog.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
              @Override
              public void onClick(DialogInterface dialogInterface, int i) {
                Uri uri = Uri.parse("market://details?id=" + SCAN_INTENT);
                Intent intent = new Intent(Intent.ACTION_VIEW, uri);
                try {
                    BarcodeScanner.this.cordova.getActivity().startActivity(intent);
                } catch (ActivityNotFoundException anfe) {
                  // Hmm, market is not installed
    //              Log.w(TAG, "Android Market is not installed; cannot install Barcode Scanner");
                }
              }
            });
            downloadDialog.setNegativeButton("No", new DialogInterface.OnClickListener() {
              @Override
              public void onClick(DialogInterface dialogInterface, int i) {}
            });
            return downloadDialog.show();
          }
    
        /**
         * Called when the barcode scanner intent completes.
         *
         * @param requestCode The request code originally supplied to startActivityForResult(),
         *                       allowing you to identify who this result came from.
         * @param resultCode  The integer result code returned by the child activity through its setResult().
         * @param intent      An Intent, which can return result data to the caller (various data can be attached to Intent "extras").
         */
        @Override
        public void onActivityResult(int requestCode, int resultCode, Intent intent) {
            if (requestCode == REQUEST_CODE) {
                if (resultCode == Activity.RESULT_OK) {
                    JSONObject obj = new JSONObject();
                    try {
                        obj.put(TEXT, intent.getStringExtra("SCAN_RESULT"));
                        obj.put(FORMAT, intent.getStringExtra("SCAN_RESULT_FORMAT"));
                        obj.put(CANCELLED, false);
                    } catch (JSONException e) {
                        Log.d(LOG_TAG, "This should never happen");
                    }
                    //this.success(new PluginResult(PluginResult.Status.OK, obj), this.callback);
                    this.callbackContext.success(obj);
                } else if (resultCode == Activity.RESULT_CANCELED) {
                    JSONObject obj = new JSONObject();
                    try {
                        obj.put(TEXT, "");
                        obj.put(FORMAT, "");
                        obj.put(CANCELLED, true);
                    } catch (JSONException e) {
                        Log.d(LOG_TAG, "This should never happen");
                    }
                    //this.success(new PluginResult(PluginResult.Status.OK, obj), this.callback);
                    this.callbackContext.success(obj);
                } else {
                    //this.error(new PluginResult(PluginResult.Status.ERROR), this.callback);
                    this.callbackContext.error("Unexpected error");
                }
            }
        }
    
        /**
         * Initiates a barcode encode.
         *
         * @param type Endoiding type.
         * @param data The data to encode in the bar code.
         */
        public void encode(String type, String data) {
            Intent intentEncode = new Intent(ENCODE_INTENT);
            intentEncode.putExtra(ENCODE_TYPE, type);
            intentEncode.putExtra(ENCODE_DATA, data);
    
            this.cordova.getActivity().startActivity(intentEncode);
        }
    }