Activating tab and taking its screenshot in Android is not working well (shot took before tab is active)

I have a problem with the following code:

await browser.tabs.update(tab.id, {active: true});
const shot = await browser.tabs.captureVisibleTab(tab.windowId, {format: 'png'});

This works well on Desktop Firefox and Chrome, but on Firefox for Android this will always take a screenshot of current tab. If I place some timeout (delay) before the shooting, it will work.

Is there some hotfix for awaiting tab activation in Android?

EDIT:
Hotfix is ready :smiley::

while ((await getActiveTab()).id !== tab.id) {
  console.warn('TAB IS STILL NOT ACTIVE');
  await timeoutPromise(1);
}

And this is what I see in the console:

15:26:59.647 TAB IS STILL NOT ACTIVE screen.ts:23:18
15:26:59.649 TAB IS STILL NOT ACTIVE
15:26:59.666 TAB IS STILL NOT ACTIVE screen.ts:23:18
15:26:59.667 TAB IS STILL NOT ACTIVE
15:26:59.678 TAB IS STILL NOT ACTIVE screen.ts:23:18
15:26:59.680 TAB IS STILL NOT ACTIVE
15:26:59.691 TAB IS STILL NOT ACTIVE screen.ts:23:18
15:26:59.693 TAB IS STILL NOT ACTIVE
15:26:59.705 TAB IS STILL NOT ACTIVE screen.ts:23:18
15:26:59.706 TAB IS STILL NOT ACTIVE
15:26:59.727 TAB IS STILL NOT ACTIVE screen.ts:23:18
15:26:59.729 TAB IS STILL NOT ACTIVE
15:26:59.743 TAB IS STILL NOT ACTIVE screen.ts:23:18
15:26:59.744 TAB IS STILL NOT ACTIVE
15:26:59.759 TAB IS STILL NOT ACTIVE screen.ts:23:18
15:26:59.760 TAB IS STILL NOT ACTIVE
15:26:59.768 TAB IS STILL NOT ACTIVE screen.ts:23:18
15:26:59.769 TAB IS STILL NOT ACTIVE
15:26:59.786 TAB IS STILL NOT ACTIVE screen.ts:23:18
15:26:59.787 TAB IS STILL NOT ACTIVE
15:26:59.803 TAB IS STILL NOT ACTIVE screen.ts:23:18
15:26:59.805 TAB IS STILL NOT ACTIVE
15:26:59.824 TAB IS STILL NOT ACTIVE screen.ts:23:18
15:26:59.826 TAB IS STILL NOT ACTIVE
15:26:59.837 TAB IS STILL NOT ACTIVE screen.ts:23:18
15:26:59.837 TAB IS STILL NOT ACTIVE
15:26:59.863 TAB IS STILL NOT ACTIVE screen.ts:23:18
15:26:59.866 TAB IS STILL NOT ACTIVE
15:26:59.884 TAB IS STILL NOT ACTIVE screen.ts:23:18
15:26:59.884 TAB IS STILL NOT ACTIVE
15:26:59.893 TAB IS STILL NOT ACTIVE screen.ts:23:18
15:26:59.894 TAB IS STILL NOT ACTIVE
15:26:59.900 TAB IS STILL NOT ACTIVE screen.ts:23:18
15:26:59.901 TAB IS STILL NOT ACTIVE
15:26:59.908 TAB IS STILL NOT ACTIVE screen.ts:23:18
15:26:59.909 TAB IS STILL NOT ACTIVE
15:26:59.917 TAB IS STILL NOT ACTIVE screen.ts:23:18
15:26:59.918 TAB IS STILL NOT ACTIVE
15:26:59.933 TAB IS STILL NOT ACTIVE screen.ts:23:18
15:26:59.945 TAB IS STILL NOT ACTIVE

As you can see, it takes almost 300ms to actually activate the tab!

EDIT 2:
I’ve filed a new bug for this.

Yeah, sounds like a bug… but about the hot-fix: Have you tried using the onActivated event instead of waiting? https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/onActivated
Looking at your time-stamps, this seems to be a millisecond timeout. This might lead to bad performance depending on the situation or worse: If, for some reason, your tab never gets activated properly, this will loop forever.

I haven’t tried onActivated event, it feels too complex to register and then unregister event handler (but good idea).

Regarding infinite loop - yes, this was just “proof of concept” version, my final version is this:

export async function activateTab(tabOrId: browser.tabs.Tab | number) {
  const tabId = isObject(tabOrId) ? tabOrId.id! : tabOrId;
  const result = await browser.tabs.update(tabId, {active: true});
  // NOTE: this whole block is a hotfix for Android where awaiting tab activation is not really waiting for tab to get active! See: https://bugzilla.mozilla.org/show_bug.cgi?id=1592634
  if (await IS_ANDROID_FN()) {
    let i = 0;
    while ((await getActiveTab()).id !== tabId) {
      if (i++ > 100) break;   // prevent infinite loop!
      console.warn('TAB IS STILL NOT ACTIVE');
      await browser.tabs.update(tabId, {active: true});
      await timeoutPromise(50);
    }
  }
  return result;
}

…yeah, talking about complexity :smiley:, but it’s straightforward!

Also timeouts should be throttled to fire only every x ms:

So even if you write evil code like while (true) { setTimeout(() => {}, 0) }, it won’t affect your performance at all, because it’s actually only being executed every x ms.

Anyway, now when the Firefox for Android is reaching EOL, it’s probably not worth spending more time fixing this :slight_smile:…