Skip to content
This repository has been archived by the owner on Sep 3, 2023. It is now read-only.

Commit

Permalink
Version 1.0.1
Browse files Browse the repository at this point in the history
  • Loading branch information
afollestad committed Aug 17, 2018
1 parent 5d5853f commit 670c565
Show file tree
Hide file tree
Showing 9 changed files with 422 additions and 21 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Add this to your module's `build.gradle` file:
```gradle
dependencies {
implementation 'com.afollestad:assent:1.0.0'
implementation 'com.afollestad:assent:1.0.1'
}
```

Expand Down
9 changes: 7 additions & 2 deletions dependencies.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@ ext.versions = [
minSdk : 14,
compileSdk : 28,
buildTools : '28.0.1',
publishVersion : '1.0.0',
publishVersionCode: 10,
publishVersion : '1.0.1',
publishVersionCode: 11,

gradlePlugin : '3.1.4',
spotlessPlugin : '3.14.0',
versionPlugin : '0.20.0',
kotlin : '1.2.60',
bintrayPlugin : '0.8.1',

junit : '4.12',
assertj : '3.11.0',
mockitoCore : '2.7.5',
mockitoKotlin : '2.0.0-RC1',

supportLib : '28.0.0-rc01'
]
6 changes: 6 additions & 0 deletions library/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,19 @@ android {
targetSdkVersion versions.compileSdk
versionCode versions.publishVersionCode
versionName versions.publishVersion
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
}

dependencies {
implementation 'com.android.support:support-annotations:' + versions.supportLib
implementation 'com.android.support:appcompat-v7:' + versions.supportLib
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:' + versions.kotlin

testImplementation 'junit:junit:' + versions.junit
testImplementation 'org.assertj:assertj-core:' + versions.assertj
testImplementation 'org.mockito:mockito-core:' + versions.mockitoCore
testImplementation 'com.nhaarman.mockitokotlin2:mockito-kotlin:' + versions.mockitoKotlin
}

apply from: '../spotless.gradle'
53 changes: 36 additions & 17 deletions library/src/main/java/com/afollestad/assent/Assent.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,30 +17,33 @@ import android.support.v4.app.Fragment
import android.support.v4.content.ContextCompat.checkSelfPermission
import android.util.Log

typealias Callback = (AssentResult) -> Unit
typealias Callback = (result: AssentResult) -> Unit

internal typealias RequestExecutor = (request: PendingRequest) -> Unit

/** @author Aidan Follestad (afollestad) */
class Assent private constructor() {

private var activity: Activity? = null
private var fragment: Fragment? = null
private val context: Context
internal var activity: Activity? = null
internal var fragment: Fragment? = null
internal val context: Context
get() = when {
activity != null -> activity!!
fragment != null -> fragment!!.activity!!
else ->
throw IllegalStateException("No Activity of Fragment was set.")
}
private val requestQueue: MutableList<PendingRequest> = mutableListOf()
private var currentPendingRequest: PendingRequest? = null

internal val requestQueue = Queue<PendingRequest>()
internal var currentPendingRequest: PendingRequest? = null

companion object {

private val LOCK = Any()

@SuppressLint("StaticFieldLeak")
private var instance: Assent? = null
private val safeInstance: Assent
internal val safeInstance: Assent
get() {
if (instance == null)
instance = Assent()
Expand All @@ -65,16 +68,16 @@ class Assent private constructor() {

@JvmStatic fun setFragment(
caller: Fragment,
activity: Fragment?
fragment: Fragment?
) {
if (activity == null) {
if (fragment == null) {
val current = safeInstance.fragment
if (current != null && caller == current) {
// The caller is nullifying itself
safeInstance.fragment = null
}
} else {
safeInstance.fragment = activity
safeInstance.fragment = fragment
safeInstance.activity = null
}
}
Expand All @@ -90,7 +93,6 @@ class Assent private constructor() {
requestCode: Int = 69,
callback: Callback
) = synchronized(LOCK) {

val currentRequest = safeInstance.currentPendingRequest
if (currentRequest != null &&
currentRequest.permissions.contentEquals(permissions)
Expand All @@ -110,10 +112,13 @@ class Assent private constructor() {
if (currentRequest == null) {
// There is no active request so we can execute immediately
safeInstance.currentPendingRequest = newPendingRequest
executeRequest(newPendingRequest)
requestExecutor(newPendingRequest)
} else {
// There is an active request, append this new one to the queue
safeInstance.requestQueue.add(newPendingRequest)
if (currentRequest.requestCode == requestCode) {
newPendingRequest.requestCode = requestCode + 1
}
safeInstance.requestQueue += newPendingRequest
}
}

Expand Down Expand Up @@ -158,13 +163,27 @@ class Assent private constructor() {

if (safeInstance.requestQueue.isNotEmpty()) {
// Execute the next request in the queue
safeInstance.currentPendingRequest = safeInstance.requestQueue[0]
safeInstance.requestQueue.removeAt(0)
executeRequest(safeInstance.currentPendingRequest!!)
safeInstance.currentPendingRequest = safeInstance.requestQueue.pop()
requestExecutor(safeInstance.currentPendingRequest!!)
}
}

private fun executeRequest(request: PendingRequest) {
fun destroy() {
if (instance != null) {
with(instance!!) {
activity = null
fragment = null
currentPendingRequest = null
requestQueue.clear()
}
instance = null
}
}

/** Allows us to override in unit tests. */
internal var requestExecutor: RequestExecutor = this::defaultRequestExecutor

private fun defaultRequestExecutor(request: PendingRequest) {
when {
safeInstance.fragment != null ->
safeInstance.fragment!!.requestPermissions(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ package com.afollestad.assent
/** @author Aidan Follestad (afollestad) */
internal data class PendingRequest(
val permissions: Array<Permission>,
val requestCode: Int,
var requestCode: Int,
val callbacks: MutableList<Callback>
) {
override fun hashCode(): Int {
Expand Down
35 changes: 35 additions & 0 deletions library/src/main/java/com/afollestad/assent/Queue.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Licensed under Apache-2.0
*
* Designed an developed by Aidan Follestad (afollestad)
*/

package com.afollestad.assent

/** @author Aidan Follestad (afollestad) */
internal class Queue<T> {

private var data: MutableList<T> = mutableListOf()

fun push(item: T) = data.add(item)

fun poll() = if (data.isNotEmpty()) data[0] else null

fun pop(): T {
val result = poll() ?: throw IllegalStateException("Queue is empty, cannot pop.")
data.removeAt(0)
return result
}

fun size() = data.size

fun isEmpty() = data.isEmpty()

fun isNotEmpty() = data.isNotEmpty()

fun clear() = data.clear()

operator fun plusAssign(item: T) {
push(item)
}
}
57 changes: 57 additions & 0 deletions library/src/test/java/com/afollestad/assent/AssentResultTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.afollestad.assent

import android.content.pm.PackageManager.PERMISSION_DENIED
import android.content.pm.PackageManager.PERMISSION_GRANTED
import com.afollestad.assent.Permission.ACCESS_COARSE_LOCATION
import com.afollestad.assent.Permission.CALL_PHONE
import com.afollestad.assent.Permission.WRITE_EXTERNAL_STORAGE
import org.assertj.core.api.Java6Assertions.assertThat
import org.junit.Test

class AssentResultTest {

private val result = AssentResult(
arrayOf(WRITE_EXTERNAL_STORAGE, ACCESS_COARSE_LOCATION),
intArrayOf(PERMISSION_GRANTED, PERMISSION_DENIED)
)

@Test
fun containsPermission_true() {
assertThat(result.containsPermissions(WRITE_EXTERNAL_STORAGE)).isTrue()
}

@Test
fun containsPermission_false() {
assertThat(result.containsPermissions(CALL_PHONE)).isFalse()
}

@Test
fun isAllGranted_true() {
assertThat(result.isAllGranted(WRITE_EXTERNAL_STORAGE)).isTrue()
}

@Test
fun isAllGranted_false_denied() {
assertThat(result.isAllGranted(ACCESS_COARSE_LOCATION)).isFalse()
}

@Test(expected = IllegalArgumentException::class)
fun isAllGranted_throws_notInSet() {
result.isAllGranted(CALL_PHONE)
}

@Test
fun isAllDenied_true() {
assertThat(result.isAllDenied(ACCESS_COARSE_LOCATION)).isTrue()
}

@Test
fun isAllDenied_false_granted() {
assertThat(result.isAllDenied(WRITE_EXTERNAL_STORAGE)).isFalse()
}

@Test(expected = IllegalArgumentException::class)
fun isAllDenied_throws_notInSet() {
assertThat(result.isAllDenied(CALL_PHONE)).isFalse()
}
}
Loading

0 comments on commit 670c565

Please sign in to comment.