/*******************************************************************************
* Copyright 2011, 2012 Chris Banes.
*
* 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.handmark.pulltorefresh.library.extras;
import java.util.concurrent.atomic.AtomicBoolean;
import android.content.Context;
import android.util.AttributeSet;
import android.webkit.WebView;
import com.handmark.pulltorefresh.library.PullToRefreshWebView;
/**
* An advanced version of {@link PullToRefreshWebView} which delegates the
* triggering of the PullToRefresh gesture to the Javascript running within the
* WebView. This means that you should only use this class if:
* <p/>
* <ul>
* <li>{@link PullToRefreshWebView} doesn't work correctly because you're using
* <code>overflow:scroll</code> or something else which means
* {@link WebView#getScrollY()} doesn't return correct values.</li>
* <li>You control the web content being displayed, as you need to write some
* Javascript callbacks.</li>
* </ul>
* <p/>
* <p/>
* The way this call works is that when a PullToRefresh gesture is in action,
* the following Javascript methods will be called:
* <code>isReadyForPullDown()</code> and <code>isReadyForPullUp()</code>, it is
* your job to calculate whether the view is in a state where a PullToRefresh
* can happen, and return the result via the callback mechanism. An example can
* be seen below:
* <p/>
*
* <pre>
* function isReadyForPullDown() {
* var result = ... // Probably using the .scrollTop DOM attribute
* ptr.isReadyForPullDownResponse(result);
* }
*
* function isReadyForPullUp() {
* var result = ... // Probably using the .scrollBottom DOM attribute
* ptr.isReadyForPullUpResponse(result);
* }
* </pre>
*
* @author Chris Banes
*/
public class PullToRefreshWebView2 extends PullToRefreshWebView {
static final String JS_INTERFACE_PKG = "ptr";
static final String DEF_JS_READY_PULL_DOWN_CALL = "javascript:isReadyForPullDown();";
static final String DEF_JS_READY_PULL_UP_CALL = "javascript:isReadyForPullUp();";
public PullToRefreshWebView2(Context context) {
super(context);
}
public PullToRefreshWebView2(Context context, AttributeSet attrs) {
super(context, attrs);
}
public PullToRefreshWebView2(Context context, Mode mode) {
super(context, mode);
}
private JsValueCallback mJsCallback;
private final AtomicBoolean mIsReadyForPullDown = new AtomicBoolean(false);
private final AtomicBoolean mIsReadyForPullUp = new AtomicBoolean(false);
@Override
protected WebView createRefreshableView(Context context, AttributeSet attrs) {
WebView webView = super.createRefreshableView(context, attrs);
// Need to add JS Interface so we can get the response back
mJsCallback = new JsValueCallback();
webView.addJavascriptInterface(mJsCallback, JS_INTERFACE_PKG);
return webView;
}
@Override
protected boolean isReadyForPullStart() {
// Call Javascript...
getRefreshableView().loadUrl(DEF_JS_READY_PULL_DOWN_CALL);
// Response will be given to JsValueCallback, which will update
// mIsReadyForPullDown
return mIsReadyForPullDown.get();
}
@Override
protected boolean isReadyForPullEnd() {
// Call Javascript...
getRefreshableView().loadUrl(DEF_JS_READY_PULL_UP_CALL);
// Response will be given to JsValueCallback, which will update
// mIsReadyForPullUp
return mIsReadyForPullUp.get();
}
/**
* Used for response from Javascript
*
* @author Chris Banes
*/
final class JsValueCallback {
public void isReadyForPullUpResponse(boolean response) {
mIsReadyForPullUp.set(response);
}
public void isReadyForPullDownResponse(boolean response) {
mIsReadyForPullDown.set(response);
}
}
}