Skip to content

Deps update and QA fixes - #665

Open
RankoR wants to merge 51 commits into
GrapheneOS:mainfrom
RankoR-GOS:deps-update-and-qa-fixes
Open

Deps update and QA fixes#665
RankoR wants to merge 51 commits into
GrapheneOS:mainfrom
RankoR-GOS:deps-update-and-qa-fixes

Conversation

@RankoR

@RankoR RankoR commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

No description provided.

RankoR added 30 commits July 22, 2026 10:39
androidx.media3:media3-common declares ACCESS_NETWORK_STATE for ExoPlayer's
network playback. We only pull media3 in transitively through camera-video,
which uses media3-muxer to write MP4s locally, so nothing we ship reads it and
the app has no INTERNET permission to pair it with. Remove it from the merged
manifest with tools:node="remove".
RankoR added 20 commits July 26, 2026 17:22
@RankoR
RankoR marked this pull request as ready for review July 26, 2026 23:03
@RankoR
RankoR requested a review from inthewaves July 26, 2026 23:03
Comment thread gradle/libs.versions.toml
@@ -0,0 +1,51 @@
[versions]
agp = "9.3.1"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Crashes when building with JDK 17 because List.removeLast is added in JDK 21, should probably make the JDK 21 requirement explicit e.g. in gradle/gradle-daemon-jvm.properties

Unexpected failure during lint analysis (this is a bug in lint or one of the libraries it depends on)

Message: Unexpected failure during lint analysis (this is a bug in lint or one of the libraries it depends on)

Message: Unexpected failure during lint analysis of ExifHelper.kt (this is a bug in lint or one of the libraries it depends on)

Message: 'java.lang.Object java.util.List.removeLast()'
Stack: \\\`NoSuchMethodError:JavaDocParser.parseDataItem(JavaDocParser.kt:117)?JavaDocParser.parseDocCommentText(JavaDocParser.kt:66)?JavaDocElementType$DocCommentElementType.lambda$new$0(JavaDocElementType.java:167)?JavaParserUtil.lambda$parseFragment$9(JavaParserUtil.java:409)?ParsingUtil.parseFragment(ParsingUtil.kt:18)?JavaParserUtil.parseFragment(JavaParserUtil.java:408)?JavaParserUtil.parseFragmentWithHighestLanguageLevel(JavaParserUtil.java:379)?JavaDocElementType$DocCommentElementType.parseContents(JavaDocElementType.java:172)?LazyParseableElement.lambda$ensureParsed$2(LazyParseableElement.java:183)?DebugUtil.performPsiModification(DebugUtil.java:589)?LazyParseableElement.ensureParsed(LazyParseableElement.java:182)?LazyParseableElement.getFirstChildNode(LazyParseableElement.java:234)?PsiDocCommentImpl.findTagByName(PsiDocCommentImpl.java:86)?PsiImplUtil.isDeprecatedByDocTag(PsiImplUtil.java:614)?JavaStubImplUtil.isMemberDeprecated(JavaStubImplUtil.java:40)?PsiClassImpl.isDeprecated(PsiClassImpl.java:420)?JavaClassifierImpl.isDeprecatedInJavaDoc(JavaClassifierImpl.java:65)?FirLazyJavaAnnotationList.lazyFirAnnotations$lambda$0(FirJavaAnnotationList.kt:48)?SafePublicationLazyImpl.getValue(LazyJVM.kt:125)?FirLazyJavaAnnotationList.getFirAnnotations(FirJavaAnnotationList.kt:52)?FirLazyJavaAnnotationList.iterator(FirJavaAnnotationList.kt:61)?DeprecationUtilsKt.extractDeprecationAnnotationInfoPerUseSite(deprecationUtils.kt:534)?DeprecationUtilsKt.extractDeprecationInfoPerUseSite(deprecationUtils.kt:127)?DeprecationUtilsKt.extractDeprecationInfoPerUseSite$default(deprecationUtils.kt:114)?DeprecationUtilsKt.getDeprecationsProvider(deprecationUtils.kt:111)?FirJavaClass.deprecationsProvider_delegate$lambda$0(FirJavaClass.kt:152)?SynchronizedLazyImpl.getValue(LazyJVM.kt:86)?FirJavaClass.getDeprecationsProvider(FirJavaClass.kt:151)?FirClassLikeSymbol.getOwnDeprecation(FirClassLikeSymbol.kt:45)?DeprecationUtilsKt.getOwnDeprecationForCallSite(deprecationUtils.kt:197)?DeprecationUtilsKt.getDeprecationForCallSite(deprecationUtils.kt:214)?DeprecationUtilsKt.getDeprecation(deprecationUtils.kt:107)?CheckHiddenDeclaration.isDeprecatedHidden(ResolutionStages.kt:974)?CheckHiddenDeclaration.check(ResolutionStages.kt:958)?ResolutionStageRunner$processCandidate$1.invokeSuspend(ResolutionStageRunner.kt:35)?BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)?ResolutionStageRunner.processCandidate(ResolutionStageRunner.kt:49)?ResolutionStageRunner.processCandidate$default(ResolutionStageRunner.kt:20)?CandidateCollector.consumeCandidate(CandidateCollector.kt:48)?TowerLevelProcessor.consumeCandidate(TowerLevelHandler.kt:90)?TowerLevelProcessor.consumeCandidate$default(TowerLevelHandler.kt:82)?ScopeBasedTowerLevel.processObjectsByName$lambda$0(TowerLevels.kt:492)?ScopeBasedTowerLevel$processObjectsByName$$inlined$processClassifiersByName$1.invoke(FirScope.kt:124)?ScopeBasedTowerLevel$processObjectsByName$$inlined$processClassifiersByName$1.invoke(FirScope.kt:124)?FirAbstractSimpleImportingScope.processClassifiersByNameWithSubstitution$lambda$0(FirAbstractSimpleImportingScope.kt:33)?FirAbstractImportingScope.processClassifiersFromImportsByName(FirAbstractImportingScope.kt:55)?FirAbstractSimpleImportingScope.processClassifiersByNameWithSubstitution(FirAbstractSimpleImportingScope.kt:32)?ScopeBasedTowerLevel.processObjectsByName(TowerLevels.kt:514)?TowerLevelHandler.handleLevel(TowerLevelHandler.kt:57)?FirBaseTowerResolveTask.processLevel(FirTowerResolveTask.kt:165)?FirBaseTowerResolveTask.access$processLevel(FirTowerResolveTask.kt:53)?FirTowerResolveTask.runResolverForNoReceiver(FirTowerResolveTask.kt:528)?FirTowerResolveTask.runResolverForNoReceiver$default(FirTowerResolveTask.kt:291)?FirTowerResolver$enqueueResolutionTasks$2.invokeSuspend(FirTowerResolver.kt:80)?BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)?TowerResolveManager.resumeTask(TowerResolveManager.kt:77)?TowerResolveManager.runTasks(TowerResolveManager.kt:83)?FirTowerResolver.runResolver(FirTowerResolver.kt:54)?FirTowerResolver.runResolver(FirTowerResolver.kt:40)?FirCallResolver.collectCandidates(FirCallResolver.kt:260)?FirCallResolver.collectCandidates$default(FirCallResolver.kt:218)?FirCallResolver.resolveVariableAccessAndSelectCandidateImpl$lambda$0(FirCallResolver.kt:334)?UnsafeLazyImpl.getValue(Lazy.kt:100)?FirCallResolver.resolveVariableAccessAndSelectCandidateImpl$lambda$1(FirCallResolver.kt:333)?FirCallResolver.resolveVariableAccessAndSelectCandidateImpl(FirCallResolver.kt:366)?FirCallResolver.resolveVariableAccessAndSelectCandidate(FirCallResolver.kt:310)?FirExpressionsResolveTransformer.resolveQualifiedAccessAndSelectCandidate(FirExpressionsResolveTransformer.kt:336)?FirExpressionsResolveTransformer.transformQualifiedAccessExpression(FirExpressionsResolveTransformer.kt:198)?FirExpressionsResolveTransformer.transformAsExplicitReceiver(FirExpressionsResolveTransformer.kt:309)?FirExpressionsResolveTransformer.transformExplicitReceiverOf(FirExpressionsResolveTransformer.kt:297)?FirCallResolver.resolveVariableAccessAndSelectCandidateImpl(FirCallResolver.kt:330)?FirCallResolver.resolveVariableAccessAndSelectCandidate(FirCallResolver.kt:310)?FirExpressionsResolveTransformer.resolveQualifiedAccessAndSelectCandidate(FirExpressionsResolveTransformer.kt:336)?FirExpressionsResolveTransformer.transformQualifiedAccessExpression(FirExpressionsResolveTransformer.kt:198)?FirExpressionsResolveTransformer.transformQualifiedAccessExpression(FirExpressionsResolveTransformer.kt:109)?FirAbstractBodyResolveTransformerDispatcher.transformPropertyAccessExpression(FirAbstractBodyResolveTransformerDispatcher.kt:182)?FirAbstractBodyResolveTransformerDispatcher.transformPropertyAccessExpression(FirAbstractBodyResolveTransformerDispatcher.kt:27)?FirPropertyAccessExpression.transform(FirPropertyAccessExpression.kt:43)?FirTransformerUtilKt.transformInplace(FirTransformerUtil.kt:20)?FirArgumentListImpl.transformArguments(FirArgumentListImpl.kt:35)?FirArgumentListImpl.transformChildren(FirArgumentListImpl.kt:30)?FirArgumentListImpl.transformChildren(FirArgumentListImpl.kt:20)?FirAbstractBodyResolveTransformerDispatcher.transformElement(FirAbstractBodyResolveTransformerDispatcher.kt:92)?FirAbstractBodyResolveTransformerDispatcher.transformElement(FirAbstractBodyResolveTransformerDispatcher.kt:27)?FirTransformer.transformArgumentList(FirTransformer.kt:167)?FirArgumentList.transform(FirArgumentList.kt:29)?FirPartialBodyResolveTransformer.transformElement(FirPartialBodyResolveTransformer.kt:36)?FirPartialBodyResolveTransformer.transformElement(FirPartialBodyResolveTransformer.kt:13)?FirTransformer.transformArgumentList(FirTransformer.kt:167)?FirArgumentList.transform(FirArgumentList.kt:29)?FirExpressionsResolveTransformer.transformFunctionCallInternal$resolve(FirExpressionsResolveTransformer.kt:584)?FirExpressionsResolveTransformer.transformFunctionCall(FirExpressionsResolveTransformer.kt:520)?FirAbstractBodyResolveTransformerDispatcher.transformFunctionCall(FirAbstractBodyResolveTransformerDispatcher.kt:200)?FirAbstractBodyResolveTransformerDispatcher.transformFunctionCall(FirAbstractBodyResolveTransformerDispatcher.kt:27)?FirFunctionCall.transform(FirFunctionCall.kt:45)?FirPropertyImpl.transformInitializer(FirPropertyImpl.kt:124)?FirPropertyImpl.transformInitializer(FirPropertyImpl.kt:33)?FirDeclarationsResolveTransformer.transformProperty$lambda$0$6(FirDeclarationsResolveTransformer.kt:186)?FirDeclarationsResolveTransformer.transformMemberPropertyInternal$resolve(FirDeclarationsResolveTransformer.kt:232)?FirDeclarationsResolveTransformer.transformProperty(FirDeclarationsResolveTransformer.kt:181)\\\`
Stack: \`RuntimeException:LintDriver$Companion.handleDetectorError(LintDriver.kt:3603)?LintDriver$Companion.handleDetectorError$default(LintDriver.kt:3468)?LintDriver$Companion.handleDetectorError(LintDriver.kt:3464)?UElementVisitor.visitFile(UElementVisitor.kt:233)?LintDriver$visitUastDetectors$1.run(LintDriver.kt:2032)?LintClient.runReadAction(LintClient.kt:1655)?LintCliClient.runReadAction(LintCliClient.kt:231)?LintDriver$LintClientWrapper.runReadAction(LintDriver.kt:2694)?LintDriver.visitUastDetectors(LintDriver.kt:2030)?LintDriver.visitUast(LintDriver.kt:1977)?LintDriver.runFileDetectors(LintDriver.kt:1234)?LintDriver.checkProject(LintDriver.kt:1041)?LintDriver.checkProjectRoot(LintDriver.kt:607)?LintDriver.access$checkProjectRoot(LintDriver.kt:179)?LintDriver$analyzeOnly$1.invoke(LintDriver.kt:434)?LintDriver$analyzeOnly$1.invoke(LintDriver.kt:431)?LintDriver.doAnalyze(LintDriver.kt:490)?LintDriver.analyzeOnly(LintDriver.kt:431)?LintCliClient$analyzeOnly$1.invoke(LintCliClient.kt:265)?LintCliClient$analyzeOnly$1.invoke(LintCliClient.kt:262)?LintCliClient.run(LintCliClient.kt:311)?LintCliClient.analyzeOnly(LintCliClient.kt:262)?Main.run(Main.java:1786)?Main.run(Main.java:287)?NativeMethodAccessorImpl.invoke0(NativeMethodAccessorImpl.java:-2)?NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)?DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)?Method.invoke(Method.java:569)?AndroidLintWorkAction.invokeLintMainRunMethod(AndroidLintWorkAction.kt:103)?AndroidLintWorkAction.runLint(AndroidLintWorkAction.kt:90)?AndroidLintWorkAction.execute(AndroidLintWorkAction.kt:64)?DefaultWorkerServer.execute(DefaultWorkerServer.java:68)?NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:64)?NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:61)?ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:102)?NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:61)?AbstractWorker$1.call(AbstractWorker.java:44)?AbstractWorker$1.call(AbstractWorker.java:41)?DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:210)?DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:205)?DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:67)?DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:60)?DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:167)?DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:60)?DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:54)?AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41)?NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:58)?DefaultWorkerExecutor.lambda$submitWork$0(DefaultWorkerExecutor.java:174)?FutureTask.run(FutureTask.java:264)?DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:191)?DefaultConditionalExecutionQueue$ExecutionRunner.access$500(DefaultConditionalExecutionQueue.java:112)?DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:168)?Factories$1.create(Factories.java:30)?DefaultWorkerLeaseService.lambda$runAndReleaseLocks$0(DefaultWorkerLeaseService.java:300)?ResourceLockStatistics$1.measure(ResourceLockStatistics.java:43)?DefaultWorkerLeaseService.runAndReleaseLocks(DefaultWorkerLeaseService.java:298)?DefaultWorkerLeaseService.withLocksAcquired(DefaultWorkerLeaseService.java:294)?DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:286)?DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:130)?DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:135)?DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:163)?DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:125)?Executors$RunnableAdapter.call(Executors.java:539)?FutureTask.run(FutureTask.java:264)?ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)?AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47)?ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)?ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)?Thread.run(Thread.java:840)\`
Stack: `RuntimeException:LintDriver$Companion.handleDetectorError(LintDriver.kt:3603)?LintDriver$Companion.handleDetectorError$default(LintDriver.kt:3468)?LintDriver$Companion.handleDetectorError(LintDriver.kt:3464)?LintDriver$analyzeOnly$1.invoke(LintDriver.kt:436)?LintDriver$analyzeOnly$1.invoke(LintDriver.kt:431)?LintDriver.doAnalyze(LintDriver.kt:490)?LintDriver.analyzeOnly(LintDriver.kt:431)?LintCliClient$analyzeOnly$1.invoke(LintCliClient.kt:265)?LintCliClient$analyzeOnly$1.invoke(LintCliClient.kt:262)?LintCliClient.run(LintCliClient.kt:311)?LintCliClient.analyzeOnly(LintCliClient.kt:262)?Main.run(Main.java:1786)?Main.run(Main.java:287)?NativeMethodAccessorImpl.invoke0(NativeMethodAccessorImpl.java:-2)?NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)?DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)?Method.invoke(Method.java:569)?AndroidLintWorkAction.invokeLintMainRunMethod(AndroidLintWorkAction.kt:103)?AndroidLintWorkAction.runLint(AndroidLintWorkAction.kt:90)?AndroidLintWorkAction.execute(AndroidLintWorkAction.kt:64)?DefaultWorkerServer.execute(DefaultWorkerServer.java:68)?NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:64)?NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:61)?ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:102)?NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:61)?AbstractWorker$1.call(AbstractWorker.java:44)?AbstractWorker$1.call(AbstractWorker.java:41)?DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:210)?DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:205)?DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:67)?DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:60)?DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:167)?DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:60)?DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:54)?AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41)?NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:58)?DefaultWorkerExecutor.lambda$submitWork$0(DefaultWorkerExecutor.java:174)?FutureTask.run(FutureTask.java:264)?DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:191)?DefaultConditionalExecutionQueue$ExecutionRunner.access$500(DefaultConditionalExecutionQueue.java:112)?DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:168)?Factories$1.create(Factories.java:30)?DefaultWorkerLeaseService.lambda$runAndReleaseLocks$0(DefaultWorkerLeaseService.java:300)?ResourceLockStatistics$1.measure(ResourceLockStatistics.java:43)?DefaultWorkerLeaseService.runAndReleaseLocks(DefaultWorkerLeaseService.java:298)?DefaultWorkerLeaseService.withLocksAcquired(DefaultWorkerLeaseService.java:294)?DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:286)?DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:130)?DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:135)?DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:163)?DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:125)?Executors$RunnableAdapter.call(Executors.java:539)?FutureTask.run(FutureTask.java:264)?ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)?AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47)?ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)?ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)?Thread.run(Thread.java:840)`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can do that later and will need to do it across all the applications. I'm already using JDK 21 locally and we're using it for the GitHub Actions already too.

Comment on lines +1532 to +1539
// On cameras where the feature group is not used (see canVerifyFeatureCombinations)
// EIS is deliberately left off. The pre-1.6 stabilization setters cannot be applied
// on top of the recorder's higher qualities -- UHD in particular is in none of the
// stabilization-guaranteed configurations -- so requesting them would either kill
// the preview or force the quality down. We keep the selected quality (4K by
// default) and simply do not stabilize; the EIS toggle stays visible but has no
// effect on these cameras. This is the app's long-standing behavior (EIS regressed
// here when it moved off the Camera2 API) and is fixable separately.

@inthewaves inthewaves Jul 27, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This describes that EIS will be disabled when feature group is not used, but isVideoStabilizationSupported doesn't follow this logic. It'd seem like on API 29 to 34, the EIS toggle would still be shown from the camera's standalone capability, making the toggle a no-op on those API levels

Comment on lines 1787 to 1794
override fun onStop() {
super.onStop()
isStarted = false
// Stop explicitly rather than letting the unbind tear the recording down for us.
if (this::videoCapturer.isInitialized && videoCapturer.isRecording) {
videoCapturer.stopRecording()
}
super.onStop()
}

@inthewaves inthewaves Jul 27, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VideoCaptureActivity extends CaptureActivity, which extends MainActivity

e.g. replace app.grapheneos.camera.dev with appropriate app id

adb shell am start -W \
    -a android.media.action.VIDEO_CAPTURE \
    -n app.grapheneos.camera.dev/app.grapheneos.camera.ui.activities.VideoCaptureActivity

The Finalize / VideoCaptureActivity.afterRecording callback crosses the lifecycle boundary as follows:

  1. VideoCaptureActivity inherits this onStop() through CaptureActivity; it is the same activity instance throughout.
  2. This method requests stopRecording() and then calls super.onStop().
  3. VideoCapturer.kt:213 passed ctx.mainExecutor to PendingRecording.start(). CameraX stores it as the event-listener executor and dispatches Finalize through it.
  4. On main executor Finalize runs only after the current onStop(), including super.onStop(), returns
  5. Finalize calls VideoCaptureActivity.afterRecording(), which asserts previewView.bitmap!! even though PreviewView.getBitmap() is nullable when preview is not running.

Pressing Back during an ACTION_VIDEO_CAPTURE recording can therefore crash after the preview stops. We should skip or defer stopped-activity UI work and use a null-safe thumbnail source; output finalization should remain independent

 9442-9442  AndroidRuntime          pid-9442                             E  Stack has been retraced with Camera/app/build/outputs/mapping/play/mapping.prt
                                                                            FATAL EXCEPTION: main (Show original)
                                                                            Process: app.grapheneos.camera.play, PID: 9442
                                                                            java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Class java.lang.Object.getClass()' on a null object reference
                                                                            	at app.grapheneos.camera.ui.activities.VideoCaptureActivity.afterRecording(VideoCaptureActivity.kt:57)
                                                                            	at app.grapheneos.camera.capturer.VideoCapturer.startRecording$lambda$1$0(VideoCapturer.kt:277)
                                                                            	at androidx.camera.video.Recorder$RecordingRecord.lambda$updateVideoRecordEvent$5(Recorder.java:3523)
                                                                            	at android.os.Handler.handleCallback(Handler.java:1096)
                                                                            	at android.os.Handler.dispatchMessageImpl(Handler.java:135)
                                                                            	at android.os.Handler.dispatchMessage(Handler.java:125)
                                                                            	at android.os.Looper.loopOnce(Looper.java:296)
                                                                            	at android.os.Looper.loop(Looper.java:397)
                                                                            	at android.app.ActivityThread.main(ActivityThread.java:9569)
                                                                            	at java.lang.reflect.Method.invoke(Native Method)
                                                                            	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:575)
                                                                            	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:982)

Comment on lines +264 to +276
/**
* A capture session recorded with mode tabs it never showed, and onSwipeLeft() did not refuse
* to switch mode while recording the way onSwipeRight() does: a fling rebound the camera out
* from under the running recorder.
*/
@Test
fun flingWhileRecording_leavesTheRecordingAlone() {
val intent = Intent(targetContext, VideoCaptureActivity::class.java)
.setAction(MediaStore.ACTION_VIDEO_CAPTURE)

recordingTest({ ActivityScenario.launch<VideoCaptureActivity>(intent) }) { scenario ->
// Flinging before the tabs were built would pass whether or not any get built
Thread.sleep(2000)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VideoCaptureActivity doesn't have any tabs so this test will always pass

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants