Extract contact permission check to ContactPermissionResolver
This commit is contained in:
parent
c642d7615f
commit
b80f153ce3
6 changed files with 87 additions and 32 deletions
|
@ -1,13 +1,9 @@
|
|||
package app.k9mail.core.android.common.contact
|
||||
|
||||
import android.Manifest
|
||||
import android.content.ContentResolver
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.database.Cursor
|
||||
import android.net.Uri
|
||||
import android.provider.ContactsContract
|
||||
import androidx.core.content.ContextCompat
|
||||
import app.k9mail.core.android.common.database.EmptyCursor
|
||||
import app.k9mail.core.android.common.database.getLongOrThrow
|
||||
import app.k9mail.core.android.common.database.getStringOrNull
|
||||
|
@ -21,8 +17,8 @@ interface ContactDataSource {
|
|||
}
|
||||
|
||||
internal class ContentResolverContactDataSource(
|
||||
private val context: Context,
|
||||
private val contentResolver: ContentResolver = context.contentResolver,
|
||||
private val contentResolver: ContentResolver,
|
||||
private val contactPermissionResolver: ContactPermissionResolver,
|
||||
) : ContactDataSource {
|
||||
|
||||
override fun getContactFor(emailAddress: EmailAddress): Contact? {
|
||||
|
@ -57,12 +53,12 @@ internal class ContentResolverContactDataSource(
|
|||
}
|
||||
|
||||
private fun getCursorFor(emailAddress: EmailAddress): Cursor {
|
||||
val uri = Uri.withAppendedPath(
|
||||
ContactsContract.CommonDataKinds.Email.CONTENT_LOOKUP_URI,
|
||||
Uri.encode(emailAddress.address),
|
||||
)
|
||||
return if (contactPermissionResolver.hasContactPermission()) {
|
||||
val uri = Uri.withAppendedPath(
|
||||
ContactsContract.CommonDataKinds.Email.CONTENT_LOOKUP_URI,
|
||||
Uri.encode(emailAddress.address),
|
||||
)
|
||||
|
||||
return if (hasContactPermission()) {
|
||||
contentResolver.query(
|
||||
uri,
|
||||
PROJECTION,
|
||||
|
@ -75,13 +71,6 @@ internal class ContentResolverContactDataSource(
|
|||
}
|
||||
}
|
||||
|
||||
private fun hasContactPermission(): Boolean {
|
||||
return ContextCompat.checkSelfPermission(
|
||||
context,
|
||||
Manifest.permission.READ_CONTACTS,
|
||||
) == PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
||||
private const val SORT_ORDER = ContactsContract.Contacts.DISPLAY_NAME +
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package app.k9mail.core.android.common.contact
|
||||
|
||||
import android.content.Context
|
||||
import app.k9mail.core.common.cache.Cache
|
||||
import app.k9mail.core.common.cache.ExpiringCache
|
||||
import app.k9mail.core.common.cache.SynchronizedCache
|
||||
|
@ -14,7 +15,10 @@ internal val contactModule = module {
|
|||
)
|
||||
}
|
||||
factory<ContactDataSource> {
|
||||
ContentResolverContactDataSource(context = get())
|
||||
ContentResolverContactDataSource(
|
||||
contentResolver = get<Context>().contentResolver,
|
||||
contactPermissionResolver = get(),
|
||||
)
|
||||
}
|
||||
factory<ContactRepository> {
|
||||
CachingContactRepository(
|
||||
|
@ -22,6 +26,9 @@ internal val contactModule = module {
|
|||
dataSource = get(),
|
||||
)
|
||||
}
|
||||
factory<ContactPermissionResolver> {
|
||||
AndroidContactPermissionResolver(context = get())
|
||||
}
|
||||
}
|
||||
|
||||
internal const val CACHE_NAME = "ContactCache"
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
package app.k9mail.core.android.common.contact
|
||||
|
||||
import android.Manifest.permission.READ_CONTACTS
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager.PERMISSION_GRANTED
|
||||
import androidx.core.content.ContextCompat
|
||||
|
||||
interface ContactPermissionResolver {
|
||||
fun hasContactPermission(): Boolean
|
||||
}
|
||||
|
||||
internal class AndroidContactPermissionResolver(private val context: Context) : ContactPermissionResolver {
|
||||
override fun hasContactPermission(): Boolean {
|
||||
return ContextCompat.checkSelfPermission(context, READ_CONTACTS) == PERMISSION_GRANTED
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package app.k9mail.core.android.common.contact
|
||||
|
||||
import android.Manifest
|
||||
import assertk.assertThat
|
||||
import assertk.assertions.isFalse
|
||||
import assertk.assertions.isTrue
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.RuntimeEnvironment
|
||||
import org.robolectric.Shadows
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
class AndroidContactPermissionResolverTest {
|
||||
private val application = RuntimeEnvironment.getApplication()
|
||||
private val testSubject = AndroidContactPermissionResolver(context = application)
|
||||
|
||||
@Test
|
||||
fun `hasPermission() with contact permission`() {
|
||||
grantContactPermission()
|
||||
|
||||
val result = testSubject.hasContactPermission()
|
||||
|
||||
assertThat(result).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `hasPermission() without contact permission`() {
|
||||
denyContactPermission()
|
||||
|
||||
val result = testSubject.hasContactPermission()
|
||||
|
||||
assertThat(result).isFalse()
|
||||
}
|
||||
|
||||
private fun grantContactPermission() {
|
||||
Shadows.shadowOf(application).grantPermissions(Manifest.permission.READ_CONTACTS)
|
||||
}
|
||||
|
||||
private fun denyContactPermission() {
|
||||
Shadows.shadowOf(application).denyPermissions(Manifest.permission.READ_CONTACTS)
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
package app.k9mail.core.android.common.contact
|
||||
|
||||
import android.Manifest
|
||||
import android.content.ContentResolver
|
||||
import android.database.Cursor
|
||||
import android.database.MatrixCursor
|
||||
|
@ -12,7 +11,6 @@ import assertk.assertions.isFalse
|
|||
import assertk.assertions.isNull
|
||||
import assertk.assertions.isTrue
|
||||
import kotlin.test.Test
|
||||
import org.junit.Before
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.kotlin.anyOrNull
|
||||
import org.mockito.kotlin.doReturn
|
||||
|
@ -20,27 +18,20 @@ import org.mockito.kotlin.eq
|
|||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.stub
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.RuntimeEnvironment
|
||||
import org.robolectric.Shadows
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
internal class ContentResolverContactDataSourceTest {
|
||||
|
||||
private val contactPermissionResolver = TestContactPermissionResolver(hasPermission = true)
|
||||
private val contentResolver = mock<ContentResolver>()
|
||||
|
||||
private val testSubject = ContentResolverContactDataSource(
|
||||
context = RuntimeEnvironment.getApplication(),
|
||||
contentResolver = contentResolver,
|
||||
contactPermissionResolver = contactPermissionResolver,
|
||||
)
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
Shadows.shadowOf(RuntimeEnvironment.getApplication()).grantPermissions(Manifest.permission.READ_CONTACTS)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getContactForEmail() returns null if permission is not granted`() {
|
||||
Shadows.shadowOf(RuntimeEnvironment.getApplication()).denyPermissions(Manifest.permission.READ_CONTACTS)
|
||||
contactPermissionResolver.hasContactPermission = false
|
||||
|
||||
val result = testSubject.getContactFor(CONTACT_EMAIL_ADDRESS)
|
||||
|
||||
|
@ -67,7 +58,7 @@ internal class ContentResolverContactDataSourceTest {
|
|||
|
||||
@Test
|
||||
fun `hasContactForEmail() returns false if permission is not granted`() {
|
||||
Shadows.shadowOf(RuntimeEnvironment.getApplication()).denyPermissions(Manifest.permission.READ_CONTACTS)
|
||||
contactPermissionResolver.hasContactPermission = false
|
||||
|
||||
val result = testSubject.hasContactFor(CONTACT_EMAIL_ADDRESS)
|
||||
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package app.k9mail.core.android.common.contact
|
||||
|
||||
class TestContactPermissionResolver(hasPermission: Boolean) : ContactPermissionResolver {
|
||||
var hasContactPermission = hasPermission
|
||||
|
||||
override fun hasContactPermission(): Boolean {
|
||||
return hasContactPermission
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue