Preyea Regmi
4 years ago
14 changed files with 2264 additions and 10 deletions
-
95app/src/main/java/com/swifttech/remit/android/common/view/qrscanner/BarcodeGraphic.java
-
92app/src/main/java/com/swifttech/remit/android/common/view/qrscanner/BarcodeGraphicTracker.java
-
46app/src/main/java/com/swifttech/remit/android/common/view/qrscanner/BarcodeTrackerFactory.java
-
409app/src/main/java/com/swifttech/remit/android/common/view/qrscanner/QRScannerFragment.java
-
1216app/src/main/java/com/swifttech/remit/android/common/view/qrscanner/camera/MCameraSource.java
-
190app/src/main/java/com/swifttech/remit/android/common/view/qrscanner/camera/MCameraSourcePreview.java
-
212app/src/main/java/com/swifttech/remit/android/common/view/qrscanner/camera/MGraphicOverlay.java
-
4app/src/main/java/com/swifttech/remit/android/features/balancesend/BalanceSendViewModelFactory.java
-
2app/src/main/java/com/swifttech/remit/android/features/home/view/HomeFragmentV2.java
-
1app/src/main/java/com/swifttech/remit/android/features/kycV3/KYCV3ViewModelFactory.java
-
2app/src/main/java/com/swifttech/remit/android/features/kycV3/gateway/KYCV3Gateway.java
-
1app/src/main/java/com/swifttech/remit/android/features/kycV3/presenter/KYCV3GatewayInterface.java
-
2app/src/main/java/com/swifttech/remit/android/features/kycV3/view/KYCV3Activity.java
-
2app/src/main/java/com/swifttech/remit/android/features/register/view/RegisterV2Activity.java
@ -0,0 +1,95 @@ |
|||
/* |
|||
* Copyright (C) The Android Open Source Project |
|||
* |
|||
* 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.swifttech.remit.android.common.view.qrscanner; |
|||
|
|||
import android.graphics.Canvas; |
|||
import android.graphics.Color; |
|||
import android.graphics.Paint; |
|||
import android.graphics.RectF; |
|||
|
|||
import com.google.android.gms.vision.barcode.Barcode; |
|||
import com.swifttech.remit.android.common.view.qrscanner.camera.MGraphicOverlay; |
|||
|
|||
/** |
|||
* Graphic instance for rendering barcode position, size, and ID within an associated graphic |
|||
* overlay view. |
|||
*/ |
|||
public class BarcodeGraphic extends MGraphicOverlay.Graphic { |
|||
|
|||
private int mId; |
|||
|
|||
|
|||
|
|||
private static int mCurrentColorIndex = 0; |
|||
|
|||
private Paint mRectPaint; |
|||
private volatile Barcode mBarcode; |
|||
|
|||
BarcodeGraphic(MGraphicOverlay overlay) { |
|||
super(overlay); |
|||
|
|||
|
|||
mRectPaint = new Paint(); |
|||
mRectPaint.setColor(Color.RED); |
|||
mRectPaint.setStyle(Paint.Style.STROKE); |
|||
mRectPaint.setStrokeWidth(8.0f); |
|||
|
|||
|
|||
} |
|||
|
|||
public int getId() { |
|||
return mId; |
|||
} |
|||
|
|||
public void setId(int id) { |
|||
this.mId = id; |
|||
} |
|||
|
|||
public Barcode getBarcode() { |
|||
return mBarcode; |
|||
} |
|||
|
|||
/** |
|||
* Updates the barcode instance from the detection of the most recent frame. Invalidates the |
|||
* relevant portions of the overlay to trigger a redraw. |
|||
*/ |
|||
void updateItem(Barcode barcode) { |
|||
mBarcode = barcode; |
|||
postInvalidate(); |
|||
} |
|||
|
|||
/** |
|||
* Draws the barcode annotations for position, size, and raw value on the supplied canvas. |
|||
*/ |
|||
@Override |
|||
public void draw(Canvas canvas) { |
|||
Barcode barcode = mBarcode; |
|||
if (barcode == null) { |
|||
return; |
|||
} |
|||
|
|||
// Draws the bounding box around the barcode. |
|||
RectF rect = new RectF(barcode.getBoundingBox()); |
|||
rect.left = translateX(rect.left); |
|||
rect.top = translateY(rect.top); |
|||
rect.right = translateX(rect.right); |
|||
rect.bottom = translateY(rect.bottom); |
|||
canvas.drawRect(rect, mRectPaint); |
|||
|
|||
// Draws a label at the bottom of the barcode indicate the barcode value that was detected. |
|||
|
|||
} |
|||
} |
@ -0,0 +1,92 @@ |
|||
/* |
|||
* Copyright (C) The Android Open Source Project |
|||
* |
|||
* 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.swifttech.remit.android.common.view.qrscanner; |
|||
|
|||
import android.content.Context; |
|||
|
|||
import androidx.annotation.UiThread; |
|||
|
|||
import com.google.android.gms.vision.Detector; |
|||
import com.google.android.gms.vision.Tracker; |
|||
import com.google.android.gms.vision.barcode.Barcode; |
|||
import com.swifttech.remit.android.common.view.qrscanner.camera.MGraphicOverlay; |
|||
|
|||
/** |
|||
* Generic tracker which is used for tracking or reading a barcode (and can really be used for |
|||
* any type of item). This is used to receive newly detected items, add a graphical representation |
|||
* to an overlay, update the graphics as the item changes, and remove the graphics when the item |
|||
* goes away. |
|||
*/ |
|||
public class BarcodeGraphicTracker extends Tracker<Barcode> { |
|||
private MGraphicOverlay<BarcodeGraphic> mOverlay; |
|||
private BarcodeGraphic mGraphic; |
|||
|
|||
private BarcodeUpdateListener mBarcodeUpdateListener; |
|||
|
|||
/** |
|||
* Consume the item instance detected from an Activity or Fragment level by implementing the |
|||
* BarcodeUpdateListener interface method onBarcodeDetected. |
|||
*/ |
|||
public interface BarcodeUpdateListener { |
|||
@UiThread |
|||
void onBarcodeDetected(Barcode barcode); |
|||
} |
|||
|
|||
BarcodeGraphicTracker(MGraphicOverlay<BarcodeGraphic> mOverlay, BarcodeGraphic mGraphic, |
|||
BarcodeUpdateListener listener) { |
|||
this.mOverlay = mOverlay; |
|||
this.mGraphic = mGraphic; |
|||
this.mBarcodeUpdateListener=listener; |
|||
|
|||
} |
|||
|
|||
/** |
|||
* Start tracking the detected item instance within the item overlay. |
|||
*/ |
|||
@Override |
|||
public void onNewItem(int id, Barcode item) { |
|||
mGraphic.setId(id); |
|||
mBarcodeUpdateListener.onBarcodeDetected(item); |
|||
} |
|||
|
|||
/** |
|||
* Update the position/characteristics of the item within the overlay. |
|||
*/ |
|||
@Override |
|||
public void onUpdate(Detector.Detections<Barcode> detectionResults, Barcode item) { |
|||
mOverlay.add(mGraphic); |
|||
mGraphic.updateItem(item); |
|||
} |
|||
|
|||
/** |
|||
* Hide the graphic when the corresponding object was not detected. This can happen for |
|||
* intermediate frames temporarily, for example if the object was momentarily blocked from |
|||
* view. |
|||
*/ |
|||
@Override |
|||
public void onMissing(Detector.Detections<Barcode> detectionResults) { |
|||
mOverlay.remove(mGraphic); |
|||
} |
|||
|
|||
/** |
|||
* Called when the item is assumed to be gone for good. Remove the graphic annotation from |
|||
* the overlay. |
|||
*/ |
|||
@Override |
|||
public void onDone() { |
|||
mOverlay.remove(mGraphic); |
|||
} |
|||
} |
@ -0,0 +1,46 @@ |
|||
/* |
|||
* Copyright (C) The Android Open Source Project |
|||
* |
|||
* 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.swifttech.remit.android.common.view.qrscanner; |
|||
|
|||
import android.content.Context; |
|||
|
|||
import com.google.android.gms.vision.MultiProcessor; |
|||
import com.google.android.gms.vision.Tracker; |
|||
import com.google.android.gms.vision.barcode.Barcode; |
|||
import com.swifttech.remit.android.common.view.qrscanner.camera.MGraphicOverlay; |
|||
|
|||
/** |
|||
* Factory for creating a tracker and associated graphic to be associated with a new barcode. The |
|||
* multi-processor uses this factory to create barcode trackers as needed -- one for each barcode. |
|||
*/ |
|||
class BarcodeTrackerFactory implements MultiProcessor.Factory<Barcode> { |
|||
private MGraphicOverlay<BarcodeGraphic> mGraphicOverlay; |
|||
private BarcodeGraphicTracker.BarcodeUpdateListener listener; |
|||
|
|||
public BarcodeTrackerFactory(MGraphicOverlay<BarcodeGraphic> mGraphicOverlay, |
|||
BarcodeGraphicTracker.BarcodeUpdateListener listener) { |
|||
this.mGraphicOverlay = mGraphicOverlay; |
|||
this.listener = listener; |
|||
} |
|||
|
|||
@Override |
|||
public Tracker<Barcode> create(Barcode barcode) { |
|||
BarcodeGraphic graphic = new BarcodeGraphic(mGraphicOverlay); |
|||
return new BarcodeGraphicTracker(mGraphicOverlay, graphic,listener); |
|||
} |
|||
|
|||
} |
|||
|
@ -0,0 +1,409 @@ |
|||
package com.swifttech.remit.android.common.view.qrscanner; |
|||
|
|||
import android.Manifest; |
|||
import android.annotation.SuppressLint; |
|||
import android.app.Dialog; |
|||
import android.content.DialogInterface; |
|||
import android.content.pm.PackageManager; |
|||
import android.hardware.Camera; |
|||
import android.os.Bundle; |
|||
import android.os.Handler; |
|||
import android.os.Looper; |
|||
import android.util.Log; |
|||
import android.view.GestureDetector; |
|||
import android.view.LayoutInflater; |
|||
import android.view.MotionEvent; |
|||
import android.view.ScaleGestureDetector; |
|||
import android.view.View; |
|||
import android.view.ViewGroup; |
|||
import android.widget.Toast; |
|||
|
|||
import androidx.annotation.NonNull; |
|||
import androidx.annotation.Nullable; |
|||
import androidx.core.app.ActivityCompat; |
|||
|
|||
import com.google.android.gms.common.ConnectionResult; |
|||
import com.google.android.gms.common.GoogleApiAvailability; |
|||
import com.google.android.gms.vision.CameraSource; |
|||
import com.google.android.gms.vision.MultiProcessor; |
|||
import com.google.android.gms.vision.barcode.Barcode; |
|||
import com.google.android.gms.vision.barcode.BarcodeDetector; |
|||
import com.google.android.material.dialog.MaterialAlertDialogBuilder; |
|||
import com.google.android.material.snackbar.Snackbar; |
|||
import com.swifttech.remit.android.R; |
|||
import com.swifttech.remit.android.base.BaseFragment; |
|||
import com.swifttech.remit.android.common.view.qrscanner.camera.MCameraSource; |
|||
import com.swifttech.remit.android.common.view.qrscanner.camera.MCameraSourcePreview; |
|||
import com.swifttech.remit.android.common.view.qrscanner.camera.MGraphicOverlay; |
|||
|
|||
import java.io.IOException; |
|||
|
|||
|
|||
public abstract class QRScannerFragment extends BaseFragment { |
|||
|
|||
MCameraSourcePreview mPreview; |
|||
|
|||
MGraphicOverlay<BarcodeGraphic> mGraphicOverlay; |
|||
|
|||
private static final String TAG = "Barcode-reader"; |
|||
|
|||
// intent request code to handle updating play services if needed. |
|||
private static final int RC_HANDLE_GMS = 9001; |
|||
|
|||
// permission request codes need to be < 256 |
|||
private static final int RC_HANDLE_CAMERA_PERM = 2; |
|||
|
|||
|
|||
|
|||
private MCameraSource mCameraSource; |
|||
|
|||
BarcodeGraphicTracker.BarcodeUpdateListener listener; |
|||
|
|||
// helper objects for detecting taps and pinches. |
|||
private ScaleGestureDetector scaleGestureDetector; |
|||
private GestureDetector gestureDetector; |
|||
|
|||
|
|||
|
|||
|
|||
protected abstract @NonNull |
|||
BarcodeGraphicTracker.BarcodeUpdateListener provideListener(); |
|||
|
|||
private class CaptureGestureListener extends GestureDetector.SimpleOnGestureListener { |
|||
@Override |
|||
public boolean onSingleTapConfirmed(MotionEvent e) { |
|||
return onTap(e.getRawX(), e.getRawY()) || super.onSingleTapConfirmed(e); |
|||
} |
|||
} |
|||
|
|||
private class ScaleListener implements ScaleGestureDetector.OnScaleGestureListener { |
|||
|
|||
/** |
|||
* Responds to scaling events for a gesture in progress. |
|||
* Reported by pointer motion. |
|||
* |
|||
* @param detector The detector reporting the event - use this to |
|||
* retrieve extended info about event state. |
|||
* @return Whether or not the detector should consider this event |
|||
* as handled. If an event was not handled, the detector |
|||
* will continue to accumulate movement until an event is |
|||
* handled. This can be useful if an application, for example, |
|||
* only wants to update scaling factors if the change is |
|||
* greater than 0.01. |
|||
*/ |
|||
@Override |
|||
public boolean onScale(ScaleGestureDetector detector) { |
|||
return false; |
|||
} |
|||
|
|||
/** |
|||
* Responds to the beginning of a scaling gesture. Reported by |
|||
* new pointers going down. |
|||
* |
|||
* @param detector The detector reporting the event - use this to |
|||
* retrieve extended info about event state. |
|||
* @return Whether or not the detector should continue recognizing |
|||
* this gesture. For example, if a gesture is beginning |
|||
* with a focal point outside of a region where it makes |
|||
* sense, onScaleBegin() may return false to ignore the |
|||
* rest of the gesture. |
|||
*/ |
|||
@Override |
|||
public boolean onScaleBegin(ScaleGestureDetector detector) { |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* Responds to the end of a scale gesture. Reported by existing |
|||
* pointers going up. |
|||
* <p/> |
|||
* Once a scale has ended, {@link ScaleGestureDetector#getFocusX()} |
|||
* and {@link ScaleGestureDetector#getFocusY()} will return focal point |
|||
* of the pointers remaining on the screen. |
|||
* |
|||
* @param detector The detector reporting the event - use this to |
|||
* retrieve extended info about event state. |
|||
*/ |
|||
@Override |
|||
public void onScaleEnd(ScaleGestureDetector detector) { |
|||
mCameraSource.doZoom(detector.getScaleFactor()); |
|||
} |
|||
} |
|||
|
|||
|
|||
@Override |
|||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { |
|||
View view= inflater.inflate(R.layout.fragment_qr_scanner_view, container, false); |
|||
mPreview = view.findViewById(R.id.preview); |
|||
mGraphicOverlay = view.findViewById(R.id.graphicOverlay); |
|||
gestureDetector = new GestureDetector(getActivity(), new CaptureGestureListener()); |
|||
scaleGestureDetector = new ScaleGestureDetector(getActivity(), new ScaleListener()); |
|||
view.setOnTouchListener(new View.OnTouchListener() { |
|||
@Override |
|||
public boolean onTouch(View v, MotionEvent e) { |
|||
boolean b = scaleGestureDetector.onTouchEvent(e); |
|||
|
|||
boolean c = gestureDetector.onTouchEvent(e); |
|||
|
|||
return b || c ; |
|||
} |
|||
}); |
|||
|
|||
return view; |
|||
} |
|||
|
|||
@Override |
|||
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { |
|||
super.onViewCreated(view, savedInstanceState); |
|||
init(); |
|||
performDefaultAction(savedInstanceState); |
|||
} |
|||
|
|||
protected void init() { |
|||
listener=provideListener(); |
|||
// read parameters from the intent used to launch the activity. |
|||
|
|||
// Check for the camera permission before accessing the camera. If the |
|||
// permission is not granted yet, request permission. |
|||
int rc = ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA); |
|||
if (rc == PackageManager.PERMISSION_GRANTED) { |
|||
createCameraSource(true, false); |
|||
} else { |
|||
requestCameraPermission(); |
|||
} |
|||
|
|||
|
|||
|
|||
Snackbar.make(mGraphicOverlay, "Scan to read QR. Pinch/Stretch to zoom", |
|||
Snackbar.LENGTH_LONG) |
|||
.show(); |
|||
|
|||
|
|||
} |
|||
|
|||
|
|||
protected void performDefaultAction(Bundle savedInstanceState) { |
|||
|
|||
|
|||
|
|||
} |
|||
|
|||
/** |
|||
* onTap returns the tapped barcode result to the calling Activity. |
|||
* |
|||
* @param rawX - the raw position of the tap |
|||
* @param rawY - the raw position of the tap. |
|||
* @return true if the activity is ending. |
|||
*/ |
|||
private boolean onTap(float rawX, float rawY) { |
|||
// Find tap point in preview frame coordinates. |
|||
int[] location = new int[2]; |
|||
mGraphicOverlay.getLocationOnScreen(location); |
|||
float x = (rawX - location[0]) / mGraphicOverlay.getWidthScaleFactor(); |
|||
float y = (rawY - location[1]) / mGraphicOverlay.getHeightScaleFactor(); |
|||
|
|||
// Find the barcode whose center is closest to the tapped point. |
|||
Barcode best = null; |
|||
float bestDistance = Float.MAX_VALUE; |
|||
for (BarcodeGraphic graphic : mGraphicOverlay.getGraphics()) { |
|||
Barcode barcode = graphic.getBarcode(); |
|||
if (barcode.getBoundingBox().contains((int) x, (int) y)) { |
|||
// Exact hit, no need to keep looking. |
|||
best = barcode; |
|||
break; |
|||
} |
|||
float dx = x - barcode.getBoundingBox().centerX(); |
|||
float dy = y - barcode.getBoundingBox().centerY(); |
|||
float distance = (dx * dx) + (dy * dy); // actually squared distance |
|||
if (distance < bestDistance) { |
|||
best = barcode; |
|||
bestDistance = distance; |
|||
} |
|||
} |
|||
if(best!=null) |
|||
listener.onBarcodeDetected(best); |
|||
return false; |
|||
} |
|||
|
|||
|
|||
|
|||
private void requestCameraPermission() { |
|||
|
|||
final String[] permissions = new String[]{Manifest.permission.CAMERA}; |
|||
|
|||
if (!ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), |
|||
Manifest.permission.CAMERA)) { |
|||
ActivityCompat.requestPermissions(getActivity(), permissions, RC_HANDLE_CAMERA_PERM); |
|||
return; |
|||
} |
|||
|
|||
|
|||
View.OnClickListener listener = new View.OnClickListener() { |
|||
@Override |
|||
public void onClick(View view) { |
|||
ActivityCompat.requestPermissions(getActivity(), permissions, |
|||
RC_HANDLE_CAMERA_PERM); |
|||
} |
|||
}; |
|||
|
|||
Toast.makeText(getActivity(),"Permission not resolved",Toast.LENGTH_SHORT).show(); |
|||
} |
|||
|
|||
@Override |
|||
public void onRequestPermissionsResult(int requestCode, |
|||
@NonNull String[] permissions, |
|||
@NonNull int[] grantResults) { |
|||
if (requestCode != RC_HANDLE_CAMERA_PERM) { |
|||
super.onRequestPermissionsResult(requestCode, permissions, grantResults); |
|||
return; |
|||
} |
|||
|
|||
if (grantResults.length != 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { |
|||
Log.d(TAG, "Camera permission granted - initialize the camera source"); |
|||
// we have permission, so create the camerasource |
|||
|
|||
createCameraSource(true, false); |
|||
return; |
|||
} |
|||
|
|||
Log.e(TAG, "Permission not granted: results len = " + grantResults.length + |
|||
" Result code = " + (grantResults.length > 0 ? grantResults[0] : "(empty)")); |
|||
|
|||
DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { |
|||
public void onClick(DialogInterface dialog, int id) { |
|||
|
|||
} |
|||
}; |
|||
|
|||
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getActivity()); |
|||
builder.setTitle("Multitracker sample") |
|||
.setMessage("No camera permission") |
|||
.setPositiveButton("Ok", listener) |
|||
.show(); |
|||
} |
|||
|
|||
|
|||
|
|||
/** |
|||
* Creates and starts the camera. Note that this uses a higher resolution in comparison |
|||
* to other detection examples to enable the barcode detector to detect small barcodes |
|||
* at long distances. |
|||
* |
|||
* Suppressing InlinedApi since there is a check that the minimum version is met before using |
|||
* the constant. |
|||
*/ |
|||
@SuppressLint("InlinedApi") |
|||
private void createCameraSource(boolean autoFocus, boolean useFlash) { |
|||
|
|||
|
|||
// A barcode detector is created to track barcodes. An associated multi-processor instance |
|||
// is set to receive the barcode detection results, track the barcodes, and maintain |
|||
// graphics for each barcode on screen. The factory is used by the multi-processor to |
|||
// create a separate tracker instance for each barcode. |
|||
BarcodeDetector barcodeDetector = new BarcodeDetector.Builder(getActivity()).setBarcodeFormats(Barcode.QR_CODE).build(); |
|||
BarcodeTrackerFactory barcodeFactory = new BarcodeTrackerFactory(mGraphicOverlay, listener); |
|||
barcodeDetector.setProcessor( |
|||
new MultiProcessor.Builder<>(barcodeFactory).build()); |
|||
|
|||
if (!barcodeDetector.isOperational()) { |
|||
// Note: The first time that an app using the barcode or face API is installed on a |
|||
// device, GMS will download a native libraries to the device in order to do detection. |
|||
// Usually this completes before the app is run for the first time. But if that |
|||
// download has not yet completed, then the above call will not detect any barcodes |
|||
// and/or faces. |
|||
// |
|||
// isOperational() can be used to check if the required native libraries are currently |
|||
// available. The detectors will automatically become operational once the library |
|||
// downloads complete on device. |
|||
|
|||
} |
|||
|
|||
// Creates and starts the camera. Note that this uses a higher resolution in comparison |
|||
// to other detection examples to enable the barcode detector to detect small barcodes |
|||
// at long distances. |
|||
MCameraSource.Builder builder = new MCameraSource.Builder(getActivity(), barcodeDetector) |
|||
.setFacing(CameraSource.CAMERA_FACING_BACK) |
|||
.setRequestedPreviewSize(1600, 1024) |
|||
.setRequestedFps(15.0f); |
|||
|
|||
// make sure that auto focus is an available option |
|||
builder = builder.setFocusMode( |
|||
autoFocus ? Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE : null); |
|||
|
|||
mCameraSource = builder |
|||
.build(); |
|||
} |
|||
|
|||
/** |
|||
* Starts or restarts the camera source, if it exists. If the camera source doesn't exist yet |
|||
* (e.g., because onResume was called before the camera source was created), this will be called |
|||
* again when the camera source is created. |
|||
*/ |
|||
private void startCameraSource() throws SecurityException { |
|||
// check that the device has play services available. |
|||
int code = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable( |
|||
getActivity()); |
|||
if (code != ConnectionResult.SUCCESS) { |
|||
Dialog dlg = |
|||
GoogleApiAvailability.getInstance().getErrorDialog(getActivity(), code, RC_HANDLE_GMS); |
|||
dlg.show(); |
|||
} |
|||
|
|||
if (mCameraSource != null) { |
|||
try { |
|||
mPreview.start(mCameraSource, mGraphicOverlay); |
|||
} catch (IOException e) { |
|||
Log.e(TAG, "Unable to start camera source.", e); |
|||
mCameraSource.release(); |
|||
mCameraSource = null; |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Restarts the camera. |
|||
*/ |
|||
@Override |
|||
public void onResume() { |
|||
super.onResume(); |
|||
startQrScanning(); |
|||
Log.d("BALANCEQR"," Parent onResume"); |
|||
|
|||
} |
|||
|
|||
/** |
|||
* Stops the camera. |
|||
*/ |
|||
@Override |
|||
public void onPause() { |
|||
stopQrScanning(); |
|||
super.onPause(); |
|||
|
|||
Log.d("BALANCEQR"," Parent onPause"); |
|||
} |
|||
|
|||
public void stopQrScanning() { |
|||
if (mPreview != null) { |
|||
mPreview.stop(); |
|||
} |
|||
} |
|||
public void startQrScanning() { |
|||
startCameraSource(); |
|||
} |
|||
|
|||
/** |
|||
* Releases the resources associated with the camera source, the associated detectors, and the |
|||
* rest of the processing pipeline. |
|||
*/ |
|||
@Override |
|||
public void onDestroy() { |
|||
super.onDestroy(); |
|||
if (mPreview != null) { |
|||
mPreview.release(); |
|||
} |
|||
|
|||
} |
|||
|
|||
|
|||
|
|||
} |
1216
app/src/main/java/com/swifttech/remit/android/common/view/qrscanner/camera/MCameraSource.java
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,190 @@ |
|||
/* |
|||
* Copyright (C) The Android Open Source Project |
|||
* |
|||
* 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.swifttech.remit.android.common.view.qrscanner.camera; |
|||
|
|||
import android.Manifest; |
|||
import android.content.Context; |
|||
import android.content.res.Configuration; |
|||
import android.util.AttributeSet; |
|||
import android.util.Log; |
|||
import android.view.SurfaceHolder; |
|||
import android.view.SurfaceView; |
|||
import android.view.ViewGroup; |
|||
|
|||
import androidx.annotation.RequiresPermission; |
|||
|
|||
import com.google.android.gms.common.images.Size; |
|||
|
|||
import java.io.IOException; |
|||
|
|||
public class MCameraSourcePreview extends ViewGroup { |
|||
private static final String TAG = "CameraSourcePreview"; |
|||
|
|||
private Context mContext; |
|||
private SurfaceView mSurfaceView; |
|||
private boolean mStartRequested; |
|||
private boolean mSurfaceAvailable; |
|||
private MCameraSource mCameraSource; |
|||
|
|||
private MGraphicOverlay mOverlay; |
|||
|
|||
public MCameraSourcePreview(Context context, AttributeSet attrs) { |
|||
super(context, attrs); |
|||
mContext = context; |
|||
mStartRequested = false; |
|||
mSurfaceAvailable = false; |
|||
|
|||
mSurfaceView = new SurfaceView(context); |
|||
mSurfaceView.getHolder().addCallback(new SurfaceCallback()); |
|||
addView(mSurfaceView); |
|||
} |
|||
|
|||
@RequiresPermission(Manifest.permission.CAMERA) |
|||
public void start(MCameraSource cameraSource) throws IOException, SecurityException { |
|||
if (cameraSource == null) { |
|||
stop(); |
|||
} |
|||
|
|||
mCameraSource = cameraSource; |
|||
|
|||
if (mCameraSource != null) { |
|||
mStartRequested = true; |
|||
startIfReady(); |
|||
} |
|||
} |
|||
|
|||
@RequiresPermission(Manifest.permission.CAMERA) |
|||
public void start(MCameraSource cameraSource, MGraphicOverlay overlay) throws IOException, SecurityException { |
|||
mOverlay = overlay; |
|||
start(cameraSource); |
|||
} |
|||
|
|||
public void stop() { |
|||
if (mCameraSource != null) { |
|||
mCameraSource.stop(); |
|||
} |
|||
} |
|||
|
|||
public void release() { |
|||
if (mCameraSource != null) { |
|||
mCameraSource.release(); |
|||
mCameraSource = null; |
|||
} |
|||
} |
|||
|
|||
@RequiresPermission(Manifest.permission.CAMERA) |
|||
private void startIfReady() throws IOException, SecurityException { |
|||
if (mStartRequested && mSurfaceAvailable) { |
|||
mCameraSource.start(mSurfaceView.getHolder()); |
|||
if (mOverlay != null) { |
|||
Size size = mCameraSource.getPreviewSize(); |
|||
int min = Math.min(size.getWidth(), size.getHeight()); |
|||
int max = Math.max(size.getWidth(), size.getHeight()); |
|||
if (isPortraitMode()) { |
|||
// Swap width and height sizes when in portrait, since it will be rotated by |
|||
// 90 degrees |
|||
mOverlay.setCameraInfo(min, max, mCameraSource.getCameraFacing()); |
|||
} else { |
|||
mOverlay.setCameraInfo(max, min, mCameraSource.getCameraFacing()); |
|||
} |
|||
mOverlay.clear(); |
|||
} |
|||
mStartRequested = false; |
|||
} |
|||
} |
|||
|
|||
private class SurfaceCallback implements SurfaceHolder.Callback { |
|||
@Override |
|||
public void surfaceCreated(SurfaceHolder surface) { |
|||
mSurfaceAvailable = true; |
|||
try { |
|||
startIfReady(); |
|||
} catch (SecurityException se) { |
|||
Log.e(TAG,"Do not have permission to start the camera", se); |
|||
} catch (IOException e) { |
|||
Log.e(TAG, "Could not start camera source.", e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void surfaceDestroyed(SurfaceHolder surface) { |
|||
mSurfaceAvailable = false; |
|||
} |
|||
|
|||
@Override |
|||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) { |
|||
int width = 320; |
|||
int height = 240; |
|||
if (mCameraSource != null) { |
|||
Size size = mCameraSource.getPreviewSize(); |
|||
if (size != null) { |
|||
width = size.getWidth(); |
|||
height = size.getHeight(); |
|||
} |
|||
} |
|||
|
|||
// Swap width and height sizes when in portrait, since it will be rotated 90 degrees |
|||
if (isPortraitMode()) { |
|||
int tmp = width; |
|||
//noinspection SuspiciousNameCombination |
|||
width = height; |
|||
height = tmp; |
|||
} |
|||
|
|||
final int layoutWidth = right - left; |
|||
final int layoutHeight = bottom - top; |
|||
|
|||
// Computes height and width for potentially doing fit width. |
|||
int childWidth = layoutWidth; |
|||
int childHeight = (int)(((float) layoutWidth / (float) width) * height); |
|||
|
|||
// If height is too tall using fit width, does fit height instead. |
|||
if (childHeight > layoutHeight) { |
|||
childHeight = layoutHeight; |
|||
childWidth = (int)(((float) layoutHeight / (float) height) * width); |
|||
} |
|||
|
|||
for (int i = 0; i < getChildCount(); ++i) { |
|||
getChildAt(i).layout(0, 0, childWidth, childHeight); |
|||
} |
|||
|
|||
try { |
|||
startIfReady(); |
|||
} catch (SecurityException se) { |
|||
Log.e(TAG,"Do not have permission to start the camera", se); |
|||
} catch (IOException e) { |
|||
Log.e(TAG, "Could not start camera source.", e); |
|||
} |
|||
} |
|||
|
|||
private boolean isPortraitMode() { |
|||
int orientation = mContext.getResources().getConfiguration().orientation; |
|||
if (orientation == Configuration.ORIENTATION_LANDSCAPE) { |
|||
return false; |
|||
} |
|||
if (orientation == Configuration.ORIENTATION_PORTRAIT) { |
|||
return true; |
|||
} |
|||
|
|||
Log.d(TAG, "isPortraitMode returning false by default"); |
|||
return false; |
|||
} |
|||
} |
@ -0,0 +1,212 @@ |
|||
/* |
|||
* Copyright (C) The Android Open Source Project |
|||
* |
|||
* 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.swifttech.remit.android.common.view.qrscanner.camera; |
|||
|
|||
import android.content.Context; |
|||
import android.graphics.Canvas; |
|||
import android.util.AttributeSet; |
|||
import android.view.View; |
|||
|
|||
import com.google.android.gms.vision.CameraSource; |
|||
|
|||
import java.util.HashSet; |
|||
import java.util.List; |
|||
import java.util.Set; |
|||
import java.util.Vector; |
|||
|
|||
/** |
|||
* A view which renders a series of custom graphics to be overlayed on top of an associated preview |
|||
* (i.e., the camera preview). The creator can add graphics objects, update the objects, and remove |
|||
* them, triggering the appropriate drawing and invalidation within the view.<p> |
|||
* |
|||
* Supports scaling and mirroring of the graphics relative the camera's preview properties. The |
|||
* idea is that detection items are expressed in terms of a preview size, but need to be scaled up |
|||
* to the full view size, and also mirrored in the case of the front-facing camera.<p> |
|||
* |
|||
* Associated {@link Graphic} items should use the following methods to convert to view coordinates |
|||
* for the graphics that are drawn: |
|||
* <ol> |
|||
* <li>{@link Graphic#scaleX(float)} and {@link Graphic#scaleY(float)} adjust the size of the |
|||
* supplied value from the preview scale to the view scale.</li> |
|||
* <li>{@link Graphic#translateX(float)} and {@link Graphic#translateY(float)} adjust the coordinate |
|||
* from the preview's coordinate system to the view coordinate system.</li> |
|||
* </ol> |
|||
*/ |
|||
public class MGraphicOverlay<T extends MGraphicOverlay.Graphic> extends View { |
|||
private final Object mLock = new Object(); |
|||
private int mPreviewWidth; |
|||
private float mWidthScaleFactor = 1.0f; |
|||
private int mPreviewHeight; |
|||
private float mHeightScaleFactor = 1.0f; |
|||
private int mFacing = CameraSource.CAMERA_FACING_BACK; |
|||
private Set<T> mGraphics = new HashSet<>(); |
|||
|
|||
/** |
|||
* Base class for a custom graphics object to be rendered within the graphic overlay. Subclass |
|||
* this and implement the {@link Graphic#draw(Canvas)} method to define the |
|||
* graphics element. Add instances to the overlay using {@link MGraphicOverlay#add(Graphic)}. |
|||
*/ |
|||
public static abstract class Graphic { |
|||
private MGraphicOverlay mOverlay; |
|||
|
|||
public Graphic(MGraphicOverlay overlay) { |
|||
mOverlay = overlay; |
|||
} |
|||
|
|||
/** |
|||
* Draw the graphic on the supplied canvas. Drawing should use the following methods to |
|||
* convert to view coordinates for the graphics that are drawn: |
|||
* <ol> |
|||
* <li>{@link Graphic#scaleX(float)} and {@link Graphic#scaleY(float)} adjust the size of |
|||
* the supplied value from the preview scale to the view scale.</li> |
|||
* <li>{@link Graphic#translateX(float)} and {@link Graphic#translateY(float)} adjust the |
|||
* coordinate from the preview's coordinate system to the view coordinate system.</li> |
|||
* </ol> |
|||
* |
|||
* @param canvas drawing canvas |
|||
*/ |
|||
public abstract void draw(Canvas canvas); |
|||
|
|||
/** |
|||
* Adjusts a horizontal value of the supplied value from the preview scale to the view |
|||
* scale. |
|||
*/ |
|||
public float scaleX(float horizontal) { |
|||
return horizontal * mOverlay.mWidthScaleFactor; |
|||
} |
|||
|
|||
/** |
|||
* Adjusts a vertical value of the supplied value from the preview scale to the view scale. |
|||
*/ |
|||
public float scaleY(float vertical) { |
|||
return vertical * mOverlay.mHeightScaleFactor; |
|||
} |
|||
|
|||
/** |
|||
* Adjusts the x coordinate from the preview's coordinate system to the view coordinate |
|||
* system. |
|||
*/ |
|||
public float translateX(float x) { |
|||
if (mOverlay.mFacing == CameraSource.CAMERA_FACING_FRONT) { |
|||
return mOverlay.getWidth() - scaleX(x); |
|||
} else { |
|||
return scaleX(x); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Adjusts the y coordinate from the preview's coordinate system to the view coordinate |
|||
* system. |
|||
*/ |
|||
public float translateY(float y) { |
|||
return scaleY(y); |
|||
} |
|||
|
|||
public void postInvalidate() { |
|||
mOverlay.postInvalidate(); |
|||
} |
|||
} |
|||
|
|||
public MGraphicOverlay(Context context, AttributeSet attrs) { |
|||
super(context, attrs); |
|||
} |
|||
|
|||
/** |
|||
* Removes all graphics from the overlay. |
|||
*/ |
|||
public void clear() { |
|||
synchronized (mLock) { |
|||
mGraphics.clear(); |
|||
} |
|||
postInvalidate(); |
|||
} |
|||
|
|||
/** |
|||
* Adds a graphic to the overlay. |
|||
*/ |
|||
public void add(T graphic) { |
|||
synchronized (mLock) { |
|||
mGraphics.add(graphic); |
|||
} |
|||
postInvalidate(); |
|||
} |
|||
|
|||
/** |
|||
* Removes a graphic from the overlay. |
|||
*/ |
|||
public void remove(T graphic) { |
|||
synchronized (mLock) { |
|||
mGraphics.remove(graphic); |
|||
} |
|||
postInvalidate(); |
|||
} |
|||
|
|||
/** |
|||
* Returns a copy (as a list) of the set of all active graphics. |
|||
* @return list of all active graphics. |
|||
*/ |
|||
public List<T> getGraphics() { |
|||
synchronized (mLock) { |
|||
return new Vector(mGraphics); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Returns the horizontal scale factor. |
|||
*/ |
|||
public float getWidthScaleFactor() { |
|||
return mWidthScaleFactor; |
|||
} |
|||
|
|||
/** |
|||
* Returns the vertical scale factor. |
|||
*/ |
|||
public float getHeightScaleFactor() { |
|||
return mHeightScaleFactor; |
|||
} |
|||
|
|||
/** |
|||
* Sets the camera attributes for size and facing direction, which informs how to transform |
|||
* image coordinates later. |
|||
*/ |
|||
public void setCameraInfo(int previewWidth, int previewHeight, int facing) { |
|||
synchronized (mLock) { |
|||
mPreviewWidth = previewWidth; |
|||
mPreviewHeight = previewHeight; |
|||
mFacing = facing; |
|||
} |
|||
postInvalidate(); |
|||
} |
|||
|
|||
/** |
|||
* Draws the overlay with its associated graphic objects. |
|||
*/ |
|||
@Override |
|||
protected void onDraw(Canvas canvas) { |
|||
super.onDraw(canvas); |
|||
|
|||
synchronized (mLock) { |
|||
if ((mPreviewWidth != 0) && (mPreviewHeight != 0)) { |
|||
mWidthScaleFactor = (float) canvas.getWidth() / (float) mPreviewWidth; |
|||
mHeightScaleFactor = (float) canvas.getHeight() / (float) mPreviewHeight; |
|||
} |
|||
|
|||
for (Graphic graphic : mGraphics) { |
|||
graphic.draw(canvas); |
|||
} |
|||
} |
|||
} |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue