package adonai.diary_browser.misc; import android.annotation.TargetApi; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; import android.graphics.Rect; import android.os.Build; import android.util.AttributeSet; import android.util.TypedValue; import android.view.ActionMode; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.webkit.WebView; import adonai.diary_browser.DiaryListActivity; import adonai.diary_browser.R; /** * Враппер для WebView * Необходим для добавления кнопки "цитировать" */ public class WebFrame extends WebView { public WebFrame(Context context) { super(context); } public WebFrame(Context context, AttributeSet attrs) { super(context, attrs); } public WebFrame(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override public ActionMode startActionMode(ActionMode.Callback callback) { ActionMode.Callback wrapper = new ActionModeWrapper(callback); return super.startActionMode(wrapper); } @TargetApi(Build.VERSION_CODES.M) @Override public ActionMode startActionMode(ActionMode.Callback callback, int type) { ActionMode.Callback wrapper = new ActionModeWrapper23(callback); return super.startActionMode(wrapper, type); } public static MenuItem findByTitle(Menu menu, String regex) { for(int i = 0; i < menu.size(); ++i) { String title = menu.getItem(i).getTitle().toString(); if(title.matches(regex)) return menu.getItem(i); } return null; } /** * Враппер для добавления кнопки "цитировать" - для Андроида версии M и выше */ @TargetApi(Build.VERSION_CODES.M) private class ActionModeWrapper23 extends ActionMode.Callback2 { private final ActionMode.Callback mOriginalCallback; public ActionModeWrapper23(ActionMode.Callback cb) { mOriginalCallback = cb; } /** * Хак чтобы заставить работать систему перехвата копирования */ @Override public boolean onCreateActionMode(final ActionMode mode, final Menu menu) { boolean result = mOriginalCallback.onCreateActionMode(mode, menu); final MenuItem copyButton = findByTitle(menu, "Копировать|Copy|Копіювати"); // ugly hack, no better way if(copyButton == null) { return result; } TypedValue drawable = new TypedValue(); getContext().getTheme().resolveAttribute(R.attr.quote_menu_drawable, drawable, true); menu.add(copyButton.getGroupId(), Menu.NONE, copyButton.getOrder() + 100, R.string.quote) // будет в начале .setIcon(drawable.resourceId) .setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_ALWAYS) .setOnMenuItemClickListener(new ClipboardGrab(this, mode, copyButton)); return result; } @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { // родные пункты меню "нумеруются" с 1, // дополнительные я "пронумеровал" со 100 while (menu.getItem(0).getOrder() < 100) { MenuItem item = menu.getItem(0); menu.removeItem(item.getItemId()); // теперь родные будут "нумероваться" с 200, то есть // станут после дополнительных menu.add(item.getGroupId(), item.getItemId(), item.getOrder() + 200, item.getTitle()); } return mOriginalCallback.onPrepareActionMode(mode, menu); } @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { return mOriginalCallback.onActionItemClicked(mode, item); } @Override public void onDestroyActionMode(ActionMode mode) { mOriginalCallback.onDestroyActionMode(mode); } @Override public void onGetContentRect(ActionMode mode, View view, Rect outRect) { if(mOriginalCallback instanceof ActionMode.Callback2) { ((ActionMode.Callback2) mOriginalCallback).onGetContentRect(mode, view, outRect); } else { super.onGetContentRect(mode, view, outRect); } } } /** * Враппер для добавления кнопки "цитировать" - для моделей Андроида < 23 */ private class ActionModeWrapper implements ActionMode.Callback { private final ActionMode.Callback mOriginalCallback; public ActionModeWrapper(ActionMode.Callback cb) { mOriginalCallback = cb; } /** * Хак чтобы заставить работать систему перехвата копирования */ @Override public boolean onCreateActionMode(final ActionMode mode, final Menu menu) { boolean result = mOriginalCallback.onCreateActionMode(mode, menu); final MenuItem copyButton = findByTitle(menu, "Копировать|Copy|Копіювати"); // ugly hack, no better way if(copyButton == null) { return result; } TypedValue drawable = new TypedValue(); getContext().getTheme().resolveAttribute(R.attr.quote_menu_drawable, drawable, true); menu.add(copyButton.getGroupId(), Menu.NONE, copyButton.getOrder(), R.string.quote) // будет в начале .setIcon(drawable.resourceId) .setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_ALWAYS) .setOnMenuItemClickListener(new ClipboardGrab(this, mode, copyButton)); return result; } @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return mOriginalCallback.onPrepareActionMode(mode, menu); } @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { return mOriginalCallback.onActionItemClicked(mode, item); } @Override public void onDestroyActionMode(ActionMode mode) { mOriginalCallback.onDestroyActionMode(mode); } } private class ClipboardGrab implements MenuItem.OnMenuItemClickListener { private ActionMode.Callback callback; private final ActionMode mode; private final MenuItem copyButton; public ClipboardGrab(ActionMode.Callback cb, ActionMode mode, MenuItem copyButton) { this.callback = cb; this.mode = mode; this.copyButton = copyButton; } @Override public boolean onMenuItemClick(MenuItem item) { callback.onActionItemClicked(mode, copyButton); // программное нажатие на кнопку "скопировать" // хак чтобы текст в клипборде точно попал к нам postDelayed(new Runnable() { @Override public void run() { ClipboardManager cm = (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE); if (!cm.hasPrimaryClip()) return; ClipData cd = cm.getPrimaryClip(); if (cd.getItemCount() > 0) { String copied = cd.getItemAt(0).getText().toString(); String quoted = "<span class='quote_text'>" + copied + "</span>"; if (getContext() instanceof DiaryListActivity) { // цитируем ((DiaryListActivity) getContext()).handleMessagePaneAddText(quoted); } } } }, 500); return true; } } }