Status Update
Comments
ap...@google.com <ap...@google.com> #2
Branch: androidx-main
commit 2db6d01af84b5752190c6dd28cdea12500b701cb
Author: Charcoal Chen <charcoalchen@google.com>
Date: Fri Dec 23 10:15:10 2022
Fix JPEG image corruption issue if writing Exif location data on some Samsung Android 12 devices
This issue can be avoided in CameraX side by skipping the unnecessary Exif data copy. But there should still be some unknown reason in ExifInterface or these problematic devices to cause the issue.
Relnote: "Fixed JPEG image corruption issue if writing Exif location data on some Samsung Android 12 devices."
Bug: 263289024
Test: ImageCaptureTest
Change-Id: Ib70862aa6e654f06b9358e3f92bbb98c86cb9caf
M camera/camera-core/src/main/java/androidx/camera/core/impl/utils/Exif.java
M camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageCaptureTest.kt
ap...@google.com <ap...@google.com> #3
Thanks for reporting, i can use the example app to reproduce the problem. I saved the corrupted file and pulled it off the device and ran it through exiftool
, which complained (it doesn't complain as loudly about the source file, just some technically out-of-order tags):
$ exiftool -v2 editedFile.jpg
ExifToolVersion = 12.52
FileName = editedFile.jpg
Directory = .
FileSize = 433785
FileModifyDate = 1678109782
FileAccessDate = 1678109782
FileInodeChangeDate = 1678109782
FilePermissions = 33184
FileType = JPEG
FileTypeExtension = JPG
MIMEType = image/jpeg
Warning = [minor] Skipped unknown 617 bytes after JPEG APP1 segment
JPEG APP1 (46 bytes):
ExifByteOrder = II
Warning = Short directory size for IFD0 (missing 150 bytes)
| Warning = Bad IFD0 directory
Warning = [minor] Skipped unknown 917 bytes after JPEG NULL segment
JPEG SOI
JPEG APP0 (14 bytes):
+ [BinaryData directory, 9 bytes]
| JFIFVersion = 1 1
| - Tag 0x0000 (2 bytes, int8u[2])
| ResolutionUnit = 0
| - Tag 0x0002 (1 bytes, int8u[1])
| XResolution = 1
| - Tag 0x0003 (2 bytes, int16u[1])
| YResolution = 1
| - Tag 0x0005 (2 bytes, int16u[1])
| ThumbnailWidth = 0
| - Tag 0x0007 (1 bytes, int8u[1])
| ThumbnailHeight = 0
| - Tag 0x0008 (1 bytes, int8u[1])
JPEG DQT (65 bytes):
JPEG DQT (65 bytes):
JPEG SOF0 (15 bytes):
ImageWidth = 512
ImageHeight = 384
EncodingProcess = 0
BitsPerSample = 8
ColorComponents = 3
YCbCrSubSampling = 2 1
JPEG DHT (29 bytes):
JPEG DHT (179 bytes):
JPEG DHT (29 bytes):
JPEG DHT (179 bytes):
JPEG SOS
ap...@google.com <ap...@google.com> #4
The size of the JPEG APP1
segment looks wrong in the edited file (from exiftool
):
JPEG APP1 (46 bytes):
Compared to the original file:
JPEG APP1 (65279 bytes):
In binary this difference is visible in the 5th/6th byte of each file (from hexdump -C
). The first 4 bytes are a JPEG marker (0xFF
), a JPEG SOI (start of image, 0xd8
), another marker and an APP1 (0xe1
), followed by 2 bytes indicating the size of the APP1 segment.
Edited image:
ff d8 ff e1 00 30
Original image:
ff d8 ff e1 ff 01
Looking into why ExifInterface
is writing out the wrong APP1 size, I turned on
$ adb shell setprop log.tag.ExifInterface VERBOSE
And now it becomes a bit more obvious (this logging is from
saveJpegAttributes starting with (inputStream: java.io.BufferedInputStream@4fba9e8, outputStream: java.io.BufferedOutputStream@e5c3801)
index: 0, offsets: 8, tag count: 15, data sizes: 81, total size: 65584
65584
(0x10030
) is greater than the max 16-bit unsigned value (2^16 = 65536
), so when we ByteOrderedDataOutputStream.writeUnsignedShort
writeShort((short) val)
) truncates to the lower two bytes (0x0030
) - and this gets written out to the file and then breaks everything.
I think this likely only affects files that are very close to the 2^16
threshold, and the act of 'copying' all the EXIF attributes over probably reformats some of them just enough to take up slightly more bytes.
I'm not sure what is supposed to happen when a JPEG APP1 segment gets larger than 2^16
bytes, I need to dig a bit further into that part.
ap...@google.com <ap...@google.com> #5
Actually thinking about it more, it's not obvious to me why the APP1
segment of the original image is so large either - looking in exiftool
it doesn't seem to contain any particularly enormous fields, so I can't really see where 65kB comes from.
ap...@google.com <ap...@google.com> #6
re APP1
segment is so large, I missed the thumbnail the first time, which takes up a significant chunk (64kB):
+ [IFD1 directory with 15 entries]
| 0) ImageHeight = 384
| - Tag 0x0101 (4 bytes, int32u[1]):
| 0323: 80 01 00 00 [....]
| 1) Orientation = 6
| - Tag 0x0112 (2 bytes, int16u[1]):
| 032f: 06 00 [..]
| Warning = Tag ID 0x0103 Compression out of sequence in IFD1
| 2) Compression = 6
| - Tag 0x0103 (2 bytes, int16u[1]):
| 033b: 06 00 [..]
| 3) ThumbnailOffset = 1273
| - Tag 0x0201 (4 bytes, int32u[1]):
| 0347: f9 04 00 00 [....]
| 4) ThumbnailLength = 64000
| - Tag 0x0202 (4 bytes, int32u[1]):
| 0353: 00 fa 00 00 [....]
| Warning = Tag ID 0x010f Make out of sequence in IFD1
ap...@google.com <ap...@google.com> #7
APP1
:
Exif metadata are restricted in size to 64 kB in JPEG images because according to the specification this information must be contained within a single JPEG APP1 segment.
Charcoal: Do you know if CameraX is deciding how large to make the thumbnail in this case, or is this happening lower down in the device? Taking up 64,000 bytes doesn't leave much space for the rest of the Exif data.
Related thread I found (also complaining about a Samsung device, but from 2013...):
I experimented to see what exiftool
does now when the APP1
segment gets too large, and it looks like they just add a second APP1
segment and call it 'multi-segment EXIF` (I have no idea how well supported this is):
$ exiftool -UserComment="abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" b-263747161_original.jpg
Warning: [minor] File contains multi-segment EXIF - b-263747161_original.jpg
1 image files updated
$ exiftool -v3 b-263747161_original.jpg
ExifToolVersion = 12.52
FileName = b-263747161_original.jpg
Directory = .
FileSize = 434075
FileModifyDate = 1678121141
FileAccessDate = 1678121141
FileInodeChangeDate = 1678121141
FilePermissions = 33184
FileType = JPEG
FileTypeExtension = JPG
MIMEType = image/jpeg
JPEG APP1 (65533 bytes):
0006: 45 78 69 66 00 00 49 49 2a 00 08 00 00 00 0d 00 [Exif..II*.......]
0016: 00 01 04 00 01 00 00 00 a0 05 00 00 01 01 04 00 [................]
0026: 01 00 00 00 38 04 00 00 0e 01 02 00 01 00 00 00 [....8...........]
0036: 00 00 00 00 0f 01 02 00 08 00 00 00 aa 00 00 00 [................]
0046: 10 01 02 00 09 00 00 00 b2 00 00 00 12 01 03 00 [................]
0056: 01 00 00 00 06 00 00 00 1a 01 05 00 01 00 00 00 [................]
0066: bc 00 00 00 1b 01 05 00 01 00 00 00 c4 00 00 00 [................]
[snip 65421 bytes]
Warning = [minor] File contains multi-segment EXIF
JPEG APP1 (71 bytes):
10007: 45 78 69 66 00 00 00 00 00 00 00 00 00 00 00 00 [Exif............]
10017: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................]
10027: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................]
10037: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................]
10047: 00 00 00 00 00 00 00 [.......]
ExifByteOrder = II
Obviously the current ExifInterface
behaviour is very problematic (corrupting the image completely), but I'm not actually sure the best way to improve it. Some options I came up with:
- If the size of the
APP1
segment is larger than2^16
then just write the first2^16
bytes and hope. - Implement the same 'split segment' support that
exiftool
has. - Add logic to
ExifInterface
to resize a thumbnail to free up space in theAPP1
segment if it runs out (this seems too magical and could be very confusing for users). - Refuse to save a file in
ExifInterface.saveAttributes
if it results inAPP1
being larger than2^16
, either by silently not writing out (confusing) or throwing an exception (disruptive). - Add prioritisation of Exif tags, so when we run out of space we drop tags lowest-priority-first (very unlikely we can predict the 'correct' prioritisation such that users aren't annoyed/confused by the tags we decide to drop).
ap...@google.com <ap...@google.com> #8
Hi Ian,
Thanks for looking into the issue and provide the detailed analysis result.
About the question: Charcoal: Do you know if CameraX is deciding how large to make the thumbnail in this case, or is this happening lower down in the device? Taking up 64,000 bytes doesn't leave much space for the rest of the Exif data.
CameraX doesn't specify any thumbnail related capture request settings (
I'm curious about why this issue only happens when setting a FUSED location data but does not happen when setting a GPS location data? Does the FUSED location data in Exif actually occupy a little bit more size than GPS location data? So it causes the different result?
ap...@google.com <ap...@google.com> #9
I'm curious about why this issue only happens when setting a FUSED location data but does not happen when setting a GPS location data? Does the FUSED location data in Exif actually occupy a little bit more size than GPS location data? So it causes the different result?
Good question - I actually only got as far as playing with the image provided inside MyApplication-ExifLocationIssue.zip
, I didn't look at CameraXBasic-WriteFusedLocation.zip
, and as you noted in
ap...@google.com <ap...@google.com> #10
I've decided to go with option 4 from saveAttributes
in order to avoid creating a corrupted image. I've filed a new issue to track the possibility of adding multi-segment support in the future:
ap...@google.com <ap...@google.com> #11
Branch: androidx-main
commit c6bbc03f39f811ac546882880be46380cb31f5d5
Author: Ian Baker <ibaker@google.com>
Date: Tue Mar 07 11:09:08 2023
Throw an exception if trying to write a JPEG APP1 segment that's too large
jpeg_with_full_app_segment.jpg is an image taken with a Samsung A32
with a nearly-full APP1 segment due to a 64,000 byte thumbnail:
$ exiftool -v3 jpeg_with_exif_full_app1_segment.jpg
<snip>
JPEG APP1 (65072 bytes):
<snip>
| 5) ThumbnailLength = 64000
Bug: 263747161
Test: ./gradlew :exifinterface:exifinterface:connectedAndroidTest
Change-Id: Id421cd36d974ad4f29a2c6d6c730d99d8986d917
M exifinterface/exifinterface/build.gradle
M exifinterface/exifinterface/src/androidTest/java/androidx/exifinterface/media/ExifInterfaceTest.java
A exifinterface/exifinterface/src/androidTest/res/raw/jpeg_with_exif_full_app1_segment.jpg
M exifinterface/exifinterface/src/main/java/androidx/exifinterface/media/ExifInterface.java
ap...@google.com <ap...@google.com> #12
Are you sure it's an issue with the APP1 segment being too large with the FUSED location? I was thinking perhaps there's some issue with the length calculation that's happening as we were able to fix these images by just detecting the start of the jpeg image data and re-writing the length field based on that detection.
ap...@google.com <ap...@google.com> #13
Are you sure it's an issue with the APP1 segment being too large with the FUSED location? I was thinking perhaps there's some issue with the length calculation that's happening as we were able to fix these images by just detecting the start of the jpeg image data and re-writing the length field based on that detection.
This fix is consistent with the current failure mode of ExifInterface
when the APP1
segment gets 'too large' (before my change linked above in 0x10030
bytes to write to the APP1 segment, and ExifInterface
does two things:
- When writing the length of the APP1 segment it truncates this to
0x0030
- It writes all those
0x10030
bytes out, and then it writes the rest of the image.
A JPEG parser (I assume) comes along and reads the length of the APP1
segment (0x30
) and skips that many bytes, then expects to find JPEG data - but it's actually in the middle of the Exif and so it fails.
If you manually find the start of the JPEG data then you obviate both of the problems - and the image is 'fixed'.
vi...@google.com <vi...@google.com> #14
The following release(s) address this bug.It is possible this bug has only been partially addressed:
androidx.exifinterface:exifinterface:1.3.7
ap...@google.com <ap...@google.com> #15
The following release(s) address this bug.It is possible this bug has only been partially addressed:
androidx.exifinterface:exifinterface:1.4.0-alpha01
ap...@google.com <ap...@google.com> #16
Branch: androidx-master-dev
commit 3ca3fd13d021730e09e8dc1dc622ab753abcbd9d
Author: Ian Lake <ilake@google.com>
Date: Fri Oct 11 09:28:58 2019
Move loadAnimation out of FragmentManager
Test: all tests still pass
BUG: 139536619
Change-Id: I7e5549c825f69e38ab02a38e8067c594c908d154
A fragment/fragment/src/main/java/androidx/fragment/app/FragmentAnim.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
vi...@google.com <vi...@google.com> #17
ap...@google.com <ap...@google.com> #18
Branch: androidx-master-dev
commit c06fb9f4d3334701bc1de8ee85c7a4e6149addcf
Author: Ian Lake <ilake@google.com>
Date: Mon Nov 11 10:32:31 2019
Move <fragment> tag state handling to FragmentStateManager
Move the logic for handling <fragment> tag added
Fragments that are not in the layout to
FragmentStateManager's computeMaxState() with the
other state logic.
Test: newly added FragmentLifecycleTest
BUG: 139536619
Change-Id: Ieaabdac16786418f89279a17bbe5661e12c11290
M fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentLifecycleTest.kt
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
ap...@google.com <ap...@google.com> #19
Branch: androidx-master-dev
commit ac963796fb52c1556be07a9dae91ee4034f20715
Author: Ian Lake <ilake@google.com>
Date: Mon Nov 11 11:03:15 2019
Move initState() call into FragmentStateManager
Instead of doing this work in moveToState(), it
can be moved into FragmentStateManager since it
only depends on the Fragment's internal state.
Test: all existing Fragment tests pass
BUG: 139536619
Change-Id: I100be37c69f3d9274db308a44bfb4c8df09a3062
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
ap...@google.com <ap...@google.com> #20
Branch: androidx-master-dev
commit fd68f92de244735a6b6eccb73474d952d287b0d3
Author: Ian Lake <ilake@google.com>
Date: Tue Nov 19 16:01:35 2019
Move active and added fragments to FragmentStore
Instead of FragmentManager directly storing and
managing the set of active and added fragments, move
that functionality to a separately testable
FragmentStore object.
This will make it possible to have FragmentStateManager
access other FragmentStateManagers without directly
knowing about FragmentManager.
Test: new FragmentStore tests, all existing tests pass
BUG: 139536619
Change-Id: I69cefc8b2422f809e1498c5c9e4b09edd9026840
A fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentStoreTest.kt
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
A fragment/fragment/src/main/java/androidx/fragment/app/FragmentStore.java
an...@google.com <an...@google.com> #21
ap...@google.com <ap...@google.com> #22
Branch: androidx-master-dev
commit 9268d14672abfd46bbcb9563fb87e7ff3cfd1c58
Author: Ian Lake <ilake@google.com>
Date: Wed Nov 20 13:09:00 2019
Remove usages of mocks in FragmentStoreTest
Instead of using mock Views, construct a
real View instance to avoid Mockito spin up
time.
Test: test still passes
BUG: 139536619
Change-Id: I27831f134f5aa7a1ff4474c64b0f9f35dd51eeb3
M fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentStoreTest.kt
ap...@google.com <ap...@google.com> #23
Branch: androidx-master-dev
commit a2070a6b604f845c8bde4319a378bc3ece401eb8
Author: Ian Lake <ilake@google.com>
Date: Fri Nov 22 13:12:08 2019
Remove FragmentManager dependency from FragmentTransition
Rather than passing in the FragmentManager itself
directly into FragmentTransition.startTransitions(),
pass in only the objects we need (a Context and
a FragmentContainer).
This allow further decoupling of the transitions
from FragmentManager itself.
Test: all existing tests pass
BUG: 139536619
Change-Id: I06b2c6ca6ef2b7d5a8566fc75194169a686aef13
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentTransition.java
il...@google.com <il...@google.com>
ap...@google.com <ap...@google.com> #24
Branch: androidx-master-dev
commit 4a2e625f3a6887a737081bce3abd58f975c6f2f0
Author: Ian Lake <ilake@google.com>
Date: Mon Dec 02 13:33:22 2019
Dispatch manager state changes to FragmentStateManagers
Instead of assuming that a FragmentStateManager
can go up to RESUMED by default, dispatch the
FragmentManager's state changes to each
FragmentStateManager and use that to set
the maximum state of the FragmentStateManager.
The one exception is when using the <fragment>
tag, which allows Fragments to move to CREATED
before the FragmentManager itself moves to
CREATED.
Test: new tests pass, all existing tests pass
BUG: 139536619
Change-Id: I748bb0afc8ffe956dcd6fa695437a0a0d54e8762
M fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentStateManagerTest.kt
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentStore.java
ap...@google.com <ap...@google.com> #25
Branch: androidx-master-dev
commit a4659c8f26bed57802cc7ee75c575c9c3cc90ebf
Author: Ian Lake <ilake@google.com>
Date: Wed Dec 04 13:58:22 2019
Make mHost and mContainer private
The internal state of FragmentManager should
not be directly accessed. Create package
private setters for the cases where they are
absolutely required.
Test: Fragment compiles
BUG: 139536619
Change-Id: I02ac9ca55899423544e597421c498707e33c71f1
M fragment/fragment/src/main/java/androidx/fragment/app/BackStackRecord.java
M fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentLayoutInflaterFactory.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentTransition.java
ap...@google.com <ap...@google.com> #26
Branch: androidx-master-dev
commit 12b33f91aa82443896194bc59c5051453f2aa7ad
Author: Ian Lake <ilake@google.com>
Date: Wed Dec 04 14:23:19 2019
Retrieve lifecycle parameters from FragmentManager
Instead of being explicitly passed parameters for
attach, createView, etc., retrieve them from
the FragmentManager already set on the Fragment.
Test: all existing tests pass
BUG: 139536619
Change-Id: If011688280a3c6736374b5d6e9def6d1da6f7066
M fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentLifecycleCallbacksDispatcher.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
ap...@google.com <ap...@google.com> #27
Branch: androidx-master-dev
commit 62de6890627e3d81dbc89509960149243cb44811
Author: Ian Lake <ilake@google.com>
Date: Wed Dec 04 15:17:40 2019
Remove FragmentContainer from loadAnimation
The mContainer is already set on the Fragment
by the time loadAnimation is called, so we
can use that rather than getting the container
from FragmentContainer.
Test: all existing tests pass
BUG: 139536619
Change-Id: If7e1bce5bdd0a7c7a3ddb6e495866835f7265bb6
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentAnim.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
ap...@google.com <ap...@google.com> #28
Branch: androidx-master-dev
commit 0454ddec1befa0ace1242700bf00f85e0aee5ad3
Author: Ian Lake <ilake@google.com>
Date: Thu Dec 05 11:19:01 2019
Explicitly pass nonConfig to FragmentStateManager
Instead of passing in the FragmentManagerViewModel
into specific lifecycle methods, explicitly pass
it into the constructor.
Test: all existing tests pass
BUG: 139536619
Change-Id: I020b1b0f446c76217e2bdb95731457f03b14c2c3
M fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentStateManagerTest.kt
M fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentStoreTest.kt
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
ap...@google.com <ap...@google.com> #29
Branch: androidx-master-dev
commit d10ec06d7f998e1ab74ad3fbee6f5168f29f528f
Author: Ian Lake <ilake@google.com>
Date: Thu Dec 05 16:06:43 2019
Move add/removeRetainedFragment logic to non config
Instead of splitting the logic of
add/removeRetainedFragment between FragmentManager
and FragmentManagerViewModel (the non config),
move it all to non config.
This requires forwarding signals on whether the
state is saved to FragmentManagerViewModel so
that it can properly ignore changes after the
state is saved.
Test: newly added tests pass
BUG: 139536619
Change-Id: I5301c02534d0da4c9b5a57efc96d4b7b6382b9b4
M fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentManagerViewModelTest.kt
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentManagerViewModel.java
ap...@google.com <ap...@google.com> #30
Branch: androidx-master-dev
commit 792f47b59c1c6bbc017757d202a5c24caade98fe
Author: Ian Lake <ilake@google.com>
Date: Fri Dec 06 13:52:18 2019
Move makeActive/Inactive entirely to FragmentStore
Instead of splitting makeActive and makeInactive's
functionality between FragmentManager and
FragmentStore, move all of the logic to
FragmentStore.
Test: new FragmentStore tests, existing tests pass
BUG: 139536619
Change-Id: I5769273fe402a254b9437ced05cd3943cbd88e70
M fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentStoreTest.kt
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentStore.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentTransition.java
ap...@google.com <ap...@google.com> #31
Branch: androidx-master-dev
commit 1e2d4c45ef615d979aebf525dc22bc1350d96ead
Author: Ian Lake <ilake@google.com>
Date: Mon Dec 09 12:27:42 2019
Move remaining attach logic to FragmentStateManager
Use FragmentStateManager's access to FragmentStore
and its moveToExpectedState() to move all of the
logic for moving to the attached state to
FragmentStateManager.
Test: existing tests pass
BUG: 139536619
Change-Id: Icd63b447febcb4b1b4fae07aa7fa2a68d79730be
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
ap...@google.com <ap...@google.com> #32
Branch: androidx-master-dev
commit 57f2f664df270547e97ea806067683581c52b6d4
Author: Ian Lake <ilake@google.com>
Date: Mon Dec 09 10:20:34 2019
First draft of FragmentStateManager moveToExpectedState()
Allow components to work directly with
FragmentStateManager when moving a Fragment to its
expected state instead of going through
FragmentManager's moveToState().
This is currently only used for the case for
restoreRetainedInstanceFragmentWithTransparentActivityConfigChange
which does not rely on any of the TODOs listed in
moveToExpectedState().
Test: new tests pass
BUG: 139536619
Change-Id: Ibb1d51ea70cc00b5ff21936c74b565447391c0a4
M fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentStateManagerTest.kt
M fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentStoreTest.kt
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
ap...@google.com <ap...@google.com> #33
Branch: androidx-master-dev
commit 07cc34f9a88067c26634a575587cfe55132360c4
Author: Ian Lake <ilake@google.com>
Date: Wed Dec 11 11:06:26 2019
Use FragmentStateManager for <fragment> tag
Use FragmentStateManager's moveToExpectedState
for the <fragment> tag instead of relying on
FragmentManager's moveToState.
Test: existing tests pass
BUG: 139536619
Change-Id: I77778b3d7e634a4ea7c9d228819a9f2936e347f1
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentLayoutInflaterFactory.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
ap...@google.com <ap...@google.com> #34
Branch: androidx-master-dev
commit 3eb8650f005697c8a036605bf5170b9d8177b761
Author: Ian Lake <ilake@google.com>
Date: Thu Dec 12 13:48:29 2019
Remove getStateAfterAnimating()
FragmentStateManager already knows what the
correct state should be so we don't need to
track it separately with setStateAfterAnimating()
and getStateAfterAnimating().
Test: all existing tests pass
BUG: 139536619
Change-Id: I5d48edbf47aca4f57fda0553cf767dfbfc21d642
M fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
ap...@google.com <ap...@google.com> #35
Branch: androidx-master-dev
commit fb4893d9baba2f759a3ebba61f228a48e11fd72c
Author: Ian Lake <ilake@google.com>
Date: Thu Dec 12 14:08:08 2019
Simplify moveToState logic for FragmentTransition
FragmentTransition's moveToState() logic only
applies to newly added Fragments, so we can simplify
the logic used to rely on computeExpectedState().
Test: existing tests pass
BUG: 139536619
Change-Id: I1568791a7aaa3a8a3dfb14a75fa121a32884e443
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentTransition.java
an...@google.com <an...@google.com> #36
Release Track: (
Created: 2019-12-18 21:08:39.436017+00:00
Changes: aosp/1178750, aosp/1171290, aosp/1170093
ap...@google.com <ap...@google.com> #37
Branch: androidx-master-dev
commit 3e885783ef9bf3d7717cc55ae4ccf857d74965f8
Author: Ian Lake <ilake@google.com>
Date: Tue Feb 18 15:29:20 2020
Handle re-entrant calls to moveToExpectedState()
As moveToExpectedState() runs user code that can
potentially change the external state, it is possible
for re-entrant calls to moveToExpectedState() to
happen. In this case, we can ignore the re-entrant
call, knowing that after the current state transition
completes FragmentStateManager will call
computeExpectedState() after each transition and pick
up the updated state.
Test: this isn't technically possible yet, but it will be
BUG: 139536619
Change-Id: I500e6f0e78d20355ab21a1f21fc66067f72e46a9
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
ap...@google.com <ap...@google.com> #38
Branch: androidx-master-dev
commit 4d3bac24c5a77c5ab5624795afa709b3f265bf74
Author: Ian Lake <ilake@google.com>
Date: Tue Feb 25 15:47:06 2020
Add infrastructure to fully switch to FragmentStateManager
Add the initial logic to fully replace all usages of
moveToState() with FragmentStateManager and its
moveToExpectedState().
Enabling this flag currently causes many tests to fail
(due to work not being completed on
this infrastructure will allow us to confirm our fixes
are actually applied while iterating through those
outstanding issues.
Test: tests all pass with USE_STATE_MANAGER = false
BUG: 139536619
Change-Id: I84340091ce1b0bcc3e26051e25a12d7b38b860c4
M fragment/fragment/src/main/java/androidx/fragment/app/BackStackRecord.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentStore.java
ap...@google.com <ap...@google.com> #39
Branch: androidx-master-dev
commit b58d84209a566d60dbec35670fd3d977adcea1cf
Author: Ian Lake <ilake@google.com>
Date: Wed Feb 26 16:11:21 2020
Stop using findFragmentManager in SpecialEffectsController
Instead of relying on findFragmentManager() in
SpecialEffectsController, pass the FragmentManager
in directly. This works around issues where developers
nest fragments without using the childFragmentManager.
findFragmentManager() now correctly throws in those
cases.
Test: new tests pass
Test: SpecialEffectsController tests pass with USE_STATE_MANAGER = true
BUG: 139536619
Change-Id: I7de94fa6275fe8a5e67736194d7fc099539dd395
M fragment/fragment/src/androidTest/java/androidx/fragment/app/DefaultSpecialEffectsControllerTest.kt
A fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentManagerTest.kt
M fragment/fragment/src/androidTest/java/androidx/fragment/app/SpecialEffectsControllerTest.kt
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/SpecialEffectsController.java
ap...@google.com <ap...@google.com> #40
Branch: androidx-master-dev
commit c643f98908f3d5ee5f48b37e3edcc113a16a6bbc
Author: Ian Lake <ilake@google.com>
Date: Mon Mar 02 09:54:45 2020
Move makeInactive() out of moveToState()
Instead of calling makeInactive() as part
of moveToState() / moveToExpectedState(),
run that logic *after* the state settles.
Updating the target fragments correctly can
then be moved solely to FragmentStateManager's
destroy(), ensure it runs at the right time.
Special care had to be made when restoring
retained fragments that aren't in mActive so
that they are manually removed from the mNonConfig
(as before that would have been take care of
by moveToExpectedState()).
Test: all existing tests pass
BUG: 139536619
Change-Id: Ie33e01622f5edf212822f9c75f60c532a352a2d1
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentStore.java
fi...@google.com <fi...@google.com> #41
il...@google.com <il...@google.com> #42
Re #41 - as soon as the
fi...@google.com <fi...@google.com> #43
Is this fixed?
Thanks,
Fiona
il...@google.com <il...@google.com> #44
See
ap...@google.com <ap...@google.com> #45
Branch: androidx-master-dev
commit a719fba6b63d6081e7b69de1a70e2d1e81bf52bf
Author: Ian Lake <ilake@google.com>
Date: Fri Jul 17 15:06:39 2020
Add experimental API for enabling FragmentStateManager
Provide an experimental API for controlling whether
the FragmentStateManager and new special effects system
should be enabled.
Currently this new system defaults to off, but will
be changed to true by default once all internal tests
pass. This API will then exist only to verify that
a regression is due to the new code path.
Test: tested in a sample app
BUG: 147749580
BUG: 139536619
Relnote: "Added a new *experimental* API for controlling
whether FragmentManager uses the new internal state
manager for controlling dispatching lifecycle methods,
animations and transitions, and handling postponed
transactions."
Change-Id: I7b6ee13ea89f3989beafe7c474455e8a04e929a3
M fragment/fragment/api/public_plus_experimental_1.3.0-alpha07.txt
M fragment/fragment/api/public_plus_experimental_current.txt
M fragment/fragment/build.gradle
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
A fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManagerControl.java
ap...@google.com <ap...@google.com> #46
Branch: androidx-master-dev
commit c4e66e2a8b86db77158d21527b6eceb27290097b
Author: Ian Lake <ilake@google.com>
Date: Fri Jul 31 22:43:47 2020
Change reordering parameter from boolean to sealed class
Instead of using a boolean reorderingAllowed
parameter that only shows as 0 or 1 in test naming,
convert it to using a sealed class that makes it
more clear which type of ordering is being used.
Test: tests still pass
BUG: 139536619
Change-Id: I3e7f433d20b13f7bb5882b85d67a0c8267fd4da4
M fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentTestUtil.kt
M fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentTransitionAnimTest.kt
M fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentTransitionTest.kt
M transition/transition/src/androidTest/java/androidx/transition/FragmentTestUtil.kt
M transition/transition/src/androidTest/java/androidx/transition/FragmentTransitionTest.kt
ap...@google.com <ap...@google.com> #47
Branch: androidx-master-dev
commit 67ea65bcb2190d8be41e8896ab7b2fbd67c6f56b
Author: Ian Lake <ilake@google.com>
Date: Sun Aug 02 11:33:37 2020
Parameterize tests to use both old and new state manager
Parameterize a number of test suites affected
by the usage of FragmentStateManager so that they
run both under the old state manager and the new
system to avoid regressions during the cross over
time period.
Changed the focusedView() test to not run on the
UI thread, fixing flaky issues when running as part
of a parameterized test suite.
Changed the testTimedPostponeEnterPostponedCalledWithZero()
test to wait for the transition to finish before
finishing the test, ensuring that you don't
enable/disable the state manager while a
transition is running.
Test: tests pass
BUG: 139536619
Change-Id: I1e7bd6f5b135345a9a60c95fe5127b00ff3e69df
M fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentReorderingTest.kt
M fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentTestUtil.kt
M fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentTransitionAnimTest.kt
M fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentTransitionTest.kt
M fragment/fragment/src/androidTest/java/androidx/fragment/app/PostponedTransitionTest.kt
ap...@google.com <ap...@google.com> #48
Branch: androidx-master-dev
commit c8263b1e1289276da1b691ac05b7a1808931101c
Author: Ian Lake <ilake@google.com>
Date: Sun Aug 02 11:51:07 2020
Mirror changes in FragmentTransitionTest to transition
Update the FragmentTransitionTest suite in the
transition module to match the updated code in the
fragment module, ensuring that the tests are
parameterized to run with both the old state manager
and the new state manager.
Test: tests still pass
BUG: 139536619
Change-Id: I8c8afac8e384e1f93a44b7d7e940de374c0b8494
M transition/transition/src/androidTest/java/androidx/transition/FragmentTestUtil.kt
M transition/transition/src/androidTest/java/androidx/transition/FragmentTransitionTest.kt
ap...@google.com <ap...@google.com> #49
Branch: androidx-master-dev
commit 8c6081e883569b5620f03d5d89648bf9b38289a9
Author: Ian Lake <ilake@google.com>
Date: Sun Aug 02 12:11:43 2020
Enable the new state manager by default
Add a note to FragmentManager.enableNewStateManager()
noting that the new state manager is enabled by default
and providing a link to the issue tracker to ensure
that developers know where to file any possible
regressions with the new state manager.
Test: all existing tests still pass
BUG: 139536619
Change-Id: I80d275cad0a2e0f4cc15c34820f63c71720e3f56
M fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentTestUtil.kt
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
M transition/transition/src/androidTest/java/androidx/transition/FragmentTestUtil.kt
il...@google.com <il...@google.com> #50
All the work has completed with this effective complete rewrite of the internals of FragmentManager and how it handles animations and transitions. The new state manager is enabled by default for the Fragment 1.3.0-alpha08 release.
You can verify this by following the 6732061
and switching your fragment dependency to 1.3.0-SNAPSHOT
.
We've filed FragmentManager.enableNewStateManager()
experimental API. Please file any regressions found with the new system as soon as possible.
sa...@gmail.com <sa...@gmail.com> #51
This seems to work (the returnTransition
) with the new state manager
Description
This would allow us to very explicitly test all of the state transitions a Fragment goes through and would make it a lot easier to make further improvements / changes to those state transitions in a sustainable way.
This should have no effect to consumers of the Fragment API as it would all be internal work.