package org.sagemath.droid.views; import android.app.Activity; import android.content.Context; import android.content.SharedPreferences; import android.preference.PreferenceManager; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.view.inputmethod.BaseInputConnection; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; import android.webkit.WebView; import org.apache.commons.lang3.StringEscapeUtils; /** * The {@linkplain android.webkit.WebView} which serves as the input. * * <p>Uses CodeMirror internally to provide syntax highlighting.</p> * * @author Nikhil Peter Raj */ public class CodeView extends WebView { private static final String TAG = "Test:CodeView"; private static final String INTERFACE_NAME = "JavaScriptInterface"; private String PREFS_FONT_SIZE = "font_size"; private SageJavascriptInterface javaScriptInterface; @SuppressWarnings("unused") public CodeView(Context context) { super(context); init(); } @SuppressWarnings("unused") public CodeView(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { javaScriptInterface = new SageJavascriptInterface((Activity) getContext()); this.getSettings().setJavaScriptEnabled(true); this.getSettings().setBuiltInZoomControls(false); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext()); this.getSettings().setDefaultFixedFontSize(prefs.getInt(PREFS_FONT_SIZE, 16)); this.getSettings().setUseWideViewPort(true); this.getSettings().setLoadWithOverviewMode(true); this.addJavascriptInterface(javaScriptInterface, INTERFACE_NAME); this.post(new Runnable() { @Override public void run() { loadUrl("file:///android_asset/codetest.html"); } }); } //Hackfix @Override public InputConnection onCreateInputConnection(EditorInfo outAttrs) { return new CodeViewInputConnection(this, false); } public void getEditorText(boolean forRun) { javaScriptInterface.setForRun(forRun); this.postDelayed(new Runnable() { @Override public void run() { loadUrl("javascript:getEditorText();"); } }, 500); } public void setEditorText(String text) { //Escape Javascript final String functionCall = "javascript:setEditorText(\"%s\");"; final String textToSet = StringEscapeUtils.escapeEcmaScript(text); Log.i(TAG, "Calling js: " + String.format(functionCall, textToSet)); this.postDelayed(new Runnable() { @Override public void run() { loadUrl(String.format(functionCall, textToSet)); } }, 500); } public void paste(final String text) { final String functionCall = "javascript:paste(\"%s\");"; final String textToSet = StringEscapeUtils.escapeEcmaScript(text); this.postDelayed(new Runnable() { @Override public void run() { loadUrl(String.format(functionCall, textToSet)); } }, 500); } private class CodeViewInputConnection extends BaseInputConnection { public CodeViewInputConnection(View targetView, boolean fullEditor) { super(targetView, fullEditor); } // Hack to fix backspace. @Override public boolean deleteSurroundingText(int beforeLength, int afterLength) { if (beforeLength == 1 && afterLength == 0) { // backspace return super.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL)) && super.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL)); } return super.deleteSurroundingText(beforeLength, afterLength); } } }