private boolean processKeyDown(int keyCode, KeyEvent event, boolean isPreIme) { if (DEBUG) { Log.d( LOGTAG, "IME: processKeyDown(keyCode=" + keyCode + ", event=" + event + ", " + isPreIme + ")"); } clampSelection(); switch (keyCode) { case KeyEvent.KEYCODE_MENU: case KeyEvent.KEYCODE_BACK: case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_VOLUME_DOWN: case KeyEvent.KEYCODE_SEARCH: return false; case KeyEvent.KEYCODE_DEL: // See comments in GeckoInputConnection.onKeyDel if (onKeyDel()) { return true; } break; case KeyEvent.KEYCODE_ENTER: if ((event.getFlags() & KeyEvent.FLAG_EDITOR_ACTION) != 0 && mIMEActionHint.equalsIgnoreCase("next")) event = new KeyEvent(event.getAction(), KeyEvent.KEYCODE_TAB); break; default: break; } if (isPreIme && mIMEState != IME_STATE_DISABLED && (event.getMetaState() & KeyEvent.META_ALT_ON) != 0) // Let active IME process pre-IME key events return false; View view = GeckoApp.mAppContext.getLayerController().getView(); KeyListener keyListener = TextKeyListener.getInstance(); // KeyListener returns true if it handled the event for us. if (mIMEState == IME_STATE_DISABLED || keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_DEL || keyCode == KeyEvent.KEYCODE_TAB || (event.getFlags() & KeyEvent.FLAG_SOFT_KEYBOARD) != 0 || !keyListener.onKeyDown(view, mEditable, keyCode, event)) { // Make sure selection in Gecko is up-to-date final Editable content = getEditable(); int a = Selection.getSelectionStart(content); int b = Selection.getSelectionEnd(content); GeckoAppShell.sendEventToGecko( GeckoEvent.createIMEEvent(GeckoEvent.IME_SET_SELECTION, a, b - a)); GeckoAppShell.sendEventToGecko(GeckoEvent.createKeyEvent(event)); } return true; }
private boolean processKeyUp(int keyCode, KeyEvent event, boolean isPreIme) { if (DEBUG) { Log.d( LOGTAG, "IME: processKeyUp(keyCode=" + keyCode + ", event=" + event + ", " + isPreIme + ")"); } switch (keyCode) { case KeyEvent.KEYCODE_BACK: case KeyEvent.KEYCODE_SEARCH: case KeyEvent.KEYCODE_MENU: return false; default: break; } if (isPreIme && mIMEState != IME_STATE_DISABLED && (event.getMetaState() & KeyEvent.META_ALT_ON) != 0) // Let active IME process pre-IME key events return false; View view = GeckoApp.mAppContext.getLayerController().getView(); KeyListener keyListener = TextKeyListener.getInstance(); if (mIMEState == IME_STATE_DISABLED || keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_DEL || (event.getFlags() & KeyEvent.FLAG_SOFT_KEYBOARD) != 0 || !keyListener.onKeyUp(view, mEditable, keyCode, event)) { GeckoAppShell.sendEventToGecko(GeckoEvent.createKeyEvent(event)); } return true; }
/* * DoorHanger.OnButtonClickListener implementation */ @Override public void onButtonClick(DoorHanger dh, String tag) { JSONObject response = new JSONObject(); try { response.put("callback", tag); CheckBox checkBox = dh.getCheckBox(); // If the checkbox is being used, pass its value if (checkBox != null) { response.put("checked", checkBox.isChecked()); } List<PromptInput> doorHangerInputs = dh.getInputs(); if (doorHangerInputs != null) { JSONObject inputs = new JSONObject(); for (PromptInput input : doorHangerInputs) { inputs.put(input.getId(), input.getValue()); } response.put("inputs", inputs); } } catch (JSONException e) { Log.e(LOGTAG, "Error creating onClick response", e); } GeckoEvent e = GeckoEvent.createBroadcastEvent("Doorhanger:Reply", response.toString()); GeckoAppShell.sendEventToGecko(e); removeDoorHanger(dh); updatePopup(); }
@Override public boolean setSelection(int start, int end) { GeckoAppShell.sendEventToGecko( GeckoEvent.createIMEEvent(GeckoEvent.IME_SET_SELECTION, start, end - start)); return super.setSelection(start, end); }
/** Send current network state and connection type as a GeckoEvent, to whomever is listening. */ private void sendNetworkStateToListeners() { final Context applicationContext = GeckoAppShell.getApplicationContext(); final GeckoEvent networkEvent = GeckoEvent.createNetworkEvent( currentConnectionType.value, currentConnectionType == ConnectionType.WIFI, wifiDhcpGatewayAddress(applicationContext), currentConnectionSubtype.value); final GeckoEvent networkLinkChangeValueEvent = GeckoEvent.createNetworkLinkChangeEvent(currentNetworkStatus.value); final GeckoEvent networkLinkChangeNotificationEvent = GeckoEvent.createNetworkLinkChangeEvent(LINK_DATA_CHANGED); GeckoAppShell.sendEventToGecko(networkEvent); GeckoAppShell.sendEventToGecko(networkLinkChangeValueEvent); GeckoAppShell.sendEventToGecko(networkLinkChangeNotificationEvent); }
private void connectToGecko() { GeckoThread.setLaunchState(GeckoThread.LaunchState.GeckoRunning); Tab selectedTab = Tabs.getInstance().getSelectedTab(); if (selectedTab != null) Tabs.getInstance().notifyListeners(selectedTab, Tabs.TabEvents.SELECTED); geckoConnected(); GeckoAppShell.setLayerClient(getLayerClientObject()); GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Viewport:Flush", null)); }
@Override public void onClick(View v) { switch (v.getId()) { case R.id.find_prev: GeckoAppShell.sendEventToGecko( GeckoEvent.createBroadcastEvent("FindInPage:Prev", mFindText.getText().toString())); getInputMethodManager(mFindText).hideSoftInputFromWindow(mFindText.getWindowToken(), 0); break; case R.id.find_next: GeckoAppShell.sendEventToGecko( GeckoEvent.createBroadcastEvent("FindInPage:Next", mFindText.getText().toString())); getInputMethodManager(mFindText).hideSoftInputFromWindow(mFindText.getWindowToken(), 0); break; case R.id.find_close: hide(); break; } }
@Override public void requestZoomedViewRender() { if (stopUpdateView) { return; } // remove pending runnable ThreadUtils.removeCallbacksFromUiThread(requestRenderRunnable); // "requestZoomedViewRender" can be called very often by Gecko (endDrawing in LayerRender) // without // any thing changed in the zoomed area (useless calls from the "zoomed area" point of view). // "requestZoomedViewRender" can take time to re-render the zoomed view, it depends of the // complexity // of the html on this area. // To avoid to slow down the application, the 2 following cases are tested: // 1- Last render is still running, plan another render later. if (isRendering()) { // post a new runnable DELAY_BEFORE_NEXT_RENDER_REQUEST_MS later // We need to post with a delay to be sure that the last call to requestZoomedViewRender will // be done. // For a static html page WITHOUT any animation/video, there is a last call to endDrawing and // we need to make // the zoomed render on this last call. ThreadUtils.postDelayedToUiThread(requestRenderRunnable, DELAY_BEFORE_NEXT_RENDER_REQUEST_MS); return; } // 2- Current render occurs too early, plan another render later. if (renderFrequencyTooHigh()) { // post a new runnable DELAY_BEFORE_NEXT_RENDER_REQUEST_MS later // We need to post with a delay to be sure that the last call to requestZoomedViewRender will // be done. // For a page WITH animation/video, the animation/video can be stopped, and we need to make // the zoomed render on this last call. ThreadUtils.postDelayedToUiThread(requestRenderRunnable, DELAY_BEFORE_NEXT_RENDER_REQUEST_MS); return; } startTimeReRender = System.nanoTime(); // Allocate the buffer if it's the first call. // Change the buffer size if it's not the right size. updateBufferSize(); int tabId = Tabs.getInstance().getSelectedTab().getId(); ImmutableViewportMetrics metrics = layerView.getViewportMetrics(); PointF origin = metrics.getOrigin(); final int xPos = (int) origin.x + lastPosition.x; final int yPos = (int) origin.y + lastPosition.y; GeckoEvent e = GeckoEvent.createZoomedViewEvent( tabId, xPos, yPos, viewWidth, viewHeight, zoomFactor * metrics.zoomFactor, buffer); GeckoAppShell.sendEventToGecko(e); }
public AllPagesTab(Context context) { super(context); mSearchEngines = new ArrayList<SearchEngine>(); registerEventListener("SearchEngines:Data"); GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("SearchEngines:Get", null)); mHandler = new AllPagesHandler(); }
/** * Handle a confirmation response from the user. * * @param value String value to return to the browser context. */ public void confirmWithValue(String value) { JSONObject result = makeResult(RESULT_OK); try { result.put("textbox0", value); } catch (JSONException ex) { } GeckoAppShell.sendEventToGecko( GeckoEvent.createBroadcastEvent("Prompt:Reply", result.toString())); }
public void finishDialog(String aReturn) { mInputs = null; mButtons = null; mDialog = null; mSelected = null; mPromptQueue.offer(aReturn); // poke the Gecko thread in case it's waiting for new events GeckoAppShell.sendEventToGecko(GeckoEvent.createNoOpEvent()); }
@Override protected void onNewIntent(Intent intent) { if (checkLaunchState(LaunchState.GeckoExiting)) { // We're exiting and shouldn't try to do anything else just incase // we're hung for some reason we'll force the process to exit System.exit(0); return; } final String action = intent.getAction(); if (ACTION_DEBUG.equals(action) && checkAndSetLaunchState(LaunchState.Launching, LaunchState.WaitForDebugger)) { mMainHandler.postDelayed( new Runnable() { public void run() { Log.i(LOG_FILE_NAME, "Launching from debug intent after 5s wait"); setLaunchState(LaunchState.Launching); launch(null); } }, 1000 * 5 /* 5 seconds */); Log.i(LOG_FILE_NAME, "Intent : ACTION_DEBUG - waiting 5s before launching"); return; } if (checkLaunchState(LaunchState.WaitForDebugger) || launch(intent)) return; if (Intent.ACTION_MAIN.equals(action)) { Log.i(LOG_FILE_NAME, "Intent : ACTION_MAIN"); GeckoAppShell.sendEventToGecko(new GeckoEvent("")); } else if (Intent.ACTION_VIEW.equals(action)) { String uri = intent.getDataString(); GeckoAppShell.sendEventToGecko(new GeckoEvent(uri)); Log.i(LOG_FILE_NAME, "onNewIntent: " + uri); } else if (ACTION_WEBAPP.equals(action)) { String uri = intent.getStringExtra("args"); GeckoAppShell.sendEventToGecko(new GeckoEvent(uri)); Log.i(LOG_FILE_NAME, "Intent : WEBAPP - " + uri); } else if (ACTION_BOOKMARK.equals(action)) { String args = intent.getStringExtra("args"); GeckoAppShell.sendEventToGecko(new GeckoEvent(args)); Log.i(LOG_FILE_NAME, "Intent : BOOKMARK - " + args); } }
protected void onActivityResume(GeckoActivityStatus activity) { if (mPausedGecko) { GeckoAppShell.sendEventToGecko(GeckoEvent.createAppForegroundingEvent()); mPausedGecko = false; } GeckoConnectivityReceiver.getInstance().start(); GeckoNetworkManager.getInstance().start(); mInBackground = false; }
public void handleNotificationIntent(Intent i) { final Uri data = i.getData(); if (data == null) { Log.e(LOGTAG, "handleNotificationEvent: empty data"); return; } final String id = data.getQueryParameter(ID_ATTR); final String notificationType = data.getQueryParameter(EVENT_TYPE_ATTR); if (id == null || notificationType == null) { Log.e(LOGTAG, "handleNotificationEvent: invalid intent parameters"); return; } // In case the user swiped out the notification, we empty the id set. if (CLEARED_EVENT.equals(notificationType)) { mClearableNotifications.remove(id); // If Gecko isn't running, we throw away events where the notification was cancelled. // i.e. Don't bug the user if they're just closing a bunch of notifications. if (!GeckoThread.checkLaunchState(GeckoThread.LaunchState.GeckoRunning)) { return; } } JSONObject args = new JSONObject(); // The handler and cookie parameters are optional final String handler = data.getQueryParameter(HANDLER_ATTR); final String cookie = i.getStringExtra(COOKIE_ATTR); try { args.put(ID_ATTR, id); args.put(EVENT_TYPE_ATTR, notificationType); args.put(HANDLER_ATTR, handler); args.put(COOKIE_ATTR, cookie); if (BUTTON_EVENT.equals(notificationType)) { final String actionName = data.getQueryParameter(ACTION_ID_ATTR); args.put(ACTION_ID_ATTR, actionName); } Log.i(LOGTAG, "Send " + args.toString()); GeckoAppShell.sendEventToGecko( GeckoEvent.createBroadcastEvent("Notification:Event", args.toString())); } catch (JSONException e) { Log.e(LOGTAG, "Error building JSON notification arguments.", e); } // If the notification was clicked, we are closing it. This must be executed after // sending the event to js side because when the notification is canceled no event can be // handled. if (CLICK_EVENT.equals(notificationType) && !i.getBooleanExtra(ONGOING_ATTR, false)) { hideNotification(id, handler, cookie); } }
private void updateNetworkType() { NetworkType previousNetworkType = mNetworkType; mNetworkType = getNetworkType(); if (mNetworkType == previousNetworkType || !mShouldNotify) { return; } GeckoAppShell.sendEventToGecko( GeckoEvent.createNetworkEvent( getNetworkSpeed(mNetworkType), isNetworkUsuallyMetered(mNetworkType))); }
@Override public boolean onActionItemClicked(ActionModeCompat mode, MenuItem item) { try { final JSONObject obj = mItems.getJSONObject(item.getItemId()); GeckoAppShell.sendEventToGecko( GeckoEvent.createBroadcastEvent("TextSelection:Action", obj.optString("id"))); return true; } catch (Exception ex) { Log.i(LOGTAG, "Exception calling action", ex); } return false; }
/** * Load a URL resource into the Browser. * * @param url The URL string. */ public void loadUrl(String url) { JSONObject args = new JSONObject(); try { args.put("url", url); args.put("parentId", -1); args.put("newTab", false); args.put("tabID", mId); } catch (Exception e) { Log.w(LOGTAG, "Error building JSON arguments for loadUrl.", e); } GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Tab:Load", args.toString())); }
private void sendNotificationWasClosed(String id, String handlerKey, String cookie) { final JSONObject args = new JSONObject(); try { args.put(ID_ATTR, id); args.put(HANDLER_ATTR, handlerKey); args.put(COOKIE_ATTR, cookie); args.put(EVENT_TYPE_ATTR, CLOSED_EVENT); Log.i(LOGTAG, "Send " + args.toString()); GeckoAppShell.sendEventToGecko( GeckoEvent.createBroadcastEvent("Notification:Event", args.toString())); } catch (JSONException ex) { Log.e(LOGTAG, "sendNotificationWasClosed: error building JSON notification arguments.", ex); } }
@Override public boolean performContextMenuAction(int id) { final Editable content = getEditable(); if (content == null) return false; String text = content.toString(); clampSelection(); int a = Selection.getSelectionStart(content); int b = Selection.getSelectionEnd(content); switch (id) { case R.id.selectAll: setSelection(0, text.length()); break; case R.id.cut: // Fill the clipboard GeckoAppShell.setClipboardText(text); // If selection is empty, we'll select everything if (a >= b) GeckoAppShell.sendEventToGecko( GeckoEvent.createIMEEvent(GeckoEvent.IME_SET_SELECTION, 0, text.length())); GeckoAppShell.sendEventToGecko(GeckoEvent.createIMEEvent(GeckoEvent.IME_DELETE_TEXT, 0, 0)); break; case R.id.paste: commitText(GeckoAppShell.getClipboardText(), 1); break; case R.id.copy: // If there is no selection set, we must be doing "Copy All", // otherwise get the selection if (a < b) text = text.substring(a, b); GeckoAppShell.setClipboardText(text.substring(a, b)); break; } return true; }
@Override public void onPause() { Log.i(LOG_FILE_NAME, "pause"); GeckoAppShell.sendEventToGecko(new GeckoEvent(GeckoEvent.ACTIVITY_PAUSING)); // The user is navigating away from this activity, but nothing // has come to the foreground yet; for Gecko, we may want to // stop repainting, for example. // Whatever we do here should be fast, because we're blocking // the next activity from showing up until we finish. // onPause will be followed by either onResume or onStop. super.onPause(); unregisterReceiver(mConnectivityReceiver); GeckoNetworkManager.getInstance().stop(); GeckoScreenOrientationListener.getInstance().stop(); }
@Override public void onStop() { Log.i(LOG_FILE_NAME, "stop"); // We're about to be stopped, potentially in preparation for // being destroyed. We're killable after this point -- as I // understand it, in extreme cases the process can be terminated // without going through onDestroy. // // We might also get an onRestart after this; not sure what // that would mean for Gecko if we were to kill it here. // Instead, what we should do here is save prefs, session, // etc., and generally mark the profile as 'clean', and then // dirty it again if we get an onResume. GeckoAppShell.sendEventToGecko(new GeckoEvent(GeckoEvent.ACTIVITY_STOPPING)); super.onStop(); GeckoAppShell.putChildInBackground(); }
@Override public void onDestroy() { Log.i(LOG_FILE_NAME, "destroy"); // Tell Gecko to shutting down; we'll end up calling System.exit() // in onXreExit. if (isFinishing()) GeckoAppShell.sendEventToGecko(new GeckoEvent(GeckoEvent.ACTIVITY_SHUTDOWN)); if (SmsManager.getInstance() != null) { SmsManager.getInstance().stop(); if (isFinishing()) SmsManager.getInstance().shutdown(); } GeckoNetworkManager.getInstance().stop(); GeckoScreenOrientationListener.getInstance().stop(); super.onDestroy(); unregisterReceiver(mBatteryReceiver); }
private boolean synthesizeKeyEvents(char inputChar) { if (mKeyCharacterMap == null) { mKeyCharacterMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD); } // Synthesize VKB key events that could plausibly generate the input character. char[] inputChars = {inputChar}; KeyEvent[] events = mKeyCharacterMap.getEvents(inputChars); if (events == null) { if (DEBUG) { Log.d(LOGTAG, "synthesizeKeyEvents: char '" + inputChar + "' has no virtual key mapping"); } return false; } boolean sentKeyEvents = false; for (KeyEvent event : events) { if (!KeyEvent.isModifierKey(event.getKeyCode())) { if (DEBUG) { Log.d( LOGTAG, "synthesizeKeyEvents: char '" + inputChar + "' -> action=" + event.getAction() + ", keyCode=" + event.getKeyCode() + ", UnicodeChar='" + (char) event.getUnicodeChar() + "'"); } GeckoAppShell.sendEventToGecko(GeckoEvent.createKeyEvent(event)); sentKeyEvents = true; } } return sentKeyEvents; }
protected void onActivityPause(GeckoActivityStatus activity) { mInBackground = true; if ((activity.isFinishing() == false) && (activity.isGeckoActivityOpened() == false)) { // Notify Gecko that we are pausing; the cache service will be // shutdown, closing the disk cache cleanly. If the android // low memory killer subsequently kills us, the disk cache will // be left in a consistent state, avoiding costly cleanup and // re-creation. GeckoAppShell.sendEventToGecko(GeckoEvent.createAppBackgroundingEvent()); mPausedGecko = true; ThreadUtils.postToBackgroundThread( new Runnable() { @Override public void run() { BrowserDB.expireHistory(getContentResolver(), BrowserContract.ExpirePriority.NORMAL); } }); } GeckoConnectivityReceiver.getInstance().stop(); GeckoNetworkManager.getInstance().stop(); }
// send the Preferences:Set message to Gecko public static void setPreference(String pref, Object value) { if (pref == null || pref.length() == 0) return; try { JSONObject jsonPref = new JSONObject(); jsonPref.put("name", pref); if (value instanceof Boolean) { jsonPref.put("type", "bool"); jsonPref.put("value", ((Boolean) value).booleanValue()); } else if (value instanceof Integer) { jsonPref.put("type", "int"); jsonPref.put("value", ((Integer) value).intValue()); } else { jsonPref.put("type", "string"); jsonPref.put("value", String.valueOf(value)); } GeckoEvent event = GeckoEvent.createBroadcastEvent("Preferences:Set", jsonPref.toString()); GeckoAppShell.sendEventToGecko(event); } catch (JSONException e) { Log.e(LOGTAG, "JSON exception: ", e); } }
private void init(Context context, String url, boolean doInit) { // TODO: Fennec currently takes care of its own initialization, so this // flag is a hack used in Fennec to prevent GeckoView initialization. // This should go away once Fennec also uses GeckoView for // initialization. if (!doInit) return; // If running outside of a GeckoActivity (eg, from a library project), // load the native code and disable content providers boolean isGeckoActivity = false; try { isGeckoActivity = context instanceof GeckoActivity; } catch (NoClassDefFoundError ex) { } if (!isGeckoActivity) { // Set the GeckoInterface if the context is an activity and the GeckoInterface // has not already been set if (context instanceof Activity && getGeckoInterface() == null) { setGeckoInterface(new BaseGeckoInterface(context)); } Clipboard.init(context); HardwareUtils.init(context); // If you want to use GeckoNetworkManager, start it. GeckoLoader.loadMozGlue(); BrowserDB.setEnableContentProviders(false); } if (url != null) { GeckoThread.setUri(url); GeckoThread.setAction(Intent.ACTION_VIEW); GeckoAppShell.sendEventToGecko(GeckoEvent.createURILoadEvent(url)); } GeckoAppShell.setContextGetter(this); if (context instanceof Activity) { Tabs tabs = Tabs.getInstance(); tabs.attachToContext(context); } EventDispatcher.getInstance() .registerGeckoThreadListener( this, "Gecko:Ready", "Content:StateChange", "Content:LoadError", "Content:PageShow", "DOMTitleChanged", "Link:Favicon", "Prompt:Show", "Prompt:ShowTop"); ThreadUtils.setUiThread(Thread.currentThread(), new Handler()); initializeView(EventDispatcher.getInstance()); if (GeckoThread.checkAndSetLaunchState( GeckoThread.LaunchState.Launching, GeckoThread.LaunchState.Launched)) { // This is the first launch, so finish initialization and go. GeckoProfile profile = GeckoProfile.get(context).forceCreate(); BrowserDB.initialize(profile.getName()); GeckoAppShell.setLayerView(this); GeckoThread.createAndStart(); } else if (GeckoThread.checkLaunchState(GeckoThread.LaunchState.GeckoRunning)) { // If Gecko is already running, that means the Activity was // destroyed, so we need to re-attach Gecko to this GeckoView. connectToGecko(); } }
/** Handle a cancellation response from the user. */ public void cancel() { JSONObject result = makeResult(RESULT_CANCEL); GeckoAppShell.sendEventToGecko( GeckoEvent.createBroadcastEvent("Prompt:Reply", result.toString())); }
public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { GeckoAppShell.sendEventToGecko(GeckoEvent.createKeyEvent(event)); return true; }
private void sendTextToGecko(CharSequence text, int caretPos) { if (DEBUG) Log.d(LOGTAG, "IME: sendTextToGecko(\"" + text + "\")"); // Handle composition text styles if (text != null && text instanceof Spanned) { Spanned span = (Spanned) text; int spanStart = 0, spanEnd = 0; boolean pastSelStart = false, pastSelEnd = false; do { int rangeType = GeckoEvent.IME_RANGE_CONVERTEDTEXT; int rangeStyles = 0, rangeForeColor = 0, rangeBackColor = 0; // Find next offset where there is a style transition spanEnd = span.nextSpanTransition(spanStart + 1, text.length(), CharacterStyle.class); // Empty range, continue if (spanEnd <= spanStart) continue; // Get and iterate through list of span objects within range CharacterStyle[] styles = span.getSpans(spanStart, spanEnd, CharacterStyle.class); for (CharacterStyle style : styles) { if (style instanceof UnderlineSpan) { // Text should be underlined rangeStyles |= GeckoEvent.IME_RANGE_UNDERLINE; } else if (style instanceof ForegroundColorSpan) { // Text should be of a different foreground color rangeStyles |= GeckoEvent.IME_RANGE_FORECOLOR; rangeForeColor = ((ForegroundColorSpan) style).getForegroundColor(); } else if (style instanceof BackgroundColorSpan) { // Text should be of a different background color rangeStyles |= GeckoEvent.IME_RANGE_BACKCOLOR; rangeBackColor = ((BackgroundColorSpan) style).getBackgroundColor(); } } // Add range to array, the actual styles are // applied when IME_SET_TEXT is sent if (DEBUG) { Log.d( LOGTAG, String.format( ". . . sendTextToGecko: IME_ADD_RANGE, %d, %d, %d, %d, %d, %d", spanStart, spanEnd - spanStart, rangeType, rangeStyles, rangeForeColor, rangeBackColor)); } GeckoAppShell.sendEventToGecko( GeckoEvent.createIMERangeEvent( spanStart, spanEnd - spanStart, rangeType, rangeStyles, rangeForeColor, rangeBackColor)); spanStart = spanEnd; } while (spanStart < text.length()); } else { if (DEBUG) Log.d( LOGTAG, ". . . sendTextToGecko: IME_ADD_RANGE, 0, " + text.length() + ", IME_RANGE_RAWINPUT, IME_RANGE_UNDERLINE)"); GeckoAppShell.sendEventToGecko( GeckoEvent.createIMERangeEvent( 0, text == null ? 0 : text.length(), GeckoEvent.IME_RANGE_RAWINPUT, GeckoEvent.IME_RANGE_UNDERLINE, 0, 0)); } // Change composition (treating selection end as where the caret is) if (DEBUG) { Log.d( LOGTAG, ". . . sendTextToGecko: IME_SET_TEXT, IME_RANGE_CARETPOSITION, \"" + text + "\")"); } GeckoAppShell.sendEventToGecko( GeckoEvent.createIMERangeEvent( caretPos, 0, GeckoEvent.IME_RANGE_CARETPOSITION, 0, 0, 0, text.toString())); }
private void endComposition() { if (DEBUG) Log.d(LOGTAG, "IME: endComposition: IME_COMPOSITION_END"); GeckoAppShell.sendEventToGecko(GeckoEvent.createIMEEvent(GeckoEvent.IME_COMPOSITION_END, 0, 0)); mCompositionStart = NO_COMPOSITION_STRING; }