Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.2'
classpath 'com.android.tools.build:gradle:3.1.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version"
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.4'
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions things/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ object ChannelsRegistry {
Uri.parse("android.resource://com.example.androidthings.lantern/drawable/banner_clock"),
customizable = true
)),
Pair(::ScreenShot, ChannelInfo(
"ScreenShot",
"Take a picture",
"Take a picture of something that is under lantern and project it to any surface.",
Uri.parse("android.resource://com.example.androidthings.lantern/drawable/banner_screenshot")
)),
Pair(::NowPlayingChannel, ChannelInfo(
"now-playing",
"Now playing",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.example.androidthings.lantern.channels

import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Matrix
import android.media.ImageReader
import android.os.Bundle
import android.os.Handler
import android.os.HandlerThread
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import com.example.androidthings.lantern.Channel
import com.example.androidthings.lantern.hardware.Camera


/**
* Makes a picture with the camera and projects it afterwards
*/
class ScreenShot : Channel() {

val TAG = this::class.java.simpleName

private lateinit var view: ImageView

private val handler: Handler = Handler()

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
this.view = ImageView(context)
this.view.scaleType = ImageView.ScaleType.CENTER_INSIDE

val mCameraThread = HandlerThread("CameraBackground")
mCameraThread.start()
val mCameraHandler = Handler(mCameraThread.looper)

val mCamera = Camera.getInstance()
mCamera.initializeCamera(this.activity, mCameraHandler, imageAvailableListener)

handler.postDelayed({ mCamera.takePicture() }, 3000)
return view
}

private val imageAvailableListener = ImageReader.OnImageAvailableListener { reader ->
Log.d(TAG, "ImageAvailable!")
val image = reader.acquireLatestImage()
val imageBuffer = image.planes[0].buffer
val imageBytes = ByteArray(imageBuffer.remaining())
imageBuffer.get(imageBytes)
image.close()
val bitmap = getBitmapFromByteArray(imageBytes)
handler.post({ this.view.setImageBitmap(bitmap) })
}

private fun getBitmapFromByteArray(imageBytes: ByteArray): Bitmap {
val bitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size)
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, Matrix(), true)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
/*
* Copyright 2016, 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.example.androidthings.lantern.hardware;

import android.content.Context;
import android.graphics.ImageFormat;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.ImageReader;
import android.os.Handler;
import android.util.Log;
import android.util.Size;

import java.util.Collections;

import static android.content.Context.CAMERA_SERVICE;

/**
* Helper class to deal with methods to deal with images from the camera.
*/
public class Camera {
private static final String TAG = Camera.class.getSimpleName();

private static final int IMAGE_WIDTH = 1280;
private static final int IMAGE_HEIGHT = 720;
private static final int MAX_IMAGES = 1;

private CameraDevice mCameraDevice;

private CameraCaptureSession mCaptureSession;

/**
* An {@link ImageReader} that handles still image capture.
*/
private ImageReader mImageReader;

// Lazy-loaded singleton, so only one instance of the camera is created.
private Camera() {
}

private static class InstanceHolder {
private static Camera mCamera = new Camera();
}

public static Camera getInstance() {
return InstanceHolder.mCamera;
}

/**
* Initialize the camera device
*/
public void initializeCamera(Context context,
Handler backgroundHandler,
ImageReader.OnImageAvailableListener imageAvailableListener) {
// Discover the camera instance
CameraManager manager = (CameraManager) context.getSystemService(CAMERA_SERVICE);
String[] camIds = {};
try {
camIds = manager.getCameraIdList();
} catch (CameraAccessException e) {
Log.e(TAG, "Cam access exception getting IDs", e);
}
if (camIds.length < 1) {
Log.e(TAG, "No cameras found");
return;
}
String id = camIds[0];
Log.d(TAG, "Using camera id " + id);

// Initialize the image processor
mImageReader = ImageReader.newInstance(IMAGE_WIDTH, IMAGE_HEIGHT,
ImageFormat.JPEG, MAX_IMAGES);
mImageReader.setOnImageAvailableListener(
imageAvailableListener, backgroundHandler);

// Open the camera resource
try {
manager.openCamera(id, mStateCallback, backgroundHandler);
} catch (CameraAccessException cae) {
Log.d(TAG, "Camera access exception", cae);
}
}

/**
* Callback handling device state changes
*/
private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(CameraDevice cameraDevice) {
Log.d(TAG, "Opened camera.");
mCameraDevice = cameraDevice;
}

@Override
public void onDisconnected(CameraDevice cameraDevice) {
Log.d(TAG, "Camera disconnected, closing.");
cameraDevice.close();
}

@Override
public void onError(CameraDevice cameraDevice, int i) {
Log.d(TAG, "Camera device error, closing.");
cameraDevice.close();
}

@Override
public void onClosed(CameraDevice cameraDevice) {
Log.d(TAG, "Closed camera, releasing");
mCameraDevice = null;
}
};

/**
* Begin a still image capture
*/
public void takePicture() {
if (mCameraDevice == null) {
Log.e(TAG, "Cannot capture image. Camera not initialized.");
return;
}

// Here, we create a CameraCaptureSession for capturing still images.
try {
mCameraDevice.createCaptureSession(
Collections.singletonList(mImageReader.getSurface()),
mSessionCallback,
null);
} catch (CameraAccessException cae) {
Log.e(TAG, "access exception while preparing pic", cae);
}
}

/**
* Callback handling session state changes
*/
private CameraCaptureSession.StateCallback mSessionCallback =
new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession cameraCaptureSession) {
// The camera is already closed
if (mCameraDevice == null) {
return;
}

// When the session is ready, we start capture.
mCaptureSession = cameraCaptureSession;
triggerImageCapture();
}

@Override
public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
Log.e(TAG, "Failed to configure camera");
}
};

/**
* Execute a new capture request within the active session
*/
private void triggerImageCapture() {
try {
final CaptureRequest.Builder captureBuilder =
mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(mImageReader.getSurface());
captureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
Log.d(TAG, "Session initialized.");
mCaptureSession.capture(captureBuilder.build(), mCaptureCallback, null);
} catch (CameraAccessException cae) {
Log.e(TAG, "camera capture exception", cae);
}
}

/**
* Callback handling capture session events
*/
private final CameraCaptureSession.CaptureCallback mCaptureCallback =
new CameraCaptureSession.CaptureCallback() {

@Override
public void onCaptureProgressed(CameraCaptureSession session,
CaptureRequest request,
CaptureResult partialResult) {
Log.d(TAG, "Partial result");
}

@Override
public void onCaptureCompleted(CameraCaptureSession session,
CaptureRequest request,
TotalCaptureResult result) {
if (session != null) {
session.close();
mCaptureSession = null;
Log.d(TAG, "CaptureSession closed");
}
}
};


/**
* Close the camera resources
*/
public void shutDown() {
if (mCameraDevice != null) {
mCameraDevice.close();
}
}

/**
* Helpful debugging method: Dump all supported camera formats to log. You don't need to run
* this for normal operation, but it's very helpful when porting this code to different
* hardware.
*/
public static void dumpFormatInfo(Context context) {
CameraManager manager = (CameraManager) context.getSystemService(CAMERA_SERVICE);
String[] camIds = {};
try {
camIds = manager.getCameraIdList();
} catch (CameraAccessException e) {
Log.d(TAG, "Cam access exception getting IDs");
}
if (camIds.length < 1) {
Log.d(TAG, "No cameras found");
}
String id = camIds[0];
Log.d(TAG, "Using camera id " + id);
try {
CameraCharacteristics characteristics = manager.getCameraCharacteristics(id);
StreamConfigurationMap configs = characteristics.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
for (int format : configs.getOutputFormats()) {
Log.d(TAG, "Getting sizes for format: " + format);
for (Size s : configs.getOutputSizes(format)) {
Log.d(TAG, "\t" + s.toString());
}
}
int[] effects = characteristics.get(CameraCharacteristics.CONTROL_AVAILABLE_EFFECTS);
for (int effect : effects) {
Log.d(TAG, "Effect available: " + effect);
}
} catch (CameraAccessException e) {
Log.d(TAG, "Cam access exception getting characteristics.");
}
}
}