javaandroidandroid-intentadapter

How to start a camera intent and save picture taken to a specific location for each item in a listView


I'm new to programming and I don't know how to start camera intent from the adapter and to save image to a specific location for each item in the listview. I would like when I press the button takeImage to start a camera intent and to save the taken image to a specific location for each item in the list view. I defined in the Planet class an attribute

this.pathToSave = pathToSave

in order to be possible to save to a specific location but I don't know how to put all togheter.

public class MyCustomAdaptor extends ArrayAdapter<Planet> {

    private ArrayList<Planet> planetsArrayList;
    Context context;

    public MyCustomAdaptor(ArrayList<Planet> planetsArrayList,Context context){
        super(context, R.layout.item_list_layout,planetsArrayList);
        this.planetsArrayList = planetsArrayList;
        this.context = context;

    }

    private static class MyViewHolder{
        TextView planetName;
        ImageView planetImg;

    }

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

        Planet planets = getItem(position);

        MyViewHolder myViewHolder;
        final View result;

        if(convertView == null) {
            myViewHolder = new MyViewHolder();
            LayoutInflater inflater = LayoutInflater.from(getContext());
            convertView = inflater.inflate(
                    R.layout.item_list_layout,
                    parent,
                    false
            );

            myViewHolder.planetName = (TextView) convertView.findViewById(R.id.planet_name);
            myViewHolder.planetImg = (ImageView) convertView.findViewById(R.id.imageView);

            result = convertView;

            convertView.setTag(myViewHolder);
        }else{
            myViewHolder = (MyViewHolder) convertView.getTag();
            result = convertView;
        }

        myViewHolder.planetName.setText(planets.getPlanetName());
        myViewHolder.planetImg.setImageResource(planets.getPlanetImage());


        return result;
    }

}

Then I have the Planet class:

public class Planet {

    private String planetName;
    private int planetImage;
    private String pathToSave;

    public Planet(String planetName, int planetImage, String pathToSave){
        this.planetName = planetName;
        this.planetImage = planetImage;
        this.pathToSave = pathToSave;
    }

    public String getPlanetName() {
        return planetName;
    }

    public int getPlanetImage() {
        return planetImage;
    }

    public String getPathToSave() {
        return pathToSave;
    }

    public void setPlanetName(String planetName) {
        this.planetName = planetName;
    }

    public void setPlanetImage(int planetImage) {
        this.planetImage = planetImage;
    }

    public void setPathToSave(String pathToSave) {
        this.pathToSave = pathToSave;
    }
}

Then I have the listView:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="110sp"
        android:layout_height="110sp"
        android:layout_margin="16sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.006"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />


    <TextView
        android:id="@+id/planet_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="20dp"
        android:layout_marginTop="16dp"
        android:text="Planet Name"
        android:textSize="24sp"
        android:textStyle="bold"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toEndOf="@+id/imageView"
        app:layout_constraintTop_toTopOf="parent" />


    <Button
        android:id="@+id/takeImage"
        android:layout_width="110sp"
        android:layout_height="40sp"
        android:layout_marginTop="108dp"
        android:text="Scan Doc"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.465"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />


</androidx.constraintlayout.widget.ConstraintLayout>

I've tried to everything but doesn't work.


Solution

  • First, in your Activity you need to use the:

    ActivityResultLauncher

    And pass it to the adapter:

    public class Activity {
        private ActivityResultLauncher<Intent> cameraLauncher;
        MyCustomAdaptor adapter;
    
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.your_layout);
    
            setupCameraLauncher();
    
            // This on onCreate or after retrieve the planetsArrayList data
            adapter = new MyCustomAdaptor (planetsArrayList, context, cameraLauncher);
        }
        
        public void setupCameraLauncher() {
            cameraLauncher = registerForActivityResult(
                new ActivityResultContracts.StartActivityForResult(),
                result -> {
                    if (result.getResultCode() == Activity.RESULT_OK) {
                        Uri imageUri = adapterStructures.getCapturedImageUri();
                        String cameraUriString = imageUri.toString(); // Here is your LOCAL IMAGE 
                        
                        Planet planet = new Planet();
                        planet.setPlanetName("The Planet"); // Handle your value
                        planet.setPlanetImage(1); // Handle your value
                        planet.setPathToSave(cameraUriString );
                        planetsArrayList.add(planet);
    
                        adapter.notifyDataSetChanged();
                    }
            )
        }
       
    }
    

    Your adapter:

    public class MyCustomAdaptor extends ArrayAdapter<Planet> {
    
    private ArrayList<Planet> planetsArrayList;
    Context context;
    private final ActivityResultLauncher<Intent> cameraLauncher;
    
    public MyCustomAdaptor(ArrayList<Planet> planetsArrayList,Context context, ActivityResultLauncher<Intent> cameraLauncher){
        super(context, R.layout.item_list_layout,planetsArrayList);
        this.planetsArrayList = planetsArrayList;
        this.context = context;
        this.cameraLauncher = cameraLauncher;
    
    }
    
    private static class MyViewHolder{
        TextView planetName;
        ImageView planetImg;
        Button takeImage; // Add this
    
    }
    
    @NonNull
    @Override
    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
    
        Planet planets = getItem(position);
    
        MyViewHolder myViewHolder;
        final View result;
    
        if(convertView == null) {
            myViewHolder = new MyViewHolder();
            LayoutInflater inflater = LayoutInflater.from(getContext());
            convertView = inflater.inflate(
                    R.layout.item_list_layout,
                    parent,
                    false
            );
    
            myViewHolder.planetName = (TextView) convertView.findViewById(R.id.planet_name);
            myViewHolder.planetImg = (ImageView) convertView.findViewById(R.id.imageView);
            myViewHolder.takeImage = (Button) convertView.findViewById(R.id.takeImage);
    
            result = convertView;
    
            convertView.setTag(myViewHolder);
        }else{
            myViewHolder = (MyViewHolder) convertView.getTag();
            result = convertView;
        }
    
        myViewHolder.planetName.setText(planets.getPlanetName());
        myViewHolder.planetImg.setImageResource(planets.getPlanetImage());
        myViewHolder.takeImage.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    openCamera(); // THe method to open the camera
                }
            });
    
        return result;
        }
    
    private void openCamera() {
        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    
        if (takePictureIntent.resolveActivity(context.getPackageManager()) != null) {
            File photoFile = null;
            try {
                photoFile = createImageFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
    
            if (photoFile != null) {
                // Get the URI where the image will be saved in the gallery
                ContentValues values = new ContentValues();
                values.put(MediaStore.Images.Media.TITLE, "My Photo");
                values.put(MediaStore.Images.Media.DESCRIPTION, "From Camera");
                values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
    
                capturedImageUri = FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", photoFile);
                
                if (capturedImageUri != null) {
                    Log.d("openCamera", "Photo URI saved: " + capturedImageUri);
                    takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, capturedImageUri);
                    cameraLauncher.launch(takePictureIntent);
                }
            }
        }
    
    }
    
    
    public Uri getCapturedImageUri() {
        return capturedImageUri;
    }
    

    Then the method to create the unique image:

    private File createImageFile() throws IOException {
        Log.d("createImageFile", "Creating image file...");
        currentPhotoPath = "";
        // Create a unique image file name based on timestamp
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
        String imageFileName = "JPEG_" + timeStamp + "_";
    
        //File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
        File storageDir = equipmentInfo.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
        // Create the directory if it doesn't exist
        if (!storageDir.exists()) {
            storageDir.mkdirs();
        }
        Log.d("createImageFile", "Storage directory: " + storageDir.getAbsolutePath());
    
        // Create the image file with a unique name
        File imageFile = File.createTempFile(
                imageFileName,  /* prefix */
                ".jpg",         /* suffix */
                storageDir      /* directory */
        );
    
        // Save the file path for use with the camera intent
        currentPhotoPath = imageFile.getAbsolutePath();
    
        Log.d("createImageFile", "Image file created: " + currentPhotoPath);
    
        return imageFile;
    }