diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/AbstractFlashcardViewer.java b/AnkiDroid/src/main/java/com/ichi2/anki/AbstractFlashcardViewer.java index bcdeee2eb0..f825b79934 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/AbstractFlashcardViewer.java +++ b/AnkiDroid/src/main/java/com/ichi2/anki/AbstractFlashcardViewer.java @@ -913,6 +913,9 @@ public abstract class AbstractFlashcardViewer extends NavigationDrawerActivity { pauseTimer(); mSoundPlayer.stopSounds(); + + // Prevent loss of data in Cookies + CompatHelper.getCompat().flushWebViewCookies(); } @@ -939,6 +942,11 @@ public abstract class AbstractFlashcardViewer extends NavigationDrawerActivity { if (mUnmountReceiver != null) { unregisterReceiver(mUnmountReceiver); } + // WebView.destroy() should be called after the end of use + // http://developer.android.com/reference/android/webkit/WebView.html#destroy() + mCardFrame.removeAllViews(); + destroyWebView(mCard); + destroyWebView(mNextCard); } @@ -1491,6 +1499,16 @@ public abstract class AbstractFlashcardViewer extends NavigationDrawerActivity { } + private void destroyWebView(WebView webView) { + if (webView != null) { + webView.stopLoading(); + webView.setWebChromeClient(null); + webView.setWebViewClient(null); + webView.destroy(); + } + } + + protected void showEaseButtons() { Resources res = getResources(); @@ -2192,7 +2210,7 @@ public abstract class AbstractFlashcardViewer extends NavigationDrawerActivity { mNextCard.loadDataWithBaseURL(mBaseUrl + "__viewer__.html", mCardContent.toString(), "text/html", "utf-8", null); mNextCard.setVisibility(View.VISIBLE); mCardFrame.removeView(mCard); - mCard.destroy(); + destroyWebView(mCard); mCard = mNextCard; mNextCard = createWebView(); mNextCard.setVisibility(View.GONE); diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/AnkiDroidApp.java b/AnkiDroid/src/main/java/com/ichi2/anki/AnkiDroidApp.java index d2505fe6e6..05a1b7ac99 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/AnkiDroidApp.java +++ b/AnkiDroid/src/main/java/com/ichi2/anki/AnkiDroidApp.java @@ -176,6 +176,9 @@ public class AnkiDroidApp extends Application { // Configure WebView to allow file scheme pages to access cookies. CompatHelper.getCompat().enableCookiesForFileSchemePages(); + // Prepare Cookies to be synchronized between RAM and permanent storage. + CompatHelper.getCompat().prepareWebViewCookies(this.getApplicationContext()); + // Set good default values for swipe detection final ViewConfiguration vc = ViewConfiguration.get(this); DEFAULT_SWIPE_MIN_DISTANCE = vc.getScaledPagingTouchSlop(); diff --git a/AnkiDroid/src/main/java/com/ichi2/compat/Compat.java b/AnkiDroid/src/main/java/com/ichi2/compat/Compat.java index df5833efad..dfbd8eecf5 100644 --- a/AnkiDroid/src/main/java/com/ichi2/compat/Compat.java +++ b/AnkiDroid/src/main/java/com/ichi2/compat/Compat.java @@ -60,5 +60,7 @@ public interface Compat { void openUrl(AnkiActivity activity, Uri uri); void supportAddContentMenu(final DeckPicker a); Intent getPreferenceSubscreenIntent(Context context, String subscreen); + void prepareWebViewCookies(Context context); + void flushWebViewCookies(); } diff --git a/AnkiDroid/src/main/java/com/ichi2/compat/CompatV10.java b/AnkiDroid/src/main/java/com/ichi2/compat/CompatV10.java index 3fe147f049..36de0779e5 100644 --- a/AnkiDroid/src/main/java/com/ichi2/compat/CompatV10.java +++ b/AnkiDroid/src/main/java/com/ichi2/compat/CompatV10.java @@ -14,6 +14,7 @@ import android.support.annotation.NonNull; import android.support.v4.content.ContextCompat; import android.view.View; import android.view.WindowManager; +import android.webkit.CookieSyncManager; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.RemoteViews; @@ -73,6 +74,18 @@ public class CompatV10 implements Compat { Timber.w("Cookies not supported in API version %d", CompatHelper.getSdkVersion()); } + // CookieSyncManager is need to be initialized before use. + // Note: CookieSyncManager is deprecated since API level 21, but still need to be used here. + public void prepareWebViewCookies(Context context) { + CookieSyncManager.createInstance(context); + } + + // A data of cookies may be lost when an application exists just after it was written. + // Below API level 21, this problem can be solved by using CookieSyncManager.sync(). + // Note: CookieSyncManager is deprecated since API level 21, but still need to be used here. + public void flushWebViewCookies() { + CookieSyncManager.getInstance().sync(); + } // Below API level 16, widget dimensions cannot be adjusted public void updateWidgetDimensions(Context context, RemoteViews updateViews, Class cls) { diff --git a/AnkiDroid/src/main/java/com/ichi2/compat/CompatV21.java b/AnkiDroid/src/main/java/com/ichi2/compat/CompatV21.java index 21940e7566..898c4efab9 100644 --- a/AnkiDroid/src/main/java/com/ichi2/compat/CompatV21.java +++ b/AnkiDroid/src/main/java/com/ichi2/compat/CompatV21.java @@ -2,11 +2,13 @@ package com.ichi2.compat; import android.annotation.TargetApi; +import android.content.Context; import android.content.res.TypedArray; import android.view.View; +import android.webkit.CookieManager; -/** Implementation of {@link Compat} for SDK level 19 */ -@TargetApi(19) +/** Implementation of {@link Compat} for SDK level 21 */ +@TargetApi(21) public class CompatV21 extends CompatV19 implements Compat { @Override public void setSelectableBackground(View view) { @@ -16,4 +18,17 @@ public class CompatV21 extends CompatV19 implements Compat { view.setBackgroundResource(ta.getResourceId(0, 0)); ta.recycle(); } + + // On API level 21 and higher, CookieManager will be set automatically, so there is nothing to do here. + @Override + public void prepareWebViewCookies(Context context) { + + } + + // A data of cookies may be lost when an application exists just after it was written. + // On API level 21 and higher, this problem can be solved by using CookieManager.flush(). + @Override + public void flushWebViewCookies() { + CookieManager.getInstance().flush(); + } } \ No newline at end of file