| /* |
| * Copyright (C) 2009 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.internal.widget; |
| |
| import java.io.InputStream; |
| import java.util.ArrayList; |
| |
| import android.app.AlertDialog.Builder; |
| import android.content.Context; |
| import android.content.DialogInterface; |
| import android.graphics.Bitmap; |
| import android.graphics.BitmapFactory; |
| import android.graphics.Canvas; |
| import android.graphics.drawable.BitmapDrawable; |
| import android.graphics.drawable.Drawable; |
| import android.graphics.drawable.ShapeDrawable; |
| import android.graphics.drawable.shapes.RectShape; |
| import android.net.Uri; |
| import android.os.Bundle; |
| import android.text.Editable; |
| import android.text.Html; |
| import android.text.Layout; |
| import android.text.Spannable; |
| import android.text.Spanned; |
| import android.text.method.ArrowKeyMovementMethod; |
| import android.text.style.AbsoluteSizeSpan; |
| import android.text.style.AlignmentSpan; |
| import android.text.style.CharacterStyle; |
| import android.text.style.ForegroundColorSpan; |
| import android.text.style.ImageSpan; |
| import android.text.style.ParagraphStyle; |
| import android.text.style.QuoteSpan; |
| import android.util.AttributeSet; |
| import android.util.Log; |
| import android.view.KeyEvent; |
| import android.view.MotionEvent; |
| import android.view.View; |
| import android.view.inputmethod.InputMethodManager; |
| import android.widget.EditText; |
| import android.widget.TextView; |
| |
| /** |
| * EditStyledText extends EditText for managing the flow and status to edit |
| * the styled text. This manages the states and flows of editing, supports |
| * inserting image, import/export HTML. |
| */ |
| public class EditStyledText extends EditText { |
| |
| private static final String LOG_TAG = "EditStyledText"; |
| private static final boolean DBG = false; |
| |
| /** |
| * The modes of editing actions. |
| */ |
| /** The mode that no editing action is done. */ |
| public static final int MODE_NOTHING = 0; |
| /** The mode of copy. */ |
| public static final int MODE_COPY = 1; |
| /** The mode of paste. */ |
| public static final int MODE_PASTE = 2; |
| /** The mode of changing size. */ |
| public static final int MODE_SIZE = 3; |
| /** The mode of changing color. */ |
| public static final int MODE_COLOR = 4; |
| /** The mode of selection. */ |
| public static final int MODE_SELECT = 5; |
| /** The mode of changing alignment. */ |
| public static final int MODE_ALIGN = 6; |
| /** The mode of changing cut. */ |
| public static final int MODE_CUT = 7; |
| |
| /** |
| * The state of selection. |
| */ |
| /** The state that selection isn't started. */ |
| public static final int STATE_SELECT_OFF = 0; |
| /** The state that selection is started. */ |
| public static final int STATE_SELECT_ON = 1; |
| /** The state that selection is done, but not fixed. */ |
| public static final int STATE_SELECTED = 2; |
| /** The state that selection is done and not fixed. */ |
| public static final int STATE_SELECT_FIX = 3; |
| |
| /** |
| * The help message strings. |
| */ |
| public static final int HINT_MSG_NULL = 0; |
| public static final int HINT_MSG_COPY_BUF_BLANK = 1; |
| public static final int HINT_MSG_SELECT_START = 2; |
| public static final int HINT_MSG_SELECT_END = 3; |
| public static final int HINT_MSG_PUSH_COMPETE = 4; |
| |
| |
| /** |
| * The help message strings. |
| */ |
| public static final int DEFAULT_BACKGROUND_COLOR = 0x00FFFFFF; |
| |
| /** |
| * EditStyledTextInterface provides functions for notifying messages to |
| * calling class. |
| */ |
| public interface EditStyledTextNotifier { |
| public void notifyHintMsg(int msgId); |
| public void notifyStateChanged(int mode, int state); |
| } |
| |
| private EditStyledTextNotifier mESTInterface; |
| |
| /** |
| * EditStyledTextEditorManager manages the flow and status of each |
| * function for editing styled text. |
| */ |
| private EditorManager mManager; |
| private StyledTextConverter mConverter; |
| private StyledTextDialog mDialog; |
| private Drawable mDefaultBackground; |
| private int mBackgroundColor; |
| |
| /** |
| * EditStyledText extends EditText for managing flow of each editing |
| * action. |
| */ |
| public EditStyledText(Context context, AttributeSet attrs, int defStyle) { |
| super(context, attrs, defStyle); |
| init(); |
| } |
| |
| public EditStyledText(Context context, AttributeSet attrs) { |
| super(context, attrs); |
| init(); |
| } |
| |
| public EditStyledText(Context context) { |
| super(context); |
| init(); |
| } |
| |
| /** |
| * Set Notifier. |
| */ |
| public void setNotifier(EditStyledTextNotifier estInterface) { |
| mESTInterface = estInterface; |
| } |
| |
| /** |
| * Set Builder for AlertDialog. |
| * |
| * @param builder |
| * Builder for opening Alert Dialog. |
| */ |
| public void setBuilder(Builder builder) { |
| mDialog.setBuilder(builder); |
| } |
| |
| /** |
| * Set Parameters for ColorAlertDialog. |
| * |
| * @param colortitle |
| * Title for Alert Dialog. |
| * @param colornames |
| * List of name of selecting color. |
| * @param colorints |
| * List of int of color. |
| */ |
| public void setColorAlertParams(CharSequence colortitle, |
| CharSequence[] colornames, CharSequence[] colorints) { |
| mDialog.setColorAlertParams(colortitle, colornames, colorints); |
| } |
| |
| /** |
| * Set Parameters for SizeAlertDialog. |
| * |
| * @param sizetitle |
| * Title for Alert Dialog. |
| * @param sizenames |
| * List of name of selecting size. |
| * @param sizedisplayints |
| * List of int of size displayed in TextView. |
| * @param sizesendints |
| * List of int of size exported to HTML. |
| */ |
| public void setSizeAlertParams(CharSequence sizetitle, |
| CharSequence[] sizenames, CharSequence[] sizedisplayints, |
| CharSequence[] sizesendints) { |
| mDialog.setSizeAlertParams(sizetitle, sizenames, sizedisplayints, |
| sizesendints); |
| } |
| |
| public void setAlignAlertParams(CharSequence aligntitle, |
| CharSequence[] alignnames) { |
| mDialog.setAlignAlertParams(aligntitle, alignnames); |
| } |
| |
| @Override |
| public boolean onTouchEvent(MotionEvent event) { |
| if (mManager.isSoftKeyBlocked() && |
| event.getAction() == MotionEvent.ACTION_UP) { |
| cancelLongPress(); |
| } |
| final boolean superResult = super.onTouchEvent(event); |
| if (event.getAction() == MotionEvent.ACTION_UP) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- onTouchEvent"); |
| } |
| mManager.onCursorMoved(); |
| } |
| return superResult; |
| } |
| |
| /** |
| * Start editing. This function have to be called before other editing |
| * actions. |
| */ |
| public void onStartEdit() { |
| mManager.onStartEdit(); |
| } |
| |
| /** |
| * End editing. |
| */ |
| public void onEndEdit() { |
| mManager.onEndEdit(); |
| } |
| |
| /** |
| * Start "Copy" action. |
| */ |
| public void onStartCopy() { |
| mManager.onStartCopy(); |
| } |
| |
| /** |
| * Start "Cut" action. |
| */ |
| public void onStartCut() { |
| mManager.onStartCut(); |
| } |
| |
| /** |
| * Start "Paste" action. |
| */ |
| public void onStartPaste() { |
| mManager.onStartPaste(); |
| } |
| |
| /** |
| * Start changing "Size" action. |
| */ |
| public void onStartSize() { |
| mManager.onStartSize(); |
| } |
| |
| /** |
| * Start changing "Color" action. |
| */ |
| public void onStartColor() { |
| mManager.onStartColor(); |
| } |
| |
| /** |
| * Start changing "BackgroundColor" action. |
| */ |
| public void onStartBackgroundColor() { |
| mManager.onStartBackgroundColor(); |
| } |
| |
| /** |
| * Start changing "Alignment" action. |
| */ |
| public void onStartAlign() { |
| mManager.onStartAlign(); |
| } |
| |
| /** |
| * Start "Select" action. |
| */ |
| public void onStartSelect() { |
| mManager.onStartSelect(); |
| } |
| |
| /** |
| * Start "SelectAll" action. |
| */ |
| public void onStartSelectAll() { |
| mManager.onStartSelectAll(); |
| } |
| |
| /** |
| * Fix Selected Item. |
| */ |
| public void onFixSelectedItem() { |
| mManager.onFixSelectedItem(); |
| } |
| |
| /** |
| * InsertImage to TextView by using URI |
| * |
| * @param uri |
| * URI of the iamge inserted to TextView. |
| */ |
| public void onInsertImage(Uri uri) { |
| mManager.onInsertImage(uri); |
| } |
| |
| /** |
| * InsertImage to TextView by using resource ID |
| * |
| * @param resId |
| * Resource ID of the iamge inserted to TextView. |
| */ |
| public void onInsertImage(int resId) { |
| mManager.onInsertImage(resId); |
| } |
| |
| public void onInsertHorizontalLine() { |
| mManager.onInsertHorizontalLine(); |
| } |
| |
| public void onClearStyles() { |
| mManager.onClearStyles(); |
| } |
| /** |
| * Set Size of the Item. |
| * |
| * @param size |
| * The size of the Item. |
| */ |
| public void setItemSize(int size) { |
| mManager.setItemSize(size); |
| } |
| |
| /** |
| * Set Color of the Item. |
| * |
| * @param color |
| * The color of the Item. |
| */ |
| public void setItemColor(int color) { |
| mManager.setItemColor(color); |
| } |
| |
| /** |
| * Set Alignment of the Item. |
| * |
| * @param color |
| * The color of the Item. |
| */ |
| public void setAlignment(Layout.Alignment align) { |
| mManager.setAlignment(align); |
| } |
| |
| /** |
| * Set Background color of View. |
| * |
| * @param color |
| * The background color of view. |
| */ |
| @Override |
| public void setBackgroundColor(int color) { |
| super.setBackgroundColor(color); |
| mBackgroundColor = color; |
| } |
| |
| /** |
| * Set html to EditStyledText. |
| * |
| * @param html |
| * The html to be set. |
| */ |
| public void setHtml(String html) { |
| mConverter.SetHtml(html); |
| } |
| /** |
| * Check whether editing is started or not. |
| * |
| * @return Whether editing is started or not. |
| */ |
| public boolean isEditting() { |
| return mManager.isEditting(); |
| } |
| |
| /** |
| * Check whether styled text or not. |
| * |
| * @return Whether styled text or not. |
| */ |
| public boolean isStyledText() { |
| return mManager.isStyledText(); |
| } |
| /** |
| * Check whether SoftKey is Blocked or not. |
| * |
| * @return whether SoftKey is Blocked or not. |
| */ |
| public boolean isSoftKeyBlocked() { |
| return mManager.isSoftKeyBlocked(); |
| } |
| |
| /** |
| * Get the mode of the action. |
| * |
| * @return The mode of the action. |
| */ |
| public int getEditMode() { |
| return mManager.getEditMode(); |
| } |
| |
| /** |
| * Get the state of the selection. |
| * |
| * @return The state of the selection. |
| */ |
| public int getSelectState() { |
| return mManager.getSelectState(); |
| } |
| |
| @Override |
| public Bundle getInputExtras(boolean create) { |
| if (DBG) { |
| Log.d(LOG_TAG, "---getInputExtras"); |
| } |
| Bundle bundle = super.getInputExtras(create); |
| if (bundle != null) { |
| bundle = new Bundle(); |
| } |
| bundle.putBoolean("allowEmoji", true); |
| return bundle; |
| } |
| |
| /** |
| * Get the state of the selection. |
| * |
| * @return The state of the selection. |
| */ |
| public String getHtml() { |
| return mConverter.getHtml(); |
| } |
| |
| /** |
| * Get the state of the selection. |
| * |
| * @param uris |
| * The array of used uris. |
| * @return The state of the selection. |
| */ |
| public String getHtml(ArrayList<Uri> uris) { |
| mConverter.getUriArray(uris, getText()); |
| return mConverter.getHtml(); |
| } |
| |
| /** |
| * Get Background color of View. |
| * |
| * @return The background color of View. |
| */ |
| public int getBackgroundColor() { |
| return mBackgroundColor; |
| } |
| |
| /** |
| * Get Foreground color of View. |
| * |
| * @return The background color of View. |
| */ |
| public int getForeGroundColor(int pos) { |
| if (DBG) { |
| Log.d(LOG_TAG, "---getForeGroundColor: " + pos); |
| } |
| if (pos < 0 || pos > getText().length()) { |
| Log.e(LOG_TAG, "---getForeGroundColor: Illigal position."); |
| return DEFAULT_BACKGROUND_COLOR; |
| } else { |
| ForegroundColorSpan[] spans = |
| getText().getSpans(pos, pos, ForegroundColorSpan.class); |
| if (spans.length > 0) { |
| return spans[0].getForegroundColor(); |
| } else { |
| return DEFAULT_BACKGROUND_COLOR; |
| } |
| } |
| } |
| |
| /** |
| * Initialize members. |
| */ |
| private void init() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- init"); |
| } |
| requestFocus(); |
| mDefaultBackground = getBackground(); |
| mBackgroundColor = DEFAULT_BACKGROUND_COLOR; |
| mManager = new EditorManager(this); |
| mConverter = new StyledTextConverter(this); |
| mDialog = new StyledTextDialog(this); |
| setMovementMethod(new StyledTextArrowKeyMethod(mManager)); |
| mManager.blockSoftKey(); |
| mManager.unblockSoftKey(); |
| } |
| |
| /** |
| * Show Foreground Color Selecting Dialog. |
| */ |
| private void onShowForegroundColorAlert() { |
| mDialog.onShowForegroundColorAlertDialog(); |
| } |
| |
| /** |
| * Show Background Color Selecting Dialog. |
| */ |
| private void onShowBackgroundColorAlert() { |
| mDialog.onShowBackgroundColorAlertDialog(); |
| } |
| |
| /** |
| * Show Size Selecting Dialog. |
| */ |
| private void onShowSizeAlert() { |
| mDialog.onShowSizeAlertDialog(); |
| } |
| |
| /** |
| * Show Alignment Selecting Dialog. |
| */ |
| private void onShowAlignAlert() { |
| mDialog.onShowAlignAlertDialog(); |
| } |
| |
| /** |
| * Notify hint messages what action is expected to calling class. |
| * |
| * @param msgId |
| * Id of the hint message. |
| */ |
| private void setHintMessage(int msgId) { |
| if (mESTInterface != null) { |
| mESTInterface.notifyHintMsg(msgId); |
| } |
| } |
| |
| /** |
| * Notify the event that the mode and state are changed. |
| * |
| * @param mode |
| * Mode of the editing action. |
| * @param state |
| * Mode of the selection state. |
| */ |
| private void notifyStateChanged(int mode, int state) { |
| if (mESTInterface != null) { |
| mESTInterface.notifyStateChanged(mode, state); |
| } |
| } |
| |
| /** |
| * EditorManager manages the flow and status of editing actions. |
| */ |
| private class EditorManager { |
| private boolean mEditFlag = false; |
| private boolean mSoftKeyBlockFlag = false; |
| private int mMode = 0; |
| private int mState = 0; |
| private int mCurStart = 0; |
| private int mCurEnd = 0; |
| private EditStyledText mEST; |
| |
| EditorManager(EditStyledText est) { |
| mEST = est; |
| } |
| |
| public void onStartEdit() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- onStartEdit"); |
| } |
| Log.d(LOG_TAG, "--- onstartedit:"); |
| handleResetEdit(); |
| mEST.notifyStateChanged(mMode, mState); |
| } |
| |
| public void onEndEdit() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- onEndEdit"); |
| } |
| handleCancel(); |
| mEST.notifyStateChanged(mMode, mState); |
| } |
| |
| public void onStartCopy() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- onStartCopy"); |
| } |
| handleCopy(); |
| mEST.notifyStateChanged(mMode, mState); |
| } |
| |
| public void onStartCut() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- onStartCut"); |
| } |
| handleCut(); |
| mEST.notifyStateChanged(mMode, mState); |
| } |
| |
| public void onStartPaste() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- onStartPaste"); |
| } |
| handlePaste(); |
| mEST.notifyStateChanged(mMode, mState); |
| } |
| |
| public void onStartSize() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- onStartSize"); |
| } |
| handleSize(); |
| mEST.notifyStateChanged(mMode, mState); |
| } |
| |
| public void onStartAlign() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- onStartAlignRight"); |
| } |
| handleAlign(); |
| mEST.notifyStateChanged(mMode, mState); |
| } |
| |
| public void onStartColor() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- onClickColor"); |
| } |
| handleColor(); |
| mEST.notifyStateChanged(mMode, mState); |
| } |
| |
| public void onStartBackgroundColor() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- onClickColor"); |
| } |
| mEST.onShowBackgroundColorAlert(); |
| mEST.notifyStateChanged(mMode, mState); |
| } |
| |
| public void onStartSelect() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- onClickSelect"); |
| } |
| mMode = MODE_SELECT; |
| if (mState == STATE_SELECT_OFF) { |
| handleSelect(); |
| } else { |
| unsetSelect(); |
| handleSelect(); |
| } |
| mEST.notifyStateChanged(mMode, mState); |
| } |
| |
| public void onCursorMoved() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- onClickView"); |
| } |
| if (mState == STATE_SELECT_ON || mState == STATE_SELECTED) { |
| handleSelect(); |
| mEST.notifyStateChanged(mMode, mState); |
| } |
| } |
| |
| public void onStartSelectAll() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- onClickSelectAll"); |
| } |
| handleSelectAll(); |
| mEST.notifyStateChanged(mMode, mState); |
| } |
| |
| public void onFixSelectedItem() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- onClickComplete"); |
| } |
| handleComplete(); |
| mEST.notifyStateChanged(mMode, mState); |
| } |
| |
| public void onInsertImage(Uri uri) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- onInsertImage by URI: " + uri.getPath() |
| + "," + uri.toString()); |
| } |
| insertImageSpan(new ImageSpan(mEST.getContext(), uri)); |
| mEST.notifyStateChanged(mMode, mState); |
| } |
| |
| public void onInsertImage(int resID) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- onInsertImage by resID"); |
| } |
| insertImageSpan(new ImageSpan(mEST.getContext(), resID)); |
| mEST.notifyStateChanged(mMode, mState); |
| } |
| |
| public void onInsertHorizontalLine() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- onInsertHorizontalLine:"); |
| } |
| insertImageSpan(new HorizontalLineSpan(0xFF000000, mEST)); |
| mEST.notifyStateChanged(mMode, mState); |
| } |
| |
| public void onClearStyles() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- onClearStyles"); |
| } |
| Editable txt = mEST.getText(); |
| int len = txt.length(); |
| Object[] styles = txt.getSpans(0, len, Object.class); |
| for (Object style : styles) { |
| if (style instanceof ParagraphStyle || |
| style instanceof QuoteSpan || |
| style instanceof CharacterStyle) { |
| if (style instanceof ImageSpan) { |
| int start = txt.getSpanStart(style); |
| int end = txt.getSpanEnd(style); |
| txt.replace(start, end, ""); |
| } |
| txt.removeSpan(style); |
| } |
| } |
| mEST.setBackgroundDrawable(mEST.mDefaultBackground); |
| mEST.mBackgroundColor = DEFAULT_BACKGROUND_COLOR; |
| } |
| |
| public void setItemSize(int size) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- onClickSizeItem"); |
| } |
| if (mState == STATE_SELECTED || mState == STATE_SELECT_FIX) { |
| changeSizeSelectedText(size); |
| handleResetEdit(); |
| } |
| } |
| |
| public void setItemColor(int color) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- onClickColorItem"); |
| } |
| if (mState == STATE_SELECTED || mState == STATE_SELECT_FIX) { |
| changeColorSelectedText(color); |
| handleResetEdit(); |
| } |
| } |
| |
| public void setAlignment(Layout.Alignment align) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- onClickColorItem"); |
| } |
| if (mState == STATE_SELECTED || mState == STATE_SELECT_FIX) { |
| changeAlign(align); |
| handleResetEdit(); |
| } |
| } |
| |
| public boolean isEditting() { |
| return mEditFlag; |
| } |
| |
| /* If the style of the span is added, add check case for that style */ |
| public boolean isStyledText() { |
| Editable txt = mEST.getText(); |
| int len = txt.length(); |
| if (txt.getSpans(0, len -1, ParagraphStyle.class).length > 0 || |
| txt.getSpans(0, len -1, QuoteSpan.class).length > 0 || |
| txt.getSpans(0, len -1, CharacterStyle.class).length > 0 || |
| mEST.mBackgroundColor != DEFAULT_BACKGROUND_COLOR) { |
| return true; |
| } |
| return false; |
| } |
| |
| public boolean isSoftKeyBlocked() { |
| return mSoftKeyBlockFlag; |
| } |
| |
| public int getEditMode() { |
| return mMode; |
| } |
| |
| public int getSelectState() { |
| return mState; |
| } |
| |
| public int getSelectionStart() { |
| return mCurStart; |
| } |
| |
| public int getSelectionEnd() { |
| return mCurEnd; |
| } |
| |
| private void doNextHandle() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- doNextHandle: " + mMode + "," + mState); |
| } |
| switch (mMode) { |
| case MODE_COPY: |
| handleCopy(); |
| break; |
| case MODE_CUT: |
| handleCut(); |
| break; |
| case MODE_PASTE: |
| handlePaste(); |
| break; |
| case MODE_SIZE: |
| handleSize(); |
| break; |
| case MODE_COLOR: |
| handleColor(); |
| break; |
| case MODE_ALIGN: |
| handleAlign(); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| private void handleCancel() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- handleCancel"); |
| } |
| mMode = MODE_NOTHING; |
| mState = STATE_SELECT_OFF; |
| mEditFlag = false; |
| Log.d(LOG_TAG, "--- handleCancel:" + mEST.getInputType()); |
| unblockSoftKey(); |
| unsetSelect(); |
| } |
| |
| private void handleComplete() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- handleComplete"); |
| } |
| if (!mEditFlag) { |
| return; |
| } |
| if (mState == STATE_SELECTED) { |
| mState = STATE_SELECT_FIX; |
| } |
| doNextHandle(); |
| } |
| |
| private void handleTextViewFunc(int mode, int id) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- handleTextView: " + mMode + "," + mState + |
| "," + id); |
| } |
| if (!mEditFlag) { |
| return; |
| } |
| if (mMode == MODE_NOTHING || mMode == MODE_SELECT) { |
| mMode = mode; |
| if (mState == STATE_SELECTED) { |
| mState = STATE_SELECT_FIX; |
| handleTextViewFunc(mode, id); |
| } else { |
| handleSelect(); |
| } |
| } else if (mMode != mode) { |
| handleCancel(); |
| mMode = mode; |
| handleTextViewFunc(mode, id); |
| } else if (mState == STATE_SELECT_FIX) { |
| mEST.onTextContextMenuItem(id); |
| handleResetEdit(); |
| } |
| } |
| |
| private void handleCopy() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- handleCopy: " + mMode + "," + mState); |
| } |
| handleTextViewFunc(MODE_COPY, android.R.id.copy); |
| } |
| |
| private void handleCut() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- handleCopy: " + mMode + "," + mState); |
| } |
| handleTextViewFunc(MODE_CUT, android.R.id.cut); |
| } |
| |
| private void handlePaste() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- handlePaste"); |
| } |
| if (!mEditFlag) { |
| return; |
| } |
| mEST.onTextContextMenuItem(android.R.id.paste); |
| } |
| |
| private void handleSetSpan(int mode) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- handleSetSpan:" + mEditFlag + "," |
| + mState + ',' + mMode); |
| } |
| if (!mEditFlag) { |
| Log.e(LOG_TAG, "--- handleSetSpan: Editing is not started."); |
| return; |
| } |
| if (mMode == MODE_NOTHING || mMode == MODE_SELECT) { |
| mMode = mode; |
| if (mState == STATE_SELECTED) { |
| mState = STATE_SELECT_FIX; |
| handleSetSpan(mode); |
| } else { |
| handleSelect(); |
| } |
| } else if (mMode != mode) { |
| handleCancel(); |
| mMode = mode; |
| handleSetSpan(mode); |
| } else { |
| if (mState == STATE_SELECT_FIX) { |
| mEST.setHintMessage(HINT_MSG_NULL); |
| switch (mode) { |
| case MODE_COLOR: |
| mEST.onShowForegroundColorAlert(); |
| break; |
| case MODE_SIZE: |
| mEST.onShowSizeAlert(); |
| break; |
| case MODE_ALIGN: |
| mEST.onShowAlignAlert(); |
| break; |
| default: |
| Log.e(LOG_TAG, "--- handleSetSpan: invalid mode."); |
| break; |
| } |
| } else { |
| Log.d(LOG_TAG, "--- handleSetSpan: do nothing."); |
| } |
| } |
| } |
| |
| private void handleSize() { |
| handleSetSpan(MODE_SIZE); |
| } |
| |
| private void handleColor() { |
| handleSetSpan(MODE_COLOR); |
| } |
| |
| private void handleAlign() { |
| handleSetSpan(MODE_ALIGN); |
| } |
| |
| private void handleSelect() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- handleSelect:" + mEditFlag + "," + mState); |
| } |
| if (!mEditFlag) { |
| return; |
| } |
| if (mState == STATE_SELECT_OFF) { |
| if (isTextSelected()) { |
| Log.e(LOG_TAG, "Selection is off, but selected"); |
| } |
| setSelectStartPos(); |
| blockSoftKey(); |
| mEST.setHintMessage(HINT_MSG_SELECT_END); |
| } else if (mState == STATE_SELECT_ON) { |
| if (isTextSelected()) { |
| Log.e(LOG_TAG, "Selection now start, but selected"); |
| } |
| setSelectedEndPos(); |
| mEST.setHintMessage(HINT_MSG_PUSH_COMPETE); |
| doNextHandle(); |
| } else if (mState == STATE_SELECTED) { |
| if (!isTextSelected()) { |
| Log.e(LOG_TAG, "Selection is done, but not selected"); |
| } |
| setSelectedEndPos(); |
| doNextHandle(); |
| } |
| } |
| |
| private void handleSelectAll() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- handleSelectAll"); |
| } |
| if (!mEditFlag) { |
| return; |
| } |
| mEST.selectAll(); |
| mState = STATE_SELECTED; |
| } |
| |
| private void handleResetEdit() { |
| if (DBG) { |
| Log.d(LOG_TAG, "Reset Editor"); |
| } |
| blockSoftKey(); |
| handleCancel(); |
| mEditFlag = true; |
| mEST.setHintMessage(HINT_MSG_SELECT_START); |
| } |
| |
| private void setSelection() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- onSelect:" + mCurStart + "," + mCurEnd); |
| } |
| if (mCurStart >= 0 && mCurStart <= mEST.getText().length() |
| && mCurEnd >= 0 && mCurEnd <= mEST.getText().length()) { |
| if (mCurStart < mCurEnd) { |
| mEST.setSelection(mCurStart, mCurEnd); |
| } else { |
| mEST.setSelection(mCurEnd, mCurStart); |
| } |
| mState = STATE_SELECTED; |
| } else { |
| Log.e(LOG_TAG, |
| "Select is on, but cursor positions are illigal.:" |
| + mEST.getText().length() + "," + mCurStart |
| + "," + mCurEnd); |
| } |
| } |
| |
| private void unsetSelect() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- offSelect"); |
| } |
| int currpos = mEST.getSelectionStart(); |
| mEST.setSelection(currpos, currpos); |
| mState = STATE_SELECT_OFF; |
| } |
| |
| private void setSelectStartPos() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- setSelectStartPos"); |
| } |
| mCurStart = mEST.getSelectionStart(); |
| mState = STATE_SELECT_ON; |
| } |
| |
| private void setSelectedEndPos() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- setSelectEndPos:"); |
| } |
| if (mEST.getSelectionStart() == mCurStart) { |
| setSelectedEndPos(mEST.getSelectionEnd()); |
| } else { |
| setSelectedEndPos(mEST.getSelectionStart()); |
| } |
| } |
| |
| public void setSelectedEndPos(int pos) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- setSelectedEndPos:"); |
| } |
| mCurEnd = pos; |
| setSelection(); |
| } |
| |
| private boolean isTextSelected() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- isTextSelected:" + mCurStart + "," |
| + mCurEnd); |
| } |
| return (mCurStart != mCurEnd) |
| && (mState == STATE_SELECTED || |
| mState == STATE_SELECT_FIX); |
| } |
| |
| private void setStyledTextSpan(Object span, int start, int end) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- setStyledTextSpan:" + mMode + "," |
| + start + "," + end); |
| } |
| if (start < end) { |
| mEST.getText().setSpan(span, start, end, |
| Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
| } else { |
| mEST.getText().setSpan(span, end, start, |
| Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
| } |
| } |
| |
| private void changeSizeSelectedText(int size) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- changeSize:" + size); |
| } |
| setStyledTextSpan(new AbsoluteSizeSpan(size), |
| mCurStart, mCurEnd); |
| } |
| |
| private void changeColorSelectedText(int color) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- changeColor:" + color); |
| } |
| setStyledTextSpan(new ForegroundColorSpan(color), |
| mCurStart, mCurEnd); |
| } |
| |
| private void changeAlign(Layout.Alignment align) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- changeAlign:" + align); |
| } |
| setStyledTextSpan(new AlignmentSpan.Standard(align), |
| findLineStart(mEST.getText(), mCurStart), |
| findLineEnd(mEST.getText(), mCurEnd)); |
| } |
| |
| private int findLineStart(Editable text, int current) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- findLineStart: curr:" + current + |
| ", length:" + text.length()); |
| } |
| int pos = current; |
| for (; pos > 0; pos--) { |
| if (text.charAt(pos - 1) == '\n') { |
| break; |
| } |
| } |
| return pos; |
| } |
| |
| private void insertImageSpan(ImageSpan span) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- insertImageSpan"); |
| } |
| if (span != null) { |
| Log.d(LOG_TAG, "--- insertimagespan:" + span.getDrawable().getIntrinsicHeight() + "," + span.getDrawable().getIntrinsicWidth()); |
| Log.d(LOG_TAG, "--- insertimagespan:" + span.getDrawable().getClass()); |
| int curpos = mEST.getSelectionStart(); |
| mEST.getText().insert(curpos, "\uFFFC"); |
| mEST.getText().setSpan(span, curpos, curpos + 1, |
| Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
| mEST.notifyStateChanged(mMode, mState); |
| } else { |
| Log.e(LOG_TAG, "--- insertImageSpan: null span was inserted"); |
| } |
| } |
| |
| private int findLineEnd(Editable text, int current) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- findLineEnd: curr:" + current + |
| ", length:" + text.length()); |
| } |
| int pos = current; |
| for (; pos < text.length(); pos++) { |
| if (pos > 0 && text.charAt(pos - 1) == '\n') { |
| break; |
| } |
| } |
| return pos; |
| } |
| |
| private void blockSoftKey() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- blockSoftKey:"); |
| } |
| InputMethodManager imm = (InputMethodManager) mEST.getContext(). |
| getSystemService(Context.INPUT_METHOD_SERVICE); |
| imm.hideSoftInputFromWindow(mEST.getWindowToken(), 0); |
| mEST.setOnClickListener( |
| new OnClickListener() { |
| public void onClick(View v) { |
| Log.d(LOG_TAG, "--- ontrackballclick:"); |
| onFixSelectedItem(); |
| } |
| }); |
| mSoftKeyBlockFlag = true; |
| } |
| |
| private void unblockSoftKey() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- unblockSoftKey:"); |
| } |
| mEST.setOnClickListener(null); |
| mSoftKeyBlockFlag = false; |
| } |
| } |
| |
| private class StyledTextConverter { |
| private EditStyledText mEST; |
| |
| public StyledTextConverter(EditStyledText est) { |
| mEST = est; |
| } |
| |
| public String getHtml() { |
| String htmlBody = Html.toHtml(mEST.getText()); |
| if (DBG) { |
| Log.d(LOG_TAG, "--- getConvertedBody:" + htmlBody); |
| } |
| return htmlBody; |
| } |
| |
| public void getUriArray(ArrayList<Uri> uris, Editable text) { |
| uris.clear(); |
| if (DBG) { |
| Log.d(LOG_TAG, "--- getUriArray:"); |
| } |
| int len = text.length(); |
| int next; |
| for (int i = 0; i < text.length(); i = next) { |
| next = text.nextSpanTransition(i, len, ImageSpan.class); |
| ImageSpan[] images = text.getSpans(i, next, ImageSpan.class); |
| for (int j = 0; j < images.length; j++) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- getUriArray: foundArray" + |
| ((ImageSpan) images[j]).getSource()); |
| } |
| uris.add(Uri.parse( |
| ((ImageSpan) images[j]).getSource())); |
| } |
| } |
| } |
| |
| public void SetHtml (String html) { |
| final Spanned spanned = Html.fromHtml(html, new Html.ImageGetter() { |
| public Drawable getDrawable(String src) { |
| Log.d(LOG_TAG, "--- sethtml: src="+src); |
| if (src.startsWith("content://")) { |
| Uri uri = Uri.parse(src); |
| try { |
| InputStream is = mEST.getContext().getContentResolver().openInputStream(uri); |
| Bitmap bitmap = BitmapFactory.decodeStream(is); |
| Drawable drawable = new BitmapDrawable( |
| getContext().getResources(), bitmap); |
| drawable.setBounds(0, 0, |
| drawable.getIntrinsicWidth(), |
| drawable.getIntrinsicHeight()); |
| is.close(); |
| return drawable; |
| } catch (Exception e) { |
| Log.e(LOG_TAG, "--- set html: Failed to loaded content " + uri, e); |
| return null; |
| } |
| } |
| Log.d(LOG_TAG, " unknown src="+src); |
| return null; |
| } |
| }, null); |
| mEST.setText(spanned); |
| } |
| } |
| |
| private class StyledTextDialog { |
| Builder mBuilder; |
| CharSequence mColorTitle; |
| CharSequence mSizeTitle; |
| CharSequence mAlignTitle; |
| CharSequence[] mColorNames; |
| CharSequence[] mColorInts; |
| CharSequence[] mSizeNames; |
| CharSequence[] mSizeDisplayInts; |
| CharSequence[] mSizeSendInts; |
| CharSequence[] mAlignNames; |
| EditStyledText mEST; |
| |
| public StyledTextDialog(EditStyledText est) { |
| mEST = est; |
| } |
| |
| public void setBuilder(Builder builder) { |
| mBuilder = builder; |
| } |
| |
| public void setColorAlertParams(CharSequence colortitle, |
| CharSequence[] colornames, CharSequence[] colorints) { |
| mColorTitle = colortitle; |
| mColorNames = colornames; |
| mColorInts = colorints; |
| } |
| |
| public void setSizeAlertParams(CharSequence sizetitle, |
| CharSequence[] sizenames, CharSequence[] sizedisplayints, |
| CharSequence[] sizesendints) { |
| mSizeTitle = sizetitle; |
| mSizeNames = sizenames; |
| mSizeDisplayInts = sizedisplayints; |
| mSizeSendInts = sizesendints; |
| } |
| |
| public void setAlignAlertParams(CharSequence aligntitle, |
| CharSequence[] alignnames) { |
| mAlignTitle = aligntitle; |
| mAlignNames = alignnames; |
| } |
| |
| private boolean checkColorAlertParams() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- checkParams"); |
| } |
| if (mBuilder == null) { |
| Log.e(LOG_TAG, "--- builder is null."); |
| return false; |
| } else if (mColorTitle == null || mColorNames == null |
| || mColorInts == null) { |
| Log.e(LOG_TAG, "--- color alert params are null."); |
| return false; |
| } else if (mColorNames.length != mColorInts.length) { |
| Log.e(LOG_TAG, "--- the length of color alert params are " |
| + "different."); |
| return false; |
| } |
| return true; |
| } |
| |
| private boolean checkSizeAlertParams() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- checkParams"); |
| } |
| if (mBuilder == null) { |
| Log.e(LOG_TAG, "--- builder is null."); |
| return false; |
| } else if (mSizeTitle == null || mSizeNames == null |
| || mSizeDisplayInts == null || mSizeSendInts == null) { |
| Log.e(LOG_TAG, "--- size alert params are null."); |
| return false; |
| } else if (mSizeNames.length != mSizeDisplayInts.length |
| && mSizeSendInts.length != mSizeDisplayInts.length) { |
| Log.e(LOG_TAG, "--- the length of size alert params are " |
| + "different."); |
| return false; |
| } |
| return true; |
| } |
| |
| private boolean checkAlignAlertParams() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- checkAlignAlertParams"); |
| } |
| if (mBuilder == null) { |
| Log.e(LOG_TAG, "--- builder is null."); |
| return false; |
| } else if (mAlignTitle == null) { |
| Log.e(LOG_TAG, "--- align alert params are null."); |
| return false; |
| } |
| return true; |
| } |
| |
| private void onShowForegroundColorAlertDialog() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- onShowForegroundColorAlertDialog"); |
| } |
| if (!checkColorAlertParams()) { |
| return; |
| } |
| mBuilder.setTitle(mColorTitle); |
| mBuilder.setIcon(0); |
| mBuilder. |
| setItems(mColorNames, |
| new DialogInterface.OnClickListener() { |
| public void onClick(DialogInterface dialog, int which) { |
| Log.d("EETVM", "mBuilder.onclick:" + which); |
| int color = Integer.parseInt( |
| (String) mColorInts[which], 16) - 0x01000000; |
| mEST.setItemColor(color); |
| } |
| }); |
| mBuilder.show(); |
| } |
| |
| private void onShowBackgroundColorAlertDialog() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- onShowBackgroundColorAlertDialog"); |
| } |
| if (!checkColorAlertParams()) { |
| return; |
| } |
| mBuilder.setTitle(mColorTitle); |
| mBuilder.setIcon(0); |
| mBuilder. |
| setItems(mColorNames, |
| new DialogInterface.OnClickListener() { |
| public void onClick(DialogInterface dialog, int which) { |
| Log.d("EETVM", "mBuilder.onclick:" + which); |
| int color = Integer.parseInt( |
| (String) mColorInts[which], 16) - 0x01000000; |
| mEST.setBackgroundColor(color); |
| } |
| }); |
| mBuilder.show(); |
| } |
| |
| private void onShowSizeAlertDialog() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- onShowSizeAlertDialog"); |
| } |
| if (!checkSizeAlertParams()) { |
| return; |
| } |
| mBuilder.setTitle(mSizeTitle); |
| mBuilder.setIcon(0); |
| mBuilder. |
| setItems(mSizeNames, |
| new DialogInterface.OnClickListener() { |
| public void onClick(DialogInterface dialog, int which) { |
| Log.d(LOG_TAG, "mBuilder.onclick:" + which); |
| int size = Integer |
| .parseInt((String) mSizeDisplayInts[which]); |
| mEST.setItemSize(size); |
| } |
| }); |
| mBuilder.show(); |
| } |
| |
| private void onShowAlignAlertDialog() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- onShowAlignAlertDialog"); |
| } |
| if (!checkAlignAlertParams()) { |
| return; |
| } |
| mBuilder.setTitle(mAlignTitle); |
| mBuilder.setIcon(0); |
| mBuilder. |
| setItems(mAlignNames, |
| new DialogInterface.OnClickListener() { |
| public void onClick(DialogInterface dialog, int which) { |
| Log.d(LOG_TAG, "mBuilder.onclick:" + which); |
| Layout.Alignment align = Layout.Alignment.ALIGN_NORMAL; |
| switch (which) { |
| case 0: |
| align = Layout.Alignment.ALIGN_NORMAL; |
| break; |
| case 1: |
| align = Layout.Alignment.ALIGN_CENTER; |
| break; |
| case 2: |
| align = Layout.Alignment.ALIGN_OPPOSITE; |
| break; |
| default: |
| break; |
| } |
| mEST.setAlignment(align); |
| } |
| }); |
| mBuilder.show(); |
| } |
| } |
| |
| private class StyledTextArrowKeyMethod extends ArrowKeyMovementMethod { |
| EditorManager mManager; |
| StyledTextArrowKeyMethod(EditorManager manager) { |
| super(); |
| mManager = manager; |
| } |
| |
| @Override |
| public boolean onKeyDown(TextView widget, Spannable buffer, |
| int keyCode, KeyEvent event) { |
| if (!mManager.isSoftKeyBlocked()) { |
| return super.onKeyDown(widget, buffer, keyCode, event); |
| } |
| if (executeDown(widget, buffer, keyCode)) { |
| return true; |
| } |
| return false; |
| } |
| |
| private int getEndPos(TextView widget) { |
| int end; |
| if (widget.getSelectionStart() == mManager.getSelectionStart()) { |
| end = widget.getSelectionEnd(); |
| } else { |
| end = widget.getSelectionStart(); |
| } |
| return end; |
| } |
| |
| private boolean up(TextView widget, Spannable buffer) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- up:"); |
| } |
| Layout layout = widget.getLayout(); |
| int end = getEndPos(widget); |
| int line = layout.getLineForOffset(end); |
| if (line > 0) { |
| int to; |
| if (layout.getParagraphDirection(line) == |
| layout.getParagraphDirection(line - 1)) { |
| float h = layout.getPrimaryHorizontal(end); |
| to = layout.getOffsetForHorizontal(line - 1, h); |
| } else { |
| to = layout.getLineStart(line - 1); |
| } |
| mManager.setSelectedEndPos(to); |
| mManager.onCursorMoved(); |
| return true; |
| } |
| return false; |
| } |
| |
| private boolean down(TextView widget, Spannable buffer) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- down:"); |
| } |
| Layout layout = widget.getLayout(); |
| int end = getEndPos(widget); |
| int line = layout.getLineForOffset(end); |
| if (line < layout.getLineCount() - 1) { |
| int to; |
| if (layout.getParagraphDirection(line) == |
| layout.getParagraphDirection(line + 1)) { |
| float h = layout.getPrimaryHorizontal(end); |
| to = layout.getOffsetForHorizontal(line + 1, h); |
| } else { |
| to = layout.getLineStart(line + 1); |
| } |
| mManager.setSelectedEndPos(to); |
| mManager.onCursorMoved(); |
| return true; |
| } |
| return false; |
| } |
| |
| private boolean left(TextView widget, Spannable buffer) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- left:"); |
| } |
| Layout layout = widget.getLayout(); |
| int to = layout.getOffsetToLeftOf(getEndPos(widget)); |
| mManager.setSelectedEndPos(to); |
| mManager.onCursorMoved(); |
| return true; |
| } |
| |
| private boolean right(TextView widget, Spannable buffer) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- right:"); |
| } |
| Layout layout = widget.getLayout(); |
| int to = layout.getOffsetToRightOf(getEndPos(widget)); |
| mManager.setSelectedEndPos(to); |
| mManager.onCursorMoved(); |
| return true; |
| } |
| |
| private boolean executeDown(TextView widget, Spannable buffer, |
| int keyCode) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- executeDown: " + keyCode); |
| } |
| boolean handled = false; |
| |
| switch (keyCode) { |
| case KeyEvent.KEYCODE_DPAD_UP: |
| handled |= up(widget, buffer); |
| break; |
| case KeyEvent.KEYCODE_DPAD_DOWN: |
| handled |= down(widget, buffer); |
| break; |
| case KeyEvent.KEYCODE_DPAD_LEFT: |
| handled |= left(widget, buffer); |
| break; |
| case KeyEvent.KEYCODE_DPAD_RIGHT: |
| handled |= right(widget, buffer); |
| break; |
| case KeyEvent.KEYCODE_DPAD_CENTER: |
| mManager.onFixSelectedItem(); |
| handled = true; |
| break; |
| } |
| return handled; |
| } |
| } |
| |
| public class HorizontalLineSpan extends ImageSpan { |
| public HorizontalLineSpan(int color, View view) { |
| super(new HorizontalLineDrawable(color, view)); |
| } |
| } |
| public class HorizontalLineDrawable extends ShapeDrawable { |
| private View mView; |
| public HorizontalLineDrawable(int color, View view) { |
| super(new RectShape()); |
| mView = view; |
| renewColor(color); |
| renewBounds(view); |
| } |
| @Override |
| public void draw(Canvas canvas) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- draw:"); |
| } |
| renewColor(); |
| renewBounds(mView); |
| super.draw(canvas); |
| } |
| |
| private void renewBounds(View view) { |
| if (DBG) { |
| int width = mView.getBackground().getBounds().width(); |
| int height = mView.getBackground().getBounds().height(); |
| Log.d(LOG_TAG, "--- renewBounds:" + width + "," + height); |
| Log.d(LOG_TAG, "--- renewBounds:" + mView.getClass()); |
| } |
| int width = mView.getWidth(); |
| if (width > 20) { |
| width -= 20; |
| } |
| setBounds(0, 0, width, 2); |
| } |
| private void renewColor(int color) { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- renewColor:" + color); |
| } |
| getPaint().setColor(color); |
| } |
| private void renewColor() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- renewColor:"); |
| } |
| if (mView instanceof View) { |
| ImageSpan parent = getParentSpan(); |
| Editable text = ((EditStyledText)mView).getText(); |
| int start = text.getSpanStart(parent); |
| ForegroundColorSpan[] spans = text.getSpans(start, start, ForegroundColorSpan.class); |
| if (spans.length > 0) { |
| renewColor(spans[spans.length - 1].getForegroundColor()); |
| } |
| } |
| } |
| private ImageSpan getParentSpan() { |
| if (DBG) { |
| Log.d(LOG_TAG, "--- getParentSpan:"); |
| } |
| if (mView instanceof EditStyledText) { |
| Editable text = ((EditStyledText)mView).getText(); |
| ImageSpan[] images = text.getSpans(0, text.length(), ImageSpan.class); |
| if (images.length > 0) { |
| for (ImageSpan image: images) { |
| if (image.getDrawable() == this) { |
| return image; |
| } |
| } |
| } |
| } |
| Log.e(LOG_TAG, "---renewBounds: Couldn't find"); |
| return null; |
| } |
| } |
| } |