Search code examples
javaandroidxmlbackground-image

Programmatically change app background image (>gallery, internal memory) by another image that doesn't cover the first one. Should have same priority


I'm completely new to android, but used tons of StackOverflow questions to almost finished my app.

The workflow in short: upload an image from the gallery, save it to internal storage using a specific path (meaning, the next uploaded image would be saved to the very same internal path location as well), then set it as background (above existing background from XML: android:background="@drawable/bg_app_img which works fine).

The problem is that trying to do so works well at the saving level and the setting of wallpaper from the saved image, but the app's background doesn't work ok. Using the full window scale option to set image background, (if its ImageView is the last from the top in the XML file - highest priority, it would seem that) it couldn't be replaced by the current uploaded image. If the ImageView order is opposite, from highest scaled to lowest, it would be an image above a larger prior chosen image (see image below). So the problem lies with the order of ImageView in XML: The third (from the top) is the full-scaled one, which is "stuck" and won't let other images be shown, while the second won't let the first be shown (as it would appear behind it + smaller). The XML probably defines the priority but is unnecessary in my case, and after setting the background, even deleting the Image from internal storage does nothing to the currently shown last uploaded image pixels with their high priority.

Tried:

  1. Deleting android:background="@drawable/bg_app_img (a might be(?) solution to stretched wallpaper, didn't help).

  2. Setting the bg_app_img again before setting the new image (in the same coding way) :

    Uri uri_bg_temp = Uri.parse("android.resource://" + getPackageName() + "/" + 
    R.drawable.bg_app_img);
    full_ImageView.setImageURI(uri_bg_temp);
    smaller_ImageView.setImageURI(yourUri);
    

didn't work, as it made the "bg_app_img" the background without the new image above it.

  1. Switching the order of the 3 ImageView in the XML file made changes that didn't solve the problem as the smaller scaled one now can be above the larger size (according to priority in the XML file):

Priority from smallest to full scaled image

  1. Deleting android:scaleType="fitXY". nah.
  2. Sync clean, rebuild all, and invalidate caches, didn't help as well.

I don't want to change the XML permanently (or the current opening of the app?) using code, as the user might choose a half-scaled image, then a full one, then the half-scaled image, and if the half(height)-scaled would be deleted in any way and won't be shown-no good.

What should happen: any new chosen image from the gallery, would appear in the background above the drawable/bg_app_img without any image chosen before from the gallery.

XML code:

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

    <TextView
        android:id="@+id/textView6"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerInParent="true"
        android:adjustViewBounds="true"
        android:text="Wallpaper preview, image size:"
        android:textAlignment="center"
        android:textColor="@color/black"
        android:textSize="25sp"
        android:translationZ="90dp"
        android:scaleType="center"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <ImageView
        android:id="@+id/image_view_smallest"
        android:layout_height="match_parent"
        android:layout_width="match_parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:adjustViewBounds="true"
        android:scaleType="center"
        app:layout_constraintWidth_percent="1"
        app:layout_constraintWidth_default="percent"
        app:layout_constraintHeight_percent="1"
        app:layout_constraintHeight_default="percent" />

    <ImageView
        android:id="@+id/image_view_smaller"
        android:layout_height="match_parent"
        android:layout_width="match_parent"
        android:scaleType="center"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:adjustViewBounds="true"
        app:layout_constraintWidth_percent="1"
        app:layout_constraintWidth_default="percent"
        app:layout_constraintHeight_percent="1"
        app:layout_constraintHeight_default="percent" />


    <ImageView
        android:id="@+id/image_view"
        android:layout_height="match_parent"
        android:layout_width="match_parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:adjustViewBounds="true"
        app:layout_constraintWidth_percent="1"
        app:layout_constraintWidth_default="percent"
        app:layout_constraintHeight_percent="1"
        android:scaleType="fitXY"
        app:layout_constraintHeight_default="percent" />


    <Button
        android:id="@+id/gallery"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentStart="true"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:backgroundTint="@color/white"
        android:text="Full"

        android:textAllCaps="false"
        android:textColor="@color/black"
        android:textSize="22sp"
        app:layout_constraintBottom_toTopOf="@+id/textView6"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.2"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/chose_smaller_img" />

    <Button
        android:id="@+id/chose_smaller_img"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:backgroundTint="@color/white"
        android:text="3/4"
        android:textAllCaps="false"
        android:textColor="@color/black"
        android:textSize="22sp"
        app:layout_constraintBottom_toTopOf="@+id/gallery"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.8"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/chose_smallest_img" />

    <Button
        android:id="@+id/chose_smallest_img"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:backgroundTint="@color/white"
        android:text="half"
        android:textAllCaps="false"
        android:textColor="@color/black"
        android:textSize="22sp"
        app:layout_constraintBottom_toTopOf="@+id/chose_smaller_img"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView6" />

</androidx.constraintlayout.widget.ConstraintLayout>

Java class code:

package com.my_app;

import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AppCompatActivity;
import android.app.WallpaperManager;
import android.content.Context;
import android.content.ContextWrapper;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.Point;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.DisplayMetrics;
import android.view.Display;
import android.widget.Button;
import android.widget.ImageView;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Calendar;

public class day1 extends AppCompatActivity {
    
    //creating a mutable (changeable) bitmap:
    int w = 1, h = 1;
    Bitmap.Config conf = Bitmap.Config.ARGB_8888; // see other conf types
    Bitmap btm = Bitmap.createBitmap(w, h, conf);

    //Saving to internal memory the image as it is
    private void saveToInternalStorage(Bitmap bitmapImage){
        ContextWrapper cw = new ContextWrapper(getApplicationContext());
        // path to /data/data/your_app/app_data/imageDir
        File directory = cw.getDir("imageDir", Context.MODE_PRIVATE);
        // Create imageDir
        File internal_image_saved_path=new File(directory,"day1.jpg");

        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(internal_image_saved_path);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        // Use the compress method on the BitMap object to write image to the OutputStream
            bitmapImage.compress(Bitmap.CompressFormat.PNG, 100, fos);
    }

    //init:
    Uri uri=null;
    Context context=this;

    //day in week:
    Calendar c = Calendar.getInstance();
    int day_in_week = c.get(Calendar.DAY_OF_WEEK);

    //to scale image to window size (stretch)
    Button full_PickImage;
    ImageView full_ImageView;
    ActivityResultLauncher<String> mGetContent;
    //to scale image to window width and 0.75 height size
    Button smaller_PickImage;
    ImageView smaller_ImageView;
    ActivityResultLauncher<String> smallerGetContent;
    //to scale image to window width and 0.5 height size
    Button smallest_PickImage;
    ImageView smallest_ImageView;
    ActivityResultLauncher<String> smallestGetContent;

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

        //full size, 3/4, half:
        full_PickImage = findViewById(R.id.gallery);
        full_ImageView = findViewById(R.id.image_view);
        smaller_PickImage = findViewById(R.id.chose_smaller_img);
        smaller_ImageView = findViewById(R.id.image_view_smaller);
        smallest_PickImage = findViewById(R.id.chose_smallest_img);
        smallest_ImageView = findViewById(R.id.image_view_smallest);

        mGetContent = registerForActivityResult(new ActivityResultContracts.GetContent(),
                result -> {
                    full_ImageView.setImageURI(result);
                    uri = result;
                    if(uri!=null) {
                        //uri to bitmap to store in internal storage:
                        try {
                            Bitmap bitmap = MediaStore.Images.Media.getBitmap(context.getContentResolver() , Uri.parse(uri.toString()));

                            //get window width & height size:
                            int[] win_size = win_size();
                            int win_width  = win_size[0];
                            int win_height = win_size[1];

                            //bitmap scaled to win height & width size
                            Bitmap resized_bitmap = getResizedBitmap(bitmap, win_width, win_height);
                            //internal save:
                            saveToInternalStorage(resized_bitmap);
                            //set in App background:
                            show_background_chosen_img(0);
                            btm = resized_bitmap; //used later to set wallpaper (deleted for stackoverflow)
                        }
                        catch (Exception e) {
                            //handle exception
                        }
                    }
                });

        smallerGetContent = registerForActivityResult(new ActivityResultContracts.GetContent(),
                result -> {
                    smaller_ImageView.setImageURI(result);
                    uri = result;

                    if(uri!=null) {
                        //uri to bitmap to store in internal storage:
                        try {
                            Bitmap bitmap = MediaStore.Images.Media.getBitmap(context.getContentResolver() , Uri.parse(uri.toString()));
                            //get win h&w size:
                            int[] win_size = win_size();
                            int win_width= win_size[0];
                            int win_height=(int)(win_size[1] * 0.75);

                            //bitmap scaled to win height & width size
                            Bitmap resized_bitmap = getResizedBitmap(bitmap, win_width, win_height);
                            saveToInternalStorage(resized_bitmap);
                            //set background:
                            show_background_chosen_img(1);
                            btm = resized_bitmap; //used later
                        }
                        catch (Exception e) { 
                            //handle exception
                        }
                    }
                });

        smallestGetContent = registerForActivityResult(new ActivityResultContracts.GetContent(),
                result -> {
                    smallest_ImageView.setImageURI(result);
                    uri = result;

                    if(uri!=null) {
                        //uri to bitmap to store in internal storage:
                        try {
                            Bitmap bitmap = MediaStore.Images.Media.getBitmap(context.getContentResolver() , Uri.parse(uri.toString()));
                            //get win h&w size:
                            int[] win_size = win_size();
                            int win_width= (int)(win_size[0]);
                            int win_height=(int)(win_size[1] * 0.5);

                            //bitmap scaled to window height & width size (from above...)
                            Bitmap resized_bitmap = getResizedBitmap(bitmap, win_width, win_height);
                            saveToInternalStorage(resized_bitmap);
                            //set background:
                            show_background_chosen_img(2);
                            btm = resized_bitmap; //used later
                        }
                        catch (Exception e) {
                            //handle exception
                        }
                    }
                });


        full_PickImage.setOnClickListener(v -> mGetContent.launch("image/*"));
        smaller_PickImage.setOnClickListener(v -> smallerGetContent.launch("image/*"));
        smallest_PickImage.setOnClickListener(v -> smallestGetContent.launch("image/*"));
    }
    public Bitmap getResizedBitmap(Bitmap bm, int newWidth, int newHeight) {
        int width = bm.getWidth();
        int height = bm.getHeight();
        float scaleWidth = ((float) newWidth) / width;
        float scaleHeight = ((float) newHeight) / height;
        // CREATE A MATRIX FOR THE MANIPULATION
        Matrix matrix = new Matrix();
        // RESIZE THE BIT MAP
        matrix.postScale(scaleWidth, scaleHeight);
        // "RECREATE" THE NEW BITMAP
        Bitmap resizedBitmap = Bitmap.createBitmap(
                bm, 0, 0, width, height, matrix, false);
        bm.recycle();
        return resizedBitmap;
    }
    // get phone window size
    public int[] win_size(){
        Display display = getWindowManager(). getDefaultDisplay();
        Point size = new Point();
        display. getSize(size);
        int win_width = size.x;
        int win_height = size.y;
        return new int[] {win_width, win_height};
    }

    public void show_background_chosen_img(int type){
        //show current loaded image at first enter to class
        ContextWrapper cw = new ContextWrapper(getApplicationContext());
        // path to /data/data/your_app/app_data/imageDir
        File directory = cw.getDir("imageDir", Context.MODE_PRIVATE);
        File f = new File(directory, "day1.jpg");
        if (f.exists()) {
            Uri yourUri = Uri.fromFile(f);
            if (type==0) {
                //Uri uri_bg_temp = Uri.parse("android.resource://" + getPackageName() + "/" + R.drawable.bg_app_img);
                //full_ImageView.setImageURI(uri_bg_temp);
                full_ImageView.setImageURI(yourUri);
            }
            else if (type==1){
                //Uri uri_bg_temp = Uri.parse("android.resource://" + getPackageName() + "/" + R.drawable.bg_app_img);
                //full_ImageView.setImageURI(uri_bg_temp);
                smaller_ImageView.setImageURI(yourUri); }
            else if (type==2) {
                //Uri uri_bg_temp = Uri.parse("android.resource://" + getPackageName() + "/" + R.drawable.bg_app_img);
                //smallest_ImageView.setImageURI(uri_bg_temp);
                smallest_ImageView.setImageURI(yourUri); }
        }
    }
}

If you feel that the main class and its XML or even the build.gradle needed as well, please let me know. B.T.W, the bg_app_image.png is an xxxhdpifile (even though it is probably not connected to the problem). Thanks!


Solution

  • The trick to solving it is that I made the priority in the XML file to the smallest image, then while trying to apply the full image to the screen background, I changed ImageView from Full to the smallest (which has the highest priority), in that way: first, I applied again the background to reset the applied former background with other options (half, 3/4...):

    smallest_ImageView.setImageBitmap(bg_original);
    

    Then, changed from full (ImageView) to smallest (highest priority) at the setting part of the background image:

    Set App background:

    smallest_ImageView.setImageBitmap(resized_bitmap);