This also switches to always using getActivity().getSwapService() to make
it easily traceable where that is happening. It shouldn't be happening in
SwapViews...
java.lang.IllegalStateException: Fatal Exception thrown on Scheduler.Worker thread.
at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:62)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6128)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:889)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:779)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.String.equals(java.lang.Object)' on a null object reference
at org.fdroid.fdroid.localrepo.peers.BonjourPeer.equals(BonjourPeer.java:34)
at java.util.HashMap.put(HashMap.java:427)
at java.util.HashSet.add(HashSet.java:217)
at rx.internal.operators.OperatorDistinct$1.onNext(OperatorDistinct.java:62)
at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber.pollQueue(OperatorObserveOn.java:202)
at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber$2.call(OperatorObserveOn.java:162)
at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
https://stackoverflow.com/a/602660
java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(HashMap.java:851)
at java.util.HashMap$ValueIterator.next(HashMap.java:879)
at org.fdroid.fdroid.localrepo.LocalRepoManager.copyIconsToRepo(LocalRepoManager.java:296)
at org.fdroid.fdroid.localrepo.LocalRepoService$1.run(LocalRepoService.java:131)
SwapService is the thing that needs to be always running, and the last
thing killed. So it should start first, and stop last. So now, the user
clicking the button starts SwapService, which starts SwapWorkflowActivity.
This also eliminatings the "Loading" screen in favor of just showing the
StartSwapView with various inline progress indicators.
Instead of waiting for the user to make all the app selections, then click
next, this constantly regenerates the swap repo on each click of the app
list. This means that the swap repo is more likely to be immediately ready
when the user clicks next.
The Android back button provides a working back function, and the Swap
"close" button on the upper left already provides a reset function. So this
turns the "back" button to be a "try again" button which re-runs the
connection process.
The Receiver superclass is not reusing difficult code, but it is hiding the
simple list of UI configuration that it does.
This also eliminates the "error" TextView and just reuses the existing
TextView for error messages.
The most expensive part of this whole process is calculating the hash of the
whole APK. InstalledAppProvider already caches that, and the rest is OK to
query. If any particular part of the query is expensive, it could also be
moved to InstalledAppProviderService.
This moves all logic for setting up the local fdroid repo to its own
IntentService. That makes it much easier to interact with since things can
just use the static helper method to request it to update, and it'll do the
right thing.
Almost all of the nearby/swap view classes could be condensed into a single
base class that is instantiated in the view XML. This is the first step
towards making that happen.
It also lays the groundwork where "steps" are all SwapViews. The
original concept of "steps" put all steps together, whether
F-Droid could control them or not. For example, the Views were
mixed with the system Bluetooth prompts. This is the first step
towards converting the steps to always be SwapViews, which are
always under control of this app.
When coming back to a SwapView/step, it does not seem feasible to handle
automatically restarting things like permissions and Bluetooth prompts. If
there is a way, it should be possible to first load the proper SwapView
instance, then trigger the system prompt. The makes the SwapView a pure
View, without any Controller in it.
The date/time written to index.xml and index-v1.json should always be in
UTC format. These formats are often in the form of just a date, e.g.
2019-04-28. Those are then converted to UNIX seconds, which includes the
time. In the date only case, the time is assumed to be 00:00, which will
be different per time zone.
index-v1.json is better since it mostly uses Java-style UNIX time in millis
but the dates/times are parsed then stored in the local database in the old
format yyyy-MM-dd_HH:mm:ss which will result in different UNIX times when
the device is in different time zones.
fdroid/fdroidclient#1757
This also converts old Repo.lastUpdated values rather than just failing.
index.xml handling used to store the Repo "Last Updated" date used to store
the value as just an ISO date (2019-04-29), then the time was added. So if
date/time parsing fails, this falls back to trying to parse just the date.
null is returned when parsing fails, and the Latest Tab shows nothing if
the Last Updated is null.
Some related tests were also tweaked.
Hopefully:
closesfdroid/fdroidclient#1757