无法从服务开始服务

时间:2018-05-29 14:21:36

标签: java android

我想实现以下目标: 我有一个旧手机(android os)我不再使用了,喜欢把我的窗户放在我们周末的房子里。我用firebase控制它。当我将孩子添加到某个键时,服务应该触发手机的相机并拍照。 现在我有两件事:

  1. 一个简单的服务,如果发生任何变化,就会监听firebase
  2. 在没有任何用户互动的情况下拍摄照片的相机服务
  3. 我的问题是我无法将这两件事结合起来,因为我可以从活动中启动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);
    

    EDITED 尝试使用广播接收器我得到相同的结果:需要活动 enter image description here

    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;
            }
        }
    

1 个答案:

答案 0 :(得分:1)

Firebase服务的一个解决方案是广播消息。然后实现BroadcastReceiver来收听消息并在收到消息时启动你的图片服务。

我认为你的代码中没有任何理由需要Activity。您似乎试图从Context获得Activity。但是Service已经充当Context,因此您可以直接使用它并简化构造函数:

APictureCapturingService() {
    this.manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
}

现在我假设你也可以摆脱Activity的{​​{1}}参数。