У меня небольшой проект. Мне нужно реализовать функцию обнаружения движения в android, чтобы закрыть экран устройства, если прошло более 5 минут, и включить его, если обнаружено движение.
Проблема в том, что предварительный просмотр камеры зависает, когда устройство собирается спит и не отправляет больше предварительных просмотров активности, поэтому приложение застряло с выключенным экраном. Я пробовал с замками, но это не работает. Он по-прежнему делает вызов приложения onPause, onStop.
Мой сервис камер:
import android.annotation.TargetApi;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.camera2.*;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.WindowManager;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
public class CameraHandler extends Service {
private static final String TAG = "CameraHandler";
private static final String START_SERVICE_COMMAND = "startServiceCommands";
private static final int COMMAND_NONE = -1;
private static final int COMMAND_START_RECORDING = 0;
private Context context;
private Camera camera;
private boolean inPreview;
private AtomicReference<byte[]> nextData = new AtomicReference<>();
private AtomicInteger nextWidth = new AtomicInteger();
private AtomicInteger nextHeight = new AtomicInteger();
private IBinder cameraServiceBinder = new CameraServiceBinder();
private Camera.PreviewCallback previewCallback;
//private SurfaceHolder.Callback surfaceCallback;
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public CameraHandler() {
}
public static void starService(Context context){
Intent intent = new Intent(context, CameraHandler.class);
intent.putExtra(START_SERVICE_COMMAND, COMMAND_START_RECORDING);
context.startService(intent);
}
private void setPreviewHolder() {
// previewHolder = this.surfaceView.getHolder();
//previewHolder.addCallback(surfaceCallback);
//previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
// surfaceCallback.surfaceCreated(previewHolder);
//surfaceCallback.surfaceChanged(previewHolder, 0, 0, 0);
Log.i(TAG, "Surface was set");
}
public AtomicReference<byte[]> getNextData() {
return nextData;
}
public AtomicInteger getNextWidth() {
return nextWidth;
}
public AtomicInteger getNextHeight() {
return nextHeight;
}
private boolean checkCameraHardware() {
// if this device has a camera or not
return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA);
}
public void releaseCamera(){
//if (previewHolder != null) {
// previewHolder.removeCallback(surfaceCallback);
// }
if (camera != null){
camera.setPreviewCallback(null);
if (inPreview) camera.stopPreview();
inPreview = false;
camera.release(); // release the camera for other applications
camera = null;
Log.i(TAG, "Released camera");
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent == null) {
throw new IllegalStateException("Must start the service with intent");
}
switch (intent.getIntExtra(START_SERVICE_COMMAND, COMMAND_NONE)) {
case COMMAND_START_RECORDING:
initialize();
break;
default:
throw new UnsupportedOperationException("Cannot start service with illegal commands");
}
return START_NOT_STICKY;
}
private void initialize(){
camera = initializeCameraInstance();
previewCallback = createCameraPreviewCallback();
setPreviewHolder();
if (camera != null) {
SurfaceView sv = new SurfaceView(this);
Log.i(TAG, "aci is still null!");
WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(1, 1,
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSLUCENT);
SurfaceHolder sh = sv.getHolder();
sh.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
sv.setZOrderOnTop(true);
sh.setFormat(PixelFormat.TRANSPARENT);
sh.addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
Camera.Parameters params = camera.getParameters();
camera.setParameters(params);
Camera.Parameters parameters = camera.getParameters();
Camera.Size size = getWorstPreviewSize(parameters);
if (size != null) {
parameters.setPreviewSize(size.width, size.height);
Log.d(TAG, "Using width=" + size.width + " height=" + size.height);
}
camera.setParameters(parameters);
try {
camera.setPreviewDisplay(holder);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
camera.setPreviewCallback(previewCallback);
camera.startPreview();
//mCamera.unlock();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
});
wm.addView(sv, params);
}
}
private Camera initializeCameraInstance() {
/*if (this.camera != null) {
releaseCamera();
}*/
Camera camera = null;
try {
if (Camera.getNumberOfCameras() > 1) {
//if you want to open front facing camera use this line
camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);
} else {
camera = Camera.open();
}
}
catch (Exception e){
// Camera is not available (in use or does not exist)
Log.i(TAG, "Kamera nicht zur Benutzung freigegeben");
}
return camera; // returns null if camera is unavailable
}
private void consumeData(byte[] data, int width, int height) {
nextData.set(data);
nextWidth.set(width);
nextHeight.set(height);
}
private Camera.PreviewCallback createCameraPreviewCallback() {
return new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
Log.i(TAG, "-----Preview frame received-----");
if (data == null) return;
Camera.Size size = camera.getParameters().getPreviewSize();
if (size == null) return;
consumeData(data, size.width, size.height);
}
};
}
private static Camera.Size getWorstPreviewSize(Camera.Parameters parameters) {
Camera.Size result = null;
int width = Integer.MAX_VALUE;
int height = Integer.MAX_VALUE;
for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
if (size.width <= width && size.height <= height) {
if (result == null) {
result = size;
} else {
int resultArea = result.width * result.height;
int newArea = size.width * size.height;
if (newArea < resultArea) result = size;
}
}
}
return result;
}
private static Camera.Size getBestPreviewSize(int width, int height, Camera.Parameters parameters) {
Camera.Size result = null;
for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
if (size.width <= width && size.height <= height) {
if (result == null) {
result = size;
} else {
int resultArea = result.width * result.height;
int newArea = size.width * size.height;
if (newArea > resultArea) result = size;
}
}
}
return result;
}
public class CameraServiceBinder extends Binder {
public CameraHandler getService() {
return CameraHandler.this;
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return cameraServiceBinder;
}
}
Моя активность:
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Handler;
import android.os.IBinder;
import android.os.PowerManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.SurfaceView;
import android.widget.TextView;
import android.util.Log;
public class MotionDetectorActivity extends Activity {
private static final String TAG = "MotionDetectorActivity";
//private SurfaceView surfaceView;
private TextView txtStatus;
private MotionDetectorService motionDetectorService;
private boolean serviceBounded = false;
private ServiceConnection serviceConnection = createServiceConnection();
// private CameraHandler cameraHandler;
private AndroidScreenManager screenManager;
private long lastMotion;
PowerManager.WakeLock partialWakeLock;
private void createWakeLocks() {
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
//fullWakeLock = powerManager.newWakeLock(/*PowerManager.PARTIAL_WAKE_LOCK | */PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.FULL_WAKE_LOCK,
// "MotionDetectorActivity::FullWakelockTag");
partialWakeLock = powerManager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK,
"MotionDetectorActivity::PartialWakelockTag");
}
private ServiceConnection createServiceConnection() {
return new ServiceConnection() {
public void onServiceConnected(ComponentName cName, IBinder serviceBinder) {
Log.i(TAG, "Service is getting connected");
MotionDetectorServiceBinder binder = (MotionDetectorServiceBinder) serviceBinder;
MotionDetectorActivity.this.motionDetectorService = binder.getService();
serviceBounded = true;
//motionDetectorService.setCameraHandler(cameraHandler);
motionDetectorService.setMotionDetectorCallback(new IMotionDetectorCallback() {
@Override
public void onMotionDetected() {
Log.v(TAG, "Motion detected");
txtStatus.setText("Motion detected");
lastMotion = System.currentTimeMillis();
if (!screenManager.isScreenOn()) {
Log.v(TAG, "Screen is turned off so waking it up");
screenManager.turnOn();
if (partialWakeLock.isHeld()) {
partialWakeLock.release();
}
}
/*if (!fullWakeLock.isHeld()) {
fullWakeLock.acquire();
}*/
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
txtStatus.setText("No motion detected");
/*if (fullWakeLock.isHeld()) {
fullWakeLock.release();
}*/
}
}, 750);
}
@Override
public void onNoMotionDetected() {
long now = System.currentTimeMillis();
if (now - lastMotion > 5*1000) {
Log.i(TAG, "No motion for more than 5 seconds, turning screen off");
//screenManager.turnOff();
}
}
@Override
public void onTooDark() {
Log.v(TAG, "Too dark here");
txtStatus.setText("Too dark here");
}
});
// Custom config options
motionDetectorService.setCheckIntervalMs(500);
motionDetectorService.setLeniency(30);
motionDetectorService.setMinLuma(500);
}
public void onServiceDisconnected(ComponentName cName){
serviceBounded = false;
}
};
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
screenManager = new AndroidScreenManager(this);
CameraHandler.starService(this);
createWakeLocks();
txtStatus = (TextView) findViewById(R.id.txtStatus);
lastMotion = System.currentTimeMillis();
}
@Override
protected void onStart() {
super.onStart();
Intent motionDetectorServiceIntent = new Intent(this, MotionDetectorService.class);
bindService(motionDetectorServiceIntent, serviceConnection, BIND_AUTO_CREATE);
startService(motionDetectorServiceIntent);
}
@Override
protected void onResume() {
Log.i(TAG, "-----onResume-----");
super.onResume();
/*if (motionDetectorService != null) {
motionDetectorService.releasePartialWakeLocK();
}
if (partialWakeLock.isHeld()) {
partialWakeLock.release();
Log.v(TAG, "Released partial wake lock in the activity");
}*/
}
private void acquirePartialWakeLock() {
if (!partialWakeLock.isHeld()) {
partialWakeLock.acquire();
Log.v(TAG, "Acquired partial wake lock in the activity");
}
}
@Override
protected void onPause() {
Log.i(TAG, "-----onPause-----");
//CameraHandler cameraHandler = new CameraHandler(this, surfaceView);
/*motionDetectorService.acquirePartialWakeLocK();*/
//acquirePartialWakeLock();
super.onPause();
}
private void unbindServiceIfBounded() {
if (serviceBounded) {
unbindService(serviceConnection);
serviceBounded = false;
Log.i(TAG, "Service is unbounded");
}
}
@Override
protected void onDestroy() {
Log.v(TAG, "Destroying app");
motionDetectorService.onDestroy();
unbindServiceIfBounded();
super.onDestroy();
}
@Override
protected void onStop() {
Log.i(TAG, "-----onStop-----");
//cameraHandler.releaseCamera();
//CameraHandler cameraHandler = new CameraHandler(this, surfaceView);
//acquirePartialWakeLock();
//unbindServiceIfBounded();
super.onStop();
}
}