0

I am targeting my Android app for Android 13 (API 33)

I have generated an Excel file from my list and saved it but it doesn't save in API 33 but less than API Android 33 save very well.

If needed, these libraries have been used

implementation 'org.apache.poi:poi:4.0.0'
implementation 'org.apache.poi:poi-ooxml:4.0.0'

Manifest permission

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

Check Permission

private void checkPermission() {
    if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
        if (getApplicationContext().checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
            String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
            requestPermissions(permissions, 1);
        } else {
            importData();
        }
    } else {
        importData();
    }

}

make excel files and storage

    private void importData() {
        //get data from edit text

        try {
            userList.add(new SheetModel("kawcher", "0181238383", "nmkawcher112@gmail.com"));
            userList.add(new SheetModel("shuvo", "0171238383", "demo1@gmail.com"));
            userList.add(new SheetModel("hasan", "0161238383", "demo2@gmail.com"));
            userList.add(new SheetModel("habib", "0151238383", "demo3@gmail.com"));
            userList.add(new SheetModel("selim", "0131238383", "demo4@gmail.com"));
            userList.add(new SheetModel("tayeb", "0121238383", "demo5@gmail.com"));
            userList.add(new SheetModel("abul kalam", "0191238383", "demo6@gmail.com"));
            userList.add(new SheetModel("Kamal", "0101238383", "demo7@gmail.com"));

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

        if (userList.size() > 0) {
            createXlFile();


        } else {
            Toast.makeText(this, "list are empty", Toast.LENGTH_SHORT).show();
        }
    }

    private void createXlFile() {

        // File filePath = new File(Environment.getExternalStorageDirectory() + "/Demo.xls");
        Workbook wb = new HSSFWorkbook();


        Cell cell = null;

        Sheet sheet = null;
        sheet = wb.createSheet("Demo Excel Sheet");
        //Now column and row
        Row row = sheet.createRow(0);

        cell = row.createCell(0);
        cell.setCellValue("Person Name");


        cell = row.createCell(1);
        cell.setCellValue("Phone Number");


        cell = row.createCell(2);
        cell.setCellValue("Email Address");


        //column width
        sheet.setColumnWidth(0, (20 * 200));
        sheet.setColumnWidth(1, (30 * 200));
        sheet.setColumnWidth(2, (30 * 200));


        for (int i = 0; i < userList.size(); i++) {
            Row row1 = sheet.createRow(i + 1);

            cell = row1.createCell(0);
            cell.setCellValue(userList.get(i).getName());

            cell = row1.createCell(1);
            cell.setCellValue((userList.get(i).getPhoneNo()));
            //  cell.setCellStyle(cellStyle);

            cell = row1.createCell(2);
            cell.setCellValue(userList.get(i).getEmail());


            sheet.setColumnWidth(0, (20 * 200));
            sheet.setColumnWidth(1, (30 * 200));
            sheet.setColumnWidth(2, (30 * 200));

        }
        String folderName = "Import Excel";
        String fileName = folderName + System.currentTimeMillis() + ".xls";
        String path = Environment.getExternalStorageDirectory() + File.separator + folderName + File.separator + fileName;

        File file = new File(Environment.getExternalStorageDirectory() + File.separator + folderName);
        if (!file.exists()) {
            file.mkdirs();
        }
//         file.deleteOnExit();

        FileOutputStream outputStream = null;

        try {

            //
            outputStream = new FileOutputStream(path);
//            outputStream = new FileOutputStream(new File(getFilesDir()., path));
            wb.write(outputStream);
            // ShareViaEmail(file.getParentFile().getName(),file.getName());
            Toast.makeText(getApplicationContext(), "Excel Created in " + path, Toast.LENGTH_SHORT).show();
        } catch (IOException e) {
            e.printStackTrace();

            Toast.makeText(getApplicationContext(), "Not OK", Toast.LENGTH_LONG).show();
            try {
                outputStream.close();
            } catch (Exception ex) {
                ex.printStackTrace();

            }
        }

    }

Error logcat:

     /System.err: java.io.FileNotFoundException: /storage/emulated/0/Import Excel/Import Excel1681376608447.xls: open
 failed: ENOENT (No such file or directory)
             at libcore.io.IoBridge.open(IoBridge.java:574)
             at java.io.FileOutputStream.<init>(FileOutputStream.java:236)
             at java.io.FileOutputStream.<init>(FileOutputStream.java:125)
             at com.roomack.amlaak.view.activity.MainActivity.createXlFile(MainActivity.java:1125)
             at com.roomack.amlaak.view.activity.MainActivity.importData(MainActivity.java:1051)
             at com.roomack.amlaak.view.activity.MainActivity.checkPermission(MainActivity.java:1020)
             at com.roomack.amlaak.view.activity.MainActivity.access$300(MainActivity.java:100)
             at com.roomack.amlaak.view.activity.MainActivity$18.onClick(MainActivity.java:821)
             at android.view.View.performClick(View.java:7560)
             at android.view.View.performClickInternal(View.java:7533)
             at ndroid.view.View.-$$Nest$mperformClickInternal(Unknown Source:0)
             at android.view.View$PerformClick.run(View.java:29754)
     W/System.err:     at android.os.Handler.handleCallback(Handler.java:942)
             at android.os.Handler.dispatchMessage(Handler.java:99)
             at android.os.Looper.loopOnce(Looper.java:211)
             at android.os.Looper.loop(Looper.java:300)
             at android.app.ActivityThread.main(ActivityThread.java:8143)
             at java.lang.reflect.Method.invoke(Native Method)
             at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:580)
             at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1028)
         Caused by: android.system.ErrnoException: open failed: ENOENT (No such file or directory)
             at libcore.io.Linux.open(Native Method)
             at libcore.io.ForwardingOs.open(ForwardingOs.java:563)
             at libcore.io.BlockGuardOs.open(BlockGuardOs.java:274)
             at libcore.io.ForwardingOs.open(ForwardingOs.java:563)
             at android.app.ActivityThread$AndroidOs.open(ActivityThread.java:8019)
             at libcore.io.IoBridge.open(IoBridge.java:560)
Amin
  • 342
  • 4
  • 15
  • 1
    `but less than API Android 33 save very well.` Because you use MANAGE_EXTERNAL_STIRAGE. Without that it will fail on 30+. – blackapps Apr 13 '23 at 09:29
  • @blackapps - I have used MANAGE_EXTERNAL_STORAGE in my project, but not work – Amin Apr 13 '23 at 09:33
  • @blackapps ok I changed logcat to code block view – Amin Apr 19 '23 at 12:28
  • `if (!file.exists()) { file.mkdirs(); }` That should be: `if (!file.exists()) { if(!file.mkdirs()) return; }` – blackapps Apr 19 '23 at 15:28
  • You should use an existing public directory. Do not try to create one yourself. – blackapps Apr 19 '23 at 15:29
  • @blackapps I changed it this way but I can't write the file I even change the path but did not get correct. – Amin Apr 20 '23 at 11:00
  • Post your new code. Then tell what5 happens. – blackapps Apr 20 '23 at 11:01
  • @blackapps : > String path = this.getExternalFilesDir(null).getAbsolutePath() + File.separator + folderName + File.separator + fileName; File file = new File(path); if (!file.exists()) { File wallpaperDirectory = new File(path); wallpaperDirectory.mkdirs(); } – Amin Apr 20 '23 at 11:15
  • 1
    Terrible. You have not used an existing public directory. You introduce a new File variable. You are not checking the return value of mkdirs(). You are doing nothing with all suggestions. And then you post code as comment. Unreadable. Post your code completely in your post. Also post the new logcat lines if anything goes wrong. – blackapps Apr 20 '23 at 11:20
  • @blackapps sorry for the comment but I want to share the link answer that I used https://stackoverflow.com/a/70419518/10608055 – Amin Apr 20 '23 at 11:30

2 Answers2

1

You cannot request write permission on Android 13 devices.

You automatically have write permission in all app specific directories and all public directories on external storage.

blackapps
  • 8,011
  • 2
  • 11
  • 25
  • It's true, but all the features are in the manifest but I can't write on Android 13 that this problem still exists for me and I check anyway but I am confused to fix it for android API 33 – Amin Apr 13 '23 at 09:30
  • With MANAGE_EXTERNAL_STORAGE on an Android 13 device you can create your own files and folders also in root of external storage. – blackapps Apr 13 '23 at 09:33
0

In HomeFragment.kt is called like this:

    binding.btHomeExport.setOnClickListener {
        GlobalScope.launch {
            exportData(requireActivity())
        }
    }

The Export.kt it is just a Java utility class converted to Kotlin, practically just to move out the code:

object Export { suspend fun exportData(activity: Activity) {

    try {
        // read again from file?

        val listMyDealWithMyClient = doReadFromFile(activity)

        val timeZoneDate = SimpleDateFormat("yyyy-MMM-dd_HH-mm-ss", Locale.getDefault())
        val formattedDate = timeZoneDate.format( Date())

        val workbook = XSSFWorkbook()
        val workSheet = workbook.createSheet("MyDeals_$formattedDate")
        val colorMap = workbook.stylesSource.indexedColors

        val cellStyleHeader = workbook.createCellStyle()
        cellStyleHeader.fillForegroundColor = IndexedColors.AQUA.getIndex()
        cellStyleHeader.fillPattern = FillPatternType.SOLID_FOREGROUND
        cellStyleHeader.font.bold = true
        cellStyleHeader.verticalAlignment = VerticalAlignment.CENTER
        cellStyleHeader.alignment = HorizontalAlignment.CENTER
        cellStyleHeader.setRightBorderColor( XSSFColor(byteArrayOf(0, 0, 0), colorMap))
        cellStyleHeader.borderRight = BorderStyle.THIN


        val row0 = workSheet.createRow(0)
        row0.height = 800

more code here, which are data procesing ...

        // save workbook to file:
        val fileName = "data_$formattedDate.xlsx"
        val fos: FileOutputStream =
            activity.openFileOutput(fileName, Context.MODE_PRIVATE)!!

        workbook.write(fos)
        workbook.close()

        withContext(Dispatchers.IO) {
            fos.flush()
            fos.close();
        };

        //need: fos.path, but it is private!

        val appPath = activity.application?.filesDir?.absolutePath
        // delete old .xlsx files
        val dir = appPath?.let { File(it) }
        dir?.listFiles()!!.forEach { file ->
            run {
                if (file.name.endsWith(".xlsx")) {
                    file.deleteOnExit()
                }
            }
        }

        val exportFile = File(appPath, fileName)


        val sharingIntent = Intent(Intent.ACTION_SEND)

        val fileUri =
            FileProvider.getUriForFile(//
                activity.applicationContext!!,
                activity.packageName + ".fileProvider",
                exportFile
            );

VERY IMPORTANT ".fileProvider" must match the case with others: Manifest:

<application
    android:allowBackup="false"
    android:dataExtractionRules="@xml/data_extraction_rules"
    android:fullBackupContent="@xml/backup_rules"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/Theme.MyAppTheme"
    tools:targetApi="33">



    <provider
        android:name="androidx.core.content.FileProvider"
        android:authorities="my.package.with.myid.fileProvider"
        android:grantUriPermissions="true"
        android:exported="false">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_provider_path"/>
    </provider>

    <activity
        android:name=

NOT needed Read External, Write External permissions! None needed!

At res/xml create a file file_provider_path.xml

Paste the content:

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <files-path
        name="files"
        path="." />
</paths>

The file it wil be exported, not sure how it can be accessed by other apps. That's why I do a share / send file and I let the user choose the Intent:

            // add provider
            sharingIntent.type = "*/*"
            sharingIntent.putExtra(Intent.EXTRA_STREAM, fileUri)

            sharingIntent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION

            activity.startActivity(sharingIntent)


        } catch (ex: Exception) {
            ex.printStackTrace()
            Toast.makeText(activity, ex.message, Toast.LENGTH_LONG).show();
        }
    }
}

This is the final part of the Export.kt

Today (May 22, 2023) it is working with Android 33...tomorrow maybe not -as how Google changes their API...

I don't target other devices, just Android 33 - because it is a utility app for somebody. It were many changes at Androi pre 8, post 8, pre 9 , post 9, pre 10, post 10, pre 11, pre 12, post 12, pre 13, and +13 Spent like 10 days to put the lego pieces together :)

As testing I am sending the .xlsx file via Bluetooth to Desktop PC ( Windowws 10) and checking there the data + formatting, and is working!

matheszabi
  • 594
  • 5
  • 16