Home | History | Annotate | Download | only in webkit
      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 
     17 package android.webkit;
     18 
     19 import android.content.Context;
     20 import android.util.Log;
     21 import android.webkit.CookieManager.Cookie;
     22 
     23 import java.util.ArrayList;
     24 import 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  */
     61 public 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         if (sRef == null) {
     81             throw new IllegalStateException(
     82                     "CookieSyncManager::createInstance() needs to be called "
     83                             + "before CookieSyncManager::getInstance()");
     84         }
     85         return sRef;
     86     }
     87 
     88     /**
     89      * Create a singleton CookieSyncManager within a context
     90      * @param context
     91      * @return CookieSyncManager
     92      */
     93     public static synchronized CookieSyncManager createInstance(
     94             Context context) {
     95         if (sRef == null) {
     96             sRef = new CookieSyncManager(context.getApplicationContext());
     97         }
     98         return sRef;
     99     }
    100 
    101     /**
    102      * Package level api, called from CookieManager. Get all the cookies which
    103      * matches a given base domain.
    104      * @param domain
    105      * @return A list of Cookie
    106      */
    107     ArrayList<Cookie> getCookiesForDomain(String domain) {
    108         // null mDataBase implies that the host application doesn't support
    109         // persistent cookie. No sync needed.
    110         if (mDataBase == null) {
    111             return new ArrayList<Cookie>();
    112         }
    113 
    114         return mDataBase.getCookiesForDomain(domain);
    115     }
    116 
    117     /**
    118      * Package level api, called from CookieManager Clear all cookies in the
    119      * database
    120      */
    121     void clearAllCookies() {
    122         // null mDataBase implies that the host application doesn't support
    123         // persistent cookie.
    124         if (mDataBase == null) {
    125             return;
    126         }
    127 
    128         mDataBase.clearCookies();
    129     }
    130 
    131     /**
    132      * Returns true if there are any saved cookies.
    133      */
    134     boolean hasCookies() {
    135         // null mDataBase implies that the host application doesn't support
    136         // persistent cookie.
    137         if (mDataBase == null) {
    138             return false;
    139         }
    140 
    141         return mDataBase.hasCookies();
    142     }
    143 
    144     /**
    145      * Package level api, called from CookieManager Clear all session cookies in
    146      * the database
    147      */
    148     void clearSessionCookies() {
    149         // null mDataBase implies that the host application doesn't support
    150         // persistent cookie.
    151         if (mDataBase == null) {
    152             return;
    153         }
    154 
    155         mDataBase.clearSessionCookies();
    156     }
    157 
    158     /**
    159      * Package level api, called from CookieManager Clear all expired cookies in
    160      * the database
    161      */
    162     void clearExpiredCookies(long now) {
    163         // null mDataBase implies that the host application doesn't support
    164         // persistent cookie.
    165         if (mDataBase == null) {
    166             return;
    167         }
    168 
    169         mDataBase.clearExpiredCookies(now);
    170     }
    171 
    172     protected void syncFromRamToFlash() {
    173         if (DebugFlags.COOKIE_SYNC_MANAGER) {
    174             Log.v(LOGTAG, "CookieSyncManager::syncFromRamToFlash STARTS");
    175         }
    176 
    177         if (!CookieManager.getInstance().acceptCookie()) {
    178             return;
    179         }
    180 
    181         ArrayList<Cookie> cookieList = CookieManager.getInstance()
    182                 .getUpdatedCookiesSince(mLastUpdate);
    183         mLastUpdate = System.currentTimeMillis();
    184         syncFromRamToFlash(cookieList);
    185 
    186         ArrayList<Cookie> lruList =
    187                 CookieManager.getInstance().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