1ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio/*
2ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio * Copyright (C) 2010 The Android Open Source Project
3ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio *
4ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio * Licensed under the Apache License, Version 2.0 (the "License");
5ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio * you may not use this file except in compliance with the License.
6ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio * You may obtain a copy of the License at
7ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio *
8ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio *      http://www.apache.org/licenses/LICENSE-2.0
9ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio *
10ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio * Unless required by applicable law or agreed to in writing, software
11ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio * distributed under the License is distributed on an "AS IS" BASIS,
12ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio * See the License for the specific language governing permissions and
14ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio * limitations under the License.
15ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio */
16ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio
17ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Megliopackage com.android.providers.calendar;
18ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio
19ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglioimport android.content.ContentValues;
20ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglioimport android.database.Cursor;
21ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglioimport android.database.sqlite.SQLiteDatabase;
22ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglioimport android.database.sqlite.SQLiteOpenHelper;
23ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglioimport android.util.Log;
24a637bc824d92888eec9c6d2da0d5f1e594bebebaFabrice Di Meglioimport com.google.common.annotations.VisibleForTesting;
25ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio
26315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglioimport java.util.TimeZone;
27315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio
28ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio/**
29ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio * Class for managing a persistent Cache of (key, value) pairs. The persistent storage used is
30ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio * a SQLite database.
31ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio */
32ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Megliopublic class CalendarCache {
33ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio    private static final String TAG = "CalendarCache";
34ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio
35ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio    public static final String DATABASE_NAME = "CalendarCache";
36ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio
37ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio    public static final String KEY_TIMEZONE_DATABASE_VERSION = "timezoneDatabaseVersion";
38ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio    public static final String DEFAULT_TIMEZONE_DATABASE_VERSION = "2009s";
39ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio
40315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio    public static final String KEY_TIMEZONE_TYPE = "timezoneType";
41315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio    public static final String TIMEZONE_TYPE_AUTO = "auto";
42315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio    public static final String TIMEZONE_TYPE_HOME = "home";
43315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio
44315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio    public static final String KEY_TIMEZONE_INSTANCES = "timezoneInstances";
45315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio    public static final String KEY_TIMEZONE_INSTANCES_PREVIOUS = "timezoneInstancesPrevious";
46315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio
477cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio    public static final String COLUMN_NAME_ID = "_id";
487cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio    public static final String COLUMN_NAME_KEY = "key";
497cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio    public static final String COLUMN_NAME_VALUE = "value";
50ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio
51ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio    private static final String[] sProjection = {
52ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio        COLUMN_NAME_KEY,
53ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio        COLUMN_NAME_VALUE
54ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio    };
55ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio
56ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio    private static final int COLUMN_INDEX_KEY = 0;
57ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio    private static final int COLUMN_INDEX_VALUE = 1;
58ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio
59ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio    private final SQLiteOpenHelper mOpenHelper;
60ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio
61ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio    /**
62ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio     * This exception is thrown when the cache encounter a null key or a null database reference
63ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio     */
64ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio    public static class CacheException extends Exception {
65ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio        public CacheException() {
66ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio        }
67ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio
68ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio        public CacheException(String detailMessage) {
69ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio            super(detailMessage);
70ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio        }
71ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio    }
72ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio
73ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio    public CalendarCache(SQLiteOpenHelper openHelper) {
74ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio        mOpenHelper = openHelper;
75ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio    }
76ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio
77ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio    public void writeTimezoneDatabaseVersion(String timezoneDatabaseVersion) throws CacheException {
78315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        writeData(KEY_TIMEZONE_DATABASE_VERSION, timezoneDatabaseVersion);
79315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio    }
80315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio
81315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio    public String readTimezoneDatabaseVersion() {
82315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        try {
83315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio            return readData(KEY_TIMEZONE_DATABASE_VERSION);
84315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        } catch (CacheException e) {
85315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio            Log.e(TAG, "Could not read timezone database version from CalendarCache");
86315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        }
87315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        return null;
88ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio    }
89ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio
90a637bc824d92888eec9c6d2da0d5f1e594bebebaFabrice Di Meglio    @VisibleForTesting
91315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio    public void writeTimezoneType(String timezoneType) throws CacheException {
92315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        writeData(KEY_TIMEZONE_TYPE, timezoneType);
93315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio    }
94315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio
95315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio    public String readTimezoneType() {
96315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        try {
97315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio            return readData(KEY_TIMEZONE_TYPE);
98315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        } catch (CacheException e) {
99315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio            Log.e(TAG, "Cannot read timezone type from CalendarCache - using AUTO as default", e);
100315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        }
101315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        return TIMEZONE_TYPE_AUTO;
102315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio    }
103315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio
104315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio    public void writeTimezoneInstances(String timezone) {
105315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        try {
106315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio            writeData(KEY_TIMEZONE_INSTANCES, timezone);
107315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        } catch (CacheException e) {
108315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio            Log.e(TAG, "Cannot write instances timezone to CalendarCache");
109315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        }
110315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio    }
111315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio
112315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio    public String readTimezoneInstances() {
113315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        try {
114315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio            return readData(KEY_TIMEZONE_INSTANCES);
115315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        } catch (CacheException e) {
116315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio            String localTimezone = TimeZone.getDefault().getID();
117315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio            Log.e(TAG, "Cannot read instances timezone from CalendarCache - using device one: " +
118315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio                    localTimezone, e);
119315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio            return localTimezone;
120315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        }
121315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio    }
122315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio
123315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio    public void writeTimezoneInstancesPrevious(String timezone) {
124315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        try {
125315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio            writeData(KEY_TIMEZONE_INSTANCES_PREVIOUS, timezone);
126315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        } catch (CacheException e) {
127315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio            Log.e(TAG, "Cannot write previous instance timezone to CalendarCache");
128315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        }
129315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio    }
130315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio
131315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio    public String readTimezoneInstancesPrevious() {
132315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        try {
133315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio            return readData(KEY_TIMEZONE_INSTANCES_PREVIOUS);
134315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        } catch (CacheException e) {
135315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio            Log.e(TAG, "Cannot read previous instances timezone from CalendarCache", e);
136315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        }
137315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        return null;
138ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio    }
139ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio
140ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio    /**
141ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio     * Write a (key, value) pair in the Cache.
142ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio     *
143ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio     * @param key the key (must not be null)
144ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio     * @param value the value (can be null)
145ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio     * @throws CacheException when key is null
146ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio     */
147ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio    public void writeData(String key, String value) throws CacheException {
148ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
149ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio        db.beginTransaction();
150ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio        try {
151ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio            writeDataLocked(db, key, value);
152ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio            db.setTransactionSuccessful();
153ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio            if (Log.isLoggable(TAG, Log.VERBOSE)) {
154ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio                Log.i(TAG, "Wrote (key, value) = [ " + key + ", " + value + "] ");
155ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio            }
156ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio        } finally {
157ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio            db.endTransaction();
158ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio        }
159ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio    }
160ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio
161ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio    /**
162cad6bc946434363f6ba6fed58bfa818cd6736d21Andy McFadden     * Write a (key, value) pair in the database used by the cache. This method should be called in
163ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio     * a transaction.
164ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio     *
165ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio     * @param db the database (must not be null)
166ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio     * @param key the key (must not be null)
167ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio     * @param value the value
168ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio     * @throws CacheException when key or database are null
169ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio     */
170ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio    protected void writeDataLocked(SQLiteDatabase db, String key, String value)
171ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio            throws CacheException {
172ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio        if (null == db) {
173ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio            throw new CacheException("Database cannot be null");
174ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio        }
175ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio        if (null == key) {
176ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio            throw new CacheException("Cannot use null key for write");
177ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio        }
178ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio
179cad6bc946434363f6ba6fed58bfa818cd6736d21Andy McFadden        /*
180cad6bc946434363f6ba6fed58bfa818cd6736d21Andy McFadden         * Storing the hash code of a String into the _id column carries a (very) small risk
181cad6bc946434363f6ba6fed58bfa818cd6736d21Andy McFadden         * of weird behavior, because we're using it as a unique key, but hash codes aren't
182cad6bc946434363f6ba6fed58bfa818cd6736d21Andy McFadden         * guaranteed to be unique.  CalendarCache has a small set of keys that are known
183cad6bc946434363f6ba6fed58bfa818cd6736d21Andy McFadden         * ahead of time, so we should be okay.
184cad6bc946434363f6ba6fed58bfa818cd6736d21Andy McFadden         */
185ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio        ContentValues values = new ContentValues();
186ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio        values.put(COLUMN_NAME_ID, key.hashCode());
187ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio        values.put(COLUMN_NAME_KEY, key);
188ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio        values.put(COLUMN_NAME_VALUE, value);
189ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio
190ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio        db.replace(DATABASE_NAME, null /* null column hack */, values);
191ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio    }
192ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio
193ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio    /**
194ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio     * Read a value from the database used by the cache and depending on a key.
195ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio     *
196ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio     * @param key the key from which we want the value (must not be null)
197ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio     * @return the value that was found for the key. Can be null if no key has been found
198ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio     * @throws CacheException when key is null
199ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio     */
200ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio    public String readData(String key) throws CacheException {
201ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
202ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio        return readDataLocked(db, key);
203ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio    }
204ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio
205ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio    /**
206ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio     * Read a value from the database used by the cache and depending on a key. The database should
207ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio     * be "readable" at minimum
208ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio     *
209ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio     * @param db the database (must not be null)
210ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio     * @param key the key from which we want the value (must not be null)
211ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio     * @return the value that was found for the key. Can be null if no value has been found for the
212ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio     * key.
213ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio     * @throws CacheException when key or database are null
214ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio     */
215ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio    protected String readDataLocked(SQLiteDatabase db, String key) throws CacheException {
216ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio        if (null == db) {
217ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio            throw new CacheException("Database cannot be null");
218ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio        }
219ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio        if (null == key) {
220ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio            throw new CacheException("Cannot use null key for read");
221ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio        }
222ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio
223ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio        String rowValue = null;
224ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio
225ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio        Cursor cursor = db.query(DATABASE_NAME, sProjection,
226ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio                COLUMN_NAME_KEY + "=?", new String[] { key }, null, null, null);
227ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio        try {
228ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio            if (cursor.moveToNext()) {
229ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio                rowValue = cursor.getString(COLUMN_INDEX_VALUE);
230ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio            }
231ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio            else {
232ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio                if (Log.isLoggable(TAG, Log.VERBOSE)) {
233ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio                    Log.i(TAG, "Could not find key = [ " + key + " ]");
234ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio                }
235ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio            }
236ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio        } finally {
237ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio            cursor.close();
238ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio            cursor = null;
239ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio        }
240ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio        return rowValue;
241ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio    }
242ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio}
243