PageRenderTime 741ms CodeModel.GetById 201ms app.highlight 232ms RepoModel.GetById 226ms app.codeStats 1ms

/src/compiler/android-ndk/src/org/libftk/app/FtkActivity.java

http://ftk.googlecode.com/
Java | 892 lines | 428 code | 114 blank | 350 comment | 51 complexity | 81d1541615df6298f6b403b84d61b29b MD5 | raw file
  1package org.libftk.app;
  2
  3import java.io.InputStream;
  4
  5import javax.microedition.khronos.egl.*;
  6
  7import android.app.*;
  8import android.content.*;
  9import android.view.*;
 10import android.view.inputmethod.BaseInputConnection;
 11import android.view.inputmethod.CompletionInfo;
 12import android.view.inputmethod.EditorInfo;
 13import android.view.inputmethod.ExtractedText;
 14import android.view.inputmethod.ExtractedTextRequest;
 15import android.view.inputmethod.InputConnection;
 16import android.view.inputmethod.InputMethodManager;
 17import android.os.*;
 18import android.util.Log;
 19import android.text.method.*;
 20import android.text.*;
 21import android.content.res.AssetFileDescriptor;
 22import android.content.res.AssetManager;
 23import android.content.res.Configuration;
 24import android.graphics.Bitmap;
 25import android.graphics.BitmapFactory;
 26import android.graphics.Canvas;
 27import android.graphics.Rect;
 28
 29public class FtkActivity extends Activity {
 30    private static final boolean DEBUG = true;
 31    private static final String TAG = "FtkActivity";
 32
 33    private static FtkActivity mActivity;
 34    private static FtkView mView;
 35    private static AssetManager mAssetManager;
 36    public static Thread mThread;
 37
 38    static {
 39        System.loadLibrary("ftkapp");
 40    }
 41
 42    protected void onCreate(Bundle savedInstanceState) {
 43        super.onCreate(savedInstanceState);
 44        
 45        mActivity = this;
 46
 47        Window window = getWindow();
 48        window.requestFeature(Window.FEATURE_NO_TITLE);
 49        //requestWindowFeature(Window.FEATURE_NO_TITLE);
 50        window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
 51
 52        mAssetManager = getAssets();
 53
 54        mView = new FtkView(this, getApplication());
 55        setContentView(mView);
 56        SurfaceHolder holder = mView.getHolder();
 57        holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
 58
 59        //ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
 60        //ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
 61        //getRequestedOrientation();
 62        //setRequestedOrientation();
 63
 64        //List<InputMethodInfo> imInfos = imm.getEnabledInputMethodList();
 65        //Iterator<InputMethodInfo> it = imInfos.iterator();
 66        //while (it.hasNext()) {
 67        //	InputMethodInfo info = it.next();
 68        //	Log.d("FtkActivity", "InputMethod: " + info.getPackageName()
 69        //			+ ", " + info.loadLabel(getPackageManager()));
 70        //}
 71    }
 72
 73    //Events
 74    protected void onPause()
 75    {
 76        super.onPause();
 77    }
 78
 79    protected void onResume()
 80    {
 81        super.onResume();
 82    }
 83    
 84    protected void onStop() {
 85    	super.onStop();
 86    	if (DEBUG) { Log.d(TAG, "onStop"); }
 87    }
 88
 89    protected void onDestroy() {
 90    	super.onDestroy();
 91    	if (DEBUG) { Log.d(TAG, "onDestroy"); }
 92
 93    	nativeQuit();
 94
 95        try {
 96        	mThread.wait();
 97        } catch (Exception e) {
 98            Log.e(TAG, "stopping ftk thread: " + e);
 99        }
100
101        mAssetManager.close();
102
103        ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
104        am.restartPackage(getPackageName());
105    }
106
107    public void onConfigurationChanged(Configuration newConfig) {
108    	if (DEBUG) { Log.d(TAG, "onConfigurationChanged"); }
109    	super.onConfigurationChanged(newConfig);
110    	if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
111    		Log.d(TAG, "ORIENTATION_LANDSCAPE");
112    	} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
113    		Log.d(TAG, "ORIENTATION_PORTRAIT");
114    	} else if (newConfig.orientation == Configuration.ORIENTATION_SQUARE) {
115    		Log.d(TAG, "ORIENTATION_SQUARE");
116    	}
117    }
118
119
120    public static native void nativeInit();
121    public static native void nativeQuit();
122    public static native void nativeSetScreenSize(int width, int height);
123    public static native void nativeEnableRender();
124    public static native void nativeDisableRender();
125    public static native void onNativeKey(int action, int keyCode);
126    public static native void onNativeCommitText(String text, int newCursorPosition);
127    public static native void onNativeTouch(int action, float x, float y, float p);
128    public static native void onNativeResize(int x, int y, int format);
129
130
131    // Java functions called from C
132    
133    public static final AssetFileDescriptor getAssetFileDescriptor(String file) {
134    	if (DEBUG) { Log.d(TAG, "getAssetFileDescriptor: " + file); }
135    	try {
136    	    return mAssetManager.openFd(file);
137    	} catch (Exception ex) {
138    		Log.e(TAG, ex.getMessage());
139    	}
140    	return null;
141    }
142    
143    public static final Bitmap decodeImage(String file) {
144    	//if (DEBUG) { Log.d(TAG, "decodeImage: " + file); }
145    	InputStream is = null;
146    	try {
147    		is = mAssetManager.open(file);
148    	} catch (Exception ex) {
149    		Log.e(TAG, ex.getMessage());
150    		return null;
151    	}
152    	Bitmap bitmap = BitmapFactory.decodeStream(is);
153    	try {
154    		is.close();
155    	} catch (Exception ex) {
156    		Log.e(TAG, ex.getMessage());
157    	}
158    	is = null;
159    	return bitmap;
160    }
161
162    public static final void initEGL() {
163        mView.initEGL();
164    }
165    
166    public static final void createEGLSurface() {
167    	mView.createEGLSurface();
168    }
169    
170    public static final void destroyEGLSurface() {
171    	mView.destroyEGLSurface();
172    }
173
174    public static final void flipEGL() {
175        mView.flipEGL();
176    }
177    
178    public static final void drawBitmap(int[] colors, int offset, int stride, int x, int y, int width, int height) {
179    	mView.drawBitmap(colors, offset, stride, x, y, width, height);
180    }
181
182    public static final void showKeyboard() {
183    	InputMethodManager imm = (InputMethodManager) mActivity.getSystemService(INPUT_METHOD_SERVICE);
184    	imm.showSoftInput(mView, 0);
185    }
186
187    public static final void hideKeyboard() {
188    	InputMethodManager imm = (InputMethodManager) mActivity.getSystemService(INPUT_METHOD_SERVICE);
189    	imm.hideSoftInputFromWindow(mView.getWindowToken(), 0);
190    }
191
192    public static final void showInputMethodPicker() {
193    	InputMethodManager imm = (InputMethodManager) mActivity.getSystemService(INPUT_METHOD_SERVICE);
194    	//imm.hideSoftInputFromWindow(mView.getWindowToken(), 0);
195    	imm.showInputMethodPicker();
196    }
197}
198
199class FtkRunner implements Runnable {
200    private static final boolean DEBUG = true;
201    private static final String TAG = "FtkRunner";
202
203    private FtkActivity mActivity;
204
205    public FtkRunner(FtkActivity activity) {
206    	super();
207    	mActivity = activity;
208    }
209
210    public void run() {
211        if (DEBUG) { Log.d(TAG, "thread run"); }
212
213        FtkActivity.nativeInit();
214
215        if (DEBUG) { Log.v(TAG, "thread exit"); }
216
217        mActivity.finish();
218    }
219}
220
221class FtkInputConnection extends BaseInputConnection {
222    private static final boolean DEBUG = true;
223    private static final String TAG = "FtkInputConnection";
224
225    private final FtkView mView;
226
227    public FtkInputConnection(FtkView view) {
228        super(view, true);
229        mView = view;
230    }
231	
232    public Editable getEditable() {
233        FtkView v = mView;
234        if (v != null) {
235            return v.getEditableText();
236        }
237        return null;
238    }
239    
240    public boolean beginBatchEdit() {
241        mView.beginBatchEdit();
242        return true;
243    }
244    
245    public boolean endBatchEdit() {
246        mView.endBatchEdit();
247        return true;
248    }
249    
250    public boolean clearMetaKeyStates(int states) {
251        final Editable content = getEditable();
252        if (content == null) return false;
253        KeyListener kl = mView.getKeyListener();
254        if (kl != null) {
255            try {
256                kl.clearMetaKeyState(mView, content, states);
257            } catch (AbstractMethodError e) {
258                // This is an old listener that doesn't implement the
259                // new method.
260            }
261        }
262        return true;
263    }
264    
265    public boolean commitCompletion(CompletionInfo text) {
266        if (DEBUG) Log.v(TAG, "commitCompletion " + text);
267        mView.beginBatchEdit();
268        mView.onCommitCompletion(text);
269        mView.endBatchEdit();
270        return true;
271    }
272
273    public boolean performEditorAction(int actionCode) {
274        if (DEBUG) Log.v(TAG, "performEditorAction " + actionCode);
275        mView.onEditorAction(actionCode);
276        return true;
277    }
278    
279    public boolean performContextMenuAction(int id) {
280        if (DEBUG) Log.v(TAG, "performContextMenuAction " + id);
281        mView.beginBatchEdit();
282        mView.onTextContextMenuItem(id);
283        mView.endBatchEdit();
284        return true;
285    }
286    
287    public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
288        if (mView != null) {
289            ExtractedText et = new ExtractedText();
290            if (mView.extractText(request, et)) {
291                if ((flags&GET_EXTRACTED_TEXT_MONITOR) != 0) {
292                    mView.setExtracting(request);
293                }
294                return et;
295            }
296        }
297        return null;
298    }
299    
300    public boolean performPrivateCommand(String action, Bundle data) {
301        mView.onPrivateIMECommand(action, data);
302        return true;
303    }
304
305    @Override
306    public boolean commitText(CharSequence text, int newCursorPosition) {
307    	if (DEBUG) Log.v(TAG, "commitText " + text);
308        if (mView == null) {
309            return super.commitText(text, newCursorPosition);
310        }
311        
312        FtkActivity.onNativeCommitText(String.valueOf(text), newCursorPosition);
313
314        boolean success = super.commitText(text, newCursorPosition);
315        return success;
316    }
317}
318
319class FtkView extends SurfaceView implements SurfaceHolder.Callback, View.OnKeyListener, View.OnTouchListener {
320
321    private static final boolean DEBUG = true;
322    private static final String TAG = "FtkView";
323
324    private FtkActivity mActivity;
325	
326    private boolean mSurfaceValid = false;
327
328    private EGLDisplay mEGLDisplay;
329    private EGLConfig mEGLConfig;
330    private EGLContext mEGLContext;
331    private EGLSurface mEGLSurface;
332
333    public FtkView(FtkActivity activity, Context context) {
334        super(context);
335        mActivity = activity;
336
337        SurfaceHolder holder = getHolder();
338        holder.addCallback(this);
339
340        setFocusable(true);
341        setFocusableInTouchMode(true);
342        requestFocus();
343        setOnKeyListener(this);
344        setOnTouchListener(this);
345
346        mText = "";
347    }
348
349    public void surfaceCreated(SurfaceHolder holder) {
350        if (DEBUG) { Log.v(TAG, "surfaceCreated"); }
351
352        if (FtkActivity.mThread != null) {
353            mSurfaceValid = true;
354            FtkActivity.nativeEnableRender();
355            return;
356        }
357
358        int width = getWidth();
359        int height = getHeight();
360        FtkActivity.nativeSetScreenSize(width, height);
361
362        FtkActivity.mThread = new Thread(new FtkRunner(mActivity), "ftk thread");
363        FtkActivity.mThread.start();
364
365        mSurfaceValid = true;
366        FtkActivity.nativeEnableRender();
367    }
368
369    public void surfaceDestroyed(SurfaceHolder holder) {
370        if (DEBUG) { Log.v(TAG, "surfaceDestroyed"); }
371        mSurfaceValid = false;
372        FtkActivity.nativeDisableRender();
373    }
374
375    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
376        if (DEBUG) { Log.d(TAG, "surfaceChanged"); }
377        FtkActivity.onNativeResize(width, height, format);
378    }
379
380
381    // EGL functions
382    public boolean initEGL() {
383        if (DEBUG) { Log.d(TAG, "initEGL"); }
384
385        try {
386            EGL10 egl = (EGL10)EGLContext.getEGL();
387
388            EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
389            int[] version = new int[2];
390            egl.eglInitialize(dpy, version);
391
392            int[] configSpec = {
393		        EGL10.EGL_RED_SIZE, 5,
394		        EGL10.EGL_GREEN_SIZE, 6,
395		        EGL10.EGL_BLUE_SIZE, 5,
396		        EGL10.EGL_ALPHA_SIZE, EGL10.EGL_DONT_CARE,
397		        EGL10.EGL_DEPTH_SIZE, 16,
398		        EGL10.EGL_STENCIL_SIZE, EGL10.EGL_DONT_CARE,
399		        EGL10.EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT,
400                EGL10.EGL_NONE
401            };
402            EGLConfig[] configs = new EGLConfig[1];
403            int[] num_config = new int[1];
404            egl.eglChooseConfig(dpy, configSpec, configs, 1, num_config);
405            EGLConfig config = configs[0];
406
407            EGLContext ctx = egl.eglCreateContext(dpy, config, EGL10.EGL_NO_CONTEXT, null);
408
409            mEGLDisplay = dpy;
410            mEGLConfig = config;
411            mEGLContext = ctx;
412
413        } catch (Exception e) {
414            Log.e(TAG, e + "");
415            for(StackTraceElement s : e.getStackTrace()) {
416                Log.e(TAG, s.toString());
417            }
418        }
419
420        return true;
421    }
422    
423    public void createEGLSurface() {
424    	if (DEBUG) { Log.d(TAG, "createEGLSurface"); }
425    	EGL10 egl = (EGL10)EGLContext.getEGL();
426    	//if (mEGLSurface != null) {
427    		// xxx
428    	//}
429
430    	EGLSurface surface = egl.eglCreateWindowSurface(mEGLDisplay, mEGLConfig, this, null);
431        egl.eglMakeCurrent(mEGLDisplay, surface, surface, mEGLContext);
432
433        mEGLSurface = surface;
434    }
435
436    public void destroyEGLSurface() {
437    	if (DEBUG) { Log.d(TAG, "destroyEGLSurface"); }
438    	//EGL10 egl = (EGL10)EGLContext.getEGL();
439    	if (mEGLSurface != null) {
440    		//egl.eglMakeCurrent(mEGLDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, mEGLContext);
441    		//egl.eglDestroySurface(mEGLDisplay, mEGLSurface);
442    		mEGLSurface = null;
443    	}
444    }
445
446    public void flipEGL() {
447    	if (!mSurfaceValid) {
448        	return;
449        }
450        try {
451            EGL10 egl = (EGL10)EGLContext.getEGL();
452
453            egl.eglWaitNative(EGL10.EGL_NATIVE_RENDERABLE, null);
454            egl.eglWaitGL();
455            egl.eglSwapBuffers(mEGLDisplay, mEGLSurface);
456            
457        } catch(Exception e) {
458            Log.v("FTK", "flipEGL(): " + e);
459
460            for(StackTraceElement s : e.getStackTrace()){
461                Log.v("FTK", s.toString());
462            }
463        }
464    }
465    
466    public void drawBitmap(int[] colors, int offset, int stride, int x, int y, int width, int height) {
467    	//if (DEBUG) { Log.d(TAG, "drawBitmap: " + x + "-" + y + " " + width + "-" + height); }
468    	SurfaceHolder holder = getHolder();
469    	if (holder == null) {
470    		return;
471    	}
472    	Rect rect = new Rect(x, y, x + width, y + height);
473    	Canvas canvas = holder.lockCanvas(rect);
474    	if (canvas == null) {
475    		return;
476    	}
477    	canvas.drawBitmap(colors, offset, stride, x, y, width, height, true, null);
478    	holder.unlockCanvasAndPost(canvas);
479    }
480
481    public boolean onKey(View  v, int keyCode, KeyEvent event){
482    	FtkActivity.onNativeKey(event.getAction(), keyCode);
483        return true;
484    }
485
486    public boolean onTouch(View v, MotionEvent event){
487        FtkActivity.onNativeTouch(event.getAction(), event.getX(), event.getY(), event.getPressure());
488        return true;
489    }
490
491
492    // input method
493
494    /**
495     * Interface definition for a callback to be invoked when an action is
496     * performed on the editor.
497     */
498    public interface OnEditorActionListener {
499        /**
500         * Called when an action is being performed.
501         *
502         * @param v The view that was clicked.
503         * @param actionId Identifier of the action.  This will be either the
504         * identifier you supplied, or {@link EditorInfo#IME_NULL
505         * EditorInfo.IME_NULL} if being called due to the enter key
506         * being pressed.
507         * @param event If triggered by an enter key, this is the event;
508         * otherwise, this is null.
509         * @return Return true if you have consumed the action, else false.
510         */
511        boolean onEditorAction(FtkView v, int actionId, KeyEvent event);
512    }
513    
514    class InputContentType {
515        int imeOptions = EditorInfo.IME_NULL;
516        String privateImeOptions;
517        CharSequence imeActionLabel;
518        int imeActionId;
519        Bundle extras;
520        OnEditorActionListener onEditorActionListener;
521        boolean enterDown;
522    }
523    InputContentType mInputContentType;
524    
525    @Override public boolean onCheckIsTextEditor() {
526    	return true;
527    }
528    
529    @Override public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
530    	return new FtkInputConnection(this);
531    }
532    
533    /**
534     * Called when an attached input method calls
535     * {@link InputConnection#performEditorAction(int)
536     * InputConnection.performEditorAction()}
537     * for this text view.  The default implementation will call your action
538     * listener supplied to {@link #setOnEditorActionListener}, or perform
539     * a standard operation for {@link EditorInfo#IME_ACTION_NEXT
540     * EditorInfo.IME_ACTION_NEXT} or {@link EditorInfo#IME_ACTION_DONE
541     * EditorInfo.IME_ACTION_DONE}.
542     * 
543     * <p>For backwards compatibility, if no IME options have been set and the
544     * text view would not normally advance focus on enter, then
545     * the NEXT and DONE actions received here will be turned into an enter
546     * key down/up pair to go through the normal key handling.
547     * 
548     * @param actionCode The code of the action being performed.
549     * 
550     * @see #setOnEditorActionListener
551     */
552    public void onEditorAction(int actionCode) {
553        /*final InputContentType ict = mInputContentType;
554        if (ict != null) {
555            if (ict.onEditorActionListener != null) {
556                if (ict.onEditorActionListener.onEditorAction(this,
557                        actionCode, null)) {
558                    return;
559                }
560            }
561            
562            // This is the handling for some default action.
563            // Note that for backwards compatibility we don't do this
564            // default handling if explicit ime options have not been given,
565            // instead turning this into the normal enter key codes that an
566            // app may be expecting.
567            if (actionCode == EditorInfo.IME_ACTION_NEXT) {
568                View v = focusSearch(FOCUS_DOWN);
569                if (v != null) {
570                    if (!v.requestFocus(FOCUS_DOWN)) {
571                        throw new IllegalStateException("focus search returned a view " +
572                                "that wasn't able to take focus!");
573                    }
574                }
575                return;
576                
577            } else if (actionCode == EditorInfo.IME_ACTION_DONE) {
578            	FtkActivity activity = FtkActivity.mSingleton;
579            	InputMethodManager imm = (InputMethodManager) activity.getSystemService(FtkActivity.INPUT_METHOD_SERVICE);
580                if (imm != null) {
581                    imm.hideSoftInputFromWindow(getWindowToken(), 0);
582                }
583                return;
584            }
585        }
586        
587        Handler h = getHandler();
588        if (h != null) {
589            long eventTime = SystemClock.uptimeMillis();
590            h.sendMessage(h.obtainMessage(ViewRoot.DISPATCH_KEY_FROM_IME,
591                    new KeyEvent(eventTime, eventTime,
592                    KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER, 0, 0, 0, 0,
593                    KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE
594                    | KeyEvent.FLAG_EDITOR_ACTION)));
595            h.sendMessage(h.obtainMessage(ViewRoot.DISPATCH_KEY_FROM_IME,
596                    new KeyEvent(SystemClock.uptimeMillis(), eventTime,
597                    KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER, 0, 0, 0, 0,
598                    KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE
599                    | KeyEvent.FLAG_EDITOR_ACTION)));
600        }*/
601    }
602    
603    /**
604     * If this TextView contains editable content, extract a portion of it
605     * based on the information in <var>request</var> in to <var>outText</var>.
606     * @return Returns true if the text was successfully extracted, else false.
607     */
608    public boolean extractText(ExtractedTextRequest request,
609            ExtractedText outText) {
610        return extractTextInternal(request, EXTRACT_UNKNOWN, EXTRACT_UNKNOWN,
611                EXTRACT_UNKNOWN, outText);
612    }
613    
614    static final int EXTRACT_NOTHING = -2;
615    static final int EXTRACT_UNKNOWN = -1;
616    
617    boolean extractTextInternal(ExtractedTextRequest request,
618            int partialStartOffset, int partialEndOffset, int delta,
619            ExtractedText outText) {
620        /*final CharSequence content = mText;
621        if (content != null) {
622            if (partialStartOffset != EXTRACT_NOTHING) {
623                final int N = content.length();
624                if (partialStartOffset < 0) {
625                    outText.partialStartOffset = outText.partialEndOffset = -1;
626                    partialStartOffset = 0;
627                    partialEndOffset = N;
628                } else {
629                    // Now use the delta to determine the actual amount of text
630                    // we need.
631                    partialEndOffset += delta;
632                    // Adjust offsets to ensure we contain full spans.
633                    if (content instanceof Spanned) {
634                        Spanned spanned = (Spanned)content;
635                        Object[] spans = spanned.getSpans(partialStartOffset,
636                                partialEndOffset, ParcelableSpan.class);
637                        int i = spans.length;
638                        while (i > 0) {
639                            i--;
640                            int j = spanned.getSpanStart(spans[i]);
641                            if (j < partialStartOffset) partialStartOffset = j;
642                            j = spanned.getSpanEnd(spans[i]);
643                            if (j > partialEndOffset) partialEndOffset = j;
644                        }
645                    }
646                    outText.partialStartOffset = partialStartOffset;
647                    outText.partialEndOffset = partialEndOffset - delta;
648
649                    if (partialStartOffset > N) {
650                        partialStartOffset = N;
651                    } else if (partialStartOffset < 0) {
652                        partialStartOffset = 0;
653                    }
654                    if (partialEndOffset > N) {
655                        partialEndOffset = N;
656                    } else if (partialEndOffset < 0) {
657                        partialEndOffset = 0;
658                    }
659                }
660                if ((request.flags&InputConnection.GET_TEXT_WITH_STYLES) != 0) {
661                    outText.text = content.subSequence(partialStartOffset,
662                            partialEndOffset);
663                } else {
664                    outText.text = TextUtils.substring(content, partialStartOffset,
665                            partialEndOffset);
666                }
667            } else {
668                outText.partialStartOffset = 0;
669                outText.partialEndOffset = 0;
670                outText.text = "";
671            }
672            outText.flags = 0;
673            if (MetaKeyKeyListener.getMetaState(mText, MetaKeyKeyListener.META_SELECTING) != 0) {
674                outText.flags |= ExtractedText.FLAG_SELECTING;
675            }
676            if (mSingleLine) {
677                outText.flags |= ExtractedText.FLAG_SINGLE_LINE;
678            }
679            outText.startOffset = 0;
680            outText.selectionStart = Selection.getSelectionStart(content);
681            outText.selectionEnd = Selection.getSelectionEnd(content);
682            return true;
683        }*/
684        return false;
685    }
686    
687    /**
688     * @hide
689     */
690    public void setExtracting(ExtractedTextRequest req) {
691        /*if (mInputMethodState != null) {
692            mInputMethodState.mExtracting = req;
693        }*/
694    }
695    
696    /**
697     * Called by the framework in response to a private command from the
698     * current method, provided by it calling
699     * {@link InputConnection#performPrivateCommand
700     * InputConnection.performPrivateCommand()}.
701     *
702     * @param action The action name of the command.
703     * @param data Any additional data for the command.  This may be null.
704     * @return Return true if you handled the command, else false.
705     */
706    public boolean onPrivateIMECommand(String action, Bundle data) {
707        return false;
708    }
709    
710    /**
711     * Return the text the TextView is displaying as an Editable object.  If
712     * the text is not editable, null is returned.
713     *
714     * @see #getText
715     */
716    public Editable getEditableText() {
717        return (mText instanceof Editable) ? (Editable)mText : null;
718    }
719    
720    /**
721     * Called by the framework in response to a text completion from
722     * the current input method, provided by it calling
723     * {@link InputConnection#commitCompletion
724     * InputConnection.commitCompletion()}.  The default implementation does
725     * nothing; text views that are supporting auto-completion should override
726     * this to do their desired behavior.
727     *
728     * @param text The auto complete text the user has selected.
729     */
730    public void onCommitCompletion(CompletionInfo text) {
731    	if (DEBUG) Log.v(TAG, "onCommitCompletion " + text.getText());
732    }
733    
734    /**
735     * Called when a context menu option for the text view is selected.  Currently
736     * this will be one of: {@link android.R.id#selectAll},
737     * {@link android.R.id#startSelectingText}, {@link android.R.id#stopSelectingText},
738     * {@link android.R.id#cut}, {@link android.R.id#copy},
739     * {@link android.R.id#paste}, {@link android.R.id#copyUrl},
740     * or {@link android.R.id#switchInputMethod}.
741     */
742    public boolean onTextContextMenuItem(int id) {
743        /*int selStart = getSelectionStart();
744        int selEnd = getSelectionEnd();
745
746        if (!isFocused()) {
747            selStart = 0;
748            selEnd = mText.length();
749        }
750
751        int min = Math.min(selStart, selEnd);
752        int max = Math.max(selStart, selEnd);
753
754        if (min < 0) {
755            min = 0;
756        }
757        if (max < 0) {
758            max = 0;
759        }
760
761        ClipboardManager clip = (ClipboardManager)getContext()
762                .getSystemService(Context.CLIPBOARD_SERVICE);
763
764        switch (id) {
765            case ID_SELECT_ALL:
766                Selection.setSelection((Spannable) mText, 0,
767                        mText.length());
768                return true;
769
770            case ID_START_SELECTING_TEXT:
771                MetaKeyKeyListener.startSelecting(this, (Spannable) mText);
772                return true;
773
774            case ID_STOP_SELECTING_TEXT:
775                MetaKeyKeyListener.stopSelecting(this, (Spannable) mText);
776                Selection.setSelection((Spannable) mText, getSelectionEnd());
777                return true;
778
779            case ID_CUT:
780                MetaKeyKeyListener.stopSelecting(this, (Spannable) mText);
781
782                if (min == max) {
783                    min = 0;
784                    max = mText.length();
785                }
786
787                clip.setText(mTransformed.subSequence(min, max));
788                ((Editable) mText).delete(min, max);
789                return true;
790
791            case ID_COPY:
792                MetaKeyKeyListener.stopSelecting(this, (Spannable) mText);
793
794                if (min == max) {
795                    min = 0;
796                    max = mText.length();
797                }
798
799                clip.setText(mTransformed.subSequence(min, max));
800                return true;
801
802            case ID_PASTE:
803                MetaKeyKeyListener.stopSelecting(this, (Spannable) mText);
804
805                CharSequence paste = clip.getText();
806
807                if (paste != null) {
808                    Selection.setSelection((Spannable) mText, max);
809                    ((Editable) mText).replace(min, max, paste);
810                }
811
812                return true;
813
814            case ID_COPY_URL:
815                MetaKeyKeyListener.stopSelecting(this, (Spannable) mText);
816
817                URLSpan[] urls = ((Spanned) mText).getSpans(min, max,
818                                                       URLSpan.class);
819                if (urls.length == 1) {
820                    clip.setText(urls[0].getURL());
821                }
822
823                return true;
824
825            case ID_SWITCH_INPUT_METHOD:
826                InputMethodManager imm = InputMethodManager.peekInstance();
827                if (imm != null) {
828                    imm.showInputMethodPicker();
829                }
830                return true;
831
832            case ID_ADD_TO_DICTIONARY:
833                String word = getWordForDictionary();
834
835                if (word != null) {
836                    Intent i = new Intent("com.android.settings.USER_DICTIONARY_INSERT");
837                    i.putExtra("word", word);
838                    i.setFlags(i.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
839                    getContext().startActivity(i);
840                }
841
842                return true;
843            }*/
844
845        return false;
846    }
847    
848    public void beginBatchEdit() {
849    	if (DEBUG) Log.v(TAG, "beginBatchEdit");
850        /*final InputMethodState ims = mInputMethodState;
851        if (ims != null) {
852            int nesting = ++ims.mBatchEditNesting;
853            if (nesting == 1) {
854                ims.mCursorChanged = false;
855                ims.mChangedDelta = 0;
856                if (ims.mContentChanged) {
857                    // We already have a pending change from somewhere else,
858                    // so turn this into a full update.
859                    ims.mChangedStart = 0;
860                    ims.mChangedEnd = mText.length();
861                } else {
862                    ims.mChangedStart = EXTRACT_UNKNOWN;
863                    ims.mChangedEnd = EXTRACT_UNKNOWN;
864                    ims.mContentChanged = false;
865                }
866                onBeginBatchEdit();
867            }
868        }*/
869    }
870    
871    public void endBatchEdit() {
872    	if (DEBUG) Log.v(TAG, "endBatchEdit");
873        /*final InputMethodState ims = mInputMethodState;
874        if (ims != null) {
875            int nesting = --ims.mBatchEditNesting;
876            if (nesting == 0) {
877                finishBatchEdit(ims);
878            }
879        }*/
880    }
881    
882    /**
883     * @return the current key listener for this TextView.
884     * This will frequently be null for non-EditText TextViews.
885     */
886    public final KeyListener getKeyListener() {
887        return mInput;
888    }
889    
890    private CharSequence mText;
891    private KeyListener mInput;
892}