Show progress bar in download notification.
This enhances the download notification to include a progress bar of the downloads progress.
(It doesn't show the actual size of the download or the number of bytes downloaded in text yet. Need to think about internationalizing this from the `AppDetails` `updateProgress` method so that it is not copy-pasted in two places.)
See merge request !261
This release allows for Android 6+ support, but we'll need to ask for
permissions at runtime too. This commit simply does one half of the work
needed to support Android 6 with all things wi-fi.
See the issue and example app commit for reference:
https://github.com/mvdan/accesspoint/issues/66284f0376b
Also add useProgard true, since minifyEnabled now refers to the new
experimental code shrinker.
I'm not removing proguard yet as we depend on it for the samsung
workaround. I also do not know how to port the rest of the config
options to the new shrinker.
New DownloaderService
This merge request is too big, but I have all this work complete, so I'm submitting it now for review. If there are bigger issues with parts, I can rebase it down to the uncontroversial bits to get things merged.
This replaces `ApkDownloader`, `AsyncDownload`, and `AsyncDownloadWrapper`, and puts the whole APK download procedure into a custom `Service` that is based on the source code for `IntentService`. It can't be a subclass of `IntentService` because it needs to be cancelable. This does not yet add back a notification for the downloading, e.g. #592. That was handled before by the Android DownloadManager stuff, and was not replaced since that was disabled.
My current implementation does not filter out duplicate requests like discussed in #601. While its possible to do, I think it'll complicate the code a lot, and I really think that should be handled elsewhere. The UI should prevent the possibility of the user being able to submit duplicate install requests. If not, even if `DownloaderService` filtered them out, it would still be a buggy UX since the user would be clicking install again or something like that even though the install was in progress.
This also moves the APK verification logic to the `Installer` side. The downloading side can check the file size to see if the whole thing is downloaded. And to be extra safe, it should not be possible to submit an APK for installation without it going through the verification procedure. So the only method for installing APKs, `Installer.install()`, is where the verification now happens. Also, the installer now always copies the APK to be installed into the safe location RE: the Cure53 audit issue. This way, the APK download and cache dirs can be merged into one, making resumable downloads and cache management easy.
ping @mvdan @pserwylo @dschuermann
more comments in the commit messages
See merge request !248
Now that we have a nice background service, let's put it to work! This
makes update APKs be automatically downloaded after the index is updated.
Then when the user goes to install the updates, they will not have to wait
for the download part.
#601https://gitlab.com/fdroid/fdroidclient/issues/601
This moves a few stray preference handling instances into Preferences, and
move the non-preference "lastUpdateCheck" state to local only to
UpdateService. This will still work with existing installs since the
String constant value is the same.
This also saves the activeDownloadUrlString per packageName. Both are
necessary so that AppDetails can accurately display the current state
of a background download. Saving this per-packageName allows there to
be multiple active downloads in the background, then when people move
around AppDetails, it'll restore the progress meter and button state
when coming back to the app that they clicked install on.
By definition, there is just one DownloaderService enforced by
Android with a single active Downloader instance enforced by the
DownloaderService. That means using a static variable maps directly
to those conditions and provides a really simple, implementation,
especially compared to what would have to happen to do it via messages
from the thread and any Activities. If this ends up blocking testing
or something, it can always be changed when someone implements those
tests.
Moving towards having the Downloader always download directly into the
cache means its really easy to support resuming downloads.
This should also work for updates and icons, since it fetches the
Content Length via HTTP first. The icon and update downloading code
needs to be adjusted to support that. For APKs, it probably makes
sense to include the file size from the index db to save the query
over the net. That would be probably more helpful on Bluetooth.
This moves the last piece of code to the DownloaderService model. Moving
the APK prep and verification to Installer.installPackage() makes it hard
to mess up and make bugs like installing from the External Storage issue
found by the Cure53 audit.
AndroidNotCompatibleException is not used for anything specific right now,
and in the process of adding verification to the start of the install
process, there will be other kinds of failures. So convert that Exception
into a general usage InstallFailedException.
No need to flood receivers with progress events since they are basically
always going to the UI, and the UI will only refresh every so often. If
the refresh rate is 50Hz, then that's every 20ms. 100ms seems to make a
smooth enough progress bar, and saves some CPU time. This becomes more
important if there are multiple downloads happening in the background, like
if we make DownloaderService support parallel downloads from different repos
When dealing with complex lifecycles like Fragments, it is important
to expose the reliance of the Fragment on the Activity, since they
have different lifecycles.
Just cast to AppDetails instead of adding complexity with unneeded
Interfaces. The actual instance and class will be the same with or
without the Interfaces, so it does not help with lifecycle issues.
The methods that implement the interfaces only hide the fact that they
rely on an active instance of AppDetails, which can lead to
lifecycle-related crashes.
This is a step along the way to streamlining AppDetails Activity so that it
only uses Fragments when they are beneficial.
DownloaderService is based on IntentService to provide queued requests that
run in a background thread via the Handler and the HandlerThread. It began
as the IntentService code, but it could not be a subclass because the
downloading needs to be cancelable. IntentServices cannot be canceled and
they provide no visibility into their queue.
DownloaderService then announces relevant events via LocalBroadcastManager
and Intents with custom "action" Strings.
https://gitlab.com/fdroid/fdroidclient/issues/601#601
Verify apk signature of privileged extension before installation
This implements a check that the signature of the extension apk is the same as the signature of F-Droid before installing the extension apk. Related issue: https://gitlab.com/fdroid/fdroidclient/issues/437
See merge request !256
More tests and bug fixes
I pulled a few commits out of the !248 saga, and added a bug fix or two. It would be easier if this was merged before !248
ping @mvdan @pserwylo
See merge request !255
Currently, UpdateService is running at default priority, which is the same
as the UI tasks, since it is a regular IntentService. That means it would
put a noticable load on the device when running, especially on older
devices. This should help with that.
#563https://gitlab.com/fdroid/fdroidclient/issues/563
Android recently switched from JUnit 3 to 4 for its base testing classes.
It doesn't seem to support the old JUnit3 methods with gradle and AS. So
all the tests need to be ported to JUnit4 to work again.
#607https://gitlab.com/fdroid/fdroidclient/issues/607
Since SSLHandshakeException is a subclass of IOException, and all that is
happening is rethrowing an Exception, instead pass this one through so it
will be handled by the central Downloader error handling. That's currently
just a Toast, but it can easily be expanded in the future.
Shared element transition for app list item v21 and above
Shared element transitions for API level v21 and above

See merge request !251
fixes and cleanups related to ongoing DownloaderService work
This includes a fix for bug that @mvdan found in the processing of `Apk.maxSdkVersion`, as well as some cleanups related to the ongoing work in !248 . Indeed a couple of these commits were pulled out of that MR.
See merge request !253
Since Downloader's outputFile variable is final, it can safely be used
as a public property variable. This makes it simple to use in
subclasses. Making it a public final variable rather than a getter
also communicates that the value does not change since there is no
getter method that could potentially change it.
http://binkley.blogspot.com/2005/01/read-only-properties-in-java.html
Having 0 mean max makes the logic confusing when maxSdkValue is used in
variable. This sanitizes the data so that maxSdkValue is always just a
plain int value that can be used to test against. It does this by
defaulting to Byte.MAX_VALUE (127) if it is not explicitly set. At the rate
of 24 SDK numbers in 8 years, that gives us about 24 years before we have
to think about setting it to Short.MAX_VALUE.
This fixes an issue created by e021eb5ca7e8f05dbce7c1b87833722542138302
gitlab-ci: use android-17 emulator for `gradle connectedCheck`
The android-10 emulator does not report test failures so it is pretty useless at the moment. After lots and lots of trying, the most recent emulator that I could get running on gitlab-ci was 17, so let's hope that turns out to be more useful. I also had to reduce the RAM that was used, it seems that gitlab-ci does not let the docker images use much RAM. This might be able to be improved by creating an pre-setup AVD image in the docker image used by this.
As you can see from the history, I tried lots of things to see if it is was possible to get a more recent emulator running on gitlab-ci.
See merge request !241