我想实现以下目标: 我有一个旧手机(android os)我不再使用了,喜欢把我的窗户放在我们周末的房子里。我用firebase控制它。当我将孩子添加到某个键时,服务应该触发手机的相机并拍照。 现在我有两件事:
我的问题是我无法将这两件事结合起来,因为我可以从活动中启动APictureCapturingService中的startCapturing()方法,但不能从服务中启动。我该怎么解决这个问题?谢谢
public class FiBaService extends Service {
public static final int MY_PERMISSIONS_REQUEST_ACCESS_CODE = 1;
//public APictureCapturingService pictureService;
DatabaseReference mdb;
String user, post;
@Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
handleFIBA();
return START_STICKY;
}
@Override
public void onCreate() {
mdb = FirebaseDatabase.getInstance().getReference();
}
@Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(this, "Service is Destroyed", Toast.LENGTH_SHORT).show();
}
public void handleFIBA() {
//Toast.makeText(this, "dosomethingban!", Toast.LENGTH_SHORT).show();
FirebaseDatabase.getInstance().getReference().child
("phones4streams").addChildEventListener(new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
/*
String userName = (dataSnapshot.getValue(String.class)).toString();
Map<String, Object> map = (Map<String, Object>) dataSnapshot.getValue();
for (DataSnapshot dsp : dataSnapshot.getChildren()) {
//Userlist.add(String.valueOf(dsp.geValue())); //add result into array list
Toast.makeText(CameraActivity.this, dsp.toString(), Toast.LENGTH_SHORT).show();
}
Toast.makeText(FiBa.this, userName, Toast.LENGTH_SHORT).show();
*/
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
//String userName = (dataSnapshot.getValue(String.class).toString());
//Toast.makeText(SettingsActivity.this, "Történt változás", Toast.LENGTH_SHORT)
// .show();
Toast.makeText(FiBaService.this, "Starting capture!", Toast.LENGTH_SHORT)
.show();
//pictureService.startCapturing(FiBaService.this);
FirebaseDatabase.getInstance().getReference().child
("phones4streams").child("alamade").setValue("csalamade");
takePic();
}
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
APictureCapturingService - 处理拍照:
public abstract class APictureCapturingService {
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
static {
ORIENTATIONS.append(Surface.ROTATION_0, 90);
ORIENTATIONS.append(Surface.ROTATION_90, 0);
ORIENTATIONS.append(Surface.ROTATION_180, 270);
ORIENTATIONS.append(Surface.ROTATION_270, 180);
}
private final Activity activity;
final Context context;
final CameraManager manager;
/***
* constructor.
*
* @param activity the activity used to get display manager and the application context
*/
APictureCapturingService(final Activity activity) {
this.activity = activity;
this.context = activity.getApplicationContext();
this.manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
}
/***
* @return orientation
*/
int getOrientation() {
final int rotation = this.activity.getWindowManager().getDefaultDisplay().getRotation();
return ORIENTATIONS.get(rotation);
}
/**
* starts pictures capturing process.
*
* @param listener picture capturing listener
*/
public abstract void startCapturing(final PictureCapturingListener listener);
在其他活动中,我将此类实例化为:
public APictureCapturingService pictureService;
pictureService = PictureCapturingServiceImpl.getInstance(this);
pictureService.startCapturing(SettingsActivity.this);
PictureCapturingServiceImpl:
/**
* The aim of this service is to secretly take pictures (without preview or opening device's
* camera app)
* from all available cameras using Android Camera 2 API
*
* @author hzitoun (zitoun.hamed@gmail.com)
*/
@TargetApi(Build.VERSION_CODES.LOLLIPOP) //NOTE: camera 2 api was added in API level 21
public class PictureCapturingServiceImpl extends APictureCapturingService {
private static final String TAG = PictureCapturingServiceImpl.class.getSimpleName();
private CameraDevice cameraDevice;
private ImageReader imageReader;
/***
* camera ids queue.
*/
private Queue<String> cameraIds;
private String currentCameraId;
private boolean cameraClosed;
/**
* stores a sorted map of (pictureUrlOnDisk, PictureData).
*/
private TreeMap<String, byte[]> picturesTaken;
private PictureCapturingListener capturingListener;
/***
* private constructor, meant to force the use of {@link #getInstance} method
*/
private PictureCapturingServiceImpl(final Activity activity) {
super(activity);
}
/**
* @param activity the activity used to get the app's context and the display manager
* @return a new instance
*/
public static APictureCapturingService getInstance(final Activity activity) {
return new PictureCapturingServiceImpl(activity);
}
/**
* Starts pictures capturing treatment.
*
* @param listener picture capturing listener
*/
@Override
public void startCapturing(final PictureCapturingListener listener) {
this.picturesTaken = new TreeMap<>();
this.capturingListener = listener;
this.cameraIds = new LinkedList<>();
try {
final String[] cameraIds = manager.getCameraIdList();
System.out.println("cameraIds length: " + cameraIds.length);
System.out.println("cameraId[0]: " + cameraIds[0]);
System.out.println("cameraId[1]: " + cameraIds[1]);
if (cameraIds.length > 0) {
this.cameraIds.addAll(Arrays.asList(cameraIds));
// a currentCameraId lesz a cameraIds első eleme, de a caneraIds-ból remove-olva
// lesz
// ez az első elem
this.currentCameraId = this.cameraIds.poll();
openCamera();
} else {
//No camera detected!
capturingListener.onDoneCapturingAllPhotos(picturesTaken);
}
} catch (final CameraAccessException e) {
Log.e(TAG, "Exception occurred while accessing the list of cameras", e);
}
}
private void openCamera() {
Log.d(TAG, "opening camera " + currentCameraId);
try {
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.CAMERA)
== PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(context,
Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED) {
manager.openCamera(currentCameraId, stateCallback, null);
}
} catch (final CameraAccessException e) {
Log.e(TAG, " exception occurred while opening camera " + currentCameraId, e);
}
}
private final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession
.CaptureCallback() {
@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull
CaptureRequest request,
@NonNull TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
if (picturesTaken.lastEntry() != null) {
capturingListener.onCaptureDone(picturesTaken.lastEntry().getKey(), picturesTaken
.lastEntry().getValue());
Log.i(TAG, "done taking picture from camera " + cameraDevice.getId());
}
closeCamera();
}
};
private final ImageReader.OnImageAvailableListener onImageAvailableListener = (ImageReader
imReader) -> {
final Image image = imReader.acquireLatestImage();
final ByteBuffer buffer = image.getPlanes()[0].getBuffer();
final byte[] bytes = new byte[buffer.capacity()];
buffer.get(bytes);
saveImageToDisk(bytes, timeStamp);
image.close();
};
private final CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(@NonNull CameraDevice camera) {
cameraClosed = false;
Log.d(TAG, "camera " + camera.getId() + " opened");
cameraDevice = camera;
Log.i(TAG, "Taking picture from camera " + camera.getId());
//Take the picture after some delay. It may resolve getting a black dark photos.
new Handler().postDelayed(() -> {
try {
takePicture();
} catch (final CameraAccessException e) {
Log.e(TAG, " exception occurred while taking picture from " +
currentCameraId, e);
}
}, 500);
}
@Override
public void onDisconnected(@NonNull CameraDevice camera) {
Log.d(TAG, " camera " + camera.getId() + " disconnected");
if (cameraDevice != null && !cameraClosed) {
cameraClosed = true;
cameraDevice.close();
}
}
@Override
public void onClosed(@NonNull CameraDevice camera) {
cameraClosed = true;
Log.d(TAG, "camera " + camera.getId() + " closed");
//once the current camera has been closed, start taking another picture
//if (!cameraIds.isEmpty()) {
if (cameraIds.size() != 1 && !cameraIds.isEmpty()) {
takeAnotherPicture();
} else {
capturingListener.onDoneCapturingAllPhotos(picturesTaken);
}
}
@Override
public void onError(@NonNull CameraDevice camera, int error) {
Log.e(TAG, "camera in error, int code " + error);
if (cameraDevice != null && !cameraClosed) {
cameraDevice.close();
}
}
};
private void takePicture() throws CameraAccessException {
if (null == cameraDevice) {
Log.e(TAG, "cameraDevice is null");
return;
}
final CameraCharacteristics characteristics = manager.getCameraCharacteristics
(cameraDevice.getId());
Size[] jpegSizes = null;
StreamConfigurationMap streamConfigurationMap = characteristics.get(CameraCharacteristics
.SCALER_STREAM_CONFIGURATION_MAP);
if (streamConfigurationMap != null) {
jpegSizes = streamConfigurationMap.getOutputSizes(ImageFormat.JPEG);
}
final boolean jpegSizesNotEmpty = jpegSizes != null && 0 < jpegSizes.length;
int width = jpegSizesNotEmpty ? jpegSizes[0].getWidth() : 640;
int height = jpegSizesNotEmpty ? jpegSizes[0].getHeight() : 480;
final ImageReader reader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 1);
final List<Surface> outputSurfaces = new ArrayList<>();
outputSurfaces.add(reader.getSurface());
final CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest
(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(reader.getSurface());
captureBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation());
reader.setOnImageAvailableListener(onImageAvailableListener, null);
cameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(@NonNull CameraCaptureSession session) {
try {
session.capture(captureBuilder.build(), captureListener, null);
} catch (final CameraAccessException e) {
Log.e(TAG, " exception occurred while accessing " + currentCameraId, e);
}
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession session) {
}
}
, null);
}
//cYou - átírva a képek mentési helye a cyou mappába 240. sor
private void saveImageToDisk(final byte[] bytes, String timeStamp) {
final String cameraId = this.cameraDevice == null ? UUID.randomUUID().toString() : this
.cameraDevice.getId();
final File file = new File(Environment.getExternalStorageDirectory() + "/mup/" +
Sta.getCurrentTimeStamp() + "_pic.jpg");
try (final OutputStream output = new FileOutputStream(file)) {
output.write(bytes);
this.picturesTaken.put(file.getPath(), bytes);
} catch (final IOException e) {
Log.e(TAG, "Exception occurred while saving picture to external storage ", e);
}
}
private void takeAnotherPicture() {
this.currentCameraId = this.cameraIds.poll();
openCamera();
}
private void closeCamera() {
Log.d(TAG, "closing camera " + cameraDevice.getId());
if (null != cameraDevice && !cameraClosed) {
cameraDevice.close();
cameraDevice = null;
}
if (null != imageReader) {
imageReader.close();
imageReader = null;
}
}
答案 0 :(得分:1)
Firebase服务的一个解决方案是广播消息。然后实现BroadcastReceiver来收听消息并在收到消息时启动你的图片服务。
我认为你的代码中没有任何理由需要Activity
。您似乎试图从Context
获得Activity
。但是Service
已经充当Context
,因此您可以直接使用它并简化构造函数:
APictureCapturingService() {
this.manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
}
现在我假设你也可以摆脱Activity
的{{1}}参数。