/*
* Copyright (c) 2015 Jarrad Hope
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package io.syng.fragment;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Color;
import android.media.AudioManager;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import com.squareup.leakcanary.RefWatcher;
import org.apache.cordova.Config;
import org.apache.cordova.ConfigXmlParser;
import org.apache.cordova.CordovaInterfaceImpl;
import org.apache.cordova.CordovaPreferences;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.CordovaWebViewEngine;
import org.apache.cordova.CordovaWebViewImpl;
import org.apache.cordova.PluginEntry;
import org.apache.cordova.PluginManager;
import java.util.ArrayList;
import java.util.Locale;
import java.util.Properties;
import io.syng.activity.BaseActivity;
import io.syng.app.SyngApplication;
//import io.syng.cordova.plugin.WebViewEngine;
public class WebViewFragment extends Fragment implements View.OnTouchListener, GestureDetector.OnGestureListener {
private static final String DEFAULT_DAPP = "dapp://syng.io/dapps/wallet";
protected CordovaWebView webView;
protected CordovaInterfaceImpl cordovaInterface;
protected CordovaPreferences preferences;
protected ArrayList<PluginEntry> pluginEntries;
protected boolean keepRunning = true;
protected boolean immersiveMode;
protected GestureDetector gestureDetector;
protected String url;
/*
Dapps must keep cordova JS files inside or we must place them on external HTTP server. If inject from file: - external scripts not have access to it.
*/
private static String js_cordova = ""
+"var script = document.createElement('script'); "
+"script.setAttribute('type','text/javascript'); "
+"script.setAttribute('async','async'); "
+"script.setAttribute('src','http://syng.io/dapps/lib/cordova/cordova.js'); "
+"(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(script);"
+"";
// protected View view;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
url = getArguments() != null ? getArguments().getString("url") : null;
Properties properties = System.getProperties();
properties.setProperty("http.nonProxyHosts", "localhost|127.0.0.1");
properties.setProperty("https.nonProxyHosts", "localhost|127.0.0.1");
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
loadConfig();
// ((AppCompatActivity)getActivity()).getSupportActionBar().setDisplayShowTitleEnabled(false);
/*
TODO: it's can be only in activity before adding content and we may need it in Cordova Dapps
if(!preferences.getBoolean("ShowTitle", false))
{
try {
getActivity().getWindow().requestFeature(Window.FEATURE_NO_TITLE);
} catch (Exception e) {
System.out.print(e);
}
}
if(preferences.getBoolean("SetFullscreen", false))
{
preferences.set("Fullscreen", true);
}
if(preferences.getBoolean("Fullscreen", false))
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
{
immersiveMode = true;
}
else
{
getActivity().getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
} else {
getActivity().getWindow().setFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
}
*/
// view = inflater.inflate(R.layout.fragment_web_view, container, false);
cordovaInterface = makeCordovaInterface();
if(savedInstanceState != null)
{
cordovaInterface.restoreInstanceState(savedInstanceState);
}
init();
loadUrl();
// return view;
return webView.getView();
}
private void loadUrl() {
if (url == null || url.isEmpty()) {
url = DEFAULT_DAPP;
}
if (webView == null) {
init();
}
// If keepRunning
this.keepRunning = preferences.getBoolean("KeepRunning", true);
if (url.indexOf("dapp://") == 0) {
url = url.replace("dapp://", "http://");
}
webView.loadUrlIntoView(url, true);
}
protected void init() {
webView = makeWebView();
createViews();
if (!webView.isInitialized()) {
webView.init(cordovaInterface, pluginEntries, preferences);
}
webView.getView().requestFocusFromTouch();
cordovaInterface.onCordovaInit(webView.getPluginManager());
//webView.clearCache();
android.webkit.CookieManager.getInstance().removeAllCookie();
// Wire the hardware volume controls to control media if desired.
String volumePref = preferences.getString("DefaultVolumeStream", "");
if ("media".equals(volumePref.toLowerCase(Locale.ENGLISH))) {
getActivity().setVolumeControlStream(AudioManager.STREAM_MUSIC);
}
BaseActivity activity = (BaseActivity)getActivity();
activity.hideToolbar(2);
gestureDetector = new GestureDetector(webView.getContext(), this);
webView.getView().setOnTouchListener(this);
}
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
return gestureDetector.onTouchEvent(motionEvent);
}
@Override
public boolean onFling(MotionEvent start, MotionEvent finish, float velocityX, float velocityY) { float gapX = start.getRawX() - finish.getRawX();
float gapY = start.getRawY() - finish.getRawY();
float distanceX = Math.abs(gapX);
float distanceY = Math.abs(gapY);
if (distanceY > distanceX) { // up downs
if (gapY > 0) {
// up
System.out.println("Swipe up");
} else {
// down
System.out.println("Swipe down");
BaseActivity activity = (BaseActivity)getActivity();
activity.showToolbar(0);
activity.hideToolbar(2);
}
} else { // left right
if (gapX > 0) {
// left
System.out.println("Swipe left");
} else {
// rights
System.out.println("Swipe right");
}
}
return false;
}
@Override
public boolean onDown(MotionEvent motionEvent) {
return false;
}
@Override
public boolean onSingleTapUp(MotionEvent motionEvent) {
return false;
}
@Override
public void onShowPress(MotionEvent motionEvent) {
}
@Override
public boolean onScroll(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) {
return false;
}
@Override
public void onLongPress(MotionEvent motionEvent) {
}
@SuppressWarnings("deprecation")
protected void loadConfig() {
ConfigXmlParser parser = new ConfigXmlParser();
parser.parse(getActivity());
preferences = parser.getPreferences();
preferences.setPreferencesBundle(getActivity().getIntent().getExtras());
//preferences.set("webview", "io.syng.cordova.plugin.WebViewEngine");
pluginEntries = parser.getPluginEntries();
Config.init(getActivity());
}
@SuppressWarnings({"deprecation", "ResourceType"})
protected void createViews() {
//Why are we setting a constant as the ID? This should be investigated
webView.getView().setId(1000);
RelativeLayout.LayoutParams p = new RelativeLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
webView.getView().setLayoutParams(p);
if (preferences.contains("BackgroundColor")) {
int backgroundColor = preferences.getInteger("BackgroundColor", Color.BLACK);
// Background of activity:
webView.getView().setBackgroundColor(backgroundColor);
}
webView.getView().requestFocusFromTouch();
}
protected CordovaWebView makeWebView() {
return new CordovaWebViewImpl(makeWebViewEngine());
}
protected CordovaWebViewEngine makeWebViewEngine() {
return CordovaWebViewImpl.createEngine(getActivity(), preferences);
}
protected CordovaInterfaceImpl makeCordovaInterface() {
return new CordovaInterfaceImpl(getActivity()) {
@Override
public Object onMessage(String id, Object data) {
return WebViewFragment.this.onMessage(id, data);
}
};
}
public Object onMessage(String id, Object data) {
if ("onReceivedError".equals(id)) {
//TODO: do we need handle error and show it?
/*
JSONObject d = (JSONObject) data;
try {
this.onReceivedError(d.getInt("errorCode"), d.getString("description"), d.getString("url"));
} catch (JSONException e) {
e.printStackTrace();
}
*/
} else if ("onPageFinished".equals(id)) {
webView.getEngine().loadUrl("javascript: " + js_cordova, false);
} else if ("exit".equals(id)) {
getActivity().finish();
}
return null;
}
@Override
public void onPause() {
super.onPause();
if (this.webView != null) {
boolean keepRunning = this.keepRunning;// || this.cordovaInterface.activityResultCallback != null;
this.webView.handlePause(keepRunning);
}
BaseActivity activity = (BaseActivity)getActivity();
activity.showToolbar(0);
}
/*
TODO: it's can be only in activity and we may need it in Cordova Dapps
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
//Forward to plugins
if (this.webView != null)
this.webView.onNewIntent(intent);
}
*/
@Override
public void onResume() {
super.onResume();
if (this.webView == null) {
return;
}
// Force window to have focus, so application always
// receive user input. Workaround for some devices (Samsung Galaxy Note 3 at least)
getActivity().getWindow().getDecorView().requestFocus();
this.webView.handleResume(this.keepRunning);
}
@Override
public void onStop() {
super.onStop();
if (this.webView == null) {
return;
}
this.webView.handleStop();
}
@Override
public void onStart() {
super.onStart();
if (this.webView == null) {
return;
}
this.webView.handleStart();
}
@Override
public void onDestroy() {
super.onDestroy();
if (this.webView != null) {
webView.handleDestroy();
}
RefWatcher refWatcher = SyngApplication.getRefWatcher(getActivity());
refWatcher.watch(this);
}
/*
TODO: it's can be only in activity and we may need it in Cordova Dapps
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus && immersiveMode) {
final int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
getWindow().getDecorView().setSystemUiVisibility(uiOptions);
}
}
*/
@Override
public void startActivityForResult(Intent intent, int requestCode) {
cordovaInterface.setActivityResultRequestCode(requestCode);
super.startActivityForResult(intent, requestCode);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
cordovaInterface.onActivityResult(requestCode, resultCode, intent);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (this.webView == null) {
return;
}
PluginManager pm = this.webView.getPluginManager();
if (pm != null) {
pm.onConfigurationChanged(newConfig);
}
}
@Override
public void onSaveInstanceState(Bundle outState)
{
cordovaInterface.onSaveInstanceState(outState);
super.onSaveInstanceState(outState);
}
}