New issue
Advanced search Search tips

Issue 919017 link

Starred by 1 user

Issue metadata

Status: Assigned
Owner:
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Linux , Android , Windows , Chrome , Mac
Pri: 2
Type: Bug



Sign in to add a comment

User Activation v2: Consuming a user gesture consumes *all* the available user gestures

Project Member Reported by mgiuca@chromium.org, Jan 4

Issue description

Chrome Version: 72
OS: All

(Originally reported in  https://crbug.com/916906#c9 )

What steps will reproduce the problem?
(1) Open the attached test page.
(2) Click "Open Google", then quickly click "Open Bing" (less than 500 milliseconds apart).

(Note that each of these buttons is wired up to open a popup after a 500 ms timeout.)

What is the expected result?
Each button click opens its respective popup after 500 ms.


What happens instead?
Only the first popup opens. The second one is blocked by the popup blocker due to no user gesture.

Discussion:
Under User Activation v1 (flag #user-activation-v2 disabled), this worked as intended. Each click event had its own user gesture, which is correctly propagated through the setTimeout, and then consumed by the corresponding call to window.open.

In UAv2, there is (as I understand it), a single global Boolean user gesture token. Thus the sequence is:

  1. Click "Open Google". Global token is set to true.
  2. Click "Open Bing". Global token is set to true (no change).
  3. window.open('google.com'). Checks token (true), and consumes it (sets to false).
  4. window.open('bing.com'). Checks token (false). Popup blocked.

Basically, two unrelated threads of execution are interfering with one another, because of the shared global gesture token. It should be the case that each click allows the site to open 1 popup within 1000 ms.

Suggested solution:

Instead of a global Boolean or counter, there should be a global queue of 1000-ms timers.

- Every time the user sends a gesture, enqueue a new 1000-ms timer onto the end of the queue, and start it ticking.
- When a timer elapses (which will always be the one at the front of the queue), remove it from the queue.
- When an API needs to check if user activation is allowed, check whether the queue is non-empty.
- When an API needs to consume a user activation, pop the (non-elapsed) timer from the front of the queue.

(Other non-workable ideas are: a single global counter, where each click increments the counter and each consumption decrements it. Flaw: If the user clicks 50 times, the page can later open 50 popups. A single global counter + single global 1000 ms timer, where if the timer expires, it resets the counter. Flaw: If the user clicks 50 times once every 500 ms, for 25 seconds, the page can open 50 popups all at the end.)

Thus, we establish a 1:1 relationship between gestures and gesture consumption. If the user clicks 3 times, the site can show 3 popups as long as each popup is opened within 1000 ms of the corresponding click. The site cannot "store" the gestures for later and open a flurry of popups. If the user clicks 50 times in 500 ms, the site can open a popup one second later after each click, but that's OK because the user will presumably notice the popups and stop clicking. This proposed model exactly matches the behaviour that the site could do anyway under UAv1.
 
test.html
745 bytes View Download
Labels: UserActivation

Sign in to add a comment