summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAndrei Popescu <andreip@google.com>2009-07-27 12:01:59 +0100
committerAndrei Popescu <andreip@google.com>2009-07-29 11:08:24 +0100
commit79e82b7ba72a7278911edf0dd7b03c65c4ec0e9d (patch)
tree763bde3a478037641352fde365e0829cf14eea13 /src
parent186e593776c396bde3d720addd6f6842fe880a7c (diff)
downloadpackages_apps_Browser-79e82b7ba72a7278911edf0dd7b03c65c4ec0e9d.zip
packages_apps_Browser-79e82b7ba72a7278911edf0dd7b03c65c4ec0e9d.tar.gz
packages_apps_Browser-79e82b7ba72a7278911edf0dd7b03c65c4ec0e9d.tar.bz2
Refactor the WebStorage size management:
- Abandon the Quota UI: it does not make sense to ask the users to decide individual database quota increases. It is unlikely anyone will be able to make a meaningul decision. - Introduce a global limit for all WebStorage content. This is shared between Database and AppCache. - Make the quota increase decision automatic - Treat out-of-space situations by creaying a system notification (TODO).
Diffstat (limited to 'src')
-rw-r--r--src/com/android/browser/BrowserActivity.java53
-rw-r--r--src/com/android/browser/BrowserSettings.java41
-rw-r--r--src/com/android/browser/PermissionDialog.java175
-rw-r--r--src/com/android/browser/WebStorageSizeManager.java282
4 files changed, 314 insertions, 237 deletions
diff --git a/src/com/android/browser/BrowserActivity.java b/src/com/android/browser/BrowserActivity.java
index d148c0a..7f40494 100644
--- a/src/com/android/browser/BrowserActivity.java
+++ b/src/com/android/browser/BrowserActivity.java
@@ -165,8 +165,6 @@ public class BrowserActivity extends Activity
private SensorManager mSensorManager = null;
- private WebStorage.QuotaUpdater mWebStorageQuotaUpdater = null;
-
// These are single-character shortcuts for searching popular sources.
private static final int SHORTCUT_INVALID = 0;
private static final int SHORTCUT_GOOGLE_SEARCH = 1;
@@ -3850,36 +3848,38 @@ public class BrowserActivity extends Activity
}
/**
- * The origin has exceeded it's database quota.
+ * The origin has exceeded its database quota.
* @param url the URL that exceeded the quota
* @param databaseIdentifier the identifier of the database on
* which the transaction that caused the quota overflow was run
* @param currentQuota the current quota for the origin.
+ * @param totalUsedQuota is the sum of all origins' quota.
* @param quotaUpdater The callback to run when a decision to allow or
* deny quota has been made. Don't forget to call this!
*/
@Override
public void onExceededDatabaseQuota(String url,
- String databaseIdentifier, long currentQuota,
+ String databaseIdentifier, long currentQuota, long totalUsedQuota,
WebStorage.QuotaUpdater quotaUpdater) {
- if(LOGV_ENABLED) {
- Log.v(LOGTAG,
- "BrowserActivity received onExceededDatabaseQuota for "
- + url +
- ":"
- + databaseIdentifier +
- "(current quota: "
- + currentQuota +
- ")");
- }
- mWebStorageQuotaUpdater = quotaUpdater;
- String DIALOG_PACKAGE = "com.android.browser";
- String DIALOG_CLASS = DIALOG_PACKAGE + ".PermissionDialog";
- Intent intent = new Intent();
- intent.setClassName(DIALOG_PACKAGE, DIALOG_CLASS);
- intent.putExtra(PermissionDialog.PARAM_ORIGIN, url);
- intent.putExtra(PermissionDialog.PARAM_QUOTA, currentQuota);
- startActivityForResult(intent, WEBSTORAGE_QUOTA_DIALOG);
+ mSettings.getWebStorageSizeManager().onExceededDatabaseQuota(
+ url, databaseIdentifier, currentQuota, totalUsedQuota,
+ quotaUpdater);
+ }
+
+ /**
+ * The Application Cache has exceeded its max size.
+ * @param spaceNeeded is the amount of disk space that would be needed
+ * in order for the last appcache operation to succeed.
+ * @param totalUsedQuota is the sum of all origins' quota.
+ * @param quotaUpdater A callback to inform the WebCore thread that a new
+ * app cache size is available. This callback must always be executed at
+ * some point to ensure that the sleeping WebCore thread is woken up.
+ */
+ @Override
+ public void onReachedMaxAppCacheSize(long spaceNeeded,
+ long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) {
+ mSettings.getWebStorageSizeManager().onReachedMaxAppCacheSize(
+ spaceNeeded, totalUsedQuota, quotaUpdater);
}
/* Adds a JavaScript error message to the system log.
@@ -4616,14 +4616,6 @@ public class BrowserActivity extends Activity
}
}
break;
- case WEBSTORAGE_QUOTA_DIALOG:
- long currentQuota = 0;
- if (resultCode == RESULT_OK && intent != null) {
- currentQuota = intent.getLongExtra(
- PermissionDialog.PARAM_QUOTA, currentQuota);
- }
- mWebStorageQuotaUpdater.updateQuota(currentQuota);
- break;
default:
break;
}
@@ -5169,7 +5161,6 @@ public class BrowserActivity extends Activity
final static int COMBO_PAGE = 1;
final static int DOWNLOAD_PAGE = 2;
final static int PREFERENCES_PAGE = 3;
- final static int WEBSTORAGE_QUOTA_DIALOG = 4;
// the frenquency of checking whether system memory is low
final static int CHECK_MEMORY_INTERVAL = 30000; // 30 seconds
diff --git a/src/com/android/browser/BrowserSettings.java b/src/com/android/browser/BrowserSettings.java
index d2371cd..3074d2b 100644
--- a/src/com/android/browser/BrowserSettings.java
+++ b/src/com/android/browser/BrowserSettings.java
@@ -25,7 +25,6 @@ import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.preference.PreferenceActivity;
import android.preference.PreferenceScreen;
-import android.os.StatFs;
import android.webkit.CookieManager;
import android.webkit.WebView;
import android.webkit.WebViewDatabase;
@@ -79,6 +78,7 @@ class BrowserSettings extends Observable {
private boolean appCacheEnabled = true;
private String appCachePath; // default value set in loadFromDb().
private long appCacheMaxSize = Long.MAX_VALUE;
+ private WebStorageSizeManager webStorageSizeManager;
private boolean domStorageEnabled = true;
private String jsFlags = "";
@@ -238,7 +238,9 @@ class BrowserSettings extends Observable {
// Set the default value for the Application Caches path.
appCachePath = ctx.getDir("appcache", 0).getPath();
// Determine the maximum size of the application cache.
- appCacheMaxSize = getAppCacheMaxSize();
+ webStorageSizeManager = WebStorageSizeManager.getInstance(appCachePath,
+ ctx);
+ appCacheMaxSize = webStorageSizeManager.getAppCacheMaxSize();
// Set the default value for the Database path.
databasePath = ctx.getDir("databases", 0).getPath();
@@ -363,6 +365,10 @@ class BrowserSettings extends Observable {
return jsFlags;
}
+ public WebStorageSizeManager getWebStorageSizeManager() {
+ return webStorageSizeManager;
+ }
+
public void setHomePage(Context context, String url) {
Editor ed = PreferenceManager.
getDefaultSharedPreferences(context).edit();
@@ -532,6 +538,8 @@ class BrowserSettings extends Observable {
true);
// reset homeUrl
setHomePage(ctx, getFactoryResetHomeUrl(ctx));
+ // reset appcache max size
+ appCacheMaxSize = webStorageSizeManager.getAppCacheMaxSize();
}
private String getFactoryResetHomeUrl(Context context) {
@@ -543,35 +551,6 @@ class BrowserSettings extends Observable {
return url;
}
- private long getAppCacheMaxSize() {
- StatFs dataPartition = new StatFs(appCachePath);
- long freeSpace = dataPartition.getAvailableBlocks()
- * dataPartition.getBlockSize();
- long fileSystemSize = dataPartition.getBlockCount()
- * dataPartition.getBlockSize();
- return calculateAppCacheMaxSize(fileSystemSize, freeSpace);
- }
-
- /*package*/ static long calculateAppCacheMaxSize(long fileSystemSizeBytes,
- long freeSpaceBytes) {
- if (fileSystemSizeBytes <= 0
- || freeSpaceBytes <= 0
- || freeSpaceBytes > fileSystemSizeBytes) {
- return 0;
- }
-
- long fileSystemSizeRatio =
- 4 << ((int) Math.floor(Math.log10(fileSystemSizeBytes / (1024 * 1024))));
- long maxSizeBytes = (long) Math.min(Math.floor(fileSystemSizeBytes / fileSystemSizeRatio),
- Math.floor(freeSpaceBytes / 4));
- // Round maxSizeBytes up to a multiple of 512KB (except when freeSpaceBytes < 1MB).
- long maxSizeStepBytes = 512 * 1024;
- if (freeSpaceBytes < maxSizeStepBytes * 2) {
- return 0;
- }
- return (maxSizeStepBytes * ((maxSizeBytes / maxSizeStepBytes) + 1));
- }
-
// Private constructor that does nothing.
private BrowserSettings() {
}
diff --git a/src/com/android/browser/PermissionDialog.java b/src/com/android/browser/PermissionDialog.java
deleted file mode 100644
index b71261a..0000000
--- a/src/com/android/browser/PermissionDialog.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.browser;
-
-import android.app.Activity;
-import android.app.Dialog;
-import android.content.Intent;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.Gravity;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.Window;
-import android.widget.ImageView;
-import android.widget.TextView;
-import android.widget.Toast;
-
-/**
- * Permission dialog for HTML5
- * @hide
- */
-public class PermissionDialog extends Activity {
-
- private static final String TAG = "PermissionDialog";
- public static final String PARAM_ORIGIN = "origin";
- public static final String PARAM_QUOTA = "quota";
-
- private String mWebStorageOrigin;
- private long mWebStorageQuota = 0;
- private int mNotification = 0;
-
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- getParameters();
- setupDialog();
- }
-
- private void getParameters() {
- Intent intent = getIntent();
- mWebStorageOrigin = intent.getStringExtra(PARAM_ORIGIN);
- mWebStorageQuota = intent.getLongExtra(PARAM_QUOTA, 0);
- }
-
- private void setupDialog() {
- requestWindowFeature(Window.FEATURE_NO_TITLE);
- setContentView(R.layout.permission_dialog);
-
- setIcon(R.id.icon, android.R.drawable.ic_popup_disk_full);
- setText(R.id.dialog_title, R.string.query_storage_quota_prompt);
- setText(R.id.dialog_message, R.string.query_storage_quota_message);
- setCharSequence(R.id.origin, mWebStorageOrigin);
-
- setupButton(R.id.button_allow, R.string.permission_button_allow,
- new View.OnClickListener() {
- public void onClick(View v) { allow(); }
- });
- setupButton(R.id.button_alwaysdeny, R.string.permission_button_alwaysdeny,
- new View.OnClickListener() {
- public void onClick(View v) { alwaysdeny(); }
- });
- setupButton(R.id.button_deny, R.string.permission_button_deny,
- new View.OnClickListener() {
- public void onClick(View v) { deny(); }
- });
- }
-
- private void setText(int viewID, int stringID) {
- setCharSequence(viewID, getString(stringID));
- }
-
- private void setCharSequence(int viewID, CharSequence string) {
- View view = findViewById(viewID);
- if (view == null) {
- return;
- }
- view.setVisibility(View.VISIBLE);
- TextView textView = (TextView) view;
- textView.setText(string);
- }
-
- private void setIcon(int viewID, int imageID) {
- View view = findViewById(viewID);
- if (view == null) {
- return;
- }
- view.setVisibility(View.VISIBLE);
- ImageView icon = (ImageView) view;
- icon.setImageResource(imageID);
- }
-
- private void setupButton(int viewID, int stringID,
- View.OnClickListener listener) {
- View view = findViewById(viewID);
- if (view == null) {
- return;
- }
- setText(viewID, stringID);
- view.setOnClickListener(listener);
- }
-
- private void useNextQuota() {
- CharSequence[] values = getResources().getTextArray(
- R.array.webstorage_quota_entries_values);
- for (int i=0; i<values.length; i++) {
- long value = Long.parseLong(values[i].toString());
- value *= (1024 * 1024); // the string array is expressed in MB
- if (value > mWebStorageQuota) {
- mWebStorageQuota = value;
- break;
- }
- }
- }
-
- private void allow() {
- // If somehow there is no "next quota" in the ladder,
- // we'll add 1MB anyway.
- mWebStorageQuota += 1024*1024;
- useNextQuota();
- mNotification = R.string.webstorage_notification;
- closeDialog();
- }
-
- private void alwaysdeny() {
- // Setting the quota to 0 will prevent any new data to be
- // added, but the existing data will not be deleted.
- mWebStorageQuota = 0;
- mNotification = R.string.webstorage_notification;
- closeDialog();
- }
-
- private void deny() {
- closeDialog();
- }
-
- private void closeDialog() {
- Intent intent = new Intent();
- intent.putExtra(PARAM_QUOTA, mWebStorageQuota);
- setResult(RESULT_OK, intent);
- showToast();
- finish();
- }
-
- private void showToast() {
- if (mNotification != 0) {
- Toast toast = Toast.makeText(this, mNotification, Toast.LENGTH_LONG);
- toast.setGravity(Gravity.BOTTOM, 0, 0);
- toast.show();
- }
- }
-
- public boolean dispatchKeyEvent(KeyEvent event) {
- if ((event.getKeyCode() == KeyEvent.KEYCODE_BACK)
- && (event.getAction() == KeyEvent.ACTION_DOWN)) {
- closeDialog();
- return true; // event consumed
- }
- return super.dispatchKeyEvent(event);
- }
-
-}
diff --git a/src/com/android/browser/WebStorageSizeManager.java b/src/com/android/browser/WebStorageSizeManager.java
new file mode 100644
index 0000000..e524f4c
--- /dev/null
+++ b/src/com/android/browser/WebStorageSizeManager.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.browser;
+
+import android.content.Context;
+import android.os.StatFs;
+import android.util.Log;
+import android.webkit.WebStorage;
+
+import java.io.File;
+import java.util.Set;
+
+
+/**
+ * Package level class for managing the disk size consumed by the WebDatabase
+ * and ApplicationCaches APIs (henceforth called Web storage).
+ *
+ * Currently, the situation on the WebKit side is as follows:
+ * - WebDatabase enforces a quota for each origin.
+ * - Session/LocalStorage do not enforce any disk limits.
+ * - ApplicationCaches enforces a maximum size for all origins.
+ *
+ * The WebStorageSizeManager maintains a global limit for the disk space
+ * consumed by the WebDatabase and ApplicationCaches. As soon as WebKit will
+ * have a limit for Session/LocalStorage, this class will manage the space used
+ * by those APIs as well.
+ *
+ * The global limit is computed as a function of the size of the partition where
+ * these APIs store their data (they must store it on the same partition for
+ * this to work) and the size of the available space on that partition.
+ * The global limit is not subject to user configuration but we do provide
+ * a debug-only setting.
+ * TODO(andreip): implement the debug setting.
+ *
+ * The size of the disk space used for Web storage is initially divided between
+ * WebDatabase and ApplicationCaches as follows:
+ *
+ * 75% for WebDatabase
+ * 25% for ApplicationCaches
+ *
+ * When an origin's database usage reaches its current quota, WebKit invokes
+ * the following callback function:
+ * - exceededDatabaseQuota(Frame* frame, const String& database_name);
+ * Note that the default quota for a new origin is 0, so we will receive the
+ * 'exceededDatabaseQuota' callback before a new origin gets the chance to
+ * create its first database.
+ *
+ * When the total ApplicationCaches usage reaches its current quota, WebKit
+ * invokes the following callback function:
+ * - void reachedMaxAppCacheSize(int64_t spaceNeeded);
+ *
+ * The WebStorageSizeManager's main job is to respond to the above two callbacks
+ * by inspecting the amount of unused Web storage quota (i.e. global limit -
+ * sum of all other origins' quota) and deciding if a quota increase for the
+ * out-of-space origin is allowed or not.
+ *
+ * The default quota for an origin is min(ORIGIN_DEFAULT_QUOTA, unused_quota).
+ * Quota increases are done in steps, where the increase step is
+ * min(QUOTA_INCREASE_STEP, unused_quota).
+ *
+ * This approach has the drawback that space may remain unused if there
+ * are many websites that store a lot less content than ORIGIN_DEFAULT_QUOTA.
+ * We deal with this by picking a value for ORIGIN_DEFAULT_QUOTA that is smaller
+ * than what the HTML 5 spec recommends. At the same time, picking a very small
+ * value for ORIGIN_DEFAULT_QUOTA may create performance problems since it's
+ * more likely for origins to have to rollback and restart transactions as a
+ * result of reaching the quota more often.
+ *
+ * When all the Web storage space is used, the WebStorageSizeManager creates
+ * a system notification that will guide the user to the WebSettings UI. There,
+ * the user can free some of the Web storage space by deleting all the data used
+ * by an origin.
+ * TODO(andreip): implement the notification.
+ */
+class WebStorageSizeManager {
+ // Logging flags.
+ private final static boolean LOGV_ENABLED = com.android.browser.Browser.LOGV_ENABLED;
+ private final static boolean LOGD_ENABLED = com.android.browser.Browser.LOGD_ENABLED;
+ private final static String LOGTAG = "browser";
+ // The default quota value for an origin.
+ private final static long ORIGIN_DEFAULT_QUOTA = 4 * 1024 * 1024; // 4MB
+ // The default value for quota increases.
+ private final static long QUOTA_INCREASE_STEP = 2 * 1024 * 1024; // 2MB
+ // The name of the application cache file. Keep in sync with
+ // WebCore/loader/appcache/ApplicationCacheStorage.cpp
+ private final static String APPCACHE_FILE = "ApplicationCache.db";
+ // The WebStorageSizeManager singleton.
+ private static WebStorageSizeManager mManager;
+ // The application context.
+ private Context mContext;
+ // The global Web storage limit.
+ private long mGlobalLimit;
+ // The maximum size of the application cache file.
+ private long mAppCacheMaxSize;
+
+ /**
+ * Factory method.
+ * @param path is a path on the partition where the app cache data is kept.
+ * @param ctx is the browser application context.
+ * @param storage is the WebStorage singleton.
+ *
+ */
+ public static WebStorageSizeManager getInstance(String appCachePath,
+ Context ctx) {
+ if (mManager == null) {
+ mManager = new WebStorageSizeManager(appCachePath, ctx);
+ }
+ return mManager;
+ }
+
+ /**
+ * Returns the maximum size of the application cache.
+ */
+ public long getAppCacheMaxSize() {
+ return mAppCacheMaxSize;
+ }
+
+ /**
+ * The origin has exceeded its database quota.
+ * @param url the URL that exceeded the quota
+ * @param databaseIdentifier the identifier of the database on
+ * which the transaction that caused the quota overflow was run
+ * @param currentQuota the current quota for the origin.
+ * @param totalUsedQuota is the sum of all origins' quota.
+ * @param quotaUpdater The callback to run when a decision to allow or
+ * deny quota has been made. Don't forget to call this!
+ */
+ public void onExceededDatabaseQuota(String url,
+ String databaseIdentifier, long currentQuota, long totalUsedQuota,
+ WebStorage.QuotaUpdater quotaUpdater) {
+ if(LOGV_ENABLED) {
+ Log.v(LOGTAG,
+ "Received onExceededDatabaseQuota for "
+ + url
+ + ":"
+ + databaseIdentifier
+ + "(current quota: "
+ + currentQuota
+ + ")");
+ }
+ long totalUnusedQuota = mGlobalLimit - totalUsedQuota - mAppCacheMaxSize;
+
+ if (totalUnusedQuota < QUOTA_INCREASE_STEP) {
+ // There definitely isn't any more space. Fire notifications
+ // and exit.
+ scheduleOutOfSpaceNotification();
+ quotaUpdater.updateQuota(currentQuota);
+ if(LOGV_ENABLED) {
+ Log.v(LOGTAG, "onExceededDatabaseQuota: out of space.");
+ }
+ return;
+ }
+ // We have enough space inside mGlobalLimit.
+ long newOriginQuota = currentQuota;
+ if (newOriginQuota == 0) {
+ // This is a new origin. It wants an initial quota. It is guaranteed
+ // to get at least ORIGIN_INCREASE_STEP bytes.
+ newOriginQuota =
+ Math.min(ORIGIN_DEFAULT_QUOTA, totalUnusedQuota);
+ } else {
+ // This is an origin we have seen before. It wants a quota
+ // increase.
+ newOriginQuota +=
+ Math.min(QUOTA_INCREASE_STEP, totalUnusedQuota);
+ }
+ quotaUpdater.updateQuota(newOriginQuota);
+
+ if(LOGV_ENABLED) {
+ Log.v(LOGTAG, "onExceededDatabaseQuota set new quota to "
+ + newOriginQuota);
+ }
+ }
+
+ /**
+ * The Application Cache has exceeded its max size.
+ * @param spaceNeeded is the amount of disk space that would be needed
+ * in order for the last appcache operation to succeed.
+ * @param totalUsedQuota is the sum of all origins' quota.
+ * @param quotaUpdater A callback to inform the WebCore thread that a new
+ * app cache size is available. This callback must always be executed at
+ * some point to ensure that the sleeping WebCore thread is woken up.
+ */
+ public void onReachedMaxAppCacheSize(long spaceNeeded, long totalUsedQuota,
+ WebStorage.QuotaUpdater quotaUpdater) {
+ if(LOGV_ENABLED) {
+ Log.v(LOGTAG, "Received onReachedMaxAppCacheSize with spaceNeeded "
+ + spaceNeeded + " bytes.");
+ }
+
+ long totalUnusedQuota = mGlobalLimit - totalUsedQuota - mAppCacheMaxSize;
+
+ if (totalUnusedQuota < spaceNeeded) {
+ // There definitely isn't any more space. Fire notifications
+ // and exit.
+ scheduleOutOfSpaceNotification();
+ quotaUpdater.updateQuota(0);
+ if(LOGV_ENABLED) {
+ Log.v(LOGTAG, "onReachedMaxAppCacheSize: out of space.");
+ }
+ return;
+ }
+ // There is enough space to accommodate spaceNeeded bytes.
+ mAppCacheMaxSize += spaceNeeded;
+ quotaUpdater.updateQuota(mAppCacheMaxSize);
+
+ if(LOGV_ENABLED) {
+ Log.v(LOGTAG, "onReachedMaxAppCacheSize set new max size to "
+ + mAppCacheMaxSize);
+ }
+ }
+
+ // Computes the global limit as a function of the size of the data
+ // partition and the amount of free space on that partition.
+ private long getGlobalLimit(String path) {
+ StatFs dataPartition = new StatFs(path);
+ long freeSpace = dataPartition.getAvailableBlocks()
+ * dataPartition.getBlockSize();
+ long fileSystemSize = dataPartition.getBlockCount()
+ * dataPartition.getBlockSize();
+ return calculateGlobalLimit(fileSystemSize, freeSpace);
+ }
+
+ // Returns the current size (in bytes) of the application cache file.
+ private long getCurrentAppCacheSize(String path) {
+ File file = new File(path + File.separator + APPCACHE_FILE);
+ return file.length();
+ }
+
+ /*package*/ static long calculateGlobalLimit(long fileSystemSizeBytes,
+ long freeSpaceBytes) {
+ if (fileSystemSizeBytes <= 0
+ || freeSpaceBytes <= 0
+ || freeSpaceBytes > fileSystemSizeBytes) {
+ return 0;
+ }
+
+ long fileSystemSizeRatio =
+ 2 << ((int) Math.floor(Math.log10(
+ fileSystemSizeBytes / (1024 * 1024))));
+ long maxSizeBytes = (long) Math.min(Math.floor(
+ fileSystemSizeBytes / fileSystemSizeRatio),
+ Math.floor(freeSpaceBytes / 2));
+ // Round maxSizeBytes up to a multiple of 1024KB (but only if
+ // maxSizeBytes > 1MB).
+ long maxSizeStepBytes = 1024 * 1024;
+ if (maxSizeBytes < maxSizeStepBytes) {
+ return 0;
+ }
+ long roundingExtra = maxSizeBytes % maxSizeStepBytes == 0 ? 0 : 1;
+ return (maxSizeStepBytes
+ * ((maxSizeBytes / maxSizeStepBytes) + roundingExtra));
+ }
+
+ // Schedules a system notification that takes the user to the WebSettings
+ // activity when clicked.
+ private void scheduleOutOfSpaceNotification() {
+ // TODO(andreip): implement.
+ }
+ // Private ctor.
+ private WebStorageSizeManager(String appCachePath, Context ctx) {
+ mContext = ctx;
+ mGlobalLimit = getGlobalLimit(appCachePath);
+ // The initial max size of the app cache is either 25% of the global
+ // limit or the current size of the app cache file, whichever is bigger.
+ mAppCacheMaxSize = Math.max(mGlobalLimit / 4,
+ getCurrentAppCacheSize(appCachePath));
+ }
+} \ No newline at end of file