summaryrefslogtreecommitdiffstats
path: root/toolkit/components/extensions/parent/ext-idle.js
blob: f68ea293d7f608fb51d2351912825ac643501277 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

XPCOMUtils.defineLazyServiceGetter(
  this,
  "idleService",
  "@mozilla.org/widget/useridleservice;1",
  "nsIUserIdleService"
);

var { DefaultWeakMap } = ExtensionUtils;

// WeakMap[Extension -> Object]
const idleObserversMap = new DefaultWeakMap(() => {
  return {
    observer: null,
    detectionInterval: 60,
  };
});

const getIdleObserver = extension => {
  let observerInfo = idleObserversMap.get(extension);
  let { observer, detectionInterval } = observerInfo;
  let interval =
    extension.startupData?.idleDetectionInterval || detectionInterval;

  if (!observer) {
    observer = new (class extends ExtensionCommon.EventEmitter {
      observe(subject, topic, data) {
        if (topic == "idle" || topic == "active") {
          this.emit("stateChanged", topic);
        }
      }
    })();
    idleService.addIdleObserver(observer, interval);
    observerInfo.observer = observer;
    observerInfo.detectionInterval = interval;
  }
  return observer;
};

this.idle = class extends ExtensionAPIPersistent {
  PERSISTENT_EVENTS = {
    onStateChanged({ fire }) {
      let { extension } = this;
      let listener = (event, data) => {
        fire.sync(data);
      };

      getIdleObserver(extension).on("stateChanged", listener);
      return {
        async unregister() {
          let observerInfo = idleObserversMap.get(extension);
          let { observer, detectionInterval } = observerInfo;
          if (observer) {
            observer.off("stateChanged", listener);
            if (!observer.has("stateChanged")) {
              idleService.removeIdleObserver(observer, detectionInterval);
              observerInfo.observer = null;
            }
          }
        },
        convert(_fire) {
          fire = _fire;
        },
      };
    },
  };

  getAPI(context) {
    let { extension } = context;
    let self = this;

    return {
      idle: {
        queryState(detectionIntervalInSeconds) {
          if (idleService.idleTime < detectionIntervalInSeconds * 1000) {
            return "active";
          }
          return "idle";
        },
        setDetectionInterval(detectionIntervalInSeconds) {
          let observerInfo = idleObserversMap.get(extension);
          let { observer, detectionInterval } = observerInfo;
          if (detectionInterval == detectionIntervalInSeconds) {
            return;
          }
          if (observer) {
            idleService.removeIdleObserver(observer, detectionInterval);
            idleService.addIdleObserver(observer, detectionIntervalInSeconds);
          }
          observerInfo.detectionInterval = detectionIntervalInSeconds;
          // There is no great way to modify a persistent listener param, but we
          // need to keep this for the startup listener.
          if (!extension.persistentBackground) {
            extension.startupData.idleDetectionInterval =
              detectionIntervalInSeconds;
            extension.saveStartupData();
          }
        },
        onStateChanged: new EventManager({
          context,
          module: "idle",
          event: "onStateChanged",
          extensionApi: self,
        }).api(),
      },
    };
  }
};