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