Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initialize the project #1

Merged
merged 2 commits into from
Jan 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
3 changes: 3 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/compiler.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 21 additions & 0 deletions .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
# ServiceBase
# ServiceBase
This is a base library in order to use by other libraries which need to implement AIDL and BroadCast connection with Bazaar client.
1 change: 1 addition & 0 deletions ServiceBase/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
45 changes: 45 additions & 0 deletions ServiceBase/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
plugins {
id 'com.android.library'
id 'kotlin-android'
id 'maven-publish'
}

android {
compileSdk 30
buildToolsVersion '31.0.0'

defaultConfig {
minSdk 17
targetSdk 30
versionCode 1
versionName "1.0"

}

buildTypes {
release {
minifyEnabled false
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}

dependencies {
implementation "androidx.core:core-ktx:1.6.0"
}

afterEvaluate {
publishing {
publications {
release(MavenPublication) {
from components.release
}
}
}
}
2 changes: 2 additions & 0 deletions ServiceBase/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.cafebazaar.servicebase" />
165 changes: 165 additions & 0 deletions ServiceBase/src/main/java/com/cafebazaar/servicebase/Client.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
package com.cafebazaar.servicebase

import android.content.Context
import android.os.Looper
import com.cafebazaar.servicebase.communicator.ClientConnectionCommunicator
import com.cafebazaar.servicebase.communicator.ClientReceiverCommunicator
import com.cafebazaar.servicebase.receiver.ClientReceiver
import com.cafebazaar.servicebase.state.ClientError
import com.cafebazaar.servicebase.state.ClientStateListener

abstract class Client(private val context: Context) {

private var clientStateListener: ClientStateListener? = null

protected abstract val supportedClientVersion: Long
protected abstract fun getServiceConnection(): ClientConnectionCommunicator?
protected abstract fun getBroadcastConnections(): ClientConnectionCommunicator?

@Volatile private var clientState = DISCONNECTED
@Volatile protected var clientConnection: ClientConnectionCommunicator? = null

private val isReady: Boolean
get() = (clientState == CONNECTED)
.and(clientConnection != null)

fun startConnection(clientStateListener: ClientStateListener) {
this.clientStateListener = clientStateListener
if (isNotBazaarInstalled(clientStateListener)) return
if (isNotBazaarCompatible(clientStateListener)) return
throwExceptionIfRunningOnMainThread()
startingConnection(clientStateListener)
}

private fun isNotBazaarCompatible(clientStateListener: ClientStateListener): Boolean {
if (getBazaarVersionCode(context) < supportedClientVersion) {
handleErrorOnBazaarIsNotCompatible(clientStateListener)
return true
}
return false
}

private fun isNotBazaarInstalled(clientStateListener: ClientStateListener): Boolean {
if (verifyBazaarIsInstalled(context).not()) {
handleErrorOnBazaarIsNotInstalled(clientStateListener)
return true
}
return false
}

private fun handleErrorOnBazaarIsNotCompatible(clientStateListener: ClientStateListener) {
clientState = DISCONNECTED
clientStateListener.onError(
ClientError.ERROR_BAZAAR_IS_NOT_COMPATIBLE
)
}

private fun handleErrorOnBazaarIsNotInstalled(clientStateListener: ClientStateListener) {
clientState = DISCONNECTED
clientStateListener.onError(
ClientError.ERROR_BAZAAR_IS_NOT_INSTALL
)
}

private fun startingConnection(clientStateListener: ClientStateListener) {
if (isReady.not()) {
if (clientState == CONNECTING) {
clientStateListener.onError(
ClientError.ERROR_SDK_IS_STARTED
)
return
}
tryToConnect(clientStateListener)
} else {
clientStateListener.onReady()
}
}

private fun tryToConnect(clientStateListener: ClientStateListener) {
clientState = CONNECTING
if (tryConnectingByService()) return
if (tryConnectingByBroadcast()) return
clientState = DISCONNECTED
clientStateListener.onError(
ClientError.ERROR_SDK_COULD_NOT_CONNECT
)
}

private fun tryConnectingByBroadcast(): Boolean {
getBroadcastConnections()?.let { connection ->
if (connection is ClientReceiverCommunicator) {
ClientReceiver.addObserver(connection)
}
if (connection.startConnection()) {
clientConnection = connection
updateClientStateToConnected()
return true
}
}
return false
}

private fun tryConnectingByService(): Boolean {
synchronized(this) {
getServiceConnection()?.let { connection ->
if (connection.startConnection()) {
clientConnection = connection
return true
}
}
return false
}
}

protected fun updateClientStateToConnected() {
synchronized(this) {
clientState = CONNECTED
clientStateListener?.onReady()
}
}

private fun throwExceptionIfRunningOnMainThread() {
if (Looper.myLooper() == Looper.getMainLooper()) {
throw IllegalThreadStateException(OFF_MAIN_THREAD_EXCEPTION)
}
}

fun endConnection() {
clientStateListener = null
clientConnection?.let { connection ->
if (connection is ClientReceiverCommunicator) {
ClientReceiver.removeObserver(connection)
}
connection.stopConnection()
}
clientState = DISCONNECTED
}

protected fun errorOccurred(clientError: ClientError) {
clientStateListener?.onError(clientError)
}

@Throws(IllegalStateException::class)
protected fun <T> runIfReady(block: () -> T?): T? {
if (isReady.not()) {
throw IllegalStateException(SERVICE_IS_NOT_STARTED_EXCEPTION)
} else {
return block.invoke()
}
}

private fun verifyBazaarIsInstalled(context: Context): Boolean {
return getBazaarPackageInfo(context) != null
}

companion object {
const val SERVICE_PACKAGE_NAME = "com.farsitel.bazaar"

private const val OFF_MAIN_THREAD_EXCEPTION = "This function has to call off the main thread."
private const val SERVICE_IS_NOT_STARTED_EXCEPTION =
"Service not connected. Please start a connection before using the service."
private const val DISCONNECTED = 0
private const val CONNECTING = 1
private const val CONNECTED = 2
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.cafebazaar.servicebase

import android.content.Context
import android.content.pm.PackageInfo
import android.os.Build

internal fun getBazaarPackageInfo(context: Context): PackageInfo? {
return try {
val packageManager = context.packageManager
packageManager.getPackageInfo(Client.SERVICE_PACKAGE_NAME, 0)
} catch (ignored: Exception) {
null
}
}

internal fun getBazaarVersionCode(context: Context) = getBazaarPackageInfo(context)?.let {
sdkAwareVersionCode(it)
} ?: 0L

internal fun sdkAwareVersionCode(packageInfo: PackageInfo): Long {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
packageInfo.longVersionCode
} else {
packageInfo.versionCode.toLong()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.cafebazaar.servicebase.communicator

interface ClientConnectionCommunicator {

fun startConnection(): Boolean

fun stopConnection()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.cafebazaar.servicebase.communicator

import android.content.Intent

interface ClientReceiverCommunicator {

fun onNewBroadcastReceived(intent: Intent?)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.cafebazaar.servicebase.receiver

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import com.cafebazaar.servicebase.communicator.ClientReceiverCommunicator

class ClientReceiver: BroadcastReceiver() {

override fun onReceive(context: Context?, intent: Intent?) {
intent?.let {
notifyObservers(it)
}
}

private fun notifyObservers(intent: Intent) {
synchronized(observerLock) {
for (observer in observers) {
observer.onNewBroadcastReceived(intent)
}
}
}

companion object {

private val observerLock = Any()
private val observers = mutableListOf<ClientReceiverCommunicator>()

fun addObserver(communicator: ClientReceiverCommunicator) {
synchronized(observerLock) {
observers.add(communicator)
}
}

fun removeObserver(communicator: ClientReceiverCommunicator) {
synchronized(observerLock) {
observers.remove(communicator)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.cafebazaar.servicebase.state

enum class ClientError(var message: String) {
ERROR_BAZAAR_IS_NOT_INSTALL("Bazaar Client Is Not Installed"),
ERROR_BAZAAR_IS_NOT_COMPATIBLE("Bazaar Client Is Not Compatible"),
ERROR_SDK_COULD_NOT_CONNECT("SDK Could Not Connect"),
ERROR_SDK_IS_STARTED("SDK Is Started"),
ERROR_DURING_GETTING_REFERRER_DETAILS("Error during getting referrer details"),
ERROR_DURING_CONSUMING_REFERRER("Error during consuming referrer")
}
Loading