jesto paul
jesto paul

Reputation: 504

java.lang.IllegalArgumentException: Unknown URL content://com.android.globaldataservice.data.provider/globaldataapp

I have an automotive infotainment application that supports multiple user profiles. However, our requirement is to maintain the same data across all user profiles, making it vehicle-specific.

In my application, I have a radio group, and when a radio button is clicked, the selected value needs to be saved in a ContentProvider. Both saving and fetching operations should be handled through the ContentProvider.

When switching to another user profile, the same previously saved data should be retrieved from the ContentProvider.

Example Scenario: UserProfile1:

User selects an option via the radio group (e.g., value = 3). This value (3) should be saved in the ContentProvider.

UserProfile2:

Upon switching to another profile, the application should fetch the previously saved value from the ContentProvider. Expected value: 3 (same as what was saved in UserProfile1). However, the issue I'm facing is that the value is not being set correctly, even for UserProfile1.

am getting crash like :

FATAL EXCEPTION: DefaultDispatcher-worker-3 (Ask Gemini)
                                                                                                    Process: com.android.globaldataapp, PID: 6914
                                                                                                    java.lang.IllegalArgumentException: Unknown URL content://com.android.globaldataservice.data.provider/globaldataapp
                                                                                                        at android.content.ContentResolver.insert(ContentResolver.java:2189)
                                                                                                        at android.content.ContentResolver.insert(ContentResolver.java:2155)
                                                                                                        at com.android.globaldataservice.data.provider.AppDataProviderWrapper.setValue(AppDataProviderWrapper.kt:23)
                                                                                                        at com.android.globaldataservice.data.repository.api.can.ApiRepository.saveData(ApiRepository.kt:691)
                                                                                                        at com.android.globaldataservice.data.repository.api.can.ApiRepository$initializeBootUpValues$1.invokeSuspend(ApiRepository.kt:1791)
                                                                                                        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
                                                                                                        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
                                                                                                        at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
                                                                                                        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
                                                                                                        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
                                                                                                        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)
                                                                                                        Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@2fbca59, Dispatchers.Default]

My code will be like this :

AppGlobalDataContentProvider.kt

class AppGlobalDataContentProvider : ContentProvider() {

    private val sUriMatcher = UriMatcher(UriMatcher.NO_MATCH).apply {
        addURI("com.android.globaldataservice.data.provider", "globaldataapp", 1)
        
    }

    companion object {
        const val AUTHORITY =
            "com.android.globaldataservice.data.provider"
        val CONTENT_URI: Uri = Uri.parse("content://$AUTHORITY/globaldataapp")
    }

    private lateinit var sharedPreferences: SharedPreferences


    override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int {
        sharedPreferences.edit().remove(KEY_VALUE).apply()
        context?.contentResolver?.notifyChange(uri, null)
        return 1
    }

    override fun getType(uri: Uri): String? {
        return null
    }

    override fun insert(uri: Uri, values: ContentValues?): Uri? {


        when (sUriMatcher.match(uri)) {
            1 -> {
                val value = values?.getAsString(KEY_VALUE) ?: return null
                sharedPreferences.edit().putString(KEY_VALUE, value).apply()
                context?.contentResolver?.notifyChange(uri, null)
                return uri
            }
            else -> throw IllegalArgumentException("Unknown URI: $uri")
        }
    }

    override fun onCreate(): Boolean {
        val context = context?.createDeviceProtectedStorageContext()
            ?: throw IllegalStateException("Device-Protected storage context not available")
        sharedPreferences = context.getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE)
        return true
    }

    override fun query(
        uri: Uri, projection: Array<String>?, selection: String?,
        selectionArgs: Array<String>?, sortOrder: String?
    ): Cursor? {
        val value = sharedPreferences.getString(KEY_VALUE, null) ?: return null
        val cursor = MatrixCursor(arrayOf(KEY_VALUE))
        cursor.addRow(arrayOf(value))
        return cursor
    }

    override fun update(
        uri: Uri, values: ContentValues?, selection: String?,
        selectionArgs: Array<String>?
    ): Int {
        val value = values?.getAsString(KEY_VALUE) ?: return 0
        sharedPreferences.edit().putString(KEY_VALUE, value).apply()
        context?.contentResolver?.notifyChange(uri, null)
        return 1
    }

AppDataProviderWrapper.kt

@Singleton
class AppDataProviderWrapper @Inject constructor(@ApplicationContext private val context: Context) {

    private val mContentUri: Uri = Uri.parse("content://$AUTHORITY/globaldataapp")

    fun saveData(data: Int) {
        val contentResolver = context.contentResolver
        val contentValues = ContentValues().apply {
            put(KEY_VALUE, data)
        }
        contentResolver.insert(mContentUri, contentValues)
    }

    fun getdata(): Int? {
        val sharedPreferences = context.createDeviceProtectedStorageContext()
            ?.getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE)
        return sharedPreferences?.getInt(KEY_VALUE, 0)
    }
}

Androidmanifest.xml

<provider
            android:name=".data.provider.AppGlobalDataContentProvider"
            android:authorities="com.android.globaldataservice.data.provider"
            android:enabled="true"
            android:exported="false"
            android:grantUriPermissions="true"
            android:singleUser="true" />

ApiRepository.kt

appDataProviderWrapper.saveData(chargingType)

So here when I tried save the data app is crashing.

Upvotes: 0

Views: 28

Answers (1)

Mohammad Misbah
Mohammad Misbah

Reputation: 1084

I guess your crash occurs due to an IllegalArgumentException: Unknown URL, which indicates that the URI used in the insert operation does not match the URI pattern registered in the ContentProvider. First, ensure the AUTHORITY value in your UriMatcher matches exactly with what is used in AppDataProviderWrapper. Update the UriMatcher definition as follows:

private val sUriMatcher = UriMatcher(UriMatcher.NO_MATCH).apply {
    addURI(AUTHORITY, "globaldataapp", 1)
}

Similarly, in AppDataProviderWrapper, ensure you are using the correct URI:

private val mContentUri: Uri = Uri.parse("content://$AUTHORITY/globaldataapp")

Additionally, modify the insert() method in AppGlobalDataContentProvider to handle unknown URIs gracefully by logging the error instead of throwing an exception.

override fun insert(uri: Uri, values: ContentValues?): Uri? {
    return when (sUriMatcher.match(uri)) {
        1 -> {
            val value = values?.getAsString(KEY_VALUE) ?: return null
            sharedPreferences.edit().putString(KEY_VALUE, value).apply()
            context?.contentResolver?.notifyChange(uri, null)
            uri
        }
        else -> {
            Log.e("AppGlobalDataContentProvider", "Unknown URI: $uri")
            null
        }
    }
}

Your saveData() function should also handle potential failures when inserting into the ContentProvider:

fun saveData(data: Int) {
    val contentResolver = context.contentResolver
    val contentValues = ContentValues().apply {
        put(KEY_VALUE, data)
    }
    try {
        val resultUri = contentResolver.insert(mContentUri, contentValues)
        if (resultUri == null) {
            Log.e("AppDataProviderWrapper", "Failed to insert data into ContentProvider")
        }
    } catch (e: Exception) {
        Log.e("AppDataProviderWrapper", "Error inserting data", e)
    }
}

Furthermore, as you need to maintain data consistency across multiple user profiles, ensure that all reads and writes are performed using DeviceProtectedStorageContext, allowing the data to persist across different user sessions:

val context = context.createDeviceProtectedStorageContext()

Lastly, check your AndroidManifest.xml`` to ensure that android:exported="true"is set if other apps or system services require access. Also, consider addingandroid:directBootAware="true"``` to ensure preferences are accessible across user profiles. With these fixes, your application should correctly save and retrieve data across all user profiles without crashing.

Upvotes: 0

Related Questions