Full repository for DEX.in at https://github.com/SpaceAppsMilan/DEX.in
Last active
April 30, 2017 21:55
-
-
Save devtryongit/a2b765efda0770f8fc10150b1dfe3c02 to your computer and use it in GitHub Desktop.
DEX.in - People’s Choice nominee and nominated for global judging - Milan Space Apps Challenge 2017
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:app="http://schemas.android.com/apk/res-auto" | |
xmlns:tools="http://schemas.android.com/tools" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:fitsSystemWindows="true" | |
tools:context="com.dexin.MainActivity"> | |
<android.support.design.widget.AppBarLayout | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:theme="@style/AppTheme.AppBarOverlay"> | |
</android.support.design.widget.AppBarLayout> | |
<android.support.design.widget.FloatingActionButton | |
android:id="@+id/fab" | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:layout_gravity="bottom|center" | |
android:layout_margin="@dimen/fab_margin" | |
app:backgroundTint="@null" | |
app:fabSize="normal" | |
android:padding="0dp" | |
android:scaleType="center" | |
/> | |
<include layout="@layout/content_main" /> | |
</android.support.design.widget.CoordinatorLayout> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:app="http://schemas.android.com/apk/res-auto" | |
xmlns:tools="http://schemas.android.com/tools" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
app:layout_behavior="@string/appbar_scrolling_view_behavior" | |
tools:context="com.dexin.MainActivity" | |
tools:showIn="@layout/activity_main"> | |
<ScrollView | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:id="@+id/scrollView2"> | |
<LinearLayout | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:orientation="vertical" | |
android:weightSum="1"> | |
<ImageView | |
android:id="@+id/main_image" | |
android:background="#19191b" | |
android:layout_width="match_parent" | |
android:layout_height="300dp" | |
android:layout_alignStart="@+id/scrollView2" | |
android:layout_alignTop="@+id/scrollView2" | |
android:layout_weight="6.33" | |
android:scaleType="fitCenter" /> | |
<TextView | |
android:id="@+id/image_details" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:layout_marginBottom="8dp" | |
android:layout_margin="16dp" | |
android:textSize="20dp" | |
android:layout_weight="11.04" /> | |
<ProgressBar | |
android:id="@+id/loadingPanel" | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:indeterminate="true" | |
android:layout_gravity="center" /> | |
</LinearLayout> | |
</ScrollView> | |
</RelativeLayout> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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) */ | |
package com.dexin; | |
import android.Manifest; | |
import android.content.DialogInterface; | |
import android.content.Intent; | |
import android.graphics.Bitmap; | |
import android.graphics.Canvas; | |
import android.graphics.Color; | |
import android.graphics.ColorFilter; | |
import android.graphics.PixelFormat; | |
import android.graphics.drawable.BitmapDrawable; | |
import android.graphics.drawable.ColorDrawable; | |
import android.graphics.drawable.Drawable; | |
import android.net.Uri; | |
import android.os.AsyncTask; | |
import android.os.Bundle; | |
import android.os.Environment; | |
import android.provider.MediaStore; | |
import android.support.annotation.IntRange; | |
import android.support.annotation.NonNull; | |
import android.support.annotation.Nullable; | |
import android.support.design.widget.FloatingActionButton; | |
import android.support.v4.content.FileProvider; | |
import android.support.v7.app.AlertDialog; | |
import android.support.v7.app.AppCompatActivity; | |
import android.support.v7.widget.Toolbar; | |
import android.util.Log; | |
import android.view.View; | |
import android.widget.ImageView; | |
import android.widget.TextView; | |
import android.widget.Toast; | |
import android.text.Html; | |
import android.R.color; | |
import com.google.api.client.extensions.android.http.AndroidHttp; | |
import com.google.api.client.googleapis.json.GoogleJsonResponseException; | |
import com.google.api.client.http.HttpTransport; | |
import com.google.api.client.json.JsonFactory; | |
import com.google.api.client.json.gson.GsonFactory; | |
import com.google.api.services.vision.v1.Vision; | |
import com.google.api.services.vision.v1.VisionRequest; | |
import com.google.api.services.vision.v1.VisionRequestInitializer; | |
import com.google.api.services.vision.v1.model.AnnotateImageRequest; | |
import com.google.api.services.vision.v1.model.BatchAnnotateImagesRequest; | |
import com.google.api.services.vision.v1.model.BatchAnnotateImagesResponse; | |
import com.google.api.services.vision.v1.model.EntityAnnotation; | |
import com.google.api.services.vision.v1.model.Feature; | |
import com.google.api.services.vision.v1.model.Image; | |
import java.io.ByteArrayOutputStream; | |
import java.io.File; | |
import java.io.IOException; | |
import java.util.ArrayList; | |
import java.util.List; | |
import java.util.Locale; | |
public class MainActivity extends AppCompatActivity { | |
private static final String CLOUD_VISION_API_KEY = " AIzaSyDGS_DRiMBwXN3ijn68vCe7NoQ-8bcRuL0 "; | |
public static final String FILE_NAME = "temp.jpg"; | |
private static final String ANDROID_CERT_HEADER = "X-Android-Cert"; | |
private static final String ANDROID_PACKAGE_HEADER = "X-Android-Package"; | |
private static final String TAG = MainActivity.class.getSimpleName(); | |
private static final int GALLERY_PERMISSIONS_REQUEST = 0; | |
private static final int GALLERY_IMAGE_REQUEST = 1; | |
public static final int CAMERA_PERMISSIONS_REQUEST = 2; | |
public static final int CAMERA_IMAGE_REQUEST = 3; | |
private TextView mImageDetails; | |
private ImageView mMainImage; | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
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(new View.OnClickListener() { | |
@Override | |
public void onClick(View view) { | |
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); | |
builder | |
.setMessage(R.string.dialog_select_prompt) | |
.setPositiveButton(R.string.dialog_select_gallery, new DialogInterface.OnClickListener() { | |
@Override | |
public void onClick(DialogInterface dialog, int which) { | |
startGalleryChooser(); | |
} | |
}) | |
.setNegativeButton(R.string.dialog_select_camera, new DialogInterface.OnClickListener() { | |
@Override | |
public void onClick(DialogInterface dialog, int which) { | |
startCamera(); | |
} | |
}); | |
builder.create().show(); | |
} | |
}); | |
mImageDetails = (TextView) findViewById(R.id.image_details); | |
mMainImage = (ImageView) findViewById(R.id.main_image); | |
} | |
public void startGalleryChooser() { | |
if (PermissionUtils.requestPermission(this, GALLERY_PERMISSIONS_REQUEST, Manifest.permission.READ_EXTERNAL_STORAGE)) { | |
Intent intent = new Intent(); | |
intent.setType("image/*"); | |
intent.setAction(Intent.ACTION_GET_CONTENT); | |
startActivityForResult(Intent.createChooser(intent, "Select a photo"), | |
GALLERY_IMAGE_REQUEST); | |
} | |
} | |
public void startCamera() { | |
if (PermissionUtils.requestPermission( | |
this, | |
CAMERA_PERMISSIONS_REQUEST, | |
Manifest.permission.READ_EXTERNAL_STORAGE, | |
Manifest.permission.CAMERA)) { | |
Intent intent = new Intent(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); | |
} | |
} | |
public File getCameraFile() { | |
File dir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); | |
return new File(dir, FILE_NAME); | |
} | |
@Override | |
protected void onActivityResult(int requestCode, int resultCode, Intent data) { | |
super.onActivityResult(requestCode, resultCode, data); | |
if (requestCode == GALLERY_IMAGE_REQUEST && resultCode == RESULT_OK && data != null) { | |
uploadImage(data.getData()); | |
} else if (requestCode == CAMERA_IMAGE_REQUEST && resultCode == RESULT_OK) { | |
Uri photoUri = FileProvider.getUriForFile(this, getApplicationContext().getPackageName() + ".provider", getCameraFile()); | |
uploadImage(photoUri); | |
} | |
} | |
@Override | |
public void onRequestPermissionsResult( | |
int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { | |
super.onRequestPermissionsResult(requestCode, permissions, grantResults); | |
switch (requestCode) { | |
case CAMERA_PERMISSIONS_REQUEST: | |
if (PermissionUtils.permissionGranted(requestCode, CAMERA_PERMISSIONS_REQUEST, grantResults)) { | |
startCamera(); | |
} | |
break; | |
case GALLERY_PERMISSIONS_REQUEST: | |
if (PermissionUtils.permissionGranted(requestCode, GALLERY_PERMISSIONS_REQUEST, grantResults)) { | |
startGalleryChooser(); | |
} | |
break; | |
} | |
} | |
public void uploadImage(Uri uri) { | |
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(); | |
} | |
} | |
private void callCloudVision(final Bitmap bitmap) throws IOException { | |
// 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 | |
new AsyncTask<Object, Void, String>() { | |
@Override | |
protected String doInBackground(Object... params) { | |
try { | |
HttpTransport httpTransport = AndroidHttp.newCompatibleTransport(); | |
JsonFactory jsonFactory = GsonFactory.getDefaultInstance(); | |
VisionRequestInitializer requestInitializer = | |
new VisionRequestInitializer(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 | |
protected void initializeVisionRequest(VisionRequest<?> visionRequest) | |
throws IOException { | |
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 = new Vision.Builder(httpTransport, jsonFactory, null); | |
builder.setVisionRequestInitializer(requestInitializer); | |
Vision vision = builder.build(); | |
BatchAnnotateImagesRequest batchAnnotateImagesRequest = | |
new BatchAnnotateImagesRequest(); | |
batchAnnotateImagesRequest.setRequests(new ArrayList<AnnotateImageRequest>() {{ | |
AnnotateImageRequest annotateImageRequest = new AnnotateImageRequest(); | |
// Add the image | |
Image base64EncodedImage = new Image(); | |
// Convert the bitmap to a JPEG | |
// Just in case it's a format that Android understands but Cloud Vision | |
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); | |
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(new ArrayList<Feature>() {{ | |
Feature labelDetection = new Feature(); | |
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."; | |
} | |
protected void onPostExecute(String result) { | |
findViewById(R.id.loadingPanel).setVisibility(View.GONE); | |
mImageDetails.setText(Html.fromHtml(result)); | |
} | |
}.execute(); | |
} | |
public Bitmap scaleBitmapDown(Bitmap bitmap, int maxDimension) { | |
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); | |
} else if (originalWidth > originalHeight) { | |
resizedWidth = maxDimension; | |
resizedHeight = (int) (resizedWidth * (float) originalHeight / (float) originalWidth); | |
} else if (originalHeight == originalWidth) { | |
resizedHeight = maxDimension; | |
resizedWidth = maxDimension; | |
} | |
return Bitmap.createScaledBitmap(bitmap, resizedWidth, resizedHeight, false); | |
} | |
private String convertResponseToString(BatchAnnotateImagesResponse response) { | |
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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.dexin; | |
import android.content.pm.PackageInfo; | |
import android.content.pm.PackageManager; | |
import android.content.pm.Signature; | |
import android.support.annotation.NonNull; | |
import com.google.common.io.BaseEncoding; | |
import java.security.MessageDigest; | |
import java.security.NoSuchAlgorithmException; | |
/** | |
* Provides utility logic for getting the app's SHA1 signature. Used with restricted API keys. | |
* | |
*/ | |
public class PackageManagerUtils { | |
/** | |
* Gets the SHA1 signature, hex encoded for inclusion with Google Cloud Platform API requests | |
* | |
* @param packageName Identifies the APK whose signature should be extracted. | |
* @return a lowercase, hex-encoded | |
*/ | |
public static String getSignature(@NonNull PackageManager pm, @NonNull String packageName) { | |
try { | |
PackageInfo packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES); | |
if (packageInfo == null | |
|| packageInfo.signatures == null | |
|| packageInfo.signatures.length == 0 | |
|| packageInfo.signatures[0] == null) { | |
return null; | |
} | |
return signatureDigest(packageInfo.signatures[0]); | |
} catch (PackageManager.NameNotFoundException e) { | |
return null; | |
} | |
} | |
private static String signatureDigest(Signature sig) { | |
byte[] signature = sig.toByteArray(); | |
try { | |
MessageDigest md = MessageDigest.getInstance("SHA1"); | |
byte[] digest = md.digest(signature); | |
return BaseEncoding.base16().lowerCase().encode(digest); | |
} catch (NoSuchAlgorithmException e) { | |
return null; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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. | |
*/ | |
package com.dexin; | |
import android.app.Activity; | |
import android.content.pm.PackageManager; | |
import android.support.v4.app.ActivityCompat; | |
import android.support.v4.content.ContextCompat; | |
import java.util.ArrayList; | |
public class PermissionUtils { | |
public static boolean requestPermission( | |
Activity activity, int requestCode, String... permissions) { | |
boolean granted = true; | |
ArrayList<String> permissionsNeeded = new ArrayList<>(); | |
for (String s : permissions) { | |
int permissionCheck = ContextCompat.checkSelfPermission(activity, s); | |
boolean hasPermission = (permissionCheck == PackageManager.PERMISSION_GRANTED); | |
granted &= hasPermission; | |
if (!hasPermission) { | |
permissionsNeeded.add(s); | |
} | |
} | |
if (granted) { | |
return true; | |
} else { | |
ActivityCompat.requestPermissions(activity, | |
permissionsNeeded.toArray(new String[permissionsNeeded.size()]), | |
requestCode); | |
return false; | |
} | |
} | |
public static boolean permissionGranted( | |
int requestCode, int permissionCode, int[] grantResults) { | |
if (requestCode == permissionCode) { | |
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { | |
return true; | |
} else { | |
return false; | |
} | |
} | |
return false; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment