/* 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/. */ package org.mozilla.gecko.sync.repositories.android; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.mozilla.gecko.db.BrowserContract; import org.mozilla.gecko.sync.Logger; import org.mozilla.gecko.sync.repositories.NullCursorException; import org.mozilla.gecko.sync.repositories.domain.HistoryRecord; import org.mozilla.gecko.sync.repositories.domain.Record; import android.content.ContentValues; import android.content.Context; import android.net.Uri; public class AndroidBrowserHistoryDataAccessor extends AndroidBrowserRepositoryDataAccessor { private AndroidBrowserHistoryDataExtender dataExtender; public AndroidBrowserHistoryDataAccessor(Context context) { super(context); dataExtender = new AndroidBrowserHistoryDataExtender(context); } public AndroidBrowserHistoryDataExtender getHistoryDataExtender() { return dataExtender; } @Override protected Uri getUri() { return BrowserContractHelpers.HISTORY_CONTENT_URI; } @Override protected ContentValues getContentValues(Record record) { ContentValues cv = new ContentValues(); HistoryRecord rec = (HistoryRecord) record; cv.put(BrowserContract.History.GUID, rec.guid); cv.put(BrowserContract.History.TITLE, rec.title); cv.put(BrowserContract.History.URL, rec.histURI); if (rec.visits != null) { JSONArray visits = rec.visits; long mostRecent = 0; for (int i = 0; i < visits.size(); i++) { JSONObject visit = (JSONObject) visits.get(i); long visitDate = (Long) visit .get(AndroidBrowserHistoryRepositorySession.KEY_DATE); if (visitDate > mostRecent) { mostRecent = visitDate; } } // Fennec stores milliseconds. The rest of Sync works in microseconds. cv.put(BrowserContract.History.DATE_LAST_VISITED, mostRecent / 1000); cv.put(BrowserContract.History.VISITS, Long.toString(visits.size())); } return cv; } @Override protected String[] getAllColumns() { return BrowserContractHelpers.HistoryColumns; } @Override public Uri insert(Record record) { HistoryRecord rec = (HistoryRecord) record; Logger.debug(LOG_TAG, "Storing visits for " + record.guid); dataExtender.store(record.guid, rec.visits); Logger.debug(LOG_TAG, "Storing record " + record.guid); return super.insert(record); } @Override public void update(String oldGUID, Record newRecord) { HistoryRecord rec = (HistoryRecord) newRecord; String newGUID = newRecord.guid; Logger.debug(LOG_TAG, "Storing visits for " + newGUID + ", replacing " + oldGUID); dataExtender.delete(oldGUID); dataExtender.store(newGUID, rec.visits); super.update(oldGUID, newRecord); } @Override public int purgeGuid(String guid) { Logger.debug(LOG_TAG, "Purging record with " + guid); dataExtender.delete(guid); return super.purgeGuid(guid); } public void closeExtender() { dataExtender.close(); } public static String[] GUID_AND_ID = new String[] { BrowserContract.History.GUID, BrowserContract.History._ID }; /** * Insert records. * <p> * This inserts all the records (using <code>ContentProvider.bulkInsert</code>), * then inserts all the visit information (using the data extender's * <code>bulkInsert</code>, which internally uses a single database * transaction). * * @param records * the records to insert. * @return * the number of records actually inserted. * @throws NullCursorException */ public int bulkInsert(ArrayList<HistoryRecord> records) throws NullCursorException { if (records.isEmpty()) { Logger.debug(LOG_TAG, "No records to insert, returning."); } int size = records.size(); ContentValues[] cvs = new ContentValues[size]; String[] guids = new String[size]; Map<String, Record> guidToRecord = new HashMap<String, Record>(); int index = 0; for (Record record : records) { if (record.guid == null) { throw new IllegalArgumentException("Record with null GUID passed in to bulkInsert."); } cvs[index] = getContentValues(record); guids[index] = record.guid; guidToRecord.put(record.guid, record); index += 1; } // First update the history records. int inserted = context.getContentResolver().bulkInsert(getUri(), cvs); if (inserted == size) { Logger.debug(LOG_TAG, "Inserted " + inserted + " records, as expected."); } else { Logger.debug(LOG_TAG, "Inserted " + inserted + " records but expected " + size + " records; continuing to update visits."); } // Then update the history visits. dataExtender.bulkInsert(records); return inserted; } }