File: PC-Phone USB Sync/code/PC-Phone USB Sync--source/purgatory.py
class Purgatory:
"""
------------------------------------------------------------------------------
[1.5] A simple fixed-length queue of 'numsouls' objects.
Part of program PC-Phone USB Sync, with same terms of use.
Used to temporarily retain Python objects sent back to Java via pyjnius
on Android, per a theory that they might be garbage collected on the
Python side before used by Java and thus trigger crashes. Referencing
objects in the queue postpones their Python garbage collection.
This could explain a Java exception that occurred for an insets object,
which is passed from Java to the Python pyjnius edge-to-edge callback
onApplyWindowInsets and then returned as the callback's result to Java.
In some cases (e.g., screen switches on a Fold7), there are three such
callbacks in rapid succession, so simply saving a single object in self
is not enough. The Java info:
java.lang.NullPointerException: Attempt to invoke virtual method
'boolean android.view.WindowInsets.isConsumed()' on a null object
reference" [in java.lang.reflect.Method.invoke(Native Method)]
This also may be entirely moot. Two such crashes were observed in the
logcat within 9 minutes of each other and the app did seem to vanish during
a screen switch, but the history on this is impossible to reconstruct. There
was also unrelated prototyping in the same timeframe that crashed in the insets
callback for known unrelated coding errors, and inadvertently pressing Android
Back twice while juggling the device to switch screens can also exit the app.
Moreover, the crashes could not be recreated, and no others have been seen
or reported, even though insets callbacks have been used for 6 months since
1.4.0. In addition, pyjnius' docs state that the callback function itself
must have a retained reference but say nothing about function return values,
and pyjnius' return-value code seems sound on first survey. A general web
search was ambiguous, and an AI result advised saves - perhaps stupidly.
But race conditions are sporadic by nature, threads may happen on either
side of the Python/Java fence, and the new Splitter max_size update on insets
callbacks could conceivably aggravate a looming threat. Hence, this queue
is used as a just-in-case safety measure. It's harmless and trivial if it's
unnecessary, but vanishing apps are a Bad Thing.
Update: it's now nearly certain that the crashes this module addresses were
due to unrelated errors or inadvertent Back taps during screen changes, not
garbage collection. A later app vanish yielded a normal exit for Back tap
in the logcat. Another 1.5 mod now pauses the app on Android Back instead
of closing it, so the app will be suspended in Recents if (when) this recurs.
------------------------------------------------------------------------------
"""
def __init__(self, numsouls=6):
self.holding = [0] * numsouls
def retain(self, object, trace=False):
self.holding.pop(0) # may garbage collect now
self.holding.append(object) # stage next soul in queue
if trace:
print(f'Purgatory: {self.holding}')
if __name__ == '__main__':
retainer = Purgatory()
for object in 'Race Condition!':
retainer.retain(object, True)