| /* |
| * Copyright 2016 Google Inc. All Rights Reserved. |
| * |
| * 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. |
| */ |
| |
| /* Author: Lorenzo Bracco a.k.a. devtry (devtry@riseup.net) */ |
| |
| packagecom.dexin; |
| |
| importandroid.Manifest; |
| importandroid.content.DialogInterface; |
| importandroid.content.Intent; |
| importandroid.graphics.Bitmap; |
| importandroid.graphics.Canvas; |
| importandroid.graphics.Color; |
| importandroid.graphics.ColorFilter; |
| importandroid.graphics.PixelFormat; |
| importandroid.graphics.drawable.BitmapDrawable; |
| importandroid.graphics.drawable.ColorDrawable; |
| importandroid.graphics.drawable.Drawable; |
| importandroid.net.Uri; |
| importandroid.os.AsyncTask; |
| importandroid.os.Bundle; |
| importandroid.os.Environment; |
| importandroid.provider.MediaStore; |
| importandroid.support.annotation.IntRange; |
| importandroid.support.annotation.NonNull; |
| importandroid.support.annotation.Nullable; |
| importandroid.support.design.widget.FloatingActionButton; |
| importandroid.support.v4.content.FileProvider; |
| importandroid.support.v7.app.AlertDialog; |
| importandroid.support.v7.app.AppCompatActivity; |
| importandroid.support.v7.widget.Toolbar; |
| importandroid.util.Log; |
| importandroid.view.View; |
| importandroid.widget.ImageView; |
| importandroid.widget.TextView; |
| importandroid.widget.Toast; |
| |
| importandroid.text.Html; |
| |
| importandroid.R.color; |
| |
| importcom.google.api.client.extensions.android.http.AndroidHttp; |
| importcom.google.api.client.googleapis.json.GoogleJsonResponseException; |
| importcom.google.api.client.http.HttpTransport; |
| importcom.google.api.client.json.JsonFactory; |
| importcom.google.api.client.json.gson.GsonFactory; |
| importcom.google.api.services.vision.v1.Vision; |
| importcom.google.api.services.vision.v1.VisionRequest; |
| importcom.google.api.services.vision.v1.VisionRequestInitializer; |
| importcom.google.api.services.vision.v1.model.AnnotateImageRequest; |
| importcom.google.api.services.vision.v1.model.BatchAnnotateImagesRequest; |
| importcom.google.api.services.vision.v1.model.BatchAnnotateImagesResponse; |
| importcom.google.api.services.vision.v1.model.EntityAnnotation; |
| importcom.google.api.services.vision.v1.model.Feature; |
| importcom.google.api.services.vision.v1.model.Image; |
| |
| importjava.io.ByteArrayOutputStream; |
| importjava.io.File; |
| importjava.io.IOException; |
| importjava.util.ArrayList; |
| importjava.util.List; |
| importjava.util.Locale; |
| |
| publicclassMainActivityextendsAppCompatActivity { |
| privatestaticfinalStringCLOUD_VISION_API_KEY=" AIzaSyDGS_DRiMBwXN3ijn68vCe7NoQ-8bcRuL0 "; |
| publicstaticfinalStringFILE_NAME="temp.jpg"; |
| privatestaticfinalStringANDROID_CERT_HEADER="X-Android-Cert"; |
| privatestaticfinalStringANDROID_PACKAGE_HEADER="X-Android-Package"; |
| |
| privatestaticfinalStringTAG=MainActivity.class.getSimpleName(); |
| privatestaticfinalintGALLERY_PERMISSIONS_REQUEST=0; |
| privatestaticfinalintGALLERY_IMAGE_REQUEST=1; |
| publicstaticfinalintCAMERA_PERMISSIONS_REQUEST=2; |
| publicstaticfinalintCAMERA_IMAGE_REQUEST=3; |
| |
| privateTextView mImageDetails; |
| privateImageView mMainImage; |
| |
| @Override |
| protectedvoidonCreate(BundlesavedInstanceState) { |
| super.onCreate(savedInstanceState); |
| getWindow().getDecorView().setBackground(getResources().getDrawable(R.drawable.map)); |
| setContentView(R.layout.activity_main); |
| |
| findViewById(R.id.loadingPanel).setVisibility(View.INVISIBLE); |
| |
| ImageView viewImage = (ImageView)findViewById(R.id.main_image); |
| viewImage.setVisibility(View.INVISIBLE); |
| |
| /*SupportMapFragment mapFragment = null; |
| while (mapFragment == null) |
| mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map); |
| |
| mapFragment.getMapAsync(this);*/ |
| |
| FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); |
| fab.setImageDrawable(getResources().getDrawable(R.drawable.buttonphoto2)); |
| fab.setOnClickListener(newView.OnClickListener() { |
| @Override |
| publicvoidonClick(Viewview) { |
| AlertDialog.Builder builder =newAlertDialog.Builder(MainActivity.this); |
| builder |
| .setMessage(R.string.dialog_select_prompt) |
| .setPositiveButton(R.string.dialog_select_gallery, newDialogInterface.OnClickListener() { |
| @Override |
| publicvoidonClick(DialogInterfacedialog, intwhich) { |
| startGalleryChooser(); |
| } |
| }) |
| .setNegativeButton(R.string.dialog_select_camera, newDialogInterface.OnClickListener() { |
| @Override |
| publicvoidonClick(DialogInterfacedialog, intwhich) { |
| startCamera(); |
| } |
| }); |
| builder.create().show(); |
| } |
| }); |
| |
| mImageDetails = (TextView) findViewById(R.id.image_details); |
| mMainImage = (ImageView) findViewById(R.id.main_image); |
| } |
| |
| publicvoidstartGalleryChooser() { |
| if (PermissionUtils.requestPermission(this, GALLERY_PERMISSIONS_REQUEST, Manifest.permission.READ_EXTERNAL_STORAGE)) { |
| Intent intent =newIntent(); |
| intent.setType("image/*"); |
| intent.setAction(Intent.ACTION_GET_CONTENT); |
| startActivityForResult(Intent.createChooser(intent, "Select a photo"), |
| GALLERY_IMAGE_REQUEST); |
| } |
| } |
| |
| publicvoidstartCamera() { |
| if (PermissionUtils.requestPermission( |
| this, |
| CAMERA_PERMISSIONS_REQUEST, |
| Manifest.permission.READ_EXTERNAL_STORAGE, |
| Manifest.permission.CAMERA)) { |
| Intent intent =newIntent(MediaStore.ACTION_IMAGE_CAPTURE); |
| Uri photoUri =FileProvider.getUriForFile(this, getApplicationContext().getPackageName() +".provider", getCameraFile()); |
| intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri); |
| intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); |
| startActivityForResult(intent, CAMERA_IMAGE_REQUEST); |
| } |
| } |
| |
| publicFilegetCameraFile() { |
| File dir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); |
| returnnewFile(dir, FILE_NAME); |
| } |
| |
| @Override |
| protectedvoidonActivityResult(intrequestCode, intresultCode, Intentdata) { |
| super.onActivityResult(requestCode, resultCode, data); |
| |
| if (requestCode ==GALLERY_IMAGE_REQUEST&& resultCode ==RESULT_OK&& data !=null) { |
| uploadImage(data.getData()); |
| } elseif (requestCode ==CAMERA_IMAGE_REQUEST&& resultCode ==RESULT_OK) { |
| Uri photoUri =FileProvider.getUriForFile(this, getApplicationContext().getPackageName() +".provider", getCameraFile()); |
| uploadImage(photoUri); |
| } |
| } |
| |
| @Override |
| publicvoidonRequestPermissionsResult( |
| intrequestCode, @NonNullString[] permissions, @NonNullint[] grantResults) { |
| super.onRequestPermissionsResult(requestCode, permissions, grantResults); |
| switch (requestCode) { |
| caseCAMERA_PERMISSIONS_REQUEST: |
| if (PermissionUtils.permissionGranted(requestCode, CAMERA_PERMISSIONS_REQUEST, grantResults)) { |
| startCamera(); |
| } |
| break; |
| caseGALLERY_PERMISSIONS_REQUEST: |
| if (PermissionUtils.permissionGranted(requestCode, GALLERY_PERMISSIONS_REQUEST, grantResults)) { |
| startGalleryChooser(); |
| } |
| break; |
| } |
| } |
| |
| publicvoiduploadImage(Uriuri) { |
| if (uri !=null) { |
| try { |
| // scale the image to save on bandwidth |
| Bitmap bitmap = |
| scaleBitmapDown( |
| MediaStore.Images.Media.getBitmap(getContentResolver(), uri), |
| 1200); |
| |
| callCloudVision(bitmap); |
| mMainImage.setImageBitmap(bitmap); |
| |
| } catch (IOException e) { |
| Log.d(TAG, "Image picking failed because "+ e.getMessage()); |
| Toast.makeText(this, R.string.image_picker_error, Toast.LENGTH_LONG).show(); |
| } |
| } else { |
| Log.d(TAG, "Image picker gave us a null image."); |
| Toast.makeText(this, R.string.image_picker_error, Toast.LENGTH_LONG).show(); |
| } |
| } |
| |
| privatevoidcallCloudVision(finalBitmapbitmap) throwsIOException { |
| // Switch text to loading |
| findViewById(R.id.loadingPanel).setVisibility(View.VISIBLE); |
| getWindow().getDecorView().setBackground(null); |
| getWindow().getDecorView().setBackgroundColor(Color.WHITE); |
| |
| FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); |
| fab.setImageDrawable(getResources().getDrawable(R.drawable.check)); |
| |
| ImageView viewImage = (ImageView)findViewById(R.id.main_image); |
| viewImage.setVisibility(View.VISIBLE); |
| |
| mImageDetails.setText(R.string.loading_message); |
| |
| // Do the real work in an async task, because we need to use the network anyway |
| newAsyncTask<Object, Void, String>() { |
| @Override |
| protectedStringdoInBackground(Object... params) { |
| try { |
| HttpTransport httpTransport =AndroidHttp.newCompatibleTransport(); |
| JsonFactory jsonFactory =GsonFactory.getDefaultInstance(); |
| |
| VisionRequestInitializer requestInitializer = |
| newVisionRequestInitializer(CLOUD_VISION_API_KEY) { |
| /** |
| * We override this so we can inject important identifying fields into the HTTP |
| * headers. This enables use of a restricted cloud platform API key. |
| */ |
| @Override |
| protectedvoidinitializeVisionRequest(VisionRequest<?>visionRequest) |
| throwsIOException { |
| super.initializeVisionRequest(visionRequest); |
| |
| String packageName = getPackageName(); |
| visionRequest.getRequestHeaders().set(ANDROID_PACKAGE_HEADER, packageName); |
| |
| String sig =PackageManagerUtils.getSignature(getPackageManager(), packageName); |
| |
| visionRequest.getRequestHeaders().set(ANDROID_CERT_HEADER, sig); |
| } |
| }; |
| |
| Vision.Builder builder =newVision.Builder(httpTransport, jsonFactory, null); |
| builder.setVisionRequestInitializer(requestInitializer); |
| |
| Vision vision = builder.build(); |
| |
| BatchAnnotateImagesRequest batchAnnotateImagesRequest = |
| newBatchAnnotateImagesRequest(); |
| batchAnnotateImagesRequest.setRequests(newArrayList<AnnotateImageRequest>() {{ |
| AnnotateImageRequest annotateImageRequest =newAnnotateImageRequest(); |
| |
| // Add the image |
| Image base64EncodedImage =newImage(); |
| // Convert the bitmap to a JPEG |
| // Just in case it's a format that Android understands but Cloud Vision |
| ByteArrayOutputStream byteArrayOutputStream =newByteArrayOutputStream(); |
| bitmap.compress(Bitmap.CompressFormat.JPEG, 90, byteArrayOutputStream); |
| byte[] imageBytes = byteArrayOutputStream.toByteArray(); |
| |
| // Base64 encode the JPEG |
| base64EncodedImage.encodeContent(imageBytes); |
| annotateImageRequest.setImage(base64EncodedImage); |
| |
| // add the features we want |
| annotateImageRequest.setFeatures(newArrayList<Feature>() {{ |
| Feature labelDetection =newFeature(); |
| labelDetection.setType("LABEL_DETECTION"); |
| labelDetection.setMaxResults(10); |
| add(labelDetection); |
| }}); |
| |
| // Add the list of one thing to the request |
| add(annotateImageRequest); |
| }}); |
| |
| Vision.Images.Annotate annotateRequest = |
| vision.images().annotate(batchAnnotateImagesRequest); |
| // Due to a bug: requests to Vision API containing large images fail when GZipped. |
| annotateRequest.setDisableGZipContent(true); |
| Log.d(TAG, "created Cloud Vision request object, sending request"); |
| |
| BatchAnnotateImagesResponse response = annotateRequest.execute(); |
| return convertResponseToString(response); |
| |
| } catch (GoogleJsonResponseException e) { |
| Log.d(TAG, "failed to make API request because "+ e.getContent()); |
| } catch (IOException e) { |
| Log.d(TAG, "failed to make API request because of other IOException "+ |
| e.getMessage()); |
| } |
| return"Cloud Vision API request failed. Check logs for details."; |
| } |
| |
| protectedvoidonPostExecute(Stringresult) { |
| findViewById(R.id.loadingPanel).setVisibility(View.GONE); |
| mImageDetails.setText(Html.fromHtml(result)); |
| } |
| }.execute(); |
| } |
| |
| publicBitmapscaleBitmapDown(Bitmapbitmap, intmaxDimension) { |
| |
| int originalWidth = bitmap.getWidth(); |
| int originalHeight = bitmap.getHeight(); |
| int resizedWidth = maxDimension; |
| int resizedHeight = maxDimension; |
| |
| if (originalHeight > originalWidth) { |
| resizedHeight = maxDimension; |
| resizedWidth = (int) (resizedHeight * (float) originalWidth / (float) originalHeight); |
| } elseif (originalWidth > originalHeight) { |
| resizedWidth = maxDimension; |
| resizedHeight = (int) (resizedWidth * (float) originalHeight / (float) originalWidth); |
| } elseif (originalHeight == originalWidth) { |
| resizedHeight = maxDimension; |
| resizedWidth = maxDimension; |
| } |
| returnBitmap.createScaledBitmap(bitmap, resizedWidth, resizedHeight, false); |
| } |
| |
| privateStringconvertResponseToString(BatchAnnotateImagesResponseresponse) { |
| String message ="Recognized as "; |
| |
| List<EntityAnnotation> labels = response.getResponses().get(0).getLabelAnnotations(); |
| if (labels !=null) { |
| for (EntityAnnotation label : labels) { |
| message +=String.format(Locale.US, "<b>%s</b>", label.getDescription()); |
| message +="<br /><br /><big><b>Bottle</b></big><br /><i>/bot-l/</i><br />A portable container for holding liquids, characteristically having a neck and mouth and made of glass or plastic."; |
| break; |
| } |
| } else { |
| message +="nothing!"; |
| } |
| |
| return message; |
| } |
| } |