Android

How to access WhatsApp statuses folder in Android 11  or above.

In this tutorial we will learn how to access WhatsApp statuses folder in android 11 and above programmatically. Accessing whatsapp statuses folder in android 11 is different from the other lower android versions. This difference is due to storage enhancements in Android 11.

Scoped Storage in Android 11

The Android 11 becomes with major changes in storage. These changes leads to the division of whole storage into blocks. This division is called scoped storage. Scoped storage has Media and Download collections. The media folder contains  Images, Audios and Video files, while document collection stores the non media files.

Access WhatsApp Statuses Folder

We can access WhatsApp Status folder using the DocumentTreeIntent . This intent will allow access permission of whatsapp status folder.

Let’s start the process of accessing the whatsapp status folder.

Create a new android project

After creatiing new project add view binding feature in build.gradle file and sync the project.

buildFeatures {
    viewBinding true
}

ACTION_OPEN_DOCUMENT_TREE Intent

To access the whatsapp statuses we first need to take permission of that folder. Without this permission we cannot access the statuses. To take permission we will use ACTION_OPEN_DOCUMENT_TREE Intent. This will open an UI with a button to take permission of this folder. To launch this intent we will create a launcher object for activity result.

val launcher =
    registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
        if (result.resultCode == Activity.RESULT_OK) {
            // There are no request codes
            val data: Intent? = result.data
            if (data != null) {
                 getWAStatuses(data.data!!)
            }
        }
    }

Take WhatsApp Status Folder Access Permission

This launcher will help us to launch that ACTION_OPEN_DOCUMENT_TREE Intent, and we can get back the result. Result contains the URI of whatsapp statuses folder. Let’s launch the intent using this method.

fun askMediaFolderAccessPermission() {
    val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
    intent.putExtra(
        DocumentsContract.EXTRA_INITIAL_URI,
        DocumentFile.fromTreeUri(
            this,
           Uri.parse("content://com.android.externalstorage.documents/tree/primary%3AAndroid%2Fmedia%2Fcom.whatsapp%2FWhatsApp%2FMedia%2F.Statuses"))!!.uri
    )
    launcher.launch(intent)
}

Here we use the intent to access folder permission. The initial uri parameter is used to open the whatsapp folder. When we will launch this intent, it will open an UI in which WhatsApp statuses folder will be opened and one button will appear to access permission of this folder. By pressing that button we can access files of that folder and will get the uri of that folder in result. Now we can get all statuses of that folder .

Fetch List of Whatsapp Statuses

Here is the method to get all WhatsApp statuses.

fun getWAStatuses(uri: Uri) {
    val docFile = DocumentFile.fromTreeUri(this, uri)
    val files = docFile!!.listFiles()
    
}

In this method we just fetch the list of files from that folder using the document file.

Now we can show these statuses in recyclerview.

Here is the full code.

MainActivity.kt

package com.example.statusdemo

import android.app.Activity
import android.content.Intent
import android.net.Uri
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.provider.DocumentsContract
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.documentfile.provider.DocumentFile
import androidx.recyclerview.widget.GridLayoutManager
import com.example.statusdemo.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    val launcher =
        registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
            if (result.resultCode == Activity.RESULT_OK) {
                // There are no request codes
                val data: Intent? = result.data
                if (data != null) {
                     getWAStatuses(data.data!!)
                }
            }
        }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding=ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        initRecyclerView()
        askMediaFolderAccessPermission()
    }

    fun getWAStatuses(uri: Uri) {
        val docFile = DocumentFile.fromTreeUri(this, uri)
        val files = docFile!!.listFiles()
         setRecyclerViewAdapter(files.toList())
    }

    fun initRecyclerView() {
        val layoutManager = GridLayoutManager(this, 2)
        binding.recyclerView.layoutManager = layoutManager
    }

    fun setRecyclerViewAdapter(files: List<DocumentFile>) {
        val adapter = StatusListAdapter(this, files)
        binding.recyclerView.adapter = adapter
    }

    fun askMediaFolderAccessPermission() {
        val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
        intent.putExtra(
            DocumentsContract.EXTRA_INITIAL_URI,
            DocumentFile.fromTreeUri(
                this,
                Uri.parse("content://com.android.externalstorage.documents/tree/primary%3AAndroid%2Fmedia%2Fcom.whatsapp%2FWhatsApp%2FMedia%2F.Statuses")
            )!!
                .uri
        )
        launcher.launch(intent)
    }

}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    tools:context=".MainActivity">

   <androidx.recyclerview.widget.RecyclerView
       android:id="@+id/recycler_view"
       android:layout_width="match_parent"
       android:layout_height="match_parent"/>

</LinearLayout>
Layout_single_status.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_margin="6dp"
    android:layout_height="150dp">
<ImageView
    android:id="@+id/image_view"
    android:scaleType="centerCrop"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>
</LinearLayout>
StatusListAdapter.kt

package com.example.statusdemo

import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.documentfile.provider.DocumentFile
import androidx.recyclerview.widget.RecyclerView
 import com.example.statusdemo.databinding.LayoutSingleStatusBinding

class StatusListAdapter(val context : Context ,val list : List<DocumentFile>)  : RecyclerView.Adapter<StatusListAdapter.StatusListHolder>() {
    class StatusListHolder( val binding : LayoutSingleStatusBinding): RecyclerView.ViewHolder(binding.root){

    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): StatusListHolder {
       val binding =LayoutSingleStatusBinding.inflate(LayoutInflater.from(context),parent,false)
        return  StatusListHolder(binding)
    }

    override fun onBindViewHolder(holder: StatusListHolder, position: Int) {
       holder.binding.imageView.setImageURI(list.get(position).uri)
    }

    override fun getItemCount(): Int {
       return  list.size
    }
}

Conclusion

In this tutorial we have learned that how to access WhatsApp statuses folder in Android 11 and above with scoped store. We take permission of statuses folder using ACTION_OPEN_DOCUMENT_TREE Intent, and get list of all statues. Hope this will help you to understand the scoped storage and accessing files from this storage.

Leave a Reply

Your email address will not be published. Required fields are marked *