AI2 Component  (Version nb184)
Camera.java
Go to the documentation of this file.
1 // -*- mode: java; c-basic-offset: 2; -*-
2 // Copyright 2009-2011 Google, All Rights reserved
3 // Copyright 2011-2020 MIT, All rights reserved
4 // Released under the Apache License, Version 2.0
5 // http://www.apache.org/licenses/LICENSE-2.0
6 
7 package com.google.appinventor.components.runtime;
8 
9 import android.Manifest;
10 import android.app.Activity;
11 import android.content.ContentValues;
12 import android.content.Intent;
13 import android.net.Uri;
14 import android.os.Build;
15 import android.os.Environment;
16 import android.provider.MediaStore;
17 import android.util.Log;
31 import java.io.File;
32 import java.util.Date;
33 
45 @DesignerComponent(version = YaVersion.CAMERA_COMPONENT_VERSION,
46  description = "A component to take a picture using the device's camera. " +
47  "After the picture is taken, the name of the file on the phone " +
48  "containing the picture is available as an argument to the " +
49  "AfterPicture event. The file name can be used, for example, to set " +
50  "the Picture property of an Image component.",
51  category = ComponentCategory.MEDIA,
52  nonVisible = true,
53  iconName = "images/camera.png")
54 @SimpleObject
55 @UsesPermissions(permissionNames = "android.permission.WRITE_EXTERNAL_STORAGE, android.permission.READ_EXTERNAL_STORAGE," +
56  "android.permission.CAMERA")
57 public class Camera extends AndroidNonvisibleComponent
58  implements ActivityResultListener, Component {
59 
60  private static final String CAMERA_INTENT = MediaStore.ACTION_IMAGE_CAPTURE;
61  private static final String CAMERA_OUTPUT = MediaStore.EXTRA_OUTPUT;
62  private final ComponentContainer container;
63  private Uri imageFile;
64 
65  /* Used to identify the call to startActivityForResult. Will be passed back
66  into the resultReturned() callback method. */
67  private int requestCode;
68 
69  // whether to open into the front-facing camera
70  private boolean useFront;
71 
72  // wether or not we have permission to use the camera
73 
74  private boolean havePermission = false;
75 
83  public Camera(ComponentContainer container) {
84  super(container.$form());
85  this.container = container;
86 
87  // Default property values
88  UseFront(false);
89  }
90 
96  @Deprecated
98  public boolean UseFront() {
99  return useFront;
100  }
101 
108  @Deprecated
109  // Hide the deprecated property from the Designer
110  // @DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_BOOLEAN, defaultValue = "False")
111  @SimpleProperty(description = "Specifies whether the front-facing camera should be used (when available). "
112  + "If the device does not have a front-facing camera, this option will be ignored "
113  + "and the camera will open normally.")
114  public void UseFront(boolean front) {
115  useFront = front;
116  }
117 
125  public void TakePicture() {
126  if (!havePermission) {
127  final Camera me = this;
128  form.askPermission(new BulkPermissionRequest(this, "TakePicture",
129  Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE) {
130  @Override
131  public void onGranted() {
132  me.havePermission = true;
133  me.TakePicture();
134  }
135  });
136  return;
137  }
138  String state = Environment.getExternalStorageState();
139  if (Environment.MEDIA_MOUNTED.equals(state)) {
140  Log.i("CameraComponent", "External storage is available and writable");
141 
142  File directory = new File(QUtil.getExternalStorageDir(form), "Pictures/");
143  if (!directory.exists()) {
144  directory.mkdir();
145  }
146  File image = new File(QUtil.getExternalStorageDir(form),
147  "Pictures/app_inventor_" + new Date().getTime()
148  + ".jpg");
149  imageFile = Uri.fromFile(image);
150 
151  ContentValues values = new ContentValues();
152  values.put(MediaStore.Images.Media.DATA, imageFile.getPath());
153  values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
154  values.put(MediaStore.Images.Media.TITLE, imageFile.getLastPathSegment());
155 
156  if (requestCode == 0) {
157  requestCode = form.registerForActivityResult(this);
158  }
159 
160  Uri imageUri;
161  if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
162  imageUri = container.$context().getContentResolver().insert(
163  MediaStore.Images.Media.INTERNAL_CONTENT_URI, values);
164  } else {
165  imageUri = NougatUtil.getPackageUri(form, image);
166  }
167  Intent intent = new Intent(CAMERA_INTENT);
168  intent.putExtra(CAMERA_OUTPUT, imageUri);
169 
170  // NOTE: This uses an undocumented, testing feature (CAMERA_FACING).
171  // It may not work in the future.
172  if (useFront) {
173  intent.putExtra("android.intent.extras.CAMERA_FACING", 1);
174  }
175 
176  container.$context().startActivityForResult(intent, requestCode);
177  } else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
178  form.dispatchErrorOccurredEvent(this, "TakePicture",
179  ErrorMessages.ERROR_MEDIA_EXTERNAL_STORAGE_READONLY);
180  } else {
181  form.dispatchErrorOccurredEvent(this, "TakePicture",
182  ErrorMessages.ERROR_MEDIA_EXTERNAL_STORAGE_NOT_AVAILABLE);
183  }
184  }
185 
186  @Override
187  public void resultReturned(int requestCode, int resultCode, Intent data) {
188  Log.i("CameraComponent",
189  "Returning result. Request code = " + requestCode + ", result code = " + resultCode);
190  if (requestCode == this.requestCode && resultCode == Activity.RESULT_OK) {
191  File image = new File(imageFile.getPath());
192  if (image.length() != 0) {
193  scanFileToAdd(image);
194  AfterPicture(imageFile.toString());
195  } else {
196  deleteFile(imageFile); // delete empty file
197  // see if something useful got returned in the data
198  if (data != null && data.getData() != null) {
199  Uri tryImageUri = data.getData();
200  Log.i("CameraComponent", "Calling Camera.AfterPicture with image path "
201  + tryImageUri.toString());
202  AfterPicture(tryImageUri.toString());
203  } else {
204  Log.i("CameraComponent", "Couldn't find an image file from the Camera result");
205  form.dispatchErrorOccurredEvent(this, "TakePicture",
207  }
208  }
209  } else {
210  // delete empty file
211  deleteFile(imageFile);
212  }
213  }
214 
221  private void scanFileToAdd(File image) {
222  Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
223  Uri contentUri = NougatUtil.getPackageUri(form, image);
224  mediaScanIntent.setData(contentUri);
225  container.$context().getApplicationContext().sendBroadcast(mediaScanIntent);
226  }
227 
228  private void deleteFile(Uri fileUri) {
229  File fileToDelete = new File(fileUri.getPath());
230  try {
231  if (fileToDelete.delete()) {
232  Log.i("CameraComponent", "Deleted file " + fileUri.toString());
233  } else {
234  Log.i("CameraComponent", "Could not delete file " + fileUri.toString());
235  }
236  } catch (SecurityException e) {
237  Log.i("CameraComponent", "Got security exception trying to delete file "
238  + fileUri.toString());
239  }
240  }
241 
246  @SimpleEvent
247  public void AfterPicture(String image) {
248  EventDispatcher.dispatchEvent(this, "AfterPicture", image);
249  }
250 }
com.google.appinventor.components.runtime.EventDispatcher
Definition: EventDispatcher.java:22
com.google.appinventor.components.annotations.SimpleFunction
Definition: SimpleFunction.java:23
com.google.appinventor.components.runtime.util.ErrorMessages
Definition: ErrorMessages.java:17
com.google.appinventor.components.runtime.util
-*- mode: java; c-basic-offset: 2; -*-
Definition: AccountChooser.java:7
com.google.appinventor.components.common.YaVersion
Definition: YaVersion.java:14
com.google.appinventor.components
com.google.appinventor.components.annotations.DesignerComponent
Definition: DesignerComponent.java:22
com.google.appinventor.components.runtime.Camera.Camera
Camera(ComponentContainer container)
Definition: Camera.java:83
com.google.appinventor.components.annotations.SimpleEvent
Definition: SimpleEvent.java:20
com.google.appinventor.components.runtime.util.ErrorMessages.ERROR_CAMERA_NO_IMAGE_RETURNED
static final int ERROR_CAMERA_NO_IMAGE_RETURNED
Definition: ErrorMessages.java:30
com.google.appinventor.components.annotations.PropertyCategory.BEHAVIOR
BEHAVIOR
Definition: PropertyCategory.java:15
com.google.appinventor.components.runtime.util.NougatUtil.getPackageUri
static Uri getPackageUri(Form form, File apk)
Definition: NougatUtil.java:23
com.google.appinventor.components.runtime.File
Definition: File.java:53
com.google.appinventor.components.runtime.util.QUtil
Definition: QUtil.java:18
com.google.appinventor.components.annotations.UsesPermissions
Definition: UsesPermissions.java:21
com.google.appinventor.components.runtime.MediaStore
Definition: MediaStore.java:72
com.google.appinventor.components.runtime.EventDispatcher.dispatchEvent
static boolean dispatchEvent(Component component, String eventName, Object...args)
Definition: EventDispatcher.java:188
com.google.appinventor.components.runtime.AndroidNonvisibleComponent
Definition: AndroidNonvisibleComponent.java:17
com.google.appinventor.components.runtime.Camera.AfterPicture
void AfterPicture(String image)
Definition: Camera.java:247
com.google.appinventor.components.annotations.SimpleProperty
Definition: SimpleProperty.java:23
com.google.appinventor.components.runtime.Camera.TakePicture
void TakePicture()
Definition: Camera.java:125
com.google.appinventor.components.runtime.util.BulkPermissionRequest
Definition: BulkPermissionRequest.java:22
com.google.appinventor.components.annotations.PropertyCategory
Definition: PropertyCategory.java:13
com.google.appinventor.components.runtime.Camera
Definition: Camera.java:57
com.google.appinventor.components.runtime.ComponentContainer
Definition: ComponentContainer.java:16
com.google.appinventor.components.runtime
Copyright 2009-2011 Google, All Rights reserved.
Definition: AccelerometerSensor.java:8
com.google.appinventor.components.runtime.Component
Definition: Component.java:17
com.google.appinventor.components.common
Definition: ComponentCategory.java:7
com.google.appinventor.components.common.ComponentCategory
Definition: ComponentCategory.java:48
com.google.appinventor.components.runtime.util.NougatUtil
Definition: NougatUtil.java:16
com.google.appinventor.components.runtime.ActivityResultListener
Definition: ActivityResultListener.java:16
com.google.appinventor.components.runtime.Camera.resultReturned
void resultReturned(int requestCode, int resultCode, Intent data)
Definition: Camera.java:187
com.google.appinventor.components.annotations.SimpleObject
Definition: SimpleObject.java:23
com.google
com
com.google.appinventor.components.runtime.util.QUtil.getExternalStorageDir
static File getExternalStorageDir(Context context)
Definition: QUtil.java:72
com.google.appinventor.components.runtime.ComponentContainer.$form
Form $form()
com.google.appinventor.components.runtime.ComponentContainer.$context
Activity $context()
com.google.appinventor.components.annotations
com.google.appinventor