package com.mobilyzer.util;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import com.mobilyzer.UpdateIntent;
import com.squareup.okhttp.ConnectionPool;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Protocol;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;
import com.squareup.okhttp.internal.Util;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.http.SslError;
import android.os.Handler;
import android.webkit.SslErrorHandler;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceResponse;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
public class AndroidWebView extends WebView {
public static enum WebViewProtocol{
SPDY, HTTP
}
private static String USER_AGENT="Mozilla/5.0 (Linux; U; Android 4.3; en-us; SCH-I535 Build/JSS15J) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30";
OkHttpClient client;
boolean spdyTest;
long startTimeFilter;
String url;
Context context;
long pageStartLoading;
WebViewProtocol protocol;
// private volatile ArrayList<String> objsTimings;
// private volatile int totalByte;
public AndroidWebView(Context context, boolean spdyTest, WebViewProtocol protocol, long startTimeFilter, String url) {
super(context);
this.spdyTest=spdyTest;
this.context=context;
this.url=url;
this.protocol=protocol;
this.startTimeFilter=startTimeFilter;
clearCache(true);
getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
getSettings().setAppCacheEnabled(false);
getSettings().setJavaScriptEnabled(true);
getSettings().setUserAgentString(USER_AGENT);
context.deleteDatabase("webview.db");
context.deleteDatabase("webviewCache.db");
clearHistory();
client= new OkHttpClient();
if(client.getConnectionPool()!=null && client.getConnectionPool().getConnectionCount()!=0){
client.getConnectionPool().evictAll();
}
client.setConnectionPool(ConnectionPool.getDefault());
// client.getCache().delete();
if(spdyTest){
if(protocol.equals(WebViewProtocol.HTTP)){
client.setProtocols(Util.immutableList(Protocol.HTTP_1_1));
}else{
client.setProtocols(Util.immutableList(Protocol.SPDY_3, Protocol.HTTP_1_1));
}
}else{
client.setProtocols(Util.immutableList(Protocol.HTTP_1_1));
}
TrustManager localTrustmanager = new X509TrustManager() {
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
@Override
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
};
// Create SSLContext and set the socket factory as default
try {
SSLContext sslc = SSLContext.getInstance("SSL");
sslc.init(null, new TrustManager[] { localTrustmanager },
new SecureRandom());
client.setSslSocketFactory(sslc.getSocketFactory());
HttpsURLConnection.setDefaultSSLSocketFactory(sslc.getSocketFactory());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
setWebViewClient(new WebViewClient(){
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
handler.proceed();
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
Logger.d("ashkan_plt: Page started: "+url);
super.onPageStarted(view, url, favicon);
}
@Override
public void onPageFinished(WebView view, String url) {
Logger.d("ashkan_plt: Page finished: "+url);
new Handler(){
private WebView view;
public void init(WebView v){
view=v;
postDelayed(new Runnable() {
@Override
public void run() {
String js_code = "javascript:(\n function() { \n";
js_code += " var result='';\n";
js_code += " for(var prop in performance.timing){\n";
js_code += " if(performance.timing.hasOwnProperty(prop)){\n";
js_code += " result=prop+':'+performance.timing[prop]+'|'+result}}\n";
js_code += " console.log('mobilyzer_navigation'+result);\n";
js_code += " perfObj=window.performance.getEntriesByType('resource');\n";
js_code += " all_res='';\n";
js_code += " for(var prop in perfObj){if(perfObj.hasOwnProperty(prop)){\n";
js_code += " res='';\n";
js_code += " for(var index in perfObj[prop]){res=index+':'+perfObj[prop][index]+'|'+res;}\n";
if(AndroidWebView.this.spdyTest){
if(AndroidWebView.this.protocol.equals(WebViewProtocol.HTTP)){
js_code += " all_res=all_res+'mobilyzer_resource|http|'+res;}}\n";
}else{
js_code += " all_res=all_res+'mobilyzer_resource|spdy|'+res;}}\n";
}
}else{
js_code += " all_res=all_res+'mobilyzer_resource|http|'+res;}}\n";
}
js_code += " console.log(all_res);\n";
js_code += " })()\n";
view.loadUrl(js_code);
}
}, 20000);
}
}.init(view);
super.onPageFinished(view, url);
}
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String urlStr) {
long relStartTime;
if(urlStr.equals(AndroidWebView.this.url)){
pageStartLoading=System.currentTimeMillis();
relStartTime=0;
}else{
relStartTime=System.currentTimeMillis()-pageStartLoading;
}
Logger.d("ashkan_plt: shouldInterceptRequest: "+urlStr+" "+relStartTime);
if (urlStr == null || urlStr.trim().equals("") || !(urlStr.startsWith("http") && !urlStr.startsWith("www"))|| urlStr.contains("|")){
return super.shouldInterceptRequest(view, urlStr);
}
return new MyWebResourceResponse(urlStr);
// return super.shouldInterceptRequest(view, urlStr);
}
});
setWebChromeClient(new WebChromeClient(){
@Override
public void onConsoleMessage(String message, int lineNumber, String sourceID) {
Logger.d("onConsoleMessage: "+message);
Intent newintent = new Intent();
newintent.setAction((UpdateIntent.PLT_MEASUREMENT_ACTION)+AndroidWebView.this.startTimeFilter);
if(message.startsWith("mobilyzer_navigation")){
if(AndroidWebView.this.spdyTest){
if(AndroidWebView.this.protocol.equals(WebViewProtocol.HTTP)){
message=message.replace("mobilyzer_navigation", "mobilyzer_navigation|http");
}else{
message=message.replace("mobilyzer_navigation", "mobilyzer_navigation|spdy");
}
}else{
message=message.replace("mobilyzer_navigation", "mobilyzer_navigation|http");
}
newintent.putExtra(UpdateIntent.PLT_TASK_PAYLOAD_RESULT_NAV, message);
// newintent.putExtra(UpdateIntent.PLT_TASK_PAYLOAD_BYTE_USED, totalByte);//TODO
PhoneUtils.getGlobalContext().sendBroadcast(newintent);
Logger.d("ashkan_plt: onConsoleMessage: Broadcasting mobilyzer_navigation result "+message.length());
if(AndroidWebView.this.spdyTest && AndroidWebView.this.protocol.equals(WebViewProtocol.HTTP)){
AndroidWebView spdyWebView=new AndroidWebView(AndroidWebView.this.context, true, WebViewProtocol.SPDY ,AndroidWebView.this.startTimeFilter, AndroidWebView.this.url);
spdyWebView.loadUrl();
}
AndroidWebView.this.destroyDrawingCache();
// AndroidWebView.this.destroy();
}else if(message.startsWith("mobilyzer_resource")){
newintent.putExtra(UpdateIntent.PLT_TASK_PAYLOAD_RESULT_RES, message);
PhoneUtils.getGlobalContext().sendBroadcast(newintent);
Logger.d("ashkan_plt: onConsoleMessage: Broadcasting mobilyzer_resource result "+message.length());
}
}
});
}
class MyWebResourceResponse extends WebResourceResponse{
private String url;
public MyWebResourceResponse(String url){
super("", "", null);
this.url=url;
}
public MyWebResourceResponse(String mimeType, String encoding,
InputStream data) {
super(mimeType, encoding, data);
}
@Override
public InputStream getData() {
return new MyInputStream(url);
}
}
class MyInputStream extends InputStream{
private String url;
private boolean initialized;
private InputStream is;
public MyInputStream(String url) {
this.url=url;
initialized=false;
}
@Override
public int read() throws IOException {
if(!initialized){
try {
Request request = new Request.Builder()
.url(url)
.header("User-Agent", "Mozilla/5.0 (Linux; U; Android 4.3; en-us; SCH-I535 Build/JSS15J) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30")
.build();
long startTime=System.currentTimeMillis();
Response response = client.newCall(request).execute();
Logger.d("ashkan_plt: HTTP: "+client.getConnectionPool().getHttpConnectionCount()+" SPDY: "+client.getConnectionPool().getSpdyConnectionCount());
long endTime=System.currentTimeMillis();
is= response.body().byteStream();
Logger.d("ashkan_plt: load time for "+url+":\t "+(endTime-startTime));
} catch (IOException e) {
e.printStackTrace();
}
initialized=true;
}
return is.read();
}
}
public void loadUrl() {
super.loadUrl(this.url);
}
}