Search code examples
javaandroidandroid-camera2

Button will redirect to a Custom Camera


EDIT: Added Adapter code EDIT: I updated the codes of my main project alongside with its logcat

I have this app that is a shop-like and displays clothes to select. Every clothes has a button and I want that button to redirect to a custom camera but everytime I open my app, it just opens the launcher activity and crash afterwards and never reaches the main activity.

  1. Is it possible to use intent just like what I did? If yes, where did I go wrong?
  2. If not, what should I do?

These are my codes for the button as the main activity.

CLARTIPS_Home.java

   public class CLARTIPS_Home extends AppCompatActivity {

    private ListView lvProduct;
    private ListProductAdapter adapter;
    private List<Product> mProductList;
    private DatabaseHelper mDBHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_clartips__home);

        lvProduct = (ListView) findViewById(R.id.listview_product);
        mDBHelper = new DatabaseHelper(this);

        Button tryMe = (Button) findViewById(R.id.tryMe);

        tryMe.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                openCam();
            }
        });

        //Check exists database
        File database = getApplicationContext().getDatabasePath(DatabaseHelper.DBNAME);
        if(false==database.exists()) {
            mDBHelper.getReadableDatabase();
            //Copy db
            if (copyDatabase(this)) {
                Toast.makeText(this, "Success Copying Database", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(this, "Error Copying Database", Toast.LENGTH_SHORT).show();
                return;
            }
        }
        //Get product list in db when db exists
        mProductList = mDBHelper.getListProduct();
        //Init adapter
        adapter = new ListProductAdapter(this,mProductList);
        //Set adapter for listview
        lvProduct.setAdapter(adapter);
    }

    private void openCam() {
        Intent cameraIntent = new Intent(CLARTIPS_Home.this, Camera.class);
        startActivity(cameraIntent);
    }

    private boolean copyDatabase(Context context) {
        try {
            InputStream inputStream = context.getAssets().open(DatabaseHelper.DBNAME);
            String outFileName = DatabaseHelper.DBLOCATION + DatabaseHelper.DBNAME;
            OutputStream outputStream = new FileOutputStream(outFileName);
            byte[]buff = new byte[1024];
            int length = 0;
            while ((length = inputStream.read(buff)) > 0) {
                outputStream.write(buff, 0, length);
            }
            outputStream.flush();
            outputStream.close();
            Log.w("MainActivity","DB copied");
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu, menu);
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected (MenuItem item){
        switch (item.getItemId()) {
            case R.id.about:
                Intent aboutIntent = new Intent(CLARTIPS_Home.this, About.class);
                startActivity(aboutIntent);
        }
        return super.onOptionsItemSelected(item);
    }
}

These are my codes for the Camera. I used Camera2 by the way.

Camera.java

public class Camera extends AppCompatActivity {

    private Button btnCapture;
    private TextureView textureView;

    //Check state orientation of output image
    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 String cameraId;
    private CameraDevice cameraDevice;
    private CameraCaptureSession cameraCaptureSessions;
    private CaptureRequest.Builder captureRequestBuilder;
    private android.util.Size imageDimension;
    private ImageReader imageReader;

    //Save to FILE

    private File file;
    private static final int REQUEST_CAMERA_PERMISSION = 200;
    private boolean mFlashSupported;
    private Handler mBackgroundHandler;
    private HandlerThread mBackgroundThread;

    CameraDevice.StateCallback stateCallBack = new CameraDevice.StateCallback(){

        @Override
        public void onOpened(@NonNull CameraDevice camera) {
            cameraDevice = camera;
            createCameraPreview();
        }

        @Override
        public void onDisconnected(@NonNull CameraDevice cameraDevice) {
            cameraDevice.close();
        }

        @Override
        public void onError(@NonNull CameraDevice cameraDevice, int i) {
            cameraDevice.close();
            cameraDevice=null;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.show_camera);

        textureView = (TextureView)findViewById(R.id.textureView);
        //to check if expression is true or false
        assert  textureView != null;
        textureView.setSurfaceTextureListener(textureListener);

        btnCapture = (Button)findViewById(R.id.btnCapture);
        btnCapture.setOnClickListener(new View.OnClickListener(){

            @Override
            public void onClick(View view) {
                takePicture();
            }
        });
    }

    private void takePicture() {
        if(cameraDevice == null)
            return;
        CameraManager manager = (CameraManager)getSystemService(Context.CAMERA_SERVICE);
        try{
            CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraDevice.getId());
            android.util.Size[] jpegSizes = null;
            if(characteristics != null)
                jpegSizes = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputSizes(ImageFormat.JPEG);

            //Capture image with custom size
            int width = 640;
            int height = 480;
            if(jpegSizes != null && jpegSizes.length > 0){
                width = jpegSizes[0].getWidth();
                height = jpegSizes[0].getHeight();
            }

            final ImageReader reader = ImageReader.newInstance(width,height,ImageFormat.JPEG,1);
            List<Surface> outputSurface = new ArrayList<>(2);
            outputSurface.add(reader.getSurface());
            outputSurface.add(new Surface(textureView.getSurfaceTexture()));

            final CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
            captureBuilder.addTarget(reader.getSurface());
            captureBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);

            //Check orientation base on device
            int rotation = getWindowManager().getDefaultDisplay().getRotation();
            captureBuilder.set(CaptureRequest.JPEG_ORIENTATION,ORIENTATIONS.get(rotation));

            file = new File(Environment.getExternalStorageDirectory()+"/"+UUID.randomUUID().toString()+".jpg");
            ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener(){

                @Override
                public void onImageAvailable(ImageReader imageReader) {
                    Image image = null;
                    try{
                        image = reader.acquireLatestImage();
                        ByteBuffer buffer = image.getPlanes()[0].getBuffer();
                        byte[] bytes = new byte[buffer.capacity()];
                        buffer.get(bytes);
                        save(bytes);
                    }
                    catch (FileNotFoundException e){
                        e.printStackTrace();
                    }
                    catch (IOException e){
                        e.printStackTrace();
                    }
                    finally {
                        {
                            if (image != null)
                                image.close();
                        }
                    }

                }
                private void save(byte[] bytes) throws IOException {
                    OutputStream outputSteam = null;
                    try{
                        outputSteam = new FileOutputStream(file);
                        outputSteam.write(bytes);
                    }finally {
                        if(outputSteam != null)
                            outputSteam.close();
                    }
                }
            };

            reader.setOnImageAvailableListener(readerListener,mBackgroundHandler);
            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);
                    Toast.makeText(Camera.this, "Saved "+file, Toast.LENGTH_SHORT).show();
                    createCameraPreview();
                }
            };

            cameraDevice.createCaptureSession(outputSurface, new CameraCaptureSession.StateCallback(){

                @Override
                public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
                    try{
                        cameraCaptureSession.capture(captureBuilder.build(),captureListener,mBackgroundHandler);
                    } catch (CameraAccessException e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {

                }
            },mBackgroundHandler);

        } catch (CameraAccessException e) {
            e.printStackTrace();
        }

    }

    private void createCameraPreview() {
        try{
            SurfaceTexture texture = textureView.getSurfaceTexture();
            assert texture != null;
            texture.setDefaultBufferSize(imageDimension.getWidth(),imageDimension.getHeight());
            Surface surface = new Surface(texture);
            captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            captureRequestBuilder.addTarget(surface);
            cameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback() {

                @Override
                public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
                    if(cameraDevice == null)
                        return;
                    cameraCaptureSessions = cameraCaptureSession;
                    updatePreview();
                }

                @Override
                public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
                    Toast.makeText(Camera.this, "Changed", Toast.LENGTH_SHORT).show();
                }
            }, null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }


    }

    private void updatePreview() {
        if(cameraDevice == null)
            Toast.makeText(this, "Error", Toast.LENGTH_SHORT).show();
        captureRequestBuilder.set(CaptureRequest.CONTROL_MODE,CaptureRequest.CONTROL_MODE_AUTO);
        try{
            cameraCaptureSessions.setRepeatingRequest(captureRequestBuilder.build(), null,mBackgroundHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    private void openCamera() {
        CameraManager manager = (CameraManager)getSystemService(Context.CAMERA_SERVICE);
        try{
            cameraId = manager.getCameraIdList()[0];
            CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
            StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
            assert map != null;
            imageDimension = map.getOutputSizes(SurfaceTexture.class)[0];
            //Check realtime permission if run higher API 23
            if(ActivityCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED){
                ActivityCompat.requestPermissions(this,new String[]{
                    android.Manifest.permission.CAMERA,
                    android.Manifest.permission.WRITE_EXTERNAL_STORAGE
                },REQUEST_CAMERA_PERMISSION);
                return;
            }
            manager.openCamera(cameraId,stateCallBack,null);

        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener(){

        @Override
        public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i1) {
            openCamera();
        }

        @Override
        public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i1) {

        }

        @Override
        public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
            return false;
        }

        @Override
        public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {

        }
    };

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if(requestCode == REQUEST_CAMERA_PERMISSION){
            if(grantResults[0] != PackageManager.PERMISSION_GRANTED){
                Toast.makeText(this, "You can't use camera without permission", Toast.LENGTH_SHORT).show();
                finish();
            }
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        startBackgroundThread();
        if(textureView.isAvailable())
            openCamera();
        else
            textureView.setSurfaceTextureListener(textureListener);
    }

    @Override
    protected void onPause() {
        stopBackgroundThread();
        super.onPause();
    }

    private void stopBackgroundThread() {
        mBackgroundThread.quitSafely();
        try{
            mBackgroundThread.join();
            mBackgroundThread = null;
            mBackgroundHandler = null;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void startBackgroundThread() {
        mBackgroundThread = new HandlerThread("Camera Background");
        mBackgroundThread.start();
        mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
    }
}

My final year in college is on the line here. All your kind answers will be so much appreciated. Thank you so much.

Logcat

02-13 08:11:13.608 20959-20959/? I/art: Late-enabling -Xcheck:jni
02-13 08:11:13.804 20959-20959/? W/art: Before Android 4.1, method android.graphics.PorterDuffColorFilter android.support.graphics.drawable.VectorDrawableCompat.updateTintFilter(android.graphics.PorterDuffColorFilter, android.content.res.ColorStateList, android.graphics.PorterDuff$Mode) would have incorrectly overridden the package-private method in android.graphics.drawable.Drawable
02-13 08:11:13.953 20959-20959/? I/ViewRootImpl: CPU Rendering VSync enable = true
02-13 08:11:13.962 20959-21000/? D/OpenGLRenderer: Use EGL_SWAP_BEHAVIOR_PRESERVED: true
02-13 08:11:14.032 20959-20959/? D/Atlas: Validating map...
02-13 08:11:14.055 20959-20959/? V/PhoneWindow: updateColorViewInt()if drawable=null color=ff000000
02-13 08:11:14.096 20959-21000/? I/Adreno-EGL: <qeglDrvAPI_eglInitialize:379>: EGL 1.4 QUALCOMM build: Nondeterministic_AU_msm8916_32_LA.BR.1.2.4_RB1__release_AU (Ic8ede1fb34)
                                               OpenGL ES Shader Compiler Version: E031.25.03.04
                                               Build Date: 12/10/15 Thu
                                               Local Branch: mybranch17178083
                                               Remote Branch: quic/LA.BR.1.2.4_rb1.30
                                               Local Patches: NONE
                                               Reconstruct Branch: NOTHING
02-13 08:11:14.157 20959-21000/nerds.thesis.clartips I/OpenGLRenderer: Initialized EGL, version 1.4
02-13 08:11:14.478 20959-21000/nerds.thesis.clartips D/OpenGLRenderer: Enabling debug mode 0
02-13 08:11:14.627 20959-20959/nerds.thesis.clartips I/Timeline: Timeline: Activity_idle id: android.os.BinderProxy@2d38ca61 time:44076123
02-13 08:11:17.990 20959-20959/nerds.thesis.clartips I/Timeline: Timeline: Activity_launch_request id:nerds.thesis.clartips time:44079486
02-13 08:11:18.221 20959-20969/nerds.thesis.clartips W/art: Suspending all threads took: 10.057ms
02-13 08:11:18.230 20959-20959/nerds.thesis.clartips D/AndroidRuntime: Shutting down VM
02-13 08:11:18.232 20959-20959/nerds.thesis.clartips E/AndroidRuntime: FATAL EXCEPTION: main
                                                                       Process: nerds.thesis.clartips, PID: 20959
                                                                       java.lang.RuntimeException: Unable to start activity ComponentInfo{nerds.thesis.clartips/nerds.thesis.clartips.CLARTIPS_Home}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.Button.setOnClickListener(android.view.View$OnClickListener)' on a null object reference
                                                                           at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2335)
                                                                           at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2397)
                                                                           at android.app.ActivityThread.access$800(ActivityThread.java:151)
                                                                           at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1310)
                                                                           at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                           at android.os.Looper.loop(Looper.java:135)
                                                                           at android.app.ActivityThread.main(ActivityThread.java:5270)
                                                                           at java.lang.reflect.Method.invoke(Native Method)
                                                                           at java.lang.reflect.Method.invoke(Method.java:372)
                                                                           at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:902)
                                                                           at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:697)
                                                                        Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.Button.setOnClickListener(android.view.View$OnClickListener)' on a null object reference
                                                                           at nerds.thesis.clartips.CLARTIPS_Home.onCreate(CLARTIPS_Home.java:42)
                                                                           at android.app.Activity.performCreate(Activity.java:6057)
                                                                           at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
                                                                           at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2288

Below are my codes for the adapter.

ListProductAdapter.java

public class ListProductAdapter extends BaseAdapter {
    private Context mContext;
    private List<Product> mProductList;

    public ListProductAdapter(Context mContext, List<Product> mProductList) {
        this.mContext = mContext;
        this.mProductList = mProductList;
    }

    @Override
    public int getCount() {
        return mProductList.size();
    }

    @Override
    public Object getItem(int position) {
        return mProductList.get(position);
    }

    @Override
    public long getItemId(int position) {
        return mProductList.get(position).getId();
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        View v = View.inflate(mContext, R.layout.listview, null);
        TextView pName = (TextView) v.findViewById(R.id.product_name);
        ImageView pImage = (ImageView) v.findViewById(R.id.product_image);
        TextView pPrice = (TextView) v.findViewById(R.id.product_price);
        TextView pDescription = (TextView) v.findViewById(R.id.product_description);
        TextView pCategory = (TextView) v.findViewById(R.id.product_category);
        pName.setText(mProductList.get(position).getName());

        Product image = mProductList.get(position);
        byte[] img = image.getImage();
        Bitmap bitmap = BitmapFactory.decodeByteArray(img, 0, img.length);
        pImage.setImageBitmap(bitmap);

        pPrice.setText("$" + String.valueOf(mProductList.get(position).getPrice()));
        pDescription.setText(mProductList.get(position).getDescription());
        pCategory.setText(mProductList.get(position).getCategory());

        return v;
    }
}

Solution

  • You have ActivityNotFoundException exception. It happens because Camera.java is not registered as an activity in manifest.xml file. Try this, edit manifest.xml, add <activity android:name=".Camera"/> inside <application> opening and closing </application> tags as follows.

    <application>
    
        <!--<activity android:name=".OtherActivities"/>  Declaration of other activities -->
        <activity android:name=".Camera"/>
    
    </application>
    

    To get rid of nullpointer exception, add this inside adapter class' getView method

    Button tryMe = (Button) v.findViewById(R.id.tryMe);
    
    tryMe.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Intent cameraIntent = new Intent(mContext, Camera.class);
            mContext.startActivity(cameraIntent);
        }
    });
    

    and remove button related code from your activity.