Skip to content

Commit

Permalink
Add idle sample (GoogleChrome#961)
Browse files Browse the repository at this point in the history
* Add idle sample

* Fix typo

* Fix onStateChanged threshold

* Add README.md

* Update file structure

* Remove tabs permission

* Update api-samples/idle/README.md

Co-authored-by: amysteamdev <[email protected]>

* Update api-samples/idle/service-worker.js

Co-authored-by: amysteamdev <[email protected]>

* Update api-samples/idle/README.md

Co-authored-by: amysteamdev <[email protected]>

* Update api-samples/idle/README.md

Co-authored-by: amysteamdev <[email protected]>

---------

Co-authored-by: amysteamdev <[email protected]>
  • Loading branch information
daidr and AmySteam authored Jul 7, 2023
1 parent b4a0184 commit 50e377c
Show file tree
Hide file tree
Showing 9 changed files with 207 additions and 0 deletions.
19 changes: 19 additions & 0 deletions api-samples/idle/README.md
Original file line number Diff line number Diff line change
@@ -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.
41 changes: 41 additions & 0 deletions api-samples/idle/history.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<!DOCTYPE html>
<html>
<head>
<style>
body {
width: 100%;
margin: 0;
padding: 0 1em;
box-sizing: border-box;
font: 13px Arial;
}
</style>
</head>

<body>
<h1>Idle API Demonstration</h1>
<h2>Current state</h2>
<p>
Idle threshold:
<select id="idle-threshold">
<option selected value="15">15</option>
<option value="30">30</option>
<option value="60">60</option>
</select>
</p>

<p>
<code
>chrome.idle.queryState(<strong id="idle-set-threshold"></strong>,
...);</code
>
-
<span id="idle-state"></span>
</p>
<p>Last state change: <span id="idle-laststate"></span></p>

<h2>Idle changes:</h2>
<ul id="idle-history"></ul>
<script src="history.js"></script>
</body>
</html>
102 changes: 102 additions & 0 deletions api-samples/idle/history.js
Original file line number Diff line number Diff line change
@@ -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 "<b style='color: " + col + "'>" + state + '</b> ' + 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);
});
18 changes: 18 additions & 0 deletions api-samples/idle/manifest.json
Original file line number Diff line number Diff line change
@@ -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
}
Binary file added api-samples/idle/sample-128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added api-samples/idle/sample-16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added api-samples/idle/sample-19.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added api-samples/idle/sample-48.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 27 additions & 0 deletions api-samples/idle/service-worker.js
Original file line number Diff line number Diff line change
@@ -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'
});
});

0 comments on commit 50e377c

Please sign in to comment.