alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Android example source code file (EditStyledText.java)

This example Android source code file (EditStyledText.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Android by Example" TM.

Java - Android tags/keywords

android, charsequence, dbg, default_background_color, drawing, editable, editormanager, editstyledtext, graphics, imagespan, override, paint, spannable, state_select_fix, state_select_off, state_selected, string, styledtextdialog, text, ui

The EditStyledText.java Android example source code

/*
 * 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;
        }
    }
}

Other Android examples (source code examples)

Here is a short list of links related to this Android EditStyledText.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.