SalesforceWebViewClient.java
/*
* Copyright (c) 2012-present, salesforce.com, inc.
* All rights reserved.
* Redistribution and use of this software in source and binary forms, with or
* without modification, are permitted provided that the following conditions
* are met:
* - Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of salesforce.com, inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission of salesforce.com, inc.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package com.salesforce.androidsdk.phonegap.ui;
import android.net.Uri;
import android.util.Log;
import android.webkit.WebResourceResponse;
import android.webkit.WebSettings;
import android.webkit.WebView;
import com.salesforce.androidsdk.app.SalesforceSDKManager;
import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaResourceApi;
import org.apache.cordova.CordovaResourceApi.OpenForReadResult;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.engine.SystemWebView;
import org.apache.cordova.engine.SystemWebViewClient;
import java.io.File;
import java.io.IOException;
public class SalesforceWebViewClient extends SystemWebViewClient {
static final String WWW_DIR = "/android_asset/www";
private static final String FEATURE_LOCALHOST = "LH";
private static final String TAG = "SalesforceWebViewClient";
// The first non-reserved URL that's loaded will be considered the app's "home page", for caching purposes.
protected boolean foundHomeUrl = false;
protected SalesforceDroidGapActivity ctx;
protected CordovaWebView cordovaWebView;
/**
* Parameterized constructor.
*
* @param parentEngine SystemWebViewEngine instance.
*/
public SalesforceWebViewClient(SalesforceWebViewEngine parentEngine) {
super(parentEngine);
cordovaWebView = parentEngine.getCordovaWebView();
final CordovaInterface cordova = parentEngine.getCordovaInterface();
if (cordova != null) {
ctx = (SalesforceDroidGapActivity) cordova.getActivity();
}
final SystemWebView webView = (SystemWebView) parentEngine.getView();
final String uaStr = SalesforceSDKManager.getInstance().getUserAgent();
if (webView != null) {
final WebSettings webSettings = webView.getSettings();
// Setting custom user agent and a bunch of other settings.
final String origUserAgent = webSettings.getUserAgentString();
final String extendedUserAgentString = uaStr + " Hybrid " + (origUserAgent == null ? "" : origUserAgent);
webSettings.setUserAgentString(extendedUserAgentString);
// Configure HTML5 cache support.
webSettings.setDomStorageEnabled(true);
final String cachePath = SalesforceSDKManager.getInstance().getAppContext().getCacheDir().getAbsolutePath();
webSettings.setAppCachePath(cachePath);
webSettings.setAppCacheEnabled(true);
webSettings.setAllowFileAccess(true);
webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
}
}
@Override
public boolean shouldOverrideUrlLoading(final WebView view, String url) {
if (SalesforceWebViewClientHelper.shouldOverrideUrlLoading(ctx, view, url)) {
return true;
} else {
return super.shouldOverrideUrlLoading(view, url);
}
}
@Override
public void onPageFinished(WebView view, String url) {
if (!this.foundHomeUrl && SalesforceWebViewClientHelper.onHomePage(SalesforceSDKManager.getInstance().getAppContext(), view, url)) {
this.foundHomeUrl = true;
}
super.onPageFinished(view, url);
}
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
WebResourceResponse response = super.shouldInterceptRequest(view, url);
// Already intercepted (e.g. if url is not whitelisted).
if (response != null) {
return response;
}
// Not a localhost request.
Uri origUri = Uri.parse(url);
String host = origUri.getHost();
if (host == null || !host.equals("localhost")) {
return null;
}
// Localhost request.
SalesforceSDKManager.getInstance().registerUsedAppFeature(FEATURE_LOCALHOST);
try {
String localPath = WWW_DIR + origUri.getPath();
// Trying to access file outside assets/www.
if (!isFileUnder(localPath, WWW_DIR)) {
throw new IOException("Trying to access file outside assets/www");
} else {
Uri localUri = Uri.parse("file://" + localPath);
CordovaResourceApi resourceApi = cordovaWebView.getResourceApi();
OpenForReadResult result = resourceApi.openForRead(localUri, true);
Log.i(TAG, "Loading local file:" + localUri);
return new WebResourceResponse(result.mimeType, "UTF-8", result.inputStream);
}
} catch (IOException e) {
Log.e(TAG, "Invalid localhost url:" + url, e);
return new WebResourceResponse("text/plain", "UTF-8", null);
}
}
private boolean isFileUnder(String filePath, String dirPath) throws IOException {
File file = new File(filePath);
File dir = new File(dirPath);
return file.getCanonicalPath().indexOf(dir.getCanonicalPath()) == 0;
}
}