package com.alorma.github.ui.view; import android.content.Context; import android.graphics.Color; import android.os.Build; import android.util.AttributeSet; import android.view.ActionMode; import android.view.GestureDetector; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.MotionEvent; import android.view.ViewParent; import android.webkit.JavascriptInterface; import android.webkit.WebSettings; import android.webkit.WebView; import com.alorma.github.R; import com.mikepenz.google_material_typeface_library.GoogleMaterial; import com.mikepenz.iconics.IconicsDrawable; /** * http://stackoverflow.com/a/29353049/325479 * Created by mikepenz on 20.06.15. */ public class CopyWebView extends WebView { // setting custom action bar private ActionMode mActionMode; private ActionMode.Callback mSelectActionModeCallback; private GestureDetector mDetector; private WebViewListener mWebViewListener; // override all other constructor to avoid crash public CopyWebView(Context context) { this(context, null); } public CopyWebView(Context context, AttributeSet attrs) { this(context, attrs, -1); } public CopyWebView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); WebSettings webviewSettings = getSettings(); webviewSettings.setJavaScriptEnabled(true); addJavascriptInterface(new WebAppInterface(), "JSInterface"); mDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { @Override public void onLongPress(MotionEvent e) { startActionMode(mSelectActionModeCallback); } /* @Override public boolean onSingleTapUp(MotionEvent e) { if (mActionMode != null) { mActionMode.finish(); return true; } return false; } */ }); } // this will over ride the default action bar on long press @Override public ActionMode startActionMode(android.view.ActionMode.Callback callback) { ViewParent parent = getParent(); if (parent == null) { return null; } if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { String name = callback.getClass().toString(); if (name.contains("SelectActionModeCallback")) { mSelectActionModeCallback = callback; } } CustomActionModeCallback mActionModeCallback = new CustomActionModeCallback(); return parent.startActionModeForChild(this, mActionModeCallback); } /** * a small helper javascrip function to copy the selected text */ private void getSelectedData() { String js = "(function getSelectedText() {" + "var txt;" + "if (window.getSelection) {" + "txt = window.getSelection().toString();" + "} else if (window.document.getSelection) {" + "txt = window.document.getSelection().toString();" + "} else if (window.document.selection) {" + "txt = window.document.selection.createRange().text;" + "}" + "JSInterface.getText(txt);" + "})()"; // calling the js function if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { evaluateJavascript("javascript:" + js, null); } else { loadUrl("javascript:" + js); } } @Override public boolean onTouchEvent(MotionEvent event) { // Send the event to our gesture detector // If it is implemented, there will be a return value if (mDetector != null) { mDetector.onTouchEvent(event); } // If the detected gesture is unimplemented, send it to the superclass return super.onTouchEvent(event); } public void setWebViewListener(WebViewListener webViewListener) { mWebViewListener = webViewListener; } /** * listener interface */ public interface WebViewListener { void onTextCopy(String text); } /** * A ActionModeCallback */ private class CustomActionModeCallback implements ActionMode.Callback { @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { mActionMode = mode; MenuInflater inflater = mode.getMenuInflater(); inflater.inflate(R.menu.menu_web_view_copy, menu); menu.findItem(R.id.copy) .setIcon(new IconicsDrawable(CopyWebView.this.getContext(), GoogleMaterial.Icon.gmd_content_copy).color(Color.WHITE).actionBar()); menu.findItem(R.id.share) .setIcon(new IconicsDrawable(CopyWebView.this.getContext(), GoogleMaterial.Icon.gmd_share).color(Color.WHITE).actionBar()); return true; } @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return false; } @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { switch (item.getItemId()) { case R.id.copy: getSelectedData(); mode.finish(); return true; case R.id.share: mode.finish(); return true; default: mode.finish(); return false; } } @Override public void onDestroyActionMode(ActionMode mode) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { clearFocus(); } else { if (mSelectActionModeCallback != null) { mSelectActionModeCallback.onDestroyActionMode(mode); } mActionMode = null; } } } /** * a helper interface class to call the WebViewListener.onTextCopy */ public class WebAppInterface { @JavascriptInterface public void getText(String text) { if (mWebViewListener != null) { mWebViewListener.onTextCopy(text); } } } }