Java tutorial
// Copyright 2018 Google LLC // // 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.firebase.samples.apps.mlkit.java; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.hardware.Camera; import android.os.Bundle; import android.support.v4.app.ActivityCompat; import android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback; import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemSelectedListener; import android.widget.ArrayAdapter; import android.widget.CompoundButton; import android.widget.Spinner; import android.widget.ToggleButton; import com.google.android.gms.common.annotation.KeepName; import com.google.firebase.ml.common.FirebaseMLException; import com.google.firebase.samples.apps.mlkit.R; import com.google.firebase.samples.apps.mlkit.common.CameraSource; import com.google.firebase.samples.apps.mlkit.common.CameraSourcePreview; import com.google.firebase.samples.apps.mlkit.common.GraphicOverlay; import com.google.firebase.samples.apps.mlkit.java.barcodescanning.BarcodeScanningProcessor; import com.google.firebase.samples.apps.mlkit.java.custommodel.CustomImageClassifierProcessor; import com.google.firebase.samples.apps.mlkit.java.facedetection.FaceContourDetectorProcessor; import com.google.firebase.samples.apps.mlkit.java.facedetection.FaceDetectionProcessor; import com.google.firebase.samples.apps.mlkit.java.imagelabeling.ImageLabelingProcessor; import com.google.firebase.samples.apps.mlkit.java.textrecognition.TextRecognitionProcessor; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** Demo app showing the various features of ML Kit for Firebase. This class is used to * set up continuous frame processing on frames from a camera source. */ @KeepName public final class LivePreviewActivity extends AppCompatActivity implements OnRequestPermissionsResultCallback, OnItemSelectedListener, CompoundButton.OnCheckedChangeListener { private static final String FACE_DETECTION = "Face Detection"; private static final String TEXT_DETECTION = "Text Detection"; private static final String BARCODE_DETECTION = "Barcode Detection"; private static final String IMAGE_LABEL_DETECTION = "Label Detection"; private static final String CLASSIFICATION_QUANT = "Classification (quantized)"; private static final String CLASSIFICATION_FLOAT = "Classification (float)"; private static final String FACE_CONTOUR = "Face Contour"; private static final String TAG = "LivePreviewActivity"; private static final int PERMISSION_REQUESTS = 1; private CameraSource cameraSource = null; private CameraSourcePreview preview; private GraphicOverlay graphicOverlay; private String selectedModel = FACE_CONTOUR; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d(TAG, "onCreate"); setContentView(R.layout.activity_live_preview); preview = (CameraSourcePreview) findViewById(R.id.firePreview); if (preview == null) { Log.d(TAG, "Preview is null"); } graphicOverlay = (GraphicOverlay) findViewById(R.id.fireFaceOverlay); if (graphicOverlay == null) { Log.d(TAG, "graphicOverlay is null"); } Spinner spinner = (Spinner) findViewById(R.id.spinner); List<String> options = new ArrayList<>(); options.add(FACE_CONTOUR); options.add(FACE_DETECTION); options.add(TEXT_DETECTION); options.add(BARCODE_DETECTION); options.add(IMAGE_LABEL_DETECTION); options.add(CLASSIFICATION_QUANT); options.add(CLASSIFICATION_FLOAT); // Creating adapter for spinner ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this, R.layout.spinner_style, options); // Drop down layout style - list view with radio button dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); // attaching data adapter to spinner spinner.setAdapter(dataAdapter); spinner.setOnItemSelectedListener(this); ToggleButton facingSwitch = (ToggleButton) findViewById(R.id.facingSwitch); facingSwitch.setOnCheckedChangeListener(this); // Hide the toggle button if there is only 1 camera if (Camera.getNumberOfCameras() == 1) { facingSwitch.setVisibility(View.GONE); } if (allPermissionsGranted()) { createCameraSource(selectedModel); } else { getRuntimePermissions(); } } @Override public synchronized void onItemSelected(AdapterView<?> parent, View view, int pos, long id) { // An item was selected. You can retrieve the selected item using // parent.getItemAtPosition(pos) selectedModel = parent.getItemAtPosition(pos).toString(); Log.d(TAG, "Selected model: " + selectedModel); preview.stop(); if (allPermissionsGranted()) { createCameraSource(selectedModel); startCameraSource(); } else { getRuntimePermissions(); } } @Override public void onNothingSelected(AdapterView<?> parent) { // Do nothing. } @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { Log.d(TAG, "Set facing"); if (cameraSource != null) { if (isChecked) { cameraSource.setFacing(CameraSource.CAMERA_FACING_FRONT); } else { cameraSource.setFacing(CameraSource.CAMERA_FACING_BACK); } } preview.stop(); startCameraSource(); } private void createCameraSource(String model) { // If there's no existing cameraSource, create one. if (cameraSource == null) { cameraSource = new CameraSource(this, graphicOverlay); } try { switch (model) { case CLASSIFICATION_QUANT: Log.i(TAG, "Using Custom Image Classifier (quant) Processor"); cameraSource.setMachineLearningFrameProcessor(new CustomImageClassifierProcessor(this, true)); break; case CLASSIFICATION_FLOAT: Log.i(TAG, "Using Custom Image Classifier (float) Processor"); cameraSource.setMachineLearningFrameProcessor(new CustomImageClassifierProcessor(this, false)); break; case TEXT_DETECTION: Log.i(TAG, "Using Text Detector Processor"); cameraSource.setMachineLearningFrameProcessor(new TextRecognitionProcessor()); break; case FACE_DETECTION: Log.i(TAG, "Using Face Detector Processor"); cameraSource.setMachineLearningFrameProcessor(new FaceDetectionProcessor()); break; case BARCODE_DETECTION: Log.i(TAG, "Using Barcode Detector Processor"); cameraSource.setMachineLearningFrameProcessor(new BarcodeScanningProcessor()); break; case IMAGE_LABEL_DETECTION: Log.i(TAG, "Using Image Label Detector Processor"); cameraSource.setMachineLearningFrameProcessor(new ImageLabelingProcessor()); break; case FACE_CONTOUR: Log.i(TAG, "Using Face Contour Detector Processor"); cameraSource.setMachineLearningFrameProcessor(new FaceContourDetectorProcessor()); break; default: Log.e(TAG, "Unknown model: " + model); } } catch (FirebaseMLException e) { Log.e(TAG, "can not create camera source: " + model); } } /** * 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() { if (cameraSource != null) { try { if (preview == null) { Log.d(TAG, "resume: Preview is null"); } if (graphicOverlay == null) { Log.d(TAG, "resume: graphOverlay is null"); } preview.start(cameraSource, graphicOverlay); } catch (IOException e) { Log.e(TAG, "Unable to start camera source.", e); cameraSource.release(); cameraSource = null; } } } @Override public void onResume() { super.onResume(); Log.d(TAG, "onResume"); startCameraSource(); } /** Stops the camera. */ @Override protected void onPause() { super.onPause(); preview.stop(); } @Override public void onDestroy() { super.onDestroy(); if (cameraSource != null) { cameraSource.release(); } } private String[] getRequiredPermissions() { try { PackageInfo info = this.getPackageManager().getPackageInfo(this.getPackageName(), PackageManager.GET_PERMISSIONS); String[] ps = info.requestedPermissions; if (ps != null && ps.length > 0) { return ps; } else { return new String[0]; } } catch (Exception e) { return new String[0]; } } private boolean allPermissionsGranted() { for (String permission : getRequiredPermissions()) { if (!isPermissionGranted(this, permission)) { return false; } } return true; } private void getRuntimePermissions() { List<String> allNeededPermissions = new ArrayList<>(); for (String permission : getRequiredPermissions()) { if (!isPermissionGranted(this, permission)) { allNeededPermissions.add(permission); } } if (!allNeededPermissions.isEmpty()) { ActivityCompat.requestPermissions(this, allNeededPermissions.toArray(new String[0]), PERMISSION_REQUESTS); } } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { Log.i(TAG, "Permission granted!"); if (allPermissionsGranted()) { createCameraSource(selectedModel); } super.onRequestPermissionsResult(requestCode, permissions, grantResults); } private static boolean isPermissionGranted(Context context, String permission) { if (ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED) { Log.i(TAG, "Permission granted: " + permission); return true; } Log.i(TAG, "Permission NOT granted: " + permission); return false; } }