Skip to content

Commit

Permalink
Merge pull request #6 from mroczis/master
Browse files Browse the repository at this point in the history
sync
  • Loading branch information
cedricf25 authored Mar 28, 2021
2 parents ba59945 + fc12298 commit 8bca0ff
Show file tree
Hide file tree
Showing 30 changed files with 329 additions and 104 deletions.
19 changes: 13 additions & 6 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 29
compileSdkVersion 30

defaultConfig {
applicationId "cz.mroczis.netmonster.sample"
minSdkVersion 14
targetSdkVersion 29
targetSdkVersion 30
versionCode 1
versionName "1.0"

Expand All @@ -21,14 +21,21 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}

}

dependencies {
implementation project(":library")
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core-ktx:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'com.google.android.material:material:1.1.0-beta02'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'com.google.android.material:material:1.3.0'
}
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
ext.kotlin_version = '1.3.72'
ext.kotlin_version = '1.4.31'
repositories {
google()
jcenter()

}
dependencies {
classpath 'com.android.tools.build:gradle:4.0.0'
classpath 'com.android.tools.build:gradle:4.1.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
Expand Down
4 changes: 2 additions & 2 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#Sat Jul 04 18:21:51 CEST 2020
#Wed Feb 17 22:16:22 CET 2021
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
2 changes: 1 addition & 1 deletion library/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ android {

dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.annotation:annotation:1.1.0'
implementation 'androidx.annotation:annotation:1.2.0'

testImplementation 'junit:junit:4.12'
testImplementation 'io.kotlintest:kotlintest-runner-junit5:3.3.2'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import cz.mroczis.netmonster.core.feature.detect.*
import cz.mroczis.netmonster.core.feature.config.*
import cz.mroczis.netmonster.core.feature.merge.CellSource
import cz.mroczis.netmonster.core.model.annotation.SinceSdk
import cz.mroczis.netmonster.core.model.annotation.TillSdk
import cz.mroczis.netmonster.core.model.cell.ICell
import cz.mroczis.netmonster.core.model.config.PhysicalChannelConfig
import cz.mroczis.netmonster.core.telephony.ITelephonyManagerCompat
Expand Down Expand Up @@ -103,7 +104,7 @@ interface INetMonster {
* Obtains synchronously currently active configurations for physical channel.
*
* This method is not publicly accessible in AOSP and can be used to detect multiple
* active active carriers when LTE is active.
* active carriers when LTE is active.
*
* Works since [Build.VERSION_CODES.P] on some phones. Look to [PhysicalChannelConfig] for
* more details.
Expand All @@ -116,6 +117,10 @@ interface INetMonster {
*/
@WorkerThread
@SinceSdk(Build.VERSION_CODES.P)
@TillSdk(
sdkInt = Build.VERSION_CODES.Q,
fallbackBehaviour = "Way to access this data was removed, expect empty list on Android Q+"
)
fun getPhysicalChannelConfiguration(subId: Int) : List<PhysicalChannelConfig>

}
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ internal class NetMonster(
DetectorLteAdvancedNrServiceState(),
DetectorLteAdvancedPhysicalChannel(),
DetectorLteAdvancedCellInfo(),
DetectorLteAdvancedNrDisplayInfo(),
DetectorAosp() // best to keep last when all other strategies fail
) ?: NetworkTypeTable.get(NetworkType.UNKNOWN)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ import cz.mroczis.netmonster.core.NetMonster
import cz.mroczis.netmonster.core.subscription.ISubscriptionManagerCompat
import cz.mroczis.netmonster.core.subscription.SubscriptionManagerCompat14
import cz.mroczis.netmonster.core.subscription.SubscriptionManagerCompat22
import cz.mroczis.netmonster.core.telephony.ITelephonyManagerCompat
import cz.mroczis.netmonster.core.telephony.*
import cz.mroczis.netmonster.core.telephony.TelephonyManagerCompat14
import cz.mroczis.netmonster.core.telephony.TelephonyManagerCompat17
import cz.mroczis.netmonster.core.telephony.TelephonyManagerCompat29
import cz.mroczis.netmonster.core.telephony.TelephonyManagerCompat30

/**
* Factory that produces new instances.
Expand All @@ -23,6 +24,7 @@ object NetMonsterFactory {
*/
fun getTelephony(context: Context, subId: Int = Integer.MAX_VALUE): ITelephonyManagerCompat =
when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> TelephonyManagerCompat30(context, subId)
Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> TelephonyManagerCompat29(context, subId)
Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 -> TelephonyManagerCompat17(context, subId)
else -> TelephonyManagerCompat14(context, subId)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package cz.mroczis.netmonster.core.feature.config

import android.Manifest
import android.os.Handler
import android.os.HandlerThread
import android.telephony.*
import android.telephony.CellLocation
import android.telephony.PhoneStateListener
import android.telephony.ServiceState
import android.telephony.TelephonyManager
import androidx.annotation.RequiresPermission
import cz.mroczis.netmonster.core.feature.config.CellLocationSource.CellLocationListener
import cz.mroczis.netmonster.core.util.PhoneStateListenerPort
import cz.mroczis.netmonster.core.util.Threads
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit

Expand All @@ -15,19 +18,6 @@ import java.util.concurrent.TimeUnit
*/
class CellLocationSource {

companion object {

/**
* Async executor so can await data from [CellLocationListener]
*/
private val asyncExecutor by lazy {
val thread = HandlerThread("CellLocationSource").apply {
start()
}
Handler(thread.looper)
}
}

/**
* Registers [CellLocationListener] and awaits data. After 100 milliseconds time outs if
* nothing is delivered.
Expand All @@ -44,11 +34,12 @@ class CellLocationSource {
val asyncLock = CountDownLatch(1)
var cellLocation: CellLocation? = null

asyncExecutor.post {
Threads.phoneStateListener.post {
// We'll receive callbacks on thread that created instance of [listener] by default.
// Async processing is required otherwise deadlock would arise cause we block
// original thread
listener = CellLocationListener(subId) {
telephonyManager.listen(this, PhoneStateListener.LISTEN_NONE)
cellLocation = it
asyncLock.countDown()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package cz.mroczis.netmonster.core.feature.config

import android.Manifest
import android.annotation.TargetApi
import android.os.Build
import android.telephony.PhoneStateListener
import android.telephony.TelephonyDisplayInfo
import android.telephony.TelephonyManager
import androidx.annotation.RequiresPermission
import cz.mroczis.netmonster.core.model.DisplayInfo
import cz.mroczis.netmonster.core.telephony.mapper.toDisplayInfo
import cz.mroczis.netmonster.core.util.PhoneStateListenerPort
import cz.mroczis.netmonster.core.util.Threads
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit

/**
* Attempts to fetch fresh [TelephonyDisplayInfo] using [DisplayInfoSource].
*/
@TargetApi(Build.VERSION_CODES.R)
class DisplayInfoSource {

/**
* Registers [DisplayInfoListener] and awaits data. After 100 milliseconds time outs if
* nothing is delivered.
*/
@RequiresPermission(Manifest.permission.READ_PHONE_STATE)
@Suppress("DEPRECATION")
fun get(telephonyManager: TelephonyManager, subId: Int?): DisplayInfo =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
getFresh(telephonyManager, subId)?.toDisplayInfo()
} else {
null
} ?: DisplayInfo()

@RequiresPermission(Manifest.permission.READ_PHONE_STATE)
private fun getFresh(telephonyManager: TelephonyManager, subId: Int?): TelephonyDisplayInfo? {
var listener: DisplayInfoListener? = null
val asyncLock = CountDownLatch(1)
var displayInfo: TelephonyDisplayInfo? = null

Threads.phoneStateListener.post {
// We'll receive callbacks on thread that created instance of [listener] by default.
// Async processing is required otherwise deadlock would arise cause we block
// original thread
listener = DisplayInfoListener(subId) {
telephonyManager.listen(this, PhoneStateListener.LISTEN_NONE)
displayInfo = it
asyncLock.countDown()
}

telephonyManager.listen(listener, PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED)
}

// And we also must block original thread
// It'll get unblocked once we receive required data
// This usually takes +/- 20 ms to complete
try {
asyncLock.await(100, TimeUnit.MILLISECONDS)
} catch (e: InterruptedException) {
// System was not able to deliver PhysicalChannelConfig in this time slot
}

listener?.let { telephonyManager.listen(it, PhoneStateListener.LISTEN_NONE) }

return displayInfo
}


/**
* Kotlin friendly PhoneStateListener that grabs [TelephonyDisplayInfo]
*/
@TargetApi(Build.VERSION_CODES.R)
private class DisplayInfoListener(
subId: Int?,
private val displayInfoListener: DisplayInfoListener.(info: TelephonyDisplayInfo) -> Unit
) : PhoneStateListenerPort(subId) {

@RequiresPermission(Manifest.permission.READ_PHONE_STATE)
override fun onDisplayInfoChanged(telephonyDisplayInfo: TelephonyDisplayInfo) {
super.onDisplayInfoChanged(telephonyDisplayInfo)
displayInfoListener.invoke(this, telephonyDisplayInfo)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package cz.mroczis.netmonster.core.feature.config

import android.os.Build
import android.os.Handler
import android.os.HandlerThread
import android.telephony.PhoneStateListener
import android.telephony.TelephonyManager
import cz.mroczis.netmonster.core.model.config.PhysicalChannelConfig
import cz.mroczis.netmonster.core.util.PhoneStateListenerPort
import cz.mroczis.netmonster.core.util.Threads
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit

Expand All @@ -22,16 +21,6 @@ class PhysicalChannelConfigSource {
companion object {
// Copied from SDK, this field is currently hidden
const val LISTEN_PHYSICAL_CHANNEL_CONFIGURATION = 0x00100000

/**
* Async executor so can await data from [PhysicalChannelListener]
*/
private val asyncExecutor by lazy {
val thread = HandlerThread("PhysicalChannelConfigSource").apply {
start()
}
Handler(thread.looper)
}
}

/**
Expand All @@ -44,11 +33,12 @@ class PhysicalChannelConfigSource {
var config: List<PhysicalChannelConfig>? = null
val asyncLock = CountDownLatch(1)

asyncExecutor.post {
Threads.phoneStateListener.post {
// We'll receive callbacks on thread that created instance of [listener] by default.
// Async processing is required otherwise deadlock would arise cause we block
// original thread
listener = PhysicalChannelListener(subId) {
telephonyManager.listen(this, PhoneStateListener.LISTEN_NONE)
config = it
asyncLock.countDown()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@ package cz.mroczis.netmonster.core.feature.config

import android.Manifest
import android.os.Build
import android.os.Handler
import android.os.HandlerThread
import android.telephony.PhoneStateListener
import android.telephony.ServiceState
import android.telephony.TelephonyManager
import androidx.annotation.RequiresPermission
import cz.mroczis.netmonster.core.feature.config.ServiceStateSource.ServiceStateListener
import cz.mroczis.netmonster.core.util.PhoneStateListenerPort
import cz.mroczis.netmonster.core.util.Threads
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit

Expand All @@ -19,19 +18,6 @@ import java.util.concurrent.TimeUnit
*/
class ServiceStateSource {

companion object {

/**
* Async executor so can await data from [ServiceStateListener]
*/
private val asyncExecutor by lazy {
val thread = HandlerThread("ServiceStateSource").apply {
start()
}
Handler(thread.looper)
}
}

/**
* Registers [ServiceStateListener] and awaits data. After 100 milliseconds time outs if
* nothing is delivered.
Expand All @@ -56,11 +42,12 @@ class ServiceStateSource {
val asyncLock = CountDownLatch(1)
var simState: ServiceState? = null

asyncExecutor.post {
Threads.phoneStateListener.post {
// We'll receive callbacks on thread that created instance of [listener] by default.
// Async processing is required otherwise deadlock would arise cause we block
// original thread
listener = ServiceStateListener(subId) {
telephonyManager.listen(this, PhoneStateListener.LISTEN_NONE)
simState = it
asyncLock.countDown()
}
Expand Down
Loading

0 comments on commit 8bca0ff

Please sign in to comment.