1 /* 2 * Copyright 2007, The Android Open Source Project 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * * Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * * Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #define LOG_TAG "WebCore" 27 28 #include "config.h" 29 30 #include "ApplicationCacheStorage.h" 31 #include "ChromeClientAndroid.h" 32 #include "DatabaseTracker.h" 33 #include "Document.h" 34 #include "PlatformString.h" 35 #include "FloatRect.h" 36 #include "Frame.h" 37 #include "FrameLoader.h" 38 #include "FrameView.h" 39 #include "Geolocation.h" 40 #include "HTMLMediaElement.h" 41 #include "HTMLNames.h" 42 #include "Icon.h" 43 #include "LayerAndroid.h" 44 #include "Page.h" 45 #include "PopupMenuAndroid.h" 46 #include "ScriptController.h" 47 #include "SearchPopupMenuAndroid.h" 48 #include "WebCoreFrameBridge.h" 49 #include "WebCoreViewBridge.h" 50 #include "WebViewCore.h" 51 #include "WindowFeatures.h" 52 #include "Settings.h" 53 #include "UserGestureIndicator.h" 54 #include <wtf/text/CString.h> 55 56 namespace android { 57 58 #if ENABLE(DATABASE) 59 static unsigned long long tryToReclaimDatabaseQuota(SecurityOrigin* originNeedingQuota); 60 #endif 61 62 #if USE(ACCELERATED_COMPOSITING) 63 64 WebCore::GraphicsLayer* ChromeClientAndroid::layersSync() 65 { 66 if (m_rootGraphicsLayer && m_needsLayerSync && m_webFrame) { 67 if (FrameView* frameView = m_webFrame->page()->mainFrame()->view()) 68 frameView->syncCompositingStateIncludingSubframes(); 69 } 70 m_needsLayerSync = false; 71 return m_rootGraphicsLayer; 72 } 73 74 void ChromeClientAndroid::scheduleCompositingLayerSync() 75 { 76 if (m_needsLayerSync) 77 return; 78 m_needsLayerSync = true; 79 WebViewCore* webViewCore = WebViewCore::getWebViewCore(m_webFrame->page()->mainFrame()->view()); 80 if (webViewCore) 81 webViewCore->layersDraw(); 82 } 83 84 void ChromeClientAndroid::setNeedsOneShotDrawingSynchronization() 85 { 86 // This should not be needed 87 } 88 89 void ChromeClientAndroid::attachRootGraphicsLayer(WebCore::Frame*, WebCore::GraphicsLayer* layer) 90 { 91 // frame is not used in Android as we should only get root graphics layer for the main frame 92 m_rootGraphicsLayer = layer; 93 if (!layer) 94 return; 95 scheduleCompositingLayerSync(); 96 } 97 98 #endif 99 100 void ChromeClientAndroid::setWebFrame(android::WebFrame* webframe) 101 { 102 Release(m_webFrame); 103 m_webFrame = webframe; 104 Retain(m_webFrame); 105 } 106 107 void ChromeClientAndroid::chromeDestroyed() 108 { 109 Release(m_webFrame); 110 delete this; 111 } 112 113 void ChromeClientAndroid::setWindowRect(const FloatRect&) { notImplemented(); } 114 115 FloatRect ChromeClientAndroid::windowRect() { 116 ASSERT(m_webFrame); 117 if (!m_webFrame) 118 return FloatRect(); 119 FrameView* frameView = m_webFrame->page()->mainFrame()->view(); 120 if (!frameView) 121 return FloatRect(); 122 const WebCoreViewBridge* bridge = frameView->platformWidget(); 123 const IntRect& rect = bridge->getWindowBounds(); 124 FloatRect fRect(rect.x(), rect.y(), rect.width(), rect.height()); 125 return fRect; 126 } 127 128 FloatRect ChromeClientAndroid::pageRect() { notImplemented(); return FloatRect(); } 129 130 float ChromeClientAndroid::scaleFactor() 131 { 132 ASSERT(m_webFrame); 133 return m_webFrame->density(); 134 } 135 136 void ChromeClientAndroid::focus() 137 { 138 ASSERT(m_webFrame); 139 bool isUserGesture = UserGestureIndicator::processingUserGesture(); 140 141 // Ask the application to focus this WebView if the action is intiated by the user 142 if (isUserGesture) 143 m_webFrame->requestFocus(); 144 } 145 void ChromeClientAndroid::unfocus() { notImplemented(); } 146 147 bool ChromeClientAndroid::canTakeFocus(FocusDirection) { notImplemented(); return false; } 148 void ChromeClientAndroid::takeFocus(FocusDirection) { notImplemented(); } 149 150 void ChromeClientAndroid::focusedNodeChanged(Node* node) 151 { 152 android::WebViewCore::getWebViewCore(m_webFrame->page()->mainFrame()->view())->focusNodeChanged(node); 153 } 154 155 void ChromeClientAndroid::focusedFrameChanged(Frame*) { notImplemented(); } 156 157 Page* ChromeClientAndroid::createWindow(Frame* frame, const FrameLoadRequest&, 158 const WindowFeatures& features, const NavigationAction&) 159 { 160 ASSERT(frame); 161 #ifdef ANDROID_MULTIPLE_WINDOWS 162 if (frame->settings() && !(frame->settings()->supportMultipleWindows())) 163 // If the client doesn't support multiple windows, just return the current page 164 return frame->page(); 165 #endif 166 167 const WebCoreViewBridge* bridge = frame->view()->platformWidget(); 168 bool dialog = features.dialog || !features.resizable 169 || (features.heightSet && features.height < bridge->height() 170 && features.widthSet && features.width < bridge->width()) 171 || (!features.menuBarVisible && !features.statusBarVisible 172 && !features.toolBarVisible && !features.locationBarVisible 173 && !features.scrollbarsVisible); 174 // fullscreen definitely means no dialog 175 if (features.fullscreen) 176 dialog = false; 177 WebCore::Frame* newFrame = m_webFrame->createWindow(dialog, 178 ScriptController::processingUserGesture()); 179 if (newFrame) { 180 WebCore::Page* page = newFrame->page(); 181 page->setGroupName(frame->page()->groupName()); 182 return page; 183 } 184 return NULL; 185 } 186 187 void ChromeClientAndroid::show() { notImplemented(); } 188 189 bool ChromeClientAndroid::canRunModal() { notImplemented(); return false; } 190 void ChromeClientAndroid::runModal() { notImplemented(); } 191 192 void ChromeClientAndroid::setToolbarsVisible(bool) { notImplemented(); } 193 bool ChromeClientAndroid::toolbarsVisible() { notImplemented(); return false; } 194 195 void ChromeClientAndroid::setStatusbarVisible(bool) { notImplemented(); } 196 bool ChromeClientAndroid::statusbarVisible() { notImplemented(); return false; } 197 198 void ChromeClientAndroid::setScrollbarsVisible(bool) { notImplemented(); } 199 bool ChromeClientAndroid::scrollbarsVisible() { notImplemented(); return false; } 200 201 void ChromeClientAndroid::setMenubarVisible(bool) { notImplemented(); } 202 bool ChromeClientAndroid::menubarVisible() { notImplemented(); return false; } 203 204 void ChromeClientAndroid::setResizable(bool) { notImplemented(); } 205 206 #if ENABLE(CONTEXT_MENUS) 207 void ChromeClientAndroid::showContextMenu() { notImplemented(); } 208 #endif 209 210 // This function is called by the JavaScript bindings to print usually an error to 211 // a message console. Pass the message to the java side so that the client can 212 // handle it as it sees fit. 213 void ChromeClientAndroid::addMessageToConsole(MessageSource, MessageType, MessageLevel msgLevel, const String& message, unsigned int lineNumber, const String& sourceID) { 214 android::WebViewCore::getWebViewCore(m_webFrame->page()->mainFrame()->view())->addMessageToConsole(message, lineNumber, sourceID, msgLevel); 215 } 216 217 void ChromeClientAndroid::formDidBlur(const WebCore::Node* node) 218 { 219 android::WebViewCore::getWebViewCore(m_webFrame->page()->mainFrame()->view())->formDidBlur(node); 220 } 221 222 bool ChromeClientAndroid::canRunBeforeUnloadConfirmPanel() { return true; } 223 bool ChromeClientAndroid::runBeforeUnloadConfirmPanel(const String& message, Frame* frame) { 224 String url = frame->document()->documentURI(); 225 return android::WebViewCore::getWebViewCore(frame->view())->jsUnload(url, message); 226 } 227 228 void ChromeClientAndroid::closeWindowSoon() 229 { 230 ASSERT(m_webFrame); 231 Page* page = m_webFrame->page(); 232 Frame* mainFrame = page->mainFrame(); 233 // This will prevent javascript cross-scripting during unload 234 page->setGroupName(String()); 235 // Stop loading but do not send the unload event 236 mainFrame->loader()->stopLoading(UnloadEventPolicyNone); 237 // Cancel all pending loaders 238 mainFrame->loader()->stopAllLoaders(); 239 // Remove all event listeners so that no javascript can execute as a result 240 // of mouse/keyboard events. 241 mainFrame->document()->removeAllEventListeners(); 242 // Close the window. 243 m_webFrame->closeWindow(android::WebViewCore::getWebViewCore(mainFrame->view())); 244 } 245 246 void ChromeClientAndroid::runJavaScriptAlert(Frame* frame, const String& message) 247 { 248 String url = frame->document()->documentURI(); 249 250 android::WebViewCore::getWebViewCore(frame->view())->jsAlert(url, message); 251 } 252 253 bool ChromeClientAndroid::runJavaScriptConfirm(Frame* frame, const String& message) 254 { 255 String url = frame->document()->documentURI(); 256 257 return android::WebViewCore::getWebViewCore(frame->view())->jsConfirm(url, message); 258 } 259 260 /* This function is called for the javascript method Window.prompt(). A dialog should be shown on 261 * the screen with an input put box. First param is the text, the second is the default value for 262 * the input box, third is return param. If the function returns true, the value set in the third parameter 263 * is provided to javascript, else null is returned to the script. 264 */ 265 bool ChromeClientAndroid::runJavaScriptPrompt(Frame* frame, const String& message, const String& defaultValue, String& result) 266 { 267 String url = frame->document()->documentURI(); 268 return android::WebViewCore::getWebViewCore(frame->view())->jsPrompt(url, message, defaultValue, result); 269 } 270 void ChromeClientAndroid::setStatusbarText(const String&) { notImplemented(); } 271 272 // This is called by the JavaScript interpreter when a script has been running for a long 273 // time. A dialog should be shown to the user asking them if they would like to cancel the 274 // Javascript. If true is returned, the script is cancelled. 275 // To make a device more responsive, we default to return true to disallow long running script. 276 // This implies that some of scripts will not be completed. 277 bool ChromeClientAndroid::shouldInterruptJavaScript() { 278 FrameView* frameView = m_webFrame->page()->mainFrame()->view(); 279 return android::WebViewCore::getWebViewCore(frameView)->jsInterrupt(); 280 } 281 282 KeyboardUIMode ChromeClientAndroid::keyboardUIMode() 283 { 284 return KeyboardAccessDefault; 285 } 286 287 IntRect ChromeClientAndroid::windowResizerRect() const { return IntRect(0, 0, 0, 0); } 288 289 void ChromeClientAndroid::invalidateWindow(const IntRect&, bool) 290 { 291 notImplemented(); 292 } 293 294 void ChromeClientAndroid::invalidateContentsAndWindow(const IntRect& updateRect, bool /*immediate*/) 295 { 296 notImplemented(); 297 } 298 299 void ChromeClientAndroid::invalidateContentsForSlowScroll(const IntRect& updateRect, bool immediate) 300 { 301 notImplemented(); 302 } 303 304 // new to change 38068 (Nov 6, 2008) 305 void ChromeClientAndroid::scroll(const IntSize& scrollDelta, 306 const IntRect& rectToScroll, const IntRect& clipRect) { 307 notImplemented(); 308 } 309 310 // new to change 38068 (Nov 6, 2008) 311 IntPoint ChromeClientAndroid::screenToWindow(const IntPoint&) const { 312 notImplemented(); 313 return IntPoint(); 314 } 315 316 // new to change 38068 (Nov 6, 2008) 317 IntRect ChromeClientAndroid::windowToScreen(const IntRect&) const { 318 notImplemented(); 319 return IntRect(); 320 } 321 322 PlatformPageClient ChromeClientAndroid::platformPageClient() const { 323 Page* page = m_webFrame->page(); 324 Frame* mainFrame = page->mainFrame(); 325 FrameView* view = mainFrame->view(); 326 PlatformWidget viewBridge = view->platformWidget(); 327 return viewBridge; 328 } 329 330 void ChromeClientAndroid::contentsSizeChanged(Frame*, const IntSize&) const 331 { 332 notImplemented(); 333 } 334 335 void ChromeClientAndroid::scrollRectIntoView(const IntRect&, const ScrollView*) const 336 { 337 notImplemented(); 338 } 339 340 void ChromeClientAndroid::formStateDidChange(const Node*) 341 { 342 notImplemented(); 343 } 344 345 void ChromeClientAndroid::scrollbarsModeDidChange() const 346 { 347 notImplemented(); 348 } 349 350 void ChromeClientAndroid::dispatchViewportDataDidChange(const ViewportArguments& input) const { 351 #ifdef ANDROID_META_SUPPORT 352 const ViewportArguments emptyArgument; 353 if (input == emptyArgument) { 354 // Empty Argument is for a page with no viewport meta tag; so reset everything. 355 m_webFrame->page()->settings()->resetMetadataSettings(); 356 } 357 Document* doc = m_webFrame->page()->mainFrame()->document(); 358 if (!doc->ownerElement()) { 359 FrameView* view = doc->view(); 360 if (view) 361 PlatformBridge::updateViewport(view); 362 } 363 #endif 364 } 365 366 void ChromeClientAndroid::mouseDidMoveOverElement(const HitTestResult&, unsigned int) {} 367 void ChromeClientAndroid::setToolTip(const String&, TextDirection) {} 368 void ChromeClientAndroid::print(Frame*) {} 369 370 /* 371 * This function is called on the main (webcore) thread by SQLTransaction::deliverQuotaIncreaseCallback. 372 * The way that the callback mechanism is designed inside SQLTransaction means that there must be a new quota 373 * (which may be equal to the old quota if the user did not allow more quota) when this function returns. As 374 * we call into the browser thread to ask what to do with the quota, we block here and get woken up when the 375 * browser calls the native WebViewCore::SetDatabaseQuota method with the new quota value. 376 */ 377 #if ENABLE(DATABASE) 378 void ChromeClientAndroid::exceededDatabaseQuota(Frame* frame, const String& name) 379 { 380 SecurityOrigin* origin = frame->document()->securityOrigin(); 381 DatabaseTracker& tracker = WebCore::DatabaseTracker::tracker(); 382 383 m_isNewQuotaSet = false; 384 385 // This origin is being tracked and has exceeded it's quota. Call into 386 // the Java side of things to inform the user. 387 unsigned long long currentQuota = 0; 388 if (tracker.hasEntryForOrigin(origin)) 389 currentQuota = tracker.quotaForOrigin(origin); 390 391 unsigned long long estimatedSize = 0; 392 393 // Only update estimatedSize if we are trying to create a a new database, i.e. the usage for the database is 0. 394 if (tracker.usageForDatabase(name, origin) == 0) 395 estimatedSize = tracker.detailsForNameAndOrigin(name, origin).expectedUsage(); 396 397 if (android::WebViewCore::getWebViewCore(frame->view())->exceededDatabaseQuota(frame->document()->documentURI(), name, currentQuota, estimatedSize)) { 398 // We've sent notification to the browser so now wait for it to come back. 399 m_quotaThreadLock.lock(); 400 while (!m_isNewQuotaSet) { 401 m_quotaThreadCondition.wait(m_quotaThreadLock); 402 } 403 m_quotaThreadLock.unlock(); 404 } else { 405 // We failed to send the message to the UI thread to request a new quota, 406 // so just use the current quota as a default. 407 m_newQuota = currentQuota; 408 } 409 410 if (m_newQuota < currentQuota) 411 m_newQuota = currentQuota; 412 413 // If new quota is unavailable, we may be able to resolve the situation by 414 // shrinking the quota of an origin that asked for a lot but is only using a 415 // little. If we find such a site, shrink it's quota and ask Java to try 416 // again. 417 if (m_newQuota == currentQuota && !m_triedToReclaimDBQuota) { 418 m_triedToReclaimDBQuota = true; // we should only try this once per quota overflow. 419 unsigned long long reclaimedQuotaBytes = tryToReclaimDatabaseQuota(origin); 420 421 // If we were able to free up enough space, try asking Java again. 422 // Otherwise, give up and deny the new database. :( 423 if (reclaimedQuotaBytes >= estimatedSize) { 424 exceededDatabaseQuota(frame, name); 425 return; 426 } 427 } 428 429 // Update the DatabaseTracker with the new quota value (if the user declined 430 // new quota, this may equal the old quota) 431 tracker.setQuota(origin, m_newQuota); 432 m_triedToReclaimDBQuota = false; 433 } 434 435 static unsigned long long tryToReclaimDatabaseQuota(SecurityOrigin* originNeedingQuota) { 436 DatabaseTracker& tracker = WebCore::DatabaseTracker::tracker(); 437 Vector<RefPtr<SecurityOrigin> > origins; 438 tracker.origins(origins); 439 unsigned long long reclaimedQuotaBytes = 0; 440 for (unsigned i = 0; i < origins.size(); i++) { 441 SecurityOrigin* originToReclaimFrom = origins[i].get(); 442 443 // Don't try to reclaim from the origin that has exceeded its quota. 444 if (originToReclaimFrom->equal(originNeedingQuota)) 445 continue; 446 447 unsigned long long originUsage = tracker.usageForOrigin(originToReclaimFrom); 448 unsigned long long originQuota = tracker.quotaForOrigin(originToReclaimFrom); 449 // If the origin has a quota that is more than it's current usage +1MB, shrink it. 450 static const int ONE_MB = 1 * 1024 * 1024; 451 if (originUsage + ONE_MB < originQuota) { 452 unsigned long long newQuota = originUsage + ONE_MB; 453 tracker.setQuota(originToReclaimFrom, newQuota); 454 reclaimedQuotaBytes += originQuota - newQuota; 455 } 456 } 457 return reclaimedQuotaBytes; 458 } 459 #endif 460 461 #if ENABLE(OFFLINE_WEB_APPLICATIONS) 462 void ChromeClientAndroid::reachedMaxAppCacheSize(int64_t spaceNeeded) 463 { 464 m_isNewQuotaSet = false; 465 Page* page = m_webFrame->page(); 466 Frame* mainFrame = page->mainFrame(); 467 FrameView* view = mainFrame->view(); 468 469 // If we fail to send the message to the UI thread to request a new quota, 470 // there's nothing to do. 471 if (!android::WebViewCore::getWebViewCore(view)->reachedMaxAppCacheSize(spaceNeeded)) 472 return; 473 474 // We've sent notification to the browser so now wait for it to come back. 475 m_quotaThreadLock.lock(); 476 while (!m_isNewQuotaSet) { 477 m_quotaThreadCondition.wait(m_quotaThreadLock); 478 } 479 m_quotaThreadLock.unlock(); 480 if (m_newQuota > 0) { 481 WebCore::cacheStorage().setMaximumSize(m_newQuota); 482 // Now the app cache will retry the saving the previously failed cache. 483 } 484 } 485 #endif 486 487 void ChromeClientAndroid::populateVisitedLinks() 488 { 489 Page* page = m_webFrame->page(); 490 Frame* mainFrame = page->mainFrame(); 491 FrameView* view = mainFrame->view(); 492 android::WebViewCore::getWebViewCore(view)->populateVisitedLinks(&page->group()); 493 } 494 495 void ChromeClientAndroid::requestGeolocationPermissionForFrame(Frame* frame, Geolocation* geolocation) 496 { 497 ASSERT(geolocation); 498 if (!m_geolocationPermissions) { 499 m_geolocationPermissions = new GeolocationPermissions(android::WebViewCore::getWebViewCore(frame->view()), 500 m_webFrame->page()->mainFrame()); 501 } 502 m_geolocationPermissions->queryPermissionState(frame); 503 } 504 505 void ChromeClientAndroid::cancelGeolocationPermissionRequestForFrame(Frame* frame, WebCore::Geolocation*) 506 { 507 if (m_geolocationPermissions) 508 m_geolocationPermissions->cancelPermissionStateQuery(frame); 509 } 510 511 void ChromeClientAndroid::provideGeolocationPermissions(const String &origin, bool allow, bool remember) 512 { 513 ASSERT(m_geolocationPermissions); 514 m_geolocationPermissions->providePermissionState(origin, allow, remember); 515 } 516 517 void ChromeClientAndroid::storeGeolocationPermissions() 518 { 519 GeolocationPermissions::maybeStorePermanentPermissions(); 520 } 521 522 void ChromeClientAndroid::onMainFrameLoadStarted() 523 { 524 if (m_geolocationPermissions.get()) 525 m_geolocationPermissions->resetTemporaryPermissionStates(); 526 } 527 528 void ChromeClientAndroid::runOpenPanel(Frame* frame, 529 PassRefPtr<FileChooser> chooser) 530 { 531 android::WebViewCore* core = android::WebViewCore::getWebViewCore( 532 frame->view()); 533 core->openFileChooser(chooser); 534 } 535 536 void ChromeClientAndroid::chooseIconForFiles(const Vector<WTF::String>&, FileChooser*) 537 { 538 notImplemented(); 539 } 540 541 void ChromeClientAndroid::setCursor(const Cursor&) 542 { 543 notImplemented(); 544 } 545 546 void ChromeClientAndroid::wakeUpMainThreadWithNewQuota(long long newQuota) { 547 MutexLocker locker(m_quotaThreadLock); 548 m_newQuota = newQuota < 0 ? 0 : newQuota; 549 m_isNewQuotaSet = true; 550 m_quotaThreadCondition.signal(); 551 } 552 553 #if ENABLE(TOUCH_EVENTS) 554 void ChromeClientAndroid::needTouchEvents(bool needTouchEvents) 555 { 556 FrameView* frameView = m_webFrame->page()->mainFrame()->view(); 557 android::WebViewCore* core = android::WebViewCore::getWebViewCore(frameView); 558 if (core) 559 core->needTouchEvents(needTouchEvents); 560 } 561 #endif 562 563 bool ChromeClientAndroid::selectItemWritingDirectionIsNatural() 564 { 565 return false; 566 } 567 568 bool ChromeClientAndroid::selectItemAlignmentFollowsMenuWritingDirection() 569 { 570 return false; 571 } 572 573 PassRefPtr<PopupMenu> ChromeClientAndroid::createPopupMenu(PopupMenuClient* client) const 574 { 575 return adoptRef(new PopupMenuAndroid(static_cast<ListPopupMenuClient*>(client))); 576 } 577 578 PassRefPtr<SearchPopupMenu> ChromeClientAndroid::createSearchPopupMenu(PopupMenuClient*) const 579 { 580 return adoptRef(new SearchPopupMenuAndroid); 581 } 582 583 void ChromeClientAndroid::reachedApplicationCacheOriginQuota(SecurityOrigin*) 584 { 585 notImplemented(); 586 } 587 588 #if ENABLE(ANDROID_INSTALLABLE_WEB_APPS) 589 void ChromeClientAndroid::webAppCanBeInstalled() 590 { 591 FrameView* frameView = m_webFrame->page()->mainFrame()->view(); 592 android::WebViewCore* core = android::WebViewCore::getWebViewCore(frameView); 593 if (core) 594 core->notifyWebAppCanBeInstalled(); 595 } 596 #endif 597 598 #if ENABLE(VIDEO) 599 bool ChromeClientAndroid::supportsFullscreenForNode(const Node* node) 600 { 601 return node->hasTagName(HTMLNames::videoTag); 602 } 603 604 void ChromeClientAndroid::enterFullscreenForNode(Node* node) 605 { 606 if (!node->hasTagName(HTMLNames::videoTag)) 607 return; 608 609 HTMLMediaElement* videoElement = static_cast<HTMLMediaElement*>(node); 610 String url = videoElement->currentSrc(); 611 LayerAndroid* layer = videoElement->platformLayer(); 612 if (!layer) 613 return; 614 615 FrameView* frameView = m_webFrame->page()->mainFrame()->view(); 616 android::WebViewCore* core = android::WebViewCore::getWebViewCore(frameView); 617 m_webFrame->page()->mainFrame()->document()->webkitWillEnterFullScreenForElement(videoElement); 618 if (core) 619 core->enterFullscreenForVideoLayer(layer->uniqueId(), url); 620 } 621 622 void ChromeClientAndroid::exitFullscreenForNode(Node* node) 623 { 624 } 625 #endif 626 627 #if ENABLE(FULLSCREEN_API) 628 void ChromeClientAndroid::exitFullScreenForElement(Element* element) 629 { 630 if (!element) 631 return; 632 633 HTMLMediaElement* videoElement = static_cast<HTMLMediaElement*>(element); 634 videoElement->exitFullscreen(); 635 } 636 #endif 637 638 } 639