[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[tor-commits] [Git][tpo/applications/tor-browser][tor-browser-153.1.0esr-16.0-1] 5 commits: Bug 1842361 - Download confirmation notification can be overlaid over other...



Title: GitLab

ma1 pushed to branch tor-browser-153.1.0esr-16.0-1 at The Tor Project / Applications / Tor Browser

Commits:

  • bb66338d
    by giorga at 2026-08-16T00:41:44+02:00
    Bug 1842361 - Download confirmation notification can be overlaid over other origins. r=android-reviewers,jdelorenzo
    
    Differential Revision: https://phabricator.services.mozilla.com/D309062
    
  • 7655bbd2
    by Marcin Koziński at 2026-08-16T00:41:44+02:00
    Bug 1978587 - Forward onEnterAnimationComplete to interested fragments r=android-reviewers,twhite
    
    Differential Revision: https://phabricator.services.mozilla.com/D306954
    
  • d13ffd02
    by Marcin Koziński at 2026-08-16T00:56:58+02:00
    Bug 2049034 - Add an initial delay to download button in Fenix download dialog  a=pascalc
    
    Original Revision: https://phabricator.services.mozilla.com/D309334
    
    Differential Revision: https://phabricator.services.mozilla.com/D310049
    
  • 4e27f4b0
    by Jamie Nicol at 2026-08-17T08:17:03+02:00
    Bug 2049810 - Allocate HardwareBuffer for screen pixels request in parent process. r=gfx-reviewers,lsalzman
    
    Differential Revision: https://phabricator.services.mozilla.com/D308519
    
  • a6ed37e7
    by owlishDeveloper at 2026-08-17T10:29:07+02:00
    Bug 2055683 - IPC improvement  a=pascalc
    
    Original Revision: https://phabricator.services.mozilla.com/D314463
    
    Differential Revision: https://phabricator.services.mozilla.com/D314798
    

24 changed files:

Changes:

  • gfx/layers/ipc/PUiCompositorController.ipdl
    ... ... @@ -3,9 +3,7 @@
    3 3
      * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
    
    4 4
     
    
    5 5
     using mozilla::gfx::IntRect from "mozilla/gfx/Rect.h";
    
    6
    -using mozilla::gfx::IntSize from "mozilla/gfx/Point.h";
    
    7 6
     using mozilla::layers::CompositorScrollUpdate from "mozilla/layers/CompositorScrollUpdate.h";
    
    8
    -using mozilla::void_t from "mozilla/ipc/IPCCore.h";
    
    9 7
     
    
    10 8
     include "mozilla/GfxMessageUtils.h";
    
    11 9
     include "mozilla/layers/LayersMessageUtils.h";
    
    ... ... @@ -34,15 +32,14 @@ parent:
    34 32
       async MaxToolbarHeight(int32_t aHeight);
    
    35 33
       async FixedBottomOffset(int32_t aOffset);
    
    36 34
       async DefaultClearColor(uint32_t aColor);
    
    37
    -  async RequestScreenPixels(uint64_t aRequestId, IntRect aSourceRect, IntSize aDestSize);
    
    35
    +  async RequestScreenPixels(uint64_t aRequestId, IntRect aSourceRect,
    
    36
    +                            FileDescriptor aHardwareBuffer);
    
    38 37
       async EnableLayerUpdateNotifications(bool aEnable);
    
    39 38
     child:
    
    40 39
       async ToolbarAnimatorMessageFromCompositor(int32_t aMessage);
    
    41 40
       async NotifyCompositorScrollUpdate(CompositorScrollUpdate aUpdate);
    
    42
    -  // Returns when the child side has finished using the HardwareBuffer,
    
    43
    -  // indicating that the parent side can now release it.
    
    44
    -  async ScreenPixels(uint64_t aRequestId, FileDescriptor? aHardwareBuffer, FileDescriptor? aAcquireFence)
    
    45
    -    returns (void_t ok);
    
    41
    +  async ScreenPixels(uint64_t aRequestId, bool aSuccess,
    
    42
    +                     FileDescriptor? aAcquireFence);
    
    46 43
     };
    
    47 44
     
    
    48 45
     } // layers
    

  • gfx/layers/ipc/UiCompositorControllerChild.cpp
    ... ... @@ -148,19 +148,36 @@ UiCompositorControllerChild::RequestScreenPixels(gfx::IntRect aSourceRect,
    148 148
     
    
    149 149
       // We only support one request at a time. If an old request is still
    
    150 150
       // outstanding when a new request is made, just reject the old request.
    
    151
    -  if (mScreenPixelsPromise) {
    
    152
    -    mScreenPixelsPromise.extract().second->Reject(NS_ERROR_ABORT, __func__);
    
    151
    +  if (mScreenPixelsRequest) {
    
    152
    +    mScreenPixelsRequest.extract().mPromise->Reject(NS_ERROR_ABORT, __func__);
    
    153
    +  }
    
    154
    +
    
    155
    +  RefPtr<layers::AndroidHardwareBuffer> hardwareBuffer =
    
    156
    +      layers::AndroidHardwareBuffer::Create(aDestSize,
    
    157
    +                                            gfx::SurfaceFormat::R8G8B8A8);
    
    158
    +  if (!hardwareBuffer) {
    
    159
    +    return ScreenPixelsPromise::CreateAndReject(NS_ERROR_OUT_OF_MEMORY,
    
    160
    +                                                __func__);
    
    161
    +  }
    
    162
    +
    
    163
    +  UniqueFileHandle bufferFd = hardwareBuffer->SerializeToFileDescriptor();
    
    164
    +  if (!bufferFd) {
    
    165
    +    return ScreenPixelsPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
    
    153 166
       }
    
    154 167
     
    
    155 168
       static uint64_t nextRequestId = 0;
    
    156 169
       const uint64_t requestId = nextRequestId++;
    
    157 170
       auto promise = MakeRefPtr<ScreenPixelsPromise::Private>(__func__);
    
    158
    -  // Using synchronous dispatch ensures we are done using the hardware buffer
    
    159
    -  // prior to RecvScreenPixels calling aResolver which in turn will cause the
    
    160
    -  // hardware buffer on the parent side to be released.
    
    161
    -  promise->UseSynchronousTaskDispatch(__func__);
    
    162
    -  mScreenPixelsPromise.emplace(requestId, promise);
    
    163
    -  (void)SendRequestScreenPixels(requestId, aSourceRect, aDestSize);
    
    171
    +  mScreenPixelsRequest.emplace(ScreenPixelsRequest{
    
    172
    +      .mRequestId = requestId,
    
    173
    +      .mHardwareBuffer = hardwareBuffer,
    
    174
    +      .mPromise = promise,
    
    175
    +  });
    
    176
    +  if (!SendRequestScreenPixels(requestId, aSourceRect,
    
    177
    +                               ipc::FileDescriptor(std::move(bufferFd)))) {
    
    178
    +    mScreenPixelsRequest.extract().mPromise->Reject(NS_ERROR_NOT_AVAILABLE,
    
    179
    +                                                    __func__);
    
    180
    +  }
    
    164 181
       return promise;
    
    165 182
     }
    
    166 183
     #endif
    
    ... ... @@ -213,8 +230,8 @@ void UiCompositorControllerChild::ActorDestroy(ActorDestroyReason aWhy) {
    213 230
       mParent = nullptr;
    
    214 231
     
    
    215 232
     #ifdef MOZ_WIDGET_ANDROID
    
    216
    -  if (mScreenPixelsPromise) {
    
    217
    -    mScreenPixelsPromise->second->Reject(NS_ERROR_ABORT, __func__);
    
    233
    +  if (mScreenPixelsRequest) {
    
    234
    +    mScreenPixelsRequest->mPromise->Reject(NS_ERROR_ABORT, __func__);
    
    218 235
       }
    
    219 236
     #endif
    
    220 237
       if (mProcessToken) {
    
    ... ... @@ -258,39 +275,28 @@ UiCompositorControllerChild::RecvNotifyCompositorScrollUpdate(
    258 275
     }
    
    259 276
     
    
    260 277
     mozilla::ipc::IPCResult UiCompositorControllerChild::RecvScreenPixels(
    
    261
    -    uint64_t aRequestId, Maybe<ipc::FileDescriptor>&& aHardwareBuffer,
    
    262
    -    Maybe<ipc::FileDescriptor>&& aAcquireFence,
    
    263
    -    ScreenPixelsResolver&& aResolver) {
    
    278
    +    uint64_t aRequestId, bool aSuccess,
    
    279
    +    Maybe<ipc::FileDescriptor>&& aAcquireFence) {
    
    264 280
     #if defined(MOZ_WIDGET_ANDROID)
    
    265
    -  if (!mScreenPixelsPromise || mScreenPixelsPromise->first != aRequestId) {
    
    281
    +  if (!mScreenPixelsRequest || mScreenPixelsRequest->mRequestId != aRequestId) {
    
    266 282
         // Response is for an outdated request whose promise will have already been
    
    267 283
         // rejected. Just ignore it.
    
    268 284
         return IPC_OK();
    
    269 285
       }
    
    270 286
     
    
    271
    -  RefPtr<layers::AndroidHardwareBuffer> hardwareBuffer;
    
    272
    -  if (aHardwareBuffer) {
    
    273
    -    hardwareBuffer =
    
    274
    -        layers::AndroidHardwareBuffer::DeserializeFromFileDescriptor(
    
    275
    -            aHardwareBuffer->TakePlatformHandle());
    
    287
    +  auto request = mScreenPixelsRequest.extract();
    
    288
    +  if (!aSuccess) {
    
    289
    +    request.mPromise->Reject(NS_ERROR_FAILURE, __func__);
    
    290
    +    return IPC_OK();
    
    276 291
       }
    
    277
    -  if (hardwareBuffer && aAcquireFence) {
    
    278
    -    hardwareBuffer->SetAcquireFence(aAcquireFence->TakePlatformHandle());
    
    292
    +
    
    293
    +  if (aAcquireFence) {
    
    294
    +    request.mHardwareBuffer->SetAcquireFence(
    
    295
    +        aAcquireFence->TakePlatformHandle());
    
    279 296
       }
    
    280
    -  // Note this is resolved synchronously, ensuring we have finished using the
    
    281
    -  // hardware buffer as soon as this call returns (and importantly before the
    
    282
    -  // aResolver call below).
    
    283
    -  mScreenPixelsPromise.extract().second->Resolve(std::move(hardwareBuffer),
    
    284
    -                                                 __func__);
    
    297
    +  request.mPromise->Resolve(std::move(request.mHardwareBuffer), __func__);
    
    285 298
     #endif  // defined(MOZ_WIDGET_ANDROID)
    
    286 299
     
    
    287
    -  // Notify the parent side that it can drop its reference to the hardware
    
    288
    -  // buffer. In theory this could be done as soon as we have called
    
    289
    -  // DeserializeFromFileDescriptor(). However, on certain Exynos devices we have
    
    290
    -  // seen that releasing the original hardware buffer frees the underlying
    
    291
    -  // resource even if a reference obtained via (de)serialization remains alive.
    
    292
    -  // See bug 2017901.
    
    293
    -  aResolver(void_t{});
    
    294 300
       return IPC_OK();
    
    295 301
     }
    
    296 302
     
    

  • gfx/layers/ipc/UiCompositorControllerChild.h
    ... ... @@ -84,9 +84,8 @@ class UiCompositorControllerChild final
    84 84
       mozilla::ipc::IPCResult RecvNotifyCompositorScrollUpdate(
    
    85 85
           const CompositorScrollUpdate& aUpdate);
    
    86 86
       mozilla::ipc::IPCResult RecvScreenPixels(
    
    87
    -      uint64_t aRequestId, Maybe<ipc::FileDescriptor>&& aHardwareBuffer,
    
    88
    -      Maybe<ipc::FileDescriptor>&& aAcquireFence,
    
    89
    -      ScreenPixelsResolver&& aResolver);
    
    87
    +      uint64_t aRequestId, bool aSuccess,
    
    88
    +      Maybe<ipc::FileDescriptor>&& aAcquireFence);
    
    90 89
     
    
    91 90
      private:
    
    92 91
       explicit UiCompositorControllerChild(const uint64_t& aProcessToken,
    
    ... ... @@ -118,8 +117,12 @@ class UiCompositorControllerChild final
    118 117
       // RecvScreenPixels() altogether. Unfortunately, however, we cannot chain to a
    
    119 118
       // promise returned from an IPDL function on the Android UI thread, as the
    
    120 119
       // thread does not support direct task dispatch.
    
    121
    -  Maybe<std::pair<uint64_t, RefPtr<ScreenPixelsPromise::Private>>>
    
    122
    -      mScreenPixelsPromise;
    
    120
    +  struct ScreenPixelsRequest {
    
    121
    +    uint64_t mRequestId;
    
    122
    +    RefPtr<layers::AndroidHardwareBuffer> mHardwareBuffer;
    
    123
    +    RefPtr<ScreenPixelsPromise::Private> mPromise;
    
    124
    +  };
    
    125
    +  Maybe<ScreenPixelsRequest> mScreenPixelsRequest;
    
    123 126
     #endif
    
    124 127
     
    
    125 128
       // Should only be set when compositor is in process.
    

  • gfx/layers/ipc/UiCompositorControllerParent.cpp
    ... ... @@ -139,39 +139,39 @@ mozilla::ipc::IPCResult UiCompositorControllerParent::RecvDefaultClearColor(
    139 139
     }
    
    140 140
     
    
    141 141
     mozilla::ipc::IPCResult UiCompositorControllerParent::RecvRequestScreenPixels(
    
    142
    -    uint64_t aRequestId, gfx::IntRect aSourceRect, gfx::IntSize aDestSize) {
    
    142
    +    uint64_t aRequestId, gfx::IntRect aSourceRect,
    
    143
    +    ipc::FileDescriptor&& aHardwareBuffer) {
    
    143 144
     #if defined(MOZ_WIDGET_ANDROID)
    
    145
    +  RefPtr<AndroidHardwareBuffer> hardwareBuffer =
    
    146
    +      AndroidHardwareBuffer::DeserializeFromFileDescriptor(
    
    147
    +          aHardwareBuffer.TakePlatformHandle());
    
    148
    +  if (!hardwareBuffer) {
    
    149
    +    (void)SendScreenPixels(aRequestId, false, Nothing());
    
    150
    +    return IPC_OK();
    
    151
    +  }
    
    152
    +
    
    144 153
       LayerTreeState* state =
    
    145 154
           CompositorBridgeParent::GetLayerTreeState(mRootLayerTreeId);
    
    146 155
     
    
    147 156
       if (state && state->mWrBridge) {
    
    148
    -    state->mWrBridge->RequestScreenPixels(aSourceRect, aDestSize)
    
    157
    +    state->mWrBridge->RequestScreenPixels(aSourceRect, hardwareBuffer)
    
    149 158
             ->Then(
    
    150 159
                 GetCurrentSerialEventTarget(), __func__,
    
    151
    -            [target = RefPtr{this},
    
    152
    -             aRequestId](RefPtr<AndroidHardwareBuffer> aHardwareBuffer) {
    
    153
    -              UniqueFileHandle bufferFd =
    
    154
    -                  aHardwareBuffer->SerializeToFileDescriptor();
    
    160
    +            [target = RefPtr{this}, aRequestId,
    
    161
    +             hardwareBuffer = std::move(hardwareBuffer)](Ok) {
    
    155 162
                   UniqueFileHandle fenceFd =
    
    156
    -                  aHardwareBuffer->GetAndResetAcquireFence();
    
    157
    -              target
    
    158
    -                  ->SendScreenPixels(
    
    159
    -                      aRequestId,
    
    160
    -                      aHardwareBuffer
    
    161
    -                          ? Some(ipc::FileDescriptor(std::move(bufferFd)))
    
    162
    -                          : Nothing(),
    
    163
    -                      fenceFd ? Some(ipc::FileDescriptor(std::move(fenceFd)))
    
    164
    -                              : Nothing())
    
    165
    -                  // Ensure the hardware buffer remains alive until child side
    
    166
    -                  // has finished using it.
    
    167
    -                  ->Then(GetCurrentSerialEventTarget(), __func__,
    
    168
    -                         [aHardwareBuffer](
    
    169
    -                             ScreenPixelsPromise::ResolveOrRejectValue&&) {});
    
    163
    +                  hardwareBuffer->GetAndResetAcquireFence();
    
    164
    +              (void)target->SendScreenPixels(
    
    165
    +                  aRequestId, true,
    
    166
    +                  fenceFd ? Some(ipc::FileDescriptor(std::move(fenceFd)))
    
    167
    +                          : Nothing());
    
    170 168
                 },
    
    171 169
                 [target = RefPtr{this}, aRequestId](nsresult aError) {
    
    172
    -              (void)target->SendScreenPixels(aRequestId, Nothing(), Nothing());
    
    170
    +              (void)target->SendScreenPixels(aRequestId, false, Nothing());
    
    173 171
                 });
    
    174 172
         state->mWrBridge->ScheduleForcedGenerateFrame(wr::RenderReasons::OTHER);
    
    173
    +  } else {
    
    174
    +    (void)SendScreenPixels(aRequestId, false, Nothing());
    
    175 175
       }
    
    176 176
     #endif  // defined(MOZ_WIDGET_ANDROID)
    
    177 177
     
    

  • gfx/layers/ipc/UiCompositorControllerParent.h
    ... ... @@ -41,9 +41,9 @@ class UiCompositorControllerParent final
    41 41
       mozilla::ipc::IPCResult RecvMaxToolbarHeight(const int32_t& aHeight);
    
    42 42
       mozilla::ipc::IPCResult RecvFixedBottomOffset(const int32_t& aOffset);
    
    43 43
       mozilla::ipc::IPCResult RecvDefaultClearColor(const uint32_t& aColor);
    
    44
    -  mozilla::ipc::IPCResult RecvRequestScreenPixels(uint64_t aRequestId,
    
    45
    -                                                  gfx::IntRect aSourceRect,
    
    46
    -                                                  gfx::IntSize aDestSize);
    
    44
    +  mozilla::ipc::IPCResult RecvRequestScreenPixels(
    
    45
    +      uint64_t aRequestId, gfx::IntRect aSourceRect,
    
    46
    +      ipc::FileDescriptor&& aHardwareBuffer);
    
    47 47
       mozilla::ipc::IPCResult RecvEnableLayerUpdateNotifications(
    
    48 48
           const bool& aEnable);
    
    49 49
       void ActorDestroy(ActorDestroyReason aWhy) override;
    

  • gfx/layers/wr/WebRenderBridgeParent.cpp
    ... ... @@ -1945,8 +1945,8 @@ void WebRenderBridgeParent::UpdateBoolParameters() {
    1945 1945
     
    
    1946 1946
     #if defined(MOZ_WIDGET_ANDROID)
    
    1947 1947
     RefPtr<WebRenderBridgeParent::ScreenPixelsPromise>
    
    1948
    -WebRenderBridgeParent::RequestScreenPixels(gfx::IntRect aSourceRect,
    
    1949
    -                                           gfx::IntSize aDestSize) {
    
    1948
    +WebRenderBridgeParent::RequestScreenPixels(
    
    1949
    +    gfx::IntRect aSourceRect, RefPtr<AndroidHardwareBuffer> aHardwareBuffer) {
    
    1950 1950
       if (mDestroyed) {
    
    1951 1951
         return ScreenPixelsPromise::CreateAndReject(NS_ERROR_ABORT, __func__);
    
    1952 1952
       }
    
    ... ... @@ -1962,7 +1962,7 @@ WebRenderBridgeParent::RequestScreenPixels(gfx::IntRect aSourceRect,
    1962 1962
       }
    
    1963 1963
       mScreenPixelsRequest.emplace(ScreenPixelsRequest{
    
    1964 1964
           .mSourceRect = aSourceRect,
    
    1965
    -      .mDestSize = aDestSize,
    
    1965
    +      .mHardwareBuffer = std::move(aHardwareBuffer),
    
    1966 1966
           .mPromise = new ScreenPixelsPromise::Private(__func__),
    
    1967 1967
       });
    
    1968 1968
       return mScreenPixelsRequest->mPromise;
    
    ... ... @@ -1982,7 +1982,9 @@ void WebRenderBridgeParent::MaybeCaptureScreenPixels() {
    1982 1982
       MOZ_ASSERT(cbp && !cbp->IsPaused());
    
    1983 1983
     #  endif
    
    1984 1984
     
    
    1985
    -  mLateInit->mApi->RequestScreenPixels(request.mSourceRect, request.mDestSize)
    
    1985
    +  mLateInit->mApi
    
    1986
    +      ->RequestScreenPixels(request.mSourceRect,
    
    1987
    +                            std::move(request.mHardwareBuffer))
    
    1986 1988
           ->ChainTo(request.mPromise.forget(), __func__);
    
    1987 1989
     }
    
    1988 1990
     #endif
    

  • gfx/layers/wr/WebRenderBridgeParent.h
    ... ... @@ -325,13 +325,13 @@ class WebRenderBridgeParent final : public PWebRenderBridgeParent,
    325 325
       void BeginRecording(const TimeStamp& aRecordingStart);
    
    326 326
     
    
    327 327
     #if defined(MOZ_WIDGET_ANDROID)
    
    328
    -  using ScreenPixelsPromise =
    
    329
    -      MozPromise<RefPtr<layers::AndroidHardwareBuffer>, nsresult, true>;
    
    328
    +  using ScreenPixelsPromise = MozPromise<Ok, nsresult, true>;
    
    330 329
       /**
    
    331 330
        * Request a screengrab for android
    
    332 331
        */
    
    333
    -  RefPtr<ScreenPixelsPromise> RequestScreenPixels(gfx::IntRect aSourceRect,
    
    334
    -                                                  gfx::IntSize aDestSize);
    
    332
    +  RefPtr<ScreenPixelsPromise> RequestScreenPixels(
    
    333
    +      gfx::IntRect aSourceRect,
    
    334
    +      RefPtr<layers::AndroidHardwareBuffer> aHardwareBuffer);
    
    335 335
     #endif
    
    336 336
     
    
    337 337
       /**
    
    ... ... @@ -539,7 +539,7 @@ class WebRenderBridgeParent final : public PWebRenderBridgeParent,
    539 539
     #if defined(MOZ_WIDGET_ANDROID)
    
    540 540
       struct ScreenPixelsRequest {
    
    541 541
         gfx::IntRect mSourceRect;
    
    542
    -    gfx::IntSize mDestSize;
    
    542
    +    RefPtr<layers::AndroidHardwareBuffer> mHardwareBuffer;
    
    543 543
         RefPtr<ScreenPixelsPromise::Private> mPromise;
    
    544 544
       };
    
    545 545
       Maybe<ScreenPixelsRequest> mScreenPixelsRequest;
    

  • gfx/webrender_bindings/RenderCompositor.h
    ... ... @@ -235,7 +235,7 @@ class RenderCompositor {
    235 235
     #ifdef MOZ_WIDGET_ANDROID
    
    236 236
       virtual bool MaybeCaptureScreenPixels(
    
    237 237
           const gfx::IntRect& aSourceRect,
    
    238
    -      RefPtr<layers::AndroidHardwareBuffer> aHardwareBuffer) {
    
    238
    +      layers::AndroidHardwareBuffer* aHardwareBuffer) {
    
    239 239
         return false;
    
    240 240
       }
    
    241 241
     #endif
    

  • gfx/webrender_bindings/RenderCompositorOGLSWGL.cpp
    ... ... @@ -315,7 +315,7 @@ bool RenderCompositorOGLSWGL::MaybeReadback(
    315 315
     #ifdef MOZ_WIDGET_ANDROID
    
    316 316
     bool RenderCompositorOGLSWGL::MaybeCaptureScreenPixels(
    
    317 317
         const gfx::IntRect& aSourceRect,
    
    318
    -    RefPtr<layers::AndroidHardwareBuffer> aHardwareBuffer) {
    
    318
    +    layers::AndroidHardwareBuffer* aHardwareBuffer) {
    
    319 319
       auto* const gl = GetGLContext();
    
    320 320
       gl::ScopedBindFramebuffer scopedBind(gl);
    
    321 321
     
    

  • gfx/webrender_bindings/RenderCompositorOGLSWGL.h
    ... ... @@ -59,7 +59,7 @@ class RenderCompositorOGLSWGL : public RenderCompositorLayersSWGL {
    59 59
     #ifdef MOZ_WIDGET_ANDROID
    
    60 60
       bool MaybeCaptureScreenPixels(
    
    61 61
           const gfx::IntRect& aSourceRect,
    
    62
    -      RefPtr<layers::AndroidHardwareBuffer> aHardwareBuffer) override;
    
    62
    +      layers::AndroidHardwareBuffer* aHardwareBuffer) override;
    
    63 63
     #endif
    
    64 64
     
    
    65 65
      private:
    

  • gfx/webrender_bindings/RendererOGL.cpp
    ... ... @@ -469,7 +469,13 @@ Maybe<layers::FrameRecording> RendererOGL::EndRecording() {
    469 469
     
    
    470 470
     #ifdef MOZ_WIDGET_ANDROID
    
    471 471
     RefPtr<RendererOGL::ScreenPixelsPromise> RendererOGL::RequestScreenPixels(
    
    472
    -    gfx::IntRect aSourceRect, gfx::IntSize aDestSize) {
    
    472
    +    gfx::IntRect aSourceRect,
    
    473
    +    RefPtr<layers::AndroidHardwareBuffer> aHardwareBuffer) {
    
    474
    +  if (!aHardwareBuffer) {
    
    475
    +    return ScreenPixelsPromise::CreateAndReject(NS_ERROR_ILLEGAL_VALUE,
    
    476
    +                                                __func__);
    
    477
    +  }
    
    478
    +
    
    473 479
       // If a new request is made we no longer care about the result of the previous
    
    474 480
       // one, so just reject it if it exists.
    
    475 481
       if (mPendingScreenPixelsRequest) {
    
    ... ... @@ -478,7 +484,7 @@ RefPtr<RendererOGL::ScreenPixelsPromise> RendererOGL::RequestScreenPixels(
    478 484
       }
    
    479 485
       mPendingScreenPixelsRequest.emplace(ScreenPixelsRequest{
    
    480 486
           .mSourceRect = aSourceRect,
    
    481
    -      .mDestSize = aDestSize,
    
    487
    +      .mHardwareBuffer = std::move(aHardwareBuffer),
    
    482 488
           .mPromise = new ScreenPixelsPromise::Private(__func__),
    
    483 489
       });
    
    484 490
       return mPendingScreenPixelsRequest->mPromise;
    
    ... ... @@ -491,19 +497,16 @@ void RendererOGL::MaybeCaptureScreenPixels() {
    491 497
     
    
    492 498
       auto request = mPendingScreenPixelsRequest.extract();
    
    493 499
     
    
    494
    -  const RefPtr<layers::AndroidHardwareBuffer> hardwareBuffer =
    
    495
    -      layers::AndroidHardwareBuffer::Create(request.mDestSize,
    
    496
    -                                            gfx::SurfaceFormat::R8G8B8A8);
    
    497
    -
    
    498 500
       if (mCompositor->MaybeCaptureScreenPixels(request.mSourceRect,
    
    499
    -                                            hardwareBuffer)) {
    
    500
    -    request.mPromise->Resolve(hardwareBuffer, __func__);
    
    501
    +                                            request.mHardwareBuffer)) {
    
    502
    +    request.mPromise->Resolve(Ok{}, __func__);
    
    501 503
         return;
    
    502 504
       }
    
    503 505
     
    
    504 506
       auto* const gle = gl::GLContextEGL::Cast(gl());
    
    505 507
       const auto& egl = gle->mEgl;
    
    506
    -  gl::ScopedEGLImageForAndroidHardwareBuffer eglImage(gle, hardwareBuffer);
    
    508
    +  gl::ScopedEGLImageForAndroidHardwareBuffer eglImage(gle,
    
    509
    +                                                      request.mHardwareBuffer);
    
    507 510
       gl::ScopedBindFramebuffer scopedBind(gl());
    
    508 511
       gl::ScopedRenderbuffer rb(gl());
    
    509 512
       gl()->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, rb);
    
    ... ... @@ -517,7 +520,7 @@ void RendererOGL::MaybeCaptureScreenPixels() {
    517 520
                     request.mSourceRect.x,
    
    518 521
                     mCompositor->GetBufferSize().height - request.mSourceRect.y,
    
    519 522
                     request.mSourceRect.width, -request.mSourceRect.height);
    
    520
    -  const auto destRect = gfx::IntRect({}, hardwareBuffer->mSize);
    
    523
    +  const auto destRect = gfx::IntRect({}, request.mHardwareBuffer->mSize);
    
    521 524
       gl()->BindReadFB(0);
    
    522 525
       gl()->BindDrawFB(fb.FB());
    
    523 526
       gl()->fBlitFramebuffer(srcRect.x, srcRect.y, srcRect.XMost(), srcRect.YMost(),
    
    ... ... @@ -529,12 +532,12 @@ void RendererOGL::MaybeCaptureScreenPixels() {
    529 532
               egl->fCreateSync(LOCAL_EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr)) {
    
    530 533
         auto fence = UniqueFileHandle(egl->fDupNativeFenceFDANDROID(sync));
    
    531 534
         if (fence) {
    
    532
    -      hardwareBuffer->SetAcquireFence(std::move(fence));
    
    535
    +      request.mHardwareBuffer->SetAcquireFence(std::move(fence));
    
    533 536
         }
    
    534 537
         egl->fDestroySync(sync);
    
    535 538
       }
    
    536 539
     
    
    537
    -  request.mPromise->Resolve(hardwareBuffer, __func__);
    
    540
    +  request.mPromise->Resolve(Ok{}, __func__);
    
    538 541
     }
    
    539 542
     #endif
    
    540 543
     
    

  • gfx/webrender_bindings/RendererOGL.h
    ... ... @@ -93,12 +93,12 @@ class RendererOGL {
    93 93
       Maybe<layers::FrameRecording> EndRecording();
    
    94 94
     
    
    95 95
     #ifdef MOZ_WIDGET_ANDROID
    
    96
    -  using ScreenPixelsPromise =
    
    97
    -      MozPromise<RefPtr<layers::AndroidHardwareBuffer>, nsresult, true>;
    
    96
    +  using ScreenPixelsPromise = MozPromise<Ok, nsresult, true>;
    
    98 97
       // Captures the pixels for the next rendered frame. Returns a promise that
    
    99 98
       // resolves once the pixels are captured.
    
    100
    -  RefPtr<ScreenPixelsPromise> RequestScreenPixels(gfx::IntRect aSourceRect,
    
    101
    -                                                  gfx::IntSize aDestSize);
    
    99
    +  RefPtr<ScreenPixelsPromise> RequestScreenPixels(
    
    100
    +      gfx::IntRect aSourceRect,
    
    101
    +      RefPtr<layers::AndroidHardwareBuffer> aHardwareBuffer);
    
    102 102
     #endif
    
    103 103
     
    
    104 104
       /// This can be called on the render thread only.
    
    ... ... @@ -174,7 +174,7 @@ class RendererOGL {
    174 174
     #ifdef MOZ_WIDGET_ANDROID
    
    175 175
       struct ScreenPixelsRequest {
    
    176 176
         gfx::IntRect mSourceRect;
    
    177
    -    gfx::IntSize mDestSize;
    
    177
    +    RefPtr<layers::AndroidHardwareBuffer> mHardwareBuffer;
    
    178 178
         RefPtr<ScreenPixelsPromise::Private> mPromise;
    
    179 179
       };
    
    180 180
       Maybe<ScreenPixelsRequest> mPendingScreenPixelsRequest;
    

  • gfx/webrender_bindings/WebRenderAPI.cpp
    ... ... @@ -962,12 +962,17 @@ RefPtr<WebRenderAPI::EndRecordingPromise> WebRenderAPI::EndRecording() {
    962 962
     
    
    963 963
     #ifdef MOZ_WIDGET_ANDROID
    
    964 964
     RefPtr<WebRenderAPI::ScreenPixelsPromise> WebRenderAPI::RequestScreenPixels(
    
    965
    -    gfx::IntRect aSourceRect, gfx::IntSize aDestSize) {
    
    965
    +    gfx::IntRect aSourceRect,
    
    966
    +    RefPtr<layers::AndroidHardwareBuffer> aHardwareBuffer) {
    
    966 967
       class ScreenshotEvent final : public RendererEvent {
    
    967 968
        public:
    
    968
    -    explicit ScreenshotEvent(gfx::IntRect aSourceRect, gfx::IntSize aDestSize,
    
    969
    -                             RefPtr<ScreenPixelsPromise::Private> aPromise)
    
    970
    -        : mSourceRect(aSourceRect), mDestSize(aDestSize), mPromise(aPromise) {
    
    969
    +    explicit ScreenshotEvent(
    
    970
    +        gfx::IntRect aSourceRect,
    
    971
    +        RefPtr<layers::AndroidHardwareBuffer> aHardwareBuffer,
    
    972
    +        RefPtr<ScreenPixelsPromise::Private> aPromise)
    
    973
    +        : mSourceRect(aSourceRect),
    
    974
    +          mHardwareBuffer(std::move(aHardwareBuffer)),
    
    975
    +          mPromise(aPromise) {
    
    971 976
           MOZ_COUNT_CTOR(ScreenshotEvent);
    
    972 977
         }
    
    973 978
     
    
    ... ... @@ -977,8 +982,9 @@ RefPtr<WebRenderAPI::ScreenPixelsPromise> WebRenderAPI::RequestScreenPixels(
    977 982
           RendererOGL* const renderer = aRenderThread.GetRenderer(aWindowId);
    
    978 983
           if (!renderer) {
    
    979 984
             mPromise->Reject(NS_ERROR_FAILURE, __func__);
    
    985
    +        return;
    
    980 986
           }
    
    981
    -      renderer->RequestScreenPixels(mSourceRect, mDestSize)
    
    987
    +      renderer->RequestScreenPixels(mSourceRect, std::move(mHardwareBuffer))
    
    982 988
               ->ChainTo(mPromise.forget(), __func__);
    
    983 989
         }
    
    984 990
     
    
    ... ... @@ -986,12 +992,13 @@ RefPtr<WebRenderAPI::ScreenPixelsPromise> WebRenderAPI::RequestScreenPixels(
    986 992
     
    
    987 993
        private:
    
    988 994
         const gfx::IntRect mSourceRect;
    
    989
    -    const gfx::IntSize mDestSize;
    
    995
    +    RefPtr<layers::AndroidHardwareBuffer> mHardwareBuffer;
    
    990 996
         RefPtr<ScreenPixelsPromise::Private> mPromise;
    
    991 997
       };
    
    992 998
     
    
    993 999
       auto promise = MakeRefPtr<ScreenPixelsPromise::Private>(__func__);
    
    994
    -  auto event = MakeUnique<ScreenshotEvent>(aSourceRect, aDestSize, promise);
    
    1000
    +  auto event = MakeUnique<ScreenshotEvent>(aSourceRect,
    
    1001
    +                                           std::move(aHardwareBuffer), promise);
    
    995 1002
     
    
    996 1003
       RenderThread::Get()->PostEvent(mId, std::move(event));
    
    997 1004
       return promise;
    

  • gfx/webrender_bindings/WebRenderAPI.h
    ... ... @@ -322,13 +322,13 @@ class WebRenderAPI final {
    322 322
       RefPtr<EndRecordingPromise> EndRecording();
    
    323 323
     
    
    324 324
     #ifdef MOZ_WIDGET_ANDROID
    
    325
    -  using ScreenPixelsPromise =
    
    326
    -      MozPromise<RefPtr<layers::AndroidHardwareBuffer>, nsresult, true>;
    
    325
    +  using ScreenPixelsPromise = MozPromise<Ok, nsresult, true>;
    
    327 326
       // Queues a task to the render thread to capture screen pixels for the next
    
    328 327
       // rendered frame. Returns a promise that resolves once the pixels are
    
    329 328
       // captured.
    
    330
    -  RefPtr<ScreenPixelsPromise> RequestScreenPixels(gfx::IntRect aSourceRect,
    
    331
    -                                                  gfx::IntSize aDestSize);
    
    329
    +  RefPtr<ScreenPixelsPromise> RequestScreenPixels(
    
    330
    +      gfx::IntRect aSourceRect,
    
    331
    +      RefPtr<layers::AndroidHardwareBuffer> aHardwareBuffer);
    
    332 332
     #endif
    
    333 333
     
    
    334 334
       layers::RemoteTextureInfoList* GetPendingRemoteTextureInfoList();
    

  • mobile/android/android-components/components/feature/downloads/src/main/java/mozilla/components/feature/downloads/DownloadsFeature.kt
    ... ... @@ -122,6 +122,8 @@ value class OpenFileCallback(val value: () -> Unit)
    122 122
      * manager is provided, a dialog will be shown before every download.
    
    123 123
      * @property promptsStyling styling properties for the dialog.
    
    124 124
      * @property onDownloadStartedListener a callback invoked when a download is started.
    
    125
    + * @property dismissCustomFirstPartyDownloadDialog A callback invoked when the custom first party
    
    126
    + * download dialog should be dismissed.
    
    125 127
      * @property shouldForwardToThirdParties Indicates if downloads should be forward to third party apps,
    
    126 128
      * if there are multiple apps a chooser dialog will shown.
    
    127 129
      * @property customFirstPartyDownloadDialog An optional delegate for showing a dialog for a download
    
    ... ... @@ -145,6 +147,7 @@ class DownloadsFeature(
    145 147
         private val fragmentManager: FragmentManager? = null,
    
    146 148
         private val promptsStyling: PromptsStyling? = null,
    
    147 149
         private val onDownloadStartedListener: ((String) -> Unit) = {},
    
    150
    +    private val dismissCustomFirstPartyDownloadDialog: () -> Unit = {},
    
    148 151
         private val shouldForwardToThirdParties: () -> Boolean = { false },
    
    149 152
         private val customFirstPartyDownloadDialog: (
    
    150 153
             (
    
    ... ... @@ -555,6 +558,7 @@ class DownloadsFeature(
    555 558
         internal fun dismissAllDownloadDialogs() {
    
    556 559
             findPreviousDownloadDialogFragment()?.dismiss()
    
    557 560
             findPreviousAppDownloaderDialogFragment()?.dismiss()
    
    561
    +        dismissCustomFirstPartyDownloadDialog.invoke()
    
    558 562
         }
    
    559 563
     
    
    560 564
         private val ActivityInfo.identifier: String get() = packageName + name
    

  • mobile/android/android-components/components/feature/downloads/src/test/java/mozilla/components/feature/downloads/DownloadsFeatureTest.kt
    ... ... @@ -1513,6 +1513,64 @@ class DownloadsFeatureTest {
    1513 1513
             verify(cancelDownloadRequestUseCase).invoke(anyString(), anyString())
    
    1514 1514
         }
    
    1515 1515
     
    
    1516
    +    @Test
    
    1517
    +    fun `GIVEN a custom download dialog is used WHEN dismissAllDownloadDialogs is called THEN the dialog is dismissed`() = runTest(testDispatcher) {
    
    1518
    +        val dismissCustomDialog = mock<() -> Unit>()
    
    1519
    +        val feature = DownloadsFeature(
    
    1520
    +            testContext,
    
    1521
    +            store,
    
    1522
    +            useCases = DownloadsUseCases(store, mock()),
    
    1523
    +            downloadFileUtils = FakeDownloadFileUtils(),
    
    1524
    +            downloadManager = mock(),
    
    1525
    +            mainDispatcher = testDispatcher,
    
    1526
    +            dismissCustomFirstPartyDownloadDialog = dismissCustomDialog,
    
    1527
    +        )
    
    1528
    +
    
    1529
    +        feature.dismissAllDownloadDialogs()
    
    1530
    +
    
    1531
    +        verify(dismissCustomDialog).invoke()
    
    1532
    +    }
    
    1533
    +
    
    1534
    +    @Test
    
    1535
    +    fun `GIVEN a custom download dialog is used WHEN navigating to another website THEN the dialog is dismissed`() = runTest(testDispatcher) {
    
    1536
    +        val dismissCustomDialog = mock<() -> Unit>()
    
    1537
    +        val downloadsUseCases = spy(DownloadsUseCases(store, mock()))
    
    1538
    +        val cancelDownloadRequestUseCase = mock<CancelDownloadRequestUseCase>()
    
    1539
    +        val download = DownloadState(url = "https://www.mozilla.org", sessionId = "test-tab")
    
    1540
    +        store.dispatch(ContentAction.UpdateDownloadAction("test-tab", download = download))
    
    1541
    +
    
    1542
    +        doReturn(cancelDownloadRequestUseCase).`when`(downloadsUseCases).cancelDownloadRequest
    
    1543
    +
    
    1544
    +        val feature = spy(
    
    1545
    +            DownloadsFeature(
    
    1546
    +                testContext,
    
    1547
    +                store,
    
    1548
    +                useCases = downloadsUseCases,
    
    1549
    +                downloadFileUtils = FakeDownloadFileUtils(),
    
    1550
    +                downloadManager = mock(),
    
    1551
    +                mainDispatcher = testDispatcher,
    
    1552
    +                dismissCustomFirstPartyDownloadDialog = dismissCustomDialog,
    
    1553
    +            ),
    
    1554
    +        )
    
    1555
    +
    
    1556
    +        doReturn(true).`when`(feature).processDownload(any(), any())
    
    1557
    +
    
    1558
    +        feature.start()
    
    1559
    +        testDispatcher.scheduler.advanceUntilIdle()
    
    1560
    +
    
    1561
    +        store.dispatch(ContentAction.UpdateDownloadAction("test-tab", download = download))
    
    1562
    +        testDispatcher.scheduler.advanceUntilIdle()
    
    1563
    +
    
    1564
    +        grantPermissions()
    
    1565
    +
    
    1566
    +        val tab = createTab("https://www.firefox.com")
    
    1567
    +        store.dispatch(TabListAction.AddTabAction(tab, select = true))
    
    1568
    +        testDispatcher.scheduler.advanceUntilIdle()
    
    1569
    +
    
    1570
    +        verify(feature).dismissAllDownloadDialogs()
    
    1571
    +        verify(dismissCustomDialog).invoke()
    
    1572
    +    }
    
    1573
    +
    
    1516 1574
         @Test
    
    1517 1575
         fun `ResolveInfo to DownloaderApps`() = runTest(testDispatcher) {
    
    1518 1576
             val spyContext = spy(testContext)
    

  • mobile/android/android-components/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/SitePermissionsDialogFragment.kt
    ... ... @@ -32,6 +32,7 @@ import mozilla.components.support.base.log.logger.Logger
    32 32
     import mozilla.components.support.ktx.android.content.appName
    
    33 33
     import mozilla.components.support.ktx.kotlin.ifNullOrEmpty
    
    34 34
     import mozilla.components.support.ktx.util.PromptAbuserDetector
    
    35
    +import mozilla.components.support.utils.OnEnterAnimationCompleteListener
    
    35 36
     
    
    36 37
     internal const val KEY_SESSION_ID = "KEY_SESSION_ID"
    
    37 38
     internal const val KEY_TITLE = "KEY_TITLE"
    
    ... ... @@ -51,7 +52,9 @@ private const val KEY_IS_NOTIFICATION_REQUEST = "KEY_IS_NOTIFICATION_REQUEST"
    51 52
     private const val DEFAULT_VALUE = Int.MAX_VALUE
    
    52 53
     private const val KEY_PERMISSION_ID = "KEY_PERMISSION_ID"
    
    53 54
     
    
    54
    -internal open class SitePermissionsDialogFragment : NoObscuredTouchesDialogFragment() {
    
    55
    +internal open class SitePermissionsDialogFragment :
    
    56
    +    NoObscuredTouchesDialogFragment(),
    
    57
    +    OnEnterAnimationCompleteListener {
    
    55 58
     
    
    56 59
         private val logger = Logger("SitePermissionsDialogFragment")
    
    57 60
     
    
    ... ... @@ -134,6 +137,11 @@ internal open class SitePermissionsDialogFragment : NoObscuredTouchesDialogFragm
    134 137
             feature?.onDismiss(permissionRequestId, sessionId)
    
    135 138
         }
    
    136 139
     
    
    140
    +    override fun onEnterAnimationComplete() {
    
    141
    +        // Extend the positive button click delay.
    
    142
    +        promptAbuserDetector.updateJSDialogAbusedState()
    
    143
    +    }
    
    144
    +
    
    137 145
         private fun Dialog.setContainerView(rootView: View) {
    
    138 146
             if (dialogShouldWidthMatchParent) {
    
    139 147
                 setContentView(rootView)
    

  • mobile/android/android-components/components/support/utils/src/main/java/mozilla/components/support/utils/OnEnterAnimationCompleteListener.kt
    1
    +/* This Source Code Form is subject to the terms of the Mozilla Public
    
    2
    + * License, v. 2.0. If a copy of the MPL was not distributed with this
    
    3
    + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
    
    4
    +
    
    5
    +package mozilla.components.support.utils
    
    6
    +
    
    7
    +/**
    
    8
    + * Allows forwarding [android.app.Activity.onEnterAnimationComplete] to other classes
    
    9
    + * (e.g. fragments) that want to participate in handling it.
    
    10
    + */
    
    11
    +interface OnEnterAnimationCompleteListener {
    
    12
    +    /**
    
    13
    +     * Called when the Activity's entering animation has completed.
    
    14
    +     */
    
    15
    +    fun onEnterAnimationComplete()
    
    16
    +}

  • mobile/android/components/geckoview/GeckoViewContentChannelParent.cpp
    ... ... @@ -159,6 +159,11 @@ bool GeckoViewContentChannelParent::Init(
    159 159
     
    
    160 160
       nsCOMPtr<nsIURI> uri = ipc::DeserializeURI(aArgs.uri());
    
    161 161
     
    
    162
    +  if (!uri || !uri->SchemeIs("content")) {
    
    163
    +    rv = NS_ERROR_UNKNOWN_PROTOCOL;
    
    164
    +    return false;
    
    165
    +  }
    
    166
    +
    
    162 167
       nsAutoCString remoteType;
    
    163 168
       rv = GetRemoteType(remoteType);
    
    164 169
       if (MOZ_UNLIKELY(NS_FAILED(rv))) {
    

  • mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/ui/robots/DownloadRobot.kt
    ... ... @@ -29,6 +29,7 @@ import androidx.test.espresso.intent.matcher.IntentMatchers
    29 29
     import androidx.test.uiautomator.By
    
    30 30
     import androidx.test.uiautomator.UiSelector
    
    31 31
     import androidx.test.uiautomator.Until
    
    32
    +import mozilla.components.support.ktx.util.PromptAbuserDetector
    
    32 33
     import org.hamcrest.CoreMatchers.allOf
    
    33 34
     import org.mozilla.fenix.R
    
    34 35
     import org.mozilla.fenix.compose.snackbar.SNACKBAR_TEST_TAG
    
    ... ... @@ -257,7 +258,9 @@ class DownloadRobot(private val composeTestRule: ComposeTestRule) {
    257 258
         class Transition(private val composeTestRule: ComposeTestRule) {
    
    258 259
             fun clickDownload(composeTestRule: ComposeTestRule, interact: DownloadRobot.() -> Unit): Transition {
    
    259 260
                 Log.i(TAG, "clickDownload: Trying to click the \"Download\" download prompt button")
    
    261
    +            PromptAbuserDetector.validationsEnabled = false
    
    260 262
                 composeTestRule.downloadButton().performClick()
    
    263
    +            PromptAbuserDetector.validationsEnabled = true
    
    261 264
                 Log.i(TAG, "clickDownload: Clicked the \"Download\" download prompt button")
    
    262 265
     
    
    263 266
                 DownloadRobot(composeTestRule).interact()
    

  • mobile/android/fenix/app/src/main/java/org/mozilla/fenix/addons/AddonPopupBaseFragment.kt
    ... ... @@ -161,6 +161,10 @@ abstract class AddonPopupBaseFragment :
    161 161
                     onNeedToRequestPermissions = { permissions ->
    
    162 162
                         requestPermissions(permissions, REQUEST_CODE_DOWNLOAD_PERMISSIONS)
    
    163 163
                     },
    
    164
    +                dismissCustomFirstPartyDownloadDialog = {
    
    165
    +                    dismissRenameDialog()
    
    166
    +                    downloadDialog?.dismiss()
    
    167
    +                },
    
    164 168
                     customFirstPartyDownloadDialog = { currentDownloadState, _, positiveAction, negativeAction, _ ->
    
    165 169
                         run {
    
    166 170
                             if (canShowDownloadDialog()) {
    
    ... ... @@ -394,6 +398,13 @@ abstract class AddonPopupBaseFragment :
    394 398
             return downloadDialog == null && !isRenameFragmentShowing
    
    395 399
         }
    
    396 400
     
    
    401
    +    private fun dismissRenameDialog() {
    
    402
    +        val renameDialog = childFragmentManager.findFragmentByTag(
    
    403
    +            RenameAndChangeLocationDialogFragment.RENAME_AND_CHANGE_LOCATION_DIALOG_TAG,
    
    404
    +        ) as? RenameAndChangeLocationDialogFragment
    
    405
    +        renameDialog?.dismissAllowingStateLoss()
    
    406
    +    }
    
    407
    +
    
    397 408
         /**
    
    398 409
          * Forwards activity results to the [ActivityResultHandler] features.
    
    399 410
          */
    

  • mobile/android/fenix/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt
    ... ... @@ -742,6 +742,10 @@ abstract class BaseBrowserFragment :
    742 742
                 onNeedToRequestPermissions = { permissions ->
    
    743 743
                     requestPermissions(permissions, REQUEST_CODE_DOWNLOAD_PERMISSIONS)
    
    744 744
                 },
    
    745
    +            dismissCustomFirstPartyDownloadDialog = {
    
    746
    +                dismissRenameDialog()
    
    747
    +                dismissDownloadDialogs()
    
    748
    +            },
    
    745 749
                 customFirstPartyDownloadDialog = {
    
    746 750
                         currentDownloadState,
    
    747 751
                         fileNameIfAlreadyDownloaded,
    

  • mobile/android/fenix/app/src/main/java/org/mozilla/fenix/customtabs/ExternalAppBrowserActivity.kt
    ... ... @@ -11,6 +11,7 @@ import androidx.annotation.VisibleForTesting
    11 11
     import androidx.core.net.toUri
    
    12 12
     import mozilla.components.browser.state.selector.findCustomTab
    
    13 13
     import mozilla.components.browser.state.state.SessionState
    
    14
    +import mozilla.components.support.utils.OnEnterAnimationCompleteListener
    
    14 15
     import mozilla.components.support.utils.SafeIntent
    
    15 16
     import org.mozilla.fenix.HomeActivity
    
    16 17
     import org.mozilla.fenix.ext.components
    
    ... ... @@ -92,5 +93,14 @@ open class ExternalAppBrowserActivity : HomeActivity() {
    92 93
         override fun onEnterAnimationComplete() {
    
    93 94
             super.onEnterAnimationComplete()
    
    94 95
             isFinishedAnimating = true
    
    96
    +
    
    97
    +        val fragments = supportFragmentManager.fragments.toMutableList()
    
    98
    +        while (fragments.isNotEmpty()) {
    
    99
    +            val fragment = fragments.removeAt(0)
    
    100
    +            if (fragment is OnEnterAnimationCompleteListener) {
    
    101
    +                fragment.onEnterAnimationComplete()
    
    102
    +            }
    
    103
    +            fragments.addAll(fragment.childFragmentManager.fragments)
    
    104
    +        }
    
    95 105
         }
    
    96 106
     }

  • mobile/android/fenix/app/src/main/java/org/mozilla/fenix/downloads/RenameAndChangeLocationDialogFragment.kt
    ... ... @@ -20,6 +20,8 @@ import androidx.fragment.app.DialogFragment
    20 20
     import com.google.android.material.dialog.MaterialAlertDialogBuilder
    
    21 21
     import mozilla.components.concept.base.crash.Breadcrumb
    
    22 22
     import mozilla.components.support.base.log.logger.Logger
    
    23
    +import mozilla.components.support.ktx.util.PromptAbuserDetector
    
    24
    +import mozilla.components.support.utils.OnEnterAnimationCompleteListener
    
    23 25
     import org.mozilla.fenix.R
    
    24 26
     import org.mozilla.fenix.ext.components
    
    25 27
     import org.mozilla.fenix.ext.requireComponents
    
    ... ... @@ -38,10 +40,12 @@ import org.mozilla.fenix.theme.FirefoxTheme
    38 40
      *
    
    39 41
      * The callback [onConfirmSave] is invoked with the final file name and directory path.
    
    40 42
      */
    
    41
    -class RenameAndChangeLocationDialogFragment : DialogFragment() {
    
    43
    +class RenameAndChangeLocationDialogFragment : DialogFragment(), OnEnterAnimationCompleteListener {
    
    42 44
         private val logger = Logger("RenameAndChangeLocationDialogFragment")
    
    43 45
         private val safeArguments get() = requireNotNull(arguments)
    
    44 46
     
    
    47
    +    private val promptAbuserDetector = PromptAbuserDetector(TIME_SHOWN_OFFSET_MILLIS)
    
    48
    +
    
    45 49
         internal val fileName: String
    
    46 50
             get() = safeArguments.getString(KEY_FILE_NAME, "")
    
    47 51
     
    
    ... ... @@ -75,6 +79,15 @@ class RenameAndChangeLocationDialogFragment : DialogFragment() {
    75 79
             }
    
    76 80
         }
    
    77 81
     
    
    82
    +    override fun onResume() {
    
    83
    +        super.onResume()
    
    84
    +        promptAbuserDetector.start()
    
    85
    +    }
    
    86
    +
    
    87
    +    override fun onEnterAnimationComplete() {
    
    88
    +        promptAbuserDetector.start()
    
    89
    +    }
    
    90
    +
    
    78 91
         override fun onCancel(dialog: DialogInterface) {
    
    79 92
             super.onCancel(dialog)
    
    80 93
             onCancel()
    
    ... ... @@ -99,6 +112,8 @@ class RenameAndChangeLocationDialogFragment : DialogFragment() {
    99 112
     
    
    100 113
             val composeView = createComposeView()
    
    101 114
     
    
    115
    +        promptAbuserDetector.start()
    
    116
    +
    
    102 117
             return MaterialAlertDialogBuilder(requireContext())
    
    103 118
                 .setView(composeView)
    
    104 119
                 .create()
    
    ... ... @@ -144,11 +159,15 @@ class RenameAndChangeLocationDialogFragment : DialogFragment() {
    144 159
                                 directoryLauncher.launch(null)
    
    145 160
                             },
    
    146 161
                             onConfirm = {
    
    147
    -                            onConfirmSave(
    
    148
    -                                dialogState.fileName,
    
    149
    -                                dialogState.directoryPath,
    
    150
    -                            )
    
    151
    -                            dismiss()
    
    162
    +                            if (promptAbuserDetector.areDialogsBeingAbused()) {
    
    163
    +                                promptAbuserDetector.updateJSDialogAbusedState()
    
    164
    +                            } else {
    
    165
    +                                onConfirmSave(
    
    166
    +                                    dialogState.fileName,
    
    167
    +                                    dialogState.directoryPath,
    
    168
    +                                )
    
    169
    +                                dismiss()
    
    170
    +                            }
    
    152 171
                             },
    
    153 172
                             onCancel = {
    
    154 173
                                 onCancel()
    
    ... ... @@ -182,6 +201,7 @@ class RenameAndChangeLocationDialogFragment : DialogFragment() {
    182 201
             private const val KEY_DIRECTORY_PATH = "directory_path"
    
    183 202
             private const val KEY_CONTENT_SIZE = "content_size"
    
    184 203
             const val RENAME_AND_CHANGE_LOCATION_DIALOG_TAG = "RENAME_AND_CHANGE_LOCATION_DIALOG_TAG"
    
    204
    +        private const val TIME_SHOWN_OFFSET_MILLIS = 500
    
    185 205
     
    
    186 206
             /**
    
    187 207
              * Creates a new instance of [RenameAndChangeLocationDialogFragment].
    
    ... ... @@ -203,3 +223,14 @@ class RenameAndChangeLocationDialogFragment : DialogFragment() {
    203 223
             }
    
    204 224
         }
    
    205 225
     }
    
    226
    +
    
    227
    +/**
    
    228
    + * Starts (or restarts) the time-based check without increasing the "click count".
    
    229
    + *
    
    230
    + * Makes it safe to call from multiple/successive lifecycle methods, without running into the risk
    
    231
    + * of triggering the more restrictive count-based protection on the 1st click (or even before it).
    
    232
    + */
    
    233
    +private fun PromptAbuserDetector.start() {
    
    234
    +    resetJSAlertAbuseState()
    
    235
    +    updateJSDialogAbusedState()
    
    236
    +}

  • _______________________________________________
    tor-commits mailing list -- tor-commits@xxxxxxxxxxxxxxxxxxxx
    To unsubscribe send an email to tor-commits-leave@xxxxxxxxxxxxxxxxxxxx