Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main'
Browse files Browse the repository at this point in the history
  • Loading branch information
NoahAndrews committed Jun 16, 2021
2 parents 7bdf67c + 52019d6 commit 1de17c5
Show file tree
Hide file tree
Showing 9 changed files with 158 additions and 20 deletions.
5 changes: 4 additions & 1 deletion src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />

<!-- Added by REV Robotics on 2021-04-28 -->
<!-- Added by REV Robotics on 2021-04-28 -->
<uses-permission android:name="com.revrobotics.permission.UPDATE_CONTROL_HUB" />

<!-- Added by REV Robotics on 2021-06-09 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

<application
android:name=".MainApplication"
android:label="@string/application_name"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.util.Log
import nya.kitsunyan.foxydroid.MainActivity
import nya.kitsunyan.foxydroid.MainApplication
import nya.kitsunyan.foxydroid.service.Connection
import nya.kitsunyan.foxydroid.service.SyncService
Expand All @@ -20,16 +21,33 @@ class InternetAvailableBroadcastReceiver : BroadcastReceiver() {

override fun onReceive(context: Context, intent: Intent) {
if ("com.revrobotics.revupdateinterface.INTERNET_AVAILABLE" == intent.action) {
Log.i(tag, "Internet is available");
Log.i(tag, "Internet is available")

if (actionWaitingForInternetConnection != null) {
// Tell the main activity to perform the action that was waiting for an Internet connection
context.startActivity(
Intent(MainApplication.instance, MainActivity::class.java)
.apply {
action = MainActivity.ACTION_PERFORM_ACTION_WAITING_ON_INTERNET
flags = Intent.FLAG_ACTIVITY_NEW_TASK
})

// TODO(Noah): Only execute the desired action immediately if the repository has been updated in the last 12 hours,
// or if a specific release was requested.
// Otherwise, wait to perform it until after the automatic sync.
}

if (LastUpdateOfAllReposTracker.timeSinceLastUpdateOfAllRepos.toHours() > 12) {
// TODO(Noah): In the wait for Internet dialog, show that we are connected to the Internet, but are syncing.
Log.i(tag, "It has been more than 12 hours since all repositories were updated; initiating repository sync")
Connection(SyncService::class.java, onBind = { connection, binder ->
// We want to have the foreground notification, because otherwise the app isn't guaranteed to stay running
// long enough to finish.
binder.sync(SyncService.SyncRequest.AUTO_WITH_FOREGROUND_NOTIFICATION)
connection.unbind(MainApplication.instance)
}).bind(MainApplication.instance)
} else {
// TODO(Noah): Move the desired action execution to this block
}
}
}
Expand Down
40 changes: 40 additions & 0 deletions src/main/kotlin/com/revrobotics/RequestInternetDialogFragment.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.revrobotics

import android.app.AlertDialog
import android.app.Dialog
import android.content.Intent
import android.os.Bundle
import android.provider.Settings
import androidx.fragment.app.DialogFragment

class RequestInternetDialogFragment: DialogFragment() {
companion object {
var instance: RequestInternetDialogFragment? = null
}

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
instance = this
return activity?.let {
val dialog = AlertDialog.Builder(it)
.setMessage("Please connect to the Internet")
.setNegativeButton("Cancel", null)
.setOnDismissListener {
actionWaitingForInternetConnection = null
instance = null
}
// We use a null listener, and later override the underlying onClickListener, so the dialog doesn't get dismissed
.setPositiveButton("Wi-Fi settings", null)
.create()

dialog.setOnShowListener {
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
startActivity(Intent(Settings.ACTION_WIFI_SETTINGS).apply {
putExtra("com.revrobotics.wifiConnectionReason", "Connect to the Internet for software downloads")
})
}
}

return dialog
} ?: throw IllegalStateException("Activity cannot be null")
}
}
21 changes: 18 additions & 3 deletions src/main/kotlin/com/revrobotics/Util.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import nya.kitsunyan.foxydroid.database.Database
import nya.kitsunyan.foxydroid.service.Connection
import nya.kitsunyan.foxydroid.service.DownloadService
Expand All @@ -24,6 +26,8 @@ import nya.kitsunyan.foxydroid.MainActivity
import nya.kitsunyan.foxydroid.MainApplication
import nya.kitsunyan.foxydroid.R
import nya.kitsunyan.foxydroid.entity.ProductItem
import nya.kitsunyan.foxydroid.entity.Release
import nya.kitsunyan.foxydroid.entity.Repository
import nya.kitsunyan.foxydroid.utility.extension.resources.getColorFromAttr
import java.time.Duration
import java.time.Instant
Expand All @@ -34,10 +38,21 @@ import kotlin.concurrent.thread

val mainThreadHandler = Handler(Looper.getMainLooper())
val notificationManager = MainApplication.instance.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val connectivityManager = MainApplication.instance.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val internetAvailable: Boolean
get() = connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) == true
@Volatile var actionWaitingForInternetConnection: ActionWaitingForInternetConnection? = null // This is reset to null when RequestInternetDialogFragment is cancelled

private val downloadQueuingExecutor = Executors.newSingleThreadExecutor()

// queueDownloadAndUpdate function added by REV Robotics on 2021-05-09
sealed class ActionWaitingForInternetConnection
object UpdateAll: ActionWaitingForInternetConnection()
data class InstallApk(val packageName: String,
val productName: String,
val repository: Repository,
val release: Release): ActionWaitingForInternetConnection()
// TODO(Noah): Distinguish between "install latest" and "install specific version"

fun queueDownloadAndUpdate(packageName: String, downloadConnection: Connection<DownloadService.Binder, DownloadService>) {
downloadQueuingExecutor.submit {
val repositoryMap = Database.RepositoryAdapter.getAll(null)
Expand All @@ -61,8 +76,8 @@ fun queueDownloadAndUpdate(packageName: String, downloadConnection: Connection<D
val release = if (multipleCompatibleReleases) {
compatibleReleases!!
.filter { it.platforms.contains(Android.primaryPlatform) }
.minBy { it.platforms.size }
?: compatibleReleases.minBy { it.platforms.size }
.minByOrNull { it.platforms.size }
?: compatibleReleases.minByOrNull { it.platforms.size }
?: compatibleReleases.firstOrNull()
} else {
compatibleReleases?.firstOrNull()
Expand Down
2 changes: 2 additions & 0 deletions src/main/kotlin/nya/kitsunyan/foxydroid/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class MainActivity: ScreenActivity() {
companion object {
const val ACTION_UPDATES = "${BuildConfig.APPLICATION_ID}.intent.action.UPDATES"
const val ACTION_UPDATE_ALL = "${BuildConfig.APPLICATION_ID}.intent.action.UPDATE_ALL" // Added by REV Robotics on 2021-06-07
const val ACTION_PERFORM_ACTION_WAITING_ON_INTERNET = "${BuildConfig.APPLICATION_ID}.intent.action.WAITING_FOR_INTERNET" // Added by REV Robotics on 2021-06-15
const val ACTION_INSTALL = "${BuildConfig.APPLICATION_ID}.intent.action.INSTALL"
const val EXTRA_CACHE_FILE_NAME = "${BuildConfig.APPLICATION_ID}.intent.extra.CACHE_FILE_NAME"
}
Expand All @@ -17,6 +18,7 @@ class MainActivity: ScreenActivity() {
ACTION_INSTALL -> handleSpecialIntent(SpecialIntent.Install(intent.packageName,
intent.getStringExtra(EXTRA_CACHE_FILE_NAME)))
ACTION_UPDATE_ALL -> handleSpecialIntent(SpecialIntent.UpdateAll) // Added by REV Robotics on 2021-06-07
ACTION_PERFORM_ACTION_WAITING_ON_INTERNET -> handleSpecialIntent(SpecialIntent.PerformActionWaitingOnInternet) // Added by REV Robotics on 2021-06-07
else -> super.handleIntent(intent)
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/main/kotlin/nya/kitsunyan/foxydroid/MainApplication.kt
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,8 @@ class MainApplication: Application() {
}

// installOsUpdate() function added by REV Robotics on 2021-05-10
// Normally, we'd want to verify that we have Internet access before queueing a download, but the OS update file
// should already be downloaded to the cache at this point.
private fun installOsUpdate() {
Connection(DownloadService::class.java, onBind = { connection, _ ->
mainThreadHandler.postDelayed(::installOsUpdate, 1000)
Expand Down
22 changes: 19 additions & 3 deletions src/main/kotlin/nya/kitsunyan/foxydroid/screen/ProductFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@ import androidx.fragment.app.DialogFragment
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.revrobotics.RequestInternetDialogFragment
import com.revrobotics.RevConstants
import com.revrobotics.RevUpdater
import com.revrobotics.InstallApk
import com.revrobotics.actionWaitingForInternetConnection
import com.revrobotics.internetAvailable
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.disposables.Disposable
Expand Down Expand Up @@ -376,7 +380,7 @@ class ProductFragment(): ScreenFragment(), ProductAdapter.Callbacks {
}
val binder = downloadConnection.binder
if (productRepository != null && release != null && binder != null) {
binder.enqueue(packageName, productRepository.first.name, productRepository.second, release)
handleDownloadClick(binder, productRepository, release)
}
Unit
}
Expand Down Expand Up @@ -456,8 +460,9 @@ class ProductFragment(): ScreenFragment(), ProductAdapter.Callbacks {
else -> {
val productRepository = products.asSequence().filter { it.first.releases.any { it === release } }.firstOrNull()
if (productRepository != null) {
downloadConnection.binder?.enqueue(packageName, productRepository.first.name,
productRepository.second, release)
downloadConnection.binder?.let {
handleDownloadClick(it, productRepository, release)
}
}
}
}
Expand Down Expand Up @@ -502,4 +507,15 @@ class ProductFragment(): ScreenFragment(), ProductAdapter.Callbacks {
.create()
}
}

// handleDownloadClick function added by REV Robotics on 2021-06-12
private fun handleDownloadClick(downloadServiceBinder: DownloadService.Binder, productRepository: Pair<Product, Repository>, release: Release) {
if (internetAvailable) {
downloadServiceBinder.enqueue(packageName, productRepository.first.name,
productRepository.second, release)
} else {
actionWaitingForInternetConnection = InstallApk(packageName, productRepository.first.name, productRepository.second, release)
RequestInternetDialogFragment().show(childFragmentManager, null)
}
}
}
33 changes: 21 additions & 12 deletions src/main/kotlin/nya/kitsunyan/foxydroid/screen/ProductsFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ import com.revrobotics.RevUpdater
import com.revrobotics.LastUpdateOfAllReposTracker
import com.revrobotics.LastUpdateOfAllReposTracker.lastUpdateOfAllRepos
import com.revrobotics.LastUpdateOfAllReposTracker.timeSinceLastUpdateOfAllRepos
import com.revrobotics.RequestInternetDialogFragment
import com.revrobotics.UpdateAll
import com.revrobotics.actionWaitingForInternetConnection
import com.revrobotics.internetAvailable
import com.revrobotics.mainThreadHandler
import com.revrobotics.queueDownloadAndUpdate
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
Expand Down Expand Up @@ -116,7 +120,7 @@ class ProductsFragment(): ScreenFragment(), CursorOwner.Callback {
LastUpdateOfAllReposTracker.addTimestampChangedCallback(lastDownloadTimestampChangedCallback)
}

// The remainder of this function was reworked by REV Robotics on 2021-05-09 in order to support an Update ALl button
// The remainder of this function was reworked by REV Robotics on 2021-05-09 in order to support an Update All button

downloadConnection = Connection(DownloadService::class.java)
downloadConnection?.bind(requireContext())
Expand All @@ -134,15 +138,20 @@ class ProductsFragment(): ScreenFragment(), CursorOwner.Callback {
RecyclerFastScroller(recyclerView)

updateAllButton.setOnClickListener {
updateAllButton.isEnabled = false
updateAllButton.text = "Updating all software"
RevUpdater.updatingAllSoftware = true
val messagePart1 = "Downloading and installing all updates."
val messagePart2 = "Download progress is displayed in the notification shade, and installation progress is displayed here."
RevUpdater.showOrUpdateDialog("$messagePart1\n\n$messagePart2", activity!!)
RevUpdater.dialogPrefix = "$messagePart1 $messagePart2\n\n"
updateAll()
// TODO(Noah): Reset the text and enable the button when all updates are installed
if (internetAvailable) {
updateAllButton.isEnabled = false
updateAllButton.text = "Updating all software"
RevUpdater.updatingAllSoftware = true
val messagePart1 = "Downloading and installing all updates."
val messagePart2 = "Download progress is displayed in the notification shade, and installation progress is displayed here."
RevUpdater.showOrUpdateDialog("$messagePart1\n\n$messagePart2", activity!!)
RevUpdater.dialogPrefix = "$messagePart1 $messagePart2\n\n"
updateAll()
// TODO(Noah): Reset the text and enable the button when all updates are installed
} else {
actionWaitingForInternetConnection = UpdateAll
RequestInternetDialogFragment().show(childFragmentManager, null)
}
}

this.recyclerView = recyclerView
Expand Down Expand Up @@ -276,14 +285,14 @@ class ProductsFragment(): ScreenFragment(), CursorOwner.Callback {
}

private fun getUpdatesTabEmptyText(): String {
val asOfPrefix = " as of "

// TODO(Noah): If currently syncing, state that.
if (lastUpdateOfAllRepos < LocalDate.parse("2021-01-01").atStartOfDay().toInstant(ZoneOffset.UTC)) {
// If we haven't checked for updates in an impossibly long time, assume we never have.
return "Please connect to the Internet and check for updates"
}

// We have to tell getRelativeTimeSpanString() whether we want the results in minutes, hours, days, or weeks
val asOfPrefix = " as of "
val howLongAgo = when {
timeSinceLastUpdateOfAllRepos < Duration.ofMinutes(10) -> { // Syncing repositories can take a while, so we have a ten minute grace window
""
Expand Down
33 changes: 33 additions & 0 deletions src/main/kotlin/nya/kitsunyan/foxydroid/screen/ScreenActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,25 @@ import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.os.Parcel
import android.util.Log
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import android.widget.FrameLayout
import android.widget.Toolbar
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import com.revrobotics.InstallApk
import com.revrobotics.RequestInternetDialogFragment
import com.revrobotics.RevUpdater
import com.revrobotics.UpdateAll
import com.revrobotics.actionWaitingForInternetConnection
import nya.kitsunyan.foxydroid.R
import nya.kitsunyan.foxydroid.content.Cache
import nya.kitsunyan.foxydroid.content.Preferences
import nya.kitsunyan.foxydroid.database.CursorOwner
import nya.kitsunyan.foxydroid.service.Connection
import nya.kitsunyan.foxydroid.service.DownloadService
import nya.kitsunyan.foxydroid.service.SyncService
import nya.kitsunyan.foxydroid.utility.KParcelable
import nya.kitsunyan.foxydroid.utility.Utils
Expand All @@ -28,11 +34,13 @@ import nya.kitsunyan.foxydroid.utility.extension.text.*
abstract class ScreenActivity: FragmentActivity() {
companion object {
private const val STATE_FRAGMENT_STACK = "fragmentStack"
private const val TAG = "ScreenActivity"
}

sealed class SpecialIntent {
object Updates: SpecialIntent()
object UpdateAll: SpecialIntent() // Added by REV Robotics on 2021-06-07
object PerformActionWaitingOnInternet: SpecialIntent() // Added by REV Robotics on 2021-06-15
class Install(val packageName: String?, val cacheFileName: String?): SpecialIntent()
}

Expand Down Expand Up @@ -231,6 +239,31 @@ abstract class ScreenActivity: FragmentActivity() {
val tabsFragment = currentFragment as TabsFragment
tabsFragment.initiateUpdateAll()
}
// SpecialIntent.PerformActionWaitingOnInternet added by REV Robotics on 2021-06-15
is SpecialIntent.PerformActionWaitingOnInternet -> {
Log.i(TAG, "Performing action that was waiting for an Internet connection to be established")
val desiredAction = actionWaitingForInternetConnection
if (desiredAction != null) {
actionWaitingForInternetConnection = null
RequestInternetDialogFragment.instance?.dismiss()
when (desiredAction) {
UpdateAll -> {
handleSpecialIntent(SpecialIntent.UpdateAll)
}
is InstallApk -> {
Connection(DownloadService::class.java, onBind = { connection, _ ->
connection.binder?.enqueue(
desiredAction.packageName,
desiredAction.productName,
desiredAction.repository,
desiredAction.release)
connection.unbind(this)
}).bind(this)
}
}
}
Unit
}
}::class
}

Expand Down

0 comments on commit 1de17c5

Please sign in to comment.