Since Intents can come in any time, whether WifiInfoThread is running or
not, the global static vars for storing the WiFi settings info should only
be updated from the WifiInfoThread. Otherwise, the WiFi settings could be
nulled out between the time of the null guard and the execution in code
like this:
if (!TextUtils.isEmpty(FDroidApp.ipAddressString) && netmask != null) {
FDroidApp.subnetInfo = new SubnetUtils(FDroidApp.ipAddressString, netmask).getInfo();
fixes#589https://gitlab.com/fdroid/fdroidclient/issues/589
java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:304)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)
Caused by: java.lang.IllegalArgumentException: Could not parse [null/24]
at org.apache.commons.net.util.SubnetUtils.calculate(SubnetUtils.java:275)
at org.apache.commons.net.util.SubnetUtils.<init>(SubnetUtils.java:62)
at org.fdroid.fdroid.net.WifiStateChangeService$WaitForWifiAsyncTask.doInBackground(WifiStateChangeService.java:89)
at org.fdroid.fdroid.net.WifiStateChangeService$WaitForWifiAsyncTask.doInBackground(WifiStateChangeService.java:70)
at android.os.AsyncTask$2.call(AsyncTask.java:292)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
... 4 more
java.lang.IllegalArgumentException: Could not parse [null/24]
at org.apache.commons.net.util.SubnetUtils.calculate(SubnetUtils.java:275)
at org.apache.commons.net.util.SubnetUtils.<init>(SubnetUtils.java:62)
at org.fdroid.fdroid.net.WifiStateChangeService$WaitForWifiAsyncTask.doInBackground(WifiStateChangeService.java:89)
at org.fdroid.fdroid.net.WifiStateChangeService$WaitForWifiAsyncTask.doInBackground(WifiStateChangeService.java:70)
at android.os.AsyncTask$2.call(AsyncTask.java:292)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)
If the device is small, then the "Conenct and trade apps with people near you"
header takes up too much space and we end up not being able to see any nearby
people at all, even if they are in the list. As such, this also removes that
header for "small" and "ldpi" devices. During testing I found that "small" was
not enough, because a 240x400 screen is considered "medium" and there is not
enough space. ldpi seems to be a reasonable metric for "that header is going to
be taking valuable space and should not be shown then".
All larger devices retain the header and seem to look nice.
This also pushes the "Can't find what you're looking for?" message and associated
buttons right to the bottom of the screen. This is more in line with the original
design.
Fixes#604.
Although this is deprecated, and will result in queries being run on the
main thread, it is required to fix#606. In the future, `LoaderManagers`
should be used to address the concerns of querying on the main thread.
Don't allow download notifications to be cancelled, other than our "Cancel" action on them.
*NOTE: To be cherry-picked into stable-v0.100*
As a user, I expect removing a notification of a pending action to cancel that pending action. This change makes the pending notifications uncancellable, unless users use our cancel action added to the events by @paresh. If the user is on an older device that doesn't support these type of rich notifications, then they will need to touch the pending download notification, which will take them to the `AppDetails` activity for that app. From there, they can cancel the install, which will remove the app from the pending download queue.
Until the notifications are reworked, this is the simplest solution. In the near future, the notifications will likely be combined into one more intelligent notification with better defined semantics.
See merge request !292
Until the notifications are reworked, this is the simplest solution.
In the near future, the notifications will likely be combined into one
more intelligent notification with better defined semantics.
Type parameters can be ommited if defined and declared in same statement.
`onStart()` is deprecated and not required, as we target APIs > 5.
`Intent.FLAG_ACTIVITY_CLEAR_TASK` is not supported on APIs < 11 but we target 8.
Before, it would change fields in a final Repo instance, which means that
things could be out of sync when accessed. Now it swaps out the old one
with a new Repo instance in one step.
The local repo variables are now declared volatile so that they are more
predictable when accessed from various threads (WifiStateChangeService,
SwapService, etc.)
askServerToSwapWithUs(NewRepoConfig) was unused, so I removed it.
The IntentService provides the nice incoming Intent queue. It also runs
the Intent in a thread, so even the initial check is now in a very low
priority thread. The queuing prevents the incoming Intents from competing.
This also simplifies the code since the lifecycle is more automatic now.
The `android:process` statement in AndroidManifest.xml causes another
process to be created to run CrashReportActivity. This was causing lots of
things to be started/run twice including CleanCacheService and
WifiStateChangeService.
Lint says that only GET_META_DATA and GET_SHARED_LIBRARY_FILES are allowed.
This contradicts Android's documentation where GET_UNINSTALLED_PACKAGES
is also allowed.
Fixes#605
This was crashing when coming to SwapAppsView because some of the flow
changed related to the new DownloaderService and InstallManagerService.
Also, this lazy loading is a tiny optimization that we cannot afford right
now, there are far too many lifecycle bugs with swap.
This should fix the PMD error:
"Check the value returned by the skip() method of an InputStream to see if
the requested number of bytes has been skipped."
The check was set up to only cancel when the `AppDetails` for that app
was shown. This is the correct behaviour for the 'complete' event, but
not the cancel. The cancel event should always result in the relevant
notification being removed.
If we are capable of bailing earlier rather than later, then we should. This way,
if a hash doesn't match, the file will be removed and a new download will begin,
as expected. The alternative is to let the installer catch the unmatching hashes.
By then though, it is too late to really do anything meaningfull and it becomes
more difficult to recover in a way that the user would expect.
Due to the earlier refactoring of `getNotificationTitle()` (or something like that)
to `getAppName()`, it was still returning `getString(downloading_apk, appName)` instead
of just the app name.
I wrestled with this a bunch, it seems quite difficult to make the Cancel
button on the notification responsive. This collection of minor changes
made it more reliable, but its still kind of flaky. I think the problem
might be related to the fact that it is creating a whole new Notification
instance, with the accompanying Intent and PendingIntent instances, for
every single download progress update.
closes#652https://gitlab.com/fdroid/fdroidclient/issues/652
If an APK was queued to download but had not started downloading yet, it
was not able to be fully canceled because ACTION_INTERRUPTED was not sent.
That meant that the UI never got updated, even though the APK was removed
from the queue.
#652https://gitlab.com/fdroid/fdroidclient/issues/652
This logic is pretty basic for now, it'll have to be expanded a lot to
support the different UX between priv and non-priv installs. For example,
priv updates will be able to happen entirely in the background. Those will
then require leaving a notification to tell the user that the app was
updated so nothing can transparently install updates without the user
knowing. When the user is an active part of each install, like the
non-priv experience requires, then keeping the "app installed" notification
feels like just extra noise.
The Event class is no longer needed once there is specific ProgressListener
instances for each type of progress update. The sourceUrl serves as the
unique ID, like with DownloaderService and InstallManagerService.
fixes#633https://gitlab.com/fdroid/fdroidclient/issues/633
This allows the install process to have consistent data, even if the index
database changes while an APK is making its way through this process.
This also provides a set of packageNames to be easily queried.
Standardizing on Apk as the internal data type means that most of the data
that is needed for the whole lifecycle of a given APK going through this
process will be available regardless of the database changes. Once App
instances are also included, then all of the data should be available
separately from the database. This is important to support parallel
operation. The index could be updated and an app could disappear while an
APK of that app is being downloaded. In that case, it should not show
blank notifications.
Also, in AppDetail, the Apk instance is completely loaded from the db, so
there should not be any nulls on the essential bits like packageName and
download URL.
This keeps the IDs standard throughout the code: either urlString when it
should be a String, or urlString.hashCode() when it should be an int. It
also follows the naming convention in DownloaderService helper methods,
e.g. getIntentFilter(). "create" to me doesn't necessarily mean also "get"
Using @NonNull or @Nullable is fine when it is actually useful, like the
compiler can catch errors, but it also adds a lot of noise when reading the
code. For example, @NonNull here will just make people avoid thinking.
Context can never be null anywhere in Android, that's a given throughout
the Android API. And in this code, urlString is the unique ID used
throughout the process, so if its ever null, nothing works.
This keeps DownloaderService tightly focused on downloading, and makes it a
lot easier to manage Notifications since InstallManagerService's lifecycle
lasts as long as the Notifications, unlike DownloaderService.
DownloaderService is structured to be as simple as possible, and as tightly
matched to the downloading lifecycle as possible, with a single queue for
all requests to avoid downloads competing for bandwidth. This does not
represent the possibilities of the whole install process. For example,
downloading can happen in parallel with checking the cache, and if an APK
is fully cached, there is no need for it to go through the DownloaderService
queue.
This also lays the groundwork towards simplifying DownloaderService even
more, by moving the Notification handling to InstallManagerService. That
will provide a single place to manage all aspects of the Notifications that
has a lifecycle that is longer than the Notifications, unlike an Activity
or DownloaderService.
Fixes#624.
The `AppDetails` activity was not correctly asking for the active
download url string when being resumed. This change recalculates the
value when being resumed now.
Added assertions that both apkName and repoAddress need to be populated
in order to call `getUrl()`. Also verified that this is the case for all
usages of this method, which it should be. All `Apk` objects which currently
have `getUrl()` called on them are loaded using the `ApkProvider.Helper.findById()`
method without specifying which columns to load (which defaults to all).