EMMA Coverage Report (generated Fri Aug 23 16:39:17 PDT 2013)
[all classes][org.chromium.android_webview]

COVERAGE SUMMARY FOR SOURCE FILE [HttpAuthDatabase.java]

nameclass, %method, %block, %line, %
HttpAuthDatabase.java100% (2/2)85%  (11/13)64%  (227/352)63%  (48.4/77)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class HttpAuthDatabase100% (1/1)82%  (9/11)62%  (207/332)62%  (46.4/75)
clearHttpAuthUsernamePassword (): void 0%   (0/1)0%   (0/12)0%   (0/4)
hasHttpAuthUsernamePassword (): boolean 0%   (0/1)0%   (0/48)0%   (0/10)
initDatabase (Context, String): void 100% (1/1)49%  (29/59)64%  (9.7/15)
waitForInit (): boolean 100% (1/1)59%  (19/32)56%  (4.5/8)
getHttpAuthUsernamePassword (String, String): String [] 100% (1/1)78%  (73/93)71%  (9.2/13)
initOnBackgroundThread (Context, String): void 100% (1/1)93%  (13/14)83%  (5/6)
setHttpAuthUsernamePassword (String, String, String, String): void 100% (1/1)97%  (35/36)89%  (8/9)
<static initializer> 100% (1/1)100% (8/8)100% (1/1)
HttpAuthDatabase (Context, String): void 100% (1/1)100% (16/16)100% (5/5)
access$000 (HttpAuthDatabase, Context, String): void 100% (1/1)100% (5/5)100% (1/1)
createTable (): void 100% (1/1)100% (9/9)100% (3/3)
     
class HttpAuthDatabase$1100% (1/1)100% (2/2)100% (20/20)100% (3/3)
HttpAuthDatabase$1 (HttpAuthDatabase, Context, String): void 100% (1/1)100% (12/12)100% (1/1)
run (): void 100% (1/1)100% (8/8)100% (2/2)

1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4 
5package org.chromium.android_webview;
6 
7import android.content.ContentValues;
8import android.content.Context;
9import android.database.Cursor;
10import android.database.sqlite.SQLiteDatabase;
11import android.database.sqlite.SQLiteException;
12import android.util.Log;
13 
14/**
15 * This database is used to support WebView's setHttpAuthUsernamePassword and
16 * getHttpAuthUsernamePassword methods, and WebViewDatabase's clearHttpAuthUsernamePassword and
17 * hasHttpAuthUsernamePassword methods.
18 *
19 * While this class is intended to be used as a singleton, this property is not enforced in this
20 * layer, primarily for ease of testing. To line up with the classic implementation and behavior,
21 * there is no specific handling and reporting when SQL errors occur.
22 *
23 * Note on thread-safety: As per the classic implementation, most API functions have thread safety
24 * provided by the underlying SQLiteDatabase instance. The exception is database opening: this
25 * is handled in the dedicated background thread, which also provides a performance gain
26 * if triggered early on (e.g. as a side effect of CookieSyncManager.createInstance() call),
27 * sufficiently in advance of the first blocking usage of the API.
28 */
29public class HttpAuthDatabase {
30 
31    private static final String LOGTAG = "HttpAuthDatabase";
32 
33    private static final int DATABASE_VERSION = 1;
34 
35    private SQLiteDatabase mDatabase = null;
36 
37    private static final String ID_COL = "_id";
38 
39    private static final String[] ID_PROJECTION = new String[] {
40        ID_COL
41    };
42 
43    // column id strings for "httpauth" table
44    private static final String HTTPAUTH_TABLE_NAME = "httpauth";
45    private static final String HTTPAUTH_HOST_COL = "host";
46    private static final String HTTPAUTH_REALM_COL = "realm";
47    private static final String HTTPAUTH_USERNAME_COL = "username";
48    private static final String HTTPAUTH_PASSWORD_COL = "password";
49 
50    /**
51     * Initially false until the background thread completes.
52     */
53    private boolean mInitialized = false;
54 
55    /**
56     * Create an instance of HttpAuthDatabase for the named file, and kick-off background
57     * initialization of that database.
58     *
59     * @param context the Context to use for opening the database
60     * @param databaseFile Name of the file to be initialized.
61     */
62    public HttpAuthDatabase(final Context context, final String databaseFile) {
63        new Thread() {
64            @Override
65            public void run() {
66                initOnBackgroundThread(context, databaseFile);
67            }
68        }.start();
69    }
70 
71    /**
72     * Initializes the databases and notifies any callers waiting on waitForInit.
73     *
74     * @param context the Context to use for opening the database
75     * @param databaseFile Name of the file to be initialized.
76     */
77    private synchronized void initOnBackgroundThread(Context context, String databaseFile) {
78        if (mInitialized) {
79            return;
80        }
81 
82        initDatabase(context, databaseFile);
83 
84        // Thread done, notify.
85        mInitialized = true;
86        notifyAll();
87    }
88 
89    /**
90     * Opens the database, and upgrades it if necessary.
91     *
92     * @param context the Context to use for opening the database
93     * @param databaseFile Name of the file to be initialized.
94     */
95    private void initDatabase(Context context, String databaseFile) {
96        try {
97            mDatabase = context.openOrCreateDatabase(databaseFile, 0, null);
98        } catch (SQLiteException e) {
99            // try again by deleting the old db and create a new one
100            if (context.deleteDatabase(databaseFile)) {
101                mDatabase = context.openOrCreateDatabase(databaseFile, 0, null);
102            }
103        }
104 
105        if (mDatabase == null) {
106            // Not much we can do to recover at this point
107            Log.e(LOGTAG, "Unable to open or create " + databaseFile);
108            return;
109        }
110 
111        if (mDatabase.getVersion() != DATABASE_VERSION) {
112            mDatabase.beginTransactionNonExclusive();
113            try {
114                createTable();
115                mDatabase.setTransactionSuccessful();
116            } finally {
117                mDatabase.endTransaction();
118            }
119        }
120    }
121 
122    private void createTable() {
123        mDatabase.execSQL("CREATE TABLE " + HTTPAUTH_TABLE_NAME
124                + " (" + ID_COL + " INTEGER PRIMARY KEY, "
125                + HTTPAUTH_HOST_COL + " TEXT, " + HTTPAUTH_REALM_COL
126                + " TEXT, " + HTTPAUTH_USERNAME_COL + " TEXT, "
127                + HTTPAUTH_PASSWORD_COL + " TEXT," + " UNIQUE ("
128                + HTTPAUTH_HOST_COL + ", " + HTTPAUTH_REALM_COL
129                + ") ON CONFLICT REPLACE);");
130 
131        mDatabase.setVersion(DATABASE_VERSION);
132    }
133 
134    /**
135     * Waits for the background initialization thread to complete and check the database creation
136     * status.
137     *
138     * @return true if the database was initialized, false otherwise
139     */
140    private boolean waitForInit() {
141        synchronized (this) {
142            while (!mInitialized) {
143                try {
144                    wait();
145                } catch (InterruptedException e) {
146                    Log.e(LOGTAG, "Caught exception while checking initialization", e);
147                }
148            }
149        }
150        return mDatabase != null;
151    }
152 
153    /**
154     * Sets the HTTP authentication password. Tuple (HTTPAUTH_HOST_COL, HTTPAUTH_REALM_COL,
155     * HTTPAUTH_USERNAME_COL) is unique.
156     *
157     * @param host the host for the password
158     * @param realm the realm for the password
159     * @param username the username for the password.
160     * @param password the password
161     */
162    public void setHttpAuthUsernamePassword(String host, String realm, String username,
163            String password) {
164        if (host == null || realm == null || !waitForInit()) {
165            return;
166        }
167 
168        final ContentValues c = new ContentValues();
169        c.put(HTTPAUTH_HOST_COL, host);
170        c.put(HTTPAUTH_REALM_COL, realm);
171        c.put(HTTPAUTH_USERNAME_COL, username);
172        c.put(HTTPAUTH_PASSWORD_COL, password);
173        mDatabase.insert(HTTPAUTH_TABLE_NAME, HTTPAUTH_HOST_COL, c);
174    }
175 
176    /**
177     * Retrieves the HTTP authentication username and password for a given host and realm pair. If
178     * there are multiple username/password combinations for a host/realm, only the first one will
179     * be returned.
180     *
181     * @param host the host the password applies to
182     * @param realm the realm the password applies to
183     * @return a String[] if found where String[0] is username (which can be null) and
184     *         String[1] is password.  Null is returned if it can't find anything.
185     */
186    public String[] getHttpAuthUsernamePassword(String host, String realm) {
187        if (host == null || realm == null || !waitForInit()){
188            return null;
189        }
190 
191        final String[] columns = new String[] {
192            HTTPAUTH_USERNAME_COL, HTTPAUTH_PASSWORD_COL
193        };
194        final String selection = "(" + HTTPAUTH_HOST_COL + " == ?) AND " +
195                "(" + HTTPAUTH_REALM_COL + " == ?)";
196 
197        String[] ret = null;
198        Cursor cursor = null;
199        try {
200            cursor = mDatabase.query(HTTPAUTH_TABLE_NAME, columns, selection,
201                    new String[] { host, realm }, null, null, null);
202            if (cursor.moveToFirst()) {
203                ret = new String[] {
204                        cursor.getString(cursor.getColumnIndex(HTTPAUTH_USERNAME_COL)),
205                        cursor.getString(cursor.getColumnIndex(HTTPAUTH_PASSWORD_COL)),
206                };
207            }
208        } catch (IllegalStateException e) {
209            Log.e(LOGTAG, "getHttpAuthUsernamePassword", e);
210        } finally {
211            if (cursor != null) cursor.close();
212        }
213        return ret;
214    }
215 
216    /**
217     * Determines if there are any HTTP authentication passwords saved.
218     *
219     * @return true if there are passwords saved
220     */
221    public boolean hasHttpAuthUsernamePassword() {
222        if (!waitForInit()) {
223            return false;
224        }
225 
226        Cursor cursor = null;
227        boolean ret = false;
228        try {
229            cursor = mDatabase.query(HTTPAUTH_TABLE_NAME, ID_PROJECTION, null, null, null, null,
230                    null);
231            ret = cursor.moveToFirst();
232        } catch (IllegalStateException e) {
233            Log.e(LOGTAG, "hasEntries", e);
234        } finally {
235            if (cursor != null) cursor.close();
236        }
237        return ret;
238    }
239 
240    /**
241     * Clears the HTTP authentication password database.
242     */
243    public void clearHttpAuthUsernamePassword() {
244        if (!waitForInit()) {
245            return;
246        }
247        mDatabase.delete(HTTPAUTH_TABLE_NAME, null, null);
248    }
249}

[all classes][org.chromium.android_webview]
EMMA 2.0.5312 (C) Vladimir Roubtsov