diff --git a/api-samples/idle/README.md b/api-samples/idle/README.md new file mode 100644 index 00000000..bf92ebb5 --- /dev/null +++ b/api-samples/idle/README.md @@ -0,0 +1,19 @@ +# chrome.idle + +This sample demonstrates how to use the [`chrome.idle`](https://developer.chrome.com/docs/extensions/reference/idle/) API. + +## Overview + +In this sample, the `chrome.idle` API detects and stores the history of the user's idle state. + +## Implementation Notes + +The detection interval of [`chrome.idle.onStateChanged`](https://developer.chrome.com/docs/extensions/reference/idle/#event-onStateChanged) event needs to be modified using the [`chrome.idle.setDetectionInterval`](https://developer.chrome.com/docs/extensions/reference/idle/#method-setDetectionInterval) method. + +The idle state history is stored in the [`chrome.storage.session`](https://developer.chrome.com/docs/extensions/reference/storage/#property-session) storage area. + +## Running this extension + +1. Clone this repository. +2. Load this directory in Chrome as an [unpacked extension](https://developer.chrome.com/docs/extensions/mv3/getstarted/development-basics/#load-unpacked). +3. Click the extension's action icon to open the window. diff --git a/api-samples/idle/history.html b/api-samples/idle/history.html new file mode 100644 index 00000000..ddabf029 --- /dev/null +++ b/api-samples/idle/history.html @@ -0,0 +1,41 @@ + + + + + + + +

Idle API Demonstration

+

Current state

+

+ Idle threshold: + +

+ +

+ chrome.idle.queryState(, + ...); + - + +

+

Last state change:

+ +

Idle changes:

+ + + + diff --git a/api-samples/idle/history.js b/api-samples/idle/history.js new file mode 100644 index 00000000..c2c41062 --- /dev/null +++ b/api-samples/idle/history.js @@ -0,0 +1,102 @@ +/** + * Convert a state and time into a nice styled chunk of HTML. + */ +function renderState(state, time) { + const now = Date.now(); + const diff = Math.round((time - now) / 1000); + const str = + diff == 0 + ? 'now' + : Math.abs(diff) + ' seconds ' + (diff > 0 ? 'from now' : 'ago'); + const col = state == 'active' ? '#009900' : '#990000'; + return "" + state + ' ' + str; +} + +/** + * Creates DOM and injects a rendered state into the page. + */ +function renderItem(state, time, parent) { + const dom_item = document.createElement('li'); + dom_item.innerHTML = renderState(state, time); + parent.appendChild(dom_item); +} + +// Store previous state so we can show deltas. This is important +// because the API currently doesn't fire idle messages, and we'd +// like to keep track of last time we went idle. +let laststate = null; +let laststatetime = null; + +/** + * Checks the current state of the browser. + */ +async function checkState() { + const threshold = parseInt(document.querySelector('#idle-threshold').value); + const dom_threshold = document.querySelector('#idle-set-threshold'); + dom_threshold.innerText = threshold; + + // Request the state based off of the user-supplied threshold. + chrome.idle.queryState(threshold, function (state) { + const time = new Date(); + if (laststate != state) { + laststate = state; + laststatetime = time; + } + + // Keep rendering results so we get a nice "seconds elapsed" view. + const dom_result = document.querySelector('#idle-state'); + dom_result.innerHTML = renderState(state, time); + const dom_laststate = document.querySelector('#idle-laststate'); + dom_laststate.innerHTML = renderState(laststate, laststatetime); + }); +} + +/** + * Render the data gathered by the background service worker - should show a log + * of "active" states. + */ +async function renderHistory() { + const dom_history = document.querySelector('#idle-history'); + dom_history.innerHTML = ''; + const { history_log } = await chrome.storage.session.get(['history_log']); + if (!history_log) { + return; + } + + for (let i = 0; i < history_log.length; i++) { + const data = history_log[i]; + renderItem(data['state'], data['time'], dom_history); + } +} + +document.addEventListener('DOMContentLoaded', async function () { + // Set the threshold to the last value the user set, or 15 if not set. + let { threshold: stored_threshold } = await chrome.storage.local.get([ + 'threshold' + ]); + if (!stored_threshold || ![15, 30, 60].includes(stored_threshold)) { + stored_threshold = 15; + } + + document.querySelector( + `#idle-threshold option[value="${stored_threshold}"]` + ).selected = true; + chrome.idle.setDetectionInterval(stored_threshold); + + document + .querySelector('#idle-threshold') + .addEventListener('change', function (e) { + const threshold = parseInt(e.target.value); + chrome.storage.local.set({ threshold: threshold }); + chrome.idle.setDetectionInterval(threshold); + }); + + // Check every second (even though this is overkill - minimum idle + // threshold is 15 seconds) so that the numbers appear to be counting up. + checkState(); + window.setInterval(checkState, 1000); + + // Check every second (see above). + renderHistory(); + window.setInterval(renderHistory, 1000); +}); diff --git a/api-samples/idle/manifest.json b/api-samples/idle/manifest.json new file mode 100644 index 00000000..cf777d0f --- /dev/null +++ b/api-samples/idle/manifest.json @@ -0,0 +1,18 @@ +{ + "name": "Idle - Simple Example", + "version": "1.0.1", + "description": "Demonstrates the Idle API", + "background": { + "service_worker": "service-worker.js" + }, + "permissions": ["idle", "storage"], + "action": { + "default_icon": "sample-19.png" + }, + "icons": { + "16": "sample-16.png", + "48": "sample-48.png", + "128": "sample-128.png" + }, + "manifest_version": 3 +} diff --git a/api-samples/idle/sample-128.png b/api-samples/idle/sample-128.png new file mode 100644 index 00000000..96be429f Binary files /dev/null and b/api-samples/idle/sample-128.png differ diff --git a/api-samples/idle/sample-16.png b/api-samples/idle/sample-16.png new file mode 100644 index 00000000..5308fc97 Binary files /dev/null and b/api-samples/idle/sample-16.png differ diff --git a/api-samples/idle/sample-19.png b/api-samples/idle/sample-19.png new file mode 100644 index 00000000..108b2a77 Binary files /dev/null and b/api-samples/idle/sample-19.png differ diff --git a/api-samples/idle/sample-48.png b/api-samples/idle/sample-48.png new file mode 100644 index 00000000..a732e383 Binary files /dev/null and b/api-samples/idle/sample-48.png differ diff --git a/api-samples/idle/service-worker.js b/api-samples/idle/service-worker.js new file mode 100644 index 00000000..8c3473b8 --- /dev/null +++ b/api-samples/idle/service-worker.js @@ -0,0 +1,27 @@ +/** + * Stores a state every time it changes, up to 20 items. + */ +chrome.idle.onStateChanged.addListener(async function (newstate) { + let { history_log } = await chrome.storage.session.get(['history_log']); + if (!history_log) { + history_log = []; + } + const time = Date.now(); + if (history_log.length >= 20) { + history_log.pop(); + } + history_log.unshift({ state: newstate, time: time }); + chrome.storage.session.set({ history_log: history_log }); +}); + +/** + * Opens history.html when the browser action is clicked. + */ +chrome.action.onClicked.addListener(function () { + chrome.windows.create({ + url: 'history.html', + width: 700, + height: 600, + type: 'popup' + }); +});