CookieSyncManager.java revision 42bc2ff5d2e3a10ab6c1fb1e716a124f2b446dbc
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 class CookieSyncManager is used to synchronize the browser cookies
28 * between RAM and FLASH. To get the best performance, browser cookie is saved
29 * in RAM. We use a separate thread to sync the cookies between RAM and FLASH on
30 * a timer base.
31 * <p>
32 * To use the CookieSyncManager, the host application has to call the following
33 * when the application starts.
34 * <p>
35 * CookieSyncManager.createInstance(context)
36 * <p>
37 * To set up for sync, the host application has to call
38 * <p>
39 * CookieSyncManager.getInstance().startSync()
40 * <p>
41 * in its Activity.onResume(), and call
42 * <p>
43 * CookieSyncManager.getInstance().stopSync()
44 * <p>
45 * in its Activity.onStop().
46 * <p>
47 * To get instant sync instead of waiting for the timer to trigger, the host can
48 * call
49 * <p>
50 * CookieSyncManager.getInstance().sync()
51 */
52public final class CookieSyncManager extends WebSyncManager {
53
54    private static CookieSyncManager sRef;
55
56    // time when last update happened
57    private long mLastUpdate;
58
59    private CookieSyncManager(Context context) {
60        super(context, "CookieSyncManager");
61    }
62
63    /**
64     * Singleton access to a {@link CookieSyncManager}. An
65     * IllegalStateException will be thrown if
66     * {@link CookieSyncManager#createInstance(Context)} is not called before.
67     *
68     * @return CookieSyncManager
69     */
70    public static synchronized CookieSyncManager getInstance() {
71        if (sRef == null) {
72            throw new IllegalStateException(
73                    "CookieSyncManager::createInstance() needs to be called "
74                            + "before CookieSyncManager::getInstance()");
75        }
76        return sRef;
77    }
78
79    /**
80     * Create a singleton CookieSyncManager within a context
81     * @param context
82     * @return CookieSyncManager
83     */
84    public static synchronized CookieSyncManager createInstance(
85            Context context) {
86        if (sRef == null) {
87            sRef = new CookieSyncManager(context);
88        }
89        return sRef;
90    }
91
92    /**
93     * Package level api, called from CookieManager Get all the cookies which
94     * matches a given base domain.
95     * @param domain
96     * @return A list of Cookie
97     */
98    ArrayList<Cookie> getCookiesForDomain(String domain) {
99        // null mDataBase implies that the host application doesn't support
100        // persistent cookie. No sync needed.
101        if (mDataBase == null) {
102            return new ArrayList<Cookie>();
103        }
104
105        return mDataBase.getCookiesForDomain(domain);
106    }
107
108    /**
109     * Package level api, called from CookieManager Clear all cookies in the
110     * database
111     */
112    void clearAllCookies() {
113        // null mDataBase implies that the host application doesn't support
114        // persistent cookie.
115        if (mDataBase == null) {
116            return;
117        }
118
119        mDataBase.clearCookies();
120    }
121
122    /**
123     * Returns true if there are any saved cookies.
124     */
125    boolean hasCookies() {
126        // null mDataBase implies that the host application doesn't support
127        // persistent cookie.
128        if (mDataBase == null) {
129            return false;
130        }
131
132        return mDataBase.hasCookies();
133    }
134
135    /**
136     * Package level api, called from CookieManager Clear all session cookies in
137     * the database
138     */
139    void clearSessionCookies() {
140        // null mDataBase implies that the host application doesn't support
141        // persistent cookie.
142        if (mDataBase == null) {
143            return;
144        }
145
146        mDataBase.clearSessionCookies();
147    }
148
149    /**
150     * Package level api, called from CookieManager Clear all expired cookies in
151     * the database
152     */
153    void clearExpiredCookies(long now) {
154        // null mDataBase implies that the host application doesn't support
155        // persistent cookie.
156        if (mDataBase == null) {
157            return;
158        }
159
160        mDataBase.clearExpiredCookies(now);
161    }
162
163    protected void syncFromRamToFlash() {
164        if (WebView.LOGV_ENABLED) {
165            Log.v(LOGTAG, "CookieSyncManager::syncFromRamToFlash STARTS");
166        }
167
168        if (!CookieManager.getInstance().acceptCookie()) {
169            return;
170        }
171
172        ArrayList<Cookie> cookieList = CookieManager.getInstance()
173                .getUpdatedCookiesSince(mLastUpdate);
174        mLastUpdate = System.currentTimeMillis();
175        syncFromRamToFlash(cookieList);
176
177        ArrayList<Cookie> lruList =
178                CookieManager.getInstance().deleteLRUDomain();
179        syncFromRamToFlash(lruList);
180
181        if (WebView.LOGV_ENABLED) {
182            Log.v(LOGTAG, "CookieSyncManager::syncFromRamToFlash DONE");
183        }
184    }
185
186    private void syncFromRamToFlash(ArrayList<Cookie> list) {
187        Iterator<Cookie> iter = list.iterator();
188        while (iter.hasNext()) {
189            Cookie cookie = iter.next();
190            if (cookie.mode != Cookie.MODE_NORMAL) {
191                if (cookie.mode != Cookie.MODE_NEW) {
192                    mDataBase.deleteCookies(cookie.domain, cookie.path,
193                            cookie.name);
194                }
195                if (cookie.mode != Cookie.MODE_DELETED) {
196                    mDataBase.addCookie(cookie);
197                    CookieManager.getInstance().syncedACookie(cookie);
198                } else {
199                    CookieManager.getInstance().deleteACookie(cookie);
200                }
201            }
202        }
203    }
204}
205