This breaks out subclasses for each specific type of app list item,
allowing for code reuse, but also letting the specific business logic
belonging to each different app list item to be separate.
This is particularly helpful in the following situation:
* In the search results, it is great to be able to render "App
downloaded, ready to install" in the same manner as the update tab.
* In the installed app list, this is not desired. Indeed, the status
text which should be shown should reference the currently installed
version and whether the user has ignored any updates.
By separating the AppListItemController into subclasses, it reduced the
need to handle several different types of text view (e.g.
"installedStatus", "status", "ignoredStatus", "downloadReady"), and
replace them all with a "status" and "secondaryStatus" TextView. What is
displayed in status and secondaryStatus is up to the individual
subclasses of AppListItemController.
Previously, there were different pieces of business logic, invoked at
different times, which would touch subsets of the UI.
This change rips that out, and replaces it with a single place where the
UI is setup. This can always be called safely, and it will render the
correct data for the current state of the app (e.g. downloading, waiting
for install, etc).
The AppListItemState class is a dumb object which keeps track of what is
supposed to be displayed in the UI. The AppListItemController now
creates a different AppListItemState depending on what state the list
item is in. This AppListItemState is then used to bind the values of
each UI widget.
All of the binding code is now in the single `resetView()` method, but
all of the business logic for what the view should look like is
separated into different `getViewState*()` methods.
This separation should make it easier to make sense of the UI code, and
hopefully should be testable should somebody choose to write tests for
it in the future.
The docs say that initLoader tries to reuse existing cursors.
The error message was "IllegalStateException: attempt to re-open an
already-closed object: SQLiteQuery: ...".
There may be a bigger problem around suggested versions being null at
all, but that is getting looked at in a different feature set (i.e.
multi signature support) and will come in time. This fixes the immediate
problem some people were having and sending crash reports for in 0.104.
STACK_TRACE=java.lang.NullPointerException: Attempt to read from field 'java.lang.String org.fdroid.fdroid.data.Apk.versionName' on a null object reference
at org.fdroid.fdroid.views.AppDetailsRecyclerViewAdapter$HeaderViewHolder.bindModel(AppDetailsRecyclerViewAdapter.java:425)
at org.fdroid.fdroid.views.AppDetailsRecyclerViewAdapter.onBindViewHolder(AppDetailsRecyclerViewAdapter.java:244)
at android.support.v7.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:6310)
at android.support.v7.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:6343)
...
Introduced in 97fd3f0.
* F-Droid cannnot uninstall system apps, only their updates,
but even with the privileged extension, that can get complicated.
* Let's just not allow uninstalling system apps, the phone's settings
app can happily disable/re-enable system apps, and also uninstalls
their updates on disabling.
If the client fails due to some bug in handling index-v1.jar, then it will
be totally stuck, even if index.jar would have worked. This creates a new,
temporary "expert" preference to force the client only use the old XML
index file. Worst comes to worst, we can tell people to enable this to
upgrade.
Once everything proves stable, we can remove this.
This started with the work of @kingu, it cleans up some of the language,
including:
* upgrade --> update
* application --> app
* internet --> Internet
closes!508
... when PackageInstaller is the installer (privext).
* In the case where the Privileged Extension is installed,
but the installation happens through DefaultInstaller still
due to something like a permission mismatch,
that is set as the installer package name.
* We cannot install packages installed by that via the system methods,
so fallback to DefualtInstaller for uninstalling as well when the
app is installed by PackageInstaller
The fact that Cursors are used with the apk provider is more of an
implementation detail (to some extent). It is a crappy, leaky
implementation right now, but still an implementation detail.
This should probably be done on the database level, if purely for the
fact that we have a good set of unit tests for that. However it is still
quite clean to do so here.
This is really the intention of the method, given it used to accept
a version code and a package name. Now it optionally accepts a sig
also. If present, it will restrict the query to apks with that sig.
Also added to the multi-sig tests to ensure this method takes it into
consideration.
There is some magic conversions going on so that booleans get
converted into integers, but they are only on Android. Under
robolectric, it throws a class cast exception instead.
Some were removed and left removed if they were run during tests,
because the tests are supposed to be automated and the noise they added
would not have helped diagnose a failure.
Also removed the dead code around "uses-feature" which will never
get implemented, especially as it is in the XML index.
The main problem is that we were using an index on fdroid_apk.vercode,
when it should have been using an index on fdroid_apk.appId. There are
thousands of apks which would match based on vercode, but only two or
three which match based on appId. This improves performance of the
calculate-suggested-vercode query from 25,000ms to 100ms.
Produces the following output:
D Explain:
D SCAN TABLE fdroid_app
D EXECUTE CORRELATED SCALAR SUBQUERY 0
D SEARCH TABLE fdroid_apk USING INDEX apk_vercode
D EXECUTE CORRELATED SCALAR SUBQUERY 1
D SEARCH TABLE fdroid_app AS innerAppName USING INTEGER PRIMARY KEY (rowid=?)
D EXECUTE CORRELATED SCALAR SUBQUERY 2
D SEARCH TABLE fdroid_package AS pkg USING INTEGER PRIMARY KEY (rowid=?)
D SEARCH TABLE fdroid_installedApp AS installed USING INDEX sqlite_autoindex_fdroid_installedApp_1 (appId=?)
There are two possibilities here, one is the number of correlated sub
queries (three seems a bit excessive). Alterantively, it could be the
fact that one of the inner queries is using a string index (appId=?)
instead of an integer primary key.
The history of this is that #974 identified a problem, which was fixed
in !497. That MR added test coverage for the bug.
However, the fix for it actually added a huge performance hit, on the
order of 30 seconds or so when calculating the suggested version.
This fixes that performance problem by removing the need for a sub
query. The end goal is to take the following query:
```
UPDATE app
SET suggestedVersion = (
SELECT MAX(apk.version)
FROM apk
WHERE ...
)
```
and the `WHERE` clause needs to somehow join the outer `app` table with
the inner `apk` table, such that the repo in question does not matter.
It can't just join directly from `apk.appId -> app.rowid`, because the
`app` is specific to a given repository, but we want to select the
`MAX(apk.version)` from every related apk, regardless of repo.
This commit solves it by joining the inner `apk` table onto an
intermediate `app` table, which is used purely so that we can select
apks where their `packageId` is the same as the `packageId` of the app
being updated.