gecko/mobile/android/base/GeckoInputConnection.java

1121 lines
40 KiB
Java
Raw Normal View History

Bug 0 - Moving embedding/android into mobile/android/base. r=mfinkle,blassey --HG-- rename : embedding/android/AlertNotification.java => mobile/android/base/AlertNotification.java rename : embedding/android/AndroidManifest.xml.in => mobile/android/base/AndroidManifest.xml.in rename : embedding/android/App.java.in => mobile/android/base/App.java.in rename : embedding/android/AwesomeBar.java => mobile/android/base/AwesomeBar.java rename : embedding/android/AwesomeBarTabs.java => mobile/android/base/AwesomeBarTabs.java rename : embedding/android/BrowserToolbar.java => mobile/android/base/BrowserToolbar.java rename : embedding/android/ConfirmPreference.java => mobile/android/base/ConfirmPreference.java rename : embedding/android/CrashReporter.java.in => mobile/android/base/CrashReporter.java.in rename : embedding/android/DoorHanger.java => mobile/android/base/DoorHanger.java rename : embedding/android/DoorHangerPopup.java => mobile/android/base/DoorHangerPopup.java rename : embedding/android/Favicons.java => mobile/android/base/Favicons.java rename : embedding/android/GeckoApp.java => mobile/android/base/GeckoApp.java rename : embedding/android/GeckoAppShell.java => mobile/android/base/GeckoAppShell.java rename : embedding/android/GeckoAsyncTask.java => mobile/android/base/GeckoAsyncTask.java rename : embedding/android/GeckoBatteryManager.java => mobile/android/base/GeckoBatteryManager.java rename : embedding/android/GeckoConnectivityReceiver.java => mobile/android/base/GeckoConnectivityReceiver.java rename : embedding/android/GeckoEvent.java => mobile/android/base/GeckoEvent.java rename : embedding/android/GeckoEventListener.java => mobile/android/base/GeckoEventListener.java rename : embedding/android/GeckoInputConnection.java => mobile/android/base/GeckoInputConnection.java rename : embedding/android/GeckoPreferences.java => mobile/android/base/GeckoPreferences.java rename : embedding/android/GeckoStateListDrawable.java => mobile/android/base/GeckoStateListDrawable.java rename : embedding/android/GeckoThread.java => mobile/android/base/GeckoThread.java rename : embedding/android/GlobalHistory.java => mobile/android/base/GlobalHistory.java rename : embedding/android/LauncherShortcuts.java.in => mobile/android/base/LauncherShortcuts.java.in rename : embedding/android/Makefile.in => mobile/android/base/Makefile.in rename : embedding/android/NotificationHandler.java.in => mobile/android/base/NotificationHandler.java.in rename : embedding/android/PromptService.java => mobile/android/base/PromptService.java rename : embedding/android/Restarter.java.in => mobile/android/base/Restarter.java.in rename : embedding/android/SurfaceLockInfo.java => mobile/android/base/SurfaceLockInfo.java rename : embedding/android/Tab.java => mobile/android/base/Tab.java rename : embedding/android/Tabs.java => mobile/android/base/Tabs.java rename : embedding/android/TabsTray.java => mobile/android/base/TabsTray.java rename : embedding/android/gfx/BufferedCairoImage.java => mobile/android/base/gfx/BufferedCairoImage.java rename : embedding/android/gfx/CairoImage.java => mobile/android/base/gfx/CairoImage.java rename : embedding/android/gfx/CairoUtils.java => mobile/android/base/gfx/CairoUtils.java rename : embedding/android/gfx/GeckoSoftwareLayerClient.java => mobile/android/base/gfx/GeckoSoftwareLayerClient.java rename : embedding/android/gfx/InputConnectionHandler.java => mobile/android/base/gfx/InputConnectionHandler.java rename : embedding/android/gfx/IntSize.java => mobile/android/base/gfx/IntSize.java rename : embedding/android/gfx/Layer.java => mobile/android/base/gfx/Layer.java rename : embedding/android/gfx/LayerClient.java => mobile/android/base/gfx/LayerClient.java rename : embedding/android/gfx/LayerController.java => mobile/android/base/gfx/LayerController.java rename : embedding/android/gfx/LayerRenderer.java => mobile/android/base/gfx/LayerRenderer.java rename : embedding/android/gfx/LayerView.java => mobile/android/base/gfx/LayerView.java rename : embedding/android/gfx/NinePatchTileLayer.java => mobile/android/base/gfx/NinePatchTileLayer.java rename : embedding/android/gfx/PlaceholderLayerClient.java => mobile/android/base/gfx/PlaceholderLayerClient.java rename : embedding/android/gfx/PointUtils.java => mobile/android/base/gfx/PointUtils.java rename : embedding/android/gfx/RectUtils.java => mobile/android/base/gfx/RectUtils.java rename : embedding/android/gfx/SingleTileLayer.java => mobile/android/base/gfx/SingleTileLayer.java rename : embedding/android/gfx/TextLayer.java => mobile/android/base/gfx/TextLayer.java rename : embedding/android/gfx/TextureReaper.java => mobile/android/base/gfx/TextureReaper.java rename : embedding/android/gfx/TileLayer.java => mobile/android/base/gfx/TileLayer.java rename : embedding/android/locales/Makefile.in => mobile/android/base/locales/Makefile.in rename : embedding/android/locales/en-US/android_strings.dtd => mobile/android/base/locales/en-US/android_strings.dtd rename : embedding/android/locales/jar.mn => mobile/android/base/locales/jar.mn rename : embedding/android/locales/l10n.ini => mobile/android/base/locales/l10n.ini rename : embedding/android/package-name.txt.in => mobile/android/base/package-name.txt.in rename : embedding/android/resources/anim/grow_fade_in.xml => mobile/android/base/resources/anim/grow_fade_in.xml rename : embedding/android/resources/anim/shrink_fade_out.xml => mobile/android/base/resources/anim/shrink_fade_out.xml rename : embedding/android/resources/color/awesomebar_tab_text.xml => mobile/android/base/resources/color/awesomebar_tab_text.xml rename : embedding/android/resources/drawable-hdpi-v11/address_bar_url_bg.9.png => mobile/android/base/resources/drawable-hdpi-v11/address_bar_url_bg.9.png rename : embedding/android/resources/drawable-hdpi-v11/ic_menu_bookmark_add.png => mobile/android/base/resources/drawable-hdpi-v11/ic_menu_bookmark_add.png rename : embedding/android/resources/drawable-hdpi-v11/ic_menu_bookmark_remove.png => mobile/android/base/resources/drawable-hdpi-v11/ic_menu_bookmark_remove.png rename : embedding/android/resources/drawable-hdpi-v11/ic_menu_find_in_page.png => mobile/android/base/resources/drawable-hdpi-v11/ic_menu_find_in_page.png rename : embedding/android/resources/drawable-hdpi-v11/ic_menu_forward.png => mobile/android/base/resources/drawable-hdpi-v11/ic_menu_forward.png rename : embedding/android/resources/drawable-hdpi-v11/ic_menu_reload.png => mobile/android/base/resources/drawable-hdpi-v11/ic_menu_reload.png rename : embedding/android/resources/drawable-hdpi-v11/ic_menu_save_as_pdf.png => mobile/android/base/resources/drawable-hdpi-v11/ic_menu_save_as_pdf.png rename : embedding/android/resources/drawable-hdpi-v11/ic_menu_share.png => mobile/android/base/resources/drawable-hdpi-v11/ic_menu_share.png rename : embedding/android/resources/drawable-hdpi-v11/tabs_more.png => mobile/android/base/resources/drawable-hdpi-v11/tabs_more.png rename : embedding/android/resources/drawable-hdpi-v11/tabs_normal.png => mobile/android/base/resources/drawable-hdpi-v11/tabs_normal.png rename : embedding/android/resources/drawable-hdpi-v11/tabs_plus.png => mobile/android/base/resources/drawable-hdpi-v11/tabs_plus.png rename : embedding/android/resources/drawable-hdpi-v11/tabs_pressed.png => mobile/android/base/resources/drawable-hdpi-v11/tabs_pressed.png rename : embedding/android/resources/drawable-hdpi-v8/address_bar_url_bg.9.png => mobile/android/base/resources/drawable-hdpi-v8/address_bar_url_bg.9.png rename : embedding/android/resources/drawable-hdpi-v8/doorhanger_arrow.png => mobile/android/base/resources/drawable-hdpi-v8/doorhanger_arrow.png rename : embedding/android/resources/drawable-hdpi-v8/doorhanger_bg.9.png => mobile/android/base/resources/drawable-hdpi-v8/doorhanger_bg.9.png rename : embedding/android/resources/drawable-hdpi-v8/doorhanger_popup_bg.9.png => mobile/android/base/resources/drawable-hdpi-v8/doorhanger_popup_bg.9.png rename : embedding/android/resources/drawable-hdpi-v8/doorhanger_shadow_bg.9.png => mobile/android/base/resources/drawable-hdpi-v8/doorhanger_shadow_bg.9.png rename : embedding/android/resources/drawable-hdpi-v8/ic_menu_bookmark_add.png => mobile/android/base/resources/drawable-hdpi-v8/ic_menu_bookmark_add.png rename : embedding/android/resources/drawable-hdpi-v8/ic_menu_bookmark_remove.png => mobile/android/base/resources/drawable-hdpi-v8/ic_menu_bookmark_remove.png rename : embedding/android/resources/drawable-hdpi-v8/ic_menu_find_in_page.png => mobile/android/base/resources/drawable-hdpi-v8/ic_menu_find_in_page.png rename : embedding/android/resources/drawable-hdpi-v8/ic_menu_forward.png => mobile/android/base/resources/drawable-hdpi-v8/ic_menu_forward.png rename : embedding/android/resources/drawable-hdpi-v8/ic_menu_reload.png => mobile/android/base/resources/drawable-hdpi-v8/ic_menu_reload.png rename : embedding/android/resources/drawable-hdpi-v8/ic_menu_save_as_pdf.png => mobile/android/base/resources/drawable-hdpi-v8/ic_menu_save_as_pdf.png rename : embedding/android/resources/drawable-hdpi-v8/ic_menu_share.png => mobile/android/base/resources/drawable-hdpi-v8/ic_menu_share.png rename : embedding/android/resources/drawable-hdpi-v8/site_security_lock.png => mobile/android/base/resources/drawable-hdpi-v8/site_security_lock.png rename : embedding/android/resources/drawable-hdpi-v8/tabs_more.png => mobile/android/base/resources/drawable-hdpi-v8/tabs_more.png rename : embedding/android/resources/drawable-hdpi-v8/tabs_normal.png => mobile/android/base/resources/drawable-hdpi-v8/tabs_normal.png rename : embedding/android/resources/drawable-hdpi-v8/tabs_plus.png => mobile/android/base/resources/drawable-hdpi-v8/tabs_plus.png rename : embedding/android/resources/drawable-hdpi-v8/tabs_pressed.png => mobile/android/base/resources/drawable-hdpi-v8/tabs_pressed.png rename : embedding/android/resources/drawable-hdpi-v8/urlbar_stop.png => mobile/android/base/resources/drawable-hdpi-v8/urlbar_stop.png rename : embedding/android/resources/drawable-hdpi-v9/ic_menu_bookmark_add.png => mobile/android/base/resources/drawable-hdpi-v9/ic_menu_bookmark_add.png rename : embedding/android/resources/drawable-hdpi-v9/ic_menu_bookmark_remove.png => mobile/android/base/resources/drawable-hdpi-v9/ic_menu_bookmark_remove.png rename : embedding/android/resources/drawable-hdpi-v9/ic_menu_find_in_page.png => mobile/android/base/resources/drawable-hdpi-v9/ic_menu_find_in_page.png rename : embedding/android/resources/drawable-hdpi-v9/ic_menu_forward.png => mobile/android/base/resources/drawable-hdpi-v9/ic_menu_forward.png rename : embedding/android/resources/drawable-hdpi-v9/ic_menu_reload.png => mobile/android/base/resources/drawable-hdpi-v9/ic_menu_reload.png rename : embedding/android/resources/drawable-hdpi-v9/ic_menu_save_as_pdf.png => mobile/android/base/resources/drawable-hdpi-v9/ic_menu_save_as_pdf.png rename : embedding/android/resources/drawable-hdpi-v9/ic_menu_share.png => mobile/android/base/resources/drawable-hdpi-v9/ic_menu_share.png rename : embedding/android/resources/drawable-mdpi-v11/address_bar_url_bg.9.png => mobile/android/base/resources/drawable-mdpi-v11/address_bar_url_bg.9.png rename : embedding/android/resources/drawable-mdpi-v11/ic_menu_bookmark_add.png => mobile/android/base/resources/drawable-mdpi-v11/ic_menu_bookmark_add.png rename : embedding/android/resources/drawable-mdpi-v11/ic_menu_bookmark_remove.png => mobile/android/base/resources/drawable-mdpi-v11/ic_menu_bookmark_remove.png rename : embedding/android/resources/drawable-mdpi-v11/ic_menu_find_in_page.png => mobile/android/base/resources/drawable-mdpi-v11/ic_menu_find_in_page.png rename : embedding/android/resources/drawable-mdpi-v11/ic_menu_forward.png => mobile/android/base/resources/drawable-mdpi-v11/ic_menu_forward.png rename : embedding/android/resources/drawable-mdpi-v11/ic_menu_reload.png => mobile/android/base/resources/drawable-mdpi-v11/ic_menu_reload.png rename : embedding/android/resources/drawable-mdpi-v11/ic_menu_save_as_pdf.png => mobile/android/base/resources/drawable-mdpi-v11/ic_menu_save_as_pdf.png rename : embedding/android/resources/drawable-mdpi-v11/ic_menu_share.png => mobile/android/base/resources/drawable-mdpi-v11/ic_menu_share.png rename : embedding/android/resources/drawable-mdpi-v11/tabs_more.png => mobile/android/base/resources/drawable-mdpi-v11/tabs_more.png rename : embedding/android/resources/drawable-mdpi-v11/tabs_normal.png => mobile/android/base/resources/drawable-mdpi-v11/tabs_normal.png rename : embedding/android/resources/drawable-mdpi-v11/tabs_plus.png => mobile/android/base/resources/drawable-mdpi-v11/tabs_plus.png rename : embedding/android/resources/drawable-mdpi-v11/tabs_pressed.png => mobile/android/base/resources/drawable-mdpi-v11/tabs_pressed.png rename : embedding/android/resources/drawable-mdpi-v8/address_bar_url_bg.9.png => mobile/android/base/resources/drawable-mdpi-v8/address_bar_url_bg.9.png rename : embedding/android/resources/drawable-mdpi-v8/doorhanger_arrow.png => mobile/android/base/resources/drawable-mdpi-v8/doorhanger_arrow.png rename : embedding/android/resources/drawable-mdpi-v8/doorhanger_bg.9.png => mobile/android/base/resources/drawable-mdpi-v8/doorhanger_bg.9.png rename : embedding/android/resources/drawable-mdpi-v8/doorhanger_popup_bg.9.png => mobile/android/base/resources/drawable-mdpi-v8/doorhanger_popup_bg.9.png rename : embedding/android/resources/drawable-mdpi-v8/doorhanger_shadow_bg.9.png => mobile/android/base/resources/drawable-mdpi-v8/doorhanger_shadow_bg.9.png rename : embedding/android/resources/drawable-mdpi-v8/ic_menu_bookmark_add.png => mobile/android/base/resources/drawable-mdpi-v8/ic_menu_bookmark_add.png rename : embedding/android/resources/drawable-mdpi-v8/ic_menu_bookmark_remove.png => mobile/android/base/resources/drawable-mdpi-v8/ic_menu_bookmark_remove.png rename : embedding/android/resources/drawable-mdpi-v8/ic_menu_find_in_page.png => mobile/android/base/resources/drawable-mdpi-v8/ic_menu_find_in_page.png rename : embedding/android/resources/drawable-mdpi-v8/ic_menu_forward.png => mobile/android/base/resources/drawable-mdpi-v8/ic_menu_forward.png rename : embedding/android/resources/drawable-mdpi-v8/ic_menu_reload.png => mobile/android/base/resources/drawable-mdpi-v8/ic_menu_reload.png rename : embedding/android/resources/drawable-mdpi-v8/ic_menu_save_as_pdf.png => mobile/android/base/resources/drawable-mdpi-v8/ic_menu_save_as_pdf.png rename : embedding/android/resources/drawable-mdpi-v8/ic_menu_share.png => mobile/android/base/resources/drawable-mdpi-v8/ic_menu_share.png rename : embedding/android/resources/drawable-mdpi-v8/site_security_lock.png => mobile/android/base/resources/drawable-mdpi-v8/site_security_lock.png rename : embedding/android/resources/drawable-mdpi-v8/tabs_more.png => mobile/android/base/resources/drawable-mdpi-v8/tabs_more.png rename : embedding/android/resources/drawable-mdpi-v8/tabs_normal.png => mobile/android/base/resources/drawable-mdpi-v8/tabs_normal.png rename : embedding/android/resources/drawable-mdpi-v8/tabs_plus.png => mobile/android/base/resources/drawable-mdpi-v8/tabs_plus.png rename : embedding/android/resources/drawable-mdpi-v8/tabs_pressed.png => mobile/android/base/resources/drawable-mdpi-v8/tabs_pressed.png rename : embedding/android/resources/drawable-mdpi-v8/urlbar_stop.png => mobile/android/base/resources/drawable-mdpi-v8/urlbar_stop.png rename : embedding/android/resources/drawable-mdpi-v9/ic_menu_bookmark_add.png => mobile/android/base/resources/drawable-mdpi-v9/ic_menu_bookmark_add.png rename : embedding/android/resources/drawable-mdpi-v9/ic_menu_bookmark_remove.png => mobile/android/base/resources/drawable-mdpi-v9/ic_menu_bookmark_remove.png rename : embedding/android/resources/drawable-mdpi-v9/ic_menu_find_in_page.png => mobile/android/base/resources/drawable-mdpi-v9/ic_menu_find_in_page.png rename : embedding/android/resources/drawable-mdpi-v9/ic_menu_forward.png => mobile/android/base/resources/drawable-mdpi-v9/ic_menu_forward.png rename : embedding/android/resources/drawable-mdpi-v9/ic_menu_reload.png => mobile/android/base/resources/drawable-mdpi-v9/ic_menu_reload.png rename : embedding/android/resources/drawable-mdpi-v9/ic_menu_save_as_pdf.png => mobile/android/base/resources/drawable-mdpi-v9/ic_menu_save_as_pdf.png rename : embedding/android/resources/drawable-mdpi-v9/ic_menu_share.png => mobile/android/base/resources/drawable-mdpi-v9/ic_menu_share.png rename : embedding/android/resources/drawable-xhdpi-v11/address_bar_url_bg.9.png => mobile/android/base/resources/drawable-xhdpi-v11/address_bar_url_bg.9.png rename : embedding/android/resources/drawable-xhdpi-v11/ic_menu_bookmark_add.png => mobile/android/base/resources/drawable-xhdpi-v11/ic_menu_bookmark_add.png rename : embedding/android/resources/drawable-xhdpi-v11/ic_menu_bookmark_remove.png => mobile/android/base/resources/drawable-xhdpi-v11/ic_menu_bookmark_remove.png rename : embedding/android/resources/drawable-xhdpi-v11/ic_menu_find_in_page.png => mobile/android/base/resources/drawable-xhdpi-v11/ic_menu_find_in_page.png rename : embedding/android/resources/drawable-xhdpi-v11/ic_menu_foward.png => mobile/android/base/resources/drawable-xhdpi-v11/ic_menu_foward.png rename : embedding/android/resources/drawable-xhdpi-v11/ic_menu_reload.png => mobile/android/base/resources/drawable-xhdpi-v11/ic_menu_reload.png rename : embedding/android/resources/drawable-xhdpi-v11/ic_menu_save_as_pdf.png => mobile/android/base/resources/drawable-xhdpi-v11/ic_menu_save_as_pdf.png rename : embedding/android/resources/drawable-xhdpi-v11/ic_menu_share.png => mobile/android/base/resources/drawable-xhdpi-v11/ic_menu_share.png rename : embedding/android/resources/drawable-xhdpi-v11/tabs_more.png => mobile/android/base/resources/drawable-xhdpi-v11/tabs_more.png rename : embedding/android/resources/drawable-xhdpi-v11/tabs_normal.png => mobile/android/base/resources/drawable-xhdpi-v11/tabs_normal.png rename : embedding/android/resources/drawable-xhdpi-v11/tabs_plus.png => mobile/android/base/resources/drawable-xhdpi-v11/tabs_plus.png rename : embedding/android/resources/drawable-xhdpi-v11/tabs_pressed.png => mobile/android/base/resources/drawable-xhdpi-v11/tabs_pressed.png rename : embedding/android/resources/drawable/address_bar_bg.xml => mobile/android/base/resources/drawable/address_bar_bg.xml rename : embedding/android/resources/drawable/address_bar_url_default.xml => mobile/android/base/resources/drawable/address_bar_url_default.xml rename : embedding/android/resources/drawable/address_bar_url_pressed.xml => mobile/android/base/resources/drawable/address_bar_url_pressed.xml rename : embedding/android/resources/drawable/awesomebar_tab_focus.xml => mobile/android/base/resources/drawable/awesomebar_tab_focus.xml rename : embedding/android/resources/drawable/awesomebar_tab_focus_selected.xml => mobile/android/base/resources/drawable/awesomebar_tab_focus_selected.xml rename : embedding/android/resources/drawable/awesomebar_tab_indicator.xml => mobile/android/base/resources/drawable/awesomebar_tab_indicator.xml rename : embedding/android/resources/drawable/awesomebar_tab_press.xml => mobile/android/base/resources/drawable/awesomebar_tab_press.xml rename : embedding/android/resources/drawable/awesomebar_tab_press_selected.xml => mobile/android/base/resources/drawable/awesomebar_tab_press_selected.xml rename : embedding/android/resources/drawable/awesomebar_tab_selected.xml => mobile/android/base/resources/drawable/awesomebar_tab_selected.xml rename : embedding/android/resources/drawable/awesomebar_tab_unselected.xml => mobile/android/base/resources/drawable/awesomebar_tab_unselected.xml rename : embedding/android/resources/drawable/checkerboard.png => mobile/android/base/resources/drawable/checkerboard.png rename : embedding/android/resources/drawable/crash_reporter.png => mobile/android/base/resources/drawable/crash_reporter.png rename : embedding/android/resources/drawable/desktop_notification.png => mobile/android/base/resources/drawable/desktop_notification.png rename : embedding/android/resources/drawable/favicon.png => mobile/android/base/resources/drawable/favicon.png rename : embedding/android/resources/drawable/progress_spinner.xml => mobile/android/base/resources/drawable/progress_spinner.xml rename : embedding/android/resources/drawable/progress_spinner_1.png => mobile/android/base/resources/drawable/progress_spinner_1.png rename : embedding/android/resources/drawable/progress_spinner_10.png => mobile/android/base/resources/drawable/progress_spinner_10.png rename : embedding/android/resources/drawable/progress_spinner_11.png => mobile/android/base/resources/drawable/progress_spinner_11.png rename : embedding/android/resources/drawable/progress_spinner_12.png => mobile/android/base/resources/drawable/progress_spinner_12.png rename : embedding/android/resources/drawable/progress_spinner_13.png => mobile/android/base/resources/drawable/progress_spinner_13.png rename : embedding/android/resources/drawable/progress_spinner_14.png => mobile/android/base/resources/drawable/progress_spinner_14.png rename : embedding/android/resources/drawable/progress_spinner_15.png => mobile/android/base/resources/drawable/progress_spinner_15.png rename : embedding/android/resources/drawable/progress_spinner_16.png => mobile/android/base/resources/drawable/progress_spinner_16.png rename : embedding/android/resources/drawable/progress_spinner_17.png => mobile/android/base/resources/drawable/progress_spinner_17.png rename : embedding/android/resources/drawable/progress_spinner_18.png => mobile/android/base/resources/drawable/progress_spinner_18.png rename : embedding/android/resources/drawable/progress_spinner_2.png => mobile/android/base/resources/drawable/progress_spinner_2.png rename : embedding/android/resources/drawable/progress_spinner_3.png => mobile/android/base/resources/drawable/progress_spinner_3.png rename : embedding/android/resources/drawable/progress_spinner_4.png => mobile/android/base/resources/drawable/progress_spinner_4.png rename : embedding/android/resources/drawable/progress_spinner_5.png => mobile/android/base/resources/drawable/progress_spinner_5.png rename : embedding/android/resources/drawable/progress_spinner_6.png => mobile/android/base/resources/drawable/progress_spinner_6.png rename : embedding/android/resources/drawable/progress_spinner_7.png => mobile/android/base/resources/drawable/progress_spinner_7.png rename : embedding/android/resources/drawable/progress_spinner_8.png => mobile/android/base/resources/drawable/progress_spinner_8.png rename : embedding/android/resources/drawable/progress_spinner_9.png => mobile/android/base/resources/drawable/progress_spinner_9.png rename : embedding/android/resources/drawable/shadow.png => mobile/android/base/resources/drawable/shadow.png rename : embedding/android/resources/drawable/site_security_level.xml => mobile/android/base/resources/drawable/site_security_level.xml rename : embedding/android/resources/drawable/start.png => mobile/android/base/resources/drawable/start.png rename : embedding/android/resources/drawable/tab_close.png => mobile/android/base/resources/drawable/tab_close.png rename : embedding/android/resources/drawable/tab_new.png => mobile/android/base/resources/drawable/tab_new.png rename : embedding/android/resources/drawable/tabs_button.xml => mobile/android/base/resources/drawable/tabs_button.xml rename : embedding/android/resources/drawable/tabs_level.xml => mobile/android/base/resources/drawable/tabs_level.xml rename : embedding/android/resources/drawable/tabs_tray_bg.9.png => mobile/android/base/resources/drawable/tabs_tray_bg.9.png rename : embedding/android/resources/layout/awesomebar_header_row.xml => mobile/android/base/resources/layout/awesomebar_header_row.xml rename : embedding/android/resources/layout/awesomebar_row.xml => mobile/android/base/resources/layout/awesomebar_row.xml rename : embedding/android/resources/layout/awesomebar_search.xml => mobile/android/base/resources/layout/awesomebar_search.xml rename : embedding/android/resources/layout/awesomebar_tab_indicator.xml => mobile/android/base/resources/layout/awesomebar_tab_indicator.xml rename : embedding/android/resources/layout/awesomebar_tabs.xml => mobile/android/base/resources/layout/awesomebar_tabs.xml rename : embedding/android/resources/layout/browser_toolbar.xml => mobile/android/base/resources/layout/browser_toolbar.xml rename : embedding/android/resources/layout/crash_reporter.xml => mobile/android/base/resources/layout/crash_reporter.xml rename : embedding/android/resources/layout/doorhanger.xml => mobile/android/base/resources/layout/doorhanger.xml rename : embedding/android/resources/layout/doorhangerpopup.xml => mobile/android/base/resources/layout/doorhangerpopup.xml rename : embedding/android/resources/layout/gecko_app.xml => mobile/android/base/resources/layout/gecko_app.xml rename : embedding/android/resources/layout/gecko_menu.xml => mobile/android/base/resources/layout/gecko_menu.xml rename : embedding/android/resources/layout/launch_app_list.xml => mobile/android/base/resources/layout/launch_app_list.xml rename : embedding/android/resources/layout/launch_app_listitem.xml => mobile/android/base/resources/layout/launch_app_listitem.xml rename : embedding/android/resources/layout/list_item_header.xml => mobile/android/base/resources/layout/list_item_header.xml rename : embedding/android/resources/layout/notification_icon_text.xml => mobile/android/base/resources/layout/notification_icon_text.xml rename : embedding/android/resources/layout/notification_progress.xml => mobile/android/base/resources/layout/notification_progress.xml rename : embedding/android/resources/layout/notification_progress_text.xml => mobile/android/base/resources/layout/notification_progress_text.xml rename : embedding/android/resources/layout/select_dialog_list.xml => mobile/android/base/resources/layout/select_dialog_list.xml rename : embedding/android/resources/layout/tabs_row.xml => mobile/android/base/resources/layout/tabs_row.xml rename : embedding/android/resources/layout/tabs_tray.xml => mobile/android/base/resources/layout/tabs_tray.xml rename : embedding/android/resources/values/arrays.xml => mobile/android/base/resources/values/arrays.xml rename : embedding/android/resources/values/colors.xml => mobile/android/base/resources/values/colors.xml rename : embedding/android/resources/values/styles.xml => mobile/android/base/resources/values/styles.xml rename : embedding/android/resources/values/themes.xml => mobile/android/base/resources/values/themes.xml rename : embedding/android/resources/xml/preferences.xml => mobile/android/base/resources/xml/preferences.xml rename : embedding/android/strings.xml.in => mobile/android/base/strings.xml.in rename : embedding/android/ui/PanZoomController.java => mobile/android/base/ui/PanZoomController.java rename : embedding/android/ui/ViewportController.java => mobile/android/base/ui/ViewportController.java
2011-11-18 10:28:17 -08:00
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Android code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Michael Wu <mwu@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package org.mozilla.gecko;
import java.io.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import org.mozilla.gecko.gfx.InputConnectionHandler;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.os.*;
import android.app.*;
import android.text.*;
import android.text.style.*;
import android.view.*;
import android.view.inputmethod.*;
import android.content.*;
import android.R;
import android.text.method.TextKeyListener;
import android.text.method.KeyListener;
import android.util.*;
public class GeckoInputConnection
extends BaseInputConnection
implements TextWatcher, InputConnectionHandler
{
private static final String LOGTAG = "GeckoInputConnection";
private class ChangeNotification {
public String mText;
public int mStart;
public int mEnd;
public int mNewEnd;
ChangeNotification(String text, int start, int oldEnd, int newEnd) {
mText = text;
mStart = start;
mEnd = oldEnd;
mNewEnd = newEnd;
}
ChangeNotification(int start, int end) {
mText = null;
mStart = start;
mEnd = end;
mNewEnd = 0;
}
}
public GeckoInputConnection (View targetView) {
super(targetView, true);
mQueryResult = new SynchronousQueue<String>();
mEditableFactory = Editable.Factory.getInstance();
initEditable("");
mIMEState = IME_STATE_DISABLED;
mIMETypeHint = "";
mIMEActionHint = "";
}
@Override
public boolean beginBatchEdit() {
Log.d(LOGTAG, "IME: beginBatchEdit");
mBatchMode = true;
return true;
}
@Override
public boolean commitCompletion(CompletionInfo text) {
Log.d(LOGTAG, "IME: commitCompletion");
return commitText(text.getText(), 1);
}
@Override
public boolean commitText(CharSequence text, int newCursorPosition) {
Log.d(LOGTAG, "IME: commitText");
setComposingText(text, newCursorPosition);
finishComposingText();
return true;
}
@Override
public boolean deleteSurroundingText(int leftLength, int rightLength) {
Log.d(LOGTAG, "IME: deleteSurroundingText");
if (leftLength == 0 && rightLength == 0)
return true;
/* deleteSurroundingText is supposed to ignore the composing text,
so we cancel any pending composition, delete the text, and then
restart the composition */
if (mComposing) {
// Cancel current composition
GeckoAppShell.sendEventToGecko(
new GeckoEvent(0, 0, 0, 0, 0, 0, null));
GeckoAppShell.sendEventToGecko(
new GeckoEvent(GeckoEvent.IME_COMPOSITION_END, 0, 0));
}
// Select text to be deleted
int delStart, delLen;
GeckoAppShell.sendEventToGecko(
new GeckoEvent(GeckoEvent.IME_GET_SELECTION, 0, 0));
try {
mQueryResult.take();
} catch (InterruptedException e) {
Log.e(LOGTAG, "IME: deleteSurroundingText interrupted", e);
return false;
}
delStart = mSelectionStart > leftLength ?
mSelectionStart - leftLength : 0;
delLen = mSelectionStart + rightLength - delStart;
GeckoAppShell.sendEventToGecko(
new GeckoEvent(GeckoEvent.IME_SET_SELECTION, delStart, delLen));
// Restore composition / delete text
if (mComposing) {
GeckoAppShell.sendEventToGecko(
new GeckoEvent(GeckoEvent.IME_COMPOSITION_BEGIN, 0, 0));
if (mComposingText.length() > 0) {
/* IME_SET_TEXT doesn't work well with empty strings */
GeckoAppShell.sendEventToGecko(
new GeckoEvent(0, mComposingText.length(),
GeckoEvent.IME_RANGE_RAWINPUT,
GeckoEvent.IME_RANGE_UNDERLINE, 0, 0,
mComposingText.toString()));
}
} else {
GeckoAppShell.sendEventToGecko(
new GeckoEvent(GeckoEvent.IME_DELETE_TEXT, 0, 0));
}
// Temporarily disable text change notifications which confuse some IMEs (SlideIT, for example)
// in the middle of text update.
// They will be re-enabled on the next setComposingText
disableChangeNotifications();
return true;
}
@Override
public boolean endBatchEdit() {
Log.d(LOGTAG, "IME: endBatchEdit");
mBatchMode = false;
if (!mBatchChanges.isEmpty()) {
InputMethodManager imm = (InputMethodManager)
GeckoApp.mAppContext.getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
for (ChangeNotification n : mBatchChanges) {
if (n.mText != null)
notifyTextChange(imm, n.mText, n.mStart, n.mEnd, n.mNewEnd);
else
notifySelectionChange(imm, n.mStart, n.mEnd);
}
}
mBatchChanges.clear();
}
return true;
}
@Override
public boolean finishComposingText() {
Log.d(LOGTAG, "IME: finishComposingText");
if (mComposing) {
// Set style to none
GeckoAppShell.sendEventToGecko(
new GeckoEvent(0, mComposingText.length(),
GeckoEvent.IME_RANGE_RAWINPUT, 0, 0, 0,
mComposingText));
GeckoAppShell.sendEventToGecko(
new GeckoEvent(GeckoEvent.IME_COMPOSITION_END, 0, 0));
mComposing = false;
mComposingText = "";
if (!mBatchMode) {
// Make sure caret stays at the same position
GeckoAppShell.sendEventToGecko(
new GeckoEvent(GeckoEvent.IME_SET_SELECTION,
mCompositionStart + mCompositionSelStart, 0));
}
}
return true;
}
@Override
public int getCursorCapsMode(int reqModes) {
Log.d(LOGTAG, "IME: getCursorCapsMode");
return 0;
}
@Override
public Editable getEditable() {
Log.w(LOGTAG, "IME: getEditable called from " +
Thread.currentThread().getStackTrace()[0].toString());
return null;
}
@Override
public boolean performContextMenuAction(int id) {
Log.d(LOGTAG, "IME: performContextMenuAction");
// First we need to ask Gecko to tell us the full contents of the
// text field we're about to operate on.
String text;
GeckoAppShell.sendEventToGecko(
new GeckoEvent(GeckoEvent.IME_GET_TEXT, 0, Integer.MAX_VALUE));
try {
text = mQueryResult.take();
} catch (InterruptedException e) {
Log.e(LOGTAG, "IME: performContextMenuAction interrupted", e);
return false;
}
switch (id) {
case R.id.selectAll:
setSelection(0, text.length());
break;
case R.id.cut:
// Fill the clipboard
GeckoAppShell.setClipboardText(text);
// If GET_TEXT returned an empty selection, we'll select everything
if (mSelectionLength <= 0)
GeckoAppShell.sendEventToGecko(
new GeckoEvent(GeckoEvent.IME_SET_SELECTION, 0, text.length()));
GeckoAppShell.sendEventToGecko(
new GeckoEvent(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, we need to get the selection from Gecko
if (mSelectionLength > 0) {
GeckoAppShell.sendEventToGecko(
new GeckoEvent(GeckoEvent.IME_GET_SELECTION, 0, 0));
try {
text = mQueryResult.take();
} catch (InterruptedException e) {
Log.e(LOGTAG, "IME: performContextMenuAction interrupted", e);
return false;
}
}
GeckoAppShell.setClipboardText(text);
break;
}
return true;
}
@Override
public ExtractedText getExtractedText(ExtractedTextRequest req, int flags) {
if (req == null)
return null;
// Bail out here if gecko isn't running, otherwise we deadlock
// below when waiting for the reply to IME_GET_SELECTION.
if (!GeckoApp.checkLaunchState(GeckoApp.LaunchState.GeckoRunning))
return null;
Log.d(LOGTAG, "IME: getExtractedText");
ExtractedText extract = new ExtractedText();
extract.flags = 0;
extract.partialStartOffset = -1;
extract.partialEndOffset = -1;
GeckoAppShell.sendEventToGecko(
new GeckoEvent(GeckoEvent.IME_GET_SELECTION, 0, 0));
try {
mQueryResult.take();
} catch (InterruptedException e) {
Log.e(LOGTAG, "IME: getExtractedText interrupted", e);
return null;
}
extract.selectionStart = mSelectionStart;
extract.selectionEnd = mSelectionStart + mSelectionLength;
// bug 617298 - IME_GET_TEXT sometimes gives the wrong result due to
// a stale cache. Use a set of three workarounds:
// 1. Sleep for 20 milliseconds and hope the child updates us with the new text.
// Very evil and, consequentially, most effective.
try {
Thread.sleep(20);
} catch (InterruptedException e) {}
GeckoAppShell.sendEventToGecko(
new GeckoEvent(GeckoEvent.IME_GET_TEXT, 0, Integer.MAX_VALUE));
try {
extract.startOffset = 0;
extract.text = mQueryResult.take();
// 2. Make a guess about what the text actually is
if (mComposing && extract.selectionEnd > extract.text.length())
extract.text = extract.text.subSequence(0, Math.min(extract.text.length(), mCompositionStart)) + mComposingText;
// 3. If all else fails, make sure our selection indexes make sense
extract.selectionStart = Math.min(extract.selectionStart, extract.text.length());
extract.selectionEnd = Math.min(extract.selectionEnd, extract.text.length());
if ((flags & GET_EXTRACTED_TEXT_MONITOR) != 0)
mUpdateRequest = req;
return extract;
} catch (InterruptedException e) {
Log.e(LOGTAG, "IME: getExtractedText interrupted", e);
return null;
}
}
@Override
public CharSequence getTextAfterCursor(int length, int flags) {
Log.d(LOGTAG, "IME: getTextAfterCursor");
GeckoAppShell.sendEventToGecko(
new GeckoEvent(GeckoEvent.IME_GET_SELECTION, 0, 0));
try {
mQueryResult.take();
} catch (InterruptedException e) {
Log.e(LOGTAG, "IME: getTextBefore/AfterCursor interrupted", e);
return null;
}
/* Compatible with both positive and negative length
(no need for separate code for getTextBeforeCursor) */
int textStart = mSelectionStart;
int textLength = length;
if (length < 0) {
textStart += length;
textLength = -length;
if (textStart < 0) {
textStart = 0;
textLength = mSelectionStart;
}
}
GeckoAppShell.sendEventToGecko(
new GeckoEvent(GeckoEvent.IME_GET_TEXT, textStart, textLength));
try {
return mQueryResult.take();
} catch (InterruptedException e) {
Log.e(LOGTAG, "IME: getTextBefore/AfterCursor: Interrupted!", e);
return null;
}
}
@Override
public CharSequence getTextBeforeCursor(int length, int flags) {
Log.d(LOGTAG, "IME: getTextBeforeCursor");
return getTextAfterCursor(-length, flags);
}
@Override
public boolean setComposingText(CharSequence text, int newCursorPosition) {
Log.d(LOGTAG, "IME: setComposingText");
enableChangeNotifications();
// Set new composing text
mComposingText = text != null ? text.toString() : "";
if (!mComposing) {
// Get current selection
GeckoAppShell.sendEventToGecko(
new GeckoEvent(GeckoEvent.IME_GET_SELECTION, 0, 0));
try {
mQueryResult.take();
} catch (InterruptedException e) {
Log.e(LOGTAG, "IME: setComposingText interrupted", e);
return false;
}
if (mComposingText.length() == 0) {
// Empty composing text is usually sent by IME to delete the selection (for example, ezKeyboard)
if (mSelectionLength > 0)
GeckoAppShell.sendEventToGecko(new GeckoEvent(GeckoEvent.IME_DELETE_TEXT, 0, 0));
// Some IMEs such as iWnn sometimes call with empty composing
// text. (See bug 664364)
// If composing text is empty, ignore this and don't start
// compositing.
return true;
}
// Make sure we are in a composition
GeckoAppShell.sendEventToGecko(
new GeckoEvent(GeckoEvent.IME_COMPOSITION_BEGIN, 0, 0));
mComposing = true;
mCompositionStart = mSelectionLength >= 0 ?
mSelectionStart : mSelectionStart + mSelectionLength;
}
// Set new selection
// New selection should be within the composition
mCompositionSelStart = newCursorPosition > 0 ? mComposingText.length() : 0;
mCompositionSelLen = 0;
// 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);
// We need to count the selection as a transition
if (mCompositionSelLen >= 0) {
if (!pastSelStart && spanEnd >= mCompositionSelStart) {
spanEnd = mCompositionSelStart;
pastSelStart = true;
} else if (!pastSelEnd && spanEnd >=
mCompositionSelStart + mCompositionSelLen) {
spanEnd = mCompositionSelStart + mCompositionSelLen;
pastSelEnd = true;
rangeType = GeckoEvent.IME_RANGE_SELECTEDRAWTEXT;
}
} else {
if (!pastSelEnd && spanEnd >=
mCompositionSelStart + mCompositionSelLen) {
spanEnd = mCompositionSelStart + mCompositionSelLen;
pastSelEnd = true;
} else if (!pastSelStart &&
spanEnd >= mCompositionSelStart) {
spanEnd = mCompositionSelStart;
pastSelStart = true;
rangeType = GeckoEvent.IME_RANGE_SELECTEDRAWTEXT;
}
}
// 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
GeckoAppShell.sendEventToGecko(
new GeckoEvent(spanStart, spanEnd - spanStart,
rangeType, rangeStyles,
rangeForeColor, rangeBackColor));
spanStart = spanEnd;
} while (spanStart < text.length());
} else {
GeckoAppShell.sendEventToGecko(
new GeckoEvent(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)
GeckoAppShell.sendEventToGecko(
new GeckoEvent(mCompositionSelStart + mCompositionSelLen, 0,
GeckoEvent.IME_RANGE_CARETPOSITION, 0, 0, 0,
mComposingText));
return true;
}
@Override
public boolean setComposingRegion(int start, int end) {
Log.d(LOGTAG, "IME: setComposingRegion(start=" + start + ", end=" + end + ")");
if (start < 0 || end < start)
return true;
CharSequence text = null;
if (start == mCompositionStart && end - start == mComposingText.length()) {
// Use mComposingText to avoid extra call to Gecko
text = mComposingText;
}
finishComposingText();
if (text == null && start < end) {
GeckoAppShell.sendEventToGecko(
new GeckoEvent(GeckoEvent.IME_GET_TEXT, start, end - start));
try {
text = mQueryResult.take();
} catch (InterruptedException e) {
Log.e(LOGTAG, "IME: setComposingRegion interrupted", e);
return false;
}
}
GeckoAppShell.sendEventToGecko(
new GeckoEvent(GeckoEvent.IME_SET_SELECTION, start, end - start));
// Call setComposingText with the same text to start composition and let Gecko know about new composing region
setComposingText(text, 1);
return true;
}
@Override
public boolean setSelection(int start, int end) {
Log.d(LOGTAG, "IME: setSelection");
if (mComposing) {
/* Translate to fake selection positions */
start -= mCompositionStart;
end -= mCompositionStart;
if (start < 0)
start = 0;
else if (start > mComposingText.length())
start = mComposingText.length();
if (end < 0)
end = 0;
else if (end > mComposingText.length())
end = mComposingText.length();
mCompositionSelStart = start;
mCompositionSelLen = end - start;
} else {
GeckoAppShell.sendEventToGecko(
new GeckoEvent(GeckoEvent.IME_SET_SELECTION,
start, end - start));
}
return true;
}
public boolean onKeyDel() {
// Some IMEs don't update us on deletions
// In that case we are not updated when a composition
// is destroyed, and Bad Things happen
if (!mComposing)
return false;
if (mComposingText.length() > 0) {
mComposingText = mComposingText.substring(0,
mComposingText.length() - 1);
if (mComposingText.length() > 0)
return false;
}
commitText(null, 1);
return true;
}
public void notifyTextChange(InputMethodManager imm, String text,
int start, int oldEnd, int newEnd) {
Log.d(LOGTAG, String.format("IME: notifyTextChange: text=%s s=%d ne=%d oe=%d",
text, start, newEnd, oldEnd));
if (!mChangeNotificationsEnabled)
return;
if (mBatchMode) {
mBatchChanges.add(new ChangeNotification(text, start, oldEnd, newEnd));
return;
}
mNumPendingChanges = Math.max(mNumPendingChanges - 1, 0);
// If there are pending changes, that means this text is not the most up-to-date version
// and we'll step on ourselves if we change the editable right now.
View v = GeckoApp.mAppContext.getLayerController().getView();
if (mNumPendingChanges == 0 && !text.contentEquals(mEditable))
setEditable(text);
if (mUpdateRequest == null)
return;
mUpdateExtract.flags = 0;
// We update from (0, oldEnd) to (0, newEnd) because some Android IMEs
// assume that updates start at zero, according to jchen.
mUpdateExtract.partialStartOffset = 0;
mUpdateExtract.partialEndOffset = oldEnd;
// Faster to not query for selection
mUpdateExtract.selectionStart = newEnd;
mUpdateExtract.selectionEnd = newEnd;
mUpdateExtract.text = text.substring(0, newEnd);
mUpdateExtract.startOffset = 0;
imm.updateExtractedText(v, mUpdateRequest.token, mUpdateExtract);
}
public void notifySelectionChange(InputMethodManager imm,
int start, int end) {
Log.d(LOGTAG, String.format("IME: notifySelectionChange: s=%d e=%d", start, end));
if (!mChangeNotificationsEnabled)
return;
if (mBatchMode) {
mBatchChanges.add(new ChangeNotification(start, end));
return;
}
View v = GeckoApp.mAppContext.getLayerController().getView();
if (mComposing)
imm.updateSelection(v,
mCompositionStart + mCompositionSelStart,
mCompositionStart + mCompositionSelStart + mCompositionSelLen,
mCompositionStart,
mCompositionStart + mComposingText.length());
else
imm.updateSelection(v, start, end, -1, -1);
// We only change the selection if we are relatively sure that the text we have is
// up-to-date. Bail out if we are stil expecting changes.
if (mNumPendingChanges > 0)
return;
int maxLen = mEditable.length();
Selection.setSelection(mEditable,
Math.min(start, maxLen),
Math.min(end, maxLen));
}
public void reset() {
mComposing = false;
mComposingText = "";
mUpdateRequest = null;
mNumPendingChanges = 0;
mBatchMode = false;
mBatchChanges.clear();
}
// TextWatcher
public void onTextChanged(CharSequence s, int start, int before, int count)
{
Log.d(LOGTAG, String.format("IME: onTextChanged: t=%s s=%d b=%d l=%d",
s, start, before, count));
mNumPendingChanges++;
GeckoAppShell.sendEventToGecko(
new GeckoEvent(GeckoEvent.IME_SET_SELECTION, start, before));
if (count == 0) {
GeckoAppShell.sendEventToGecko(
new GeckoEvent(GeckoEvent.IME_DELETE_TEXT, 0, 0));
} else {
// Start and stop composition to force UI updates.
finishComposingText();
GeckoAppShell.sendEventToGecko(
new GeckoEvent(GeckoEvent.IME_COMPOSITION_BEGIN, 0, 0));
GeckoAppShell.sendEventToGecko(
new GeckoEvent(0, count,
GeckoEvent.IME_RANGE_RAWINPUT, 0, 0, 0,
s.subSequence(start, start + count).toString()));
GeckoAppShell.sendEventToGecko(
new GeckoEvent(GeckoEvent.IME_COMPOSITION_END, 0, 0));
GeckoAppShell.sendEventToGecko(
new GeckoEvent(GeckoEvent.IME_SET_SELECTION, start + count, 0));
}
// Block this thread until all pending events are processed
GeckoAppShell.geckoEventSync();
}
public void afterTextChanged(Editable s)
{
}
public void beforeTextChanged(CharSequence s, int start, int count, int after)
{
}
private void disableChangeNotifications() {
mChangeNotificationsEnabled = false;
}
private void enableChangeNotifications() {
mChangeNotificationsEnabled = true;
}
public InputConnection onCreateInputConnection(EditorInfo outAttrs)
{
Log.d(LOGTAG, "IME: handleCreateInputConnection called");
outAttrs.inputType = InputType.TYPE_CLASS_TEXT;
outAttrs.imeOptions = EditorInfo.IME_ACTION_NONE;
outAttrs.actionLabel = null;
mKeyListener = TextKeyListener.getInstance();
if (mIMEState == IME_STATE_PASSWORD)
outAttrs.inputType |= InputType.TYPE_TEXT_VARIATION_PASSWORD;
else if (mIMETypeHint.equalsIgnoreCase("url"))
outAttrs.inputType |= InputType.TYPE_TEXT_VARIATION_URI;
else if (mIMETypeHint.equalsIgnoreCase("email"))
outAttrs.inputType |= InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
else if (mIMETypeHint.equalsIgnoreCase("search"))
outAttrs.imeOptions = EditorInfo.IME_ACTION_SEARCH;
else if (mIMETypeHint.equalsIgnoreCase("tel"))
outAttrs.inputType = InputType.TYPE_CLASS_PHONE;
else if (mIMETypeHint.equalsIgnoreCase("number") ||
mIMETypeHint.equalsIgnoreCase("range"))
outAttrs.inputType = InputType.TYPE_CLASS_NUMBER;
else if (mIMETypeHint.equalsIgnoreCase("datetime") ||
mIMETypeHint.equalsIgnoreCase("datetime-local"))
outAttrs.inputType = InputType.TYPE_CLASS_DATETIME |
InputType.TYPE_DATETIME_VARIATION_NORMAL;
else if (mIMETypeHint.equalsIgnoreCase("date"))
outAttrs.inputType = InputType.TYPE_CLASS_DATETIME |
InputType.TYPE_DATETIME_VARIATION_DATE;
else if (mIMETypeHint.equalsIgnoreCase("time"))
outAttrs.inputType = InputType.TYPE_CLASS_DATETIME |
InputType.TYPE_DATETIME_VARIATION_TIME;
if (mIMEActionHint.equalsIgnoreCase("go"))
outAttrs.imeOptions = EditorInfo.IME_ACTION_GO;
else if (mIMEActionHint.equalsIgnoreCase("done"))
outAttrs.imeOptions = EditorInfo.IME_ACTION_DONE;
else if (mIMEActionHint.equalsIgnoreCase("next"))
outAttrs.imeOptions = EditorInfo.IME_ACTION_NEXT;
else if (mIMEActionHint.equalsIgnoreCase("search"))
outAttrs.imeOptions = EditorInfo.IME_ACTION_SEARCH;
else if (mIMEActionHint.equalsIgnoreCase("send"))
outAttrs.imeOptions = EditorInfo.IME_ACTION_SEND;
else if (mIMEActionHint != null && mIMEActionHint.length() != 0)
outAttrs.actionLabel = mIMEActionHint;
if (mIMELandscapeFS == false)
outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_EXTRACT_UI;
reset();
return this;
}
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
switch (event.getAction()) {
case KeyEvent.ACTION_DOWN:
return processKeyDown(keyCode, event, true);
case KeyEvent.ACTION_UP:
return processKeyUp(keyCode, event, true);
case KeyEvent.ACTION_MULTIPLE:
return onKeyMultiple(keyCode, event.getRepeatCount(), event);
}
return false;
}
public boolean onKeyDown(int keyCode, KeyEvent event) {
return processKeyDown(keyCode, event, false);
}
private boolean processKeyDown(int keyCode, KeyEvent event, boolean isPreIme) {
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 v = GeckoApp.mAppContext.getLayerController().getView();
// KeyListener returns true if it handled the event for us.
if (mIMEState == IME_STATE_DISABLED ||
keyCode == KeyEvent.KEYCODE_ENTER ||
keyCode == KeyEvent.KEYCODE_DEL ||
(event.getFlags() & KeyEvent.FLAG_SOFT_KEYBOARD) != 0 ||
!mKeyListener.onKeyDown(v, mEditable, keyCode, event))
GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
return true;
}
public boolean onKeyUp(int keyCode, KeyEvent event) {
return processKeyUp(keyCode, event, false);
}
private boolean processKeyUp(int keyCode, KeyEvent event, boolean 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 v = GeckoApp.mAppContext.getLayerController().getView();
if (mIMEState == IME_STATE_DISABLED ||
keyCode == KeyEvent.KEYCODE_ENTER ||
keyCode == KeyEvent.KEYCODE_DEL ||
(event.getFlags() & KeyEvent.FLAG_SOFT_KEYBOARD) != 0 ||
!mKeyListener.onKeyUp(v, mEditable, keyCode, event))
GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
return true;
}
public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
return true;
}
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
View v = GeckoApp.mAppContext.getLayerController().getView();
switch (keyCode) {
case KeyEvent.KEYCODE_MENU:
InputMethodManager imm = (InputMethodManager)
v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInputFromWindow(v.getWindowToken(),
imm.SHOW_FORCED, 0);
return true;
default:
break;
}
return false;
}
public void notifyIME(int type, int state) {
View v = GeckoApp.mAppContext.getLayerController().getView();
Log.d(LOGTAG, "notifyIME");
if (v == null)
return;
Log.d(LOGTAG, "notifyIME v!= null");
switch (type) {
case NOTIFY_IME_RESETINPUTSTATE:
Log.d(LOGTAG, "notifyIME = reset");
// Composition event is already fired from widget.
// So reset IME flags.
reset();
// Don't use IMEStateUpdater for reset.
// Because IME may not work showSoftInput()
// after calling restartInput() immediately.
// So we have to call showSoftInput() delay.
InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
// no way to reset IME status directly
IMEStateUpdater.resetIME();
} else {
imm.restartInput(v);
}
// keep current enabled state
IMEStateUpdater.enableIME();
break;
case NOTIFY_IME_CANCELCOMPOSITION:
Log.d(LOGTAG, "notifyIME = cancel");
IMEStateUpdater.resetIME();
break;
case NOTIFY_IME_FOCUSCHANGE:
Log.d(LOGTAG, "notifyIME = focus");
IMEStateUpdater.resetIME();
break;
}
}
public void notifyIMEEnabled(int state, String typeHint,
String actionHint, boolean landscapeFS)
{
View v = GeckoApp.mAppContext.getLayerController().getView();
if (v == null)
return;
/* When IME is 'disabled', IME processing is disabled.
In addition, the IME UI is hidden */
mIMEState = state;
mIMETypeHint = typeHint;
mIMEActionHint = actionHint;
mIMELandscapeFS = landscapeFS;
IMEStateUpdater.enableIME();
}
public void notifyIMEChange(String text, int start, int end, int newEnd) {
View v = GeckoApp.mAppContext.getLayerController().getView();
if (v == null)
return;
InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm == null)
return;
Log.d(LOGTAG, String.format("IME: notifyIMEChange: t=%s s=%d ne=%d oe=%d",
text, start, newEnd, end));
if (newEnd < 0)
notifySelectionChange(imm, start, end);
else
notifyTextChange(imm, text, start, end, newEnd);
}
public void returnIMEQueryResult(String result, int selectionStart, int selectionLength) {
mSelectionStart = selectionStart;
mSelectionLength = selectionLength;
try {
mQueryResult.put(result);
} catch (InterruptedException e) {}
}
static private final Timer mIMETimer = new Timer();
static private final int NOTIFY_IME_RESETINPUTSTATE = 0;
static private final int NOTIFY_IME_SETOPENSTATE = 1;
static private final int NOTIFY_IME_CANCELCOMPOSITION = 2;
static private final int NOTIFY_IME_FOCUSCHANGE = 3;
/* Delay updating IME states (see bug 573800) */
private static final class IMEStateUpdater extends TimerTask
{
static private IMEStateUpdater instance;
private boolean mEnable, mReset;
static private IMEStateUpdater getInstance() {
if (instance == null) {
instance = new IMEStateUpdater();
mIMETimer.schedule(instance, 200);
}
return instance;
}
static public synchronized void enableIME() {
getInstance().mEnable = true;
}
static public synchronized void resetIME() {
getInstance().mReset = true;
}
public void run() {
Log.d(LOGTAG, "IME: run()");
synchronized(IMEStateUpdater.class) {
instance = null;
}
View v = GeckoApp.mAppContext.getLayerController().getView();
Log.d(LOGTAG, "IME: v="+v);
InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm == null)
return;
if (mReset)
imm.restartInput(v);
if (!mEnable)
return;
if (mIMEState != IME_STATE_DISABLED &&
mIMEState != IME_STATE_PLUGIN)
imm.showSoftInput(v, 0);
else
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
}
public void setEditable(String contents)
{
mEditable.removeSpan(this);
mEditable.replace(0, mEditable.length(), contents);
mEditable.setSpan(this, 0, contents.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
Selection.setSelection(mEditable, contents.length());
}
public void initEditable(String contents)
{
mEditable = mEditableFactory.newEditable(contents);
mEditable.setSpan(this, 0, contents.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
Selection.setSelection(mEditable, contents.length());
}
// Is a composition active?
boolean mComposing;
// Composition text when a composition is active
String mComposingText = "";
// Start index of the composition within the text body
int mCompositionStart;
/* During a composition, we should not alter the real selection,
therefore we keep our own offsets to emulate selection */
// Start of fake selection, relative to start of composition
int mCompositionSelStart;
// Length of fake selection
int mCompositionSelLen;
// Number of in flight changes
int mNumPendingChanges;
// IME stuff
public static final int IME_STATE_DISABLED = 0;
public static final int IME_STATE_ENABLED = 1;
public static final int IME_STATE_PASSWORD = 2;
public static final int IME_STATE_PLUGIN = 3;
KeyListener mKeyListener;
Editable mEditable;
Editable.Factory mEditableFactory;
static int mIMEState;
static String mIMETypeHint;
static String mIMEActionHint;
static boolean mIMELandscapeFS;
private boolean mBatchMode;
private boolean mChangeNotificationsEnabled = true;
private CopyOnWriteArrayList<ChangeNotification> mBatchChanges =
new CopyOnWriteArrayList<ChangeNotification>();
ExtractedTextRequest mUpdateRequest;
final ExtractedText mUpdateExtract = new ExtractedText();
int mSelectionStart, mSelectionLength;
SynchronousQueue<String> mQueryResult;
}