MC40 scanner blocks internal camera?

// Expert user has replied.
J Jacek Rys 2 years 11 months ago
7 1 0

Hello,
 
I'm developing and app for MC40N0.Build number: 01-12-03-4AJ22-K-V0-M1-072015
EMDKService version: 4.0.2.0
 
I'm using EMDKWrapper (the idea is described within this thread: EMDKWrapper class for non-Zebra devices concerns )
The app architecture is as following:
There are several separate activities which handle separate processes. In one activity we have scanning and taking a photo implemented.Activity handles emdkWrapper class calls and Fragments embeded within it are just adding/removing listeners to proceed with scan when needed. The fragment where the camera preview is implemented and where it's meant to take a photo does not need scanning functionality.
Now, even though it's not needed to scan we have an issue when we call onPause and then onResume methods on Photo fragment (and activity too, of course), for example by pressing the sleep button.
Then I get an error on camera initialization like this:
 
09-22 14:53:00.073 1265-1265/? E/ACRA: ACRA caught a RuntimeException for com.doddle.concession.jacek
                                       java.lang.RuntimeException: Unable to resume activity {com.jacek/com.Storage.StorageActivity}: java.lang.RuntimeException: Fail to connect to camera service
                                           at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2775)
                                           at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2804)
                                           at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1239)
                                           at android.os.Handler.dispatchMessage(Handler.java:102)
                                           at android.os.Looper.loop(Looper.java:136)
                                           at android.app.ActivityThread.main(ActivityThread.java:5002)
                                           at java.lang.reflect.Method.invokeNative(Native Method)
                                           at java.lang.reflect.Method.invoke(Method.java:515)
                                           at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
                                           at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
                                           at dalvik.system.NativeStart.main(Native Method)
                                        Caused by: java.lang.RuntimeException: Fail to connect to camera service
                                           at android.hardware.Camera.native_setup(Native Method)
                                           at android.hardware.Camera.(Camera.java:358)
                                           at android.hardware.Camera.open(Camera.java:331)
                                           at com.doddle.concession.Storage.TakePhotoFragment.initCamera(TakePhotoFragment.java:110)
                                           at com.doddle.concession.Storage.TakePhotoFragment.setupCamera(TakePhotoFragment.java:96)
                                           at com.doddle.concession.Storage.TakePhotoFragment.onResume(TakePhotoFragment.java:81)
                                           at android.support.v4.app.Fragment.performResume(Fragment.java:2020)
                                           at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1107)
                                           at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1252)
                                           at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1234)
                                           at android.support.v4.app.FragmentManagerImpl.dispatchResume(FragmentManager.java:2056)
                                           at android.support.v4.app.FragmentController.dispatchResume(FragmentController.java:196)
                                           at android.support.v4.app.FragmentActivity.onResumeFragments(FragmentActivity.java:505)
                                           at android.support.v4.app.FragmentActivity.onPostResume(FragmentActivity.java:494)
                                           at android.support.v7.app.AppCompatActivity.onPostResume(AppCompatActivity.java:174)
                                           at android.app.Activity.performResume(Activity.java:5348)
                                           at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2765)
                                           at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2804)
                                           at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1239)
                                           at android.os.Handler.dispatchMessage(Handler.java:102)
                                           at android.os.Looper.loop(Looper.java:136)
                                           at android.app.ActivityThread.main(ActivityThread.java:5002)
                                           at java.lang.reflect.Method.invokeNative(Native Method)
                                           at java.lang.reflect.Method.invoke(Method.java:515)
                                           at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
                                           at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
                                           at dalvik.system.NativeStart.main(Native Method)

 
Also, I noticed some warnings in EMDK, please check it too:
 
09-22 14:57:54.840 21933-21933/? D/EMDKWrapper: setDecoders (scanner != null): true
09-22 14:57:54.880 12389-12405/? W/System.err: com.symbol.emdk.emdkservice.barcode.SvcScannerException: The scanner device is not enabled.
09-22 14:57:54.880 12389-12405/? W/System.err:     at com.symbol.emdk.emdkservice.barcode.SvcScanner.getConfig(SvcScanner.java:175)
09-22 14:57:54.880 12389-12405/? W/System.err:     at com.symbol.emdk.emdkservice.ProfileService.scnGetConfig(ProfileService.java:1072)
09-22 14:57:54.880 12389-12405/? W/System.err:     at com.symbol.emdk.emdkservice.IEMDKService$Stub.onTransact(IEMDKService.java:530)
09-22 14:57:54.900 21933-21933/? D/EMDKWrapper: Status: Failure
09-22 14:57:54.900 21933-21933/? W/System.err: com.symbol.emdk.barcode.ScannerException: Failure
09-22 14:57:54.900 21933-21933/? W/System.err:     at com.symbol.emdk.barcode.Scanner.getConfig(Scanner.java:238)
09-22 14:57:54.900 21933-21933/? W/System.err:     at com.doddle.concession.EMDK.EMDKWrapper.setDecoders(EMDKWrapper.java:322)
09-22 14:57:54.900 21933-21933/? W/System.err:     at com.doddle.concession.EMDK.EMDKWrapper.onResumeWrapped(EMDKWrapper.java:257)
09-22 14:57:54.900 21933-21933/? W/System.err:     at com.doddle.concession.EMDK.EMDKWrapper.onOpened(EMDKWrapper.java:119)
09-22 14:57:54.910 21933-21933/? W/System.err:     at com.symbol.emdk.EMDKServiceConnection.notifyonConnected(EMDKServiceConnection.java:112)
09-22 14:57:54.910 21933-21933/? W/System.err:     at com.symbol.emdk.EMDKServiceConnection.onServiceConnected(EMDKServiceConnection.java:92)

 
 
 
---------------------------------------------------------------------------
Please take a look on my EMDKWrapper class (it's attached and also pasted at the end of the description).
It's used in the following way:
 
Please take a look on my implementation on the substantial methods inside activity:
public class MyActivity extends Activity implements EMDKWrapper.IWrapperKeeper{
 
/**/
 
@Overrideprotected void onCreate(Bundle savedInstanceState) {
if (AppConfig.ENABLE_ZEBRA) {
 
   emdkWrapper = new EMDKWrapper(getApplicationContext());
   emdkWrapper.setCurrentProcess(RealScanCurrentProcess.STORAGE_PROCESS);
   emdkWrapper.onCreateWrapped();
  }
}
@Override   public void onDestroy() {
   super.onDestroy();
   if (AppConfig.ENABLE_ZEBRA) {
        if (emdkWrapper != null) {
             emdkWrapper.onDestroyWrapped();
            }
       }
  }
 
 
   @Override   public void onStop() {
   super.onStop();
   if (AppConfig.ENABLE_ZEBRA) {
        if (emdkWrapper != null) {
             emdkWrapper.onStopWrapped();
            }
       }
  }
 
 
 
   @Override   public void onPause() {
   super.onPause();
   if (AppConfig.ENABLE_ZEBRA) {
        if (emdkWrapper != null) {
             emdkWrapper.onPauseWrapped();
            }
       }
  }
 
 
   @Override   public void onResume() {
   super.onResume();
   if (AppConfig.ENABLE_ZEBRA) {
        if (emdkWrapper != null) {
             emdkWrapper.onResumeWrapped();
            }
       }
  }
 
@Overridepublic EMDKWrapper getEMDKWrapper() {
   return emdkWrapper;
}
 
 
@Overridepublic void addRealScanCompletedListener(RealScanLifecycleListener callback) {
   if (emdkWrapper != null) {
   emdkWrapper.addRealScanCompletedListener(callback);
  }
}
 
 
@Overridepublic void removeRealScanCompletedListener() {
   if (emdkWrapper != null) {
        emdkWrapper.removeRealScanCompletedListener();
  }
}
 
@Overridepublic void setEMDKWrapper(EMDKWrapper wrapper) {
   emdkWrapper = wrapper;
}
 
}
 

 
Please take a look on my implementation on the substantial methods inside fragment:
 
public class MyFragment extends Fragment implements RealScanLifecycleListener{
 
/**/
@Overridepublic void onResume() {
   super.onResume();
       initializeRealScan();
}
 
private void initializeRealScan() {
  if (AppConfig.ENABLE_ZEBRA) {
       EMDKWrapper.IWrapperKeeper wrapperKeeper = (EMDKWrapper.IWrapperKeeper) getActivity();
       wrapperKeeper.addRealScanCompletedListener(this);
  }
}
 
@Override   public void onRealScanStarted() {
          //some UI actions take place
  }
 
@Overridepublic void onRealScanCompleted(String result) {
         //processing result
}
 
@Overridepublic void onDestroy() {
   super.onDestroy();
 
   if (AppConfig.ENABLE_ZEBRA) {
       EMDKWrapper.IWrapperKeeper wrapperKeeper = (EMDKWrapper.IWrapperKeeper) getActivity();
       wrapperKeeper.removeRealScanCompletedListener();
  }
}
 
}

 
 
This is the interface for handling scan results:
public interface RealScanLifecycleListener {
 
   void onRealScanStarted();
 
   void onRealScanCompleted(String result);
 
}

 
This is my EMDKWrapper class:
 
package com.mypackage.EMDK;
 
import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.Toast;
 
 
import com.symbol.emdk.EMDKManager;
import com.symbol.emdk.EMDKManager.EMDKListener;
import com.symbol.emdk.EMDKResults;
import com.symbol.emdk.barcode.BarcodeManager;
import com.symbol.emdk.barcode.ScanDataCollection;
import com.symbol.emdk.barcode.Scanner;
import com.symbol.emdk.barcode.Scanner.DataListener;
import com.symbol.emdk.barcode.Scanner.StatusListener;
import com.symbol.emdk.barcode.ScannerConfig;
import com.symbol.emdk.barcode.ScannerException;
import com.symbol.emdk.barcode.ScannerInfo;
import com.symbol.emdk.barcode.ScannerResults;
import com.symbol.emdk.barcode.StatusData;
 
import java.util.ArrayList;
 
public class EMDKWrapper implements EMDKListener, StatusListener, DataListener, BarcodeManager.ScannerConnectionListener {
 
   private static final String TAG = EMDKWrapper.class.getSimpleName() ;
   // Declare a variable to store EMDKManager object   private EMDKManager emdkManager = null;
 
   // Declare a variable to store Barcode Manager object   private BarcodeManager barcodeManager = null;
 
   // Declare a variable to hold scanner device to scan   private Scanner scanner = null;
 
   private Context context;
 
   private RealScanLifecycleListener mScanningCallback;
 
   private int CURRENT_PROCESS = RealScanCurrentProcess.UNDEFINED_PROCESS;
 
   private boolean bContinuousMode = false;
 
 
  
public EMDKWrapper(Context context) {
        this.context = context;
  }
 
 
 
public void setCurrentProcess(int currentProcess) {
   this.CURRENT_PROCESS = currentProcess;
  }
 
 
   public void addRealScanCompletedListener(RealScanLifecycleListener callback) {
        if (mScanningCallback == null) {
             this.mScanningCallback = callback;
       }
  }
 
 
   public void removeRealScanCompletedListener() {
        if (mScanningCallback != null) {
             this.mScanningCallback = null;
       }
  }
 
 
   //initialization   public boolean initializeScanner() throws ScannerException {
 
 
   if (scanner == null) {
             // Get the Barcode Manager object             barcodeManager = (BarcodeManager) this.emdkManager.getInstance(EMDKManager.FEATURE_TYPE.BARCODE);
             // Get default scanner defined on the device             scanner = barcodeManager.getDevice(BarcodeManager.DeviceIdentifier.DEFAULT);
             // Add data and status listeners             scanner.addDataListener(this);
             scanner.addStatusListener(this);
             // Hard trigger. When this mode is set, the user has to manually            // press the trigger on the device after issuing the read call.             scanner.triggerType = Scanner.TriggerType.HARD;
             // Enable the scanner             scanner.enable();
             // Starts an asynchronous Scan. The method will not turn ON the            // scanner. It will, however, put the scanner in a state in which            // the scanner can be turned ON either by pressing a hardware            // trigger or can be turned ON automatically.      
 
          if (scanner.isEnabled() && !scanner.isReadPending()) {
                  scanner.read();
          }
        return true;
    } else {
        return false;
   }
}
 
 
   //Listeners   @Override   public void onOpened(EMDKManager emdkManager) {
 
        this.emdkManager = emdkManager;
 
       onResumeWrapped();
 
  }
 
 
   @Override   public void onClosed() {
 
        if (this.emdkManager != null) {
 
             // Remove connection listener             removeConnectionListenerFromBarcodeManager();
 
 
             this.emdkManager.release();
             this.emdkManager = null;
       }
 
    
  }
 
 
   @Override   public void onStatus(StatusData statusData) {
 
 
       StatusData.ScannerStates state = statusData.getState();
 
             switch (state) {
                  // Scanner is IDLE             case IDLE:
 
 
                  if (bContinuousMode) {
                       try {
                               // An attempt to use the scanner continuously and rapidly (with a delay 100 ms between scans)                               // may cause the scanner to pause momentarily before resuming the scanning.                               // Hence add some delay (>= 100ms) before submitting the next read.                                 try {
                                     Thread.sleep(100);
                                } catch (InterruptedException e) {
                                     e.printStackTrace();
                                }
 
 
                         if (scanner.isEnabled() && !scanner.isReadPending()) {
                                 scanner.read();
                         }
                      } catch (ScannerException e) {
                           e.printStackTrace();
                      }
                 }
 
                  break;
                  // Scanner is SCANNING             case SCANNING:
 
                  if (mScanningCallback != null) {
                       mScanningCallback.onRealScanStarted();
                    }
                  break;
                  // Scanner is waiting for trigger press             case WAITING:
 
                  if (mScanningCallback != null) {
                       mScanningCallback.hideGreenBoarderNow();
                 }
                  break;
                  // Scanner is not enabled             case DISABLED:
                  break;
             case ERROR:
                  break;
 
             default:
                 break;
            }
  }
 
 
   @Override   public void onData(ScanDataCollection scanDataCollection) {
        new AsyncDataUpdated().execute(scanDataCollection);
  }
 
 
   public void onCreateWrapped() {
 
       EMDKResults results = EMDKManager.getEMDKManager(context, this);
        if (results.statusCode != EMDKResults.STATUS_CODE.SUCCESS) {
            Toast.makeText(context, context.getString(R.string.scanner_status) + context.getString(R.string.emdk_object_request_failed),                                                Toast.LENGTH_SHORT).show();
       }
  }
 
 
   public void onResumeWrapped() {
        if (emdkManager != null) {
             barcodeManager = (BarcodeManager) emdkManager.getInstance(EMDKManager.FEATURE_TYPE.BARCODE);
 
             // Add connection listener             if (barcodeManager != null) {
                  barcodeManager.addConnectionListener(this);
            }
 
            initScanner();
            setTrigger();
            setDecoders();
            startScan();
       }
  }
 
 
   private void startScan() {
 
        if (scanner == null) {
            initScanner();
       }
 
        if (scanner != null) {
             try {
 
                    // Submit a new read.
                    if (scanner.isEnabled() && !scanner.isReadPending()) {
                            scanner.read();
                    }
 
                  bContinuousMode = true;
 
            } catch (ScannerException e) {
                 e.printStackTrace();
 
            }
       }
 
  }
 
 
   private void stopScan() {
        if (scanner != null) {
 
             try {
                  // Reset continuous flag                  bContinuousMode = false;
                  // Cancel the pending read.                  scanner.cancelRead();
            } catch (ScannerException e) {
                   e.printStackTrace();
            }
       }
  }
 
 
 
 
   private void setDecoders() {
         if (scanner == null) {
                 initScanner();
            }
 
         if (scanner != null) {
             try {
 
                      ScannerConfig config = scanner.getConfig();
                      config.decoderParams.i2of5.enabled = true;
                      config.decoderParams.i2of5.length1 = 1;
                      config.decoderParams.i2of5.length2 = 40;
 
                      config.decoderParams.ean8.enabled = true;
                      config.decoderParams.ean13.enabled = true;
                      config.decoderParams.code39.enabled = true;
                      config.decoderParams.code128.enabled = true;
 
                       scanner.setConfig(config);
 
                 } catch (ScannerException e) {
                     e.printStackTrace();
                 }
            }
  }
 
 
private void setTrigger() {
        if (scanner == null) {
            initScanner();
       }
 
 
        if (scanner != null) {
             scanner.triggerType = Scanner.TriggerType.HARD;
       }
  }
 
 
   private void initScanner() {
        if (scanner == null) {
 
             scanner = barcodeManager.getDevice(BarcodeManager.DeviceIdentifier.DEFAULT);
 
 
             if (scanner != null) {
 
                  scanner.addDataListener(this);
                  scanner.addStatusListener(this);
 
                  try {
                       scanner.enable();
                 } catch (ScannerException e) {
                      e.printStackTrace();
                }
            }
       }
  }
 
 
   private void removeConnectionListenerFromBarcodeManager() {
        if (barcodeManager != null) {
             barcodeManager.removeConnectionListener(this);
             barcodeManager = null;
       }
  }
 
 
   public void onDestroyWrapped() {
       deInitializeScanner();
 
       removeConnectionListenerFromBarcodeManager();
 
        if (emdkManager != null) {
             // Clean up the objects created by EMDK manager             emdkManager.release();
             emdkManager = null;
       }
 
 
  }
 
 
   public void onStopWrapped() {
  
  }
 
 
   public void onPauseWrapped() {
 
       stopScan();
       deInitializeScanner();
 
       removeConnectionListenerFromBarcodeManager();
 
        if (emdkManager != null) {
             emdkManager.release(EMDKManager.FEATURE_TYPE.BARCODE);
       }
 
  }
 
 
   public void deInitializeScanner() {
 
        if (scanner != null) {
          
             scanner.removeDataListener(this);
             scanner.removeStatusListener(this);
 
            try {
                  scanner.cancelRead();
                  scanner.disable();
            } catch (ScannerException e) {
                 e.printStackTrace();
            }
            
             try {
                  scanner.release();
             } catch (ScannerException e) {
                 e.printStackTrace();
             }
 
 
 
             scanner = null;
       }
  }
 
 
   @Override   public void onConnectionChange(ScannerInfo scannerInfo, BarcodeManager.ConnectionState connectionState) {
        switch (connectionState) {
             case CONNECTED:
 
                      initScanner();
                      setTrigger();
                      setDecoders();
                      startScan();
                  break;
             case DISCONNECTED:
                      deInitializeScanner();
                  break;
            }
  }
 
 
 
   public interface IWrapperKeeper {
            EMDKWrapper getEMDKWrapper();
 
             void setEMDKWrapper(EMDKWrapper wrapper);
 
             void addRealScanCompletedListener(RealScanLifecycleListener callback);
 
             void removeRealScanCompletedListener();
  }
 
 
   private class AsyncDataUpdated extends AsyncTask {
 
             @Override             protected String doInBackground(ScanDataCollection... params) {
 
                      String dataString = "";
                      ScanDataCollection datas = params[0];
                       if ((datas != null) && (datas.getResult() == ScannerResults.SUCCESS)) {
                               ArrayList scanData = datas.getScanData();
                                 for (ScanDataCollection.ScanData data : scanData) {
                                          dataString = data.getData();
                                     }
                      }
 
             return dataString;
            }
 
 
             @Override
             protected void onPostExecute(String result) {
 
                       if (result.trim().isEmpty() || result.trim() == null) {
                                Toast.makeText(context, R.string.no_data_scanned, Toast.LENGTH_SHORT).show();
                      } else {
                                 switch (CURRENT_PROCESS) {
 
                                           case RealScanCurrentProcess.CHECKIN_PROCESS:
                                                    onRealScanCompleted(result);
                                                break;
                                           case RealScanCurrentProcess.STORAGE_PROCESS:
                                                    onRealScanCompleted(result);
                                                break;
                                           case RealScanCurrentProcess.COLLECTION_PROCESS:
                                                    onRealScanCompleted(result);
                                                break;
                                           case RealScanCurrentProcess.RETURNS_PROCESS:
                                                    onRealScanCompleted(result);
                                                 break;
                                           case RealScanCurrentProcess.UNDEFINED_PROCESS:
                                                    Toast.makeText(context, R.string.scan_unexpected, Toast.LENGTH_SHORT).show();
                                                break;
                                         }
                           }
                      }
 
     }
 
 
   private void onRealScanCompleted(String result) {
             if(mScanningCallback != null){
                  mScanningCallback.onRealScanCompleted(result);
            }else{
                 Log.d(TAG, "Scan callback is missing");
                 LogManager.logMessage(TAG + "Scan callback is missing");
            }
       }
 
}

 
 
The question is: should I disable EMDK for the time where I want to take a photo? Or maybe disable it one fragment before camera fragment and enable one fragment after camera fragment?
Please advice me in that matter.
 
Thanks in advance,
Jacek

Please register or login to post a reply

1 Replies

K Kanagal Raj Ramaswamy

Did you call scanner.release before taking picture using camera?

CONTACT
Can’t find what you’re looking for?