summaryrefslogtreecommitdiffstats
path: root/mobile/android/modules/HomeProvider.jsm
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/modules/HomeProvider.jsm')
-rw-r--r--mobile/android/modules/HomeProvider.jsm407
1 files changed, 0 insertions, 407 deletions
diff --git a/mobile/android/modules/HomeProvider.jsm b/mobile/android/modules/HomeProvider.jsm
deleted file mode 100644
index bca8fa526..000000000
--- a/mobile/android/modules/HomeProvider.jsm
+++ /dev/null
@@ -1,407 +0,0 @@
-// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
-/* 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";
-
-this.EXPORTED_SYMBOLS = [ "HomeProvider" ];
-
-const { utils: Cu, classes: Cc, interfaces: Ci } = Components;
-
-Cu.import("resource://gre/modules/Messaging.jsm");
-Cu.import("resource://gre/modules/osfile.jsm");
-Cu.import("resource://gre/modules/Promise.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/Sqlite.jsm");
-Cu.import("resource://gre/modules/Task.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-/*
- * SCHEMA_VERSION history:
- * 1: Create HomeProvider (bug 942288)
- * 2: Add filter column to items table (bug 942295/975841)
- * 3: Add background_color and background_url columns (bug 1157539)
- */
-const SCHEMA_VERSION = 3;
-
-// The maximum number of items you can attempt to save at once.
-const MAX_SAVE_COUNT = 100;
-
-XPCOMUtils.defineLazyGetter(this, "DB_PATH", function() {
- return OS.Path.join(OS.Constants.Path.profileDir, "home.sqlite");
-});
-
-const PREF_STORAGE_LAST_SYNC_TIME_PREFIX = "home.storage.lastSyncTime.";
-const PREF_SYNC_UPDATE_MODE = "home.sync.updateMode";
-const PREF_SYNC_CHECK_INTERVAL_SECS = "home.sync.checkIntervalSecs";
-
-XPCOMUtils.defineLazyGetter(this, "gSyncCheckIntervalSecs", function() {
- return Services.prefs.getIntPref(PREF_SYNC_CHECK_INTERVAL_SECS);
-});
-
-XPCOMUtils.defineLazyServiceGetter(this,
- "gUpdateTimerManager", "@mozilla.org/updates/timer-manager;1", "nsIUpdateTimerManager");
-
-/**
- * All SQL statements should be defined here.
- */
-const SQL = {
- createItemsTable:
- "CREATE TABLE items (" +
- "_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
- "dataset_id TEXT NOT NULL, " +
- "url TEXT," +
- "title TEXT," +
- "description TEXT," +
- "image_url TEXT," +
- "background_color TEXT," +
- "background_url TEXT," +
- "filter TEXT," +
- "created INTEGER" +
- ")",
-
- dropItemsTable:
- "DROP TABLE items",
-
- insertItem:
- "INSERT INTO items (dataset_id, url, title, description, image_url, background_color, background_url, filter, created) " +
- "VALUES (:dataset_id, :url, :title, :description, :image_url, :background_color, :background_url, :filter, :created)",
-
- deleteFromDataset:
- "DELETE FROM items WHERE dataset_id = :dataset_id",
-
- addColumnBackgroundColor:
- "ALTER TABLE items ADD COLUMN background_color TEXT",
-
- addColumnBackgroundUrl:
- "ALTER TABLE items ADD COLUMN background_url TEXT",
-}
-
-/**
- * Technically this function checks to see if the user is on a local network,
- * but we express this as "wifi" to the user.
- */
-function isUsingWifi() {
- let network = Cc["@mozilla.org/network/network-link-service;1"].getService(Ci.nsINetworkLinkService);
- return (network.linkType === Ci.nsINetworkLinkService.LINK_TYPE_WIFI || network.linkType === Ci.nsINetworkLinkService.LINK_TYPE_ETHERNET);
-}
-
-function getNowInSeconds() {
- return Math.round(Date.now() / 1000);
-}
-
-function getLastSyncPrefName(datasetId) {
- return PREF_STORAGE_LAST_SYNC_TIME_PREFIX + datasetId;
-}
-
-// Whether or not we've registered an update timer.
-var gTimerRegistered = false;
-
-// Map of datasetId -> { interval: <integer>, callback: <function> }
-var gSyncCallbacks = {};
-
-/**
- * nsITimerCallback implementation. Checks to see if it's time to sync any registered datasets.
- *
- * @param timer The timer which has expired.
- */
-function syncTimerCallback(timer) {
- for (let datasetId in gSyncCallbacks) {
- let lastSyncTime = 0;
- try {
- lastSyncTime = Services.prefs.getIntPref(getLastSyncPrefName(datasetId));
- } catch(e) { }
-
- let now = getNowInSeconds();
- let { interval: interval, callback: callback } = gSyncCallbacks[datasetId];
-
- if (lastSyncTime < now - interval) {
- let success = HomeProvider.requestSync(datasetId, callback);
- if (success) {
- Services.prefs.setIntPref(getLastSyncPrefName(datasetId), now);
- }
- }
- }
-}
-
-this.HomeStorage = function(datasetId) {
- this.datasetId = datasetId;
-};
-
-this.ValidationError = function(message) {
- this.name = "ValidationError";
- this.message = message;
-};
-ValidationError.prototype = new Error();
-ValidationError.prototype.constructor = ValidationError;
-
-this.HomeProvider = Object.freeze({
- ValidationError: ValidationError,
-
- /**
- * Returns a storage associated with a given dataset identifer.
- *
- * @param datasetId
- * (string) Unique identifier for the dataset.
- *
- * @return HomeStorage
- */
- getStorage: function(datasetId) {
- return new HomeStorage(datasetId);
- },
-
- /**
- * Checks to see if it's an appropriate time to sync.
- *
- * @param datasetId Unique identifier for the dataset to sync.
- * @param callback Function to call when it's time to sync, called with datasetId as a parameter.
- *
- * @return boolean Whether or not we were able to sync.
- */
- requestSync: function(datasetId, callback) {
- // Make sure it's a good time to sync.
- if ((Services.prefs.getIntPref(PREF_SYNC_UPDATE_MODE) === 1) && !isUsingWifi()) {
- Cu.reportError("HomeProvider: Failed to sync because device is not on a local network");
- return false;
- }
-
- callback(datasetId);
- return true;
- },
-
- /**
- * Specifies that a sync should be requested for the given dataset and update interval.
- *
- * @param datasetId Unique identifier for the dataset to sync.
- * @param interval Update interval in seconds. By default, this is throttled to 3600 seconds (1 hour).
- * @param callback Function to call when it's time to sync, called with datasetId as a parameter.
- */
- addPeriodicSync: function(datasetId, interval, callback) {
- // Warn developers if they're expecting more frequent notifications that we allow.
- if (interval < gSyncCheckIntervalSecs) {
- Cu.reportError("HomeProvider: Warning for dataset " + datasetId +
- " : Sync notifications are throttled to " + gSyncCheckIntervalSecs + " seconds");
- }
-
- gSyncCallbacks[datasetId] = {
- interval: interval,
- callback: callback
- };
-
- if (!gTimerRegistered) {
- gUpdateTimerManager.registerTimer("home-provider-sync-timer", syncTimerCallback, gSyncCheckIntervalSecs);
- gTimerRegistered = true;
- }
- },
-
- /**
- * Removes a periodic sync timer.
- *
- * @param datasetId Dataset to sync.
- */
- removePeriodicSync: function(datasetId) {
- delete gSyncCallbacks[datasetId];
- Services.prefs.clearUserPref(getLastSyncPrefName(datasetId));
- // You can't unregister a update timer, so we don't try to do that.
- }
-});
-
-var gDatabaseEnsured = false;
-
-/**
- * Creates the database schema.
- */
-function createDatabase(db) {
- return Task.spawn(function create_database_task() {
- yield db.execute(SQL.createItemsTable);
- });
-}
-
-/**
- * Migrates the database schema to a new version.
- */
-function upgradeDatabase(db, oldVersion, newVersion) {
- return Task.spawn(function upgrade_database_task() {
- switch (oldVersion) {
- case 1:
- // Migration from v1 to latest:
- // Recreate the items table discarding any
- // existing data.
- yield db.execute(SQL.dropItemsTable);
- yield db.execute(SQL.createItemsTable);
- break;
-
- case 2:
- // Migration from v2 to latest:
- // Add new columns: background_color, background_url
- yield db.execute(SQL.addColumnBackgroundColor);
- yield db.execute(SQL.addColumnBackgroundUrl);
- break;
- }
- });
-}
-
-/**
- * Opens a database connection and makes sure that the database schema version
- * is correct, performing migrations if necessary. Consumers should be sure
- * to close any database connections they open.
- *
- * @return Promise
- * @resolves Handle on an opened SQLite database.
- */
-function getDatabaseConnection() {
- return Task.spawn(function get_database_connection_task() {
- let db = yield Sqlite.openConnection({ path: DB_PATH });
- if (gDatabaseEnsured) {
- throw new Task.Result(db);
- }
-
- try {
- // Check to see if we need to perform any migrations.
- let dbVersion = parseInt(yield db.getSchemaVersion());
-
- // getSchemaVersion() returns a 0 int if the schema
- // version is undefined.
- if (dbVersion === 0) {
- yield createDatabase(db);
- } else if (dbVersion < SCHEMA_VERSION) {
- yield upgradeDatabase(db, dbVersion, SCHEMA_VERSION);
- }
-
- yield db.setSchemaVersion(SCHEMA_VERSION);
- } catch(e) {
- // Close the DB connection before passing the exception to the consumer.
- yield db.close();
- throw e;
- }
-
- gDatabaseEnsured = true;
- throw new Task.Result(db);
- });
-}
-
-/**
- * Validates an item to be saved to the DB.
- *
- * @param item
- * (object) item object to be validated.
- */
-function validateItem(datasetId, item) {
- if (!item.url) {
- throw new ValidationError('HomeStorage: All rows must have an URL: datasetId = ' +
- datasetId);
- }
-
- if (!item.image_url && !item.title && !item.description) {
- throw new ValidationError('HomeStorage: All rows must have at least an image URL, ' +
- 'or a title or a description: datasetId = ' + datasetId);
- }
-}
-
-var gRefreshTimers = {};
-
-/**
- * Sends a message to Java to refresh the given dataset. Delays sending
- * messages to avoid successive refreshes, which can result in flashing views.
- */
-function refreshDataset(datasetId) {
- // Bail if there's already a refresh timer waiting to fire
- if (gRefreshTimers[datasetId]) {
- return;
- }
-
- let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
- timer.initWithCallback(function(timer) {
- delete gRefreshTimers[datasetId];
-
- Messaging.sendRequest({
- type: "HomePanels:RefreshDataset",
- datasetId: datasetId
- });
- }, 100, Ci.nsITimer.TYPE_ONE_SHOT);
-
- gRefreshTimers[datasetId] = timer;
-}
-
-HomeStorage.prototype = {
- /**
- * Saves data rows to the DB.
- *
- * @param data
- * An array of JS objects represnting row items to save.
- * Each object may have the following properties:
- * - url (string)
- * - title (string)
- * - description (string)
- * - image_url (string)
- * - filter (string)
- * @param options
- * A JS object holding additional cofiguration properties.
- * The following properties are currently supported:
- * - replace (boolean): Whether or not to replace existing items.
- *
- * @return Promise
- * @resolves When the operation has completed.
- */
- save: function(data, options) {
- if (data && data.length > MAX_SAVE_COUNT) {
- throw "save failed for dataset = " + this.datasetId +
- ": you cannot save more than " + MAX_SAVE_COUNT + " items at once";
- }
-
- return Task.spawn(function save_task() {
- let db = yield getDatabaseConnection();
- try {
- yield db.executeTransaction(function save_transaction() {
- if (options && options.replace) {
- yield db.executeCached(SQL.deleteFromDataset, { dataset_id: this.datasetId });
- }
-
- // Insert data into DB.
- for (let item of data) {
- validateItem(this.datasetId, item);
-
- // XXX: Directly pass item as params? More validation for item?
- let params = {
- dataset_id: this.datasetId,
- url: item.url,
- title: item.title,
- description: item.description,
- image_url: item.image_url,
- background_color: item.background_color,
- background_url: item.background_url,
- filter: item.filter,
- created: Date.now()
- };
- yield db.executeCached(SQL.insertItem, params);
- }
- }.bind(this));
- } finally {
- yield db.close();
- }
-
- refreshDataset(this.datasetId);
- }.bind(this));
- },
-
- /**
- * Deletes all rows associated with this storage.
- *
- * @return Promise
- * @resolves When the operation has completed.
- */
- deleteAll: function() {
- return Task.spawn(function delete_all_task() {
- let db = yield getDatabaseConnection();
- try {
- let params = { dataset_id: this.datasetId };
- yield db.executeCached(SQL.deleteFromDataset, params);
- } finally {
- yield db.close();
- }
-
- refreshDataset(this.datasetId);
- }.bind(this));
- }
-};