mirror of
https://github.com/AU-COVIDSafe/mobile-android.git
synced 2025-01-18 08:46:35 +00:00
COVIDSafe code from version 1.11.0 (#26)
This commit is contained in:
parent
12c06add12
commit
ae18438d17
139 changed files with 8039 additions and 6010 deletions
|
@ -1,19 +1,14 @@
|
|||
apply plugin: 'com.android.application'
|
||||
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
|
||||
apply plugin: 'kotlin-kapt'
|
||||
|
||||
apply plugin: "androidx.navigation.safeargs.kotlin"
|
||||
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
google()
|
||||
|
||||
jcenter()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,26 +22,22 @@ def getGitHash = { ->
|
|||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
buildToolsVersion "29.0.3"
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
buildToolsVersion rootProject.ext.buildToolsVersion
|
||||
|
||||
defaultConfig {
|
||||
applicationId "au.gov.health.covidsafe"
|
||||
minSdkVersion 21
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
/*
|
||||
TargetSdk is currently set to 28 because we are using a greylisted api in SDK 29, in order to fix a BLE vulnerability
|
||||
Before you increase the targetSdkVersion make sure that all its usage are still working
|
||||
*/
|
||||
targetSdkVersion 28
|
||||
versionCode 54
|
||||
versionName "1.0.54"
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 72
|
||||
versionName "1.11.0"
|
||||
buildConfigField "String", "GITHASH", "\"${getGitHash()}\""
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
|
||||
javaCompileOptions {
|
||||
annotationProcessorOptions {
|
||||
arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
|
||||
|
@ -107,7 +98,7 @@ android {
|
|||
String ssid = STAGING_SERVICE_UUID
|
||||
versionNameSuffix "-debug-${getGitHash()}-${ssid.substring(ssid.length() - 5, ssid.length() - 1)}"
|
||||
resValue "string", "app_name", "COVIDSafe Debug"
|
||||
applicationIdSuffix "debug"
|
||||
applicationIdSuffix ".debug"
|
||||
signingConfig signingConfigs.debug
|
||||
}
|
||||
|
||||
|
@ -119,15 +110,12 @@ android {
|
|||
buildConfigField "String", "IOS_BACKGROUND_UUID", STAGING_BACKGROUND_IOS_SERVICE_UUID
|
||||
buildConfigField "String", "ENCRYPTION_PUBLIC_KEY", STAGING_ENCRYPTION_PUBLIC_KEY
|
||||
|
||||
|
||||
|
||||
|
||||
// Retrieve bluetooth ssid from staging's strings.xml
|
||||
String ssid = STAGING_SERVICE_UUID
|
||||
versionNameSuffix "-beta-${getGitHash()}-${ssid.substring(ssid.length() - 5, ssid.length() - 1)}"
|
||||
debuggable false
|
||||
|
||||
applicationIdSuffix "beta"
|
||||
applicationIdSuffix ".beta"
|
||||
resValue "string", "app_name", "COVIDSafe beta"
|
||||
|
||||
lintOptions {
|
||||
|
@ -137,6 +125,7 @@ android {
|
|||
matchingFallbacks = ['release']
|
||||
signingConfig signingConfigs.staging
|
||||
}
|
||||
|
||||
release {
|
||||
|
||||
buildConfigField "String", "BLE_SSID", PRODUCTION_SERVICE_UUID
|
||||
|
@ -145,8 +134,6 @@ android {
|
|||
buildConfigField "String", "IOS_BACKGROUND_UUID", PRODUCTION_BACKGROUND_IOS_SERVICE_UUID
|
||||
buildConfigField "String", "ENCRYPTION_PUBLIC_KEY", PRODUCTION_ENCRYPTION_PUBLIC_KEY
|
||||
|
||||
|
||||
|
||||
debuggable false
|
||||
jniDebuggable false
|
||||
renderscriptDebuggable false
|
||||
|
@ -161,10 +148,13 @@ android {
|
|||
abortOnError false
|
||||
}
|
||||
signingConfig signingConfigs.release
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
dataBinding true
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
staging {
|
||||
java.srcDirs = ['src/debug/java']
|
||||
|
@ -185,45 +175,31 @@ android {
|
|||
packagingOptions {
|
||||
exclude 'META-INF/atomicfu.kotlin_module'
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
|
||||
implementation project(":feedback-android")
|
||||
// kotlin
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
def kotlin_coroutines_version = "1.3.5"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
|
||||
|
||||
//androidx
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.1.0'
|
||||
implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0"
|
||||
|
||||
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
|
||||
|
||||
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.1.0-alpha01'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||
implementation 'pub.devrel:easypermissions:3.0.0'
|
||||
implementation 'com.google.code.gson:gson:2.8.6'
|
||||
testImplementation 'junit:junit:4.13'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||
|
||||
// room
|
||||
def room_version = "2.2.5"
|
||||
kapt "androidx.room:room-compiler:$room_version"
|
||||
implementation "androidx.room:room-runtime:$room_version"
|
||||
implementation "androidx.room:room-ktx:$room_version"
|
||||
|
||||
// http
|
||||
implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
|
||||
implementation "com.squareup.retrofit2:converter-gson:$retrofit_version"
|
||||
implementation "com.squareup.okhttp3:okhttp:$okhttp_version"
|
||||
implementation "com.squareup.okhttp3:logging-interceptor:$okhttp_version"
|
||||
|
||||
// rx
|
||||
|
@ -233,11 +209,10 @@ dependencies {
|
|||
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.0'
|
||||
implementation 'androidx.navigation:navigation-ui-ktx:2.3.0'
|
||||
|
||||
//cardview
|
||||
implementation 'androidx.cardview:cardview:1.0.0'
|
||||
implementation "androidx.swiperefreshlayout:swiperefreshlayout:$androidx_swiperefreshlayout_version"
|
||||
|
||||
//Lottie
|
||||
implementation 'com.airbnb.android:lottie:3.4.0'
|
||||
implementation 'com.airbnb.android:lottie:3.4.1'
|
||||
|
||||
implementation 'com.google.guava:guava:28.2-android'
|
||||
implementation "androidx.collection:collection:1.1.0"
|
||||
|
@ -251,7 +226,9 @@ dependencies {
|
|||
// Firebase Cloud Messaging
|
||||
implementation 'com.google.firebase:firebase-messaging:20.2.4'
|
||||
|
||||
//Unit testing
|
||||
testImplementation 'junit:junit:4.13'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
|
||||
androidTestImplementation "androidx.room:room-testing:2.2.5"
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
package="au.gov.health.covidsafe">
|
||||
|
||||
<application
|
||||
android:name=".TracerApp"
|
||||
android:name=".app.TracerApp"
|
||||
android:allowBackup="false"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
|
|
|
@ -12,14 +12,18 @@ import androidx.lifecycle.ViewModelProvider
|
|||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import au.gov.health.covidsafe.extensions.fromHtml
|
||||
import au.gov.health.covidsafe.logging.CentralLog
|
||||
import au.gov.health.covidsafe.preference.Preference
|
||||
import au.gov.health.covidsafe.streetpass.persistence.StreetPassRecordStorage
|
||||
import au.gov.health.covidsafe.streetpass.view.RecordViewModel
|
||||
import au.gov.health.covidsafe.ui.utils.Utils
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import kotlinx.android.synthetic.main.database_peek.*
|
||||
import kotlinx.android.synthetic.main.database_peek.home_push_notification_token
|
||||
import java.io.File
|
||||
|
||||
private const val TAG = "PeekActivity"
|
||||
|
@ -72,7 +76,7 @@ class PeekActivity : AppCompatActivity() {
|
|||
.setTitle("Are you sure?")
|
||||
.setCancelable(false)
|
||||
.setMessage("Deleting the DB records is irreversible")
|
||||
.setPositiveButton("DELETE") { dialog, which ->
|
||||
.setPositiveButton("DELETE") { dialog, _ ->
|
||||
Observable.create<Boolean> {
|
||||
StreetPassRecordStorage(this).nukeDb()
|
||||
it.onNext(true)
|
||||
|
@ -87,7 +91,7 @@ class PeekActivity : AppCompatActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
.setNegativeButton("DON'T DELETE") { dialog, which ->
|
||||
.setNegativeButton("DON'T DELETE") { dialog, _ ->
|
||||
view.isEnabled = true
|
||||
dialog.cancel()
|
||||
}
|
||||
|
@ -123,6 +127,8 @@ class PeekActivity : AppCompatActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
showPushTokenOnDebugBuild()
|
||||
|
||||
if (!BuildConfig.DEBUG) {
|
||||
start.visibility = View.GONE
|
||||
stop.visibility = View.GONE
|
||||
|
@ -131,6 +137,20 @@ class PeekActivity : AppCompatActivity() {
|
|||
|
||||
}
|
||||
|
||||
private fun showPushTokenOnDebugBuild() {
|
||||
if (BuildConfig.DEBUG) {
|
||||
val token = Preference.getFirebaseInstanceID(this)
|
||||
home_push_notification_token.run {
|
||||
visibility = View.VISIBLE
|
||||
val tokenText = "<b>Firebase Push Token:</b> $token"
|
||||
text = fromHtml(tokenText)
|
||||
}
|
||||
|
||||
} else {
|
||||
home_push_notification_token.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
private var timePeriod: Int = 0
|
||||
|
||||
private fun nextTimePeriod(): Int {
|
||||
|
|
|
@ -8,6 +8,7 @@ import android.widget.TextView
|
|||
import androidx.recyclerview.widget.RecyclerView
|
||||
import au.gov.health.covidsafe.streetpass.persistence.StreetPassRecord
|
||||
import au.gov.health.covidsafe.streetpass.view.StreetPassRecordViewModel
|
||||
import au.gov.health.covidsafe.ui.utils.Utils
|
||||
|
||||
|
||||
class RecordListAdapter internal constructor(context: Context) :
|
|
@ -19,7 +19,7 @@
|
|||
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
||||
|
||||
<application
|
||||
android:name="au.gov.health.covidsafe.TracerApp"
|
||||
android:name="au.gov.health.covidsafe.app.TracerApp"
|
||||
android:allowBackup="false"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
|
@ -30,7 +30,7 @@
|
|||
tools:replace="android:supportsRtl">
|
||||
|
||||
<activity
|
||||
android:name="au.gov.health.covidsafe.SplashActivity"
|
||||
android:name="au.gov.health.covidsafe.ui.splash.SplashActivity"
|
||||
android:configChanges="keyboardHidden">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
@ -47,9 +47,9 @@
|
|||
|
||||
android:windowSoftInputMode="adjustPan" />
|
||||
|
||||
<activity android:name="au.gov.health.covidsafe.WebViewActivity" />
|
||||
<activity android:name="au.gov.health.covidsafe.DeviceNameChangePromptActivity" />
|
||||
<activity android:name="au.gov.health.covidsafe.InternetConnectionIssuesActivity" />
|
||||
<activity android:name="au.gov.health.covidsafe.ui.webview.WebViewActivity" />
|
||||
<activity android:name="au.gov.health.covidsafe.ui.devicename.DeviceNameChangePromptActivity" />
|
||||
<activity android:name="au.gov.health.covidsafe.ui.connection.InternetConnectionIssuesActivity" />
|
||||
|
||||
<activity
|
||||
android:name="au.gov.health.covidsafe.HomeActivity"
|
||||
|
@ -57,6 +57,10 @@
|
|||
android:windowSoftInputMode="adjustPan">
|
||||
<intent-filter>
|
||||
<action android:name="au.gov.health.covidsafe.UPGRADE_APP" />
|
||||
<action android:name="au.gov.health.covidsafe.POSSIBLE_ISSUE" />
|
||||
<action android:name="au.gov.health.covidsafe.NO_CHECKIN" />
|
||||
<action android:name="au.gov.health.covidsafe.POSSIBLE_ENCOUNTER_ERROR" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
@ -72,8 +76,6 @@
|
|||
android:name="au.gov.health.covidsafe.services.BluetoothMonitoringService"
|
||||
android:foregroundServiceType="location" />
|
||||
|
||||
<service android:name="au.gov.health.covidsafe.services.SensorMonitoringService" />
|
||||
|
||||
<receiver android:name="au.gov.health.covidsafe.receivers.UpgradeReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
|
||||
|
@ -83,7 +85,7 @@
|
|||
<receiver android:name="au.gov.health.covidsafe.receivers.PrivacyCleanerReceiver" />
|
||||
|
||||
<service
|
||||
android:name="au.gov.health.covidsafe.services.CovidFirebaseMessagingService"
|
||||
android:name="au.gov.health.covidsafe.notifications.CovidFirebaseMessagingService"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.firebase.MESSAGING_EVENT" />
|
||||
|
@ -92,8 +94,8 @@
|
|||
|
||||
<service
|
||||
android:name="au.gov.health.covidsafe.scheduler.GetMessagesJobSchedulerService"
|
||||
android:permission="android.permission.BIND_JOB_SERVICE"
|
||||
android:exported="true"/>
|
||||
android:exported="true"
|
||||
android:permission="android.permission.BIND_JOB_SERVICE" />
|
||||
|
||||
</application>
|
||||
|
||||
|
|
|
@ -3,22 +3,94 @@ package au.gov.health.covidsafe
|
|||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import au.gov.health.covidsafe.Utils.checkInternetConnectionToGoogle
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import au.gov.health.covidsafe.app.TracerApp
|
||||
import au.gov.health.covidsafe.logging.CentralLog
|
||||
import au.gov.health.covidsafe.networking.response.Message
|
||||
import au.gov.health.covidsafe.networking.response.MessagesResponse
|
||||
import au.gov.health.covidsafe.notifications.NotificationBuilder
|
||||
import au.gov.health.covidsafe.preference.Preference
|
||||
import au.gov.health.covidsafe.scheduler.GetMessagesScheduler
|
||||
import au.gov.health.covidsafe.ui.home.HomeFragment
|
||||
import au.gov.health.covidsafe.ui.devicename.DeviceNameChangePromptActivity
|
||||
import au.gov.health.covidsafe.ui.utils.Utils
|
||||
import au.gov.health.covidsafe.utils.NetworkConnectionCheck
|
||||
import com.google.android.gms.tasks.OnCompleteListener
|
||||
import com.google.firebase.iid.FirebaseInstanceId
|
||||
|
||||
private const val TAG = "HomeActivity"
|
||||
|
||||
class HomeActivity : FragmentActivity() {
|
||||
private fun checkInternetConnection() {
|
||||
checkInternetConnectionToGoogle {
|
||||
HomeFragment.instanceWeakRef?.get()?.updateConnectionTile(it)
|
||||
class HomeActivity : FragmentActivity(), NetworkConnectionCheck.NetworkConnectionListener {
|
||||
|
||||
var isAppUpdateAvailableLiveData = MutableLiveData<Boolean>()
|
||||
var appUpdateAvailableMessageResponseLiveData = MutableLiveData<MessagesResponse>()
|
||||
var isWindowFocusChangeLiveData = MutableLiveData<Boolean>()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
CentralLog.d(TAG, "onCreate() intent.action = ${intent.action}")
|
||||
NotificationBuilder.clearPossibleIssueNotificationCheck()
|
||||
NotificationBuilder.handlePushNotification(this, intent.action)
|
||||
|
||||
setContentView(R.layout.activity_home)
|
||||
|
||||
Utils.startBluetoothMonitoringService(this)
|
||||
|
||||
//Get Firebase Token
|
||||
getInstanceID()
|
||||
|
||||
NetworkConnectionCheck.addNetworkChangedListener(this, this)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
checkAndShowDeviceNameChangePrompt()
|
||||
checkAndUpdateHealthStatus()
|
||||
}
|
||||
|
||||
private fun checkAndShowDeviceNameChangePrompt() {
|
||||
if (!Preference.isDeviceNameChangePromptDisplayed(this)) {
|
||||
Intent(this, DeviceNameChangePromptActivity::class.java).also {
|
||||
startActivity(it)
|
||||
}
|
||||
Preference.setDeviceNameChangePromptDisplayed(this)
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkAndUpdateHealthStatus() {
|
||||
GetMessagesScheduler.scheduleGetMessagesJob {
|
||||
val isAppWithLatestVersion = it.messages.isNullOrEmpty()
|
||||
isAppUpdateAvailableLiveData.postValue(isAppWithLatestVersion)
|
||||
CentralLog.d(TAG, "isAppWithLatestVersion: $it")
|
||||
|
||||
if (!isAppWithLatestVersion) {
|
||||
val title = getString(R.string.update_available_title)
|
||||
val body = getString(R.string.update_available_message_android)
|
||||
|
||||
appUpdateAvailableMessageResponseLiveData.postValue(MessagesResponse(
|
||||
listOf(
|
||||
Message(
|
||||
title,
|
||||
body,
|
||||
"https://play.google.com/store/apps/details?id=au.gov.health.covidsafe")
|
||||
)
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNewIntent(intent: Intent?) {
|
||||
super.onNewIntent(intent)
|
||||
CentralLog.d(TAG, "onNewIntent = ${intent?.action})")
|
||||
NotificationBuilder.handlePushNotification(this, intent?.action)
|
||||
}
|
||||
|
||||
override fun onWindowFocusChanged(hasFocus: Boolean) {
|
||||
CentralLog.d(TAG, "onWindowFocusChanged(hasFocus = $hasFocus)")
|
||||
isWindowFocusChangeLiveData.postValue(hasFocus)
|
||||
|
||||
super.onWindowFocusChanged(hasFocus)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -46,76 +118,12 @@ class HomeActivity : FragmentActivity() {
|
|||
})
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
CentralLog.d(TAG, "onCreate() intent.action = ${intent.action}")
|
||||
|
||||
setContentView(R.layout.activity_home)
|
||||
|
||||
Utils.startBluetoothMonitoringService(this)
|
||||
|
||||
// messages API related
|
||||
getInstanceID()
|
||||
private var previousInternetConnection = true
|
||||
override fun onNetworkStatusChanged(isAvailable: Boolean) {
|
||||
if (!previousInternetConnection && isAvailable) {
|
||||
checkAndUpdateHealthStatus()
|
||||
}
|
||||
previousInternetConnection = isAvailable
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
CentralLog.d(TAG, "onResume() intent.action = ${intent.action}")
|
||||
|
||||
if (intent.action == "au.gov.health.covidsafe.UPGRADE_APP") {
|
||||
Utils.gotoPlayStore(this)
|
||||
}
|
||||
|
||||
if (!Preference.isDeviceNameChangePromptDisplayed(this)) {
|
||||
Intent(this, DeviceNameChangePromptActivity::class.java).also {
|
||||
startActivity(it)
|
||||
}
|
||||
|
||||
Preference.setDeviceNameChangePromptDisplayed(this)
|
||||
}
|
||||
|
||||
checkInternetConnection()
|
||||
|
||||
GetMessagesScheduler.scheduleGetMessagesJob {
|
||||
// HomeFragment.instanceWeakRef?.get()?.updateMessageTiles(it)
|
||||
|
||||
// HomeFragment.instanceWeakRef?.get()?.updateMessageTiles(MessagesResponse(
|
||||
// listOf(
|
||||
// Message(
|
||||
// "Update available",
|
||||
// "We’ve been making improvements to COVIDSafe. Update via Google Play Store.",
|
||||
// "market://details?id=au.gov.health.covidsafe"),
|
||||
// Message(
|
||||
// "Update available",
|
||||
// "We’ve been making improvements to COVIDSafe. Update via Google Play Store.",
|
||||
// "https://play.google.com/store/apps/details?id=au.gov.health.covidsafe")
|
||||
// )
|
||||
// ))
|
||||
|
||||
if (!it.messages.isNullOrEmpty()) {
|
||||
val title = getString(R.string.update_available_title)
|
||||
val body = getString(R.string.update_available_message_android)
|
||||
|
||||
HomeFragment.instanceWeakRef?.get()?.updateMessageTiles(MessagesResponse(
|
||||
listOf(
|
||||
Message(
|
||||
title,
|
||||
body,
|
||||
"https://play.google.com/store/apps/details?id=au.gov.health.covidsafe")
|
||||
)
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onWindowFocusChanged(hasFocus: Boolean) {
|
||||
CentralLog.d(TAG, "onWindowFocusChanged(hasFocus = $hasFocus)")
|
||||
|
||||
HomeFragment.instanceWeakRef?.get()?.refreshSetupCompleteOrIncompleteUi()
|
||||
checkInternetConnection()
|
||||
|
||||
super.onWindowFocusChanged(hasFocus)
|
||||
}
|
||||
}
|
|
@ -1,12 +1,12 @@
|
|||
package au.gov.health.covidsafe
|
||||
package au.gov.health.covidsafe.app
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import au.gov.health.covidsafe.BuildConfig
|
||||
import com.atlassian.mobilekit.module.feedback.FeedbackModule
|
||||
|
||||
import au.gov.health.covidsafe.logging.CentralLog
|
||||
import au.gov.health.covidsafe.scheduler.GetMessagesScheduler
|
||||
import au.gov.health.covidsafe.services.BluetoothMonitoringService
|
||||
import au.gov.health.covidsafe.streetpass.CentralDevice
|
||||
import au.gov.health.covidsafe.streetpass.PeripheralDevice
|
||||
|
@ -23,6 +23,7 @@ class TracerApp : Application() {
|
|||
|
||||
companion object {
|
||||
|
||||
|
||||
private const val TAG = "TracerApp"
|
||||
const val ORG = BuildConfig.ORG
|
||||
const val protocolVersion = BuildConfig.PROTOCOL_VERSION
|
|
@ -10,7 +10,7 @@ import android.os.ParcelUuid
|
|||
import android.util.Base64
|
||||
import android.util.Base64.decode
|
||||
import au.gov.health.covidsafe.BuildConfig
|
||||
import au.gov.health.covidsafe.Utils
|
||||
import au.gov.health.covidsafe.ui.utils.Utils
|
||||
import au.gov.health.covidsafe.bluetooth.BLEScanner.FilterConstant.APPLE_MANUFACTURER_ID
|
||||
import au.gov.health.covidsafe.bluetooth.BLEScanner.FilterConstant.BACKGROUND_IOS_SERVICE_UUID
|
||||
import au.gov.health.covidsafe.logging.CentralLog
|
||||
|
|
|
@ -4,8 +4,8 @@ import android.bluetooth.*
|
|||
import android.bluetooth.BluetoothGatt.GATT_FAILURE
|
||||
import android.bluetooth.BluetoothGatt.GATT_SUCCESS
|
||||
import android.content.Context
|
||||
import au.gov.health.covidsafe.TracerApp
|
||||
import au.gov.health.covidsafe.Utils
|
||||
import au.gov.health.covidsafe.app.TracerApp
|
||||
import au.gov.health.covidsafe.ui.utils.Utils
|
||||
import au.gov.health.covidsafe.logging.CentralLog
|
||||
import au.gov.health.covidsafe.streetpass.CentralDevice
|
||||
import au.gov.health.covidsafe.streetpass.ConnectionRecord
|
||||
|
@ -41,8 +41,7 @@ class GattServer constructor(val context: Context, serviceUUIDString: String) {
|
|||
BluetoothProfile.STATE_CONNECTED -> {
|
||||
CentralLog.i(TAG, "${device?.address} Connected to local GATT server")
|
||||
device?.let {
|
||||
val b = bluetoothManager.getConnectedDevices(BluetoothProfile.GATT)
|
||||
.contains(device)
|
||||
bluetoothManager.getConnectedDevices(BluetoothProfile.GATT).contains(device)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,23 +3,33 @@ package au.gov.health.covidsafe.boot
|
|||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import au.gov.health.covidsafe.Utils
|
||||
import au.gov.health.covidsafe.ui.utils.Utils
|
||||
import au.gov.health.covidsafe.logging.CentralLog
|
||||
import au.gov.health.covidsafe.scheduler.GetMessagesScheduler
|
||||
|
||||
private const val TAG = "StartOnBootReceiver"
|
||||
|
||||
class StartOnBootReceiver : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
|
||||
if (Intent.ACTION_BOOT_COMPLETED == intent.action) {
|
||||
CentralLog.d("StartOnBootReceiver", "boot completed received")
|
||||
CentralLog.d(TAG, "boot completed received")
|
||||
|
||||
try {
|
||||
CentralLog.d("StartOnBootReceiver", "Attempting to start service")
|
||||
Utils.scheduleStartMonitoringService(context, 500)
|
||||
checkAndUpdateHealthStatus()
|
||||
} catch (e: Throwable) {
|
||||
CentralLog.e("StartOnBootReceiver", e.localizedMessage)
|
||||
CentralLog.e(TAG, e.localizedMessage ?: "Error message is empty:")
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkAndUpdateHealthStatus() {
|
||||
GetMessagesScheduler.scheduleGetMessagesJob {
|
||||
CentralLog.d(TAG, "checkAndUpdateHealthStatus on app reboot completed ")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,10 +11,9 @@ import android.os.PowerManager
|
|||
import android.provider.Settings
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import au.gov.health.covidsafe.R
|
||||
import au.gov.health.covidsafe.Utils
|
||||
import au.gov.health.covidsafe.ui.utils.Utils
|
||||
import pub.devrel.easypermissions.EasyPermissions
|
||||
import pub.devrel.easypermissions.PermissionRequest
|
||||
|
||||
|
@ -62,6 +61,7 @@ private fun Fragment.requestFineLocationAndCheckBleSupportThenNextPermission(onE
|
|||
}
|
||||
} else {
|
||||
checkBLESupport()
|
||||
onEndCallback.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
package au.gov.health.covidsafe.extensions
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.text.Html
|
||||
import android.text.SpannableString
|
||||
import android.text.Spanned
|
||||
import android.text.style.URLSpan
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import au.gov.health.covidsafe.BuildConfig
|
||||
import au.gov.health.covidsafe.R
|
||||
|
||||
fun TextView.toHyperlink(textToHyperLink: String? = null, onClick: () -> Unit) {
|
||||
|
@ -28,3 +33,34 @@ fun TextView.toHyperlink(textToHyperLink: String? = null, onClick: () -> Unit) {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
fun Context.shareThisApp() {
|
||||
val newIntent = Intent(Intent.ACTION_SEND)
|
||||
newIntent.type = "text/plain"
|
||||
newIntent.putExtra(Intent.EXTRA_TEXT, getString(R.string.share_this_app_content))
|
||||
startActivity(Intent.createChooser(newIntent, null))
|
||||
}
|
||||
|
||||
fun Context.getAppVersionNumberDetails(): String {
|
||||
return getString(R.string.home_version_number, BuildConfig.VERSION_NAME)
|
||||
}
|
||||
|
||||
fun fromHtml(stringData: String): Spanned {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
Html.fromHtml(stringData, Html.FROM_HTML_MODE_COMPACT)
|
||||
} else {
|
||||
Html.fromHtml(stringData)
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.allPermissionsEnabled(): Boolean {
|
||||
|
||||
val bluetoothEnabled = isBlueToothEnabled() ?: false
|
||||
val nonBatteryOptimizationAllowed = isBatteryOptimizationDisabled() ?: true
|
||||
val locationStatusAllowed = isLocationPermissionAllowed() ?: true
|
||||
|
||||
return bluetoothEnabled &&
|
||||
nonBatteryOptimizationAllowed &&
|
||||
locationStatusAllowed &&
|
||||
isLocationEnabledOnDevice()
|
||||
}
|
|
@ -19,6 +19,8 @@ interface NetworkFactory {
|
|||
RetrofitServiceGenerator.createService(AwsClient::class.java)
|
||||
}
|
||||
|
||||
private const val USER_AGENT_TAG = "User-Agent"
|
||||
|
||||
val okHttpClient: OkHttpClient by lazy {
|
||||
val okHttpClientBuilder = OkHttpClient.Builder()
|
||||
|
||||
|
@ -26,6 +28,15 @@ interface NetworkFactory {
|
|||
okHttpClientBuilder.addInterceptor(logging)
|
||||
}
|
||||
|
||||
okHttpClientBuilder.addInterceptor { chain ->
|
||||
val request = chain.request()
|
||||
val newRequest = request.newBuilder()
|
||||
.removeHeader(USER_AGENT_TAG)
|
||||
.addHeader(USER_AGENT_TAG, getCustomUserAgent())
|
||||
.build()
|
||||
chain.proceed(newRequest)
|
||||
}
|
||||
|
||||
// This certificate pinning mechanism is only needed on Android 23 and lower.
|
||||
// For Android 24 and above, the pinning is set up in AndroidManifest.xml
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
|
||||
|
@ -52,6 +63,10 @@ interface NetworkFactory {
|
|||
|
||||
okHttpClientBuilder.build()
|
||||
}
|
||||
|
||||
private fun getCustomUserAgent(): String = "COVIDSafe/${BuildConfig.VERSION_NAME}" +
|
||||
" (build:${BuildConfig.VERSION_CODE}; android-${Build.VERSION.SDK_INT}) " + okhttp3.internal.userAgent
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
package au.gov.health.covidsafe.interactor.usecase
|
||||
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import au.gov.health.covidsafe.interactor.Either
|
||||
import au.gov.health.covidsafe.interactor.Failure
|
||||
import au.gov.health.covidsafe.interactor.Success
|
||||
import au.gov.health.covidsafe.interactor.UseCase
|
||||
import au.gov.health.covidsafe.logging.CentralLog
|
||||
import au.gov.health.covidsafe.networking.response.CaseStatisticResponse
|
||||
import au.gov.health.covidsafe.networking.service.AwsClient
|
||||
import au.gov.health.covidsafe.preference.Preference
|
||||
|
||||
private const val TAG = "GetCaseStatisticsUseCase"
|
||||
|
||||
class GetCaseStatisticsUseCase(private val awsClient: AwsClient, lifecycle: Lifecycle, private val context: Context?) : UseCase<CaseStatisticResponse, String>(lifecycle) {
|
||||
|
||||
override suspend fun run(params: String): Either<Exception, CaseStatisticResponse> {
|
||||
val token = Preference.getEncrypterJWTToken(context)
|
||||
return token?.let { jwtToken ->
|
||||
try {
|
||||
CentralLog.d(TAG, "GetCaseStatisticsUseCase run request")
|
||||
val response = retryRetrofitCall { awsClient.getCaseStatistics("Bearer $jwtToken").execute() }
|
||||
|
||||
when {
|
||||
response?.code() == 200 -> {
|
||||
response.body()?.let { body ->
|
||||
CentralLog.d(TAG, "GetCaseStatistics Success: ${body.national}")
|
||||
Success(body)
|
||||
} ?: run {
|
||||
CentralLog.d(TAG, "GetCaseStatistics Invalid response")
|
||||
Failure(GetCaseStatisticsException.GetGetCaseStatisticsServiceException(response.code()))
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
CentralLog.d(TAG, "GetCaseStatistics AWSAuthServiceError")
|
||||
Failure(GetCaseStatisticsException.GetGetCaseStatisticsServiceException(response?.code()))
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Failure(e)
|
||||
}
|
||||
} ?: run {
|
||||
return Failure(Exception())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class GetCaseStatisticsException : Exception() {
|
||||
class GetGetCaseStatisticsServiceException(val code: Int? = null) : GetCaseStatisticsException()
|
||||
}
|
||||
|
||||
|
|
@ -4,8 +4,8 @@ import android.content.Context
|
|||
import androidx.lifecycle.Lifecycle
|
||||
import kotlinx.coroutines.delay
|
||||
import retrofit2.Response
|
||||
import au.gov.health.covidsafe.Preference
|
||||
import au.gov.health.covidsafe.Utils
|
||||
import au.gov.health.covidsafe.preference.Preference
|
||||
import au.gov.health.covidsafe.ui.utils.Utils
|
||||
import au.gov.health.covidsafe.interactor.Either
|
||||
import au.gov.health.covidsafe.interactor.Failure
|
||||
import au.gov.health.covidsafe.interactor.Success
|
||||
|
@ -24,8 +24,8 @@ class UpdateBroadcastMessageAndPerformScanWithExponentialBackOff(private val aws
|
|||
lifecycle: Lifecycle) : UseCase<BroadcastMessageResponse, Void?>(lifecycle) {
|
||||
|
||||
override suspend fun run(params: Void?): Either<Exception, BroadcastMessageResponse> {
|
||||
val jwtToken = Preference.getEncrypterJWTToken(context)
|
||||
return jwtToken?.let { jwtToken ->
|
||||
val token = Preference.getEncrypterJWTToken(context)
|
||||
return token?.let { jwtToken ->
|
||||
var response = call(jwtToken)
|
||||
var retryCount = 0
|
||||
while ((response == null || !response.isSuccessful || response.body() == null) && retryCount < RETRIES_LIMIT) {
|
||||
|
|
|
@ -2,8 +2,8 @@ package au.gov.health.covidsafe.interactor.usecase
|
|||
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import au.gov.health.covidsafe.Preference
|
||||
import au.gov.health.covidsafe.TracerApp
|
||||
import au.gov.health.covidsafe.preference.Preference
|
||||
import au.gov.health.covidsafe.app.TracerApp
|
||||
import au.gov.health.covidsafe.interactor.Either
|
||||
import au.gov.health.covidsafe.interactor.Failure
|
||||
import au.gov.health.covidsafe.interactor.Success
|
||||
|
@ -26,8 +26,8 @@ class UploadData(private val awsClient: AwsClient,
|
|||
private val TAG = this.javaClass.simpleName
|
||||
|
||||
override suspend fun run(params: String): Either<Exception, None> {
|
||||
val jwtToken = Preference.getEncrypterJWTToken(context)
|
||||
return jwtToken?.let { jwtToken ->
|
||||
val token = Preference.getEncrypterJWTToken(context)
|
||||
return token?.let { jwtToken ->
|
||||
try {
|
||||
val initialUploadResponse = retryRetrofitCall {
|
||||
awsClient.initiateUpload("Bearer $jwtToken", params).execute()
|
||||
|
|
|
@ -10,7 +10,7 @@ import android.text.TextPaint
|
|||
import android.text.style.ClickableSpan
|
||||
import android.view.View
|
||||
import au.gov.health.covidsafe.R
|
||||
import au.gov.health.covidsafe.TracerApp
|
||||
import au.gov.health.covidsafe.app.TracerApp
|
||||
import au.gov.health.covidsafe.logging.CentralLog
|
||||
import java.lang.StringBuilder
|
||||
import java.util.*
|
||||
|
@ -18,11 +18,13 @@ import java.util.*
|
|||
|
||||
const val TAG = "LinkBuilder"
|
||||
|
||||
private const val PRIVACY_URL = "https://www.health.gov.au/using-our-websites/privacy/privacy-notice-for-covidsafe-app"
|
||||
private const val DEPARTMENT_OF_HEALTH_URL = "https://www.health.gov.au/"
|
||||
private const val HOST_URL = "https://www.covidsafe.gov.au"
|
||||
|
||||
private const val HELP_TOPICS_BASE = "https://www.covidsafe.gov.au/help-topics"
|
||||
private const val HELP_TOPICS_SUFFIX = ".html"
|
||||
private const val HELP_TOPICS_BASE = "/help-topics"
|
||||
private const val PRIVACY_TOPICS_BASE = "/privacy-policy"
|
||||
|
||||
private const val TOPICS_EXT_SUFFIX = ".html"
|
||||
private const val HELP_TOPICS_ENGLISH_PAGE = ""
|
||||
private const val HELP_TOPICS_S_CHINESE_PAGE = "/zh-hans"
|
||||
private const val HELP_TOPICS_T_CHINESE_PAGE = "/zh-hant"
|
||||
|
@ -36,6 +38,7 @@ private const val HELP_TOPICS_TURKISH_PAGE = "/tr"
|
|||
|
||||
private const val HELP_TOPICS_ANCHOR_VERIFY_MOBILE_NUMBER_PIN = "#verify-mobile-number-pin"
|
||||
private const val HELP_TOPICS_ANCHOR_BLUETOOTH_PAIRING_REQUEST = "#bluetooth-pairing-request"
|
||||
private const val HELP_TOPICS_ANCHOR_LOCATION_PERMISSION_ANDROID = "#location-permission-android"
|
||||
|
||||
object LinkBuilder {
|
||||
|
||||
|
@ -47,9 +50,23 @@ object LinkBuilder {
|
|||
}
|
||||
|
||||
fun getHelpTopicsUrl(): String {
|
||||
val url = buildLocalisedURL(HELP_TOPICS_BASE)
|
||||
CentralLog.d(TAG, "getHelpTopicsUrl() $url")
|
||||
return url
|
||||
}
|
||||
|
||||
private fun getPrivacyTopicsUrl(): String {
|
||||
val url = buildLocalisedURL(PRIVACY_TOPICS_BASE)
|
||||
CentralLog.d(TAG, "getPrivacyTopicsUrl() $url")
|
||||
return url
|
||||
}
|
||||
|
||||
private fun buildLocalisedURL(path: String): String {
|
||||
val localeLanguageTag = Locale.getDefault().toLanguageTag()
|
||||
|
||||
val url = HELP_TOPICS_BASE + when {
|
||||
CentralLog.d(TAG, "Locale Language: $localeLanguageTag")
|
||||
|
||||
return HOST_URL + path + when {
|
||||
localeLanguageTag.startsWith("zh-Hans") -> HELP_TOPICS_S_CHINESE_PAGE
|
||||
localeLanguageTag.startsWith("zh-Hant") -> HELP_TOPICS_T_CHINESE_PAGE
|
||||
localeLanguageTag.startsWith("ar") -> HELP_TOPICS_ARABIC_PAGE
|
||||
|
@ -60,14 +77,8 @@ object LinkBuilder {
|
|||
localeLanguageTag.startsWith("pa") -> HELP_TOPICS_PUNJABI_PAGE
|
||||
localeLanguageTag.startsWith("tr") -> HELP_TOPICS_TURKISH_PAGE
|
||||
else -> HELP_TOPICS_ENGLISH_PAGE
|
||||
} + HELP_TOPICS_SUFFIX
|
||||
} + TOPICS_EXT_SUFFIX
|
||||
|
||||
|
||||
CentralLog.d(TAG, "getHelpTopicsUrl() " +
|
||||
"localeLanguageTag = $localeLanguageTag " +
|
||||
"url = $url")
|
||||
|
||||
return url
|
||||
}
|
||||
|
||||
fun getHelpTopicsUrlWithAnchor(anchor: String) =
|
||||
|
@ -76,6 +87,9 @@ object LinkBuilder {
|
|||
private fun getBluetoothPairingRequestUrl() =
|
||||
getHelpTopicsUrl() + HELP_TOPICS_ANCHOR_BLUETOOTH_PAIRING_REQUEST
|
||||
|
||||
private fun getLocationPairingRequestUrl() =
|
||||
getHelpTopicsUrl() + HELP_TOPICS_ANCHOR_LOCATION_PERMISSION_ANDROID
|
||||
|
||||
private fun getVerifyMobileNumberPinLink(linkText: String) = buildHtmlText(
|
||||
"<a href=\"${getHelpTopicsUrl() + HELP_TOPICS_ANCHOR_VERIFY_MOBILE_NUMBER_PIN}\">$linkText</a>")
|
||||
|
||||
|
@ -126,15 +140,16 @@ object LinkBuilder {
|
|||
}
|
||||
|
||||
fun getRegistrationAndPrivacyContent(context: Context): SpannableString {
|
||||
val privacyUrl = getPrivacyTopicsUrl()
|
||||
return buildSpannableStringContent(
|
||||
context,
|
||||
TracerApp.AppContext.getString(R.string.data_privacy_content),
|
||||
listOf(
|
||||
PRIVACY_URL,
|
||||
PRIVACY_URL,
|
||||
privacyUrl,
|
||||
privacyUrl,
|
||||
getHelpTopicsUrl(),
|
||||
DEPARTMENT_OF_HEALTH_URL,
|
||||
PRIVACY_URL
|
||||
privacyUrl
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -143,7 +158,7 @@ object LinkBuilder {
|
|||
return buildSpannableStringContent(
|
||||
context,
|
||||
TracerApp.AppContext.getString(R.string.permission_success_content),
|
||||
listOf(getBluetoothPairingRequestUrl())
|
||||
listOf(getBluetoothPairingRequestUrl(), getLocationPairingRequestUrl())
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -166,7 +181,7 @@ object LinkBuilder {
|
|||
return buildSpannableStringContent(
|
||||
context,
|
||||
TracerApp.AppContext.getString(R.string.upload_step_4_sub_header),
|
||||
listOf(PRIVACY_URL)
|
||||
listOf(getPrivacyTopicsUrl())
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package au.gov.health.covidsafe.networking.response
|
||||
|
||||
import androidx.annotation.Keep
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
@Keep
|
||||
data class CaseStatisticResponse(@SerializedName("updated_date") val updatedDate: String?,
|
||||
@SerializedName("stats_published_status") val statsPublishedStatus: String?,
|
||||
val national: CaseDetailsData?,
|
||||
val act: CaseDetailsData?,
|
||||
val nsw: CaseDetailsData?,
|
||||
val nt: CaseDetailsData?,
|
||||
val qld: CaseDetailsData?,
|
||||
val sa: CaseDetailsData?,
|
||||
val tas: CaseDetailsData?,
|
||||
val vic: CaseDetailsData?,
|
||||
val wa: CaseDetailsData?)
|
||||
|
||||
@Keep
|
||||
data class CaseDetailsData(
|
||||
@SerializedName("total_cases") var totalCases: Int?,
|
||||
@SerializedName("active_cases") var activeCases: Int?,
|
||||
@SerializedName("new_cases") var newCases: Int?,
|
||||
@SerializedName("recovered_cases") var recoveredCases: Int?,
|
||||
var deaths: Int?)
|
|
@ -1,6 +1,7 @@
|
|||
package au.gov.health.covidsafe.networking.service
|
||||
|
||||
import au.gov.health.covidsafe.BuildConfig
|
||||
import au.gov.health.covidsafe.networking.response.CaseStatisticResponse
|
||||
import au.gov.health.covidsafe.networking.request.AuthChallengeRequest
|
||||
import au.gov.health.covidsafe.networking.request.OTPChallengeRequest
|
||||
import au.gov.health.covidsafe.networking.response.*
|
||||
|
@ -40,7 +41,11 @@ interface AwsClient {
|
|||
@Query("appversion") appversion: String,
|
||||
@Query("token") token: String,
|
||||
@Query("healthcheck") healthcheck: String,
|
||||
@Query("encountershealth") encountershealth: String,
|
||||
@Query("preferredlanguages") preferredLanguages: String
|
||||
): Call<MessagesResponse>
|
||||
|
||||
@GET(BuildConfig.END_POINT_PREFIX + "/statistics")
|
||||
fun getCaseStatistics(@Header("Authorization") jwtToken: String?): Call<CaseStatisticResponse>
|
||||
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
package au.gov.health.covidsafe.notifications
|
||||
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.media.RingtoneManager
|
||||
import android.os.Build
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import au.gov.health.covidsafe.HomeActivity
|
||||
import au.gov.health.covidsafe.R
|
||||
import au.gov.health.covidsafe.app.TracerApp
|
||||
import au.gov.health.covidsafe.logging.CentralLog
|
||||
import au.gov.health.covidsafe.preference.Preference
|
||||
import au.gov.health.covidsafe.ui.utils.Utils.gotoPlayStore
|
||||
import com.google.firebase.messaging.FirebaseMessagingService
|
||||
import com.google.firebase.messaging.RemoteMessage
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
private const val TAG = "CovidFirebaseMessagingService"
|
||||
|
||||
|
||||
class CovidFirebaseMessagingService : FirebaseMessagingService(), CoroutineScope {
|
||||
|
||||
/**
|
||||
* Called when message is received.
|
||||
*
|
||||
* @param remoteMessage Object representing the message received from Firebase Cloud Messaging.
|
||||
*/
|
||||
override fun onMessageReceived(remoteMessage: RemoteMessage) {
|
||||
// There are two types of messages data messages and notification messages. Data messages are handled
|
||||
// here in onMessageReceived whether the app is in the foreground or background. Data messages are the type
|
||||
// traditionally used with GCM. Notification messages are only received here in onMessageReceived when the app
|
||||
// is in the foreground. When the app is in the background an automatically generated notification is displayed.
|
||||
// When the user taps on the notification they are returned to the app. Messages containing both notification
|
||||
// and data payloads are treated as notification messages. The Firebase console always sends notification
|
||||
// messages. For more see: https://firebase.google.com/docs/cloud-messaging/concept-options
|
||||
|
||||
// Not getting messages here? See why this may be: https://goo.gl/39bRNJ
|
||||
CentralLog.d(TAG, "onMessageReceived() received message from ${remoteMessage.from}")
|
||||
|
||||
// log notification payload.
|
||||
remoteMessage.notification?.let {
|
||||
CentralLog.d(TAG, "onMessageReceived() notification = ${it.title} ${it.body} ${it.clickAction}")
|
||||
|
||||
if (it.clickAction == getString(R.string.notification_click_action_upgrade_app)) {
|
||||
gotoPlayStore(applicationContext)
|
||||
} else {
|
||||
createPushNotification(it)
|
||||
}
|
||||
}
|
||||
|
||||
// log data payload.
|
||||
remoteMessage.data.isNotEmpty().let {
|
||||
CentralLog.d(TAG, "onMessageReceived() data = " + remoteMessage.data)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createPushNotification(notification: RemoteMessage.Notification) {
|
||||
launch(Dispatchers.Main) {
|
||||
val intent = Intent(this@CovidFirebaseMessagingService, HomeActivity::class.java)
|
||||
intent.action = notification.clickAction
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||
|
||||
val pendingIntent = PendingIntent.getActivity(this@CovidFirebaseMessagingService, 0, intent, PendingIntent.FLAG_ONE_SHOT)
|
||||
val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
|
||||
val channelId = getString(R.string.default_notification_channel_id)
|
||||
|
||||
val notificationBuilder = NotificationCompat.Builder(this@CovidFirebaseMessagingService, channelId)
|
||||
.setContentTitle(notification.title)
|
||||
.setContentText(notification.body)
|
||||
.setAutoCancel(true)
|
||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||
.setSmallIcon(R.drawable.ic_notification_icon)
|
||||
.setContentIntent(pendingIntent)
|
||||
.setSound(defaultSoundUri)
|
||||
.setColor(ContextCompat.getColor(this@CovidFirebaseMessagingService, R.color.notification_tint))
|
||||
|
||||
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val channel = NotificationChannel(
|
||||
channelId,
|
||||
getString(R.string.default_notification_channel_name),
|
||||
NotificationManager.IMPORTANCE_DEFAULT
|
||||
)
|
||||
notificationManager.createNotificationChannel(channel)
|
||||
}
|
||||
|
||||
notificationManager.notify(0, notificationBuilder.build())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when InstanceID token is updated.
|
||||
*/
|
||||
override fun onNewToken(token: String) {
|
||||
CentralLog.d(TAG, "onNewToken() InstanceID = $token")
|
||||
Preference.putFirebaseInstanceID(TracerApp.AppContext, token)
|
||||
}
|
||||
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = Dispatchers.IO + Job()
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package au.gov.health.covidsafe.notifications
|
||||
|
||||
import android.content.Context
|
||||
import au.gov.health.covidsafe.R
|
||||
import au.gov.health.covidsafe.ui.utils.Utils
|
||||
|
||||
class NotificationBuilder {
|
||||
|
||||
companion object {
|
||||
|
||||
private var isPushNotificationErrorCheck = false
|
||||
|
||||
fun handlePushNotification(context: Context, action: String?) {
|
||||
action?.let {
|
||||
when (it) {
|
||||
context.getString(R.string.notification_click_action_upgrade_app) -> {
|
||||
Utils.gotoPlayStore(context)
|
||||
}
|
||||
context.getString(R.string.notification_click_action_no_check_in),
|
||||
context.getString(R.string.notification_click_action_check_possible_encountered_error),
|
||||
context.getString(R.string.notification_click_action_check_possible_issue) -> {
|
||||
isPushNotificationErrorCheck = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun isShowPossibleIssueNotification() = isPushNotificationErrorCheck
|
||||
|
||||
fun clearPossibleIssueNotificationCheck() {
|
||||
isPushNotificationErrorCheck = false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -45,7 +45,11 @@ class NotificationTemplates {
|
|||
return builder.build()
|
||||
}
|
||||
|
||||
fun lackingThingsNotification(context: Context, channel: String): Notification {
|
||||
fun lackingThingsNotification(context: Context, contentTextResId: Int, channel: String): Notification {
|
||||
return lackingThingsNotification(context, context.getString(contentTextResId), channel)
|
||||
}
|
||||
|
||||
fun lackingThingsNotification(context: Context, contentText: String, channel: String): Notification {
|
||||
val intent = Intent(context, HomeActivity::class.java)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||
intent.putExtra("page", 3)
|
||||
|
@ -57,13 +61,13 @@ class NotificationTemplates {
|
|||
|
||||
val builder = NotificationCompat.Builder(context, channel)
|
||||
.setContentTitle(context.getText(R.string.service_not_ok_title))
|
||||
.setContentText(context.getText(R.string.service_not_ok_body))
|
||||
.setStyle(NotificationCompat.BigTextStyle().bigText(context.getText(R.string.service_not_ok_body)))
|
||||
.setContentText(contentText)
|
||||
.setStyle(NotificationCompat.BigTextStyle().bigText(contentText))
|
||||
|
||||
.setOngoing(true)
|
||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||
.setSmallIcon(R.drawable.ic_notification_warning)
|
||||
.setTicker(context.getText(R.string.service_not_ok_body))
|
||||
.setTicker(contentText)
|
||||
.addAction(
|
||||
R.drawable.ic_notification_setting,
|
||||
context.getText(R.string.service_not_ok_action),
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
package au.gov.health.covidsafe
|
||||
package au.gov.health.covidsafe.preference
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import au.gov.health.covidsafe.R
|
||||
import au.gov.health.covidsafe.security.crypto.EncryptedSharedPreferences
|
||||
import au.gov.health.covidsafe.security.crypto.MasterKeys
|
||||
import au.gov.health.covidsafe.security.crypto.AESEncryptionForPreAndroidM
|
||||
|
@ -32,6 +33,7 @@ object Preference {
|
|||
private const val IS_MINOR = "IS_MINOR"
|
||||
private const val POST_CODE = "POST_CODE"
|
||||
private const val AGE = "AGE"
|
||||
private const val CASE_STATISTIC = "CASESTATISTIC"
|
||||
private const val IS_DEVICE_NAME_CHANGE_PROMPT_DISPLAYED = "IS_DEVICE_NAME_CHANGE_DISPLAYED"
|
||||
|
||||
fun putDeviceID(context: Context, value: String) {
|
||||
|
@ -275,4 +277,14 @@ object Preference {
|
|||
.getBoolean(IS_DEVICE_NAME_CHANGE_PROMPT_DISPLAYED, false)
|
||||
}
|
||||
|
||||
fun putCaseStatisticData(context: Context, caseStaticData: String): Boolean {
|
||||
return context.getSharedPreferences(PREF_ID, Context.MODE_PRIVATE)
|
||||
.edit().putString(CASE_STATISTIC, caseStaticData).commit()
|
||||
}
|
||||
|
||||
fun getCaseStatisticData(context: Context): String? {
|
||||
return context.getSharedPreferences(PREF_ID, Context.MODE_PRIVATE)
|
||||
.getString(CASE_STATISTIC, null)
|
||||
}
|
||||
|
||||
}
|
|
@ -7,7 +7,6 @@ import android.content.Context
|
|||
import android.content.Intent
|
||||
import au.gov.health.covidsafe.logging.CentralLog
|
||||
import au.gov.health.covidsafe.services.BluetoothMonitoringService.Companion.PENDING_PRIVACY_CLEANER_CODE
|
||||
import au.gov.health.covidsafe.services.SensorMonitoringService.Companion.TAG
|
||||
import au.gov.health.covidsafe.status.persistence.StatusRecordStorage
|
||||
import au.gov.health.covidsafe.streetpass.persistence.StreetPassRecordStorage
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
@ -19,8 +18,6 @@ import kotlin.coroutines.CoroutineContext
|
|||
|
||||
class PrivacyCleanerReceiver : BroadcastReceiver(), CoroutineScope {
|
||||
|
||||
private val TAG = this.javaClass.simpleName
|
||||
|
||||
private var job: Job = Job()
|
||||
|
||||
override val coroutineContext: CoroutineContext
|
||||
|
@ -40,7 +37,7 @@ class PrivacyCleanerReceiver : BroadcastReceiver(), CoroutineScope {
|
|||
alarm.setRepeating(AlarmManager.RTC, System.currentTimeMillis(), AlarmManager.INTERVAL_DAY, pendingIntent)
|
||||
}
|
||||
|
||||
suspend fun cleanDb(context: Context) {
|
||||
fun cleanDb(context: Context) {
|
||||
val twentyOneDaysAgo = Calendar.getInstance()
|
||||
twentyOneDaysAgo.set(Calendar.HOUR_OF_DAY, 23)
|
||||
twentyOneDaysAgo.set(Calendar.MINUTE, 59)
|
||||
|
@ -53,6 +50,8 @@ class PrivacyCleanerReceiver : BroadcastReceiver(), CoroutineScope {
|
|||
CentralLog.i(TAG, "Street info deleted count : $countStreetDeleted")
|
||||
CentralLog.i(TAG, "Status info deleted count : $countStatusDeleted")
|
||||
}
|
||||
|
||||
const val TAG = "PrivacyCleanerReceiver"
|
||||
}
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
|
|
|
@ -3,7 +3,7 @@ package au.gov.health.covidsafe.receivers
|
|||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import au.gov.health.covidsafe.Utils
|
||||
import au.gov.health.covidsafe.ui.utils.Utils
|
||||
import au.gov.health.covidsafe.logging.CentralLog
|
||||
|
||||
class UpgradeReceiver : BroadcastReceiver() {
|
||||
|
|
|
@ -7,8 +7,8 @@ import android.app.job.JobService
|
|||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import au.gov.health.covidsafe.BuildConfig
|
||||
import au.gov.health.covidsafe.Preference
|
||||
import au.gov.health.covidsafe.TracerApp
|
||||
import au.gov.health.covidsafe.preference.Preference
|
||||
import au.gov.health.covidsafe.app.TracerApp
|
||||
import au.gov.health.covidsafe.extensions.isBatteryOptimizationDisabled
|
||||
import au.gov.health.covidsafe.extensions.isBlueToothEnabled
|
||||
import au.gov.health.covidsafe.extensions.isLocationEnabledOnDevice
|
||||
|
@ -31,14 +31,16 @@ import java.util.*
|
|||
|
||||
private const val TAG = "GetMessagesScheduler"
|
||||
private const val GET_MESSAGES_JOB_ID = 1
|
||||
private const val TWENTY_FOUR_HOURS_IN_MILLIS = 24 * 60 * 60 * 1000L
|
||||
private const val ONE_HOURS_IN_MILLIS = 60 * 60 * 1000L
|
||||
private const val FOUR_HOURS_IN_MILLIS = 4 * ONE_HOURS_IN_MILLIS
|
||||
private const val TWENTY_FOUR_HOURS_IN_MILLIS = 24 * ONE_HOURS_IN_MILLIS
|
||||
private const val SEVEN_DAYS_IN_MILLIS = 7 * TWENTY_FOUR_HOURS_IN_MILLIS
|
||||
|
||||
private const val HEALTH_CHECK_RESULT_OK = "OK"
|
||||
private const val HEALTH_CHECK_RESULT_POSSIBLE_ERROR = "POSSIBLE_ERROR"
|
||||
|
||||
// for testing only
|
||||
//private const val TWENTY_FOUR_HOURS_IN_MILLIS = 16 * 60 * 1000L
|
||||
//private const val FOUR_HOURS_IN_MILLIS = 16 * 60 * 1000L
|
||||
|
||||
class GetMessagesJobSchedulerService : JobService() {
|
||||
private val mostRecentRecordLiveData = StreetPassRecordDatabase.getDatabase(TracerApp.AppContext).recordDao().getMostRecentRecord()
|
||||
|
@ -89,19 +91,27 @@ object GetMessagesScheduler {
|
|||
(context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler?)
|
||||
?.let {
|
||||
CentralLog.d(TAG, "JobScheduler available")
|
||||
val schedulerInMillis = getRandomMinsInMillis() + FOUR_HOURS_IN_MILLIS
|
||||
CentralLog.d(TAG, "Next scheduled Jon run in ${(schedulerInMillis / 1000) / 60} mins")
|
||||
|
||||
it.schedule(
|
||||
JobInfo.Builder(GET_MESSAGES_JOB_ID,
|
||||
ComponentName(context, GetMessagesJobSchedulerService::class.java))
|
||||
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
|
||||
.setPersisted(true)
|
||||
.setPeriodic(TWENTY_FOUR_HOURS_IN_MILLIS)
|
||||
.setPeriodic(schedulerInMillis)
|
||||
.build()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getRandomMinsInMillis(): Long {
|
||||
//We don't want everyone calling at the same time eg 9 am, 1 pm, etc we want to add an offset between 0-30 minutes based upon some random number.
|
||||
val randomSecs = Random().nextInt(30 * 60)
|
||||
return randomSecs * 1000L
|
||||
}
|
||||
|
||||
fun getMessages(jobService: JobService? = null, params: JobParameters? = null) {
|
||||
val context = TracerApp.AppContext
|
||||
|
||||
|
@ -127,14 +137,19 @@ object GetMessagesScheduler {
|
|||
isBlueToothEnabled &&
|
||||
isBatteryOptimizationDisabled &&
|
||||
isLocationPermissionAllowed &&
|
||||
isLocationEnabledOnDevice &&
|
||||
isLastRecordWithinSevenDays
|
||||
isLocationEnabledOnDevice
|
||||
) {
|
||||
HEALTH_CHECK_RESULT_OK
|
||||
} else {
|
||||
HEALTH_CHECK_RESULT_POSSIBLE_ERROR
|
||||
}
|
||||
|
||||
val encountersHealth = if (isLastRecordWithinSevenDays) {
|
||||
HEALTH_CHECK_RESULT_OK
|
||||
} else {
|
||||
HEALTH_CHECK_RESULT_POSSIBLE_ERROR
|
||||
}
|
||||
|
||||
CentralLog.d(TAG, "healthCheck = $healthCheck")
|
||||
|
||||
val preferredLanguages = Locale.getDefault().language
|
||||
|
@ -145,6 +160,7 @@ object GetMessagesScheduler {
|
|||
appVersion,
|
||||
token,
|
||||
healthCheck,
|
||||
encountersHealth,
|
||||
preferredLanguages
|
||||
)
|
||||
|
||||
|
|
|
@ -3,8 +3,8 @@ package au.gov.health.covidsafe.security.crypto
|
|||
import android.security.KeyPairGeneratorSpec
|
||||
import android.security.keystore.KeyProperties
|
||||
import android.util.Base64
|
||||
import au.gov.health.covidsafe.Preference
|
||||
import au.gov.health.covidsafe.TracerApp
|
||||
import au.gov.health.covidsafe.preference.Preference
|
||||
import au.gov.health.covidsafe.app.TracerApp
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.math.BigInteger
|
||||
|
|
|
@ -4,24 +4,31 @@ import android.app.NotificationChannel
|
|||
import android.app.NotificationManager
|
||||
import android.bluetooth.BluetoothAdapter
|
||||
import android.bluetooth.BluetoothManager
|
||||
import android.content.*
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.location.LocationManager
|
||||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
import android.os.PowerManager
|
||||
import androidx.annotation.Keep
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.LifecycleService
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||
import au.gov.health.covidsafe.*
|
||||
import au.gov.health.covidsafe.BuildConfig
|
||||
import au.gov.health.covidsafe.R
|
||||
import au.gov.health.covidsafe.app.TracerApp
|
||||
import au.gov.health.covidsafe.bluetooth.BLEAdvertiser
|
||||
import au.gov.health.covidsafe.bluetooth.gatt.ACTION_RECEIVED_STATUS
|
||||
import au.gov.health.covidsafe.bluetooth.gatt.ACTION_RECEIVED_STREETPASS
|
||||
import au.gov.health.covidsafe.bluetooth.gatt.STATUS
|
||||
import au.gov.health.covidsafe.bluetooth.gatt.STREET_PASS
|
||||
import au.gov.health.covidsafe.extensions.isLocationEnabledOnDevice
|
||||
import au.gov.health.covidsafe.factory.NetworkFactory
|
||||
import au.gov.health.covidsafe.interactor.usecase.UpdateBroadcastMessageAndPerformScanWithExponentialBackOff
|
||||
import au.gov.health.covidsafe.logging.CentralLog
|
||||
import au.gov.health.covidsafe.notifications.NotificationTemplates
|
||||
import au.gov.health.covidsafe.preference.Preference
|
||||
import au.gov.health.covidsafe.receivers.PrivacyCleanerReceiver
|
||||
import au.gov.health.covidsafe.status.Status
|
||||
import au.gov.health.covidsafe.status.persistence.StatusRecord
|
||||
|
@ -39,6 +46,8 @@ import au.gov.health.covidsafe.streetpass.persistence.StreetPassRecordDatabase.C
|
|||
import au.gov.health.covidsafe.streetpass.persistence.StreetPassRecordDatabase.Companion.ENCRYPTED_EMPTY_DICT
|
||||
import au.gov.health.covidsafe.streetpass.persistence.StreetPassRecordDatabase.Companion.VERSION_ONE
|
||||
import au.gov.health.covidsafe.streetpass.persistence.StreetPassRecordStorage
|
||||
import au.gov.health.covidsafe.ui.utils.LocalBlobV2
|
||||
import au.gov.health.covidsafe.ui.utils.Utils
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
@ -46,15 +55,14 @@ import kotlinx.coroutines.Dispatchers
|
|||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import pub.devrel.easypermissions.EasyPermissions
|
||||
import java.lang.Exception
|
||||
import java.lang.ref.WeakReference
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
private const val POWER_SAVE_WHITELIST_CHANGED = "android.os.action.POWER_SAVE_WHITELIST_CHANGED"
|
||||
|
||||
@Keep
|
||||
class BluetoothMonitoringService : LifecycleService(), CoroutineScope {
|
||||
|
||||
private var mNotificationManager: NotificationManager? = null
|
||||
|
||||
@Keep
|
||||
private lateinit var serviceUUID: String
|
||||
|
||||
|
@ -78,31 +86,12 @@ class BluetoothMonitoringService : LifecycleService(), CoroutineScope {
|
|||
|
||||
private lateinit var commandHandler: CommandHandler
|
||||
|
||||
private lateinit var mService: SensorMonitoringService
|
||||
private var mBound: Boolean = false
|
||||
|
||||
private lateinit var localBroadcastManager: LocalBroadcastManager
|
||||
|
||||
private val awsClient = NetworkFactory.awsClient
|
||||
|
||||
private val gson: Gson = GsonBuilder().disableHtmlEscaping().create()
|
||||
|
||||
|
||||
/** Defines callbacks for service binding, passed to bindService() */
|
||||
private val connection = object : ServiceConnection {
|
||||
|
||||
override fun onServiceConnected(className: ComponentName, service: IBinder) {
|
||||
// We've bound to LocalService, cast the IBinder and get LocalService instance
|
||||
val binder = service as SensorMonitoringService.LocalBinder
|
||||
mService = binder.getService()
|
||||
mBound = true
|
||||
}
|
||||
|
||||
override fun onServiceDisconnected(arg0: ComponentName) {
|
||||
mBound = false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
localBroadcastManager = LocalBroadcastManager.getInstance(this)
|
||||
|
@ -171,6 +160,10 @@ class BluetoothMonitoringService : LifecycleService(), CoroutineScope {
|
|||
return EasyPermissions.hasPermissions(this.applicationContext, *perms)
|
||||
}
|
||||
|
||||
private fun isLocationPermissionEnabled(): Boolean {
|
||||
return hasLocationPermissions() && this.isLocationEnabledOnDevice()
|
||||
}
|
||||
|
||||
private fun isBluetoothEnabled(): Boolean {
|
||||
var btOn = false
|
||||
val bluetoothAdapter: BluetoothAdapter? by lazy(LazyThreadSafetyMode.NONE) {
|
||||
|
@ -204,20 +197,13 @@ class BluetoothMonitoringService : LifecycleService(), CoroutineScope {
|
|||
super.onStartCommand(intent, flags, startId)
|
||||
CentralLog.i(TAG, "Service onStartCommand")
|
||||
|
||||
// Bind to LocalService
|
||||
Intent(this.applicationContext, SensorMonitoringService::class.java).also { intent ->
|
||||
bindService(intent, connection, Context.BIND_AUTO_CREATE)
|
||||
}
|
||||
|
||||
//check for permissions
|
||||
if (!hasLocationPermissions() || !isBluetoothEnabled() || !isBatteryOptimizationDisabled()) {
|
||||
if (!isLocationPermissionEnabled() || !isBluetoothEnabled() || !isBatteryOptimizationDisabled()) {
|
||||
CentralLog.i(
|
||||
TAG,
|
||||
"location permission: ${hasLocationPermissions()} bluetooth: ${isBluetoothEnabled()}"
|
||||
"location permission: ${isLocationPermissionEnabled()} bluetooth: ${isBluetoothEnabled()}"
|
||||
)
|
||||
val notif =
|
||||
NotificationTemplates.lackingThingsNotification(this.applicationContext, CHANNEL_ID)
|
||||
startForeground(NOTIFICATION_ID, notif)
|
||||
showForegroundNotification()
|
||||
return START_STICKY
|
||||
}
|
||||
|
||||
|
@ -242,14 +228,12 @@ class BluetoothMonitoringService : LifecycleService(), CoroutineScope {
|
|||
CentralLog.i(TAG, "Command is:${cmd?.string}")
|
||||
|
||||
//check for permissions
|
||||
if (!hasLocationPermissions() || !isBluetoothEnabled()) {
|
||||
if (!isLocationPermissionEnabled() || !isBluetoothEnabled()) {
|
||||
CentralLog.i(
|
||||
TAG,
|
||||
"location permission: ${hasLocationPermissions()} bluetooth: ${isBluetoothEnabled()}"
|
||||
"location permission: ${isLocationPermissionEnabled()} bluetooth: ${isBluetoothEnabled()}"
|
||||
)
|
||||
val notif =
|
||||
NotificationTemplates.lackingThingsNotification(this.applicationContext, CHANNEL_ID)
|
||||
startForeground(NOTIFICATION_ID, notif)
|
||||
showForegroundNotification()
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -326,7 +310,6 @@ class BluetoothMonitoringService : LifecycleService(), CoroutineScope {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private fun actionUpdateBm() {
|
||||
Utils.scheduleBMUpdateCheck(this.applicationContext, bmCheckInterval)
|
||||
|
||||
|
@ -345,7 +328,6 @@ class BluetoothMonitoringService : LifecycleService(), CoroutineScope {
|
|||
} else {
|
||||
CentralLog.i(TAG, "Don't need to update bm")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun calcPhaseShift(min: Long, max: Long): Long {
|
||||
|
@ -448,11 +430,9 @@ class BluetoothMonitoringService : LifecycleService(), CoroutineScope {
|
|||
|
||||
CentralLog.i(TAG, "Performing self diagnosis")
|
||||
|
||||
if (!hasLocationPermissions() || !isBluetoothEnabled() || !isBatteryOptimizationDisabled()) {
|
||||
if (!isLocationPermissionEnabled() || !isBluetoothEnabled() || !isBatteryOptimizationDisabled()) {
|
||||
CentralLog.i(TAG, "no location permission")
|
||||
val notif =
|
||||
NotificationTemplates.lackingThingsNotification(this.applicationContext, CHANNEL_ID)
|
||||
startForeground(NOTIFICATION_ID, notif)
|
||||
showForegroundNotification()
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -480,8 +460,10 @@ class BluetoothMonitoringService : LifecycleService(), CoroutineScope {
|
|||
} else {
|
||||
CentralLog.w(
|
||||
TAG,
|
||||
"Advertise Schedule present. Should be advertising?: ${advertiser?.shouldBeAdvertising
|
||||
?: false}. Is Advertising?: ${advertiser?.isAdvertising ?: false}"
|
||||
"Advertise Schedule present. Should be advertising?: ${
|
||||
advertiser?.shouldBeAdvertising
|
||||
?: false
|
||||
}. Is Advertising?: ${advertiser?.isAdvertising ?: false}"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -498,12 +480,72 @@ class BluetoothMonitoringService : LifecycleService(), CoroutineScope {
|
|||
|
||||
job.cancel()
|
||||
|
||||
if (mBound) {
|
||||
unbindService(connection)
|
||||
mBound = false
|
||||
CentralLog.i(TAG, "BluetoothMonitoringService destroyed")
|
||||
}
|
||||
|
||||
CentralLog.i(TAG, "BluetoothMonitoringService destroyed")
|
||||
private fun showForegroundNotification() {
|
||||
|
||||
launch(Dispatchers.Main) {
|
||||
|
||||
val notificationContentText: Int = if (!isLocationPermissionEnabled() && isBluetoothEnabled() && isBatteryOptimizationDisabled()) {
|
||||
//Location Disabled
|
||||
R.string.notification_location
|
||||
} else if (!isBluetoothEnabled() && isLocationPermissionEnabled() && isBatteryOptimizationDisabled()) {
|
||||
//Bluetooth Disabled
|
||||
R.string.notification_bluetooth
|
||||
} else if (!isBatteryOptimizationDisabled() && isLocationPermissionEnabled() && isBluetoothEnabled()) {
|
||||
//Battery optimization Disabled
|
||||
R.string.notification_battery
|
||||
} else if (!isBatteryOptimizationDisabled() || !isLocationPermissionEnabled() || !isBluetoothEnabled()) {
|
||||
//Multiple permission Disabled
|
||||
R.string.notification_settings
|
||||
} else {
|
||||
//All permission are enabled, so we should show Active message.
|
||||
-1
|
||||
}
|
||||
|
||||
val notificationMessage = if (notificationContentText > 0) {
|
||||
NotificationTemplates.lackingThingsNotification(
|
||||
this@BluetoothMonitoringService.applicationContext,
|
||||
notificationContentText,
|
||||
CHANNEL_ID)
|
||||
} else {
|
||||
//All permissions are enabled
|
||||
NotificationTemplates.getRunningNotification(this@BluetoothMonitoringService.applicationContext, CHANNEL_ID)
|
||||
}
|
||||
|
||||
startForeground(NOTIFICATION_ID, notificationMessage)
|
||||
}
|
||||
}
|
||||
|
||||
private val gpsSwitchStateReceiver: BroadcastReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
intent.action?.let {
|
||||
if (it == LocationManager.PROVIDERS_CHANGED_ACTION) {
|
||||
CentralLog.i(TAG, "Location ON/OFF status changed")
|
||||
showForegroundNotification()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val powerStateChangeReceiver: BroadcastReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
intent.action?.let {
|
||||
if (it == POWER_SAVE_WHITELIST_CHANGED) {
|
||||
CentralLog.i(TAG, "Save mode status changed")
|
||||
showForegroundNotification()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun registerLocationChangeReceiver() {
|
||||
registerReceiver(gpsSwitchStateReceiver, IntentFilter(LocationManager.PROVIDERS_CHANGED_ACTION))
|
||||
}
|
||||
|
||||
private fun registerPowerModeChangeReceiver() {
|
||||
registerReceiver(powerStateChangeReceiver, IntentFilter(POWER_SAVE_WHITELIST_CHANGED))
|
||||
}
|
||||
|
||||
private fun registerReceivers() {
|
||||
|
@ -516,6 +558,9 @@ class BluetoothMonitoringService : LifecycleService(), CoroutineScope {
|
|||
val bluetoothStatusReceivedFilter = IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)
|
||||
registerReceiver(bluetoothStatusReceiver, bluetoothStatusReceivedFilter)
|
||||
|
||||
registerLocationChangeReceiver()
|
||||
registerPowerModeChangeReceiver()
|
||||
|
||||
CentralLog.i(TAG, "Receivers registered")
|
||||
}
|
||||
|
||||
|
@ -534,9 +579,29 @@ class BluetoothMonitoringService : LifecycleService(), CoroutineScope {
|
|||
|
||||
try {
|
||||
unregisterReceiver(bluetoothStatusReceiver)
|
||||
|
||||
} catch (e: Throwable) {
|
||||
CentralLog.w(TAG, "bluetoothStatusReceiver is not registered?")
|
||||
}
|
||||
|
||||
unregisterLocationReceiver()
|
||||
unregisterPowerStateChangeReceiver()
|
||||
}
|
||||
|
||||
private fun unregisterLocationReceiver() {
|
||||
try {
|
||||
unregisterReceiver(gpsSwitchStateReceiver)
|
||||
} catch (e: Throwable) {
|
||||
CentralLog.w(TAG, "Location Receiver is not registered?")
|
||||
}
|
||||
}
|
||||
|
||||
private fun unregisterPowerStateChangeReceiver() {
|
||||
try {
|
||||
unregisterReceiver(powerStateChangeReceiver)
|
||||
} catch (e: Throwable) {
|
||||
CentralLog.w(TAG, "Power State Receiver is not registered?")
|
||||
}
|
||||
}
|
||||
|
||||
inner class BluetoothStatusReceiver : BroadcastReceiver() {
|
||||
|
@ -549,11 +614,7 @@ class BluetoothMonitoringService : LifecycleService(), CoroutineScope {
|
|||
when (intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1)) {
|
||||
BluetoothAdapter.STATE_TURNING_OFF -> {
|
||||
CentralLog.d(TAG, "BluetoothAdapter.STATE_TURNING_OFF")
|
||||
val notif = NotificationTemplates.lackingThingsNotification(
|
||||
this@BluetoothMonitoringService.applicationContext,
|
||||
CHANNEL_ID
|
||||
)
|
||||
startForeground(NOTIFICATION_ID, notif)
|
||||
showForegroundNotification()
|
||||
teardown()
|
||||
}
|
||||
BluetoothAdapter.STATE_OFF -> {
|
||||
|
@ -565,6 +626,7 @@ class BluetoothMonitoringService : LifecycleService(), CoroutineScope {
|
|||
BluetoothAdapter.STATE_ON -> {
|
||||
CentralLog.d(TAG, "BluetoothAdapter.STATE_ON")
|
||||
Utils.startBluetoothMonitoringService(this@BluetoothMonitoringService.applicationContext)
|
||||
showForegroundNotification()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -580,22 +642,10 @@ class BluetoothMonitoringService : LifecycleService(), CoroutineScope {
|
|||
|
||||
if (ACTION_RECEIVED_STREETPASS == intent.action) {
|
||||
val connRecord: ConnectionRecord? = intent.getParcelableExtra(STREET_PASS)
|
||||
CentralLog.d(
|
||||
TAG,
|
||||
"StreetPass received: $connRecord"
|
||||
)
|
||||
CentralLog.d(TAG, "StreetPass received: $connRecord")
|
||||
|
||||
if (connRecord != null && connRecord.msg.isNotEmpty()) {
|
||||
|
||||
if (mBound) {
|
||||
val proximity = mService.proximity
|
||||
val light = mService.light
|
||||
CentralLog.d(
|
||||
TAG,
|
||||
"Sensor values just before saving StreetPassRecord: proximity=$proximity light=$light"
|
||||
)
|
||||
}
|
||||
|
||||
val remoteBlob: String = if (connRecord.version == VERSION_ONE) {
|
||||
with(receiver = connRecord) {
|
||||
val plainRecordByteArray = gson.toJson(StreetPassRecordDatabase.Companion.EncryptedRecord(
|
||||
|
@ -646,11 +696,12 @@ class BluetoothMonitoringService : LifecycleService(), CoroutineScope {
|
|||
override fun onReceive(context: Context, intent: Intent) {
|
||||
|
||||
if (ACTION_RECEIVED_STATUS == intent.action) {
|
||||
val statusRecord: Status = intent.getParcelableExtra(STATUS)
|
||||
CentralLog.d(TAG, "Status received: ${statusRecord.msg}")
|
||||
val status: Status? = intent.getParcelableExtra(STATUS)
|
||||
status?.let {
|
||||
CentralLog.d(TAG, "Status received: ${it.msg}")
|
||||
|
||||
if (statusRecord.msg.isNotEmpty()) {
|
||||
val statusRecord = StatusRecord(statusRecord.msg)
|
||||
if (it.msg.isNotEmpty()) {
|
||||
val statusRecord = StatusRecord(it.msg)
|
||||
launch {
|
||||
statusRecordStorage.saveRecord(statusRecord)
|
||||
}
|
||||
|
@ -658,6 +709,7 @@ class BluetoothMonitoringService : LifecycleService(), CoroutineScope {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class Command(val index: Int, val string: String) {
|
||||
INVALID(-1, "INVALID"),
|
||||
|
@ -713,6 +765,4 @@ class BluetoothMonitoringService : LifecycleService(), CoroutineScope {
|
|||
const val blacklistDuration: Long = BuildConfig.BLACKLIST_DURATION
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
package au.gov.health.covidsafe.services
|
||||
|
||||
import au.gov.health.covidsafe.*
|
||||
import au.gov.health.covidsafe.Utils.gotoPlayStore
|
||||
import au.gov.health.covidsafe.logging.CentralLog
|
||||
import com.google.firebase.messaging.FirebaseMessagingService
|
||||
import com.google.firebase.messaging.RemoteMessage
|
||||
|
||||
private const val TAG = "CovidFirebaseMessagingService"
|
||||
|
||||
class CovidFirebaseMessagingService : FirebaseMessagingService() {
|
||||
|
||||
/**
|
||||
* Called when message is received.
|
||||
*
|
||||
* @param remoteMessage Object representing the message received from Firebase Cloud Messaging.
|
||||
*/
|
||||
override fun onMessageReceived(remoteMessage: RemoteMessage) {
|
||||
// There are two types of messages data messages and notification messages. Data messages are handled
|
||||
// here in onMessageReceived whether the app is in the foreground or background. Data messages are the type
|
||||
// traditionally used with GCM. Notification messages are only received here in onMessageReceived when the app
|
||||
// is in the foreground. When the app is in the background an automatically generated notification is displayed.
|
||||
// When the user taps on the notification they are returned to the app. Messages containing both notification
|
||||
// and data payloads are treated as notification messages. The Firebase console always sends notification
|
||||
// messages. For more see: https://firebase.google.com/docs/cloud-messaging/concept-options
|
||||
|
||||
// Not getting messages here? See why this may be: https://goo.gl/39bRNJ
|
||||
CentralLog.d(TAG, "onMessageReceived() received message from ${remoteMessage.from}")
|
||||
|
||||
// log notification payload.
|
||||
remoteMessage.notification?.let {
|
||||
CentralLog.d(TAG, "onMessageReceived() notification = ${it.title} ${it.body} ${it.clickAction}")
|
||||
|
||||
if (it.clickAction == "au.gov.health.covidsafe.UPGRADE_APP"){
|
||||
gotoPlayStore(applicationContext)
|
||||
}
|
||||
}
|
||||
|
||||
// log data payload.
|
||||
remoteMessage.data.isNotEmpty().let {
|
||||
CentralLog.d(TAG, "onMessageReceived() data = " + remoteMessage.data)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when InstanceID token is updated.
|
||||
*/
|
||||
override fun onNewToken(token: String) {
|
||||
CentralLog.d(TAG, "onNewToken() InstanceID = $token")
|
||||
|
||||
Preference.putFirebaseInstanceID(TracerApp.AppContext, token)
|
||||
}
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
package au.gov.health.covidsafe.services
|
||||
|
||||
import android.app.Service
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.hardware.Sensor
|
||||
import android.hardware.SensorEvent
|
||||
import android.hardware.SensorEventListener
|
||||
import android.hardware.SensorManager
|
||||
import android.os.Binder
|
||||
import android.os.IBinder
|
||||
import au.gov.health.covidsafe.logging.CentralLog
|
||||
import kotlin.math.sqrt
|
||||
|
||||
class SensorMonitoringService : Service(), SensorEventListener {
|
||||
private lateinit var sensorManager: SensorManager
|
||||
private var _light: FloatArray? = null
|
||||
private var _proximity: FloatArray? = null
|
||||
private val binder = LocalBinder()
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
|
||||
|
||||
val proximitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY)
|
||||
val lightSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT)
|
||||
|
||||
if (proximitySensor != null) {
|
||||
CentralLog.d(TAG, "Proximity sensor: $proximitySensor")
|
||||
sensorManager.registerListener(this, proximitySensor, SENSOR_DELAY_SUPER_SLOW)
|
||||
|
||||
} else {
|
||||
CentralLog.d(TAG, "Proximity sensor not available")
|
||||
}
|
||||
|
||||
if (lightSensor != null) {
|
||||
CentralLog.d(TAG, "Light sensor: $lightSensor")
|
||||
sensorManager.registerListener(this, lightSensor, SENSOR_DELAY_SUPER_SLOW)
|
||||
} else {
|
||||
CentralLog.d(TAG, "Light sensor not available")
|
||||
}
|
||||
|
||||
CentralLog.d(TAG, "SensorMonitoringService started")
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
sensorManager.unregisterListener(this)
|
||||
CentralLog.d(TAG, "SensorMonitoringService destroyed")
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
inner class LocalBinder : Binder() {
|
||||
fun getService(): SensorMonitoringService = this@SensorMonitoringService
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent): IBinder {
|
||||
return binder
|
||||
}
|
||||
|
||||
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
|
||||
CentralLog.d(TAG, "Sensor accuracy changed! $sensor")
|
||||
}
|
||||
|
||||
override fun onSensorChanged(event: SensorEvent) {
|
||||
when (event.sensor.type) {
|
||||
Sensor.TYPE_PROXIMITY -> {
|
||||
_proximity = event.values
|
||||
}
|
||||
Sensor.TYPE_LIGHT -> {
|
||||
_light = event.values
|
||||
}
|
||||
else -> {
|
||||
CentralLog.w(TAG, "Unexpected sensor type changed: ${event.sensor.type}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val proximity
|
||||
get() = if (_proximity != null) {
|
||||
sqrt((_proximity as FloatArray).reduce { acc: Float, n: Float -> acc + n * n })
|
||||
} else {
|
||||
-1.0f
|
||||
}
|
||||
|
||||
val light
|
||||
get() = if (_light != null) {
|
||||
sqrt((_light as FloatArray).reduce { acc: Float, n: Float -> acc + n * n })
|
||||
} else {
|
||||
-1.0f
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TAG = "SensorMonitoringService"
|
||||
const val SENSOR_DELAY_SUPER_SLOW = 3_000_000
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@ import android.bluetooth.le.ScanResult
|
|||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.os.Handler
|
||||
import au.gov.health.covidsafe.Utils
|
||||
import au.gov.health.covidsafe.ui.utils.Utils
|
||||
import au.gov.health.covidsafe.bluetooth.BLEScanner
|
||||
import au.gov.health.covidsafe.logging.CentralLog
|
||||
import au.gov.health.covidsafe.status.Status
|
||||
|
|
|
@ -9,8 +9,8 @@ import android.os.Handler
|
|||
import androidx.annotation.Keep
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||
import au.gov.health.covidsafe.BuildConfig
|
||||
import au.gov.health.covidsafe.TracerApp
|
||||
import au.gov.health.covidsafe.Utils
|
||||
import au.gov.health.covidsafe.app.TracerApp
|
||||
import au.gov.health.covidsafe.ui.utils.Utils
|
||||
import au.gov.health.covidsafe.bluetooth.gatt.*
|
||||
import au.gov.health.covidsafe.logging.CentralLog
|
||||
import au.gov.health.covidsafe.services.BluetoothMonitoringService
|
||||
|
|
|
@ -8,14 +8,12 @@ import androidx.room.Room
|
|||
import androidx.room.RoomDatabase
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import au.gov.health.covidsafe.LocalBlobV2
|
||||
import au.gov.health.covidsafe.ui.utils.LocalBlobV2
|
||||
import au.gov.health.covidsafe.logging.CentralLog
|
||||
import au.gov.health.covidsafe.status.persistence.StatusRecord
|
||||
import au.gov.health.covidsafe.status.persistence.StatusRecordDao
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
|
||||
const val CURRENT_DB_VERSION = 3
|
||||
|
||||
|
@ -31,7 +29,7 @@ abstract class StreetPassRecordDatabase : RoomDatabase() {
|
|||
|
||||
companion object {
|
||||
|
||||
private val TAG = this.javaClass.simpleName
|
||||
private val TAG = this::class.java.simpleName
|
||||
|
||||
private const val ID_COLUMN_INDEX = 0
|
||||
private const val TIMESTAMP_COLUMN_INDEX = 1
|
||||
|
@ -147,12 +145,12 @@ abstract class StreetPassRecordDatabase : RoomDatabase() {
|
|||
val localBlob: String = if (version == 1) {
|
||||
ENCRYPTED_EMPTY_DICT
|
||||
} else {
|
||||
val modelP = if (DUMMY_DEVICE == modelP) null else modelP
|
||||
val modelC = if (DUMMY_DEVICE == modelC) null else modelC
|
||||
val rssi = if (DUMMY_RSSI == rssi) null else rssi
|
||||
val txPower = if (DUMMY_TXPOWER == txPower) null else txPower
|
||||
val plainRecord = gson.toJson(LocalBlobV2(modelP, modelC, rssi, txPower)).toByteArray(Charsets.UTF_8)
|
||||
Encryption.encryptPayload(plainRecord)
|
||||
val colModelP = if (DUMMY_DEVICE == modelP) null else modelP
|
||||
val colModelC = if (DUMMY_DEVICE == modelC) null else modelC
|
||||
val colRssi = if (DUMMY_RSSI == rssi) null else rssi
|
||||
val colTxPower = if (DUMMY_TXPOWER == txPower) null else txPower
|
||||
val updatedPlainRecord = gson.toJson(LocalBlobV2(colModelP, colModelC, colRssi, colTxPower)).toByteArray(Charsets.UTF_8)
|
||||
Encryption.encryptPayload(updatedPlainRecord)
|
||||
}
|
||||
contentValues.put("v", VERSION_TWO)
|
||||
contentValues.put("org", org)
|
||||
|
|
|
@ -3,7 +3,7 @@ package au.gov.health.covidsafe.talkback
|
|||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import au.gov.health.covidsafe.R
|
||||
import au.gov.health.covidsafe.TracerApp
|
||||
import au.gov.health.covidsafe.app.TracerApp
|
||||
import au.gov.health.covidsafe.logging.CentralLog
|
||||
import java.lang.StringBuilder
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package au.gov.health.covidsafe.ui
|
||||
package au.gov.health.covidsafe.ui.base
|
||||
|
||||
import android.content.res.Configuration
|
||||
import android.os.Bundle
|
||||
|
@ -6,8 +6,6 @@ import android.view.View
|
|||
import androidx.fragment.app.Fragment
|
||||
import androidx.navigation.Navigator
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
import au.gov.health.covidsafe.HasBlockingState
|
||||
import kotlinx.android.synthetic.main.fragment_intro.*
|
||||
|
||||
open class BaseFragment : Fragment() {
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
package au.gov.health.covidsafe.ui.base
|
||||
|
||||
import android.graphics.Typeface
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.databinding.BindingAdapter
|
||||
import au.gov.health.covidsafe.extensions.fromHtml
|
||||
import au.gov.health.covidsafe.ui.home.view.ExternalLinkCard
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
@BindingAdapter("visibility")
|
||||
fun setVisibility(view: View, isVisible: Boolean?) {
|
||||
isVisible?.let {
|
||||
view.visibility = if (isVisible) View.VISIBLE else View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("addUnderline")
|
||||
fun setUnderlineText(textView: TextView, text: String?) {
|
||||
text?.let {
|
||||
textView.text = fromHtml("<u>$text</u>")
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("externalCardTitle")
|
||||
fun setExternalCardTitle(view: ExternalLinkCard, text: Int?) {
|
||||
text?.let {
|
||||
view.setTitleTextTypeFace(Typeface.DEFAULT_BOLD)
|
||||
view.setTitleText(String.format("%,d", it))
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("stateCaseNumberFormat")
|
||||
fun setStateCaseNumberFormat(view: TextView, text: Int?) {
|
||||
text?.let {
|
||||
view.text = String.format("%,d", it)
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("dateFormat")
|
||||
fun setDateFormat(textView: TextView, dateString: String?) {
|
||||
dateString?.let {
|
||||
val cal = Calendar.getInstance()
|
||||
val timeZoneID = "Australia/Sydney"
|
||||
val tz = TimeZone.getTimeZone(timeZoneID)
|
||||
val dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm", Locale.getDefault())
|
||||
dateFormat.timeZone = tz
|
||||
cal.time = dateFormat.parse(it)
|
||||
val convertedDateString = SimpleDateFormat("dd MMMM yyyy", Locale.getDefault()).format(cal.time)
|
||||
val convertedTimeString = SimpleDateFormat("h a", Locale.getDefault()).format(cal.time)
|
||||
|
||||
val finalDisplayDateFormat = "$convertedDateString at $convertedTimeString AEST"
|
||||
textView.text = finalDisplayDateFormat
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package au.gov.health.covidsafe
|
||||
package au.gov.health.covidsafe.ui.base
|
||||
|
||||
interface HasBlockingState {
|
||||
var isUiBlocked: Boolean
|
|
@ -1,4 +1,4 @@
|
|||
package au.gov.health.covidsafe.ui
|
||||
package au.gov.health.covidsafe.ui.base
|
||||
|
||||
import android.view.View
|
||||
import androidx.annotation.StringRes
|
|
@ -1,4 +1,4 @@
|
|||
package au.gov.health.covidsafe.ui
|
||||
package au.gov.health.covidsafe.ui.base
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
package au.gov.health.covidsafe
|
||||
package au.gov.health.covidsafe.ui.connection
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import au.gov.health.covidsafe.R
|
||||
import kotlinx.android.synthetic.main.activity_internet_connection_issues.*
|
||||
import kotlinx.android.synthetic.main.activity_onboarding.toolbar
|
||||
|
|
@ -1,14 +1,10 @@
|
|||
package au.gov.health.covidsafe
|
||||
package au.gov.health.covidsafe.ui.devicename
|
||||
|
||||
import android.bluetooth.BluetoothAdapter
|
||||
import android.os.Bundle
|
||||
import android.provider.Settings
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import au.gov.health.covidsafe.logging.CentralLog
|
||||
import au.gov.health.covidsafe.scheduler.GetMessagesScheduler
|
||||
import au.gov.health.covidsafe.ui.home.HomeFragment
|
||||
import com.google.android.gms.tasks.OnCompleteListener
|
||||
import com.google.firebase.iid.FirebaseInstanceId
|
||||
import au.gov.health.covidsafe.R
|
||||
import kotlinx.android.synthetic.main.activity_device_name_change_prompt.*
|
||||
import kotlinx.android.synthetic.main.fragment_permission_device_name.*
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package au.gov.health.covidsafe.ui.home
|
||||
|
||||
enum class CaseNumbersState(state: Int) {
|
||||
LOADING(0),
|
||||
SUCCESS(1),
|
||||
ERROR_NO_NETWORK(2),
|
||||
ERROR_UNKNOWN(3),
|
||||
}
|
|
@ -14,7 +14,7 @@ import androidx.core.view.isVisible
|
|||
import androidx.navigation.fragment.findNavController
|
||||
import au.gov.health.covidsafe.R
|
||||
import au.gov.health.covidsafe.links.LinkBuilder
|
||||
import au.gov.health.covidsafe.ui.BaseFragment
|
||||
import au.gov.health.covidsafe.ui.base.BaseFragment
|
||||
import com.atlassian.mobilekit.module.feedback.FeedbackModule
|
||||
import kotlinx.android.synthetic.main.fragment_help.*
|
||||
import kotlinx.android.synthetic.main.fragment_help.view.*
|
||||
|
|
|
@ -4,11 +4,8 @@ import android.Manifest
|
|||
import android.annotation.SuppressLint
|
||||
import android.bluetooth.BluetoothAdapter
|
||||
import android.content.*
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.graphics.Typeface
|
||||
import android.os.Bundle
|
||||
import android.provider.Settings
|
||||
import android.text.Html
|
||||
import android.text.method.LinkMovementMethod
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
|
@ -16,92 +13,207 @@ import android.view.View.GONE
|
|||
import android.view.View.VISIBLE
|
||||
import android.view.ViewGroup
|
||||
import android.view.accessibility.AccessibilityEvent
|
||||
import android.widget.LinearLayout
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.children
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import au.gov.health.covidsafe.*
|
||||
import au.gov.health.covidsafe.app.TracerApp
|
||||
import au.gov.health.covidsafe.databinding.FragmentHomeBinding
|
||||
import au.gov.health.covidsafe.extensions.*
|
||||
import au.gov.health.covidsafe.links.LinkBuilder
|
||||
import au.gov.health.covidsafe.logging.CentralLog
|
||||
import au.gov.health.covidsafe.networking.response.MessagesResponse
|
||||
import au.gov.health.covidsafe.notifications.NotificationBuilder
|
||||
import au.gov.health.covidsafe.preference.Preference
|
||||
import au.gov.health.covidsafe.talkback.setHeading
|
||||
import au.gov.health.covidsafe.ui.BaseFragment
|
||||
import au.gov.health.covidsafe.ui.home.view.ExternalLinkCard
|
||||
import au.gov.health.covidsafe.ui.base.BaseFragment
|
||||
import au.gov.health.covidsafe.utils.NetworkConnectionCheck
|
||||
import kotlinx.android.synthetic.main.fragment_home_case_statistics.*
|
||||
import kotlinx.android.synthetic.main.fragment_home.*
|
||||
import kotlinx.android.synthetic.main.fragment_home.view.*
|
||||
import kotlinx.android.synthetic.main.fragment_home_external_links.*
|
||||
import kotlinx.android.synthetic.main.fragment_home_setup_complete_header.*
|
||||
import kotlinx.android.synthetic.main.fragment_home_setup_incomplete_content.*
|
||||
import kotlinx.android.synthetic.main.fragment_home_header.*
|
||||
import kotlinx.android.synthetic.main.view_covid_share_tile.*
|
||||
import kotlinx.android.synthetic.main.view_help_topics_tile.*
|
||||
import kotlinx.android.synthetic.main.view_home_setup_complete.*
|
||||
import kotlinx.android.synthetic.main.view_home_setup_incomplete.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import pub.devrel.easypermissions.AppSettingsDialog
|
||||
import pub.devrel.easypermissions.EasyPermissions
|
||||
import java.lang.ref.WeakReference
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
|
||||
private const val TAG = "HomeFragment"
|
||||
|
||||
private const val ONE_DAY_IN_MILLIS = 24 * 60 * 60 * 1000L
|
||||
private const val FOURTEEN_DAYS_IN_MILLIS = 14 * ONE_DAY_IN_MILLIS
|
||||
|
||||
class HomeFragment : BaseFragment(), EasyPermissions.PermissionCallbacks {
|
||||
class HomeFragment : BaseFragment(), EasyPermissions.PermissionCallbacks, NetworkConnectionCheck.NetworkConnectionListener {
|
||||
|
||||
companion object {
|
||||
var instanceWeakRef: WeakReference<HomeFragment>? = null
|
||||
}
|
||||
|
||||
private lateinit var presenter: HomePresenter
|
||||
private val homeFragmentViewModel: HomeFragmentViewModel by viewModels()
|
||||
|
||||
private var mIsBroadcastListenerRegistered = false
|
||||
|
||||
private var counter: Int = 0
|
||||
|
||||
private val mBroadcastListener: BroadcastReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
val action = intent.action
|
||||
if (action == BluetoothAdapter.ACTION_STATE_CHANGED) {
|
||||
when (intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1)) {
|
||||
BluetoothAdapter.STATE_OFF -> {
|
||||
bluetooth_card_view.render(formatBlueToothTitle(false), false)
|
||||
refreshSetupCompleteOrIncompleteUi()
|
||||
}
|
||||
BluetoothAdapter.STATE_TURNING_OFF -> {
|
||||
bluetooth_card_view.render(formatBlueToothTitle(false), false)
|
||||
refreshSetupCompleteOrIncompleteUi()
|
||||
}
|
||||
BluetoothAdapter.STATE_ON -> {
|
||||
bluetooth_card_view.render(formatBlueToothTitle(true), true)
|
||||
refreshSetupCompleteOrIncompleteUi()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private var checkIsInternetConnected = false
|
||||
private var isAppWithLatestVersion = false
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
initializeObservers()
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
presenter = HomePresenter(this)
|
||||
return inflater.inflate(R.layout.fragment_home, container, false)
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return FragmentHomeBinding.inflate(layoutInflater).apply {
|
||||
lifecycleOwner = viewLifecycleOwner
|
||||
viewModel = homeFragmentViewModel
|
||||
}.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
view.home_header_help.setOnClickListener {
|
||||
initializeSettingsNavigation()
|
||||
setAppVersionNumber()
|
||||
initializeDebugTestActivity()
|
||||
initializeNoNetworkError()
|
||||
initializeRefreshButton()
|
||||
|
||||
initializePullToRefresh()
|
||||
|
||||
NetworkConnectionCheck.addNetworkChangedListener(requireContext(), this)
|
||||
}
|
||||
|
||||
private fun initializeNoNetworkError() {
|
||||
no_network_error_text_view.setOnClickListener {
|
||||
startActivity(Intent(android.provider.Settings.ACTION_WIRELESS_SETTINGS))
|
||||
}
|
||||
}
|
||||
|
||||
private fun initializeRefreshButton() {
|
||||
refresh_button.setOnClickListener {
|
||||
initiateFetchingCaseNumbers()
|
||||
}
|
||||
}
|
||||
|
||||
private fun initializePullToRefresh() {
|
||||
swipeRefreshLayout.setOnRefreshListener {
|
||||
initiateFetchingCaseNumbers()
|
||||
}
|
||||
}
|
||||
|
||||
private fun initiateFetchingCaseNumbers() {
|
||||
lifecycleScope.launch {
|
||||
homeFragmentViewModel.fetchGetCaseStatistics(lifecycle)
|
||||
}
|
||||
}
|
||||
|
||||
private fun initializeObservers() {
|
||||
(activity as HomeActivity?)?.run {
|
||||
isAppUpdateAvailableLiveData.observe(this@HomeFragment, latestAppAvailable)
|
||||
isWindowFocusChangeLiveData.observe(this@HomeFragment, refreshUiObserver)
|
||||
}
|
||||
}
|
||||
|
||||
private val latestAppAvailable = Observer<Boolean> {
|
||||
isAppWithLatestVersion = it
|
||||
refreshSetupCompleteOrIncompleteUi()
|
||||
showCovidThanksMessage()
|
||||
}
|
||||
|
||||
private val refreshUiObserver = Observer<Boolean> {
|
||||
refreshSetupCompleteOrIncompleteUi()
|
||||
|
||||
if (it) {
|
||||
initiateFetchingCaseNumbers()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
// disable the app update reminder for now
|
||||
app_update_reminder.visibility = GONE
|
||||
|
||||
initializePermissionViewButtonClickListeners()
|
||||
|
||||
initializeUploadTestDataNavigation()
|
||||
|
||||
initializeAppShareNavigation()
|
||||
initializeHelpTopicsNavigation()
|
||||
initializeChangeLanguageNavigation()
|
||||
|
||||
registerBroadcastListener()
|
||||
|
||||
refreshSetupCompleteOrIncompleteUi()
|
||||
|
||||
updateHealthOfficialTile()
|
||||
initializeBluetoothPairingInfo()
|
||||
}
|
||||
|
||||
private fun initializeSettingsNavigation() {
|
||||
home_header_settings.setOnClickListener {
|
||||
navigateToSettingsFragment()
|
||||
}
|
||||
}
|
||||
|
||||
private fun navigateToSettingsFragment() {
|
||||
findNavController().navigate(HomeFragmentDirections.actionHomeFragmentToSettingsFragment())
|
||||
}
|
||||
|
||||
private fun setAppVersionNumber() {
|
||||
home_version_number.text = context?.getAppVersionNumberDetails()
|
||||
}
|
||||
|
||||
private fun initializePermissionViewButtonClickListeners() {
|
||||
bluetooth_card_view.setOnClickListener { requestBlueToothPermissionThenNextPermission() }
|
||||
location_card_view.setOnClickListener { askForLocationPermission() }
|
||||
battery_card_view.setOnClickListener { excludeFromBatteryOptimization() }
|
||||
}
|
||||
|
||||
private fun initializeUploadTestDataNavigation() {
|
||||
home_been_tested_button.setOnClickListener {
|
||||
navigateTo(R.id.action_home_to_selfIsolate)
|
||||
}
|
||||
}
|
||||
|
||||
private fun registerBroadcastListener() {
|
||||
if (!mIsBroadcastListenerRegistered) {
|
||||
registerBroadcast()
|
||||
}
|
||||
}
|
||||
|
||||
private fun initializeAppShareNavigation() {
|
||||
app_share.setOnClickListener {
|
||||
context?.shareThisApp()
|
||||
}
|
||||
}
|
||||
|
||||
private fun initializeHelpTopicsNavigation() {
|
||||
help_topics_link.setOnClickListener {
|
||||
HelpFragment.anchor = null
|
||||
findNavController().navigate(HomeFragmentDirections.actionHomeFragmentToHelpFragment())
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private fun initializeChangeLanguageNavigation() {
|
||||
change_language_link.setOnClickListener {
|
||||
HelpFragment.anchor = "#other-languages"
|
||||
findNavController().navigate(HomeFragmentDirections.actionHomeFragmentToHelpFragment())
|
||||
}
|
||||
}
|
||||
|
||||
private fun initializeBluetoothPairingInfo() {
|
||||
home_header_no_bluetooth_pairing.text = LinkBuilder.getNoBluetoothPairingContent(requireContext())
|
||||
home_header_no_bluetooth_pairing.movementMethod = LinkMovementMethod.getInstance()
|
||||
}
|
||||
|
||||
private fun initializeDebugTestActivity() {
|
||||
if (BuildConfig.ENABLE_DEBUG_SCREEN) {
|
||||
view.header_background.setOnClickListener {
|
||||
header_background.setOnClickListener {
|
||||
counter++
|
||||
if (counter >= 2) {
|
||||
counter = 0
|
||||
|
@ -109,69 +221,25 @@ class HomeFragment : BaseFragment(), EasyPermissions.PermissionCallbacks {
|
|||
}
|
||||
}
|
||||
}
|
||||
home_version_number.text = getString(R.string.home_version_number, BuildConfig.VERSION_NAME)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
instanceWeakRef = WeakReference(this)
|
||||
|
||||
// disable the app update reminder for now
|
||||
app_update_reminder.visibility = GONE
|
||||
|
||||
bluetooth_card_view.setOnClickListener { requestBlueToothPermissionThenNextPermission() }
|
||||
location_card_view.setOnClickListener { askForLocationPermission() }
|
||||
battery_card_view.setOnClickListener { excludeFromBatteryOptimization() }
|
||||
|
||||
home_been_tested_button.setOnClickListener {
|
||||
navigateTo(R.id.action_home_to_selfIsolate)
|
||||
}
|
||||
home_setup_complete_share.setOnClickListener {
|
||||
shareThisApp()
|
||||
}
|
||||
home_setup_complete_news.setOnClickListener {
|
||||
goToNewsWebsite()
|
||||
}
|
||||
home_setup_complete_app.setOnClickListener {
|
||||
goToCovidApp()
|
||||
}
|
||||
|
||||
help_topics_link.setOnClickListener {
|
||||
HelpFragment.anchor = null
|
||||
findNavController().navigate(HomeFragmentDirections.actionHomeFragmentToHelpFragment())
|
||||
}
|
||||
|
||||
change_language_link.setOnClickListener {
|
||||
HelpFragment.anchor = "#other-languages"
|
||||
findNavController().navigate(HomeFragmentDirections.actionHomeFragmentToHelpFragment())
|
||||
}
|
||||
|
||||
if (!mIsBroadcastListenerRegistered) {
|
||||
registerBroadcast()
|
||||
}
|
||||
refreshSetupCompleteOrIncompleteUi()
|
||||
|
||||
home_header_no_bluetooth_pairing.text = LinkBuilder.getNoBluetoothPairingContent(requireContext())
|
||||
home_header_no_bluetooth_pairing.movementMethod = LinkMovementMethod.getInstance()
|
||||
|
||||
updateNotificationStatusTile()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
|
||||
instanceWeakRef = null
|
||||
unregisterAllClickListener()
|
||||
unregisterBroadcastListener()
|
||||
}
|
||||
|
||||
private fun unregisterAllClickListener() {
|
||||
bluetooth_card_view.setOnClickListener(null)
|
||||
location_card_view.setOnClickListener(null)
|
||||
battery_card_view.setOnClickListener(null)
|
||||
home_been_tested_button.setOnClickListener(null)
|
||||
home_setup_complete_share.setOnClickListener(null)
|
||||
home_setup_complete_news.setOnClickListener(null)
|
||||
home_setup_complete_app.setOnClickListener(null)
|
||||
app_share.setOnClickListener(null)
|
||||
help_topics_link.setOnClickListener(null)
|
||||
}
|
||||
|
||||
private fun unregisterBroadcastListener() {
|
||||
activity?.let { activity ->
|
||||
if (mIsBroadcastListenerRegistered) {
|
||||
activity.unregisterReceiver(mBroadcastListener)
|
||||
|
@ -182,12 +250,26 @@ class HomeFragment : BaseFragment(), EasyPermissions.PermissionCallbacks {
|
|||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
|
||||
NetworkConnectionCheck.removeNetworkChangedListener(this)
|
||||
home_root.removeAllViews()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
unregisterObservers()
|
||||
}
|
||||
|
||||
private fun unregisterObservers() {
|
||||
(activity as HomeActivity?)?.run {
|
||||
isAppUpdateAvailableLiveData.removeObserver(latestAppAvailable)
|
||||
isWindowFocusChangeLiveData.removeObserver(refreshUiObserver)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isDataUploadedInPast14Days(context: Context): Boolean {
|
||||
val isUploaded = Preference.isDataUploaded(context)
|
||||
|
||||
CentralLog.d(TAG, "isDataUploadedInPast14Days : $isUploaded")
|
||||
if (!isUploaded) {
|
||||
return false
|
||||
}
|
||||
|
@ -205,97 +287,88 @@ class HomeFragment : BaseFragment(), EasyPermissions.PermissionCallbacks {
|
|||
|
||||
@SuppressLint("SetTextI18n")
|
||||
fun refreshSetupCompleteOrIncompleteUi() {
|
||||
lifecycleScope.launch(Dispatchers.Main) {
|
||||
CentralLog.d(TAG, "refreshSetupCompleteOrIncompleteUi")
|
||||
context?.let {
|
||||
val isAllPermissionsEnabled = allPermissionsEnabled()
|
||||
val isAllPermissionsEnabled = it.allPermissionsEnabled()
|
||||
if (!isAllPermissionsEnabled) {
|
||||
NotificationBuilder.clearPossibleIssueNotificationCheck()
|
||||
}
|
||||
val isDataUploadedInPast14Days = isDataUploadedInPast14Days(it)
|
||||
|
||||
val line1 = it.getString(
|
||||
updateSetupCompleteStatus(isAllPermissionsEnabled)
|
||||
updateSetupCompleteHeaderTitle1(it, isAllPermissionsEnabled, isDataUploadedInPast14Days)
|
||||
updateSetupCompleteHeaderTitle2(isAllPermissionsEnabled)
|
||||
updateHealthOfficialTile(isDataUploadedInPast14Days)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateSetupCompleteHeaderTitle1(context: Context, isAllPermissionsEnabled: Boolean, isDataUploadedInPast14Days: Boolean) {
|
||||
showLastDataUploadedInfo(context, isDataUploadedInPast14Days)
|
||||
|
||||
home_header_setup_complete_header_line_1.run {
|
||||
text = getString(getCovidActiveStatusMessage(isAllPermissionsEnabled))
|
||||
setHeading()
|
||||
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateSetupCompleteHeaderTitle2(isAllPermissionsEnabled: Boolean) {
|
||||
if (isAllPermissionsEnabled) {
|
||||
R.string.home_header_active_title
|
||||
} else {
|
||||
R.string.home_header_inactive_title
|
||||
}
|
||||
)
|
||||
val isAppPerformanceRequired = !checkIsInternetConnected || !isAppWithLatestVersion
|
||||
|
||||
val line2 = if (isDataUploadedInPast14Days) {
|
||||
it.getString(R.string.home_header_uploaded_on_date, getDataUploadDateHtmlString(it)) + "<br/>"
|
||||
} else {
|
||||
""
|
||||
home_header_setup_complete_header_line_2.run {
|
||||
setTextColor(ContextCompat.getColor(TracerApp.AppContext, if (isAppPerformanceRequired) R.color.error_red else R.color.slate_black_2))
|
||||
typeface = if (isAppPerformanceRequired) Typeface.DEFAULT_BOLD else Typeface.DEFAULT
|
||||
text = fromHtml(getString(if (isAppPerformanceRequired) R.string.improve else R.string.home_header_active_no_action_required))
|
||||
}
|
||||
|
||||
val line3 = it.getString(
|
||||
active_status_layout.setOnClickListener {
|
||||
if (isAppPerformanceRequired) {
|
||||
navigateToSettingsFragment()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showLastDataUploadedInfo(context: Context, isDataUploadedInPast14Days: Boolean) {
|
||||
if (isDataUploadedInPast14Days) {
|
||||
data_last_uploaded_layout.visibility = VISIBLE
|
||||
val appendUploadInfo = getString(R.string.home_header_uploaded_on_date, getDataUploadDateHtmlString(context))
|
||||
home_header_no_last_updated_text_view.text = fromHtml(appendUploadInfo)
|
||||
} else {
|
||||
data_last_uploaded_layout.visibility = GONE
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateHealthOfficialTile(isDataUploadedInPast14Days: Boolean) {
|
||||
home_been_tested_button.visibility = if (isDataUploadedInPast14Days) GONE else VISIBLE
|
||||
}
|
||||
|
||||
private fun updateSetupCompleteStatus(isAllPermissionsEnabled: Boolean) {
|
||||
if (isAllPermissionsEnabled) {
|
||||
R.string.home_header_active_no_action_required
|
||||
home_setup_incomplete_permissions_layout.visibility = GONE
|
||||
home_setup_complete_layout.visibility = VISIBLE
|
||||
} else {
|
||||
R.string.home_header_inactive_check_your_permissions
|
||||
}
|
||||
)
|
||||
|
||||
home_header_setup_complete_header_line_1.text = line1
|
||||
|
||||
home_header_setup_complete_header_line_1.setHeading()
|
||||
home_header_setup_complete_header_line_1.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED)
|
||||
|
||||
val line2and3 = "$line2$line3"
|
||||
|
||||
home_header_setup_complete_header_line_2.text =
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
|
||||
Html.fromHtml(line2and3, Html.FROM_HTML_MODE_COMPACT)
|
||||
} else {
|
||||
Html.fromHtml(line2and3)
|
||||
}
|
||||
|
||||
if (isAllPermissionsEnabled) {
|
||||
home_header_top_left_icon.visibility = GONE
|
||||
home_header_picture_setup_complete.layoutParams.let { layoutParams ->
|
||||
val size = resources.getDimensionPixelSize(R.dimen.covidsafe_lottie_size)
|
||||
layoutParams.height = size
|
||||
layoutParams.width = size
|
||||
}
|
||||
home_header_picture_setup_complete.setAnimation("spinner_home.json")
|
||||
home_header_picture_setup_complete.resumeAnimation()
|
||||
|
||||
content_setup_incomplete_group.visibility = GONE
|
||||
ContextCompat.getColor(it, R.color.lighter_green).let { bgColor ->
|
||||
header_background.setBackgroundColor(bgColor)
|
||||
header_background_overlap.setBackgroundColor(bgColor)
|
||||
}
|
||||
} else {
|
||||
home_header_top_left_icon.visibility = VISIBLE
|
||||
home_header_picture_setup_complete.layoutParams.let { layoutParams ->
|
||||
val size = resources.getDimensionPixelSize(R.dimen.keyline_8)
|
||||
layoutParams.height = size
|
||||
layoutParams.width = size
|
||||
}
|
||||
home_header_picture_setup_complete.setImageResource(R.drawable.ic_red_cross_no_circle)
|
||||
|
||||
content_setup_incomplete_group.visibility = VISIBLE
|
||||
home_setup_incomplete_permissions_layout.visibility = VISIBLE
|
||||
home_setup_complete_layout.visibility = GONE
|
||||
updateBlueToothStatus()
|
||||
updateBatteryOptimizationStatus()
|
||||
updateLocationStatus()
|
||||
ContextCompat.getColor(it, R.color.grey).let { bgColor ->
|
||||
header_background.setBackgroundColor(bgColor)
|
||||
header_background_overlap.setBackgroundColor(bgColor)
|
||||
}
|
||||
}
|
||||
|
||||
home_been_tested_button.visibility = if (isDataUploadedInPast14Days) GONE else VISIBLE
|
||||
private fun getCovidActiveStatusMessage(isAllPermissionsEnabled: Boolean): Int {
|
||||
return if (isAllPermissionsEnabled) {
|
||||
if (isShowThanksCovidMsg(isAllPermissionsEnabled))
|
||||
R.string.home_header_active_title_thanks
|
||||
else R.string.home_header_active_title
|
||||
} else {
|
||||
R.string.home_header_inactive_title
|
||||
}
|
||||
}
|
||||
|
||||
private fun allPermissionsEnabled(): Boolean {
|
||||
val context = requireContext()
|
||||
|
||||
val bluetoothEnabled = context.isBlueToothEnabled() ?: false
|
||||
val nonBatteryOptimizationAllowed = context.isBatteryOptimizationDisabled() ?: true
|
||||
val locationStatusAllowed = context.isLocationPermissionAllowed() ?: true
|
||||
|
||||
return bluetoothEnabled &&
|
||||
nonBatteryOptimizationAllowed &&
|
||||
locationStatusAllowed &&
|
||||
context.isLocationEnabledOnDevice()
|
||||
}
|
||||
|
||||
private fun registerBroadcast() {
|
||||
activity?.let { activity ->
|
||||
var f = IntentFilter()
|
||||
|
@ -308,32 +381,33 @@ class HomeFragment : BaseFragment(), EasyPermissions.PermissionCallbacks {
|
|||
}
|
||||
}
|
||||
|
||||
private fun shareThisApp() {
|
||||
val newIntent = Intent(Intent.ACTION_SEND)
|
||||
newIntent.type = "text/plain"
|
||||
newIntent.putExtra(Intent.EXTRA_TEXT, getString(R.string.share_this_app_content))
|
||||
startActivity(Intent.createChooser(newIntent, null))
|
||||
}
|
||||
|
||||
private fun updateBlueToothStatus() {
|
||||
requireContext().isBlueToothEnabled()?.let {
|
||||
bluetooth_card_view.visibility = VISIBLE
|
||||
if (!it) {
|
||||
bluetooth_card_view_layout.visibility = VISIBLE
|
||||
bluetooth_card_view.render(formatBlueToothTitle(it), it)
|
||||
} else {
|
||||
bluetooth_card_view_layout.visibility = GONE
|
||||
}
|
||||
} ?: run {
|
||||
bluetooth_card_view.visibility = GONE
|
||||
bluetooth_card_view_layout.visibility = GONE
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateBatteryOptimizationStatus() {
|
||||
requireContext().isBatteryOptimizationDisabled()?.let {
|
||||
battery_card_view.visibility = VISIBLE
|
||||
if (!it) {
|
||||
battery_card_view_layout.visibility = VISIBLE
|
||||
battery_card_view.render(
|
||||
formatNonBatteryOptimizationTitle(!it),
|
||||
it,
|
||||
getString(R.string.battery_optimisation_prompt)
|
||||
)
|
||||
} else {
|
||||
battery_card_view_layout.visibility = GONE
|
||||
}
|
||||
} ?: run {
|
||||
battery_card_view.visibility = GONE
|
||||
battery_card_view_layout.visibility = GONE
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -341,11 +415,21 @@ class HomeFragment : BaseFragment(), EasyPermissions.PermissionCallbacks {
|
|||
requireContext().isLocationPermissionAllowed()?.let {
|
||||
val locationWorking = it && requireContext().isLocationEnabledOnDevice()
|
||||
val locationOffPrompts = getString(R.string.home_set_location_why)
|
||||
|
||||
location_card_view.visibility = VISIBLE
|
||||
if (!locationWorking) {
|
||||
location_card_view_layout.visibility = VISIBLE
|
||||
location_card_view.render(formatLocationTitle(locationWorking), locationWorking, locationOffPrompts)
|
||||
} else {
|
||||
location_card_view_layout.visibility = GONE
|
||||
}
|
||||
} ?: run {
|
||||
location_card_view.visibility = GONE
|
||||
location_card_view_layout.visibility = GONE
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateHealthOfficialTile() {
|
||||
home_been_tested_button.run {
|
||||
setTitleTextTypeFace(Typeface.DEFAULT_BOLD)
|
||||
setContentTextTypeFace(Typeface.DEFAULT_BOLD)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -361,10 +445,6 @@ class HomeFragment : BaseFragment(), EasyPermissions.PermissionCallbacks {
|
|||
return resources.getString(R.string.home_non_battery_optimization_permission, getEnabledOrDisabledString(on))
|
||||
}
|
||||
|
||||
private fun formatPushNotificationTitle(on: Boolean): String {
|
||||
return resources.getString(R.string.home_push_notification_permission, getPermissionEnabledTitle(on))
|
||||
}
|
||||
|
||||
private fun getPermissionEnabledTitle(on: Boolean): String {
|
||||
return resources.getString(if (on) R.string.home_permission_on else R.string.home_permission_off)
|
||||
}
|
||||
|
@ -373,34 +453,6 @@ class HomeFragment : BaseFragment(), EasyPermissions.PermissionCallbacks {
|
|||
return resources.getString(if (isEnabled) R.string.enabled else R.string.disabled)
|
||||
}
|
||||
|
||||
private fun goToNewsWebsite() {
|
||||
val url = getString(R.string.home_set_complete_external_link_news_url)
|
||||
try {
|
||||
Intent(Intent.ACTION_VIEW).run {
|
||||
data = Uri.parse(url)
|
||||
startActivity(this)
|
||||
}
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
val intent = Intent(activity, WebViewActivity::class.java)
|
||||
intent.putExtra(WebViewActivity.URL_ARG, url)
|
||||
startActivity(intent)
|
||||
}
|
||||
}
|
||||
|
||||
private fun goToCovidApp() {
|
||||
val url = getString(R.string.home_set_complete_external_link_app_url)
|
||||
try {
|
||||
Intent(Intent.ACTION_VIEW).run {
|
||||
data = Uri.parse(url)
|
||||
startActivity(this)
|
||||
}
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
val intent = Intent(activity, WebViewActivity::class.java)
|
||||
intent.putExtra(WebViewActivity.URL_ARG, url)
|
||||
startActivity(intent)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPermissionsDenied(requestCode: Int, perms: MutableList<String>) {
|
||||
if (requestCode == LOCATION && EasyPermissions.somePermissionPermanentlyDenied(this, listOf(Manifest.permission.ACCESS_COARSE_LOCATION))) {
|
||||
AppSettingsDialog.Builder(this).build().show()
|
||||
|
@ -418,111 +470,44 @@ class HomeFragment : BaseFragment(), EasyPermissions.PermissionCallbacks {
|
|||
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)
|
||||
}
|
||||
|
||||
fun updateConnectionTile(isInternetConnected: Boolean) {
|
||||
// called on IO thread; run the UI logic on UI thread
|
||||
GlobalScope.launch(Dispatchers.Main) {
|
||||
CentralLog.d(TAG, "updateConnectionTile() isInternetConnected = $isInternetConnected")
|
||||
|
||||
var visibility = if (isInternetConnected) GONE else VISIBLE
|
||||
|
||||
// don't display the tile when there's permission not enabled
|
||||
if (!allPermissionsEnabled()) {
|
||||
visibility = GONE
|
||||
private fun isShowThanksCovidMsg(isAllPermissionsEnabled: Boolean): Boolean {
|
||||
return isAllPermissionsEnabled && checkIsInternetConnected && isAppWithLatestVersion && NotificationBuilder.isShowPossibleIssueNotification()
|
||||
}
|
||||
|
||||
improve_performance_card.visibility = visibility
|
||||
internet_connection_tile.visibility = visibility
|
||||
|
||||
if (visibility == VISIBLE) {
|
||||
internet_connection_tile.setOnClickListener {
|
||||
// startActivity(Intent(ACTION_DATA_ROAMING_SETTINGS))
|
||||
// startActivity(Intent(ACTION_WIFI_SETTINGS))
|
||||
|
||||
startActivity(Intent(requireContext(), InternetConnectionIssuesActivity::class.java))
|
||||
}
|
||||
private fun showCovidThanksMessage() {
|
||||
activity?.runOnUiThread {
|
||||
context?.let {
|
||||
home_header_setup_complete_header_line_1.text = it.getString(getCovidActiveStatusMessage(it.allPermissionsEnabled()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun updateMessageTiles(messagesResponse: MessagesResponse) {
|
||||
GlobalScope.launch(Dispatchers.Main) {
|
||||
improve_performance_card_linear_layout.children.forEach {
|
||||
if (it != internet_connection_tile && it != improve_performance_title) {
|
||||
improve_performance_card_linear_layout.removeView(it)
|
||||
}
|
||||
override fun onNetworkStatusChanged(isAvailable: Boolean) {
|
||||
CentralLog.d(TAG, "onNetworkStatusChanged: $checkIsInternetConnected $isAvailable")
|
||||
checkIsInternetConnected = isAvailable
|
||||
refreshSetupCompleteOrIncompleteUi()
|
||||
|
||||
initiateFetchingCaseNumbers()
|
||||
}
|
||||
|
||||
if (!messagesResponse.messages.isNullOrEmpty()) {
|
||||
improve_performance_card.visibility = VISIBLE
|
||||
|
||||
messagesResponse.messages.forEach { message ->
|
||||
ExternalLinkCard(requireContext(), null, 0).also {
|
||||
it.layoutParams = LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
).also { layoutParams ->
|
||||
layoutParams.setMargins(0, resources.getDimensionPixelSize(R.dimen.divider_height), 0, 0)
|
||||
private val mBroadcastListener: BroadcastReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
val action = intent.action
|
||||
if (action == BluetoothAdapter.ACTION_STATE_CHANGED) {
|
||||
when (intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1)) {
|
||||
BluetoothAdapter.STATE_OFF -> {
|
||||
bluetooth_card_view.render(formatBlueToothTitle(false), false)
|
||||
refreshSetupCompleteOrIncompleteUi()
|
||||
}
|
||||
|
||||
it.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.white))
|
||||
|
||||
it.setMessage(message)
|
||||
it.setErrorTextColor()
|
||||
|
||||
improve_performance_card_linear_layout.addView(it)
|
||||
BluetoothAdapter.STATE_TURNING_OFF -> {
|
||||
bluetooth_card_view.render(formatBlueToothTitle(false), false)
|
||||
refreshSetupCompleteOrIncompleteUi()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
improve_performance_card.visibility = GONE
|
||||
BluetoothAdapter.STATE_ON -> {
|
||||
refreshSetupCompleteOrIncompleteUi()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateNotificationStatusTile() {
|
||||
var title = ""
|
||||
var body = ""
|
||||
|
||||
if (NotificationManagerCompat.from(requireContext()).areNotificationsEnabled()
|
||||
) {
|
||||
notification_status_link.setTopRightIcon(R.drawable.ic_green_tick)
|
||||
title = getString(R.string.home_set_complete_external_link_notifications_title_iOS)
|
||||
body = getString(R.string.NotificationsEnabledBlurb)
|
||||
} else {
|
||||
notification_status_link.setTopRightIcon(R.drawable.ic_red_cross)
|
||||
title = getString(R.string.home_set_complete_external_link_notifications_title_iOS_off)
|
||||
body = getString(R.string.NotificationsEnabledBlurb)
|
||||
}
|
||||
|
||||
notification_status_link.setTitleBodyAndClickCallback(title, body) {
|
||||
openAppNotificationSettings()
|
||||
}
|
||||
|
||||
notification_status_link.setColorForContentWithAction()
|
||||
}
|
||||
|
||||
private fun openAppNotificationSettings() {
|
||||
val context = requireContext()
|
||||
|
||||
val intent = Intent().apply {
|
||||
when {
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O -> {
|
||||
action = Settings.ACTION_APP_NOTIFICATION_SETTINGS
|
||||
putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName)
|
||||
}
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP -> {
|
||||
action = "android.settings.APP_NOTIFICATION_SETTINGS"
|
||||
putExtra("app_package", context.packageName)
|
||||
putExtra("app_uid", context.applicationInfo.uid)
|
||||
}
|
||||
else -> {
|
||||
action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
|
||||
addCategory(Intent.CATEGORY_DEFAULT)
|
||||
data = Uri.parse("package:" + context.packageName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
package au.gov.health.covidsafe.ui.home
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.*
|
||||
import au.gov.health.covidsafe.factory.RetrofitServiceGenerator
|
||||
import au.gov.health.covidsafe.interactor.usecase.GetCaseStatisticsUseCase
|
||||
import au.gov.health.covidsafe.logging.CentralLog
|
||||
import au.gov.health.covidsafe.networking.response.CaseStatisticResponse
|
||||
import au.gov.health.covidsafe.extensions.isInternetAvailable
|
||||
import au.gov.health.covidsafe.networking.service.AwsClient
|
||||
import au.gov.health.covidsafe.preference.Preference
|
||||
import com.google.gson.Gson
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
private const val TAG = "HomeFragmentViewModel"
|
||||
|
||||
class HomeFragmentViewModel(application: Application) : AndroidViewModel(application) {
|
||||
|
||||
val caseNumberDataState = MutableLiveData<CaseNumbersState>()
|
||||
val caseStatisticsLiveData = MutableLiveData<CaseStatisticResponse>()
|
||||
val isRefreshing = MutableLiveData<Boolean>()
|
||||
|
||||
val awsClient: AwsClient by lazy {
|
||||
RetrofitServiceGenerator.createService(AwsClient::class.java)
|
||||
}
|
||||
|
||||
fun fetchGetCaseStatistics(lifecycle: Lifecycle) {
|
||||
if(caseNumberDataState.value != CaseNumbersState.LOADING) {
|
||||
caseNumberDataState.value = CaseNumbersState.LOADING
|
||||
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
|
||||
GetCaseStatisticsUseCase(awsClient, lifecycle, getApplication()).invoke("",
|
||||
onSuccess = {
|
||||
updateOnSuccess(it)
|
||||
},
|
||||
onFailure = {
|
||||
CentralLog.e(TAG, "On Failure: ${it.message}")
|
||||
showErrorMessage()
|
||||
}
|
||||
)
|
||||
}
|
||||
} else {
|
||||
isRefreshing.value = false
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateOnSuccess(caseStatisticResponse: CaseStatisticResponse) {
|
||||
viewModelScope.launch {
|
||||
isRefreshing.value = false
|
||||
|
||||
CentralLog.d(TAG, "On Success: ${caseStatisticResponse.vic?.totalCases}")
|
||||
caseNumberDataState.value = CaseNumbersState.SUCCESS
|
||||
cacheCaseStatisticDataInPersistent(caseStatisticResponse)
|
||||
caseStatisticsLiveData.value = caseStatisticResponse
|
||||
}
|
||||
}
|
||||
|
||||
private fun showErrorMessage() {
|
||||
viewModelScope.launch {
|
||||
|
||||
isRefreshing.value = false
|
||||
|
||||
val context = getApplication() as Context
|
||||
caseStatisticsLiveData.value = getCachedCaseStatisticDataFromPersistent(context)
|
||||
if (context.isInternetAvailable()) {
|
||||
caseNumberDataState.value = CaseNumbersState.ERROR_UNKNOWN
|
||||
} else {
|
||||
caseNumberDataState.value = CaseNumbersState.ERROR_NO_NETWORK
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun cacheCaseStatisticDataInPersistent(caseStatisticResponse: CaseStatisticResponse) {
|
||||
Preference.putCaseStatisticData(getApplication(), Gson().toJson(caseStatisticResponse))
|
||||
}
|
||||
|
||||
private fun getCachedCaseStatisticDataFromPersistent(context: Context): CaseStatisticResponse? {
|
||||
val caseStatisticString = Preference.getCaseStatisticData(context)
|
||||
return caseStatisticString?.let {
|
||||
val caseStatisticData = Gson().fromJson(it, CaseStatisticResponse::class.java)
|
||||
CentralLog.d(TAG, "On Preference: ${caseStatisticData.vic?.totalCases}")
|
||||
caseStatisticData
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package au.gov.health.covidsafe.ui.home
|
||||
|
||||
import androidx.lifecycle.LifecycleObserver
|
||||
|
||||
class HomePresenter(fragment: HomeFragment) : LifecycleObserver {
|
||||
|
||||
init {
|
||||
fragment.lifecycle.addObserver(this)
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ package au.gov.health.covidsafe.ui.home.view
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.res.TypedArray
|
||||
import android.graphics.Typeface
|
||||
import android.net.Uri
|
||||
import android.text.Html
|
||||
import android.util.AttributeSet
|
||||
|
@ -26,24 +27,32 @@ class ExternalLinkCard @JvmOverloads constructor(
|
|||
|
||||
attrs?.let {
|
||||
val a: TypedArray = context.obtainStyledAttributes(attrs, R.styleable.ExternalLinkCard)
|
||||
val icon = a.getDrawable(R.styleable.ExternalLinkCard_external_linkCard_icon)
|
||||
val iconVisible = a.getBoolean(R.styleable.ExternalLinkCard_external_linkCard_icon_visible, true)
|
||||
val startIcon = a.getDrawable(R.styleable.ExternalLinkCard_external_linkCard_start_icon)
|
||||
val startIconVisible = a.getBoolean(R.styleable.ExternalLinkCard_external_linkCard_start_icon_visible, true)
|
||||
val title = a.getString(R.styleable.ExternalLinkCard_external_linkCard_title)
|
||||
val content = a.getString(R.styleable.ExternalLinkCard_external_linkCard_content)
|
||||
val padding = a.getDimension(R.styleable.ExternalLinkCard_external_linkCard_icon_padding, 0f).toInt()
|
||||
val iconBackground = a.getResourceId(R.styleable.ExternalLinkCard_external_linkCard_icon_background, R.color.transparent)
|
||||
val padding = a.getDimension(R.styleable.ExternalLinkCard_external_linkCard_start_icon_padding, 0f).toInt()
|
||||
val contentPadding = a.getDimension(R.styleable.ExternalLinkCard_external_linkCard_content_padding, 0f).toInt()
|
||||
val iconBackground = a.getResourceId(R.styleable.ExternalLinkCard_external_linkCard_start_icon_background, R.color.transparent)
|
||||
val textColorResId = a.getResourceId(R.styleable.ExternalLinkCard_external_linkCard_text_color, R.color.slack_black)
|
||||
val endIconVisible = a.getBoolean(R.styleable.ExternalLinkCard_external_linkCard_end_icon_visible, true)
|
||||
val textColor = ContextCompat.getColor(context, textColorResId)
|
||||
|
||||
external_link_round_image.setImageDrawable(icon)
|
||||
external_link_round_image.visibility = if (iconVisible) View.VISIBLE else View.GONE
|
||||
external_link_round_image.setImageDrawable(startIcon)
|
||||
external_link_round_image.visibility = if (startIconVisible) View.VISIBLE else View.GONE
|
||||
external_link_round_image.setBackgroundResource(iconBackground)
|
||||
external_link_round_image.setPadding(padding, padding, padding, padding)
|
||||
|
||||
external_link_headline.text = title
|
||||
|
||||
external_link_content.text = content
|
||||
if (contentPadding > 0) {
|
||||
external_link_content.setPadding(0, contentPadding, 0, 0)
|
||||
}
|
||||
|
||||
external_link_end_image_view.visibility = if (endIconVisible) View.VISIBLE else View.GONE
|
||||
|
||||
setTextColor(textColor)
|
||||
|
||||
a.recycle()
|
||||
}
|
||||
}
|
||||
|
@ -53,19 +62,33 @@ class ExternalLinkCard @JvmOverloads constructor(
|
|||
external_link_content.setTextColor(textColor)
|
||||
|
||||
val icChevron =
|
||||
if (textColor == ContextCompat.getColor(context, R.color.error)) {
|
||||
when (textColor) {
|
||||
ContextCompat.getColor(context, R.color.error_red) -> {
|
||||
R.drawable.ic_chevron_right_red
|
||||
} else {
|
||||
R.drawable.ic_chevron_right
|
||||
}
|
||||
ContextCompat.getColor(context, R.color.white) -> {
|
||||
R.drawable.ic_chevron_right_white
|
||||
}
|
||||
else -> {
|
||||
R.drawable.ic_chevron_right_black
|
||||
}
|
||||
}
|
||||
|
||||
next_arrow.setImageDrawable(
|
||||
external_link_end_image_view.setImageDrawable(
|
||||
ContextCompat.getDrawable(context, icChevron).also {
|
||||
it?.isAutoMirrored = true
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun setTitleTextTypeFace(typeface: Typeface) {
|
||||
external_link_headline.typeface = typeface
|
||||
}
|
||||
|
||||
fun setContentTextTypeFace(typeface: Typeface) {
|
||||
external_link_content.typeface = typeface
|
||||
}
|
||||
|
||||
fun setMessage(message: Message) {
|
||||
external_link_round_image.visibility = View.GONE
|
||||
|
||||
|
@ -79,6 +102,10 @@ class ExternalLinkCard @JvmOverloads constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun setTitleText(title: String) {
|
||||
external_link_headline.text = title
|
||||
}
|
||||
|
||||
fun setTitleBodyAndClickCallback(title: String, body: String, clickCallBack: () -> Unit) {
|
||||
external_link_headline.text = title
|
||||
external_link_content.text = body
|
||||
|
@ -89,11 +116,11 @@ class ExternalLinkCard @JvmOverloads constructor(
|
|||
}
|
||||
|
||||
fun setErrorTextColor() {
|
||||
setTextColor(ContextCompat.getColor(context, R.color.error))
|
||||
setTextColor(ContextCompat.getColor(context, R.color.error_red))
|
||||
}
|
||||
|
||||
fun setTopRightIcon(iconResID: Int) {
|
||||
next_arrow.setImageResource(iconResID)
|
||||
external_link_end_image_view.setImageResource(iconResID)
|
||||
}
|
||||
|
||||
fun setColorForContentWithAction() {
|
||||
|
|
|
@ -9,7 +9,7 @@ import android.view.ViewGroup
|
|||
import android.widget.FrameLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import au.gov.health.covidsafe.R
|
||||
import au.gov.health.covidsafe.TracerApp
|
||||
import au.gov.health.covidsafe.app.TracerApp
|
||||
import kotlinx.android.synthetic.main.view_card_permission_card.view.*
|
||||
|
||||
class PermissionStatusCard @JvmOverloads constructor(
|
||||
|
@ -32,7 +32,7 @@ class PermissionStatusCard @JvmOverloads constructor(
|
|||
}
|
||||
|
||||
fun render(title: String, correct: Boolean, body: String? = null) {
|
||||
val errorTextColor = ContextCompat.getColor(TracerApp.AppContext, R.color.error)
|
||||
val errorTextColor = ContextCompat.getColor(TracerApp.AppContext, R.color.error_red)
|
||||
val normalTextColor = ContextCompat.getColor(TracerApp.AppContext, R.color.slack_black)
|
||||
|
||||
permission_icon.isSelected = correct
|
||||
|
|
|
@ -7,9 +7,9 @@ import android.view.ViewGroup
|
|||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import au.gov.health.covidsafe.Preference
|
||||
import au.gov.health.covidsafe.preference.Preference
|
||||
import au.gov.health.covidsafe.R
|
||||
import au.gov.health.covidsafe.TracerApp
|
||||
import au.gov.health.covidsafe.app.TracerApp
|
||||
|
||||
const val VIEW_TYPE_GROUP_TITLE = 1
|
||||
const val VIEW_TYPE_COUNTRY = 2
|
||||
|
|
|
@ -8,11 +8,11 @@ import androidx.core.content.ContextCompat
|
|||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import au.gov.health.covidsafe.HasBlockingState
|
||||
import au.gov.health.covidsafe.Preference
|
||||
import au.gov.health.covidsafe.ui.base.HasBlockingState
|
||||
import au.gov.health.covidsafe.preference.Preference
|
||||
import au.gov.health.covidsafe.R
|
||||
import au.gov.health.covidsafe.ui.PagerContainer
|
||||
import au.gov.health.covidsafe.ui.UploadButtonLayout
|
||||
import au.gov.health.covidsafe.ui.base.PagerContainer
|
||||
import au.gov.health.covidsafe.ui.base.UploadButtonLayout
|
||||
import com.github.razir.progressbutton.bindProgressButton
|
||||
import com.github.razir.progressbutton.hideProgress
|
||||
import com.github.razir.progressbutton.showProgress
|
||||
|
|
|
@ -9,8 +9,8 @@ import android.view.accessibility.AccessibilityEvent
|
|||
import au.gov.health.covidsafe.R
|
||||
import au.gov.health.covidsafe.links.LinkBuilder
|
||||
import au.gov.health.covidsafe.talkback.setHeading
|
||||
import au.gov.health.covidsafe.ui.PagerChildFragment
|
||||
import au.gov.health.covidsafe.ui.UploadButtonLayout
|
||||
import au.gov.health.covidsafe.ui.base.PagerChildFragment
|
||||
import au.gov.health.covidsafe.ui.base.UploadButtonLayout
|
||||
import kotlinx.android.synthetic.main.fragment_data_privacy.*
|
||||
import kotlinx.android.synthetic.main.fragment_data_privacy.root
|
||||
import kotlinx.android.synthetic.main.fragment_data_privacy.view.*
|
||||
|
|
|
@ -16,12 +16,12 @@ import androidx.annotation.NavigationRes
|
|||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.core.widget.addTextChangedListener
|
||||
import au.gov.health.covidsafe.Preference
|
||||
import au.gov.health.covidsafe.preference.Preference
|
||||
import au.gov.health.covidsafe.R
|
||||
import au.gov.health.covidsafe.TracerApp
|
||||
import au.gov.health.covidsafe.app.TracerApp
|
||||
import au.gov.health.covidsafe.talkback.setHeading
|
||||
import au.gov.health.covidsafe.ui.PagerChildFragment
|
||||
import au.gov.health.covidsafe.ui.UploadButtonLayout
|
||||
import au.gov.health.covidsafe.ui.base.PagerChildFragment
|
||||
import au.gov.health.covidsafe.ui.base.UploadButtonLayout
|
||||
import au.gov.health.covidsafe.ui.onboarding.CountryCodeSelectionActivity
|
||||
import au.gov.health.covidsafe.ui.onboarding.fragment.enterpin.EnterPinFragment.Companion.ENTER_PIN_CALLING_CODE
|
||||
import au.gov.health.covidsafe.ui.onboarding.fragment.enterpin.EnterPinFragment.Companion.ENTER_PIN_CHALLENGE_NAME
|
||||
|
@ -50,7 +50,7 @@ class EnterNumberFragment : PagerChildFragment() {
|
|||
private var callingCode: Int = 0
|
||||
private var nationalFlagResID: Int = 0
|
||||
|
||||
private val errorTextColor = ContextCompat.getColor(TracerApp.AppContext, R.color.error)
|
||||
private val errorTextColor = ContextCompat.getColor(TracerApp.AppContext, R.color.error_red)
|
||||
private val normalTextColor = ContextCompat.getColor(TracerApp.AppContext, R.color.slack_black)
|
||||
|
||||
private fun updateSelectedCountry() {
|
||||
|
|
|
@ -4,7 +4,7 @@ package au.gov.health.covidsafe.ui.onboarding.fragment.enternumber
|
|||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleObserver
|
||||
import androidx.lifecycle.OnLifecycleEvent
|
||||
import au.gov.health.covidsafe.Preference
|
||||
import au.gov.health.covidsafe.preference.Preference
|
||||
import au.gov.health.covidsafe.R
|
||||
import au.gov.health.covidsafe.extensions.isInternetAvailable
|
||||
import au.gov.health.covidsafe.factory.NetworkFactory
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package au.gov.health.covidsafe.ui.onboarding.fragment.enterpin
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
import android.os.CountDownTimer
|
||||
import android.text.method.LinkMovementMethod
|
||||
|
@ -9,15 +10,14 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import android.view.accessibility.AccessibilityEvent
|
||||
import androidx.annotation.NavigationRes
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import au.gov.health.covidsafe.R
|
||||
import au.gov.health.covidsafe.Utils.announceForAccessibility
|
||||
import au.gov.health.covidsafe.ui.utils.Utils.announceForAccessibility
|
||||
import au.gov.health.covidsafe.extensions.toHyperlink
|
||||
import au.gov.health.covidsafe.links.LinkBuilder
|
||||
import au.gov.health.covidsafe.talkback.setHeading
|
||||
import au.gov.health.covidsafe.ui.PagerChildFragment
|
||||
import au.gov.health.covidsafe.ui.UploadButtonLayout
|
||||
import au.gov.health.covidsafe.ui.base.PagerChildFragment
|
||||
import au.gov.health.covidsafe.ui.base.UploadButtonLayout
|
||||
import com.atlassian.mobilekit.module.core.utils.SystemUtils
|
||||
import kotlinx.android.synthetic.main.fragment_enter_pin.*
|
||||
import kotlinx.android.synthetic.main.fragment_enter_pin.view.*
|
||||
|
@ -107,23 +107,15 @@ class EnterPinFragment : PagerChildFragment() {
|
|||
} else {
|
||||
"$numberOfSecondsInt"
|
||||
}
|
||||
|
||||
enter_pin_timer_value?.text = "$numberOfMinsInt:$finalNumberOfSecondsString"
|
||||
}
|
||||
|
||||
override fun onFinish() {
|
||||
enter_pin_timer_value?.text = "0:00"
|
||||
enter_pin_resend_pin.isEnabled = true
|
||||
activity?.let {
|
||||
enter_pin_resend_pin.setLinkTextColor(ContextCompat.getColor(it, R.color.hyperlink_enabled))
|
||||
}
|
||||
setupTimer(false)
|
||||
}
|
||||
}
|
||||
stopWatch?.start()
|
||||
enter_pin_resend_pin.isEnabled = false
|
||||
activity?.let {
|
||||
enter_pin_resend_pin.setLinkTextColor(ContextCompat.getColor(it, R.color.hyperlink_disabled))
|
||||
}
|
||||
setupTimer(true)
|
||||
}
|
||||
|
||||
fun resetTimer() {
|
||||
|
@ -200,4 +192,10 @@ class EnterPinFragment : PagerChildFragment() {
|
|||
.setPositiveButton(android.R.string.yes, null).show()
|
||||
}
|
||||
|
||||
private fun setupTimer(isTimerOn: Boolean) {
|
||||
enter_pin_resend_pin.visibility = if (isTimerOn) View.GONE else View.VISIBLE
|
||||
enter_pin_timer_label.text = if (isTimerOn) context?.getString(R.string.enter_pin_timer_expire) else context?.getString(R.string.CodeHasExpired)
|
||||
enter_pin_timer_label.setTextColor(if (isTimerOn) Color.BLACK else Color.RED)
|
||||
enter_pin_timer_value.visibility = if (isTimerOn) View.VISIBLE else View.INVISIBLE
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ import android.text.TextUtils
|
|||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleObserver
|
||||
import androidx.lifecycle.OnLifecycleEvent
|
||||
import au.gov.health.covidsafe.Preference
|
||||
import au.gov.health.covidsafe.preference.Preference
|
||||
import au.gov.health.covidsafe.extensions.isInternetAvailable
|
||||
import au.gov.health.covidsafe.factory.NetworkFactory
|
||||
import au.gov.health.covidsafe.interactor.usecase.GetOnboardingOtp
|
||||
|
|
|
@ -9,8 +9,8 @@ import android.view.accessibility.AccessibilityEvent
|
|||
import au.gov.health.covidsafe.R
|
||||
import au.gov.health.covidsafe.links.LinkBuilder
|
||||
import au.gov.health.covidsafe.talkback.setHeading
|
||||
import au.gov.health.covidsafe.ui.PagerChildFragment
|
||||
import au.gov.health.covidsafe.ui.UploadButtonLayout
|
||||
import au.gov.health.covidsafe.ui.base.PagerChildFragment
|
||||
import au.gov.health.covidsafe.ui.base.UploadButtonLayout
|
||||
import kotlinx.android.synthetic.main.fragment_how_it_works.*
|
||||
import kotlinx.android.synthetic.main.fragment_how_it_works.view.*
|
||||
|
||||
|
|
|
@ -7,8 +7,8 @@ import android.view.ViewGroup
|
|||
import android.view.accessibility.AccessibilityEvent
|
||||
import au.gov.health.covidsafe.R
|
||||
import au.gov.health.covidsafe.talkback.setHeading
|
||||
import au.gov.health.covidsafe.ui.PagerChildFragment
|
||||
import au.gov.health.covidsafe.ui.UploadButtonLayout
|
||||
import au.gov.health.covidsafe.ui.base.PagerChildFragment
|
||||
import au.gov.health.covidsafe.ui.base.UploadButtonLayout
|
||||
import kotlinx.android.synthetic.main.fragment_intro.*
|
||||
|
||||
class IntroductionFragment : PagerChildFragment() {
|
||||
|
|
|
@ -7,11 +7,11 @@ import android.view.LayoutInflater
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.accessibility.AccessibilityEvent
|
||||
import au.gov.health.covidsafe.Preference
|
||||
import au.gov.health.covidsafe.preference.Preference
|
||||
import au.gov.health.covidsafe.R
|
||||
import au.gov.health.covidsafe.talkback.setHeading
|
||||
import au.gov.health.covidsafe.ui.PagerChildFragment
|
||||
import au.gov.health.covidsafe.ui.UploadButtonLayout
|
||||
import au.gov.health.covidsafe.ui.base.PagerChildFragment
|
||||
import au.gov.health.covidsafe.ui.base.UploadButtonLayout
|
||||
import kotlinx.android.synthetic.main.fragment_permission.root
|
||||
import kotlinx.android.synthetic.main.fragment_permission_device_name.*
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import android.Manifest
|
|||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.PowerManager
|
||||
|
@ -13,13 +14,13 @@ import android.view.ViewGroup
|
|||
import android.view.accessibility.AccessibilityEvent
|
||||
import androidx.core.content.ContextCompat
|
||||
import au.gov.health.covidsafe.HomeActivity
|
||||
import au.gov.health.covidsafe.Preference
|
||||
import au.gov.health.covidsafe.preference.Preference
|
||||
import au.gov.health.covidsafe.R
|
||||
import au.gov.health.covidsafe.TracerApp
|
||||
import au.gov.health.covidsafe.app.TracerApp
|
||||
import au.gov.health.covidsafe.extensions.*
|
||||
import au.gov.health.covidsafe.talkback.setHeading
|
||||
import au.gov.health.covidsafe.ui.PagerChildFragment
|
||||
import au.gov.health.covidsafe.ui.UploadButtonLayout
|
||||
import au.gov.health.covidsafe.ui.base.PagerChildFragment
|
||||
import au.gov.health.covidsafe.ui.base.UploadButtonLayout
|
||||
import kotlinx.android.synthetic.main.fragment_permission.*
|
||||
import pub.devrel.easypermissions.EasyPermissions
|
||||
|
||||
|
@ -82,9 +83,25 @@ class PermissionFragment : PagerChildFragment(), EasyPermissions.PermissionCallb
|
|||
|
||||
private fun hasAllPermissionsAndBluetoothOn(): Boolean {
|
||||
val context = TracerApp.AppContext
|
||||
return context.isBlueToothEnabled() == true
|
||||
&& requiredPermissions.all { ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED }
|
||||
&& ContextCompat.getSystemService(context, PowerManager::class.java)?.isIgnoringBatteryOptimizations(context.packageName) ?: true
|
||||
return context.isBlueToothEnabled() == true && checkAllRequiredPermissions() && checkIgnoreBatteryOptimization()
|
||||
}
|
||||
|
||||
private fun checkAllRequiredPermissions(): Boolean {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
val context = TracerApp.AppContext
|
||||
requiredPermissions.all { ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED }
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkIgnoreBatteryOptimization(): Boolean {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
val context = TracerApp.AppContext
|
||||
ContextCompat.getSystemService(context, PowerManager::class.java)?.isIgnoringBatteryOptimizations(context.packageName) ?: true
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
private fun navigateToMainActivity() {
|
||||
|
|
|
@ -11,8 +11,8 @@ import au.gov.health.covidsafe.HomeActivity
|
|||
import au.gov.health.covidsafe.R
|
||||
import au.gov.health.covidsafe.links.LinkBuilder
|
||||
import au.gov.health.covidsafe.talkback.setHeading
|
||||
import au.gov.health.covidsafe.ui.PagerChildFragment
|
||||
import au.gov.health.covidsafe.ui.UploadButtonLayout
|
||||
import au.gov.health.covidsafe.ui.base.PagerChildFragment
|
||||
import au.gov.health.covidsafe.ui.base.UploadButtonLayout
|
||||
import kotlinx.android.synthetic.main.fragment_permission_success.*
|
||||
|
||||
class PermissionSuccessFragment : PagerChildFragment() {
|
||||
|
|
|
@ -13,12 +13,12 @@ import android.widget.ArrayAdapter
|
|||
import android.widget.TextView.OnEditorActionListener
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.os.bundleOf
|
||||
import au.gov.health.covidsafe.Preference
|
||||
import au.gov.health.covidsafe.preference.Preference
|
||||
import au.gov.health.covidsafe.R
|
||||
import au.gov.health.covidsafe.logging.CentralLog
|
||||
import au.gov.health.covidsafe.talkback.setHeading
|
||||
import au.gov.health.covidsafe.ui.PagerChildFragment
|
||||
import au.gov.health.covidsafe.ui.UploadButtonLayout
|
||||
import au.gov.health.covidsafe.ui.base.PagerChildFragment
|
||||
import au.gov.health.covidsafe.ui.base.UploadButtonLayout
|
||||
import au.gov.health.covidsafe.ui.onboarding.fragment.enternumber.EnterNumberFragment
|
||||
import kotlinx.android.synthetic.main.fragment_personal_details.*
|
||||
import java.util.regex.Pattern
|
||||
|
@ -27,7 +27,7 @@ import java.util.regex.Pattern
|
|||
private const val TAG = "PersonalDetailsFragment"
|
||||
|
||||
private val POST_CODE_REGEX = Pattern.compile("^(?:(?:[2-8]\\d|9[0-7]|0?[28]|0?9(?=09))(?:\\d{2}))$")
|
||||
private val NAME_REGEX = Pattern.compile("^[A-Za-z0-9\\u00C0-\\u017F][A-Za-z'0-9\\-\\u00C0-\\u017F ]{0,80}\$")
|
||||
private val NAME_REGEX = Pattern.compile("^[.A-Za-z0-9\\u00C0-\\u017F][.A-Za-z'0-9\\-\\u00C0-\\u017F ]{0,80}\$")
|
||||
|
||||
class PersonalDetailsFragment : PagerChildFragment() {
|
||||
|
||||
|
@ -121,7 +121,7 @@ class PersonalDetailsFragment : PagerChildFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
personal_details_name.setOnEditorActionListener(OnEditorActionListener { textView, actionId, event ->
|
||||
personal_details_name.setOnEditorActionListener(OnEditorActionListener { textView, actionId, _ ->
|
||||
if (actionId == EditorInfo.IME_ACTION_NEXT) {
|
||||
hideKeyboard()
|
||||
textView.clearFocus()
|
||||
|
|
|
@ -7,9 +7,9 @@ import android.view.ViewGroup
|
|||
import android.view.accessibility.AccessibilityEvent
|
||||
import au.gov.health.covidsafe.R
|
||||
import au.gov.health.covidsafe.talkback.setHeading
|
||||
import au.gov.health.covidsafe.ui.PagerChildFragment
|
||||
import au.gov.health.covidsafe.ui.PagerContainer
|
||||
import au.gov.health.covidsafe.ui.UploadButtonLayout
|
||||
import au.gov.health.covidsafe.ui.base.PagerChildFragment
|
||||
import au.gov.health.covidsafe.ui.base.PagerContainer
|
||||
import au.gov.health.covidsafe.ui.base.UploadButtonLayout
|
||||
import kotlinx.android.synthetic.main.fragment_registration_consent.*
|
||||
|
||||
class RegistrationConsentFragment : PagerChildFragment() {
|
||||
|
|
|
@ -8,8 +8,8 @@ import android.view.accessibility.AccessibilityEvent
|
|||
import androidx.core.os.bundleOf
|
||||
import au.gov.health.covidsafe.R
|
||||
import au.gov.health.covidsafe.talkback.setHeading
|
||||
import au.gov.health.covidsafe.ui.PagerChildFragment
|
||||
import au.gov.health.covidsafe.ui.UploadButtonLayout
|
||||
import au.gov.health.covidsafe.ui.base.PagerChildFragment
|
||||
import au.gov.health.covidsafe.ui.base.UploadButtonLayout
|
||||
import au.gov.health.covidsafe.ui.onboarding.fragment.enternumber.EnterNumberFragment
|
||||
import kotlinx.android.synthetic.main.fragment_under_sixteen.*
|
||||
|
||||
|
|
|
@ -0,0 +1,226 @@
|
|||
package au.gov.health.covidsafe.ui.settings
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.provider.Settings
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.children
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import au.gov.health.covidsafe.HomeActivity
|
||||
import au.gov.health.covidsafe.R
|
||||
import au.gov.health.covidsafe.extensions.allPermissionsEnabled
|
||||
import au.gov.health.covidsafe.extensions.getAppVersionNumberDetails
|
||||
import au.gov.health.covidsafe.extensions.shareThisApp
|
||||
import au.gov.health.covidsafe.logging.CentralLog
|
||||
import au.gov.health.covidsafe.networking.response.MessagesResponse
|
||||
import au.gov.health.covidsafe.ui.base.BaseFragment
|
||||
import au.gov.health.covidsafe.ui.connection.InternetConnectionIssuesActivity
|
||||
import au.gov.health.covidsafe.ui.home.HelpFragment
|
||||
import au.gov.health.covidsafe.ui.home.view.ExternalLinkCard
|
||||
import au.gov.health.covidsafe.utils.NetworkConnectionCheck
|
||||
import com.atlassian.mobilekit.module.feedback.FeedbackModule
|
||||
import kotlinx.android.synthetic.main.fragment_settings.*
|
||||
import kotlinx.android.synthetic.main.fragment_settings_external_link.*
|
||||
import kotlinx.android.synthetic.main.view_covid_share_tile.*
|
||||
import kotlinx.android.synthetic.main.view_help_topics_tile.*
|
||||
import kotlinx.android.synthetic.main.view_settings_improve_app_performance_tile.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
private const val TAG = "SettingsFragment"
|
||||
|
||||
class SettingsFragment : BaseFragment(), NetworkConnectionCheck.NetworkConnectionListener {
|
||||
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_settings, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
initializeToolbarNavigation()
|
||||
initializeObservers()
|
||||
NetworkConnectionCheck.addNetworkChangedListener(requireContext(), this)
|
||||
}
|
||||
|
||||
private fun initializeToolbarNavigation() {
|
||||
settings_toolbar.setNavigationOnClickListener { findNavController().popBackStack() }
|
||||
}
|
||||
|
||||
private fun initializeObservers() {
|
||||
(activity as HomeActivity?)?.run {
|
||||
appUpdateAvailableMessageResponseLiveData.observe(viewLifecycleOwner, latestAppAvailable)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
updateNotificationStatusTile()
|
||||
initializeHelpTopicsNavigation()
|
||||
initializeSupportNavigation()
|
||||
initializeAppShareNavigation()
|
||||
setAppVersionNumber()
|
||||
}
|
||||
|
||||
private fun initializeHelpTopicsNavigation() {
|
||||
help_topics_link.setOnClickListener {
|
||||
HelpFragment.anchor = null
|
||||
findNavController().navigate(SettingsFragmentDirections.actionSettingsFragmentToHelpFragment())
|
||||
}
|
||||
}
|
||||
|
||||
private fun initializeSupportNavigation() {
|
||||
settings_support_view.setOnClickListener {
|
||||
FeedbackModule.showFeedbackScreen()
|
||||
}
|
||||
}
|
||||
|
||||
private fun initializeAppShareNavigation() {
|
||||
app_share.setOnClickListener {
|
||||
context?.shareThisApp()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setAppVersionNumber() {
|
||||
settings_version_number.text = context?.getAppVersionNumberDetails()
|
||||
}
|
||||
|
||||
private val latestAppAvailable = Observer<MessagesResponse> {
|
||||
updateMessageTiles(it)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
|
||||
NetworkConnectionCheck.removeNetworkChangedListener(this)
|
||||
removeObservers()
|
||||
}
|
||||
|
||||
private fun removeObservers() {
|
||||
(activity as HomeActivity?)?.run {
|
||||
appUpdateAvailableMessageResponseLiveData.removeObserver(latestAppAvailable)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateNotificationStatusTile() {
|
||||
val title: String
|
||||
val body: String
|
||||
|
||||
if (NotificationManagerCompat.from(requireContext()).areNotificationsEnabled()) {
|
||||
notification_status_link.setTopRightIcon(R.drawable.ic_green_tick)
|
||||
title = getString(R.string.home_set_complete_external_link_notifications_title_iOS)
|
||||
body = getString(R.string.NotificationsEnabledBlurb)
|
||||
} else {
|
||||
notification_status_link.setTopRightIcon(R.drawable.ic_white_background_red_error)
|
||||
title = getString(R.string.home_set_complete_external_link_notifications_title_iOS_off)
|
||||
body = getString(R.string.NotificationsEnabledBlurb)
|
||||
}
|
||||
|
||||
notification_status_link.setTitleBodyAndClickCallback(title, body) {
|
||||
openAppNotificationSettings()
|
||||
}
|
||||
|
||||
notification_status_link.setColorForContentWithAction()
|
||||
}
|
||||
|
||||
private fun updateInternetConnectionTile(isInternetConnected: Boolean) {
|
||||
// called on IO thread; run the UI logic on UI thread
|
||||
GlobalScope.launch(Dispatchers.Main) {
|
||||
context?.let {
|
||||
CentralLog.d(TAG, "updateConnectionTile() isInternetConnected = $isInternetConnected")
|
||||
|
||||
var visibility = if (isInternetConnected) View.GONE else View.VISIBLE
|
||||
|
||||
// don't display the tile when there's permission not enabled
|
||||
val isAllPermissionsEnabled = it.allPermissionsEnabled()
|
||||
if (!isAllPermissionsEnabled) {
|
||||
visibility = View.GONE
|
||||
}
|
||||
|
||||
improve_performance_group.visibility = visibility
|
||||
internet_connection_tile.visibility = visibility
|
||||
|
||||
if (visibility == View.VISIBLE) {
|
||||
internet_connection_tile.setOnClickListener {
|
||||
startActivity(Intent(requireContext(), InternetConnectionIssuesActivity::class.java))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateMessageTiles(messagesResponse: MessagesResponse) {
|
||||
GlobalScope.launch(Dispatchers.Main) {
|
||||
improve_performance_card_linear_layout.children.forEach {
|
||||
if (it != internet_connection_tile && it != improve_performance_title) {
|
||||
improve_performance_card_linear_layout.removeView(it)
|
||||
}
|
||||
}
|
||||
|
||||
if (!messagesResponse.messages.isNullOrEmpty()) {
|
||||
improve_performance_group.visibility = View.VISIBLE
|
||||
|
||||
messagesResponse.messages.forEach { message ->
|
||||
ExternalLinkCard(requireContext(), null, 0).also {
|
||||
it.layoutParams = LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
).also { layoutParams ->
|
||||
layoutParams.setMargins(0, resources.getDimensionPixelSize(R.dimen.divider_height), 0, 0)
|
||||
}
|
||||
|
||||
it.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.white))
|
||||
|
||||
it.setMessage(message)
|
||||
it.setErrorTextColor()
|
||||
|
||||
improve_performance_card_linear_layout.addView(it)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
improve_performance_group.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun openAppNotificationSettings() {
|
||||
val context = requireContext()
|
||||
|
||||
val intent = Intent().apply {
|
||||
when {
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O -> {
|
||||
action = Settings.ACTION_APP_NOTIFICATION_SETTINGS
|
||||
putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName)
|
||||
}
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP -> {
|
||||
action = "android.settings.APP_NOTIFICATION_SETTINGS"
|
||||
putExtra("app_package", context.packageName)
|
||||
putExtra("app_uid", context.applicationInfo.uid)
|
||||
}
|
||||
else -> {
|
||||
action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
|
||||
addCategory(Intent.CATEGORY_DEFAULT)
|
||||
data = Uri.parse("package:" + context.packageName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
override fun onNetworkStatusChanged(isAvailable: Boolean) {
|
||||
CentralLog.d(TAG, "Settings onNetworkStatusChanged: $isAvailable")
|
||||
updateInternetConnectionTile(isAvailable)
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package au.gov.health.covidsafe
|
||||
package au.gov.health.covidsafe.ui.splash
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
|
@ -10,12 +10,11 @@ import android.view.View.VISIBLE
|
|||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import au.gov.health.covidsafe.HomeActivity
|
||||
import au.gov.health.covidsafe.preference.Preference
|
||||
import au.gov.health.covidsafe.R
|
||||
import au.gov.health.covidsafe.ui.onboarding.OnboardingActivity
|
||||
import au.gov.health.covidsafe.ui.splash.SplashNavigationEvent
|
||||
import au.gov.health.covidsafe.ui.splash.SplashViewModel
|
||||
import au.gov.health.covidsafe.ui.splash.SplashViewModelFactory
|
||||
import kotlinx.android.synthetic.main.activity_splash.*
|
||||
import java.util.*
|
||||
|
||||
class SplashActivity : AppCompatActivity() {
|
||||
|
|
@ -9,8 +9,8 @@ import androidx.annotation.StringRes
|
|||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import au.gov.health.covidsafe.R
|
||||
import au.gov.health.covidsafe.ui.PagerContainer
|
||||
import au.gov.health.covidsafe.ui.UploadButtonLayout
|
||||
import au.gov.health.covidsafe.ui.base.PagerContainer
|
||||
import au.gov.health.covidsafe.ui.base.UploadButtonLayout
|
||||
import com.github.razir.progressbutton.hideProgress
|
||||
import com.github.razir.progressbutton.showProgress
|
||||
import kotlinx.android.synthetic.main.fragment_upload_master.*
|
||||
|
@ -26,9 +26,8 @@ class UploadContainerFragment : Fragment(), PagerContainer {
|
|||
activity?.onBackPressed()
|
||||
}
|
||||
|
||||
if (resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL) {
|
||||
toolbar.navigationIcon =
|
||||
requireContext().getDrawable(R.drawable.ic_up_rtl)
|
||||
if (resources.configuration.layoutDirection == LAYOUT_DIRECTION_RTL) {
|
||||
toolbar.navigationIcon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_up_rtl)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,13 +50,13 @@ class UploadContainerFragment : Fragment(), PagerContainer {
|
|||
}
|
||||
}
|
||||
|
||||
override fun refreshButton(uploadButtonLayout: UploadButtonLayout) {
|
||||
when (uploadButtonLayout) {
|
||||
override fun refreshButton(updateButtonLayout: UploadButtonLayout) {
|
||||
when (updateButtonLayout) {
|
||||
is UploadButtonLayout.ContinueLayout -> {
|
||||
upload_continue.setOnClickListener {
|
||||
uploadButtonLayout.buttonListener?.invoke()
|
||||
updateButtonLayout.buttonListener?.invoke()
|
||||
}
|
||||
upload_continue.setText(uploadButtonLayout.buttonText)
|
||||
upload_continue.setText(updateButtonLayout.buttonText)
|
||||
upload_continue.visibility = VISIBLE
|
||||
upload_answerNo.setOnClickListener(null)
|
||||
upload_answerYes.setOnClickListener(null)
|
||||
|
@ -68,10 +67,10 @@ class UploadContainerFragment : Fragment(), PagerContainer {
|
|||
upload_continue.setOnClickListener(null)
|
||||
upload_continue.visibility = GONE
|
||||
upload_answerNo.setOnClickListener {
|
||||
uploadButtonLayout.buttonNoListener.invoke()
|
||||
updateButtonLayout.buttonNoListener.invoke()
|
||||
}
|
||||
upload_answerYes.setOnClickListener {
|
||||
uploadButtonLayout.buttonYesListener.invoke()
|
||||
updateButtonLayout.buttonYesListener.invoke()
|
||||
}
|
||||
upload_answerNo.visibility = VISIBLE
|
||||
upload_answerYes.visibility = VISIBLE
|
||||
|
|
|
@ -7,8 +7,8 @@ import android.view.ViewGroup
|
|||
import android.view.accessibility.AccessibilityEvent
|
||||
import au.gov.health.covidsafe.R
|
||||
import au.gov.health.covidsafe.talkback.setHeading
|
||||
import au.gov.health.covidsafe.ui.PagerChildFragment
|
||||
import au.gov.health.covidsafe.ui.UploadButtonLayout
|
||||
import au.gov.health.covidsafe.ui.base.PagerChildFragment
|
||||
import au.gov.health.covidsafe.ui.base.UploadButtonLayout
|
||||
import kotlinx.android.synthetic.main.fragment_upload_finished.*
|
||||
|
||||
class UploadFinishedFragment : PagerChildFragment() {
|
||||
|
|
|
@ -7,8 +7,8 @@ import android.view.ViewGroup
|
|||
import android.view.accessibility.AccessibilityEvent
|
||||
import au.gov.health.covidsafe.R
|
||||
import au.gov.health.covidsafe.talkback.setHeading
|
||||
import au.gov.health.covidsafe.ui.PagerChildFragment
|
||||
import au.gov.health.covidsafe.ui.UploadButtonLayout
|
||||
import au.gov.health.covidsafe.ui.base.PagerChildFragment
|
||||
import au.gov.health.covidsafe.ui.base.UploadButtonLayout
|
||||
import kotlinx.android.synthetic.main.fragment_upload_initial.*
|
||||
import kotlinx.android.synthetic.main.fragment_upload_page_4.root
|
||||
|
||||
|
@ -45,5 +45,4 @@ class UploadInitialFragment : PagerChildFragment() {
|
|||
super.onDestroyView()
|
||||
root.removeAllViews()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,8 +10,8 @@ import android.view.accessibility.AccessibilityEvent
|
|||
import au.gov.health.covidsafe.R
|
||||
import au.gov.health.covidsafe.links.LinkBuilder
|
||||
import au.gov.health.covidsafe.talkback.setHeading
|
||||
import au.gov.health.covidsafe.ui.PagerChildFragment
|
||||
import au.gov.health.covidsafe.ui.UploadButtonLayout
|
||||
import au.gov.health.covidsafe.ui.base.PagerChildFragment
|
||||
import au.gov.health.covidsafe.ui.base.UploadButtonLayout
|
||||
import kotlinx.android.synthetic.main.fragment_upload_page_4.*
|
||||
|
||||
class UploadStepFourFragment : PagerChildFragment() {
|
||||
|
|
|
@ -11,8 +11,8 @@ import androidx.core.os.bundleOf
|
|||
import androidx.core.widget.doOnTextChanged
|
||||
import au.gov.health.covidsafe.R
|
||||
import au.gov.health.covidsafe.talkback.setHeading
|
||||
import au.gov.health.covidsafe.ui.PagerChildFragment
|
||||
import au.gov.health.covidsafe.ui.UploadButtonLayout
|
||||
import au.gov.health.covidsafe.ui.base.PagerChildFragment
|
||||
import au.gov.health.covidsafe.ui.base.UploadButtonLayout
|
||||
import au.gov.health.covidsafe.ui.onboarding.fragment.enternumber.EnterNumberFragment
|
||||
import au.gov.health.covidsafe.ui.view.UploadingDialog
|
||||
import au.gov.health.covidsafe.ui.view.UploadingErrorDialog
|
||||
|
|
|
@ -4,7 +4,7 @@ import androidx.lifecycle.Lifecycle
|
|||
import androidx.lifecycle.LifecycleObserver
|
||||
import androidx.lifecycle.OnLifecycleEvent
|
||||
import au.gov.health.covidsafe.BuildConfig
|
||||
import au.gov.health.covidsafe.Preference
|
||||
import au.gov.health.covidsafe.preference.Preference
|
||||
import au.gov.health.covidsafe.extensions.isInternetAvailable
|
||||
import au.gov.health.covidsafe.factory.NetworkFactory
|
||||
import au.gov.health.covidsafe.interactor.usecase.UploadData
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
package au.gov.health.covidsafe
|
||||
package au.gov.health.covidsafe.ui.utils
|
||||
|
||||
class LocalBlobV2(val modelP : String?, val modelC : String?, val txPower : Int?, val rssi : Int?)
|
|
@ -1,4 +1,4 @@
|
|||
package au.gov.health.covidsafe
|
||||
package au.gov.health.covidsafe.ui.utils
|
||||
|
||||
import android.Manifest
|
||||
import android.bluetooth.BluetoothAdapter
|
||||
|
@ -12,6 +12,9 @@ import android.provider.Settings
|
|||
import android.view.accessibility.AccessibilityEvent
|
||||
import android.view.accessibility.AccessibilityManager
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||
import au.gov.health.covidsafe.BuildConfig
|
||||
import au.gov.health.covidsafe.preference.Preference
|
||||
import au.gov.health.covidsafe.app.TracerApp
|
||||
import au.gov.health.covidsafe.bluetooth.gatt.*
|
||||
import au.gov.health.covidsafe.logging.CentralLog
|
||||
import au.gov.health.covidsafe.scheduler.Scheduler
|
||||
|
@ -29,7 +32,9 @@ import kotlinx.coroutines.Dispatchers
|
|||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.File
|
||||
import java.net.InetAddress
|
||||
import java.net.InetSocketAddress
|
||||
import java.net.Socket
|
||||
import java.net.SocketAddress
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
|
@ -295,17 +300,21 @@ object Utils {
|
|||
|
||||
private fun checkInternetConnectionToURL(url: String, callback: (Boolean) -> Unit) {
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
var reachable = false
|
||||
|
||||
reachable = try {
|
||||
InetAddress.getByName(url).isReachable(2000)
|
||||
val reachable = try {
|
||||
// InetAddress.getByName(url).isReachable(2000)
|
||||
val timeoutMs = 2000
|
||||
val sock = Socket()
|
||||
val sockaddr: SocketAddress = InetSocketAddress(url, 53)
|
||||
sock.connect(sockaddr, timeoutMs)
|
||||
sock.close()
|
||||
true
|
||||
} catch (e: Exception) {
|
||||
CentralLog.w(TAG, "checkInternetConnectionToURL() failed to reach the url $url")
|
||||
false
|
||||
}
|
||||
|
||||
CentralLog.w(TAG, "checkInternetConnectionToURL() reachability to url $url is $reachable")
|
||||
|
||||
callback(reachable)
|
||||
}
|
||||
}
|
|
@ -1,10 +1,11 @@
|
|||
package au.gov.health.covidsafe
|
||||
package au.gov.health.covidsafe.ui.webview
|
||||
|
||||
import android.os.Bundle
|
||||
import android.webkit.WebChromeClient
|
||||
import android.webkit.WebView
|
||||
import android.webkit.WebViewClient
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import au.gov.health.covidsafe.R
|
||||
import au.gov.health.covidsafe.logging.CentralLog
|
||||
|
||||
class WebViewActivity : FragmentActivity() {
|
|
@ -0,0 +1,93 @@
|
|||
package au.gov.health.covidsafe.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.Network
|
||||
import android.net.NetworkRequest
|
||||
import android.os.Build
|
||||
import au.gov.health.covidsafe.ui.utils.Utils
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
|
||||
object NetworkConnectionCheck {
|
||||
|
||||
private var networkConnectionListener: ArrayList<NetworkConnectionListener>? = null
|
||||
|
||||
private var isInternetConnected:Boolean? = null
|
||||
|
||||
fun addNetworkChangedListener(context: Context, listener: NetworkConnectionListener) {
|
||||
if (networkConnectionListener == null) {
|
||||
networkConnectionListener = ArrayList()
|
||||
registerNetworkChange(context)
|
||||
}
|
||||
|
||||
isInternetConnected?.let {
|
||||
listener.onNetworkStatusChanged(it)
|
||||
}
|
||||
|
||||
networkConnectionListener?.add(listener)
|
||||
}
|
||||
|
||||
fun removeNetworkChangedListener(listener: NetworkConnectionListener) {
|
||||
networkConnectionListener?.let {
|
||||
val i: Int = it.indexOf(listener)
|
||||
if (i >= 0) {
|
||||
it.removeAt(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun registerNetworkChange(context: Context) {
|
||||
val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||
connectivityManager.let {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
it.registerDefaultNetworkCallback(object : ConnectivityManager.NetworkCallback() {
|
||||
override fun onAvailable(network: Network) {
|
||||
networkStatusUpdate(true)
|
||||
}
|
||||
|
||||
override fun onLost(network: Network?) {
|
||||
networkStatusUpdate(false)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
it.registerNetworkCallback(NetworkRequest.Builder().build(),
|
||||
object : ConnectivityManager.NetworkCallback() {
|
||||
override fun onAvailable(network: Network?) {
|
||||
networkStatusUpdate(true)
|
||||
}
|
||||
|
||||
override fun onLost(network: Network?) {
|
||||
networkStatusUpdate(false)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun networkStatusUpdate(isAvailable: Boolean) {
|
||||
if (!isAvailable) {
|
||||
isInternetConnected = isAvailable
|
||||
sendNetworkStatusToListeners(isAvailable)
|
||||
} else {
|
||||
checkInternetConnection()
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkInternetConnection() {
|
||||
Utils.checkInternetConnectionToGoogle {
|
||||
isInternetConnected = it
|
||||
sendNetworkStatusToListeners(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun sendNetworkStatusToListeners(isAvailable: Boolean) {
|
||||
networkConnectionListener?.forEach {
|
||||
it.onNetworkStatusChanged(isAvailable)
|
||||
}
|
||||
}
|
||||
|
||||
interface NetworkConnectionListener {
|
||||
fun onNetworkStatusChanged(isAvailable: Boolean)
|
||||
}
|
||||
}
|
5
app/src/main/res/drawable/background_circular_grey.xml
Normal file
5
app/src/main/res/drawable/background_circular_grey.xml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
<solid android:color="@color/death_icon_background_color_grey" />
|
||||
</shape>
|
5
app/src/main/res/drawable/background_circular_white.xml
Normal file
5
app/src/main/res/drawable/background_circular_white.xml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
<solid android:color="@color/white" />
|
||||
</shape>
|
9
app/src/main/res/drawable/ic_chevron_right_white.xml
Normal file
9
app/src/main/res/drawable/ic_chevron_right_white.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M10,6L8.59,7.41 13.17,12l-4.58,4.59L10,18l6,-6z" />
|
||||
</vector>
|
18
app/src/main/res/drawable/ic_confirmed_cases.xml
Normal file
18
app/src/main/res/drawable/ic_confirmed_cases.xml
Normal file
|
@ -0,0 +1,18 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M21.5611,5.6551C21.9849,5.6551 22.4101,5.4929 22.7331,5.17C23.379,4.5241 23.379,3.472 22.7331,2.8261C22.0872,2.1802 21.0351,2.1802 20.3892,2.8261C19.9084,3.3069 19.7857,4.0127 20.0209,4.6074L17.414,7.2143C16.2859,6.32 14.8948,5.7443 13.3736,5.6259C13.3736,5.623 13.3751,5.6201 13.3751,5.6171V3.1768C13.9625,2.9211 14.3746,2.3366 14.3746,1.6571C14.3746,0.7438 13.6308,0 12.7175,0C11.8042,0 11.0604,0.7438 11.0604,1.6571C11.0604,2.3366 11.4725,2.9225 12.0599,3.1768V5.6171C12.0599,5.6245 12.0614,5.6303 12.0614,5.6361C10.4993,5.7867 9.0789,6.4208 7.9493,7.3853L6.9805,6.4165C7.2158,5.8203 7.093,5.1159 6.6123,4.6352C5.9664,3.9893 4.9157,3.9893 4.2684,4.6352C3.6225,5.2811 3.6225,6.3332 4.2684,6.9791C4.5811,7.2918 4.9976,7.4642 5.4403,7.4642C5.6537,7.4642 5.8597,7.4233 6.0511,7.3473L7.0273,8.3234C6.0935,9.4588 5.4915,10.8748 5.3614,12.4252H3.1768C2.9211,11.8378 2.3366,11.4257 1.6571,11.4257C0.7438,11.4257 0,12.1695 0,13.0828C0,13.9961 0.7438,14.7399 1.6571,14.7399C2.3366,14.7399 2.9225,14.3278 3.1768,13.7404H5.3658C5.5075,15.2864 6.1198,16.6965 7.0594,17.8232C7.0331,17.8422 7.0083,17.8612 6.9849,17.8846L6.1213,18.7482C6.0497,18.8198 6.0015,18.9031 5.9693,18.9907C5.7604,18.8972 5.5309,18.8461 5.2957,18.8461C4.8529,18.8461 4.4364,19.0185 4.1237,19.3312C3.4778,19.9771 3.4778,21.0278 4.1237,21.6751C4.4364,21.9878 4.8529,22.1603 5.2957,22.1603C5.7384,22.1603 6.1549,21.9878 6.4676,21.6751C6.9659,21.1768 7.0784,20.4374 6.8081,19.8295C6.8972,19.7974 6.9805,19.7477 7.0521,19.6775L7.9157,18.8139C7.9377,18.792 7.9552,18.7672 7.9742,18.7423C9.0672,19.6688 10.4306,20.284 11.9299,20.4549C11.2767,20.7414 10.8193,21.3931 10.8193,22.15C10.8193,23.17 11.6493,24 12.6693,24C13.6892,24 14.5192,23.17 14.5192,22.15C14.5192,21.4092 14.0794,20.7691 13.4496,20.4739C14.9868,20.338 16.3897,19.7375 17.5163,18.811L18.7219,20.0166C18.4866,20.6128 18.6094,21.3171 19.0901,21.7979C19.4028,22.1106 19.8193,22.283 20.2621,22.283C20.7048,22.283 21.1213,22.1106 21.434,21.7979C22.0799,21.152 22.0799,20.0999 21.434,19.454C20.9532,18.9732 20.2474,18.8505 19.6527,19.0857L18.4545,17.8875C19.5665,16.5884 20.2387,14.9006 20.2387,13.055C20.2387,11.1627 19.5314,9.4355 18.3697,8.1203L20.9518,5.5382C21.1461,5.6157 21.3536,5.6551 21.5611,5.6551ZM12.7862,19.1924C9.4018,19.1924 6.6488,16.4394 6.6488,13.055C6.6488,9.6707 9.4018,6.9177 12.7862,6.9177C16.1705,6.9177 18.9235,9.6707 18.9235,13.055C18.9235,16.4394 16.1705,19.1924 12.7862,19.1924Z"
|
||||
android:fillColor="#131313"/>
|
||||
<path
|
||||
android:pathData="M10.1106,13.4657C9.3975,13.4657 8.8174,14.0458 8.8174,14.7589C8.8174,15.472 9.3975,16.0522 10.1106,16.0522C10.8237,16.0522 11.4038,15.472 11.4038,14.7589C11.4038,14.0458 10.8237,13.4657 10.1106,13.4657Z"
|
||||
android:fillColor="#131313"/>
|
||||
<path
|
||||
android:pathData="M10.4964,9.3346C9.6766,9.3346 9.0103,10.0009 9.0103,10.8207C9.0103,11.6405 9.6766,12.3068 10.4964,12.3068C11.3161,12.3068 11.9825,11.6405 11.9825,10.8207C11.9825,10.0009 11.3161,9.3346 10.4964,9.3346Z"
|
||||
android:fillColor="#131313"/>
|
||||
<path
|
||||
android:pathData="M13.6179,11.9503C12.9048,11.9503 12.3247,12.5304 12.3247,13.2435C12.3247,13.9566 12.9048,14.5368 13.6179,14.5368C14.331,14.5368 14.9112,13.9566 14.9112,13.2435C14.9112,12.5304 14.331,11.9503 13.6179,11.9503Z"
|
||||
android:fillColor="#131313"/>
|
||||
</vector>
|
13
app/src/main/res/drawable/ic_heart.xml
Normal file
13
app/src/main/res/drawable/ic_heart.xml
Normal file
|
@ -0,0 +1,13 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M20.8401,4.61C20.3294,4.099 19.7229,3.6936 19.0555,3.4171C18.388,3.1405 17.6726,2.9982 16.9501,2.9982C16.2276,2.9982 15.5122,3.1405 14.8448,3.4171C14.1773,3.6936 13.5709,4.099 13.0601,4.61L12.0001,5.67L10.9401,4.61C9.9084,3.5783 8.5091,2.9987 7.0501,2.9987C5.5911,2.9987 4.1918,3.5783 3.1601,4.61C2.1284,5.6417 1.5488,7.041 1.5488,8.5C1.5488,9.959 2.1284,11.3583 3.1601,12.39L4.2201,13.45L12.0001,21.23L19.7801,13.45L20.8401,12.39C21.3511,11.8792 21.7565,11.2728 22.033,10.6053C22.3096,9.9379 22.4519,9.2225 22.4519,8.5C22.4519,7.7775 22.3096,7.0621 22.033,6.3946C21.7565,5.7272 21.3511,5.1207 20.8401,4.61V4.61Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#000000"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
14
app/src/main/res/drawable/ic_help_question.xml
Normal file
14
app/src/main/res/drawable/ic_help_question.xml
Normal file
|
@ -0,0 +1,14 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="14dp"
|
||||
android:height="21dp"
|
||||
android:viewportWidth="14"
|
||||
android:viewportHeight="21">
|
||||
<path
|
||||
android:pathData="M6.9473,3.3813C6.1715,3.2482 5.3735,3.394 4.6948,3.7929C4.0162,4.1918 3.5006,4.8179 3.2393,5.5605C2.9339,6.4289 1.9824,6.8851 1.1141,6.5797C0.2457,6.2742 -0.2106,5.3227 0.0949,4.4544C0.6173,2.9692 1.6486,1.7169 3.0059,0.9191C4.3632,0.1214 5.9591,-0.1702 7.5108,0.096C9.0626,0.3621 10.47,1.1689 11.484,2.3733C12.4977,3.5775 13.0526,5.1016 13.0505,6.6757C13.0497,9.2262 11.1587,10.9106 9.8083,11.8109C9.0822,12.2949 8.368,12.6508 7.8419,12.8846C7.5765,13.0026 7.353,13.0921 7.192,13.1535C7.1113,13.1842 7.0459,13.208 6.9983,13.225L6.9404,13.2452L6.922,13.2515L6.9155,13.2537L6.9129,13.2546C6.9124,13.2547 6.9108,13.2553 6.3838,11.6741L6.9108,13.2553C6.0376,13.5463 5.0937,13.0744 4.8026,12.2012C4.5118,11.3285 4.9829,10.3853 5.855,10.0936L5.8529,10.0943C5.853,10.0942 5.8532,10.0942 5.855,10.0936L5.8816,10.0842C5.9072,10.0751 5.9493,10.0599 6.0053,10.0385C6.1177,9.9957 6.2848,9.929 6.4881,9.8386C6.8995,9.6558 7.4353,9.3867 7.9593,9.0374C9.1086,8.2712 9.7171,7.456 9.7171,6.6741L9.7171,6.6716C9.7183,5.8844 9.4408,5.1222 8.9339,4.52C8.4269,3.9178 7.7232,3.5144 6.9473,3.3813Z"
|
||||
android:fillColor="#131313"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M4.8506,18.3405C4.8506,17.42 5.5968,16.6738 6.5173,16.6738H6.5339C7.4544,16.6738 8.2006,17.42 8.2006,18.3405C8.2006,19.261 7.4544,20.0072 6.5339,20.0072H6.5173C5.5968,20.0072 4.8506,19.261 4.8506,18.3405Z"
|
||||
android:fillColor="#131313"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
20
app/src/main/res/drawable/ic_mail_support.xml
Normal file
20
app/src/main/res/drawable/ic_mail_support.xml
Normal file
|
@ -0,0 +1,20 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M4,4H20C21.1,4 22,4.9 22,6V18C22,19.1 21.1,20 20,20H4C2.9,20 2,19.1 2,18V6C2,4.9 2.9,4 4,4Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#000000"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M22,6L12,13L2,6"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#000000"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
|
@ -1,18 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="40dp"
|
||||
android:height="40dp"
|
||||
android:viewportWidth="40"
|
||||
android:viewportHeight="40">
|
||||
<path
|
||||
android:pathData="M19.9998,5C11.7156,5 4.9998,11.7157 4.9998,20C4.9998,28.2842 11.7156,35 19.9998,35C28.2841,35 34.9998,28.2842 34.9998,20C34.9998,11.7157 28.2841,5 19.9998,5ZM1.6665,20C1.6665,9.8747 9.8746,1.6666 19.9998,1.6666C30.1251,1.6666 38.3332,9.8747 38.3332,20C38.3332,30.1252 30.1251,38.3333 19.9998,38.3333C9.8746,38.3333 1.6665,30.1252 1.6665,20Z"
|
||||
android:fillColor="#131313"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M20.4302,13.3739C19.6544,13.2408 18.8564,13.3866 18.1778,13.7855C17.4991,14.1843 16.9835,14.8105 16.7223,15.5531C16.4168,16.4214 15.4653,16.8777 14.597,16.5722C13.7286,16.2668 13.2724,15.3153 13.5778,14.4469C14.1003,12.9618 15.1315,11.7094 16.4888,10.9117C17.8462,10.114 19.442,9.8224 20.9938,10.0885C22.5455,10.3547 23.953,11.1614 24.9669,12.3659C25.9806,13.5701 26.5355,15.0941 26.5334,16.6682C26.5326,19.2188 24.6416,20.9032 23.2912,21.8034C22.5651,22.2875 21.851,22.6434 21.3248,22.8772C21.0594,22.9952 20.8359,23.0847 20.6749,23.146C20.5942,23.1768 20.5288,23.2006 20.4812,23.2175L20.4233,23.2378L20.4049,23.2441L20.3984,23.2463L20.3958,23.2471C20.3953,23.2473 20.3937,23.2478 19.8667,21.6667L20.3937,23.2478C19.5205,23.5389 18.5766,23.067 18.2856,22.1937C17.9947,21.3211 18.4658,20.3779 19.3379,20.0861L19.3358,20.0868C19.3359,20.0868 19.3361,20.0868 19.3379,20.0861L19.3645,20.0768C19.3901,20.0677 19.4322,20.0524 19.4882,20.0311C19.6006,19.9883 19.7677,19.9215 19.971,19.8312C20.3824,19.6483 20.9182,19.3792 21.4422,19.0299C22.5915,18.2637 23.2,17.4486 23.2,16.6667L23.2,16.6642C23.2012,15.877 22.9237,15.1148 22.4168,14.5126C21.9098,13.9103 21.2061,13.507 20.4302,13.3739Z"
|
||||
android:fillColor="#131313"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M18.3335,28.3333C18.3335,27.4128 19.0797,26.6666 20.0002,26.6666H20.0168C20.9373,26.6666 21.6835,27.4128 21.6835,28.3333C21.6835,29.2538 20.9373,30 20.0168,30H20.0002C19.0797,30 18.3335,29.2538 18.3335,28.3333Z"
|
||||
android:fillColor="#131313"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
|
@ -1,20 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="48dp"
|
||||
android:height="48dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:pathData="M4,4L44,44"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="8"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#A31919"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M44,4L4,44"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="8"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#A31919"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
23
app/src/main/res/drawable/ic_red_error.xml
Normal file
23
app/src/main/res/drawable/ic_red_error.xml
Normal file
|
@ -0,0 +1,23 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12,12m-12,0a12,12 0,1 1,24 0a12,12 0,1 1,-24 0"
|
||||
android:fillColor="#ffffff"/>
|
||||
<path
|
||||
android:pathData="M12,12.6827V8"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="3"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#A31919"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M12,17.3652H12.012"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="3"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#A31919"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
20
app/src/main/res/drawable/ic_settings_outline_black.xml
Normal file
20
app/src/main/res/drawable/ic_settings_outline_black.xml
Normal file
|
@ -0,0 +1,20 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12,15C13.6569,15 15,13.6569 15,12C15,10.3431 13.6569,9 12,9C10.3431,9 9,10.3431 9,12C9,13.6569 10.3431,15 12,15Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#000000"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M19.4,15C19.2669,15.3016 19.2272,15.6362 19.286,15.9606C19.3448,16.285 19.4995,16.5843 19.73,16.82L19.79,16.88C19.976,17.0657 20.1235,17.2863 20.2241,17.5291C20.3248,17.7719 20.3766,18.0322 20.3766,18.295C20.3766,18.5578 20.3248,18.8181 20.2241,19.0609C20.1235,19.3037 19.976,19.5243 19.79,19.71C19.6043,19.896 19.3837,20.0435 19.1409,20.1441C18.8981,20.2448 18.6378,20.2966 18.375,20.2966C18.1122,20.2966 17.8519,20.2448 17.6091,20.1441C17.3663,20.0435 17.1457,19.896 16.96,19.71L16.9,19.65C16.6643,19.4195 16.365,19.2648 16.0406,19.206C15.7162,19.1472 15.3816,19.1869 15.08,19.32C14.7842,19.4468 14.532,19.6572 14.3543,19.9255C14.1766,20.1938 14.0813,20.5082 14.08,20.83V21C14.08,21.5304 13.8693,22.0391 13.4942,22.4142C13.1191,22.7893 12.6104,23 12.08,23C11.5496,23 11.0409,22.7893 10.6658,22.4142C10.2907,22.0391 10.08,21.5304 10.08,21V20.91C10.0723,20.579 9.9651,20.258 9.7725,19.9887C9.5799,19.7194 9.3107,19.5143 9,19.4C8.6984,19.2669 8.3638,19.2272 8.0394,19.286C7.715,19.3448 7.4157,19.4995 7.18,19.73L7.12,19.79C6.9342,19.976 6.7137,20.1235 6.4709,20.2241C6.2281,20.3248 5.9678,20.3766 5.705,20.3766C5.4422,20.3766 5.1819,20.3248 4.9391,20.2241C4.6963,20.1235 4.4757,19.976 4.29,19.79C4.1041,19.6043 3.9565,19.3837 3.8559,19.1409C3.7552,18.8981 3.7034,18.6378 3.7034,18.375C3.7034,18.1122 3.7552,17.8519 3.8559,17.6091C3.9565,17.3663 4.1041,17.1457 4.29,16.96L4.35,16.9C4.5805,16.6643 4.7352,16.365 4.794,16.0406C4.8528,15.7162 4.8131,15.3816 4.68,15.08C4.5532,14.7842 4.3428,14.532 4.0745,14.3543C3.8062,14.1766 3.4918,14.0813 3.17,14.08H3C2.4696,14.08 1.9609,13.8693 1.5858,13.4942C1.2107,13.1191 1,12.6104 1,12.08C1,11.5496 1.2107,11.0409 1.5858,10.6658C1.9609,10.2907 2.4696,10.08 3,10.08H3.09C3.421,10.0723 3.742,9.9651 4.0113,9.7725C4.2806,9.5799 4.4857,9.3107 4.6,9C4.7331,8.6984 4.7728,8.3638 4.714,8.0394C4.6552,7.715 4.5005,7.4157 4.27,7.18L4.21,7.12C4.0241,6.9342 3.8765,6.7137 3.7759,6.4709C3.6752,6.2281 3.6234,5.9678 3.6234,5.705C3.6234,5.4422 3.6752,5.1819 3.7759,4.9391C3.8765,4.6963 4.0241,4.4757 4.21,4.29C4.3958,4.1041 4.6163,3.9565 4.8591,3.8559C5.1019,3.7552 5.3622,3.7034 5.625,3.7034C5.8878,3.7034 6.1481,3.7552 6.3909,3.8559C6.6337,3.9565 6.8542,4.1041 7.04,4.29L7.1,4.35C7.3357,4.5805 7.635,4.7352 7.9594,4.794C8.2838,4.8528 8.6184,4.8131 8.92,4.68H9C9.2958,4.5532 9.548,4.3428 9.7257,4.0745C9.9034,3.8062 9.9987,3.4918 10,3.17V3C10,2.4696 10.2107,1.9609 10.5858,1.5858C10.9609,1.2107 11.4696,1 12,1C12.5304,1 13.0391,1.2107 13.4142,1.5858C13.7893,1.9609 14,2.4696 14,3V3.09C14.0013,3.4118 14.0966,3.7262 14.2743,3.9945C14.452,4.2628 14.7042,4.4732 15,4.6C15.3016,4.7331 15.6362,4.7728 15.9606,4.714C16.285,4.6552 16.5843,4.5005 16.82,4.27L16.88,4.21C17.0657,4.0241 17.2863,3.8765 17.5291,3.7759C17.7719,3.6752 18.0322,3.6234 18.295,3.6234C18.5578,3.6234 18.8181,3.6752 19.0609,3.7759C19.3037,3.8765 19.5243,4.0241 19.71,4.21C19.896,4.3958 20.0435,4.6163 20.1441,4.8591C20.2448,5.1019 20.2966,5.3622 20.2966,5.625C20.2966,5.8878 20.2448,6.1481 20.1441,6.3909C20.0435,6.6337 19.896,6.8542 19.71,7.04L19.65,7.1C19.4195,7.3357 19.2648,7.635 19.206,7.9594C19.1472,8.2838 19.1869,8.6184 19.32,8.92V9C19.4468,9.2958 19.6572,9.548 19.9255,9.7257C20.1938,9.9034 20.5082,9.9987 20.83,10H21C21.5304,10 22.0391,10.2107 22.4142,10.5858C22.7893,10.9609 23,11.4696 23,12C23,12.5304 22.7893,13.0391 22.4142,13.4142C22.0391,13.7893 21.5304,14 21,14H20.91C20.5882,14.0013 20.2738,14.0966 20.0055,14.2743C19.7372,14.452 19.5268,14.7042 19.4,15V15Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#000000"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
20
app/src/main/res/drawable/ic_trending_up.xml
Normal file
20
app/src/main/res/drawable/ic_trending_up.xml
Normal file
|
@ -0,0 +1,20 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M23,6L13.5,15.5L8.5,10.5L1,18"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#000000"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M17,6H23V12"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#000000"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
|
@ -7,16 +7,16 @@
|
|||
android:pathData="M12,12m-12,0a12,12 0,1 1,24 0a12,12 0,1 1,-24 0"
|
||||
android:fillColor="#A31919"/>
|
||||
<path
|
||||
android:pathData="M16.5,7.5L7.5,16.5"
|
||||
android:pathData="M12,12.6827V8"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:strokeWidth="3"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M7.5,7.5L16.5,16.5"
|
||||
android:pathData="M12,17.3652H12.012"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:strokeWidth="3"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeLineCap="round"/>
|
|
@ -1,27 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:exitFadeDuration="@android:integer/config_mediumAnimTime">
|
||||
<item
|
||||
android:state_enabled="false"
|
||||
android:drawable="@drawable/ic_red_cross" />
|
||||
<item
|
||||
android:state_activated="true"
|
||||
android:drawable="@drawable/ic_green_tick" />
|
||||
<item
|
||||
android:state_selected="true"
|
||||
android:drawable="@drawable/ic_green_tick" />
|
||||
<item
|
||||
android:state_selected="false"
|
||||
android:drawable="@drawable/ic_red_cross" />
|
||||
<item
|
||||
android:state_checked="true"
|
||||
android:drawable="@drawable/ic_green_tick" />
|
||||
<item
|
||||
android:state_pressed="true"
|
||||
android:drawable="@drawable/ic_green_tick" />
|
||||
<item
|
||||
android:state_focused="true"
|
||||
android:drawable="@drawable/ic_green_tick" />
|
||||
<item
|
||||
android:drawable="@drawable/ic_green_tick" />
|
||||
</selector>
|
|
@ -3,6 +3,6 @@
|
|||
android:shape="rectangle">
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="@color/error" />
|
||||
android:color="@color/error_red" />
|
||||
<corners android:radius="2dp" />
|
||||
</shape>
|
|
@ -4,7 +4,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:context=".DeviceNameChangePromptActivity">
|
||||
tools:context=".ui.devicename.DeviceNameChangePromptActivity">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
android:layout_gravity="center_vertical"
|
||||
android:background="@color/splash_background"
|
||||
android:backgroundTint="@color/splash_frame_background"
|
||||
tools:context=".SplashActivity"
|
||||
tools:context=".ui.splash.SplashActivity"
|
||||
>
|
||||
|
||||
<ImageView
|
||||
|
|
|
@ -5,6 +5,27 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/home_push_notification_token"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/space_16"
|
||||
android:background="@color/screen_background"
|
||||
android:gravity="center"
|
||||
android:paddingStart="@dimen/space_8"
|
||||
android:paddingEnd="@dimen/space_8"
|
||||
android:text="Firebase Push Token:"
|
||||
style="?textAppearanceBody2"
|
||||
android:textColor="@color/slate_black_2"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<Space
|
||||
android:id="@+id/push_token_space"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/space_24"
|
||||
app:layout_constraintTop_toBottomOf="@+id/home_push_notification_token" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerview"
|
||||
android:layout_width="0dp"
|
||||
|
@ -12,22 +33,11 @@
|
|||
android:background="@android:color/darker_gray"
|
||||
android:backgroundTint="@color/lighter"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/push_token_space"
|
||||
tools:listitem="@layout/recycler_view_item" />
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/delete"
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -35,9 +45,7 @@
|
|||
android:layout_margin="8dp"
|
||||
android:src="@drawable/ic_delete_black_24dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
|
||||
app:layout_constraintTop_toBottomOf="@+id/home_push_notification_token" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="@dimen/keyline_1"
|
||||
android:layout_marginTop="@dimen/keyline_1">
|
||||
|
||||
<TextView
|
||||
|
@ -132,7 +133,7 @@
|
|||
android:layout_marginEnd="@dimen/keyline_5"
|
||||
android:text="@string/invalid_phone_number"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/error"
|
||||
android:textColor="@color/error_red"
|
||||
android:textSize="16sp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
android:layout_marginStart="@dimen/keyline_2"
|
||||
android:text="@string/wrong_ping_number"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/error"
|
||||
android:textColor="@color/error_red"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/pin"
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
style="@style/HelpToolbarStyle"
|
||||
app:titleTextAppearance="@style/ToolbarStyle.TitleTextStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
|
|
|
@ -1,76 +1,68 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<data>
|
||||
|
||||
<variable
|
||||
name="viewModel"
|
||||
type="au.gov.health.covidsafe.ui.home.HomeFragmentViewModel" />
|
||||
|
||||
</data>
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/home_root"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#f6f6f6">
|
||||
android:background="@color/screen_background">
|
||||
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
android:id="@+id/swipeRefreshLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
app:refreshing="@{safeUnbox(viewModel.isRefreshing)}">
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fillViewport="true">
|
||||
android:fillViewport="true"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<View
|
||||
android:id="@+id/header_background"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:background="@color/lighter_green"
|
||||
android:importantForAccessibility="no"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/header_background_overlap"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
<include layout="@layout/fragment_home_header" />
|
||||
|
||||
<View
|
||||
android:id="@+id/header_background_overlap"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp"
|
||||
android:background="@color/lighter_green"
|
||||
app:layout_constraintTop_toBottomOf="@+id/header_barrier" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/home_header_top_left_icon"
|
||||
android:layout_width="@dimen/keyline_8"
|
||||
android:layout_height="@dimen/keyline_8"
|
||||
android:layout_marginLeft="@dimen/keyline_4"
|
||||
android:layout_marginTop="@dimen/keyline_7"
|
||||
android:src="@drawable/ic_splash_screen_logo"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/home_header_help"
|
||||
android:layout_width="@dimen/keyline_9"
|
||||
<androidx.constraintlayout.widget.Barrier
|
||||
android:id="@+id/home_header_barrier"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/keyline_7"
|
||||
android:accessibilityTraversalAfter="@id/home_header_setup_complete_header_line_2"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:drawableTop="@drawable/ic_help_outline_black"
|
||||
android:drawablePadding="-4dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/title_help"
|
||||
android:textAlignment="center"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
app:barrierDirection="bottom"
|
||||
app:constraint_referenced_ids="header_background" />
|
||||
|
||||
<include layout="@layout/fragment_home_setup_complete_header" />
|
||||
<include layout="@layout/fragment_home_setup_status_header" />
|
||||
|
||||
<androidx.constraintlayout.widget.Barrier
|
||||
android:id="@+id/case_top_barrier"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:barrierDirection="bottom"
|
||||
app:constraint_referenced_ids="active_status_card" />
|
||||
|
||||
<include
|
||||
layout="@layout/fragment_home_case_statistics"
|
||||
app:viewModel="@{viewModel}" />
|
||||
|
||||
<androidx.constraintlayout.widget.Barrier
|
||||
android:id="@+id/header_barrier"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:barrierDirection="bottom"
|
||||
app:constraint_referenced_ids="home_header_no_bluetooth_pairing" />
|
||||
|
||||
<include layout="@layout/fragment_home_setup_incomplete_content" />
|
||||
app:constraint_referenced_ids="case_number_card" />
|
||||
|
||||
<include layout="@layout/fragment_home_external_links" />
|
||||
|
||||
|
@ -79,28 +71,29 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:barrierDirection="bottom"
|
||||
app:constraint_referenced_ids="push_card_view, change_language_card" />
|
||||
app:constraint_referenced_ids="health_link_card_view" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/home_version_number"
|
||||
style="?textAppearanceBody2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/keyline_4"
|
||||
android:layout_marginBottom="@dimen/keyline_5"
|
||||
android:layout_marginTop="@dimen/space_24"
|
||||
android:gravity="center"
|
||||
android:textColor="@color/cadet_grey"
|
||||
android:textColor="@color/slate_black_2"
|
||||
app:layout_constraintTop_toBottomOf="@+id/content_barrier" />
|
||||
|
||||
<Space
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/keyline_2"
|
||||
android:layout_height="@dimen/space_24"
|
||||
app:layout_constraintTop_toBottomOf="@+id/home_version_number" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/app_update_reminder"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -113,8 +106,11 @@
|
|||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/keyline_2"
|
||||
android:background="@color/error" />
|
||||
android:layout_height="@dimen/space_12"
|
||||
android:background="@color/error_red" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
</layout>
|
166
app/src/main/res/layout/fragment_home_case_statistics.xml
Normal file
166
app/src/main/res/layout/fragment_home_case_statistics.xml
Normal file
|
@ -0,0 +1,166 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:card_view="http://schemas.android.com/tools"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<data>
|
||||
|
||||
<variable
|
||||
name="viewModel"
|
||||
type="au.gov.health.covidsafe.ui.home.HomeFragmentViewModel" />
|
||||
|
||||
<import type="au.gov.health.covidsafe.ui.home.CaseNumbersState" />
|
||||
|
||||
</data>
|
||||
|
||||
<merge>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/case_number_card"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/space_24"
|
||||
app:layout_constraintTop_toBottomOf="@+id/case_top_barrier"
|
||||
card_view:cardBackgroundColor="@color/white"
|
||||
card_view:cardCornerRadius="0dp"
|
||||
card_view:cardMaxElevation="@dimen/card_elevation_10dp"
|
||||
card_view:cardUseCompatPadding="true"
|
||||
card_view:contentPadding="0dp">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/case_loading_view"
|
||||
visibility="@{viewModel.caseNumberDataState == CaseNumbersState.LOADING}"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/case_number_loading_card_height"
|
||||
android:visibility="gone">
|
||||
|
||||
<com.airbnb.lottie.LottieAnimationView
|
||||
android:id="@+id/case_loading_animation_view"
|
||||
android:layout_width="@dimen/covidsafe_loading_animation_size"
|
||||
android:layout_height="@dimen/covidsafe_loading_animation_size"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="@dimen/space_24"
|
||||
android:layout_marginBottom="@dimen/space_24"
|
||||
app:lottie_autoPlay="true"
|
||||
app:lottie_fileName="loading_upload.json"
|
||||
app:lottie_loop="true"
|
||||
app:lottie_speed="1" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/case_loading_animation_view"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:text="@string/loading_numbers"
|
||||
android:textAppearance="@style/fontRobotoRegular16"
|
||||
android:textColor="@color/slate_black_1" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
visibility="@{viewModel.caseNumberDataState != CaseNumbersState.LOADING}"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/national_numbers_text_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/space_16"
|
||||
android:layout_marginTop="@dimen/space_16"
|
||||
android:layout_marginBottom="@dimen/space_8"
|
||||
android:text="@string/national_numbers"
|
||||
android:textAppearance="@style/fontRobotoRegular28"
|
||||
android:textColor="@color/slate_black_1"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/date_text_view"
|
||||
dateFormat="@{viewModel.caseStatisticsLiveData.updatedDate}"
|
||||
visibility="@{viewModel.caseStatisticsLiveData != null}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/space_16"
|
||||
android:layout_marginEnd="@dimen/space_16"
|
||||
android:layout_marginBottom="@dimen/space_16"
|
||||
android:text="27 August 2020 at 3pm AEST"
|
||||
android:textAppearance="@style/fontRobotoRegular16"
|
||||
android:textColor="@color/slate_black_2"
|
||||
android:visibility="visible"
|
||||
tools:text="27 August 2020 at 3pm AEST" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/show_error_message"
|
||||
visibility="@{viewModel.caseNumberDataState == CaseNumbersState.ERROR_NO_NETWORK || viewModel.caseNumberDataState == CaseNumbersState.ERROR_UNKNOWN}"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/no_network_error_text_view"
|
||||
visibility="@{viewModel.caseNumberDataState == CaseNumbersState.ERROR_NO_NETWORK}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/space_16"
|
||||
android:layout_marginEnd="@dimen/space_16"
|
||||
android:layout_marginBottom="@dimen/space_16"
|
||||
android:text="@string/numbers_no_internet"
|
||||
android:textAppearance="@style/fontRobotoRegular16"
|
||||
android:textColor="@color/error_red"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/unknown_error_text_view"
|
||||
visibility="@{viewModel.caseNumberDataState == CaseNumbersState.ERROR_UNKNOWN}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/space_16"
|
||||
android:layout_marginEnd="@dimen/space_16"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:text="@string/numbers_error"
|
||||
android:textAppearance="@style/fontRobotoRegular16"
|
||||
android:textColor="@color/error_red"
|
||||
android:visibility="gone" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/refresh_button"
|
||||
addUnderline="@{@string/numbers_refresh}"
|
||||
visibility="@{viewModel.caseNumberDataState == CaseNumbersState.ERROR_UNKNOWN}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/transparent"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:paddingStart="@dimen/space_16"
|
||||
android:paddingTop="@dimen/space_16"
|
||||
android:paddingEnd="@dimen/space_16"
|
||||
android:paddingBottom="@dimen/space_16"
|
||||
android:textAppearance="@style/fontRobotoRegular16"
|
||||
android:textColor="@color/dark_green"
|
||||
android:visibility="gone" />
|
||||
|
||||
<include
|
||||
layout="@layout/view_national_case_statistics"
|
||||
app:viewModel="@{viewModel}" />
|
||||
|
||||
<include
|
||||
layout="@layout/view_state_case_statistics"
|
||||
app:viewModel="@{viewModel}" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
</merge>
|
||||
|
||||
</layout>
|
|
@ -3,227 +3,31 @@
|
|||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:card_view="http://schemas.android.com/tools">
|
||||
|
||||
<androidx.constraintlayout.widget.Barrier
|
||||
android:id="@+id/cards_top_barrier"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:barrierDirection="bottom"
|
||||
app:constraint_referenced_ids="permissions_card_bottom_space,header_barrier" />
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/improve_performance_card"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/keyline_4"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintTop_toBottomOf="@+id/cards_top_barrier"
|
||||
card_view:cardBackgroundColor="@color/white"
|
||||
card_view:cardCornerRadius="6dp"
|
||||
card_view:cardMaxElevation="2dp"
|
||||
card_view:cardUseCompatPadding="true"
|
||||
card_view:contentPadding="0dp">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/improve_performance_card_linear_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/slack_black_3"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/improve_performance_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/white"
|
||||
android:padding="@dimen/keyline_4"
|
||||
android:text="@string/improve_heading"
|
||||
android:textSize="28sp" />
|
||||
|
||||
<au.gov.health.covidsafe.ui.home.view.ExternalLinkCard
|
||||
android:id="@+id/internet_connection_tile"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="1dp"
|
||||
android:background="@color/white"
|
||||
android:minHeight="@dimen/external_link_height"
|
||||
android:paddingTop="@dimen/keyline_0"
|
||||
android:paddingBottom="@dimen/keyline_0"
|
||||
app:external_linkCard_content="@string/internet_connection_content"
|
||||
app:external_linkCard_icon="@drawable/ic_home_share"
|
||||
app:external_linkCard_icon_visible="false"
|
||||
app:external_linkCard_text_color="@color/error"
|
||||
app:external_linkCard_title="@string/internet_connection_heading" />
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/external_links_top_card"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/keyline_4"
|
||||
app:layout_constraintTop_toBottomOf="@+id/improve_performance_card"
|
||||
card_view:cardBackgroundColor="@color/white"
|
||||
card_view:cardCornerRadius="6dp"
|
||||
card_view:cardMaxElevation="2dp"
|
||||
card_view:cardUseCompatPadding="true"
|
||||
card_view:contentPadding="0dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<au.gov.health.covidsafe.ui.home.view.ExternalLinkCard
|
||||
android:id="@+id/home_setup_complete_share"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/white"
|
||||
android:minHeight="@dimen/external_link_height"
|
||||
android:paddingTop="@dimen/keyline_0"
|
||||
android:paddingBottom="@dimen/keyline_0"
|
||||
app:external_linkCard_content="@string/home_set_complete_external_link_share_content"
|
||||
app:external_linkCard_icon="@drawable/ic_home_share"
|
||||
app:external_linkCard_icon_background="@drawable/background_circular_green"
|
||||
app:external_linkCard_icon_padding="@dimen/keyline_1"
|
||||
app:external_linkCard_title="@string/home_set_complete_external_link_share_title" />
|
||||
|
||||
<View
|
||||
android:id="@+id/home_setup_complete_share_space"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="@color/slack_black_3"
|
||||
app:layout_constraintTop_toBottomOf="@+id/home_setup_complete_share" />
|
||||
|
||||
<au.gov.health.covidsafe.ui.home.view.ExternalLinkCard
|
||||
android:id="@+id/home_been_tested_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/white"
|
||||
android:minHeight="@dimen/external_link_height"
|
||||
android:paddingTop="@dimen/keyline_0"
|
||||
android:paddingBottom="@dimen/keyline_0"
|
||||
app:external_linkCard_content="@string/home_set_complete_external_link_been_contacted_content"
|
||||
app:external_linkCard_icon="@drawable/ic_upload_icon"
|
||||
app:external_linkCard_icon_background="@drawable/background_circular_green"
|
||||
app:external_linkCard_icon_padding="@dimen/keyline_1"
|
||||
app:external_linkCard_title="@string/home_set_complete_external_link_been_contacted_title" />
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/external_links_bottom_card"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/keyline_4"
|
||||
app:layout_constraintTop_toBottomOf="@+id/external_links_top_card"
|
||||
card_view:cardBackgroundColor="@color/white"
|
||||
card_view:cardCornerRadius="6dp"
|
||||
card_view:cardMaxElevation="2dp"
|
||||
card_view:cardUseCompatPadding="true"
|
||||
card_view:contentPadding="0dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<au.gov.health.covidsafe.ui.home.view.ExternalLinkCard
|
||||
android:id="@+id/home_setup_complete_app"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/white"
|
||||
android:minHeight="@dimen/external_link_height"
|
||||
android:paddingTop="@dimen/keyline_0"
|
||||
android:paddingBottom="@dimen/keyline_0"
|
||||
app:external_linkCard_content="@string/home_set_complete_external_link_app_content"
|
||||
app:external_linkCard_icon="@drawable/ic_home_news"
|
||||
app:external_linkCard_icon_background="@drawable/background_circular_black"
|
||||
app:external_linkCard_title="@string/home_set_complete_external_link_app_title"
|
||||
app:layout_constraintTop_toBottomOf="@+id/home_setup_complete_share_space" />
|
||||
|
||||
<View
|
||||
android:id="@+id/home_setup_complete_news_space"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="@color/slack_black_3"
|
||||
app:layout_constraintTop_toBottomOf="@+id/home_setup_complete_app" />
|
||||
|
||||
<au.gov.health.covidsafe.ui.home.view.ExternalLinkCard
|
||||
android:id="@+id/home_setup_complete_news"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/white"
|
||||
android:minHeight="@dimen/external_link_height"
|
||||
android:paddingTop="@dimen/keyline_0"
|
||||
android:paddingBottom="@dimen/keyline_0"
|
||||
app:external_linkCard_content="@string/home_set_complete_external_link_news_content"
|
||||
app:external_linkCard_icon="@drawable/ic_home_news"
|
||||
app:external_linkCard_icon_background="@drawable/background_circular_dark_cerulean_1"
|
||||
app:external_linkCard_title="@string/home_set_complete_external_link_news_title"
|
||||
app:layout_constraintTop_toBottomOf="@+id/home_setup_complete_news_space" />
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/help_topics_card"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/keyline_4"
|
||||
app:layout_constraintTop_toBottomOf="@+id/external_links_bottom_card"
|
||||
android:layout_marginTop="@dimen/space_24"
|
||||
app:layout_constraintTop_toBottomOf="@+id/header_barrier"
|
||||
card_view:cardBackgroundColor="@color/white"
|
||||
card_view:cardCornerRadius="6dp"
|
||||
card_view:cardMaxElevation="2dp"
|
||||
card_view:cardCornerRadius="0dp"
|
||||
card_view:cardMaxElevation="@dimen/card_elevation_10dp"
|
||||
card_view:cardUseCompatPadding="true"
|
||||
card_view:contentPadding="0dp">
|
||||
|
||||
<au.gov.health.covidsafe.ui.home.view.ExternalLinkCard
|
||||
android:id="@+id/help_topics_link"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/white"
|
||||
android:minHeight="@dimen/external_link_height"
|
||||
android:paddingTop="@dimen/keyline_0"
|
||||
android:paddingBottom="@dimen/keyline_0"
|
||||
app:external_linkCard_content="@string/home_set_complete_external_link_help_topics_content"
|
||||
app:external_linkCard_icon="@drawable/ic_question_circle"
|
||||
app:external_linkCard_title="@string/home_set_complete_external_link_help_topics_title" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
<include layout="@layout/view_help_topics_tile" />
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/notification_status_card"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/keyline_4"
|
||||
app:layout_constraintTop_toBottomOf="@+id/help_topics_card"
|
||||
card_view:cardBackgroundColor="@color/white"
|
||||
card_view:cardCornerRadius="6dp"
|
||||
card_view:cardMaxElevation="2dp"
|
||||
card_view:cardUseCompatPadding="true"
|
||||
card_view:contentPadding="0dp">
|
||||
|
||||
<au.gov.health.covidsafe.ui.home.view.ExternalLinkCard
|
||||
android:id="@+id/notification_status_link"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/white"
|
||||
android:minHeight="@dimen/external_link_height"
|
||||
android:paddingTop="@dimen/keyline_0"
|
||||
android:paddingBottom="@dimen/keyline_0"
|
||||
app:external_linkCard_content="@string/NotificationsEnabledBlurb"
|
||||
app:external_linkCard_icon="@drawable/ic_bell"
|
||||
app:external_linkCard_title="@string/home_set_complete_external_link_notifications_title_iOS" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/change_language_card"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/keyline_4"
|
||||
app:layout_constraintTop_toBottomOf="@+id/notification_status_card"
|
||||
android:layout_marginTop="@dimen/space_24"
|
||||
app:layout_constraintTop_toBottomOf="@+id/help_topics_card"
|
||||
card_view:cardBackgroundColor="@color/white"
|
||||
card_view:cardCornerRadius="6dp"
|
||||
card_view:cardMaxElevation="2dp"
|
||||
card_view:cardCornerRadius="0dp"
|
||||
card_view:cardMaxElevation="@dimen/card_elevation_10dp"
|
||||
card_view:cardUseCompatPadding="true"
|
||||
card_view:contentPadding="0dp">
|
||||
|
||||
|
@ -233,11 +37,62 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:background="@color/white"
|
||||
android:minHeight="@dimen/external_link_height"
|
||||
android:paddingTop="@dimen/keyline_0"
|
||||
android:paddingBottom="@dimen/keyline_0"
|
||||
android:paddingTop="@dimen/space_4"
|
||||
android:paddingBottom="@dimen/space_4"
|
||||
app:external_linkCard_content="@string/change_language_content"
|
||||
app:external_linkCard_icon="@drawable/ic_globe"
|
||||
app:external_linkCard_start_icon="@drawable/ic_globe"
|
||||
app:external_linkCard_start_icon_background="@drawable/background_circular_green"
|
||||
app:external_linkCard_start_icon_padding="@dimen/space_8"
|
||||
app:external_linkCard_title="@string/change_language" />
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/share_card_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/space_24"
|
||||
app:cardBackgroundColor="@color/white"
|
||||
app:layout_constraintTop_toBottomOf="@+id/change_language_card"
|
||||
card_view:cardBackgroundColor="@color/white"
|
||||
card_view:cardCornerRadius="0dp"
|
||||
card_view:cardMaxElevation="@dimen/card_elevation_10dp"
|
||||
card_view:cardUseCompatPadding="true"
|
||||
card_view:contentPadding="0dp">
|
||||
|
||||
<include layout="@layout/view_covid_share_tile" />
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/health_link_card_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/space_24"
|
||||
app:layout_constraintTop_toBottomOf="@+id/share_card_view"
|
||||
card_view:cardBackgroundColor="@color/dark_green"
|
||||
card_view:cardCornerRadius="0dp"
|
||||
card_view:cardMaxElevation="@dimen/card_elevation_10dp"
|
||||
card_view:cardUseCompatPadding="true"
|
||||
card_view:contentPadding="0dp">
|
||||
|
||||
<au.gov.health.covidsafe.ui.home.view.ExternalLinkCard
|
||||
android:id="@+id/home_been_tested_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/dark_green"
|
||||
android:minHeight="@dimen/external_link_height"
|
||||
android:paddingTop="@dimen/space_4"
|
||||
android:paddingBottom="@dimen/space_4"
|
||||
app:external_linkCard_content="@string/home_set_complete_external_link_been_contacted_content"
|
||||
app:external_linkCard_start_icon="@drawable/ic_upload_icon"
|
||||
app:external_linkCard_start_icon_background="@drawable/background_circular_white"
|
||||
app:external_linkCard_start_icon_padding="@dimen/space_8"
|
||||
app:external_linkCard_text_color="@color/white"
|
||||
app:external_linkCard_content_padding="@dimen/space_8"
|
||||
app:external_linkCard_title="@string/home_set_complete_external_link_been_contacted_title" />
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
</merge>
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue