From d2a2342abf25992ff4e09da449f0c44168c13c3a Mon Sep 17 00:00:00 2001 From: COVIDSafe Support <64945427+covidsafe-support@users.noreply.github.com> Date: Tue, 18 Aug 2020 10:57:15 +1000 Subject: [PATCH] COVIDSafe code from version 1.0.54 (#24) --- app/build.gradle | 10 +- app/src/main/AndroidManifest.xml | 2 + .../DeviceNameChangePromptActivity.kt | 32 + .../au/gov/health/covidsafe/HomeActivity.kt | 57 +- .../InternetConnectionIssuesActivity.kt | 26 + .../au/gov/health/covidsafe/Preference.kt | 11 +- .../java/au/gov/health/covidsafe/Utils.kt | 31 + .../extensions/PermissionExtensions.kt | 4 - .../gov/health/covidsafe/links/LinkBuilder.kt | 4 + .../networking/response/MessagesResponse.kt | 5 +- .../covidsafe/networking/service/AwsClient.kt | 2 +- .../scheduler/GetMessagesScheduler.kt | 39 +- .../crypto/EncryptedSharedPreferences.java | 1 + .../streetpass/persistence/Encryption.kt | 24 +- .../health/covidsafe/ui/home/HomeFragment.kt | 171 +++- .../ui/home/view/ExternalLinkCard.kt | 108 ++- .../enternumber/EnterNumberFragment.kt | 2 + .../PermissionDeviceNameFragment.kt | 2 + .../res/drawable-hdpi/small_green_tick.png | Bin 910 -> 0 bytes .../res/drawable-hdpi/small_red_cross.png | Bin 838 -> 0 bytes .../res/drawable-mdpi/small_green_tick.png | Bin 654 -> 0 bytes .../res/drawable-mdpi/small_red_cross.png | Bin 564 -> 0 bytes .../res/drawable-xhdpi/small_green_tick.png | Bin 1218 -> 0 bytes .../res/drawable-xhdpi/small_red_cross.png | Bin 1089 -> 0 bytes .../res/drawable-xxhdpi/small_green_tick.png | Bin 1670 -> 0 bytes .../res/drawable-xxhdpi/small_red_cross.png | Bin 1561 -> 0 bytes app/src/main/res/drawable/ic_bell.xml | 14 + .../res/drawable/ic_chevron_right_red.xml | 9 + app/src/main/res/drawable/ic_green_tick.xml | 16 + .../main/res/drawable/ic_internet_issues.xml | 74 ++ app/src/main/res/drawable/ic_red_cross.xml | 23 +- .../res/drawable/ic_red_cross_no_circle.xml | 20 + app/src/main/res/drawable/icon_checkbox.xml | 16 +- .../activity_device_name_change_prompt.xml | 29 + .../activity_internet_connection_issues.xml | 69 ++ .../main/res/layout/fragment_enter_pin.xml | 2 +- app/src/main/res/layout/fragment_home.xml | 43 - .../layout/fragment_home_external_links.xml | 78 +- ...fragment_home_setup_incomplete_content.xml | 11 - .../fragment_permission_device_name.xml | 2 +- app/src/main/res/values-ar/strings.xml | 871 ++++++++--------- app/src/main/res/values-el-rGR/strings.xml | 785 ++++++++-------- app/src/main/res/values-it-rIT/strings.xml | 872 ++++++++--------- app/src/main/res/values-ko/strings.xml | 872 ++++++++--------- app/src/main/res/values-pa-rIN/strings.xml | 449 +++++++++ app/src/main/res/values-tr/strings.xml | 449 +++++++++ app/src/main/res/values-vi/strings.xml | 873 +++++++++--------- app/src/main/res/values-zh-rCN/strings.xml | 871 ++++++++--------- app/src/main/res/values-zh-rTW/strings.xml | 872 ++++++++--------- app/src/main/res/values/attrs.xml | 2 + app/src/main/res/values/dimens.xml | 2 + app/src/main/res/values/strings.xml | 18 + build.gradle | 2 +- 53 files changed, 4752 insertions(+), 3123 deletions(-) create mode 100644 app/src/main/java/au/gov/health/covidsafe/DeviceNameChangePromptActivity.kt create mode 100644 app/src/main/java/au/gov/health/covidsafe/InternetConnectionIssuesActivity.kt delete mode 100644 app/src/main/res/drawable-hdpi/small_green_tick.png delete mode 100644 app/src/main/res/drawable-hdpi/small_red_cross.png delete mode 100644 app/src/main/res/drawable-mdpi/small_green_tick.png delete mode 100644 app/src/main/res/drawable-mdpi/small_red_cross.png delete mode 100644 app/src/main/res/drawable-xhdpi/small_green_tick.png delete mode 100644 app/src/main/res/drawable-xhdpi/small_red_cross.png delete mode 100644 app/src/main/res/drawable-xxhdpi/small_green_tick.png delete mode 100644 app/src/main/res/drawable-xxhdpi/small_red_cross.png create mode 100644 app/src/main/res/drawable/ic_bell.xml create mode 100644 app/src/main/res/drawable/ic_chevron_right_red.xml create mode 100644 app/src/main/res/drawable/ic_green_tick.xml create mode 100644 app/src/main/res/drawable/ic_internet_issues.xml create mode 100644 app/src/main/res/drawable/ic_red_cross_no_circle.xml create mode 100644 app/src/main/res/layout/activity_device_name_change_prompt.xml create mode 100644 app/src/main/res/layout/activity_internet_connection_issues.xml create mode 100644 app/src/main/res/values-pa-rIN/strings.xml create mode 100644 app/src/main/res/values-tr/strings.xml diff --git a/app/build.gradle b/app/build.gradle index fe90bb9..343a905 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -41,8 +41,8 @@ android { Before you increase the targetSdkVersion make sure that all its usage are still working */ targetSdkVersion 28 - versionCode 48 - versionName "1.0.48" + versionCode 54 + versionName "1.0.54" buildConfigField "String", "GITHASH", "\"${getGitHash()}\"" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -210,7 +210,7 @@ dependencies { 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.12' + testImplementation 'junit:junit:4.13' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' @@ -241,7 +241,7 @@ dependencies { implementation 'com.google.guava:guava:28.2-android' implementation "androidx.collection:collection:1.1.0" - implementation "com.google.crypto.tink:tink-android:1.4.0-rc2" + implementation "com.google.crypto.tink:tink-android:1.4.0" implementation "androidx.lifecycle:lifecycle-service:2.2.0" implementation 'com.github.razir.progressbutton:progressbutton:2.0.1' @@ -249,7 +249,7 @@ dependencies { implementation 'com.michaelfotiadis:android-country-flags:1.0.3' // Firebase Cloud Messaging - implementation 'com.google.firebase:firebase-messaging:20.2.3' + implementation 'com.google.firebase:firebase-messaging:20.2.4' androidTestImplementation "androidx.room:room-testing:2.2.5" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d20850c..724713b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -48,6 +48,8 @@ android:windowSoftInputMode="adjustPan" /> + + Unit) { + GlobalScope.launch(Dispatchers.IO) { + var reachable = false + + reachable = try { + InetAddress.getByName(url).isReachable(2000) + } 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) + } + } + + fun checkInternetConnectionToCOVIDSafeBackend(callback: (Boolean) -> Unit) { + checkInternetConnectionToURL(BuildConfig.BASE_URL, callback) + } + + fun checkInternetConnectionToGoogle(callback: (Boolean) -> Unit) { + checkInternetConnectionToURL("8.8.8.8", callback) + } + } diff --git a/app/src/main/java/au/gov/health/covidsafe/extensions/PermissionExtensions.kt b/app/src/main/java/au/gov/health/covidsafe/extensions/PermissionExtensions.kt index 4f529d6..297d0ce 100644 --- a/app/src/main/java/au/gov/health/covidsafe/extensions/PermissionExtensions.kt +++ b/app/src/main/java/au/gov/health/covidsafe/extensions/PermissionExtensions.kt @@ -109,10 +109,6 @@ fun Context.isBlueToothEnabled(): Boolean? { return bluetoothManager?.adapter?.isEnabled } -fun Context.isPushNotificationEnabled(): Boolean? { - return NotificationManagerCompat.from(this).areNotificationsEnabled() -} - fun Context.isLocationPermissionAllowed(): Boolean? { return EasyPermissions.hasPermissions(this, ACCESS_COARSE_LOCATION) } diff --git a/app/src/main/java/au/gov/health/covidsafe/links/LinkBuilder.kt b/app/src/main/java/au/gov/health/covidsafe/links/LinkBuilder.kt index 10da2ba..e6b4a76 100644 --- a/app/src/main/java/au/gov/health/covidsafe/links/LinkBuilder.kt +++ b/app/src/main/java/au/gov/health/covidsafe/links/LinkBuilder.kt @@ -31,6 +31,8 @@ private const val HELP_TOPICS_VIETNAMESE_PAGE = "/vi" private const val HELP_TOPICS_KOREAN_PAGE = "/ko" private const val HELP_TOPICS_GREEK_PAGE = "/el" private const val HELP_TOPICS_ITALIAN_PAGE = "/it" +private const val HELP_TOPICS_PUNJABI_PAGE = "/pa-in" +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" @@ -55,6 +57,8 @@ object LinkBuilder { localeLanguageTag.startsWith("ko") -> HELP_TOPICS_KOREAN_PAGE localeLanguageTag.startsWith("el") -> HELP_TOPICS_GREEK_PAGE localeLanguageTag.startsWith("it") -> HELP_TOPICS_ITALIAN_PAGE + localeLanguageTag.startsWith("pa") -> HELP_TOPICS_PUNJABI_PAGE + localeLanguageTag.startsWith("tr") -> HELP_TOPICS_TURKISH_PAGE else -> HELP_TOPICS_ENGLISH_PAGE } + HELP_TOPICS_SUFFIX diff --git a/app/src/main/java/au/gov/health/covidsafe/networking/response/MessagesResponse.kt b/app/src/main/java/au/gov/health/covidsafe/networking/response/MessagesResponse.kt index 13416cf..b530394 100644 --- a/app/src/main/java/au/gov/health/covidsafe/networking/response/MessagesResponse.kt +++ b/app/src/main/java/au/gov/health/covidsafe/networking/response/MessagesResponse.kt @@ -3,4 +3,7 @@ package au.gov.health.covidsafe.networking.response import androidx.annotation.Keep @Keep -data class MessagesResponse(val message: String, val forceappupgrade: Boolean) \ No newline at end of file +data class MessagesResponse(val messages: List?) + +@Keep +data class Message(val title: String, val body: String, val destination: String) \ No newline at end of file diff --git a/app/src/main/java/au/gov/health/covidsafe/networking/service/AwsClient.kt b/app/src/main/java/au/gov/health/covidsafe/networking/service/AwsClient.kt index 46b74ef..8a5fefe 100644 --- a/app/src/main/java/au/gov/health/covidsafe/networking/service/AwsClient.kt +++ b/app/src/main/java/au/gov/health/covidsafe/networking/service/AwsClient.kt @@ -40,7 +40,7 @@ interface AwsClient { @Query("appversion") appversion: String, @Query("token") token: String, @Query("healthcheck") healthcheck: String, - @Query("preferredLanguages") preferredLanguages: String + @Query("preferredlanguages") preferredLanguages: String ): Call } \ No newline at end of file diff --git a/app/src/main/java/au/gov/health/covidsafe/scheduler/GetMessagesScheduler.kt b/app/src/main/java/au/gov/health/covidsafe/scheduler/GetMessagesScheduler.kt index b27b979..3727758 100644 --- a/app/src/main/java/au/gov/health/covidsafe/scheduler/GetMessagesScheduler.kt +++ b/app/src/main/java/au/gov/health/covidsafe/scheduler/GetMessagesScheduler.kt @@ -76,24 +76,30 @@ class GetMessagesJobSchedulerService : JobService() { object GetMessagesScheduler { var mostRecentRecordTimestamp: Long = 0 - fun scheduleGetMessagesJob() { - CentralLog.d(TAG, "scheduleGetMessagesJob()") + var messagesResponseCallback: ((MessagesResponse) -> Unit)? = null - val context = TracerApp.AppContext + fun scheduleGetMessagesJob(callback: (MessagesResponse) -> Unit) { + GlobalScope.launch(Dispatchers.Default) { + CentralLog.d(TAG, "scheduleGetMessagesJob()") - (context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler?) - ?.let { - CentralLog.d(TAG, "JobScheduler available") + messagesResponseCallback = callback - 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) - .build() - ) - } + val context = TracerApp.AppContext + + (context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler?) + ?.let { + CentralLog.d(TAG, "JobScheduler available") + + 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) + .build() + ) + } + } } fun getMessages(jobService: JobService? = null, params: JobParameters? = null) { @@ -147,11 +153,14 @@ object GetMessagesScheduler { messagesCall.enqueue(object : Callback { override fun onResponse(call: Call, response: Response) { val responseCode = response.code() + if (responseCode == 200) { CentralLog.d(TAG, "onResponse() got 200 response.") response.body()?.let { CentralLog.d(TAG, "onResponse() MessagesResponse = $it") + + messagesResponseCallback?.invoke(it) } } else { CentralLog.w(TAG, "onResponse() got error response code = $responseCode.") diff --git a/app/src/main/java/au/gov/health/covidsafe/security/crypto/EncryptedSharedPreferences.java b/app/src/main/java/au/gov/health/covidsafe/security/crypto/EncryptedSharedPreferences.java index 9afe84c..3106bd5 100644 --- a/app/src/main/java/au/gov/health/covidsafe/security/crypto/EncryptedSharedPreferences.java +++ b/app/src/main/java/au/gov/health/covidsafe/security/crypto/EncryptedSharedPreferences.java @@ -313,6 +313,7 @@ public final class EncryptedSharedPreferences implements SharedPreferences { clearKeysIfNeeded(); mEditor.apply(); notifyListeners(); + mKeysChanged.clear(); } private void clearKeysIfNeeded() { diff --git a/app/src/main/java/au/gov/health/covidsafe/streetpass/persistence/Encryption.kt b/app/src/main/java/au/gov/health/covidsafe/streetpass/persistence/Encryption.kt index ac41801..a34dd9f 100644 --- a/app/src/main/java/au/gov/health/covidsafe/streetpass/persistence/Encryption.kt +++ b/app/src/main/java/au/gov/health/covidsafe/streetpass/persistence/Encryption.kt @@ -1,13 +1,10 @@ package au.gov.health.covidsafe.streetpass.persistence +import android.os.Build import android.util.Base64 import au.gov.health.covidsafe.BuildConfig import java.math.BigInteger -import java.security.KeyFactory -import java.security.KeyPair -import java.security.KeyPairGenerator -import java.security.MessageDigest -import java.security.PublicKey +import java.security.* import java.security.interfaces.ECPublicKey import java.security.spec.X509EncodedKeySpec import javax.crypto.Cipher @@ -98,6 +95,11 @@ object Encryption { private val NONCE_PADDING = ByteArray(14) { 0x0E.toByte() } private val serverPubKey: PublicKey = readKey() + private val random: SecureRandom = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + SecureRandom.getInstanceStrong() + } else { + SecureRandom() + } private var cachedEphPubKey: ByteArray? = null private var cachedAesKey: SecretKey? = null @@ -146,13 +148,21 @@ object Encryption { @Synchronized private fun encryptionKeys(): EncryptionKeys { - if (keyGenTime <= System.currentTimeMillis() - KEY_GEN_TIME_DELTA || counter >= 65535) { + // Allowing 2^8 encryption cycles with a 2B random IV gives a ~40% chance of IV collision. + // This threshold has been chosen as a balance between the competing needs of: + // - Reducing the number of key agreements, due to mobile platform limitations (battery, performance, background compute restrictions) + // - Ensuring semantic security + if (keyGenTime <= System.currentTimeMillis() - KEY_GEN_TIME_DELTA || counter >= 255) { generateKeys() keyGenTime = System.currentTimeMillis() counter = 0 } else { counter++ } - return EncryptionKeys(cachedEphPubKey!!, cachedAesKey!!, cachedMacKey!!, counterBytes(counter)) + + val nonce: ByteArray = ByteArray(2) + random.nextBytes(nonce) + + return EncryptionKeys(cachedEphPubKey!!, cachedAesKey!!, cachedMacKey!!, nonce) } } \ No newline at end of file diff --git a/app/src/main/java/au/gov/health/covidsafe/ui/home/HomeFragment.kt b/app/src/main/java/au/gov/health/covidsafe/ui/home/HomeFragment.kt index 8b33382..9adf415 100644 --- a/app/src/main/java/au/gov/health/covidsafe/ui/home/HomeFragment.kt +++ b/app/src/main/java/au/gov/health/covidsafe/ui/home/HomeFragment.kt @@ -5,7 +5,9 @@ import android.annotation.SuppressLint import android.bluetooth.BluetoothAdapter import android.content.* import android.net.Uri +import android.os.Build import android.os.Bundle +import android.provider.Settings import android.text.Html import android.text.method.LinkMovementMethod import android.view.LayoutInflater @@ -14,33 +16,42 @@ 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.navigation.fragment.findNavController -import au.gov.health.covidsafe.BuildConfig -import au.gov.health.covidsafe.Preference -import au.gov.health.covidsafe.R -import au.gov.health.covidsafe.WebViewActivity +import au.gov.health.covidsafe.* 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.talkback.setHeading import au.gov.health.covidsafe.ui.BaseFragment +import au.gov.health.covidsafe.ui.home.view.ExternalLinkCard 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.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 { - companion object{ + companion object { var instanceWeakRef: WeakReference? = null } @@ -106,22 +117,12 @@ class HomeFragment : BaseFragment(), EasyPermissions.PermissionCallbacks { instanceWeakRef = WeakReference(this) - // display app update reminder -// if (System.currentTimeMillis() -// - -// Preference.getAppUpdateReminderDismissedTime(requireContext()) -// > ONE_DAY_IN_MILLIS -// ) { -// app_update_reminder.visibility = VISIBLE -// } - // 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() } - push_card_view.setOnClickListener { gotoPushNotificationSettings() } home_been_tested_button.setOnClickListener { navigateTo(R.id.action_home_to_selfIsolate) @@ -146,15 +147,6 @@ class HomeFragment : BaseFragment(), EasyPermissions.PermissionCallbacks { findNavController().navigate(HomeFragmentDirections.actionHomeFragmentToHelpFragment()) } -// go_to_play_store.setOnClickListener { -// app_update_reminder.visibility = GONE -// } -// -// remind_me_later.setOnClickListener { -// Preference.putAppUpdateReminderDismissedTime(requireContext()) -// app_update_reminder.visibility = GONE -// } - if (!mIsBroadcastListenerRegistered) { registerBroadcast() } @@ -162,6 +154,8 @@ class HomeFragment : BaseFragment(), EasyPermissions.PermissionCallbacks { home_header_no_bluetooth_pairing.text = LinkBuilder.getNoBluetoothPairingContent(requireContext()) home_header_no_bluetooth_pairing.movementMethod = LinkMovementMethod.getInstance() + + updateNotificationStatusTile() } override fun onPause() { @@ -177,6 +171,7 @@ class HomeFragment : BaseFragment(), EasyPermissions.PermissionCallbacks { home_setup_complete_news.setOnClickListener(null) home_setup_complete_app.setOnClickListener(null) help_topics_link.setOnClickListener(null) + activity?.let { activity -> if (mIsBroadcastListenerRegistered) { activity.unregisterReceiver(mBroadcastListener) @@ -272,11 +267,10 @@ class HomeFragment : BaseFragment(), EasyPermissions.PermissionCallbacks { layoutParams.height = size layoutParams.width = size } - home_header_picture_setup_complete.setImageResource(R.drawable.ic_red_cross) + home_header_picture_setup_complete.setImageResource(R.drawable.ic_red_cross_no_circle) content_setup_incomplete_group.visibility = VISIBLE updateBlueToothStatus() - updatePushNotificationStatus() updateBatteryOptimizationStatus() updateLocationStatus() ContextCompat.getColor(it, R.color.grey).let { bgColor -> @@ -293,12 +287,10 @@ class HomeFragment : BaseFragment(), EasyPermissions.PermissionCallbacks { val context = requireContext() val bluetoothEnabled = context.isBlueToothEnabled() ?: false - val pushNotificationEnabled = context.isPushNotificationEnabled() ?: true val nonBatteryOptimizationAllowed = context.isBatteryOptimizationDisabled() ?: true val locationStatusAllowed = context.isLocationPermissionAllowed() ?: true return bluetoothEnabled && - pushNotificationEnabled && nonBatteryOptimizationAllowed && locationStatusAllowed && context.isLocationEnabledOnDevice() @@ -332,19 +324,6 @@ class HomeFragment : BaseFragment(), EasyPermissions.PermissionCallbacks { } } - private fun updatePushNotificationStatus() { - requireContext().isPushNotificationEnabled()?.let { - push_card_view.visibility = VISIBLE - push_card_view.render( - formatPushNotificationTitle(it), - it, - getString(R.string.home_app_permission_push_notification_prompt) - ) - } ?: run { - push_card_view.visibility = GONE - } - } - private fun updateBatteryOptimizationStatus() { requireContext().isBatteryOptimizationDisabled()?.let { battery_card_view.visibility = VISIBLE @@ -361,9 +340,10 @@ class HomeFragment : BaseFragment(), EasyPermissions.PermissionCallbacks { private fun updateLocationStatus() { requireContext().isLocationPermissionAllowed()?.let { val locationWorking = it && requireContext().isLocationEnabledOnDevice() + val locationOffPrompts = getString(R.string.home_set_location_why) location_card_view.visibility = VISIBLE - location_card_view.render(formatLocationTitle(locationWorking), locationWorking) + location_card_view.render(formatLocationTitle(locationWorking), locationWorking, locationOffPrompts) } ?: run { location_card_view.visibility = GONE } @@ -438,4 +418,111 @@ 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 + } + + 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)) + } + } + } + } + + 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_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) + } + + it.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.white)) + + it.setMessage(message) + it.setErrorTextColor() + + improve_performance_card_linear_layout.addView(it) + } + } + } else { + improve_performance_card.visibility = GONE + } + } + } + + 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) + } + } diff --git a/app/src/main/java/au/gov/health/covidsafe/ui/home/view/ExternalLinkCard.kt b/app/src/main/java/au/gov/health/covidsafe/ui/home/view/ExternalLinkCard.kt index 1cf2f83..5bda36f 100644 --- a/app/src/main/java/au/gov/health/covidsafe/ui/home/view/ExternalLinkCard.kt +++ b/app/src/main/java/au/gov/health/covidsafe/ui/home/view/ExternalLinkCard.kt @@ -1,15 +1,20 @@ package au.gov.health.covidsafe.ui.home.view import android.content.Context -import android.content.res.Resources +import android.content.Intent import android.content.res.TypedArray +import android.net.Uri +import android.text.Html import android.util.AttributeSet import android.view.LayoutInflater +import android.view.View import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.content.ContextCompat import au.gov.health.covidsafe.R +import au.gov.health.covidsafe.networking.response.Message import kotlinx.android.synthetic.main.view_card_external_link_card.view.* + class ExternalLinkCard @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, @@ -19,24 +24,99 @@ class ExternalLinkCard @JvmOverloads constructor( init { LayoutInflater.from(context).inflate(R.layout.view_card_external_link_card, this, true) - val a: TypedArray = context.obtainStyledAttributes(attrs, R.styleable.ExternalLinkCard) - val icon = a.getDrawable(R.styleable.ExternalLinkCard_external_linkCard_icon) - 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) + 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 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 textColorResId = a.getResourceId(R.styleable.ExternalLinkCard_external_linkCard_text_color, R.color.slack_black) + val textColor = ContextCompat.getColor(context, textColorResId) - external_link_round_image.setImageDrawable(icon) - 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 - a.recycle() + external_link_round_image.setImageDrawable(icon) + external_link_round_image.visibility = if (iconVisible) 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 + + setTextColor(textColor) + + a.recycle() + } + } + + private fun setTextColor(textColor: Int) { + external_link_headline.setTextColor(textColor) + external_link_content.setTextColor(textColor) + + val icChevron = + if (textColor == ContextCompat.getColor(context, R.color.error)) { + R.drawable.ic_chevron_right_red + } else { + R.drawable.ic_chevron_right + } next_arrow.setImageDrawable( - ContextCompat.getDrawable(context, R.drawable.ic_chevron_right).also { + ContextCompat.getDrawable(context, icChevron).also { it?.isAutoMirrored = true } ) } + + fun setMessage(message: Message) { + external_link_round_image.visibility = View.GONE + + external_link_headline.text = message.title + external_link_content.text = message.body + + this.setOnClickListener { + Intent(Intent.ACTION_VIEW, Uri.parse(message.destination)).also { + context.startActivity(it) + } + } + } + + fun setTitleBodyAndClickCallback(title: String, body: String, clickCallBack: () -> Unit) { + external_link_headline.text = title + external_link_content.text = body + + this.setOnClickListener { + clickCallBack() + } + } + + fun setErrorTextColor() { + setTextColor(ContextCompat.getColor(context, R.color.error)) + } + + fun setTopRightIcon(iconResID: Int) { + next_arrow.setImageResource(iconResID) + } + + fun setColorForContentWithAction() { + val actionColor = ContextCompat.getColor(context, R.color.dark_green) + val actionColorString = String.format("%X", actionColor).substring(2) + + val stringBuilder = StringBuilder() + + external_link_content.text.split("\n").forEachIndexed { index, s -> + if (index == 0) { + stringBuilder.append(s) + } else { + stringBuilder.append("
$s") + } + } + + val htmlText = stringBuilder.toString() + + external_link_content.text = + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { + Html.fromHtml(htmlText, Html.FROM_HTML_MODE_COMPACT) + } else { + Html.fromHtml(htmlText) + } + } } \ No newline at end of file diff --git a/app/src/main/java/au/gov/health/covidsafe/ui/onboarding/fragment/enternumber/EnterNumberFragment.kt b/app/src/main/java/au/gov/health/covidsafe/ui/onboarding/fragment/enternumber/EnterNumberFragment.kt index 53c9472..7c672b1 100644 --- a/app/src/main/java/au/gov/health/covidsafe/ui/onboarding/fragment/enternumber/EnterNumberFragment.kt +++ b/app/src/main/java/au/gov/health/covidsafe/ui/onboarding/fragment/enternumber/EnterNumberFragment.kt @@ -78,6 +78,8 @@ class EnterNumberFragment : PagerChildFragment() { enter_number_phone_number.addTextChangedListener { enter_number_phone_number.setTextColor(normalTextColor) + + updateButtonState() } enter_number_phone_number.setOnEditorActionListener { _, actionId, event -> diff --git a/app/src/main/java/au/gov/health/covidsafe/ui/onboarding/fragment/permission/PermissionDeviceNameFragment.kt b/app/src/main/java/au/gov/health/covidsafe/ui/onboarding/fragment/permission/PermissionDeviceNameFragment.kt index 3fd9a65..63c1478 100644 --- a/app/src/main/java/au/gov/health/covidsafe/ui/onboarding/fragment/permission/PermissionDeviceNameFragment.kt +++ b/app/src/main/java/au/gov/health/covidsafe/ui/onboarding/fragment/permission/PermissionDeviceNameFragment.kt @@ -7,6 +7,7 @@ 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.R import au.gov.health.covidsafe.talkback.setHeading import au.gov.health.covidsafe.ui.PagerChildFragment @@ -27,6 +28,7 @@ class PermissionDeviceNameFragment : PagerChildFragment() { context?.let { change_device_name_content.setText(R.string.change_device_name_content_line_2) change_device_name_text_box.setText(Settings.Secure.getString(it.contentResolver, "bluetooth_name")) + Preference.setDeviceNameChangePromptDisplayed(it) } change_device_name_headline.setHeading() diff --git a/app/src/main/res/drawable-hdpi/small_green_tick.png b/app/src/main/res/drawable-hdpi/small_green_tick.png deleted file mode 100644 index a0121f8d339fd8de0decafec56290001e750a5a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 910 zcmV;919AL`P)hP@~d;DIor=Nmc|REFjcYsbGgrtrP-H zRe{7rGPFyJ6t-rmkQx?9V(wjH%Q1;##|}R!u`fRReSY`e-McW@!2jOwgNzZBFu=eD z6ewQx8gFM6resmXciv1T-z8J90c+I37x#6_kVD+~Ja2ZwA|$McV)Xd!@h5BjO&I$y zHYqV_L;vP>u_~yhkct<=6)(7hgjh0|T!2*}LWClJgMtCL4MV!X3NKT^)D`aOG|(~; z1b;3)pI#PbLi}<6M$1I##n7-D(1vF8!-d zB!rMRoTO+i`XBe3UMG8UL7uM?;r8)^gikp-cZT>&EVkIL8IGzWg#BEh`B&lM;D_0DB9cF zMLUDq7f##vF?y2rH zkCoRvf=#yzG!!S7C*s&lh8RR-d1W6|+rlHFm{qV~tI`m6G1dd()?7A3$c1$uq{NTQt0~lT_dzm k8vh>=3ut-mvi<+a9jQxPm75qObN~PV07*qoM6N<$f)xamxBvhE diff --git a/app/src/main/res/drawable-hdpi/small_red_cross.png b/app/src/main/res/drawable-hdpi/small_red_cross.png deleted file mode 100644 index 71bcefd9049320337a55ef57b1b5c485a20bdbb6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 838 zcmV-M1G)T(P)n6KwkgZJ(g+6QuhD+c#+UdXaMD(KW zbD*KPKM!#M3^7{+tCqh7l=gv1`bHsrVT};1BKLouvDOkGuV?FFT@VorPkZ{J6@#eK zn((kWRStl`90*y+7+13nQw6kM_T_pBr-nyE2jaHtLPwhIoWC)v3_+$DbC%YFW)n|_ z!?09o*YmX6v1mGuqH}iJ*342C$}X4j_~az2f9rPfsnN)UxL2)4^$(Q_CWC>hYaWCW zZwEXgE^@@3{Ww03>i6q)IG(43_}XsgLI}D1Q=ri})M*{iOSp5XyHuAjSrA`ZEodrq z7nZ5DJfs)I=l@R-;D+NY3&HCoAlJXgAX6AB4YMqS6!{ZtDUfa3#W-kJv{ibE* zYhzkNRs0u&(CWKbP~h&Yvs&Bh~gG+3b@5y43V8x*G)@p|OYMA+8D zX4FgPIf-;)&8dWxe-KVWQVAE&Q^a`(G@aZs5Tbu5K_rYIUiCEf7A03KW$r6d3^r>A z%PXLx5lY6jdEEwGw0|S&@+11%?h3*clm6P+V0+ zVoHV7sX{fK%2H(ri*fFH?<7;pIDg!HOYZL7{q*kLmuG<#?VV@}!an(wDAVcD!IeP_3`mYkk2QYG-7o5oR~6_!f8mT`8Kq z7!}$JPGMjaD2vZ#vY7^#@*eE$J6oebqj3G;{5B9=0!vyyky81oJjS!*X#Q%(L+yZq z86rtVq|{_?5|tMf)SMdTrsm>dV^bnQYe*r6?!4MDzs>6=E`MJ>+$2yWp@fYT;w%|@ z)49R+*X_hTLWn%2d9?DgGG-sm8tBH!25$Y^#C^=9UXZ0HOUPw&_w&{HRV+VUHZX=V zyq}1T9baTX<$1+q$Xb|Qz{>oJ8Sh@~4umq((#_?_hCy(ZG+tALFQXgkdCwJfOe|KI>w)li-^tn+AUM=L&ll zdl**SPE8YXJ~>tW=iW-%#4cd?pt}B}qE>%fuNp8njxjmb(nYs1g7nS3vo~imJT`W7 z*WGrPx+M`_T2eM o(Hi?a`Y|=$*EVHG#et#z0?lCpjyTO2r2qf`07*qoM6N<$f(3vg`2YX_ diff --git a/app/src/main/res/drawable-mdpi/small_red_cross.png b/app/src/main/res/drawable-mdpi/small_red_cross.png deleted file mode 100644 index 065929ab62a31fb2319fffd94da507a1c2d93e75..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 564 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 Hu0mjfkqPnk diff --git a/app/src/main/res/drawable-xxhdpi/small_green_tick.png b/app/src/main/res/drawable-xxhdpi/small_green_tick.png deleted file mode 100644 index bd76e1bca5448ad8fdbe4ce8e134aa35696a00bf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1670 zcmV;126_33P)#}&jB%HXn-k80#RBdrdGRu@BQvQ z6lw$7f|ly(?a?f<2Ka7@6iO+UlH~iT+Vd1r3YKCO$)W<^Em)TIGc#G?(e$HDiWr3= zV&sPrjToKgn^XKJNg;qhCYgCI(CYe^>pxKhNEJd`(ozXZOp;08P{^Bi!xqIT8QJ_y zzCe)UBIpfDwnAa1v z@3p}mvnLmK5di8FUbo~>zj*zOCyRgx2{nbws*H_;nxKUORZH@EutH&;oQ(U zI^K7jCO(>=#nX#)=(+gVEQoH)*fQ z66Z`Y@a{mJ2sRL5aV(T&Bt?^%Y>QAtw>g&JCbJ`1*W)k#eL*jGUs6zbmu(F1Z106> z6hj~a%-=0jK!Dk`aG{MqN14RCQt35pPz-_D_rKlmcnl(3d~h+8HQ1PznPMtaQxrpH zKACY90l*Suh#)X21J}?fW*|c#MY@3+0+z>sPwCFa9g+^CK8B~#6a&0ui1}aUDGHzgi$fuWn{QSn+8N?i z=@mtRa1Dw92##(d;O1qe$!2t1h*lW_!7*wPfK(xn_eb9!^?W`AXm^HiBO#{iNQe^< zp*Gk({Oe)M^HDUp0RbY(5Dq{CCgv=K1i8OfgqdT_t3odWDH)9yuRsH4nO1>9F#5r$ z=o;0gy~DkS>DsAlj$(Mp5Mc*WzArCrD4wixz}+pRV?=AX>BT?By1Y3kAOquf7O;Mp%b|LxH8f1V2$aiUl4r4xN8 zgcxT&KI8g5$PoAcyic8gne1E9#U8#nyu-~SRH==$dHJ);6aQ@ZJgCOEb#iCWbRUh!ka1Wb_4<|$| z(F~cbwxHN@d2%HKMJBNIg? zi5ejSzjiMRSUk1!g&52j>Lxc4?f?<^wR<_=^K%XEUj;5krYpqYL0-fJk0JnH4|pnK z48=LMB1MYj2tJoS243!n8T>qeV$o}gVt|NYybuh!WIFI8KNKdyRV*uXn=dS|0)8#& zFzd$UEr~YNIX+mMq&5-uu+7Rft-*}VL1Ook{G|G$MM z^V(Nyd5VC@gs4SSr+d>FHU85FVYnMP|04~{DppeT7M{YDOXa-Gzq}j&0|egj2HXwQ Q=Kufz07*qoM6N<$g3?y{6aWAK diff --git a/app/src/main/res/drawable-xxhdpi/small_red_cross.png b/app/src/main/res/drawable-xxhdpi/small_red_cross.png deleted file mode 100644 index 4db4b69452e7a76c4047463c7fc6fe771a051def..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1561 zcmV+!2Il#RP)?er)1g>}4*?p-R!b48<8nQt|;ZXKhK#tbLNa4RKP>PZ2)aK z{rFPO5xkn}7{!y4->u66V&@D(gz zR0#Ftx8#OzqkQAj@I|=*dh3A&8NrAU6krk9Mey`1LvFrrN{~`QoXS%dAKq0K@X9bD z$izZC1~%nzANE|JD4sl&o^-5zOh92Fro{@|(?|6MhjO}#>Bf5w zbc(o&wh-S)<7mP${nO@m^l$bw8W@o{ZffA zijLMT4y|i&)I)Oy-S7 ztgRy<)Hu5hL%h4Y3-`Xc{&q#K#cP^^nX_nYu@Ih^vY7J>)g<@u{axlP;oeuszOP}OjlZNGqp(Dc6g9H2^f6EZQX*nv_ za0)}zRYR_2G=ySNG>R8x$#wC;;bE=_p17Jxr2THKW;lvu8^KUqfB+H-(I+kEs z1oA>=rF4xpEWjJi6XT=PQ(u5kgoYf`uq6T!5mp&TtiTfCji>eS4JAN$o`y{k2-jmN zgbR!4h>-<@r{5BWWRu9qu|n6do`$0sPxkjwlqy6ZB1E(Pr7Vb`0{(vR0FLAM@q`Xl ziJ=%OP2IXS_?@-p7Oc{B5U44;3!dlywwLxpg3Xl~>Ov5Zica{3O_R3=0iJ2W&J z7>*`Yia{YfSf+>wAytaOG9?O8Xw|qVI`fM(LNT(!brVP&F|cY8IwEj%$V#+SA%+NX z&VcG17SIvl7fG=E5lOJ5rQ*VgT;A+`-j7HJ}kT}MLlybO5W?6v@& zlvvtCTqTvWQ~ppAv$6#wOS|(t9f~h zrt?d?N77TG2+S`&o3OX1n=oq~?{f@I%6zxr$tc7YWs1*}<5!LOZCMcrEhC=at3EL#;_2p(GvmyCA5rqbJGpcykFd}cWK;WaNj z4<=yQ@+ZJf35zbM^TOgprOcp<72f0L@Fqg7bXWxgU3D{`+SW>js_4(60$ z%65jt43(-nn@1PfPus@eqd4w`29lG9u5aN z%y4CX2p{NL-gbrDEHmH9e*Hnh_D6yv$?Ei>gNp6*@^qP?!MuKWzM zAqF2@r^pWCLJK_Ws^`UY53T$4g8R8hZfBW>s^Fidx@|uYoOH|d#7llMbL-Rmh6d7n z2A~zR%Iq7T*dn5E)+#sBH8F)R!qjYujuR2&3)pj+0kdf@5@wKPFe*e8R`ZJ6Y#I`U z{(rzE^Jj+FVM4445k*C(E`ka^7O(L<^B-x*>zu1_T!31yV95Rt + + + diff --git a/app/src/main/res/drawable/ic_chevron_right_red.xml b/app/src/main/res/drawable/ic_chevron_right_red.xml new file mode 100644 index 0000000..a5c8d7d --- /dev/null +++ b/app/src/main/res/drawable/ic_chevron_right_red.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_green_tick.xml b/app/src/main/res/drawable/ic_green_tick.xml new file mode 100644 index 0000000..3500f71 --- /dev/null +++ b/app/src/main/res/drawable/ic_green_tick.xml @@ -0,0 +1,16 @@ + + + + diff --git a/app/src/main/res/drawable/ic_internet_issues.xml b/app/src/main/res/drawable/ic_internet_issues.xml new file mode 100644 index 0000000..01f441d --- /dev/null +++ b/app/src/main/res/drawable/ic_internet_issues.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_red_cross.xml b/app/src/main/res/drawable/ic_red_cross.xml index a189255..ad1318f 100644 --- a/app/src/main/res/drawable/ic_red_cross.xml +++ b/app/src/main/res/drawable/ic_red_cross.xml @@ -1,20 +1,23 @@ + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + diff --git a/app/src/main/res/drawable/ic_red_cross_no_circle.xml b/app/src/main/res/drawable/ic_red_cross_no_circle.xml new file mode 100644 index 0000000..c80fa06 --- /dev/null +++ b/app/src/main/res/drawable/ic_red_cross_no_circle.xml @@ -0,0 +1,20 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/icon_checkbox.xml b/app/src/main/res/drawable/icon_checkbox.xml index cc6ef6a..fa2c9eb 100644 --- a/app/src/main/res/drawable/icon_checkbox.xml +++ b/app/src/main/res/drawable/icon_checkbox.xml @@ -3,25 +3,25 @@ android:exitFadeDuration="@android:integer/config_mediumAnimTime"> + android:drawable="@drawable/ic_red_cross" /> + android:drawable="@drawable/ic_green_tick" /> + android:drawable="@drawable/ic_green_tick" /> + android:drawable="@drawable/ic_red_cross" /> + android:drawable="@drawable/ic_green_tick" /> + android:drawable="@drawable/ic_green_tick" /> + android:drawable="@drawable/ic_green_tick" /> + android:drawable="@drawable/ic_green_tick" /> diff --git a/app/src/main/res/layout/activity_device_name_change_prompt.xml b/app/src/main/res/layout/activity_device_name_change_prompt.xml new file mode 100644 index 0000000..0246abf --- /dev/null +++ b/app/src/main/res/layout/activity_device_name_change_prompt.xml @@ -0,0 +1,29 @@ + + + + + + + + +