WebSettings.java revision ec696c0115bbc915417bd76af6432bc603b680d2
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.ContentValues; 20import android.content.Context; 21import android.content.SharedPreferences; 22import android.os.Build; 23import android.os.Handler; 24import android.os.Message; 25import android.preference.PreferenceManager; 26import android.provider.Checkin; 27import android.provider.Settings; 28import android.util.Log; 29 30import java.io.File; 31import java.lang.SecurityException; 32 33import android.content.SharedPreferences.Editor; 34import android.content.pm.PackageManager; 35import android.database.sqlite.SQLiteDatabase; 36import android.database.sqlite.SQLiteException; 37import android.database.sqlite.SQLiteStatement; 38 39import java.util.HashSet; 40import java.util.Locale; 41 42/** 43 * Manages settings state for a WebView. When a WebView is first created, it 44 * obtains a set of default settings. These default settings will be returned 45 * from any getter call. A WebSettings object obtained from 46 * WebView.getSettings() is tied to the life of the WebView. If a WebView has 47 * been destroyed, any method call on WebSettings will throw an 48 * IllegalStateException. 49 */ 50public class WebSettings { 51 /** 52 * Enum for controlling the layout of html. 53 * NORMAL means no rendering changes. 54 * SINGLE_COLUMN moves all content into one column that is the width of the 55 * view. 56 * NARROW_COLUMNS makes all columns no wider than the screen if possible. 57 */ 58 // XXX: These must match LayoutAlgorithm in Settings.h in WebCore. 59 public enum LayoutAlgorithm { 60 NORMAL, 61 SINGLE_COLUMN, 62 NARROW_COLUMNS 63 } 64 65 /** 66 * Enum for specifying the text size. 67 * SMALLEST is 50% 68 * SMALLER is 75% 69 * NORMAL is 100% 70 * LARGER is 150% 71 * LARGEST is 200% 72 */ 73 public enum TextSize { 74 SMALLEST(50), 75 SMALLER(75), 76 NORMAL(100), 77 LARGER(150), 78 LARGEST(200); 79 TextSize(int size) { 80 value = size; 81 } 82 int value; 83 } 84 85 /** 86 * Enum for specifying the WebView's desired density. 87 * FAR makes 100% looking like in 240dpi 88 * MEDIUM makes 100% looking like in 160dpi 89 * CLOSE makes 100% looking like in 120dpi 90 * @hide Pending API council approval 91 */ 92 public enum ZoomDensity { 93 FAR(150), // 240dpi 94 MEDIUM(100), // 160dpi 95 CLOSE(75); // 120dpi 96 ZoomDensity(int size) { 97 value = size; 98 } 99 int value; 100 } 101 102 /** 103 * Default cache usage pattern Use with {@link #setCacheMode}. 104 */ 105 public static final int LOAD_DEFAULT = -1; 106 107 /** 108 * Normal cache usage pattern Use with {@link #setCacheMode}. 109 */ 110 public static final int LOAD_NORMAL = 0; 111 112 /** 113 * Use cache if content is there, even if expired (eg, history nav) 114 * If it is not in the cache, load from network. 115 * Use with {@link #setCacheMode}. 116 */ 117 public static final int LOAD_CACHE_ELSE_NETWORK = 1; 118 119 /** 120 * Don't use the cache, load from network 121 * Use with {@link #setCacheMode}. 122 */ 123 public static final int LOAD_NO_CACHE = 2; 124 125 /** 126 * Don't use the network, load from cache only. 127 * Use with {@link #setCacheMode}. 128 */ 129 public static final int LOAD_CACHE_ONLY = 3; 130 131 public enum RenderPriority { 132 NORMAL, 133 HIGH, 134 LOW 135 } 136 137 // WebView associated with this WebSettings. 138 private WebView mWebView; 139 // BrowserFrame used to access the native frame pointer. 140 private BrowserFrame mBrowserFrame; 141 // Flag to prevent multiple SYNC messages at one time. 142 private boolean mSyncPending = false; 143 // Custom handler that queues messages until the WebCore thread is active. 144 private final EventHandler mEventHandler; 145 146 // Private settings so we don't have to go into native code to 147 // retrieve the values. After setXXX, postSync() needs to be called. 148 // 149 // The default values need to match those in WebSettings.cpp 150 // If the defaults change, please also update the JavaDocs so developers 151 // know what they are. 152 private LayoutAlgorithm mLayoutAlgorithm = LayoutAlgorithm.NARROW_COLUMNS; 153 private Context mContext; 154 private TextSize mTextSize = TextSize.NORMAL; 155 private String mStandardFontFamily = "sans-serif"; 156 private String mFixedFontFamily = "monospace"; 157 private String mSansSerifFontFamily = "sans-serif"; 158 private String mSerifFontFamily = "serif"; 159 private String mCursiveFontFamily = "cursive"; 160 private String mFantasyFontFamily = "fantasy"; 161 private String mDefaultTextEncoding; 162 private String mUserAgent; 163 private boolean mUseDefaultUserAgent; 164 private String mAcceptLanguage; 165 private int mMinimumFontSize = 8; 166 private int mMinimumLogicalFontSize = 8; 167 private int mDefaultFontSize = 16; 168 private int mDefaultFixedFontSize = 13; 169 private boolean mLoadsImagesAutomatically = true; 170 private boolean mBlockNetworkImage = false; 171 private boolean mBlockNetworkLoads; 172 private boolean mJavaScriptEnabled = false; 173 private boolean mPluginsEnabled = false; 174 private long mWebStorageDefaultQuota = 0; 175 private boolean mJavaScriptCanOpenWindowsAutomatically = false; 176 private boolean mUseDoubleTree = false; 177 private boolean mUseWideViewport = false; 178 private boolean mSupportMultipleWindows = false; 179 private boolean mShrinksStandaloneImagesToFit = false; 180 // Don't need to synchronize the get/set methods as they 181 // are basic types, also none of these values are used in 182 // native WebCore code. 183 private ZoomDensity mDefaultZoom = ZoomDensity.MEDIUM; 184 private RenderPriority mRenderPriority = RenderPriority.NORMAL; 185 private int mOverrideCacheMode = LOAD_DEFAULT; 186 private boolean mSaveFormData = true; 187 private boolean mSavePassword = true; 188 private boolean mLightTouchEnabled = false; 189 private boolean mNeedInitialFocus = true; 190 private boolean mNavDump = false; 191 private boolean mSupportZoom = true; 192 private boolean mBuiltInZoomControls = false; 193 private boolean mAllowFileAccess = true; 194 private String mDatabasePath = ""; 195 private boolean mDatabaseEnabled = false; 196 private String mAppCachePath = ""; 197 private boolean mAppCacheEnabled = false; 198 private boolean mDomStorageEnabled = false; 199 200 // Donut-specific hack to keep Gears permissions in sync with the 201 // system location setting. 202 // TODO: Make sure this hack is removed in Eclair, when Gears 203 // is also removed. 204 // Used to remember if we checked the Gears permissions already. 205 static boolean mCheckedGearsPermissions = false; 206 // The Gears permissions database directory. 207 private final static String GEARS_DATABASE_DIR = "gears"; 208 // The Gears permissions database file name. 209 private final static String GEARS_DATABASE_FILE = "permissions.db"; 210 // The Gears location permissions table. 211 private final static String GEARS_LOCATION_ACCESS_TABLE_NAME = 212 "LocationAccess"; 213 // The Gears storage access permissions table. 214 private final static String GEARS_STORAGE_ACCESS_TABLE_NAME = "Access"; 215 // The Gears permissions db schema version table. 216 private final static String GEARS_SCHEMA_VERSION_TABLE_NAME = 217 "VersionInfo"; 218 // The shared pref name. 219 private static final String LAST_KNOWN_LOCATION_SETTING = 220 "lastKnownLocationSystemSetting"; 221 // The Browser package name. 222 private static final String BROWSER_PACKAGE_NAME = "com.android.browser"; 223 // The Google URLs whitelisted for Gears location access. 224 private static HashSet<String> sGearsWhiteList; 225 226 static { 227 sGearsWhiteList = new HashSet<String>(); 228 // NOTE: DO NOT ADD A "/" AT THE END! 229 sGearsWhiteList.add("http://www.google.com"); 230 sGearsWhiteList.add("http://www.google.co.uk"); 231 } 232 233 private static final String LOGTAG = "webcore"; 234 static final boolean DEBUG = false; 235 static final boolean LOGV_ENABLED = DEBUG; 236 237 // Class to handle messages before WebCore is ready. 238 private class EventHandler { 239 // Message id for syncing 240 static final int SYNC = 0; 241 // Message id for setting priority 242 static final int PRIORITY = 1; 243 // Actual WebCore thread handler 244 private Handler mHandler; 245 246 private synchronized void createHandler() { 247 // as mRenderPriority can be set before thread is running, sync up 248 setRenderPriority(); 249 250 // create a new handler 251 mHandler = new Handler() { 252 @Override 253 public void handleMessage(Message msg) { 254 switch (msg.what) { 255 case SYNC: 256 synchronized (WebSettings.this) { 257 checkGearsPermissions(); 258 if (mBrowserFrame.mNativeFrame != 0) { 259 nativeSync(mBrowserFrame.mNativeFrame); 260 } 261 mSyncPending = false; 262 } 263 break; 264 265 case PRIORITY: { 266 setRenderPriority(); 267 break; 268 } 269 } 270 } 271 }; 272 } 273 274 private void setRenderPriority() { 275 synchronized (WebSettings.this) { 276 if (mRenderPriority == RenderPriority.NORMAL) { 277 android.os.Process.setThreadPriority( 278 android.os.Process.THREAD_PRIORITY_DEFAULT); 279 } else if (mRenderPriority == RenderPriority.HIGH) { 280 android.os.Process.setThreadPriority( 281 android.os.Process.THREAD_PRIORITY_FOREGROUND + 282 android.os.Process.THREAD_PRIORITY_LESS_FAVORABLE); 283 } else if (mRenderPriority == RenderPriority.LOW) { 284 android.os.Process.setThreadPriority( 285 android.os.Process.THREAD_PRIORITY_BACKGROUND); 286 } 287 } 288 } 289 290 /** 291 * Send a message to the private queue or handler. 292 */ 293 private synchronized boolean sendMessage(Message msg) { 294 if (mHandler != null) { 295 mHandler.sendMessage(msg); 296 return true; 297 } else { 298 return false; 299 } 300 } 301 } 302 303 // User agent strings. 304 private static final String DESKTOP_USERAGENT = 305 "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_7; en-us)" 306 + " AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0" 307 + " Safari/530.17"; 308 private static final String IPHONE_USERAGENT = 309 "Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_0 like Mac OS X; en-us)" 310 + " AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0" 311 + " Mobile/7A341 Safari/528.16"; 312 private static Locale sLocale; 313 private static Object sLockForLocaleSettings; 314 315 /** 316 * Package constructor to prevent clients from creating a new settings 317 * instance. 318 */ 319 WebSettings(Context context, WebView webview) { 320 mEventHandler = new EventHandler(); 321 mContext = context; 322 mWebView = webview; 323 mDefaultTextEncoding = context.getString(com.android.internal. 324 R.string.default_text_encoding); 325 326 if (sLockForLocaleSettings == null) { 327 sLockForLocaleSettings = new Object(); 328 sLocale = Locale.getDefault(); 329 } 330 mAcceptLanguage = getCurrentAcceptLanguage(); 331 mUserAgent = getCurrentUserAgent(); 332 mUseDefaultUserAgent = true; 333 334 mBlockNetworkLoads = mContext.checkPermission( 335 "android.permission.INTERNET", android.os.Process.myPid(), 336 android.os.Process.myUid()) != PackageManager.PERMISSION_GRANTED; 337 } 338 339 /** 340 * Looks at sLocale and returns current AcceptLanguage String. 341 * @return Current AcceptLanguage String. 342 */ 343 private String getCurrentAcceptLanguage() { 344 Locale locale; 345 synchronized(sLockForLocaleSettings) { 346 locale = sLocale; 347 } 348 StringBuffer buffer = new StringBuffer(); 349 final String language = locale.getLanguage(); 350 if (language != null) { 351 buffer.append(language); 352 final String country = locale.getCountry(); 353 if (country != null) { 354 buffer.append("-"); 355 buffer.append(country); 356 } 357 } 358 if (!locale.equals(Locale.US)) { 359 buffer.append(", "); 360 java.util.Locale us = Locale.US; 361 if (us.getLanguage() != null) { 362 buffer.append(us.getLanguage()); 363 final String country = us.getCountry(); 364 if (country != null) { 365 buffer.append("-"); 366 buffer.append(country); 367 } 368 } 369 } 370 371 return buffer.toString(); 372 } 373 374 /** 375 * Looks at sLocale and mContext and returns current UserAgent String. 376 * @return Current UserAgent String. 377 */ 378 private synchronized String getCurrentUserAgent() { 379 Locale locale; 380 synchronized(sLockForLocaleSettings) { 381 locale = sLocale; 382 } 383 StringBuffer buffer = new StringBuffer(); 384 // Add version 385 final String version = Build.VERSION.RELEASE; 386 if (version.length() > 0) { 387 buffer.append(version); 388 } else { 389 // default to "1.0" 390 buffer.append("1.0"); 391 } 392 buffer.append("; "); 393 final String language = locale.getLanguage(); 394 if (language != null) { 395 buffer.append(language.toLowerCase()); 396 final String country = locale.getCountry(); 397 if (country != null) { 398 buffer.append("-"); 399 buffer.append(country.toLowerCase()); 400 } 401 } else { 402 // default to "en" 403 buffer.append("en"); 404 } 405 406 final String model = Build.MODEL; 407 if (model.length() > 0) { 408 buffer.append("; "); 409 buffer.append(model); 410 } 411 final String id = Build.ID; 412 if (id.length() > 0) { 413 buffer.append(" Build/"); 414 buffer.append(id); 415 } 416 final String base = mContext.getResources().getText( 417 com.android.internal.R.string.web_user_agent).toString(); 418 return String.format(base, buffer); 419 } 420 421 /** 422 * Enables dumping the pages navigation cache to a text file. 423 */ 424 public void setNavDump(boolean enabled) { 425 mNavDump = enabled; 426 } 427 428 /** 429 * Returns true if dumping the navigation cache is enabled. 430 */ 431 public boolean getNavDump() { 432 return mNavDump; 433 } 434 435 /** 436 * Set whether the WebView supports zoom 437 */ 438 public void setSupportZoom(boolean support) { 439 mSupportZoom = support; 440 } 441 442 /** 443 * Returns whether the WebView supports zoom 444 */ 445 public boolean supportZoom() { 446 return mSupportZoom; 447 } 448 449 /** 450 * Sets whether the zoom mechanism built into WebView is used. 451 */ 452 public void setBuiltInZoomControls(boolean enabled) { 453 mBuiltInZoomControls = enabled; 454 } 455 456 /** 457 * Returns true if the zoom mechanism built into WebView is being used. 458 */ 459 public boolean getBuiltInZoomControls() { 460 return mBuiltInZoomControls; 461 } 462 463 /** 464 * Enable or disable file access within WebView. File access is enabled by 465 * default. 466 */ 467 public void setAllowFileAccess(boolean allow) { 468 mAllowFileAccess = allow; 469 } 470 471 /** 472 * Returns true if this WebView supports file access. 473 */ 474 public boolean getAllowFileAccess() { 475 return mAllowFileAccess; 476 } 477 478 /** 479 * Store whether the WebView is saving form data. 480 */ 481 public void setSaveFormData(boolean save) { 482 mSaveFormData = save; 483 } 484 485 /** 486 * Return whether the WebView is saving form data. 487 */ 488 public boolean getSaveFormData() { 489 return mSaveFormData; 490 } 491 492 /** 493 * Store whether the WebView is saving password. 494 */ 495 public void setSavePassword(boolean save) { 496 mSavePassword = save; 497 } 498 499 /** 500 * Return whether the WebView is saving password. 501 */ 502 public boolean getSavePassword() { 503 return mSavePassword; 504 } 505 506 /** 507 * Set the text size of the page. 508 * @param t A TextSize value for increasing or decreasing the text. 509 * @see WebSettings.TextSize 510 */ 511 public synchronized void setTextSize(TextSize t) { 512 if (WebView.mLogEvent && mTextSize != t ) { 513 Checkin.updateStats(mContext.getContentResolver(), 514 Checkin.Stats.Tag.BROWSER_TEXT_SIZE_CHANGE, 1, 0.0); 515 } 516 mTextSize = t; 517 postSync(); 518 } 519 520 /** 521 * Get the text size of the page. 522 * @return A TextSize enum value describing the text size. 523 * @see WebSettings.TextSize 524 */ 525 public synchronized TextSize getTextSize() { 526 return mTextSize; 527 } 528 529 /** 530 * Set the default zoom density of the page. This should be called from UI 531 * thread. 532 * @param zoom A ZoomDensity value 533 * @see WebSettings.ZoomDensity 534 * @hide Pending API council approval 535 */ 536 public void setDefaultZoom(ZoomDensity zoom) { 537 if (mDefaultZoom != zoom) { 538 mDefaultZoom = zoom; 539 mWebView.updateDefaultZoomDensity(zoom.value); 540 } 541 } 542 543 /** 544 * Get the default zoom density of the page. This should be called from UI 545 * thread. 546 * @return A ZoomDensity value 547 * @see WebSettings.ZoomDensity 548 * @hide Pending API council approval 549 */ 550 public ZoomDensity getDefaultZoom() { 551 return mDefaultZoom; 552 } 553 554 /** 555 * Enables using light touches to make a selection and activate mouseovers. 556 */ 557 public void setLightTouchEnabled(boolean enabled) { 558 mLightTouchEnabled = enabled; 559 } 560 561 /** 562 * Returns true if light touches are enabled. 563 */ 564 public boolean getLightTouchEnabled() { 565 return mLightTouchEnabled; 566 } 567 568 /** 569 * @deprecated This setting controlled a rendering optimization 570 * that is no longer present. Setting it now has no effect. 571 */ 572 @Deprecated 573 public synchronized void setUseDoubleTree(boolean use) { 574 return; 575 } 576 577 /** 578 * @deprecated This setting controlled a rendering optimization 579 * that is no longer present. Setting it now has no effect. 580 */ 581 @Deprecated 582 public synchronized boolean getUseDoubleTree() { 583 return false; 584 } 585 586 /** 587 * Tell the WebView about user-agent string. 588 * @param ua 0 if the WebView should use an Android user-agent string, 589 * 1 if the WebView should use a desktop user-agent string. 590 * 591 * @deprecated Please use setUserAgentString instead. 592 */ 593 @Deprecated 594 public synchronized void setUserAgent(int ua) { 595 String uaString = null; 596 if (ua == 1) { 597 if (DESKTOP_USERAGENT.equals(mUserAgent)) { 598 return; // do nothing 599 } else { 600 uaString = DESKTOP_USERAGENT; 601 } 602 } else if (ua == 2) { 603 if (IPHONE_USERAGENT.equals(mUserAgent)) { 604 return; // do nothing 605 } else { 606 uaString = IPHONE_USERAGENT; 607 } 608 } else if (ua != 0) { 609 return; // do nothing 610 } 611 setUserAgentString(uaString); 612 } 613 614 /** 615 * Return user-agent as int 616 * @return int 0 if the WebView is using an Android user-agent string. 617 * 1 if the WebView is using a desktop user-agent string. 618 * -1 if the WebView is using user defined user-agent string. 619 * 620 * @deprecated Please use getUserAgentString instead. 621 */ 622 @Deprecated 623 public synchronized int getUserAgent() { 624 if (DESKTOP_USERAGENT.equals(mUserAgent)) { 625 return 1; 626 } else if (IPHONE_USERAGENT.equals(mUserAgent)) { 627 return 2; 628 } else if (mUseDefaultUserAgent) { 629 return 0; 630 } 631 return -1; 632 } 633 634 /** 635 * Tell the WebView to use the wide viewport 636 */ 637 public synchronized void setUseWideViewPort(boolean use) { 638 if (mUseWideViewport != use) { 639 mUseWideViewport = use; 640 postSync(); 641 } 642 } 643 644 /** 645 * @return True if the WebView is using a wide viewport 646 */ 647 public synchronized boolean getUseWideViewPort() { 648 return mUseWideViewport; 649 } 650 651 /** 652 * Tell the WebView whether it supports multiple windows. TRUE means 653 * that {@link WebChromeClient#onCreateWindow(WebView, boolean, 654 * boolean, Message)} is implemented by the host application. 655 */ 656 public synchronized void setSupportMultipleWindows(boolean support) { 657 if (mSupportMultipleWindows != support) { 658 mSupportMultipleWindows = support; 659 postSync(); 660 } 661 } 662 663 /** 664 * @return True if the WebView is supporting multiple windows. This means 665 * that {@link WebChromeClient#onCreateWindow(WebView, boolean, 666 * boolean, Message)} is implemented by the host application. 667 */ 668 public synchronized boolean supportMultipleWindows() { 669 return mSupportMultipleWindows; 670 } 671 672 /** 673 * Set the underlying layout algorithm. This will cause a relayout of the 674 * WebView. 675 * @param l A LayoutAlgorithm enum specifying the algorithm to use. 676 * @see WebSettings.LayoutAlgorithm 677 */ 678 public synchronized void setLayoutAlgorithm(LayoutAlgorithm l) { 679 // XXX: This will only be affective if libwebcore was built with 680 // ANDROID_LAYOUT defined. 681 if (mLayoutAlgorithm != l) { 682 mLayoutAlgorithm = l; 683 postSync(); 684 } 685 } 686 687 /** 688 * Return the current layout algorithm. The default is NARROW_COLUMNS. 689 * @return LayoutAlgorithm enum value describing the layout algorithm 690 * being used. 691 * @see WebSettings.LayoutAlgorithm 692 */ 693 public synchronized LayoutAlgorithm getLayoutAlgorithm() { 694 return mLayoutAlgorithm; 695 } 696 697 /** 698 * Set the standard font family name. 699 * @param font A font family name. 700 */ 701 public synchronized void setStandardFontFamily(String font) { 702 if (font != null && !font.equals(mStandardFontFamily)) { 703 mStandardFontFamily = font; 704 postSync(); 705 } 706 } 707 708 /** 709 * Get the standard font family name. The default is "sans-serif". 710 * @return The standard font family name as a string. 711 */ 712 public synchronized String getStandardFontFamily() { 713 return mStandardFontFamily; 714 } 715 716 /** 717 * Set the fixed font family name. 718 * @param font A font family name. 719 */ 720 public synchronized void setFixedFontFamily(String font) { 721 if (font != null && !font.equals(mFixedFontFamily)) { 722 mFixedFontFamily = font; 723 postSync(); 724 } 725 } 726 727 /** 728 * Get the fixed font family name. The default is "monospace". 729 * @return The fixed font family name as a string. 730 */ 731 public synchronized String getFixedFontFamily() { 732 return mFixedFontFamily; 733 } 734 735 /** 736 * Set the sans-serif font family name. 737 * @param font A font family name. 738 */ 739 public synchronized void setSansSerifFontFamily(String font) { 740 if (font != null && !font.equals(mSansSerifFontFamily)) { 741 mSansSerifFontFamily = font; 742 postSync(); 743 } 744 } 745 746 /** 747 * Get the sans-serif font family name. 748 * @return The sans-serif font family name as a string. 749 */ 750 public synchronized String getSansSerifFontFamily() { 751 return mSansSerifFontFamily; 752 } 753 754 /** 755 * Set the serif font family name. The default is "sans-serif". 756 * @param font A font family name. 757 */ 758 public synchronized void setSerifFontFamily(String font) { 759 if (font != null && !font.equals(mSerifFontFamily)) { 760 mSerifFontFamily = font; 761 postSync(); 762 } 763 } 764 765 /** 766 * Get the serif font family name. The default is "serif". 767 * @return The serif font family name as a string. 768 */ 769 public synchronized String getSerifFontFamily() { 770 return mSerifFontFamily; 771 } 772 773 /** 774 * Set the cursive font family name. 775 * @param font A font family name. 776 */ 777 public synchronized void setCursiveFontFamily(String font) { 778 if (font != null && !font.equals(mCursiveFontFamily)) { 779 mCursiveFontFamily = font; 780 postSync(); 781 } 782 } 783 784 /** 785 * Get the cursive font family name. The default is "cursive". 786 * @return The cursive font family name as a string. 787 */ 788 public synchronized String getCursiveFontFamily() { 789 return mCursiveFontFamily; 790 } 791 792 /** 793 * Set the fantasy font family name. 794 * @param font A font family name. 795 */ 796 public synchronized void setFantasyFontFamily(String font) { 797 if (font != null && !font.equals(mFantasyFontFamily)) { 798 mFantasyFontFamily = font; 799 postSync(); 800 } 801 } 802 803 /** 804 * Get the fantasy font family name. The default is "fantasy". 805 * @return The fantasy font family name as a string. 806 */ 807 public synchronized String getFantasyFontFamily() { 808 return mFantasyFontFamily; 809 } 810 811 /** 812 * Set the minimum font size. 813 * @param size A non-negative integer between 1 and 72. 814 * Any number outside the specified range will be pinned. 815 */ 816 public synchronized void setMinimumFontSize(int size) { 817 size = pin(size); 818 if (mMinimumFontSize != size) { 819 mMinimumFontSize = size; 820 postSync(); 821 } 822 } 823 824 /** 825 * Get the minimum font size. The default is 8. 826 * @return A non-negative integer between 1 and 72. 827 */ 828 public synchronized int getMinimumFontSize() { 829 return mMinimumFontSize; 830 } 831 832 /** 833 * Set the minimum logical font size. 834 * @param size A non-negative integer between 1 and 72. 835 * Any number outside the specified range will be pinned. 836 */ 837 public synchronized void setMinimumLogicalFontSize(int size) { 838 size = pin(size); 839 if (mMinimumLogicalFontSize != size) { 840 mMinimumLogicalFontSize = size; 841 postSync(); 842 } 843 } 844 845 /** 846 * Get the minimum logical font size. The default is 8. 847 * @return A non-negative integer between 1 and 72. 848 */ 849 public synchronized int getMinimumLogicalFontSize() { 850 return mMinimumLogicalFontSize; 851 } 852 853 /** 854 * Set the default font size. 855 * @param size A non-negative integer between 1 and 72. 856 * Any number outside the specified range will be pinned. 857 */ 858 public synchronized void setDefaultFontSize(int size) { 859 size = pin(size); 860 if (mDefaultFontSize != size) { 861 mDefaultFontSize = size; 862 postSync(); 863 } 864 } 865 866 /** 867 * Get the default font size. The default is 16. 868 * @return A non-negative integer between 1 and 72. 869 */ 870 public synchronized int getDefaultFontSize() { 871 return mDefaultFontSize; 872 } 873 874 /** 875 * Set the default fixed font size. 876 * @param size A non-negative integer between 1 and 72. 877 * Any number outside the specified range will be pinned. 878 */ 879 public synchronized void setDefaultFixedFontSize(int size) { 880 size = pin(size); 881 if (mDefaultFixedFontSize != size) { 882 mDefaultFixedFontSize = size; 883 postSync(); 884 } 885 } 886 887 /** 888 * Get the default fixed font size. The default is 16. 889 * @return A non-negative integer between 1 and 72. 890 */ 891 public synchronized int getDefaultFixedFontSize() { 892 return mDefaultFixedFontSize; 893 } 894 895 /** 896 * Tell the WebView to load image resources automatically. 897 * @param flag True if the WebView should load images automatically. 898 */ 899 public synchronized void setLoadsImagesAutomatically(boolean flag) { 900 if (mLoadsImagesAutomatically != flag) { 901 mLoadsImagesAutomatically = flag; 902 postSync(); 903 } 904 } 905 906 /** 907 * Return true if the WebView will load image resources automatically. 908 * The default is true. 909 * @return True if the WebView loads images automatically. 910 */ 911 public synchronized boolean getLoadsImagesAutomatically() { 912 return mLoadsImagesAutomatically; 913 } 914 915 /** 916 * Tell the WebView to block network image. This is only checked when 917 * getLoadsImagesAutomatically() is true. 918 * @param flag True if the WebView should block network image 919 */ 920 public synchronized void setBlockNetworkImage(boolean flag) { 921 if (mBlockNetworkImage != flag) { 922 mBlockNetworkImage = flag; 923 postSync(); 924 } 925 } 926 927 /** 928 * Return true if the WebView will block network image. The default is false. 929 * @return True if the WebView blocks network image. 930 */ 931 public synchronized boolean getBlockNetworkImage() { 932 return mBlockNetworkImage; 933 } 934 935 /** 936 * @hide 937 * Tell the WebView to block all network load requests. 938 * @param flag True if the WebView should block all network loads 939 */ 940 public synchronized void setBlockNetworkLoads(boolean flag) { 941 if (mBlockNetworkLoads != flag) { 942 mBlockNetworkLoads = flag; 943 verifyNetworkAccess(); 944 } 945 } 946 947 /** 948 * @hide 949 * Return true if the WebView will block all network loads. 950 * The default is false. 951 * @return True if the WebView blocks all network loads. 952 */ 953 public synchronized boolean getBlockNetworkLoads() { 954 return mBlockNetworkLoads; 955 } 956 957 958 private void verifyNetworkAccess() { 959 if (!mBlockNetworkLoads) { 960 if (mContext.checkPermission("android.permission.INTERNET", 961 android.os.Process.myPid(), android.os.Process.myUid()) != 962 PackageManager.PERMISSION_GRANTED) { 963 throw new SecurityException 964 ("Permission denied - " + 965 "application missing INTERNET permission"); 966 } 967 } 968 } 969 970 /** 971 * Tell the WebView to enable javascript execution. 972 * @param flag True if the WebView should execute javascript. 973 */ 974 public synchronized void setJavaScriptEnabled(boolean flag) { 975 if (mJavaScriptEnabled != flag) { 976 mJavaScriptEnabled = flag; 977 postSync(); 978 } 979 } 980 981 /** 982 * Tell the WebView to enable plugins. 983 * @param flag True if the WebView should load plugins. 984 */ 985 public synchronized void setPluginsEnabled(boolean flag) { 986 if (mPluginsEnabled != flag) { 987 mPluginsEnabled = flag; 988 postSync(); 989 } 990 } 991 992 /** 993 * TODO: need to add @Deprecated 994 */ 995 public synchronized void setPluginsPath(String pluginsPath) { 996 } 997 998 /** 999 * @hide 1000 * Set the default quota for WebStorage DBs 1001 * @param quota the default quota in bytes 1002 */ 1003 public synchronized void setWebStorageDefaultQuota(long quota) { 1004 if (mWebStorageDefaultQuota != quota) { 1005 mWebStorageDefaultQuota = quota; 1006 postSync(); 1007 } 1008 } 1009 1010 /** 1011 * Set the path to where database storage API databases should be saved. 1012 * This will update WebCore when the Sync runs in the C++ side. 1013 * @param databasePath String path to the directory where databases should 1014 * be saved. May be the empty string but should never be null. 1015 */ 1016 public synchronized void setDatabasePath(String databasePath) { 1017 if (databasePath != null && !databasePath.equals(mDatabasePath)) { 1018 mDatabasePath = databasePath; 1019 postSync(); 1020 } 1021 } 1022 1023 /** 1024 * Tell the WebView to enable Application Caches API. 1025 * @param flag True if the WebView should enable Application Caches. 1026 * @hide pending api council approval 1027 */ 1028 public synchronized void setAppCacheEnabled(boolean flag) { 1029 if (mAppCacheEnabled != flag) { 1030 mAppCacheEnabled = flag; 1031 postSync(); 1032 } 1033 } 1034 1035 /** 1036 * Set a custom path to the Application Caches files. The client 1037 * must ensure it exists before this call. 1038 * @param appCachePath String path to the directory containing Application 1039 * Caches files. The appCache path can be the empty string but should not 1040 * be null. Passing null for this parameter will result in a no-op. 1041 * @hide pending api council approval 1042 */ 1043 public synchronized void setAppCachePath(String appCachePath) { 1044 if (appCachePath != null && !appCachePath.equals(mAppCachePath)) { 1045 mAppCachePath = appCachePath; 1046 postSync(); 1047 } 1048 } 1049 1050 /** 1051 * Set whether the database storage API is enabled. 1052 * @param flag boolean True if the WebView should use the database storage 1053 * API. 1054 */ 1055 public synchronized void setDatabaseEnabled(boolean flag) { 1056 if (mDatabaseEnabled != flag) { 1057 mDatabaseEnabled = flag; 1058 postSync(); 1059 } 1060 } 1061 1062 /** 1063 * Set whether the DOM storage API is enabled. 1064 * @param flag boolean True if the WebView should use the DOM storage 1065 * API. 1066 * @hide pending API council. 1067 */ 1068 public synchronized void setDomStorageEnabled(boolean flag) { 1069 if (mDomStorageEnabled != flag) { 1070 mDomStorageEnabled = flag; 1071 postSync(); 1072 } 1073 } 1074 1075 /** 1076 * Returns true if the DOM Storage API's are enabled. 1077 * @return True if the DOM Storage API's are enabled. 1078 * @hide pending API council. 1079 */ 1080 public synchronized boolean getDomStorageEnabled() { 1081 return mDomStorageEnabled; 1082 } 1083 1084 /** 1085 * Return the path to where database storage API databases are saved for 1086 * the current WebView. 1087 * @return the String path to the database storage API databases. 1088 */ 1089 public synchronized String getDatabasePath() { 1090 return mDatabasePath; 1091 } 1092 1093 /** 1094 * Returns true if database storage API is enabled. 1095 * @return True if the database storage API is enabled. 1096 */ 1097 public synchronized boolean getDatabaseEnabled() { 1098 return mDatabaseEnabled; 1099 } 1100 1101 /** 1102 * Return true if javascript is enabled. <b>Note: The default is false.</b> 1103 * @return True if javascript is enabled. 1104 */ 1105 public synchronized boolean getJavaScriptEnabled() { 1106 return mJavaScriptEnabled; 1107 } 1108 1109 /** 1110 * Return true if plugins are enabled. 1111 * @return True if plugins are enabled. 1112 */ 1113 public synchronized boolean getPluginsEnabled() { 1114 return mPluginsEnabled; 1115 } 1116 1117 /** 1118 * TODO: need to add @Deprecated 1119 */ 1120 public synchronized String getPluginsPath() { 1121 return ""; 1122 } 1123 1124 /** 1125 * @hide 1126 * Return the default quota for WebStorage DBs 1127 * @return the default quota in bytes 1128 */ 1129 public synchronized long getWebStorageDefaultQuota() { 1130 return mWebStorageDefaultQuota; 1131 } 1132 1133 /** 1134 * Tell javascript to open windows automatically. This applies to the 1135 * javascript function window.open(). 1136 * @param flag True if javascript can open windows automatically. 1137 */ 1138 public synchronized void setJavaScriptCanOpenWindowsAutomatically( 1139 boolean flag) { 1140 if (mJavaScriptCanOpenWindowsAutomatically != flag) { 1141 mJavaScriptCanOpenWindowsAutomatically = flag; 1142 postSync(); 1143 } 1144 } 1145 1146 /** 1147 * Return true if javascript can open windows automatically. The default 1148 * is false. 1149 * @return True if javascript can open windows automatically during 1150 * window.open(). 1151 */ 1152 public synchronized boolean getJavaScriptCanOpenWindowsAutomatically() { 1153 return mJavaScriptCanOpenWindowsAutomatically; 1154 } 1155 1156 /** 1157 * Set the default text encoding name to use when decoding html pages. 1158 * @param encoding The text encoding name. 1159 */ 1160 public synchronized void setDefaultTextEncodingName(String encoding) { 1161 if (encoding != null && !encoding.equals(mDefaultTextEncoding)) { 1162 mDefaultTextEncoding = encoding; 1163 postSync(); 1164 } 1165 } 1166 1167 /** 1168 * Get the default text encoding name. The default is "Latin-1". 1169 * @return The default text encoding name as a string. 1170 */ 1171 public synchronized String getDefaultTextEncodingName() { 1172 return mDefaultTextEncoding; 1173 } 1174 1175 /** 1176 * Set the WebView's user-agent string. If the string "ua" is null or empty, 1177 * it will use the system default user-agent string. 1178 */ 1179 public synchronized void setUserAgentString(String ua) { 1180 if (ua == null || ua.length() == 0) { 1181 synchronized(sLockForLocaleSettings) { 1182 Locale currentLocale = Locale.getDefault(); 1183 if (!sLocale.equals(currentLocale)) { 1184 sLocale = currentLocale; 1185 mAcceptLanguage = getCurrentAcceptLanguage(); 1186 } 1187 } 1188 ua = getCurrentUserAgent(); 1189 mUseDefaultUserAgent = true; 1190 } else { 1191 mUseDefaultUserAgent = false; 1192 } 1193 1194 if (!ua.equals(mUserAgent)) { 1195 mUserAgent = ua; 1196 postSync(); 1197 } 1198 } 1199 1200 /** 1201 * Return the WebView's user-agent string. 1202 */ 1203 public synchronized String getUserAgentString() { 1204 if (DESKTOP_USERAGENT.equals(mUserAgent) || 1205 IPHONE_USERAGENT.equals(mUserAgent) || 1206 !mUseDefaultUserAgent) { 1207 return mUserAgent; 1208 } 1209 1210 boolean doPostSync = false; 1211 synchronized(sLockForLocaleSettings) { 1212 Locale currentLocale = Locale.getDefault(); 1213 if (!sLocale.equals(currentLocale)) { 1214 sLocale = currentLocale; 1215 mUserAgent = getCurrentUserAgent(); 1216 mAcceptLanguage = getCurrentAcceptLanguage(); 1217 doPostSync = true; 1218 } 1219 } 1220 if (doPostSync) { 1221 postSync(); 1222 } 1223 return mUserAgent; 1224 } 1225 1226 /* package api to grab the Accept Language string. */ 1227 /*package*/ synchronized String getAcceptLanguage() { 1228 synchronized(sLockForLocaleSettings) { 1229 Locale currentLocale = Locale.getDefault(); 1230 if (!sLocale.equals(currentLocale)) { 1231 sLocale = currentLocale; 1232 mAcceptLanguage = getCurrentAcceptLanguage(); 1233 } 1234 } 1235 return mAcceptLanguage; 1236 } 1237 1238 /** 1239 * Tell the WebView whether it needs to set a node to have focus when 1240 * {@link WebView#requestFocus(int, android.graphics.Rect)} is called. 1241 * 1242 * @param flag 1243 */ 1244 public void setNeedInitialFocus(boolean flag) { 1245 if (mNeedInitialFocus != flag) { 1246 mNeedInitialFocus = flag; 1247 } 1248 } 1249 1250 /* Package api to get the choice whether it needs to set initial focus. */ 1251 /* package */ boolean getNeedInitialFocus() { 1252 return mNeedInitialFocus; 1253 } 1254 1255 /** 1256 * Set the priority of the Render thread. Unlike the other settings, this 1257 * one only needs to be called once per process. The default is NORMAL. 1258 * 1259 * @param priority RenderPriority, can be normal, high or low. 1260 */ 1261 public synchronized void setRenderPriority(RenderPriority priority) { 1262 if (mRenderPriority != priority) { 1263 mRenderPriority = priority; 1264 mEventHandler.sendMessage(Message.obtain(null, 1265 EventHandler.PRIORITY)); 1266 } 1267 } 1268 1269 /** 1270 * Override the way the cache is used. The way the cache is used is based 1271 * on the navigation option. For a normal page load, the cache is checked 1272 * and content is re-validated as needed. When navigating back, content is 1273 * not revalidated, instead the content is just pulled from the cache. 1274 * This function allows the client to override this behavior. 1275 * @param mode One of the LOAD_ values. 1276 */ 1277 public void setCacheMode(int mode) { 1278 if (mode != mOverrideCacheMode) { 1279 mOverrideCacheMode = mode; 1280 } 1281 } 1282 1283 /** 1284 * Return the current setting for overriding the cache mode. For a full 1285 * description, see the {@link #setCacheMode(int)} function. 1286 */ 1287 public int getCacheMode() { 1288 return mOverrideCacheMode; 1289 } 1290 1291 /** 1292 * If set, webkit alternately shrinks and expands images viewed outside 1293 * of an HTML page to fit the screen. This conflicts with attempts by 1294 * the UI to zoom in and out of an image, so it is set false by default. 1295 * @param shrink Set true to let webkit shrink the standalone image to fit. 1296 * {@hide} 1297 */ 1298 public void setShrinksStandaloneImagesToFit(boolean shrink) { 1299 if (mShrinksStandaloneImagesToFit != shrink) { 1300 mShrinksStandaloneImagesToFit = shrink; 1301 postSync(); 1302 } 1303 } 1304 1305 /** 1306 * Transfer messages from the queue to the new WebCoreThread. Called from 1307 * WebCore thread. 1308 */ 1309 /*package*/ 1310 synchronized void syncSettingsAndCreateHandler(BrowserFrame frame) { 1311 mBrowserFrame = frame; 1312 if (DebugFlags.WEB_SETTINGS) { 1313 junit.framework.Assert.assertTrue(frame.mNativeFrame != 0); 1314 } 1315 nativeSync(frame.mNativeFrame); 1316 mSyncPending = false; 1317 mEventHandler.createHandler(); 1318 } 1319 1320 private int pin(int size) { 1321 // FIXME: 72 is just an arbitrary max text size value. 1322 if (size < 1) { 1323 return 1; 1324 } else if (size > 72) { 1325 return 72; 1326 } 1327 return size; 1328 } 1329 1330 private void checkGearsPermissions() { 1331 // Did we already check the permissions? 1332 if (mCheckedGearsPermissions) { 1333 return; 1334 } 1335 // Are we running in the browser? 1336 if (!BROWSER_PACKAGE_NAME.equals(mContext.getPackageName())) { 1337 return; 1338 } 1339 1340 // Remember we checked the Gears permissions. 1341 mCheckedGearsPermissions = true; 1342 // Get the current system settings. 1343 int setting = Settings.Secure.getInt(mContext.getContentResolver(), 1344 Settings.Secure.USE_LOCATION_FOR_SERVICES, -1); 1345 // Check if we need to set the Gears permissions. 1346 if (setting != -1 && locationSystemSettingChanged(setting)) { 1347 setGearsPermissionForGoogleDomains(setting); 1348 } 1349 } 1350 1351 private boolean locationSystemSettingChanged(int newSetting) { 1352 SharedPreferences prefs = 1353 PreferenceManager.getDefaultSharedPreferences(mContext); 1354 int oldSetting = 0; 1355 oldSetting = prefs.getInt(LAST_KNOWN_LOCATION_SETTING, oldSetting); 1356 if (oldSetting == newSetting) { 1357 return false; 1358 } 1359 Editor ed = prefs.edit(); 1360 ed.putInt(LAST_KNOWN_LOCATION_SETTING, newSetting); 1361 ed.commit(); 1362 return true; 1363 } 1364 1365 private void setGearsPermissionForGoogleDomains(int systemPermission) { 1366 // Transform the system permission into a Gears permission 1367 int gearsPermission = (systemPermission == 1 ? 1 : 2); 1368 // Build the path to the Gears library. 1369 1370 // hack for now 1371 File file = mContext.getDir("plugins", 0); 1372 if (file == null) { 1373 return; 1374 } 1375 file = file.getParentFile(); 1376 // Build the Gears database file name. 1377 file = new File(file.getAbsolutePath() + File.separator 1378 + GEARS_DATABASE_DIR + File.separator + GEARS_DATABASE_FILE); 1379 // Remember whether or not we need to create the LocationAccess table. 1380 boolean needToCreateTables = !file.exists(); 1381 // Try opening the Gears database. 1382 SQLiteDatabase permissions; 1383 try { 1384 permissions = SQLiteDatabase.openOrCreateDatabase(file, null); 1385 } catch (SQLiteException e) { 1386 if (LOGV_ENABLED) { 1387 Log.v(LOGTAG, "Could not open Gears permission DB: " + 1388 e.getMessage()); 1389 } 1390 // Just bail out. 1391 return; 1392 } 1393 // We now have a database open. Begin a transaction. 1394 permissions.beginTransaction(); 1395 try { 1396 if (needToCreateTables) { 1397 // Create the tables. Note that this creates the 1398 // Gears tables for the permissions DB schema version 2. 1399 // The Gears schema upgrade process will take care of the rest. 1400 // First, the storage access table. 1401 SQLiteStatement statement = permissions.compileStatement( 1402 "CREATE TABLE IF NOT EXISTS " + 1403 GEARS_STORAGE_ACCESS_TABLE_NAME + 1404 " (Name TEXT UNIQUE, Value)"); 1405 statement.execute(); 1406 // Next the location access table. 1407 statement = permissions.compileStatement( 1408 "CREATE TABLE IF NOT EXISTS " + 1409 GEARS_LOCATION_ACCESS_TABLE_NAME + 1410 " (Name TEXT UNIQUE, Value)"); 1411 statement.execute(); 1412 // Finally, the schema version table. 1413 statement = permissions.compileStatement( 1414 "CREATE TABLE IF NOT EXISTS " + 1415 GEARS_SCHEMA_VERSION_TABLE_NAME + 1416 " (Name TEXT UNIQUE, Value)"); 1417 statement.execute(); 1418 // Set the schema version to 2. 1419 ContentValues schema = new ContentValues(); 1420 schema.put("Name", "Version"); 1421 schema.put("Value", 2); 1422 permissions.insert(GEARS_SCHEMA_VERSION_TABLE_NAME, null, 1423 schema); 1424 } 1425 1426 ContentValues permissionValues = new ContentValues(); 1427 1428 for (String url : sGearsWhiteList) { 1429 permissionValues.put("Name", url); 1430 permissionValues.put("Value", gearsPermission); 1431 permissions.replace(GEARS_LOCATION_ACCESS_TABLE_NAME, null, 1432 permissionValues); 1433 permissionValues.clear(); 1434 } 1435 // Commit the transaction. 1436 permissions.setTransactionSuccessful(); 1437 } catch (SQLiteException e) { 1438 if (LOGV_ENABLED) { 1439 Log.v(LOGTAG, "Could not set the Gears permissions: " + 1440 e.getMessage()); 1441 } 1442 } finally { 1443 permissions.endTransaction(); 1444 permissions.close(); 1445 } 1446 } 1447 /* Post a SYNC message to handle syncing the native settings. */ 1448 private synchronized void postSync() { 1449 // Only post if a sync is not pending 1450 if (!mSyncPending) { 1451 mSyncPending = mEventHandler.sendMessage( 1452 Message.obtain(null, EventHandler.SYNC)); 1453 } 1454 } 1455 1456 // Synchronize the native and java settings. 1457 private native void nativeSync(int nativeFrame); 1458} 1459