If a new repo comes in via Intent, like from clicking a link, scanning a QR
Code, etc., then stay in FDroid once the add dialog is complete.
Previously, it would sometimes stay in FDroid and sometimes go back to the
sending Activity, depending on the sending Activity. It was confusing and
annoying behavior.
Previously the data was not stored anywhere, and each time we wanted
to know about all installed apps, we built a ridiculously long SQL
query. The query had essentially one "OR" clause for each installed
app. To make matters worse, it also required one parameter for each
of these, so we could bind the installed app name to a "?" in the query.
SQL has a limit of (usually) 999 parameters which can be provided to
a query, which meant it would fall over if the user had more than
1000 apps installed.
This change introduces a new table called "fdroid_installedApps".
It is initialized on first run, by iterating over the installed apps
as given by the PackageManager. It is subsequenty kept up to date
by a set of BroadcastReceivers, which listen for apps being
uninstalled/installed/upgraded.
It also includes tests to verify that queries of installed apps,
when there are more than 1000 apps installed, don't break.
Finally, tests are also now able to to insert into providers other
than the one under test. This is due to the fact that the providers
often join onto tables managed by other providers.
Some QR Code scanners don't respect custom schemes like fdroidrepo://, so
this is a workaround, since the local repo URI is all uppercase in the QR
Code for sending the local repo to another device. This way, the QR Code
can still be all uppercase and use HTTP:// and Android will still route it
to FDroid, but via the Just Once/Always chooser (fdroidrepo:// goes
directly to FDroid with no prompt, when it works)
Following the Android 4.2 changes, which explain how to add native support for
RTL, I've replaced Right for End and Left for Start. Enabling RTL to see the
results.
Huge improvements! Amongst them:
* Pressing Up is just as fast as pressing Back
* Like Back, it keeps the scroll position and everything
* Now FDroid behaves like the other activities that an user may navigate up to
This is another easy method to send FDroid to a device that doesn't have it
yet. Unfortunately, stock Android blocks the receiving of APKs, but many
ROMs and even some Samsung devices do not have this block.
You can find the lengthy backstory on this work here:
https://dev.guardianproject.info/issues/2084
Setting android.permission.ACCESS_WIFI_STATE automatically sets up
uses-feature to require wifi. Therefore, we have to manually say that
wifi is not actually required.
This is the framework for easily swapping repos. The idea is that a user
can send the URL with the fingerprint for trusted bootstrapping of the repo
on a new user's device. This will be essential for p2p repos provided
by Bazaar/Kerplapp.
The required NFC APIs were introduced in android-14. So android-14 and below
skip the NFC stuff.
Yay!
As expected, a lot of the stuff in DB class is due to UpdateService
requiring it to process the downloaded indexes and insert data into
the database. Thus, this change is about removing that stuff from
the DB class and migrating to ContentProviders.
This required a bit of a change to the way that UpdateService decides
what to do with the data from indexes, but I hope it will make
understanding and changing UpdateService easier in the long term.
For example, it used to read the app details from database, then
if a repo wasn't updated (due to unchanged index) then it would take
the app details for that repo from the list of apps, and re-update
the database (or something like that).
Now, it has been refactored into the following methods:
* updateOrInsertApps(appsToUpdate);
* updateOrInsertApks(apksToUpdate);
* removeApksFromRepos(disabledRepos);
* removeApksNoLongerInRepo(appsToUpdate, updatedRepos);
* removeAppsWithoutApks();
* and probably some others...
Which hopefully are self-explanitory.
The recent change to implement single repo updates was re-implemented
with in light of the methods above. The interface to UpdateService for
scheduling a single repo update is the same as it was before, but
the implementation is completely different. Still works though.
Using batch content provider operations for repo updates,
but they suffer from the problem of not all being under the same
transaction, so if an insert/update stuffs up half way through, we
are left with only half of the update being complete. In the future,
if there is some way to implement notifications from the content provider's
applyBatch method, then we can do it all in the one transaction, and
still have notifications. Currently we break it into several calls
to applyBatch (and hence several transactions) to inform the user
of the progress.
Also adding the beginnings of some tests for AppProvider. In the future, I'll
work on adding better coverage, including instrumentation to test UI features.
==========================
Below is a list of many of the minor changes that also happened along the way
==========================
Make "Can update" tab stay up to date using content observer, rather
than manually deciding when to refresh the tab label as before.
The installed app list is now cached in Utils, because it is invoked
quite a few times, especially when rendering the app lists. The cache is
invalidated when PackageReceiver is notified of new apps.
The content providers don't notify changes if we are in batch mode.
I've left the notification at the end of the batch updates as the
responsibility of the UpdateService. However, it would be nice if this
was somehow handled by the content, as they are really the ones who
should worry about it.
Made curVersion, curVercode and curApk work with providers.
This was done by removing curApk (otherwise we'd need to query the db each
time we fetched one app to get a reference to that apk (resulting in hundreds
of queries). Instead, UpdateService now calculates curVercode and curVersion
and saves them to the database. We then use these where possible. If we really
need curApk (because we want info other than its version and code) we still have
the option of ApkProvider.Helper.find(app.id, app.curVercode). I considered
putting this inside the app value object, e.g. in getCurApk() but thought
better of it as it will likely result in people invoking it all the time,
without realising it causes a DB query.
incompatibleReasons required a minor UI tweak, removing the "min sdk"
ui element from the Apk list. It is replaced by the "Requires: %s" view
(which only appears when the app is incompatible). In the process, and in
response to some feedback from mvdan, I left the min sdk in there, but
only made it show when in "expert mode", just like the architecture.
In order to make the "installed apps" query work under test conditions,
needed to change the way the InstalledApkCache be replaceable with a
mock object.
Pause UIL loading on fast scroll of list, as the list was very choppy for
some reason.
Re-added "Last repo scan" info to the Manage Repo list view.
Fixed up some misc TODO's, removed some unused/empty functions.
Instead of ramming the fingerprint in the user field of the URI, use the
query string. Having the fingerprint in the user field was confusing some
browsers because it was trying to log in. The query string is the standard
place for such meta data, and has lots of room for expansion including
things like wifi network names. This will be useful later to determine if
both devices are currently on the same wifi network, and if they are local
repos, they should try syncing.
Its quite annoying to have the URI EditText in focus and the soft keyboard
pop up when viewing the RepoDetails since the vast majority of the time,
the user will be viewing the info there, not editing the URL.
This commit just moves the focus to the frame, and prevents the soft
keyboard from showing up by default. The user can still click on the URI
EditText to edit it and the soft keyboard will pop up.
Android's scheme matcher is case-sensitive, so include
ALL CAPS versions to support ALL CAPS URLs in QR Codes.
QR Codes have a special ALL CAPS mode that uses a reduced
character set, making for more compact QR Codes.
This reverts:
We should not encourage all caps urls
2651b81792bdeed0db3c3960d0b7283536611012
The performance improvement from this will not be noticable (perhaps
there isn't one), however it is part of the bigger plan to move all of
the DB access to ContentProviders. This will make a big improvement to
the startup time of the app, given we are currently loading all of the
apps to populate the list of apps.
It will come at the cost of some apparantly weird code convensions. Most
notably, when loading data from a content provder, you only ask
for the fields that you intend to use. As a result of my Helper class which
converts results from the content providers cursor into Repo value objects,
there is no guarantee that certain attributes will be available on the
value object. E.g. if I load repos and only ask for "_ID" and "ADDRESS",
then it is meaningless to ask the resulting Repo object for its "VERSION"
(it wont be there), despite it being a perfectly legal attribute from
the Java compilers perspective.
Repo.id field has also been made private (sqlite is the only
entity should be able to set id's), and made id a long (sqlite stores
identifiers as longs rather than ints).
Before, "Repo Details" always had a title of "Repositories". Now
it shows the name of the repo as the title. This also enables the
ActionBar back button (aka "display home as up") to return to
"Manage Repos".
In order to support F-droid repositories hosted with HTTPS using
a self-signed certificate the f-droid client should prompt the user to
trust or 'memorize' the certificate presented by a repository. The
MemorizingTrustManager[0] project enables easy integration of
a prompting activity and corresponding trust manager implementation.
This behaviour is useful to projects such as Kerplapp[1] that boostrap
an F-droid repository on a user's device where it isn't possible to
acquire a long lived CA vetted TLS certificate.
In addition to Trust-on-First-Use (TOFU) behaviour, this patch
integrates the PinningTrustManager [2] project by Moxie Marlinspike to
allow the FDroid client to ship a hardcoded set of Subject Public Key
Identifier pins [3] for the official FDroid repository TLS certificate,
and the Guardian Project TLS certificate. Additional pins can be added
to the FDroidPins.java class.
The upstream release of AndroidPinning by moxie0 uses a minsdk value of
8. The Fdroid client has a minsdk of 5, presenting compatibility issues
using the AndroidPinning lib as a submodule. Fortunately it seems there
is no technical reason preventing using a minSDK of 5 with
AndroidPinning. I have created a fork with this change and submitted
a pull req upstream. Until this pull is merged we can use my fork of
AndroidPinning as the submodule.
The new 'flow' for deciding if a repositories presented TLS certificate
should be trusted is as follows:
1) If the certificate was previously trusted by a TOFU action, then the
certificate is accepted as trusted
2) If the certificate wasn't previously trusted by a TOFU action but
there is a matching SPKI pin then the certificate is accepted as
trusted
3) If the certificate wasn't previously trusted by a TOFU action and
there is no SPKI pin but the certificate is signed by a trusted
Certificate Authority it is accepted as trusted (This is the
behaviour of the FDroid client prior to this patch with all other
conditions being a hard-fail).
4) If the certificate wasn't previously trusted by a TOFU action and
there is no SPKI pin and the certificate is not signed by a trusted
CA (i.e. self signed or otherwise) then the user is prompted to TOFU
the certificate. The user may choose to trust the certificate for the
current connection or forever. If the user chooses an option other
than "deny" the certificate is accepted as trusted for the specified
duration.
Users currently using a TLS protected repository will see *no
difference* in user experience after this patch is merged as the only
TLS protected repositories that would function prior to this patch were
providing certificates that match condition #3.
[0] https://github.com/ge0rg/MemorizingTrustManager/wiki/Integration
[1] https://github.com/guardianproject/kerplapp
[2] https://github.com/moxie0/AndroidPinning
[3] https://www.imperialviolet.org/2011/05/04/pinning.html
It's handier to have just the one resource version_name, but lint gets very
angry at this (and there must be a reason for that). We must not forget to
update the resource in res/values/no_trans.xml, since it's still used in the
code.
Phew, monster merge. Going to commit after *seemingly* resolving
conflicts, but it will no doubt take a few compile and runs to sort out
any funny stuff.
Conflicts:
AndroidManifest.xml
res/layout/addrepo.xml
res/layout/appdetails.xml
res/layout/repolisticons.xml
res/values/strings.xml
src/org/fdroid/fdroid/DB.java
src/org/fdroid/fdroid/FDroid.java
src/org/fdroid/fdroid/ManageRepo.java
src/org/fdroid/fdroid/UpdateService.java
SwitchCompat will return a Switch or a ToggleButton depending on the
platform (doesn't matter, both are CompoundButtons) and this will be
added to the repo_item view programatically.
I'm using some pretty specific listeners
to communicate between the details fragment and the repo list activity.
I've also split the functionality (e.g. for deleting) between the repo
list and the details view. In the future, when we have content providers
for repos, it will be easier to take care of everything from the details
screen, and automatically notify the repo list of changes.
Refactored update service.
Now has a static update method that can be called which
will setup the required intent to begin the update. It also deals with
progress listeners and dialogs for the user, so all of this is moved out
of FDroid. This was so that RepoDetailsFragment can now invoke the same
functionality.
With so many patterns being matched, it is highly likely that there will be
false positives, i.e. random URLs will trigger the prompt of whether to use
F-Droid or not. The updated set of patterns narrowly tailors the matches
so that it is highly unlikely to match URLs that are not fdroid repos, yet
still makes it useful both as a generic repo and a peer-to-peer
bootstrapping repo.
This set of patterns only matches URLs like this:
https://foo.org/fdroid/repohttps://foo.org/fdroid/repo/https://foo.org/fdroid/repo/////
It does not match URLs like this:
https://f-droid.org/repohttps://myblog.com/thoughts-about-my-lovely-fdroid-repohttps://news.com/tag/repohttps://somesite.com/repo/this-is-my-stuff
It matches multiple slashes to since those are in effect the same URL, and
they sometimes show up as typos. This does not include mvdan's proposal
for the 'fdroid-bootstrap' tag on the end because its not something that I
would use in this current project, so I don't know how best to apply it. I
have no objection to the 'fdroid-bootstrap' proposal.
This patch makes F-Droid register with Android that it accepts the URI
schemes of fdroidrepo (HTTP) and fdroidrepos(HTTPS). When F-Droid receives
one of these URIs, it launches the ManageRepo Activity and then launches
the New Repository dialog.
refs #2454