CookieSyncManager.java revision 99f39771ab15fc13d221ebfb3682741002c5f7b1
1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.webkit;
18
19import android.content.Context;
20import android.util.Log;
21import android.webkit.CookieManager.Cookie;
22
23import java.util.ArrayList;
24import java.util.Iterator;
25
26/**
27 * The CookieSyncManager is used to synchronize the browser cookie store
28 * between RAM and permanent storage. To get the best performance, browser cookies are
29 * saved in RAM. A separate thread saves the cookies between, driven by a timer.
30 * <p>
31 *
32 * To use the CookieSyncManager, the host application has to call the following
33 * when the application starts:
34 * <p>
35 *
36 * <pre class="prettyprint">CookieSyncManager.createInstance(context)</pre><p>
37 *
38 * To set up for sync, the host application has to call<p>
39 * <pre class="prettyprint">CookieSyncManager.getInstance().startSync()</pre><p>
40 *
41 * in Activity.onResume(), and call
42 * <p>
43 *
44 * <pre class="prettyprint">
45 * CookieSyncManager.getInstance().stopSync()
46 * </pre><p>
47 *
48 * in Activity.onPause().<p>
49 *
50 * To get instant sync instead of waiting for the timer to trigger, the host can
51 * call
52 * <p>
53 * <pre class="prettyprint">CookieSyncManager.getInstance().sync()</pre><p>
54 *
55 * The sync interval is 5 minutes, so you will want to force syncs
56 * manually anyway, for instance in {@link
57 * WebViewClient#onPageFinished}. Note that even sync() happens
58 * asynchronously, so don't do it just as your activity is shutting
59 * down.
60 */
61public final class CookieSyncManager extends WebSyncManager {
62
63    private static CookieSyncManager sRef;
64
65    // time when last update happened
66    private long mLastUpdate;
67
68    private CookieSyncManager(Context context) {
69        super(context, "CookieSyncManager");
70    }
71
72    /**
73     * Singleton access to a {@link CookieSyncManager}. An
74     * IllegalStateException will be thrown if
75     * {@link CookieSyncManager#createInstance(Context)} is not called before.
76     *
77     * @return CookieSyncManager
78     */
79    public static synchronized CookieSyncManager getInstance() {
80        checkInstanceIsCreated();
81        return sRef;
82    }
83
84    /**
85     * Create a singleton CookieSyncManager within a context
86     * @param context
87     * @return CookieSyncManager
88     */
89    public static synchronized CookieSyncManager createInstance(
90            Context context) {
91        JniUtil.setContext(context);
92        Context appContext = context.getApplicationContext();
93        if (sRef == null) {
94            sRef = new CookieSyncManager(appContext);
95        }
96        return sRef;
97    }
98
99    /**
100     * Package level api, called from CookieManager. Get all the cookies which
101     * matches a given base domain.
102     * @param domain
103     * @return A list of Cookie
104     */
105    ArrayList<Cookie> getCookiesForDomain(String domain) {
106        // null mDataBase implies that the host application doesn't support
107        // persistent cookie. No sync needed.
108        if (mDataBase == null) {
109            return new ArrayList<Cookie>();
110        }
111
112        return mDataBase.getCookiesForDomain(domain);
113    }
114
115    /**
116     * Package level api, called from CookieManager Clear all cookies in the
117     * database
118     */
119    void clearAllCookies() {
120        // null mDataBase implies that the host application doesn't support
121        // persistent cookie.
122        if (mDataBase == null) {
123            return;
124        }
125
126        mDataBase.clearCookies();
127    }
128
129    /**
130     * Returns true if there are any saved cookies.
131     */
132    boolean hasCookies() {
133        // null mDataBase implies that the host application doesn't support
134        // persistent cookie.
135        if (mDataBase == null) {
136            return false;
137        }
138
139        return mDataBase.hasCookies();
140    }
141
142    /**
143     * Package level api, called from CookieManager Clear all session cookies in
144     * the database
145     */
146    void clearSessionCookies() {
147        // null mDataBase implies that the host application doesn't support
148        // persistent cookie.
149        if (mDataBase == null) {
150            return;
151        }
152
153        mDataBase.clearSessionCookies();
154    }
155
156    /**
157     * Package level api, called from CookieManager Clear all expired cookies in
158     * the database
159     */
160    void clearExpiredCookies(long now) {
161        // null mDataBase implies that the host application doesn't support
162        // persistent cookie.
163        if (mDataBase == null) {
164            return;
165        }
166
167        mDataBase.clearExpiredCookies(now);
168    }
169
170    protected void syncFromRamToFlash() {
171        if (DebugFlags.COOKIE_SYNC_MANAGER) {
172            Log.v(LOGTAG, "CookieSyncManager::syncFromRamToFlash STARTS");
173        }
174
175        CookieManager manager = CookieManager.getInstance();
176
177        if (!manager.acceptCookie()) {
178            return;
179        }
180
181        manager.flushCookieStore();
182
183        ArrayList<Cookie> cookieList = manager.getUpdatedCookiesSince(mLastUpdate);
184        mLastUpdate = System.currentTimeMillis();
185        syncFromRamToFlash(cookieList);
186
187        ArrayList<Cookie> lruList = manager.deleteLRUDomain();
188        syncFromRamToFlash(lruList);
189
190        if (DebugFlags.COOKIE_SYNC_MANAGER) {
191            Log.v(LOGTAG, "CookieSyncManager::syncFromRamToFlash DONE");
192        }
193    }
194
195    private void syncFromRamToFlash(ArrayList<Cookie> list) {
196        Iterator<Cookie> iter = list.iterator();
197        while (iter.hasNext()) {
198            Cookie cookie = iter.next();
199            if (cookie.mode != Cookie.MODE_NORMAL) {
200                if (cookie.mode != Cookie.MODE_NEW) {
201                    mDataBase.deleteCookies(cookie.domain, cookie.path,
202                            cookie.name);
203                }
204                if (cookie.mode != Cookie.MODE_DELETED) {
205                    mDataBase.addCookie(cookie);
206                    CookieManager.getInstance().syncedACookie(cookie);
207                } else {
208                    CookieManager.getInstance().deleteACookie(cookie);
209                }
210            }
211        }
212    }
213
214    private static void checkInstanceIsCreated() {
215        if (sRef == null) {
216            throw new IllegalStateException(
217                    "CookieSyncManager::createInstance() needs to be called "
218                            + "before CookieSyncManager::getInstance()");
219        }
220    }
221}
222