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
@ -53,8 +53,4 @@ XPCSHELL_TESTS = tests/unit
|
||||
DIRS += test
|
||||
endif
|
||||
|
||||
ifeq ($(MOZ_WIDGET_TOOLKIT),android)
|
||||
DIRS += android
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
@ -43,7 +43,7 @@ VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
DIRS = chrome locales components modules themes/core app
|
||||
DIRS = base chrome locales components modules themes/core app
|
||||
|
||||
ifndef LIBXUL_SDK
|
||||
PARALLEL_DIRS += $(DEPTH)/xulrunner/tools/redit
|
||||
|
146
mobile/android/base/AlertNotification.java
Normal file
@ -0,0 +1,146 @@
|
||||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; 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 Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Alex Pakhotin <alexp@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 android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.graphics.*;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
import android.widget.RemoteViews;
|
||||
import java.net.*;
|
||||
import java.text.NumberFormat;
|
||||
|
||||
public class AlertNotification
|
||||
extends Notification
|
||||
{
|
||||
private static final String LOGTAG = "GeckoAlertNotification";
|
||||
|
||||
private final int mId;
|
||||
private final int mIcon;
|
||||
private final String mTitle;
|
||||
private final String mText;
|
||||
private final NotificationManager mNotificationManager;
|
||||
|
||||
private boolean mProgressStyle; // = false
|
||||
private double mPrevPercent = -1;
|
||||
private String mPrevAlertText = "";
|
||||
|
||||
private static final double UPDATE_THRESHOLD = .01;
|
||||
|
||||
public AlertNotification(Context aContext, int aNotificationId, int aIcon,
|
||||
String aTitle, String aText, long aWhen) {
|
||||
super(aIcon, (aText.length() > 0) ? aText : aTitle, aWhen);
|
||||
|
||||
mIcon = aIcon;
|
||||
mTitle = aTitle;
|
||||
mText = aText;
|
||||
mId = aNotificationId;
|
||||
|
||||
mNotificationManager = (NotificationManager)
|
||||
aContext.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
}
|
||||
|
||||
public boolean isProgressStyle() {
|
||||
return mProgressStyle;
|
||||
}
|
||||
|
||||
public void show() {
|
||||
mNotificationManager.notify(mId, this);
|
||||
}
|
||||
|
||||
public void setCustomIcon(Uri aIconUri) {
|
||||
if (aIconUri == null || aIconUri.getScheme() == null)
|
||||
return;
|
||||
|
||||
// Custom view
|
||||
int layout = R.layout.notification_icon_text;
|
||||
RemoteViews view = new RemoteViews(GeckoApp.mAppContext.getPackageName(), layout);
|
||||
try {
|
||||
URL url = new URL(aIconUri.toString());
|
||||
Bitmap bm = BitmapFactory.decodeStream(url.openStream());
|
||||
view.setImageViewBitmap(R.id.notification_image, bm);
|
||||
view.setTextViewText(R.id.notification_title, mTitle);
|
||||
if (mText.length() > 0) {
|
||||
view.setTextViewText(R.id.notification_text, mText);
|
||||
}
|
||||
contentView = view;
|
||||
mNotificationManager.notify(mId, this);
|
||||
} catch(Exception ex) {
|
||||
Log.e(LOGTAG, "failed to create bitmap", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateProgress(String aAlertText, long aProgress, long aProgressMax) {
|
||||
if (!mProgressStyle) {
|
||||
// Custom view
|
||||
int layout = aAlertText.length() > 0 ? R.layout.notification_progress_text : R.layout.notification_progress;
|
||||
|
||||
RemoteViews view = new RemoteViews(GeckoApp.mAppContext.getPackageName(), layout);
|
||||
view.setImageViewResource(R.id.notification_image, mIcon);
|
||||
view.setTextViewText(R.id.notification_title, mTitle);
|
||||
contentView = view;
|
||||
flags |= FLAG_ONGOING_EVENT | FLAG_ONLY_ALERT_ONCE;
|
||||
|
||||
mProgressStyle = true;
|
||||
}
|
||||
|
||||
String text;
|
||||
double percent = 0;
|
||||
if (aProgressMax > 0)
|
||||
percent = ((double)aProgress / (double)aProgressMax);
|
||||
|
||||
if (aAlertText.length() > 0)
|
||||
text = aAlertText;
|
||||
else
|
||||
text = NumberFormat.getPercentInstance().format(percent);
|
||||
|
||||
if (mPrevAlertText.equals(text) && Math.abs(mPrevPercent - percent) < UPDATE_THRESHOLD)
|
||||
return;
|
||||
|
||||
contentView.setTextViewText(R.id.notification_text, text);
|
||||
contentView.setProgressBar(R.id.notification_progressbar, (int)aProgressMax, (int)aProgress, false);
|
||||
|
||||
// Update the notification
|
||||
mNotificationManager.notify(mId, this);
|
||||
|
||||
mPrevPercent = percent;
|
||||
mPrevAlertText = text;
|
||||
}
|
||||
}
|
164
mobile/android/base/AndroidManifest.xml.in
Normal file
@ -0,0 +1,164 @@
|
||||
#filter substitution
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="@ANDROID_PACKAGE_NAME@"
|
||||
android:installLocation="auto"
|
||||
android:versionCode="@ANDROID_VERSION_CODE@"
|
||||
android:versionName="@MOZ_APP_VERSION@"
|
||||
#ifdef MOZ_ANDROID_SHARED_ID
|
||||
android:sharedUserId="@MOZ_ANDROID_SHARED_ID@"
|
||||
#endif
|
||||
>
|
||||
<uses-sdk android:minSdkVersion="5"
|
||||
android:targetSdkVersion="11"/>
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
|
||||
|
||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||
|
||||
<uses-permission android:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS"/>
|
||||
<uses-permission android:name="com.android.browser.permission.WRITE_HISTORY_BOOKMARKS"/>
|
||||
|
||||
<uses-feature android:name="android.hardware.location" android:required="false"/>
|
||||
<uses-feature android:name="android.hardware.location.gps" android:required="false"/>
|
||||
<uses-feature android:name="android.hardware.touchscreen"/>
|
||||
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-feature android:name="android.hardware.camera" android:required="false"/>
|
||||
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>
|
||||
|
||||
<application android:label="@MOZ_APP_DISPLAYNAME@"
|
||||
android:icon="@drawable/icon"
|
||||
#if MOZILLA_OFFICIAL
|
||||
android:debuggable="false">
|
||||
#else
|
||||
android:debuggable="true">
|
||||
#endif
|
||||
|
||||
<activity android:name="App"
|
||||
android:label="@MOZ_APP_DISPLAYNAME@"
|
||||
android:configChanges="keyboard|keyboardHidden|mcc|mnc|orientation"
|
||||
android:windowSoftInputMode="stateUnspecified|adjustResize"
|
||||
android:launchMode="singleTask"
|
||||
android:theme="@style/GreyTheme">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
<!-- Default browser intents -->
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="http" />
|
||||
<data android:scheme="https" />
|
||||
<data android:scheme="about" />
|
||||
<data android:scheme="javascript" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:scheme="file" />
|
||||
<data android:scheme="http" />
|
||||
<data android:scheme="https" />
|
||||
<data android:mimeType="text/html"/>
|
||||
<data android:mimeType="text/plain"/>
|
||||
<data android:mimeType="application/xhtml+xml"/>
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.WEB_SEARCH" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="" />
|
||||
<data android:scheme="http" />
|
||||
<data android:scheme="https" />
|
||||
</intent-filter>
|
||||
|
||||
<!-- For debugging -->
|
||||
<intent-filter>
|
||||
<action android:name="org.mozilla.gecko.DEBUG" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<receiver android:name="NotificationHandler">
|
||||
<intent-filter>
|
||||
<action android:name="org.mozilla.gecko.ACTION_ALERT_CLICK" />
|
||||
<action android:name="org.mozilla.gecko.ACTION_ALERT_CLEAR" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<activity android:name="Restarter"
|
||||
android:process="@ANDROID_PACKAGE_NAME@Restarter"
|
||||
android:theme="@style/GreyTheme"
|
||||
android:excludeFromRecents="true">
|
||||
<intent-filter>
|
||||
<action android:name="org.mozilla.gecko.restart"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
#if MOZ_CRASHREPORTER
|
||||
<activity android:name="CrashReporter"
|
||||
android:label="@string/crash_reporter_title"
|
||||
android:icon="@drawable/crash_reporter"
|
||||
android:theme="@style/GreyTheme"
|
||||
android:excludeFromRecents="true">
|
||||
<intent-filter>
|
||||
<action android:name="org.mozilla.gecko.reportCrash" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
#endif
|
||||
|
||||
<activity android:name="LauncherShortcuts"
|
||||
android:label="@string/launcher_shortcuts_title"
|
||||
android:theme="@android:style/Theme.Translucent">
|
||||
<!-- This intent-filter allows your shortcuts to be created in the launcher. -->
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.CREATE_SHORTCUT" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name="org.mozilla.gecko.AwesomeBar"
|
||||
android:theme="@android:style/Theme.Light"
|
||||
android:configChanges="orientation"
|
||||
android:windowSoftInputMode="stateAlwaysVisible|adjustResize"
|
||||
android:windowIsTranslucent="true"
|
||||
android:windowContentOverlay="@null"
|
||||
android:windowNoTitle="true"
|
||||
android:windowIsFloating="true"
|
||||
android:backgroundDimEnabled="false">
|
||||
</activity>
|
||||
|
||||
<activity android:name="org.mozilla.gecko.TabsTray"
|
||||
android:theme="@android:style/Theme.Translucent"
|
||||
android:windowIsTranslucent="true"
|
||||
android:windowContentOverlay="@null"
|
||||
android:windowNoTitle="true"
|
||||
android:windowIsFloating="true"
|
||||
android:backgroundDimEnabled="false">
|
||||
</activity>
|
||||
|
||||
<activity android:name="org.mozilla.gecko.GeckoPreferences"
|
||||
android:label="@string/preferences_title"
|
||||
android:excludeFromRecents="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name="org.mozilla.gecko.GeckoBookmarks"
|
||||
android:label="@string/bookmarks_title"
|
||||
android:excludeFromRecents="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
52
mobile/android/base/App.java.in
Normal file
@ -0,0 +1,52 @@
|
||||
/* -*- 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):
|
||||
* Brad Lassey <blassey@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 ***** */
|
||||
|
||||
#filter substitution
|
||||
package @ANDROID_PACKAGE_NAME@;
|
||||
|
||||
import org.mozilla.gecko.GeckoApp;
|
||||
|
||||
public class App extends GeckoApp {
|
||||
public String getPackageName() {
|
||||
return "@ANDROID_PACKAGE_NAME@";
|
||||
}
|
||||
|
||||
public String getContentProcessName() {
|
||||
return "@MOZ_CHILD_PROCESS_NAME@";
|
||||
}
|
||||
};
|
||||
|
247
mobile/android/base/AwesomeBar.java
Normal file
@ -0,0 +1,247 @@
|
||||
/* -*- 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) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Vladimir Vukicevic <vladimir@pobox.com>
|
||||
* Wes Johnston <wjohnston@mozilla.com>
|
||||
* Mark Finkle <mfinkle@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.File;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.EditText;
|
||||
|
||||
public class AwesomeBar extends Activity {
|
||||
private static final String LOGTAG = "GeckoAwesomeBar";
|
||||
|
||||
static final String URL_KEY = "url";
|
||||
static final String TITLE_KEY = "title";
|
||||
static final String CURRENT_URL_KEY = "currenturl";
|
||||
static final String TYPE_KEY = "type";
|
||||
static enum Type { ADD, EDIT };
|
||||
|
||||
private String mType;
|
||||
private AwesomeBarTabs mAwesomeTabs;
|
||||
private AwesomeBarEditText mText;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
Log.d(LOGTAG, "creating awesomebar");
|
||||
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
setContentView(R.layout.awesomebar_search);
|
||||
|
||||
mAwesomeTabs = (AwesomeBarTabs) findViewById(R.id.awesomebar_tabs);
|
||||
mAwesomeTabs.setOnUrlOpenListener(new AwesomeBarTabs.OnUrlOpenListener() {
|
||||
public void onUrlOpen(AwesomeBarTabs tabs, String url) {
|
||||
openUrlAndFinish(url);
|
||||
}
|
||||
});
|
||||
|
||||
mText = (AwesomeBarEditText) findViewById(R.id.awesomebar_text);
|
||||
|
||||
Resources resources = getResources();
|
||||
|
||||
int padding[] = { mText.getPaddingLeft(),
|
||||
mText.getPaddingTop(),
|
||||
mText.getPaddingRight(),
|
||||
mText.getPaddingBottom() };
|
||||
|
||||
GeckoStateListDrawable states = new GeckoStateListDrawable();
|
||||
states.initializeFilter(GeckoApp.mBrowserToolbar.getHighlightColor());
|
||||
states.addState(new int[] { android.R.attr.state_focused }, resources.getDrawable(R.drawable.address_bar_url_pressed));
|
||||
states.addState(new int[] { android.R.attr.state_pressed }, resources.getDrawable(R.drawable.address_bar_url_pressed));
|
||||
states.addState(new int[] { }, resources.getDrawable(R.drawable.address_bar_url_default));
|
||||
mText.setBackgroundDrawable(states);
|
||||
|
||||
mText.setPadding(padding[0], padding[1], padding[2], padding[3]);
|
||||
|
||||
Intent intent = getIntent();
|
||||
String currentUrl = intent.getStringExtra(CURRENT_URL_KEY);
|
||||
mType = intent.getStringExtra(TYPE_KEY);
|
||||
if (currentUrl != null) {
|
||||
mText.setText(currentUrl);
|
||||
mText.selectAll();
|
||||
}
|
||||
|
||||
mText.setOnKeyPreImeListener(new AwesomeBarEditText.OnKeyPreImeListener() {
|
||||
public boolean onKeyPreIme(View v, int keyCode, KeyEvent event) {
|
||||
InputMethodManager imm =
|
||||
(InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
|
||||
// If input method is in fullscreen mode, we want to dismiss
|
||||
// it instead of closing awesomebar straight away.
|
||||
if (!imm.isFullscreenMode() && keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
cancelAndFinish();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
mText.addTextChangedListener(new TextWatcher() {
|
||||
public void afterTextChanged(Editable s) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public void beforeTextChanged(CharSequence s, int start, int count,
|
||||
int after) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public void onTextChanged(CharSequence s, int start, int before,
|
||||
int count) {
|
||||
mAwesomeTabs.filter(s.toString());
|
||||
}
|
||||
});
|
||||
|
||||
mText.setOnKeyListener(new View.OnKeyListener() {
|
||||
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
||||
if (keyCode == KeyEvent.KEYCODE_ENTER) {
|
||||
if (event.getAction() != KeyEvent.ACTION_DOWN)
|
||||
return true;
|
||||
|
||||
openUrlAndFinish(mText.getText().toString());
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
mText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
||||
public void onFocusChange(View v, boolean hasFocus) {
|
||||
if (!hasFocus) {
|
||||
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfiguration) {
|
||||
super.onConfigurationChanged(newConfiguration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSearchRequested() {
|
||||
cancelAndFinish();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void cancelAndFinish() {
|
||||
setResult(Activity.RESULT_CANCELED);
|
||||
finish();
|
||||
}
|
||||
|
||||
private void openUrlAndFinish(String url) {
|
||||
Intent resultIntent = new Intent();
|
||||
resultIntent.putExtra(URL_KEY, url);
|
||||
resultIntent.putExtra(TYPE_KEY, mType);
|
||||
|
||||
setResult(Activity.RESULT_OK, resultIntent);
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
// This method is called only if the key event was not handled
|
||||
// by any of the views, which usually means the edit box lost focus
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK ||
|
||||
keyCode == KeyEvent.KEYCODE_MENU ||
|
||||
keyCode == KeyEvent.KEYCODE_SEARCH ||
|
||||
keyCode == KeyEvent.KEYCODE_DPAD_UP ||
|
||||
keyCode == KeyEvent.KEYCODE_DPAD_DOWN ||
|
||||
keyCode == KeyEvent.KEYCODE_DPAD_LEFT ||
|
||||
keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ||
|
||||
keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
|
||||
return super.onKeyDown(keyCode, event);
|
||||
} else {
|
||||
// Return focus to the edit box, and dispatch the event to it
|
||||
mText.requestFocusFromTouch();
|
||||
mText.dispatchKeyEvent(event);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
mAwesomeTabs.destroy();
|
||||
}
|
||||
|
||||
public static class AwesomeBarEditText extends EditText {
|
||||
OnKeyPreImeListener mOnKeyPreImeListener;
|
||||
|
||||
public interface OnKeyPreImeListener {
|
||||
public boolean onKeyPreIme(View v, int keyCode, KeyEvent event);
|
||||
}
|
||||
|
||||
public AwesomeBarEditText(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
mOnKeyPreImeListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
|
||||
if (mOnKeyPreImeListener != null)
|
||||
return mOnKeyPreImeListener.onKeyPreIme(this, keyCode, event);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setOnKeyPreImeListener(OnKeyPreImeListener listener) {
|
||||
mOnKeyPreImeListener = listener;
|
||||
}
|
||||
}
|
||||
}
|
624
mobile/android/base/AwesomeBarTabs.java
Normal file
@ -0,0 +1,624 @@
|
||||
/* -*- 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) 2009-2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Lucas Rocha <lucasr@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 android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.LightingColorFilter;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.AsyncTask;
|
||||
import android.provider.Browser;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ExpandableListView;
|
||||
import android.widget.FilterQueryProvider;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.SimpleCursorAdapter;
|
||||
import android.widget.SimpleExpandableListAdapter;
|
||||
import android.widget.TabHost;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class AwesomeBarTabs extends TabHost {
|
||||
private static final String LOGTAG = "GeckoAwesomeBarTabs";
|
||||
|
||||
private static final String ALL_PAGES_TAB = "all";
|
||||
private static final String BOOKMARKS_TAB = "bookmarks";
|
||||
private static final String HISTORY_TAB = "history";
|
||||
|
||||
private static enum HistorySection { TODAY, YESTERDAY, WEEK, OLDER };
|
||||
|
||||
private Context mContext;
|
||||
private OnUrlOpenListener mUrlOpenListener;
|
||||
private View.OnTouchListener mListTouchListener;
|
||||
|
||||
private SimpleCursorAdapter mAllPagesAdapter;
|
||||
private SimpleCursorAdapter mBookmarksAdapter;
|
||||
private SimpleExpandableListAdapter mHistoryAdapter;
|
||||
|
||||
// FIXME: This value should probably come from a
|
||||
// prefs key (just like XUL-based fennec)
|
||||
private static final int MAX_RESULTS = 100;
|
||||
|
||||
public interface OnUrlOpenListener {
|
||||
public abstract void onUrlOpen(AwesomeBarTabs tabs, String url);
|
||||
}
|
||||
|
||||
private class HistoryListAdapter extends SimpleExpandableListAdapter {
|
||||
public HistoryListAdapter(Context context, List<? extends Map<String, ?>> groupData,
|
||||
int groupLayout, String[] groupFrom, int[] groupTo,
|
||||
List<? extends List<? extends Map<String, ?>>> childData,
|
||||
int childLayout, String[] childFrom, int[] childTo) {
|
||||
|
||||
super(context, groupData, groupLayout, groupFrom, groupTo,
|
||||
childData, childLayout, childFrom, childTo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
|
||||
View convertView, ViewGroup parent) {
|
||||
|
||||
View childView =
|
||||
super.getChildView(groupPosition, childPosition, isLastChild, convertView, parent);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String,Object> historyItem =
|
||||
(Map<String,Object>) mHistoryAdapter.getChild(groupPosition, childPosition);
|
||||
|
||||
byte[] b = (byte[]) historyItem.get(Browser.BookmarkColumns.FAVICON);
|
||||
ImageView favicon = (ImageView) childView.findViewById(R.id.favicon);
|
||||
|
||||
if (b == null) {
|
||||
favicon.setImageResource(R.drawable.favicon);
|
||||
} else {
|
||||
Bitmap bitmap = BitmapFactory.decodeByteArray(b, 0, b.length);
|
||||
favicon.setImageBitmap(bitmap);
|
||||
}
|
||||
|
||||
return childView;
|
||||
}
|
||||
}
|
||||
|
||||
private class AwesomeCursorViewBinder implements SimpleCursorAdapter.ViewBinder {
|
||||
private boolean updateFavicon(View view, Cursor cursor, int faviconIndex) {
|
||||
byte[] b = cursor.getBlob(faviconIndex);
|
||||
ImageView favicon = (ImageView) view;
|
||||
|
||||
if (b == null) {
|
||||
favicon.setImageResource(R.drawable.favicon);
|
||||
} else {
|
||||
Bitmap bitmap = BitmapFactory.decodeByteArray(b, 0, b.length);
|
||||
favicon.setImageBitmap(bitmap);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean updateTitle(View view, Cursor cursor, int titleIndex) {
|
||||
String title = cursor.getString(titleIndex);
|
||||
TextView titleView = (TextView)view;
|
||||
// Use the URL instead of an empty title for consistency with the normal URL
|
||||
// bar view - this is the equivalent of getDisplayTitle() in Tab.java
|
||||
if (title == null || title.length() == 0) {
|
||||
int urlIndex = cursor.getColumnIndexOrThrow(Browser.BookmarkColumns.URL);
|
||||
title = cursor.getString(urlIndex);
|
||||
}
|
||||
|
||||
titleView.setText(title);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
|
||||
int faviconIndex = cursor.getColumnIndexOrThrow(Browser.BookmarkColumns.FAVICON);
|
||||
if (columnIndex == faviconIndex) {
|
||||
return updateFavicon(view, cursor, faviconIndex);
|
||||
}
|
||||
|
||||
int titleIndex = cursor.getColumnIndexOrThrow(Browser.BookmarkColumns.TITLE);
|
||||
if (columnIndex == titleIndex) {
|
||||
return updateTitle(view, cursor, titleIndex);
|
||||
}
|
||||
|
||||
// Other columns are handled automatically
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private class BookmarksQueryTask extends AsyncTask<Void, Void, Cursor> {
|
||||
protected Cursor doInBackground(Void... arg0) {
|
||||
ContentResolver resolver = mContext.getContentResolver();
|
||||
|
||||
return resolver.query(Browser.BOOKMARKS_URI,
|
||||
null,
|
||||
// Select all bookmarks with a non-empty URL. When the history
|
||||
// is empty there appears to be a dummy entry in the database
|
||||
// which has a title of "Bookmarks" and no URL; the length restriction
|
||||
// is to avoid picking that up specifically.
|
||||
Browser.BookmarkColumns.BOOKMARK + " = 1 AND LENGTH(" + Browser.BookmarkColumns.URL + ") > 0",
|
||||
null,
|
||||
Browser.BookmarkColumns.TITLE);
|
||||
}
|
||||
|
||||
protected void onPostExecute(Cursor cursor) {
|
||||
// Load the list using a custom adapter so we can create the bitmaps
|
||||
mBookmarksAdapter = new SimpleCursorAdapter(
|
||||
mContext,
|
||||
R.layout.awesomebar_row,
|
||||
cursor,
|
||||
new String[] { AwesomeBar.TITLE_KEY,
|
||||
AwesomeBar.URL_KEY,
|
||||
Browser.BookmarkColumns.FAVICON },
|
||||
new int[] { R.id.title, R.id.url, R.id.favicon }
|
||||
);
|
||||
|
||||
mBookmarksAdapter.setViewBinder(new AwesomeCursorViewBinder());
|
||||
|
||||
final ListView bookmarksList = (ListView) findViewById(R.id.bookmarks_list);
|
||||
|
||||
bookmarksList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
handleItemClick(bookmarksList, position);
|
||||
}
|
||||
});
|
||||
|
||||
bookmarksList.setAdapter(mBookmarksAdapter);
|
||||
}
|
||||
}
|
||||
|
||||
private class HistoryQueryTask extends AsyncTask<Void, Void, Pair<List,List>> {
|
||||
private static final long MS_PER_DAY = 86400000;
|
||||
private static final long MS_PER_WEEK = MS_PER_DAY * 7;
|
||||
|
||||
protected Pair<List,List> doInBackground(Void... arg0) {
|
||||
Pair<List,List> result = null;
|
||||
ContentResolver resolver = mContext.getContentResolver();
|
||||
|
||||
Cursor cursor =
|
||||
resolver.query(Browser.BOOKMARKS_URI,
|
||||
null,
|
||||
// Bookmarks that have not been visited have a date value
|
||||
// of 0, so don't pick them up in the history view.
|
||||
Browser.BookmarkColumns.DATE + " > 0",
|
||||
null,
|
||||
Browser.BookmarkColumns.DATE + " DESC LIMIT " + MAX_RESULTS);
|
||||
|
||||
Date now = new Date();
|
||||
now.setHours(0);
|
||||
now.setMinutes(0);
|
||||
now.setSeconds(0);
|
||||
|
||||
long today = now.getTime();
|
||||
|
||||
// Split the list of urls into separate date range groups
|
||||
// and show it in an expandable list view.
|
||||
List<List<Map<String,?>>> childrenLists = null;
|
||||
List<Map<String,?>> children = null;
|
||||
List<Map<String,?>> groups = null;
|
||||
HistorySection section = null;
|
||||
|
||||
// Move cursor before the first row in preparation
|
||||
// for the iteration.
|
||||
cursor.moveToPosition(-1);
|
||||
|
||||
// Split the history query results into adapters per time
|
||||
// section (today, yesterday, week, older). Queries on content
|
||||
// Browser content provider don't support limitting the number
|
||||
// of returned rows so we limit it here.
|
||||
while (cursor.moveToNext()) {
|
||||
long time = cursor.getLong(cursor.getColumnIndexOrThrow(Browser.BookmarkColumns.DATE));
|
||||
HistorySection itemSection = getSectionForTime(time, today);
|
||||
|
||||
if (groups == null)
|
||||
groups = new LinkedList<Map<String,?>>();
|
||||
|
||||
if (childrenLists == null)
|
||||
childrenLists = new LinkedList<List<Map<String,?>>>();
|
||||
|
||||
if (section != itemSection) {
|
||||
if (section != null) {
|
||||
groups.add(createGroupItem(section));
|
||||
childrenLists.add(children);
|
||||
}
|
||||
|
||||
section = itemSection;
|
||||
children = new LinkedList<Map<String,?>>();
|
||||
}
|
||||
|
||||
children.add(createHistoryItem(cursor));
|
||||
}
|
||||
|
||||
// Add any remaining section to the list if it hasn't
|
||||
// been added to the list after the loop.
|
||||
if (section != null && children != null) {
|
||||
groups.add(createGroupItem(section));
|
||||
childrenLists.add(children);
|
||||
}
|
||||
|
||||
// Close the query cursor as we won't use it anymore
|
||||
cursor.close();
|
||||
|
||||
if (groups != null && childrenLists != null) {
|
||||
result = Pair.create((List) groups, (List) childrenLists);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public Map<String,?> createHistoryItem(Cursor cursor) {
|
||||
Map<String,Object> historyItem = new HashMap<String,Object>();
|
||||
|
||||
String url = cursor.getString(cursor.getColumnIndexOrThrow(AwesomeBar.URL_KEY));
|
||||
String title = cursor.getString(cursor.getColumnIndexOrThrow(AwesomeBar.TITLE_KEY));
|
||||
byte[] favicon = cursor.getBlob(cursor.getColumnIndexOrThrow(Browser.BookmarkColumns.FAVICON));
|
||||
|
||||
// Use the URL instead of an empty title for consistency with the normal URL
|
||||
// bar view - this is the equivalent of getDisplayTitle() in Tab.java
|
||||
if (title == null || title.length() == 0)
|
||||
title = url;
|
||||
|
||||
historyItem.put(AwesomeBar.URL_KEY, url);
|
||||
historyItem.put(AwesomeBar.TITLE_KEY, title);
|
||||
|
||||
if (favicon != null)
|
||||
historyItem.put(Browser.BookmarkColumns.FAVICON, favicon);
|
||||
|
||||
return historyItem;
|
||||
}
|
||||
|
||||
public Map<String,?> createGroupItem(HistorySection section) {
|
||||
Map<String,String> groupItem = new HashMap<String,String>();
|
||||
|
||||
groupItem.put(AwesomeBar.TITLE_KEY, getSectionName(section));
|
||||
|
||||
return groupItem;
|
||||
}
|
||||
|
||||
private String getSectionName(HistorySection section) {
|
||||
Resources resources = mContext.getResources();
|
||||
|
||||
switch (section) {
|
||||
case TODAY:
|
||||
return resources.getString(R.string.history_today_section);
|
||||
case YESTERDAY:
|
||||
return resources.getString(R.string.history_yesterday_section);
|
||||
case WEEK:
|
||||
return resources.getString(R.string.history_week_section);
|
||||
case OLDER:
|
||||
return resources.getString(R.string.history_older_section);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void expandAllGroups(ExpandableListView historyList) {
|
||||
int groupCount = mHistoryAdapter.getGroupCount();
|
||||
|
||||
for (int i = 0; i < groupCount; i++) {
|
||||
historyList.expandGroup(i);
|
||||
}
|
||||
}
|
||||
|
||||
private HistorySection getSectionForTime(long time, long today) {
|
||||
long delta = today - time;
|
||||
|
||||
if (delta < 0) {
|
||||
return HistorySection.TODAY;
|
||||
} else if (delta > 0 && delta < MS_PER_DAY) {
|
||||
return HistorySection.YESTERDAY;
|
||||
} else if (delta > MS_PER_DAY && delta < MS_PER_WEEK) {
|
||||
return HistorySection.WEEK;
|
||||
}
|
||||
|
||||
return HistorySection.OLDER;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void onPostExecute(Pair<List,List> result) {
|
||||
// FIXME: display some sort of message when there's no history
|
||||
if (result == null)
|
||||
return;
|
||||
|
||||
mHistoryAdapter = new HistoryListAdapter(
|
||||
mContext,
|
||||
result.first,
|
||||
R.layout.awesomebar_header_row,
|
||||
new String[] { AwesomeBar.TITLE_KEY },
|
||||
new int[] { R.id.title },
|
||||
result.second,
|
||||
R.layout.awesomebar_row,
|
||||
new String[] { AwesomeBar.TITLE_KEY, AwesomeBar.URL_KEY },
|
||||
new int[] { R.id.title, R.id.url }
|
||||
);
|
||||
|
||||
final ExpandableListView historyList =
|
||||
(ExpandableListView) findViewById(R.id.history_list);
|
||||
|
||||
historyList.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
|
||||
public boolean onChildClick(ExpandableListView parent, View view,
|
||||
int groupPosition, int childPosition, long id) {
|
||||
handleHistoryItemClick(groupPosition, childPosition);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
// This is to disallow collapsing the expandable groups in the
|
||||
// history expandable list view to mimic simpler sections. We should
|
||||
// Remove this if we decide to allow expanding/collapsing groups.
|
||||
historyList.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
|
||||
public boolean onGroupClick(ExpandableListView parent, View v,
|
||||
int groupPosition, long id) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
historyList.setAdapter(mHistoryAdapter);
|
||||
|
||||
expandAllGroups(historyList);
|
||||
}
|
||||
}
|
||||
|
||||
public AwesomeBarTabs(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
Log.d(LOGTAG, "Creating AwesomeBarTabs");
|
||||
|
||||
mContext = context;
|
||||
|
||||
// Load layout into the custom view
|
||||
LayoutInflater inflater =
|
||||
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
|
||||
inflater.inflate(R.layout.awesomebar_tabs, this);
|
||||
|
||||
// This should be called before adding any tabs
|
||||
// to the TabHost.
|
||||
setup();
|
||||
|
||||
mListTouchListener = new View.OnTouchListener() {
|
||||
public boolean onTouch(View view, MotionEvent event) {
|
||||
hideSoftInput(view);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
addAllPagesTab();
|
||||
addBookmarksTab();
|
||||
addHistoryTab();
|
||||
|
||||
setOnTabChangedListener(new TabHost.OnTabChangeListener() {
|
||||
@Override
|
||||
public void onTabChanged(String tabId) {
|
||||
// Lazy load bookmarks and history lists. Only query the database
|
||||
// if those lists requested by user.
|
||||
if (tabId.equals(BOOKMARKS_TAB) && mBookmarksAdapter == null) {
|
||||
new BookmarksQueryTask().execute();
|
||||
} else if (tabId.equals(HISTORY_TAB) && mHistoryAdapter == null) {
|
||||
new HistoryQueryTask().execute();
|
||||
}
|
||||
|
||||
// Always dismiss SKB when changing tabs
|
||||
View tabView = getCurrentTabView();
|
||||
hideSoftInput(tabView);
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize "App Pages" list with no filter
|
||||
filter("");
|
||||
}
|
||||
|
||||
private TabSpec addAwesomeTab(String id, int titleId, int contentId) {
|
||||
TabSpec tab = newTabSpec(id);
|
||||
|
||||
LayoutInflater inflater =
|
||||
(LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
|
||||
View indicatorView = inflater.inflate(R.layout.awesomebar_tab_indicator, null);
|
||||
Drawable background = indicatorView.getBackground();
|
||||
background.setColorFilter(new LightingColorFilter(Color.WHITE, GeckoApp.mBrowserToolbar.getHighlightColor()));
|
||||
|
||||
TextView title = (TextView) indicatorView.findViewById(R.id.title);
|
||||
title.setText(titleId);
|
||||
|
||||
tab.setIndicator(indicatorView);
|
||||
tab.setContent(contentId);
|
||||
|
||||
addTab(tab);
|
||||
|
||||
return tab;
|
||||
}
|
||||
|
||||
private void addAllPagesTab() {
|
||||
Log.d(LOGTAG, "Creating All Pages tab");
|
||||
|
||||
addAwesomeTab(ALL_PAGES_TAB,
|
||||
R.string.awesomebar_all_pages_title,
|
||||
R.id.all_pages_list);
|
||||
|
||||
// Load the list using a custom adapter so we can create the bitmaps
|
||||
mAllPagesAdapter = new SimpleCursorAdapter(
|
||||
mContext,
|
||||
R.layout.awesomebar_row,
|
||||
null,
|
||||
new String[] { AwesomeBar.TITLE_KEY,
|
||||
AwesomeBar.URL_KEY,
|
||||
Browser.BookmarkColumns.FAVICON },
|
||||
new int[] { R.id.title, R.id.url, R.id.favicon }
|
||||
);
|
||||
|
||||
mAllPagesAdapter.setViewBinder(new AwesomeCursorViewBinder());
|
||||
|
||||
mAllPagesAdapter.setFilterQueryProvider(new FilterQueryProvider() {
|
||||
public Cursor runQuery(CharSequence constraint) {
|
||||
ContentResolver resolver = mContext.getContentResolver();
|
||||
|
||||
return resolver.query(Browser.BOOKMARKS_URI,
|
||||
null,
|
||||
// The length restriction on URL is for the same reason as in the general bookmark query
|
||||
// (see comment earlier in this file).
|
||||
"(" + Browser.BookmarkColumns.URL + " LIKE ? OR " + Browser.BookmarkColumns.TITLE + " LIKE ?)"
|
||||
+ " AND LENGTH(" + Browser.BookmarkColumns.URL + ") > 0",
|
||||
new String[] {"%" + constraint.toString() + "%", "%" + constraint.toString() + "%",},
|
||||
// ORDER BY is number of visits times a multiplier from 1 - 120 of how recently the site
|
||||
// was accessed with a site accessed today getting 120 and a site accessed 119 or more
|
||||
// days ago getting 1
|
||||
Browser.BookmarkColumns.VISITS + " * MAX(1, (" +
|
||||
Browser.BookmarkColumns.DATE + " - " + new Date().getTime() + ") / 86400000 + 120) DESC LIMIT " + MAX_RESULTS);
|
||||
}
|
||||
});
|
||||
|
||||
final ListView allPagesList = (ListView) findViewById(R.id.all_pages_list);
|
||||
|
||||
allPagesList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
handleItemClick(allPagesList, position);
|
||||
}
|
||||
});
|
||||
|
||||
allPagesList.setAdapter(mAllPagesAdapter);
|
||||
allPagesList.setOnTouchListener(mListTouchListener);
|
||||
}
|
||||
|
||||
private void addBookmarksTab() {
|
||||
Log.d(LOGTAG, "Creating Bookmarks tab");
|
||||
|
||||
addAwesomeTab(BOOKMARKS_TAB,
|
||||
R.string.awesomebar_bookmarks_title,
|
||||
R.id.bookmarks_list);
|
||||
|
||||
ListView bookmarksList = (ListView) findViewById(R.id.bookmarks_list);
|
||||
bookmarksList.setOnTouchListener(mListTouchListener);
|
||||
|
||||
// Only load bookmark list when tab is actually used.
|
||||
// See OnTabChangeListener above.
|
||||
}
|
||||
|
||||
private void addHistoryTab() {
|
||||
Log.d(LOGTAG, "Creating History tab");
|
||||
|
||||
addAwesomeTab(HISTORY_TAB,
|
||||
R.string.awesomebar_history_title,
|
||||
R.id.history_list);
|
||||
|
||||
ListView historyList = (ListView) findViewById(R.id.history_list);
|
||||
historyList.setOnTouchListener(mListTouchListener);
|
||||
|
||||
// Only load history list when tab is actually used.
|
||||
// See OnTabChangeListener above.
|
||||
}
|
||||
|
||||
private void hideSoftInput(View view) {
|
||||
InputMethodManager imm =
|
||||
(InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
|
||||
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
|
||||
}
|
||||
|
||||
private void handleHistoryItemClick(int groupPosition, int childPosition) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String,Object> historyItem =
|
||||
(Map<String,Object>) mHistoryAdapter.getChild(groupPosition, childPosition);
|
||||
|
||||
String url = (String) historyItem.get(AwesomeBar.URL_KEY);
|
||||
|
||||
if (mUrlOpenListener != null)
|
||||
mUrlOpenListener.onUrlOpen(this, url);
|
||||
}
|
||||
|
||||
private void handleItemClick(ListView list, int position) {
|
||||
Cursor cursor = (Cursor) list.getItemAtPosition(position);
|
||||
String url = cursor.getString(cursor.getColumnIndexOrThrow(AwesomeBar.URL_KEY));
|
||||
|
||||
if (mUrlOpenListener != null)
|
||||
mUrlOpenListener.onUrlOpen(this, url);
|
||||
}
|
||||
|
||||
public void setOnUrlOpenListener(OnUrlOpenListener listener) {
|
||||
mUrlOpenListener = listener;
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
Cursor allPagesCursor = mAllPagesAdapter.getCursor();
|
||||
if (allPagesCursor != null)
|
||||
allPagesCursor.close();
|
||||
|
||||
if (mBookmarksAdapter != null) {
|
||||
Cursor bookmarksCursor = mBookmarksAdapter.getCursor();
|
||||
if (bookmarksCursor != null)
|
||||
bookmarksCursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void filter(String searchTerm) {
|
||||
// Don't let the tab's content steal focus on tab switch
|
||||
setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
|
||||
|
||||
// Ensure the 'All Pages' tab is selected
|
||||
setCurrentTabByTag(ALL_PAGES_TAB);
|
||||
|
||||
// Restore normal focus behavior on tab host
|
||||
setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
|
||||
|
||||
// The tabs should only be visible if there's no on-going search
|
||||
int tabsVisibility = (searchTerm.length() == 0 ? View.VISIBLE : View.GONE);
|
||||
getTabWidget().setVisibility(tabsVisibility);
|
||||
|
||||
// Perform the actual search
|
||||
mAllPagesAdapter.getFilter().filter(searchTerm);
|
||||
}
|
||||
}
|
269
mobile/android/base/BrowserToolbar.java
Normal file
@ -0,0 +1,269 @@
|
||||
/* -*- 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) 2009-2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Vladimir Vukicevic <vladimir@pobox.com>
|
||||
* Matt Brubeck <mbrubeck@mozilla.com>
|
||||
* Vivien Nicolas <vnicolas@mozilla.com>
|
||||
* Lucas Rocha <lucasr@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 android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.AnimationDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.Typeface;
|
||||
import android.os.Handler;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.animation.TranslateAnimation;
|
||||
import android.view.Gravity;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.TextSwitcher;
|
||||
import android.widget.ViewSwitcher.ViewFactory;
|
||||
|
||||
public class BrowserToolbar extends LinearLayout {
|
||||
final private Button mAwesomeBar;
|
||||
final private ImageButton mTabs;
|
||||
final public ImageButton mFavicon;
|
||||
final public ImageButton mStop;
|
||||
final public ImageButton mSiteSecurity;
|
||||
final private AnimationDrawable mProgressSpinner;
|
||||
final private TextSwitcher mTabsCount;
|
||||
|
||||
final private Context mContext;
|
||||
final private Handler mHandler;
|
||||
final private int mColor;
|
||||
final private int mCounterColor;
|
||||
|
||||
final private int mDuration;
|
||||
final private TranslateAnimation mSlideUpIn;
|
||||
final private TranslateAnimation mSlideUpOut;
|
||||
final private TranslateAnimation mSlideDownIn;
|
||||
final private TranslateAnimation mSlideDownOut;
|
||||
|
||||
private int mCount;
|
||||
|
||||
public BrowserToolbar(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
mContext = context;
|
||||
|
||||
// Get the device's highlight color
|
||||
ContextThemeWrapper wrapper = new ContextThemeWrapper(mContext, android.R.style.TextAppearance);
|
||||
TypedArray typedArray = wrapper.getTheme().obtainStyledAttributes(new int[] { android.R.attr.textColorHighlight });
|
||||
mColor = typedArray.getColor(typedArray.getIndex(0), 0);
|
||||
|
||||
// Load layout into the custom view
|
||||
LayoutInflater inflater =
|
||||
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
|
||||
inflater.inflate(R.layout.browser_toolbar, this);
|
||||
|
||||
mAwesomeBar = (Button) findViewById(R.id.awesome_bar);
|
||||
mAwesomeBar.setOnClickListener(new Button.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
onAwesomeBarSearch();
|
||||
}
|
||||
});
|
||||
|
||||
Resources resources = getResources();
|
||||
|
||||
int padding[] = { mAwesomeBar.getPaddingLeft(),
|
||||
mAwesomeBar.getPaddingTop(),
|
||||
mAwesomeBar.getPaddingRight(),
|
||||
mAwesomeBar.getPaddingBottom() };
|
||||
|
||||
GeckoStateListDrawable states = new GeckoStateListDrawable();
|
||||
states.initializeFilter(mColor);
|
||||
states.addState(new int[] { android.R.attr.state_pressed }, resources.getDrawable(R.drawable.address_bar_url_pressed));
|
||||
states.addState(new int[] { }, resources.getDrawable(R.drawable.address_bar_url_default));
|
||||
mAwesomeBar.setBackgroundDrawable(states);
|
||||
|
||||
mAwesomeBar.setPadding(padding[0], padding[1], padding[2], padding[3]);
|
||||
|
||||
mTabs = (ImageButton) findViewById(R.id.tabs);
|
||||
mTabs.setOnClickListener(new Button.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
if (Tabs.getInstance().getCount() > 1)
|
||||
showTabs();
|
||||
else
|
||||
addTab();
|
||||
}
|
||||
});
|
||||
mTabs.setImageLevel(1);
|
||||
|
||||
mCounterColor = 0x99ffffff;
|
||||
|
||||
mTabsCount = (TextSwitcher) findViewById(R.id.tabs_count);
|
||||
mTabsCount.setFactory(new ViewFactory() {
|
||||
public View makeView() {
|
||||
TextView text = new TextView(mContext);
|
||||
text.setGravity(Gravity.CENTER);
|
||||
text.setTextSize(16);
|
||||
text.setTextColor(mCounterColor);
|
||||
text.setTypeface(text.getTypeface(), Typeface.BOLD);
|
||||
return text;
|
||||
}
|
||||
});
|
||||
mCount = 0;
|
||||
mTabsCount.setText("0");
|
||||
|
||||
mFavicon = (ImageButton) findViewById(R.id.favicon);
|
||||
mSiteSecurity = (ImageButton) findViewById(R.id.site_security);
|
||||
mProgressSpinner = (AnimationDrawable) resources.getDrawable(R.drawable.progress_spinner);
|
||||
|
||||
mStop = (ImageButton) findViewById(R.id.stop);
|
||||
mStop.setOnClickListener(new Button.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
doStop();
|
||||
}
|
||||
});
|
||||
|
||||
mHandler = new Handler();
|
||||
mSlideUpIn = new TranslateAnimation(0, 0, 30, 0);
|
||||
mSlideUpOut = new TranslateAnimation(0, 0, 0, -30);
|
||||
mSlideDownIn = new TranslateAnimation(0, 0, -30, 0);
|
||||
mSlideDownOut = new TranslateAnimation(0, 0, 0, 30);
|
||||
|
||||
mDuration = 750;
|
||||
mSlideUpIn.setDuration(mDuration);
|
||||
mSlideUpOut.setDuration(mDuration);
|
||||
mSlideDownIn.setDuration(mDuration);
|
||||
mSlideDownOut.setDuration(mDuration);
|
||||
}
|
||||
|
||||
private void onAwesomeBarSearch() {
|
||||
GeckoApp.mAppContext.onEditRequested();
|
||||
}
|
||||
|
||||
private void addTab() {
|
||||
GeckoApp.mAppContext.addTab();
|
||||
}
|
||||
|
||||
private void showTabs() {
|
||||
GeckoApp.mAppContext.showTabs();
|
||||
}
|
||||
|
||||
private void doStop() {
|
||||
GeckoApp.mAppContext.doStop();
|
||||
}
|
||||
|
||||
public int getHighlightColor() {
|
||||
return mColor;
|
||||
}
|
||||
|
||||
public void updateTabs(int count) {
|
||||
if (mCount > count) {
|
||||
mTabsCount.setInAnimation(mSlideDownIn);
|
||||
mTabsCount.setOutAnimation(mSlideDownOut);
|
||||
} else if (mCount < count) {
|
||||
mTabsCount.setInAnimation(mSlideUpIn);
|
||||
mTabsCount.setOutAnimation(mSlideUpOut);
|
||||
}
|
||||
|
||||
if (count > 1)
|
||||
mTabs.setImageLevel(count);
|
||||
else
|
||||
mTabs.setImageLevel(0);
|
||||
|
||||
mTabsCount.setVisibility(View.VISIBLE);
|
||||
mTabsCount.setText(String.valueOf(count));
|
||||
mCount = count;
|
||||
|
||||
mHandler.postDelayed(new Runnable() {
|
||||
public void run() {
|
||||
((TextView) mTabsCount.getCurrentView()).setTextColor(mColor);
|
||||
}
|
||||
}, mDuration);
|
||||
|
||||
mHandler.postDelayed(new Runnable() {
|
||||
public void run() {
|
||||
if (Tabs.getInstance().getCount() == 1) {
|
||||
mTabs.setImageLevel(1);
|
||||
mTabsCount.setVisibility(View.GONE);
|
||||
((TextView) mTabsCount.getCurrentView()).setTextColor(mCounterColor);
|
||||
} else {
|
||||
((TextView) mTabsCount.getCurrentView()).setTextColor(mCounterColor);
|
||||
}
|
||||
}
|
||||
}, 2 * mDuration);
|
||||
}
|
||||
|
||||
public void setProgressVisibility(boolean visible) {
|
||||
if (visible) {
|
||||
mFavicon.setImageDrawable(mProgressSpinner);
|
||||
mProgressSpinner.start();
|
||||
setStopVisibility(true);
|
||||
} else {
|
||||
mProgressSpinner.stop();
|
||||
setStopVisibility(false);
|
||||
setFavicon(Tabs.getInstance().getSelectedTab().getFavicon());
|
||||
}
|
||||
}
|
||||
|
||||
public void setStopVisibility(boolean visible) {
|
||||
mStop.setVisibility(visible ? View.VISIBLE : View.GONE);
|
||||
mSiteSecurity.setVisibility(visible ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
|
||||
public void setTitle(CharSequence title) {
|
||||
mAwesomeBar.setText(title);
|
||||
}
|
||||
|
||||
public void setFavicon(Drawable image) {
|
||||
if (Tabs.getInstance().getSelectedTab().isLoading())
|
||||
return;
|
||||
|
||||
if (image != null)
|
||||
mFavicon.setImageDrawable(image);
|
||||
else
|
||||
mFavicon.setImageResource(R.drawable.favicon);
|
||||
}
|
||||
|
||||
public void setSecurityMode(String mode) {
|
||||
if (mode.equals("identified") || mode.equals("verified"))
|
||||
mSiteSecurity.setImageLevel(1);
|
||||
else
|
||||
mSiteSecurity.setImageLevel(0);
|
||||
}
|
||||
}
|
79
mobile/android/base/ConfirmPreference.java
Normal file
@ -0,0 +1,79 @@
|
||||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; 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) 2009-2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brad Lassey <blassey@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 android.content.Context;
|
||||
import android.preference.DialogPreference;
|
||||
import android.provider.Browser;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
|
||||
class ConfirmPreference extends DialogPreference {
|
||||
private static final String LOGTAG = "GeckoConfirmPreference";
|
||||
|
||||
private String mAction = null;
|
||||
private Context mContext = null;
|
||||
public ConfirmPreference(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
mAction = attrs.getAttributeValue(null, "action");
|
||||
mContext = context;
|
||||
}
|
||||
public ConfirmPreference(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
mAction = attrs.getAttributeValue(null, "action");
|
||||
mContext = context;
|
||||
}
|
||||
protected void onDialogClosed(boolean positiveResult) {
|
||||
if (!positiveResult)
|
||||
return;
|
||||
if ("clear_history".equalsIgnoreCase(mAction)) {
|
||||
GeckoAppShell.getHandler().post(new Runnable(){
|
||||
public void run() {
|
||||
Browser.clearHistory(mContext.getContentResolver());
|
||||
}
|
||||
});
|
||||
} else if ("clear_private_data".equalsIgnoreCase(mAction)) {
|
||||
GeckoAppShell.getHandler().post(new Runnable(){
|
||||
public void run() {
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent("Sanitize:ClearAll", null));
|
||||
}
|
||||
});
|
||||
}
|
||||
Log.i(LOGTAG, "action: " + mAction);
|
||||
}
|
||||
}
|
334
mobile/android/base/CrashReporter.java.in
Normal file
@ -0,0 +1,334 @@
|
||||
/* -*- Mode: Java; 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):
|
||||
* Brad Lassey <blassey@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 ***** */
|
||||
|
||||
#filter substitution
|
||||
package @ANDROID_PACKAGE_NAME@;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.FileChannel;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
|
||||
import org.mozilla.gecko.R;
|
||||
|
||||
public class CrashReporter extends Activity
|
||||
{
|
||||
private static final String LOGTAG = "GeckoCrashReporter";
|
||||
|
||||
private static final String PASSED_MINI_DUMP_KEY = "minidumpPath";
|
||||
private static final String MINI_DUMP_PATH_KEY = "upload_file_minidump";
|
||||
private static final String PAGE_URL_KEY = "URL";
|
||||
private static final String NOTES_KEY = "Notes";
|
||||
private static final String SERVER_URL_KEY = "ServerURL";
|
||||
|
||||
private static final String CRASH_REPORT_DIR = "/data/data/@ANDROID_PACKAGE_NAME@/files/mozilla/Crash Reports/";
|
||||
private static final String PENDING_DIR = CRASH_REPORT_DIR + "pending";
|
||||
private static final String SUBMITTED_DIR = CRASH_REPORT_DIR + "submitted";
|
||||
|
||||
private Handler mHandler;
|
||||
private ProgressDialog mProgressDialog;
|
||||
private File mPendingMinidumpFile;
|
||||
private File mPendingExtrasFile;
|
||||
private HashMap<String, String> mExtrasStringMap;
|
||||
|
||||
private boolean moveFile(File inFile, File outFile) {
|
||||
Log.i(LOGTAG, "moving " + inFile + " to " + outFile);
|
||||
if (inFile.renameTo(outFile))
|
||||
return true;
|
||||
try {
|
||||
outFile.createNewFile();
|
||||
Log.i(LOGTAG, "couldn't rename minidump file");
|
||||
// so copy it instead
|
||||
FileChannel inChannel = new FileInputStream(inFile).getChannel();
|
||||
FileChannel outChannel = new FileOutputStream(outFile).getChannel();
|
||||
long transferred = inChannel.transferTo(0, inChannel.size(), outChannel);
|
||||
inChannel.close();
|
||||
outChannel.close();
|
||||
|
||||
if (transferred > 0)
|
||||
inFile.delete();
|
||||
} catch (Exception e) {
|
||||
Log.e(LOGTAG, "exception while copying minidump file: ", e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void doFinish() {
|
||||
if (mHandler != null) {
|
||||
mHandler.post(new Runnable() {
|
||||
public void run() {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
mProgressDialog.dismiss();
|
||||
super.finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
// mHandler is created here so runnables can be run on the main thread
|
||||
mHandler = new Handler();
|
||||
setContentView(R.layout.crash_reporter);
|
||||
mProgressDialog = new ProgressDialog(this);
|
||||
mProgressDialog.setMessage(getString(R.string.sending_crash_report));
|
||||
|
||||
final Button restartButton = (Button) findViewById(R.id.restart);
|
||||
final Button closeButton = (Button) findViewById(R.id.close);
|
||||
String passedMinidumpPath = getIntent().getStringExtra(PASSED_MINI_DUMP_KEY);
|
||||
File passedMinidumpFile = new File(passedMinidumpPath);
|
||||
File pendingDir = new File(PENDING_DIR);
|
||||
pendingDir.mkdirs();
|
||||
mPendingMinidumpFile = new File(pendingDir, passedMinidumpFile.getName());
|
||||
moveFile(passedMinidumpFile, mPendingMinidumpFile);
|
||||
|
||||
File extrasFile = new File(passedMinidumpPath.replaceAll(".dmp", ".extra"));
|
||||
mPendingExtrasFile = new File(pendingDir, extrasFile.getName());
|
||||
moveFile(extrasFile, mPendingExtrasFile);
|
||||
|
||||
mExtrasStringMap = new HashMap<String, String>();
|
||||
readStringsFromFile(mPendingExtrasFile.getPath(), mExtrasStringMap);
|
||||
}
|
||||
|
||||
private void backgroundSendReport() {
|
||||
final CheckBox sendReportCheckbox = (CheckBox) findViewById(R.id.send_report);
|
||||
if (!sendReportCheckbox.isChecked()) {
|
||||
doFinish();
|
||||
return;
|
||||
}
|
||||
|
||||
mProgressDialog.show();
|
||||
new Thread(new Runnable() {
|
||||
public void run() {
|
||||
sendReport(mPendingMinidumpFile, mExtrasStringMap, mPendingExtrasFile);
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
public void onCloseClick(View v) { // bound via crash_reporter.xml
|
||||
backgroundSendReport();
|
||||
}
|
||||
|
||||
public void onRestartClick(View v) { // bound via crash_reporter.xml
|
||||
doRestart();
|
||||
backgroundSendReport();
|
||||
}
|
||||
|
||||
private boolean readStringsFromFile(String filePath, Map<String, String> stringMap) {
|
||||
try {
|
||||
BufferedReader reader = new BufferedReader(new FileReader(filePath));
|
||||
return readStringsFromReader(reader, stringMap);
|
||||
} catch (Exception e) {
|
||||
Log.e(LOGTAG, "exception while reading strings: ", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean readStringsFromReader(BufferedReader reader, Map<String, String> stringMap) throws IOException {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
int equalsPos = -1;
|
||||
if ((equalsPos = line.indexOf('=')) != -1) {
|
||||
String key = line.substring(0, equalsPos);
|
||||
String val = unescape(line.substring(equalsPos + 1));
|
||||
stringMap.put(key, val);
|
||||
}
|
||||
}
|
||||
reader.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
private String generateBoundary() {
|
||||
// Generate some random numbers to fill out the boundary
|
||||
int r0 = (int)((double)Integer.MAX_VALUE * Math.random());
|
||||
int r1 = (int)((double)Integer.MAX_VALUE * Math.random());
|
||||
return String.format("---------------------------%08X%08X", r0, r1);
|
||||
}
|
||||
|
||||
private void sendPart(OutputStream os, String boundary, String name, String data) {
|
||||
try {
|
||||
os.write(("--" + boundary + "\r\n" +
|
||||
"Content-Disposition: form-data; name=\"" + name + "\"\r\n" +
|
||||
"\r\n" +
|
||||
data + "\r\n"
|
||||
).getBytes());
|
||||
} catch (Exception ex) {
|
||||
Log.e(LOGTAG, "Exception when sending \"" + name + "\"", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendFile(OutputStream os, String boundary, String name, File file) throws IOException {
|
||||
os.write(("--" + boundary + "\r\n" +
|
||||
"Content-Disposition: form-data; name=\"" + name + "\"; " +
|
||||
"filename=\"" + file.getName() + "\"\r\n" +
|
||||
"Content-Type: application/octet-stream\r\n" +
|
||||
"\r\n"
|
||||
).getBytes());
|
||||
FileChannel fc = new FileInputStream(file).getChannel();
|
||||
fc.transferTo(0, fc.size(), Channels.newChannel(os));
|
||||
fc.close();
|
||||
}
|
||||
|
||||
private void sendReport(File minidumpFile, Map<String, String> extras, File extrasFile) {
|
||||
Log.i(LOGTAG, "sendReport: " + minidumpFile.getPath());
|
||||
final CheckBox includeURLCheckbox = (CheckBox) findViewById(R.id.include_url);
|
||||
|
||||
String spec = extras.get(SERVER_URL_KEY);
|
||||
if (spec == null)
|
||||
doFinish();
|
||||
|
||||
Log.i(LOGTAG, "server url: " + spec);
|
||||
try {
|
||||
URL url = new URL(spec);
|
||||
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
|
||||
conn.setRequestMethod("POST");
|
||||
String boundary = generateBoundary();
|
||||
conn.setDoOutput(true);
|
||||
conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
|
||||
|
||||
OutputStream os = conn.getOutputStream();
|
||||
for (String key : extras.keySet()) {
|
||||
if (key.equals(PAGE_URL_KEY)) {
|
||||
if (includeURLCheckbox.isChecked())
|
||||
sendPart(os, boundary, key, extras.get(key));
|
||||
} else if (!key.equals(SERVER_URL_KEY) && !key.equals(NOTES_KEY)) {
|
||||
sendPart(os, boundary, key, extras.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
// Add some extra information to notes so its displayed by
|
||||
// crash-stats.mozilla.org. Remove this when bug 607942 is fixed.
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(extras.containsKey(NOTES_KEY) ? extras.get(NOTES_KEY) + "\n" : "");
|
||||
if (@MOZ_MIN_CPU_VERSION@ < 7)
|
||||
sb.append("nothumb Build\n");
|
||||
sb.append(Build.MANUFACTURER).append(' ')
|
||||
.append(Build.MODEL).append('\n')
|
||||
.append(Build.FINGERPRINT);
|
||||
sendPart(os, boundary, NOTES_KEY, sb.toString());
|
||||
|
||||
sendPart(os, boundary, "Min_ARM_Version", "@MOZ_MIN_CPU_VERSION@");
|
||||
sendPart(os, boundary, "Android_Manufacturer", Build.MANUFACTURER);
|
||||
sendPart(os, boundary, "Android_Model", Build.MODEL);
|
||||
sendPart(os, boundary, "Android_Board", Build.BOARD);
|
||||
sendPart(os, boundary, "Android_Brand", Build.BRAND);
|
||||
sendPart(os, boundary, "Android_Device", Build.DEVICE);
|
||||
sendPart(os, boundary, "Android_Display", Build.DISPLAY);
|
||||
sendPart(os, boundary, "Android_Fingerprint", Build.FINGERPRINT);
|
||||
sendPart(os, boundary, "Android_CPU_ABI", Build.CPU_ABI);
|
||||
if (Build.VERSION.SDK_INT >= 8) {
|
||||
try {
|
||||
sendPart(os, boundary, "Android_CPU_ABI2", Build.CPU_ABI2);
|
||||
sendPart(os, boundary, "Android_Hardware", Build.HARDWARE);
|
||||
} catch (Exception ex) {
|
||||
Log.e(LOGTAG, "Exception while sending SDK version 8 keys", ex);
|
||||
}
|
||||
}
|
||||
sendPart(os, boundary, "Android_Version", Build.VERSION.SDK_INT + " (" + Build.VERSION.CODENAME + ")");
|
||||
|
||||
sendFile(os, boundary, MINI_DUMP_PATH_KEY, minidumpFile);
|
||||
os.write(("\r\n--" + boundary + "--\r\n").getBytes());
|
||||
os.flush();
|
||||
os.close();
|
||||
BufferedReader br = new BufferedReader(
|
||||
new InputStreamReader(conn.getInputStream()));
|
||||
HashMap<String, String> responseMap = new HashMap<String, String>();
|
||||
readStringsFromReader(br, responseMap);
|
||||
|
||||
if (conn.getResponseCode() == conn.HTTP_OK) {
|
||||
File submittedDir = new File(SUBMITTED_DIR);
|
||||
submittedDir.mkdirs();
|
||||
minidumpFile.delete();
|
||||
extrasFile.delete();
|
||||
String crashid = responseMap.get("CrashID");
|
||||
File file = new File(submittedDir, crashid + ".txt");
|
||||
FileOutputStream fos = new FileOutputStream(file);
|
||||
fos.write("Crash ID: ".getBytes());
|
||||
fos.write(crashid.getBytes());
|
||||
fos.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(LOGTAG, "exception during send: ", e);
|
||||
}
|
||||
|
||||
doFinish();
|
||||
}
|
||||
|
||||
private void doRestart() {
|
||||
try {
|
||||
String action = "android.intent.action.MAIN";
|
||||
Intent intent = new Intent(action);
|
||||
intent.setClassName("@ANDROID_PACKAGE_NAME@",
|
||||
"@ANDROID_PACKAGE_NAME@.App");
|
||||
Log.i(LOGTAG, intent.toString());
|
||||
startActivity(intent);
|
||||
} catch (Exception e) {
|
||||
Log.e(LOGTAG, "error while trying to restart", e);
|
||||
}
|
||||
}
|
||||
|
||||
private String unescape(String string) {
|
||||
return string.replaceAll("\\\\", "\\").replaceAll("\\n", "\n").replaceAll("\\t", "\t");
|
||||
}
|
||||
}
|
162
mobile/android/base/DoorHanger.java
Normal file
@ -0,0 +1,162 @@
|
||||
/* -*- 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) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Gian-Carlo Pascutto <gpascutto@mozilla.com>
|
||||
* Sriram Ramasubramanian <sriram@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.util.Date;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.LinearLayout.LayoutParams;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import org.json.JSONException;
|
||||
|
||||
public class DoorHanger extends LinearLayout implements Button.OnClickListener {
|
||||
private Context mContext;
|
||||
private LinearLayout mChoicesLayout;
|
||||
private TextView mTextView;
|
||||
private Button mButton;
|
||||
private LayoutParams mLayoutParams;
|
||||
public Tab mTab;
|
||||
// value used to identify the notification
|
||||
private String mValue;
|
||||
|
||||
private int mPersistence = 0;
|
||||
private long mTimeout = 0;
|
||||
|
||||
public DoorHanger(Context aContext, String aValue) {
|
||||
super(aContext);
|
||||
|
||||
mContext = aContext;
|
||||
mValue = aValue;
|
||||
|
||||
setOrientation(VERTICAL);
|
||||
setBackgroundResource(R.drawable.doorhanger_shadow_bg);
|
||||
|
||||
// Load layout into the custom view
|
||||
LayoutInflater inflater =
|
||||
(LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
inflater.inflate(R.layout.doorhanger, this);
|
||||
hide();
|
||||
|
||||
mTextView = (TextView) findViewById(R.id.doorhanger_title);
|
||||
mChoicesLayout = (LinearLayout) findViewById(R.id.doorhanger_choices);
|
||||
|
||||
mLayoutParams = new LayoutParams(LayoutParams.FILL_PARENT,
|
||||
LayoutParams.FILL_PARENT,
|
||||
1.0f);
|
||||
}
|
||||
|
||||
public void addButton(String aText, int aCallback) {
|
||||
Button mButton = new Button(mContext);
|
||||
mButton.setText(aText);
|
||||
mButton.setTag(Integer.toString(aCallback));
|
||||
mButton.setOnClickListener(this);
|
||||
mChoicesLayout.addView(mButton, mLayoutParams);
|
||||
}
|
||||
|
||||
public void onClick(View v) {
|
||||
GeckoEvent e = new GeckoEvent("Doorhanger:Reply", v.getTag().toString());
|
||||
GeckoAppShell.sendEventToGecko(e);
|
||||
mTab.removeDoorHanger(mValue);
|
||||
|
||||
// This will hide the doorhanger (and hide the popup if there are no
|
||||
// more doorhangers to show)
|
||||
GeckoApp.mDoorHangerPopup.updatePopup();
|
||||
}
|
||||
|
||||
public void show() {
|
||||
setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
public void hide() {
|
||||
setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
return getVisibility() == View.VISIBLE;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
public void setText(String aText) {
|
||||
mTextView.setText(aText);
|
||||
}
|
||||
|
||||
public Tab getTab() {
|
||||
return mTab;
|
||||
}
|
||||
|
||||
public void setTab(Tab tab) {
|
||||
mTab = tab;
|
||||
}
|
||||
|
||||
public void setOptions(JSONObject options) {
|
||||
try {
|
||||
mPersistence = options.getInt("persistence");
|
||||
} catch (JSONException e) { }
|
||||
|
||||
try {
|
||||
mTimeout = options.getLong("timeout");
|
||||
} catch (JSONException e) { }
|
||||
}
|
||||
|
||||
// This method checks with persistence and timeout options to see if
|
||||
// it's okay to remove a doorhanger.
|
||||
public boolean shouldRemove() {
|
||||
// If persistence is set to -1, the doorhanger will never be
|
||||
// automatically removed.
|
||||
if (mPersistence != 0) {
|
||||
mPersistence--;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (new Date().getTime() <= mTimeout) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
163
mobile/android/base/DoorHangerPopup.java
Normal file
@ -0,0 +1,163 @@
|
||||
/* -*- 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) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Gian-Carlo Pascutto <gpascutto@mozilla.com>
|
||||
* Sriram Ramasubramanian <sriram@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.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.PopupWindow;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.LinearLayout.LayoutParams;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.json.JSONException;
|
||||
|
||||
public class DoorHangerPopup extends PopupWindow {
|
||||
private static final String LOGTAG = "GeckoDoorHangerPopup";
|
||||
|
||||
private Context mContext;
|
||||
private LinearLayout mContent;
|
||||
|
||||
public DoorHangerPopup(Context aContext) {
|
||||
super(aContext);
|
||||
mContext = aContext;
|
||||
|
||||
setBackgroundDrawable(new BitmapDrawable());
|
||||
setOutsideTouchable(true);
|
||||
setWindowLayoutMode(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
|
||||
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
RelativeLayout layout = (RelativeLayout) inflater.inflate(R.layout.doorhangerpopup, null);
|
||||
mContent = (LinearLayout) layout.findViewById(R.id.doorhanger_container);
|
||||
|
||||
setContentView(layout);
|
||||
}
|
||||
|
||||
public void addDoorHanger(String message, String value, JSONArray buttons,
|
||||
Tab tab, JSONObject options) {
|
||||
Log.i(LOGTAG, "Adding a DoorHanger to Tab: " + tab.getId());
|
||||
|
||||
// Replace the doorhanger if it already exists
|
||||
DoorHanger dh = tab.getDoorHanger(value);
|
||||
if (dh != null) {
|
||||
tab.removeDoorHanger(value);
|
||||
}
|
||||
dh = new DoorHanger(mContent.getContext(), value);
|
||||
|
||||
// Set the doorhanger text and buttons
|
||||
dh.setText(message);
|
||||
for (int i = 0; i < buttons.length(); i++) {
|
||||
try {
|
||||
JSONObject buttonObject = buttons.getJSONObject(i);
|
||||
String label = buttonObject.getString("label");
|
||||
int callBackId = buttonObject.getInt("callback");
|
||||
dh.addButton(label, callBackId);
|
||||
} catch (JSONException e) {
|
||||
Log.i(LOGTAG, "JSON throws " + e);
|
||||
}
|
||||
}
|
||||
dh.setOptions(options);
|
||||
|
||||
dh.setTab(tab);
|
||||
tab.addDoorHanger(value, dh);
|
||||
mContent.addView(dh);
|
||||
|
||||
updatePopup();
|
||||
}
|
||||
|
||||
// Updates popup contents to show doorhangers for the selected tab
|
||||
public void updatePopup() {
|
||||
Tab tab = Tabs.getInstance().getSelectedTab();
|
||||
Log.i(LOGTAG, "Showing all doorhangers for tab: " + tab.getId());
|
||||
|
||||
HashMap<String, DoorHanger> doorHangers = tab.getDoorHangers();
|
||||
// Hide the popup if there aren't any doorhangers to show
|
||||
if (doorHangers == null || doorHangers.size() == 0) {
|
||||
hidePopup();
|
||||
return;
|
||||
}
|
||||
|
||||
// Hide old doorhangers
|
||||
for (int i = 0; i < mContent.getChildCount(); i++) {
|
||||
DoorHanger dh = (DoorHanger) mContent.getChildAt(i);
|
||||
dh.hide();
|
||||
}
|
||||
|
||||
// Show the doorhangers for the tab
|
||||
for (DoorHanger dh : doorHangers.values()) {
|
||||
dh.show();
|
||||
}
|
||||
|
||||
showPopup();
|
||||
}
|
||||
|
||||
public void hidePopup() {
|
||||
if (isShowing()) {
|
||||
Log.i(LOGTAG, "Hiding the DoorHangerPopup");
|
||||
dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
public void showPopup() {
|
||||
Log.i(LOGTAG, "Showing the DoorHangerPopup");
|
||||
fixBackgroundForFirst();
|
||||
|
||||
if (isShowing())
|
||||
update();
|
||||
else
|
||||
showAsDropDown(GeckoApp.mBrowserToolbar.mFavicon);
|
||||
}
|
||||
|
||||
private void fixBackgroundForFirst() {
|
||||
for (int i=0; i < mContent.getChildCount(); i++) {
|
||||
DoorHanger dh = (DoorHanger) mContent.getChildAt(i);
|
||||
if (dh.isVisible()) {
|
||||
dh.setBackgroundResource(R.drawable.doorhanger_bg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
422
mobile/android/base/Favicons.java
Normal file
@ -0,0 +1,422 @@
|
||||
/* -*- 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) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Lucas Rocha <lucasr@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 android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.database.sqlite.SQLiteQueryBuilder;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.AsyncTask;
|
||||
import android.provider.Browser;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class Favicons {
|
||||
private static final String LOGTAG = "GeckoFavicons";
|
||||
|
||||
public static final long NOT_LOADING = 0;
|
||||
|
||||
private Context mContext;
|
||||
private DatabaseHelper mDbHelper;
|
||||
|
||||
private Map<Long,LoadFaviconTask> mLoadTasks;
|
||||
private long mNextFaviconLoadId;
|
||||
|
||||
public interface OnFaviconLoadedListener {
|
||||
public void onFaviconLoaded(String url, Drawable favicon);
|
||||
}
|
||||
|
||||
private class DatabaseHelper extends SQLiteOpenHelper {
|
||||
private static final String DATABASE_NAME = "favicon_urls.db";
|
||||
private static final String TABLE_NAME = "favicon_urls";
|
||||
private static final int DATABASE_VERSION = 1;
|
||||
|
||||
private static final String COLUMN_ID = "_id";
|
||||
private static final String COLUMN_FAVICON_URL = "favicon_url";
|
||||
private static final String COLUMN_PAGE_URL = "page_url";
|
||||
|
||||
DatabaseHelper(Context context) {
|
||||
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
||||
Log.d(LOGTAG, "Creating DatabaseHelper");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(SQLiteDatabase db) {
|
||||
Log.d(LOGTAG, "Creating database for favicon URLs");
|
||||
|
||||
db.execSQL("CREATE TABLE " + TABLE_NAME + " (" +
|
||||
COLUMN_ID + " INTEGER PRIMARY KEY," +
|
||||
COLUMN_FAVICON_URL + " TEXT NOT NULL," +
|
||||
COLUMN_PAGE_URL + " TEXT UNIQUE NOT NULL" +
|
||||
");");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
Log.w(LOGTAG, "Upgrading favicon URLs database from version " +
|
||||
oldVersion + " to " + newVersion + ", which will destroy all old data");
|
||||
|
||||
// Drop table completely
|
||||
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
|
||||
|
||||
// Recreate database
|
||||
onCreate(db);
|
||||
}
|
||||
|
||||
public String getFaviconUrlForPageUrl(String pageUrl) {
|
||||
Log.d(LOGTAG, "Calling getFaviconUrlForPageUrl() for " + pageUrl);
|
||||
|
||||
SQLiteDatabase db = mDbHelper.getReadableDatabase();
|
||||
|
||||
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
|
||||
qb.setTables(TABLE_NAME);
|
||||
|
||||
Cursor c = qb.query(
|
||||
db,
|
||||
new String[] { COLUMN_FAVICON_URL },
|
||||
COLUMN_PAGE_URL + " = ?",
|
||||
new String[] { pageUrl },
|
||||
null, null, null
|
||||
);
|
||||
|
||||
if (!c.moveToFirst())
|
||||
return null;
|
||||
|
||||
String url = c.getString(c.getColumnIndexOrThrow(COLUMN_FAVICON_URL));
|
||||
c.close();
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setFaviconUrlForPageUrl(String pageUrl, String faviconUrl) {
|
||||
Log.d(LOGTAG, "Calling setFaviconUrlForPageUrl() for " + pageUrl);
|
||||
|
||||
SQLiteDatabase db = mDbHelper.getWritableDatabase();
|
||||
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(COLUMN_FAVICON_URL, faviconUrl);
|
||||
values.put(COLUMN_PAGE_URL, pageUrl);
|
||||
|
||||
db.replace(TABLE_NAME, null, values);
|
||||
}
|
||||
}
|
||||
|
||||
public Favicons(Context context) {
|
||||
Log.d(LOGTAG, "Creating Favicons instance");
|
||||
|
||||
mContext = context;
|
||||
mDbHelper = new DatabaseHelper(context);
|
||||
|
||||
mLoadTasks = new HashMap<Long,LoadFaviconTask>();
|
||||
mNextFaviconLoadId = 0;
|
||||
}
|
||||
|
||||
public long loadFavicon(String pageUrl, String faviconUrl,
|
||||
OnFaviconLoadedListener listener) {
|
||||
|
||||
// Handle the case where page url is empty
|
||||
if (pageUrl == null || pageUrl.length() == 0) {
|
||||
if (listener != null)
|
||||
listener.onFaviconLoaded(null, null);
|
||||
}
|
||||
|
||||
LoadFaviconTask task = new LoadFaviconTask(pageUrl, faviconUrl, listener);
|
||||
|
||||
long taskId = task.getId();
|
||||
mLoadTasks.put(taskId, task);
|
||||
|
||||
task.execute();
|
||||
|
||||
Log.d(LOGTAG, "Calling loadFavicon() with URL = " + pageUrl +
|
||||
" and favicon URL = " + faviconUrl +
|
||||
" (" + taskId + ")");
|
||||
|
||||
return taskId;
|
||||
}
|
||||
|
||||
public boolean cancelFaviconLoad(long taskId) {
|
||||
Log.d(LOGTAG, "Requesting cancelation of favicon load (" + taskId + ")");
|
||||
|
||||
if (!mLoadTasks.containsKey(taskId))
|
||||
return false;
|
||||
|
||||
Log.d(LOGTAG, "Cancelling favicon load (" + taskId + ")");
|
||||
|
||||
LoadFaviconTask task = mLoadTasks.get(taskId);
|
||||
return task.cancel(false);
|
||||
}
|
||||
|
||||
public void close() {
|
||||
Log.d(LOGTAG, "Closing Favicons database");
|
||||
mDbHelper.close();
|
||||
|
||||
// Cancel any pending tasks
|
||||
Set<Long> taskIds = mLoadTasks.keySet();
|
||||
Iterator iter = taskIds.iterator();
|
||||
while (iter.hasNext()) {
|
||||
long taskId = (Long) iter.next();
|
||||
cancelFaviconLoad(taskId);
|
||||
}
|
||||
}
|
||||
|
||||
private class LoadFaviconTask extends AsyncTask<Void, Void, BitmapDrawable> {
|
||||
private long mId;
|
||||
private String mPageUrl;
|
||||
private String mFaviconUrl;
|
||||
private OnFaviconLoadedListener mListener;
|
||||
|
||||
public LoadFaviconTask(String pageUrl, String faviconUrl, OnFaviconLoadedListener listener) {
|
||||
mId = ++mNextFaviconLoadId;
|
||||
mPageUrl = pageUrl;
|
||||
mFaviconUrl = faviconUrl;
|
||||
mListener = listener;
|
||||
|
||||
Log.d(LOGTAG, "Creating LoadFaviconTask with URL = " + pageUrl +
|
||||
" and favicon URL = " + faviconUrl);
|
||||
}
|
||||
|
||||
// Runs in background thread
|
||||
private BitmapDrawable loadFaviconFromDb() {
|
||||
Log.d(LOGTAG, "Loading favicon from DB for URL = " + mPageUrl);
|
||||
|
||||
ContentResolver resolver = mContext.getContentResolver();
|
||||
|
||||
Cursor c = resolver.query(Browser.BOOKMARKS_URI,
|
||||
new String[] { Browser.BookmarkColumns.FAVICON },
|
||||
Browser.BookmarkColumns.URL + " = ?",
|
||||
new String[] { mPageUrl },
|
||||
null);
|
||||
|
||||
if (!c.moveToFirst()) {
|
||||
c.close();
|
||||
return null;
|
||||
}
|
||||
|
||||
int faviconIndex = c.getColumnIndexOrThrow(Browser.BookmarkColumns.FAVICON);
|
||||
|
||||
byte[] b = c.getBlob(faviconIndex);
|
||||
c.close();
|
||||
if (b == null)
|
||||
return null;
|
||||
|
||||
Bitmap bitmap = BitmapFactory.decodeByteArray(b, 0, b.length);
|
||||
|
||||
Log.d(LOGTAG, "Loaded favicon from DB successfully for URL = " + mPageUrl);
|
||||
|
||||
return new BitmapDrawable(bitmap);
|
||||
}
|
||||
|
||||
// Runs in background thread
|
||||
private void saveFaviconToDb(BitmapDrawable favicon) {
|
||||
Bitmap bitmap = favicon.getBitmap();
|
||||
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
|
||||
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(Browser.BookmarkColumns.FAVICON, stream.toByteArray());
|
||||
values.put(Browser.BookmarkColumns.URL, mPageUrl);
|
||||
|
||||
ContentResolver resolver = mContext.getContentResolver();
|
||||
|
||||
Log.d(LOGTAG, "Saving favicon on browser database for URL = " + mPageUrl);
|
||||
resolver.update(Browser.BOOKMARKS_URI,
|
||||
values,
|
||||
Browser.BookmarkColumns.URL + " = ?",
|
||||
new String[] { mPageUrl });
|
||||
|
||||
|
||||
Log.d(LOGTAG, "Saving favicon URL for URL = " + mPageUrl);
|
||||
mDbHelper.setFaviconUrlForPageUrl(mPageUrl, mFaviconUrl);
|
||||
}
|
||||
|
||||
// Runs in background thread
|
||||
private BitmapDrawable downloadFavicon(URL faviconUrl) {
|
||||
Log.d(LOGTAG, "Downloading favicon for URL = " + mPageUrl +
|
||||
" with favicon URL = " + mFaviconUrl);
|
||||
|
||||
// due to android bug 6066, we must download the entire image before using it
|
||||
// http://code.google.com/p/android/issues/detail?id=6066
|
||||
HttpURLConnection urlConnection = null;
|
||||
BufferedInputStream contentStream = null;
|
||||
ByteArrayInputStream byteStream = null;
|
||||
BitmapDrawable image = null;
|
||||
|
||||
try {
|
||||
urlConnection = (HttpURLConnection) faviconUrl.openConnection();
|
||||
int length = urlConnection.getContentLength();
|
||||
contentStream = new BufferedInputStream(urlConnection.getInputStream(), length);
|
||||
byte[] bytes = new byte[length];
|
||||
int pos = 0;
|
||||
int offset = 0;
|
||||
while ((pos = contentStream.read(bytes, offset, length - offset)) > 0)
|
||||
offset += pos;
|
||||
if (length == offset) {
|
||||
byteStream = new ByteArrayInputStream(bytes);
|
||||
image = (BitmapDrawable) Drawable.createFromStream(byteStream, "src");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.d(LOGTAG, "Error downloading favicon: " + e);
|
||||
} finally {
|
||||
if (urlConnection != null)
|
||||
urlConnection.disconnect();
|
||||
try {
|
||||
if (contentStream != null)
|
||||
contentStream.close();
|
||||
if (byteStream != null)
|
||||
byteStream.close();
|
||||
} catch (IOException e) {
|
||||
Log.d(LOGTAG, "error closing favicon stream");
|
||||
}
|
||||
}
|
||||
|
||||
if (image != null) {
|
||||
Log.d(LOGTAG, "Downloaded favicon successfully for URL = " + mPageUrl);
|
||||
saveFaviconToDb(image);
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BitmapDrawable doInBackground(Void... unused) {
|
||||
BitmapDrawable image = null;
|
||||
URL pageUrl = null;
|
||||
|
||||
if (isCancelled())
|
||||
return null;
|
||||
|
||||
// Handle the case of malformed URL
|
||||
try {
|
||||
pageUrl = new URL(mPageUrl);
|
||||
} catch (MalformedURLException e) {
|
||||
Log.d(LOGTAG, "The provided URL is not valid: " + e);
|
||||
return null;
|
||||
}
|
||||
|
||||
URL faviconUrl = null;
|
||||
|
||||
// Handle the case of malformed favicon URL
|
||||
try {
|
||||
// If favicon is empty, fallback to default favicon URI
|
||||
if (mFaviconUrl == null || mFaviconUrl.length() == 0) {
|
||||
faviconUrl = new URL(pageUrl.getProtocol(), pageUrl.getAuthority(), "/favicon.ico");
|
||||
mFaviconUrl = faviconUrl.toString();
|
||||
} else {
|
||||
faviconUrl = new URL(mFaviconUrl);
|
||||
}
|
||||
} catch (MalformedURLException e) {
|
||||
Log.d(LOGTAG, "The provided favicon URL is not valid: " + e);
|
||||
return null;
|
||||
}
|
||||
|
||||
Log.d(LOGTAG, "Favicon URL is now: " + mFaviconUrl);
|
||||
|
||||
if (isCancelled())
|
||||
return null;
|
||||
|
||||
String storedFaviconUrl = mDbHelper.getFaviconUrlForPageUrl(mPageUrl);
|
||||
if (storedFaviconUrl != null && storedFaviconUrl.equals(mFaviconUrl)) {
|
||||
image = loadFaviconFromDb();
|
||||
|
||||
if (isCancelled())
|
||||
return null;
|
||||
|
||||
// If favicon URL is defined but the favicon image is not
|
||||
// stored in the database for some reason, we force download.
|
||||
if (image == null) {
|
||||
image = downloadFavicon(faviconUrl);
|
||||
}
|
||||
} else {
|
||||
image = downloadFavicon(faviconUrl);
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(final BitmapDrawable image) {
|
||||
Log.d(LOGTAG, "LoadFaviconTask finished for URL = " + mPageUrl +
|
||||
" (" + mId + ")");
|
||||
|
||||
mLoadTasks.remove(mId);
|
||||
|
||||
if (mListener != null) {
|
||||
// We want to always run the listener on UI thread
|
||||
GeckoApp.mAppContext.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
mListener.onFaviconLoaded(mPageUrl, image);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCancelled() {
|
||||
Log.d(LOGTAG, "LoadFaviconTask cancelled for URL = " + mPageUrl +
|
||||
" (" + mId + ")");
|
||||
|
||||
mLoadTasks.remove(mId);
|
||||
|
||||
// Note that we don't call the listener callback if the
|
||||
// favicon load is cancelled.
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return mId;
|
||||
}
|
||||
}
|
||||
}
|
1912
mobile/android/base/GeckoApp.java
Normal file
1577
mobile/android/base/GeckoAppShell.java
Normal file
57
mobile/android/base/GeckoAsyncTask.java
Normal file
@ -0,0 +1,57 @@
|
||||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; 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) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brad Lassey <blassey@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;
|
||||
|
||||
// AsyncTask runs onPostExecute on the thread it is constructed on
|
||||
// We construct these off of the main thread, and we want that to run
|
||||
// on the main UI thread, so this is a convenience class to do that
|
||||
public abstract class GeckoAsyncTask<Params, Progress, Result> {
|
||||
public void execute(final Params... params) {
|
||||
GeckoAppShell.getHandler().post(new Runnable() {
|
||||
public void run() {
|
||||
final Result result = doInBackground(params);
|
||||
GeckoApp.mAppContext.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
onPostExecute(result);
|
||||
}});
|
||||
}});
|
||||
}
|
||||
|
||||
protected abstract Result doInBackground(Params... params);
|
||||
protected abstract void onPostExecute(Result result);
|
||||
}
|
183
mobile/android/base/GeckoBatteryManager.java
Normal file
@ -0,0 +1,183 @@
|
||||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; 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) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
|
||||
*
|
||||
* 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.lang.Math;
|
||||
import java.util.Date;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import android.os.BatteryManager;
|
||||
|
||||
public class GeckoBatteryManager
|
||||
extends BroadcastReceiver
|
||||
{
|
||||
private static final String LOGTAG = "GeckoBatteryManager";
|
||||
|
||||
// Those constants should be keep in sync with the ones in:
|
||||
// dom/battery/Constants.h
|
||||
private final static double kDefaultLevel = 1.0;
|
||||
private final static boolean kDefaultCharging = true;
|
||||
private final static double kUnknownRemainingTime = -1.0;
|
||||
|
||||
private static Date sLastLevelChange = new Date(0);
|
||||
private static boolean sNotificationsEnabled = false;
|
||||
private static double sLevel = kDefaultLevel;
|
||||
private static boolean sCharging = kDefaultCharging;
|
||||
private static double sRemainingTime = kUnknownRemainingTime;;
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (!intent.getAction().equals(Intent.ACTION_BATTERY_CHANGED)) {
|
||||
Log.e(LOGTAG, "Got an unexpected intent!");
|
||||
return;
|
||||
}
|
||||
|
||||
boolean previousCharging = isCharging();
|
||||
double previousLevel = getLevel();
|
||||
|
||||
if (intent.getBooleanExtra(BatteryManager.EXTRA_PRESENT, false)) {
|
||||
int plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
|
||||
if (plugged == -1) {
|
||||
sCharging = kDefaultCharging;
|
||||
Log.e(LOGTAG, "Failed to get the plugged status!");
|
||||
} else {
|
||||
// Likely, if plugged > 0, it's likely plugged and charging but the doc
|
||||
// isn't clear about that.
|
||||
sCharging = plugged != 0;
|
||||
}
|
||||
|
||||
if (sCharging != previousCharging) {
|
||||
sRemainingTime = kUnknownRemainingTime;
|
||||
// The new remaining time is going to take some time to show up but
|
||||
// it's the best way to show a not too wrong value.
|
||||
sLastLevelChange = new Date(0);
|
||||
}
|
||||
|
||||
// We need two doubles because sLevel is a double.
|
||||
double current = (double)intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
|
||||
double max = (double)intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
|
||||
if (current == -1 || max == -1) {
|
||||
Log.e(LOGTAG, "Failed to get battery level!");
|
||||
sLevel = kDefaultLevel;
|
||||
} else {
|
||||
sLevel = current / max;
|
||||
}
|
||||
|
||||
if (sLevel == 1.0 && sCharging) {
|
||||
sRemainingTime = 0.0;
|
||||
} else if (sLevel != previousLevel) {
|
||||
// Estimate remaining time.
|
||||
if (sLastLevelChange.getTime() != 0) {
|
||||
Date currentTime = new Date();
|
||||
long dt = (currentTime.getTime() - sLastLevelChange.getTime()) / 1000;
|
||||
double dLevel = sLevel - previousLevel;
|
||||
|
||||
if (sCharging) {
|
||||
if (dLevel < 0) {
|
||||
Log.w(LOGTAG, "When charging, level should increase!");
|
||||
sRemainingTime = kUnknownRemainingTime;
|
||||
} else {
|
||||
sRemainingTime = Math.round(dt / dLevel * (1.0 - sLevel));
|
||||
}
|
||||
} else {
|
||||
if (dLevel > 0) {
|
||||
Log.w(LOGTAG, "When discharging, level should decrease!");
|
||||
sRemainingTime = kUnknownRemainingTime;
|
||||
} else {
|
||||
sRemainingTime = Math.round(dt / -dLevel * sLevel);
|
||||
}
|
||||
}
|
||||
|
||||
sLastLevelChange = currentTime;
|
||||
} else {
|
||||
// That's the first time we got an update, we can't do anything.
|
||||
sLastLevelChange = new Date();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sLevel = kDefaultLevel;
|
||||
sCharging = kDefaultCharging;
|
||||
sRemainingTime = kUnknownRemainingTime;
|
||||
}
|
||||
|
||||
/*
|
||||
* We want to inform listeners if the following conditions are fulfilled:
|
||||
* - we have at least one observer;
|
||||
* - the charging state or the level has changed.
|
||||
*
|
||||
* Note: no need to check for a remaining time change given that it's only
|
||||
* updated if there is a level change or a charging change.
|
||||
*
|
||||
* The idea is to prevent doing all the way to the DOM code in the child
|
||||
* process to finally not send an event.
|
||||
*/
|
||||
if (sNotificationsEnabled &&
|
||||
(previousCharging != isCharging() || previousLevel != getLevel())) {
|
||||
GeckoAppShell.notifyBatteryChange(getLevel(), isCharging(), getRemainingTime());
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isCharging() {
|
||||
return sCharging;
|
||||
}
|
||||
|
||||
public static double getLevel() {
|
||||
return sLevel;
|
||||
}
|
||||
|
||||
public static double getRemainingTime() {
|
||||
return sRemainingTime;
|
||||
}
|
||||
|
||||
public static void enableNotifications() {
|
||||
sNotificationsEnabled = true;
|
||||
}
|
||||
|
||||
public static void disableNotifications() {
|
||||
sNotificationsEnabled = false;
|
||||
}
|
||||
|
||||
public static double[] getCurrentInformation() {
|
||||
return new double[] { getLevel(), isCharging() ? 1.0 : 0.0, getRemainingTime() };
|
||||
}
|
||||
}
|
73
mobile/android/base/GeckoConnectivityReceiver.java
Normal file
@ -0,0 +1,73 @@
|
||||
/* -*- 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) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Makoto Kato <m_kato@ga2.so-net.ne.jp> (Original Author)
|
||||
*
|
||||
* 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 android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
|
||||
public class GeckoConnectivityReceiver
|
||||
extends BroadcastReceiver
|
||||
{
|
||||
/*
|
||||
* Keep the below constants in sync with
|
||||
* http://mxr.mozilla.org/mozilla-central/source/netwerk/base/public/nsINetworkLinkService.idl
|
||||
*/
|
||||
private static final String LINK_DATA_UP = "up";
|
||||
private static final String LINK_DATA_DOWN = "down";
|
||||
private static final String LINK_DATA_UNKNOWN = "unknown";
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String status;
|
||||
ConnectivityManager cm = (ConnectivityManager)
|
||||
context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
NetworkInfo info = cm.getActiveNetworkInfo();
|
||||
if (info == null)
|
||||
status = LINK_DATA_UNKNOWN;
|
||||
else if (!info.isConnected())
|
||||
status = LINK_DATA_DOWN;
|
||||
else
|
||||
status = LINK_DATA_UP;
|
||||
|
||||
if (GeckoApp.checkLaunchState(GeckoApp.LaunchState.GeckoRunning))
|
||||
GeckoAppShell.onChangeNetworkLinkStatus(status);
|
||||
}
|
||||
}
|
241
mobile/android/base/GeckoEvent.java
Normal file
@ -0,0 +1,241 @@
|
||||
/* -*- Mode: Java; tab-width: 4; 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) 2009-2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Vladimir Vukicevic <vladimir@pobox.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 android.os.*;
|
||||
import android.app.*;
|
||||
import android.view.*;
|
||||
import android.content.*;
|
||||
import android.graphics.*;
|
||||
import android.widget.*;
|
||||
import android.hardware.*;
|
||||
import android.location.*;
|
||||
import android.util.FloatMath;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
/* We're not allowed to hold on to most events given to us
|
||||
* so we save the parts of the events we want to use in GeckoEvent.
|
||||
* Fields have different meanings depending on the event type.
|
||||
*/
|
||||
|
||||
public class GeckoEvent {
|
||||
private static final String LOGTAG = "GeckoEvent";
|
||||
|
||||
public static final int INVALID = -1;
|
||||
public static final int NATIVE_POKE = 0;
|
||||
public static final int KEY_EVENT = 1;
|
||||
public static final int MOTION_EVENT = 2;
|
||||
public static final int ORIENTATION_EVENT = 3;
|
||||
public static final int ACCELERATION_EVENT = 4;
|
||||
public static final int LOCATION_EVENT = 5;
|
||||
public static final int IME_EVENT = 6;
|
||||
public static final int DRAW = 7;
|
||||
public static final int SIZE_CHANGED = 8;
|
||||
public static final int ACTIVITY_STOPPING = 9;
|
||||
public static final int ACTIVITY_PAUSING = 10;
|
||||
public static final int ACTIVITY_SHUTDOWN = 11;
|
||||
public static final int LOAD_URI = 12;
|
||||
public static final int SURFACE_CREATED = 13;
|
||||
public static final int SURFACE_DESTROYED = 14;
|
||||
public static final int GECKO_EVENT_SYNC = 15;
|
||||
public static final int ACTIVITY_START = 17;
|
||||
public static final int SAVE_STATE = 18;
|
||||
public static final int BROADCAST = 19;
|
||||
|
||||
public static final int IME_COMPOSITION_END = 0;
|
||||
public static final int IME_COMPOSITION_BEGIN = 1;
|
||||
public static final int IME_SET_TEXT = 2;
|
||||
public static final int IME_GET_TEXT = 3;
|
||||
public static final int IME_DELETE_TEXT = 4;
|
||||
public static final int IME_SET_SELECTION = 5;
|
||||
public static final int IME_GET_SELECTION = 6;
|
||||
public static final int IME_ADD_RANGE = 7;
|
||||
|
||||
public static final int IME_RANGE_CARETPOSITION = 1;
|
||||
public static final int IME_RANGE_RAWINPUT = 2;
|
||||
public static final int IME_RANGE_SELECTEDRAWTEXT = 3;
|
||||
public static final int IME_RANGE_CONVERTEDTEXT = 4;
|
||||
public static final int IME_RANGE_SELECTEDCONVERTEDTEXT = 5;
|
||||
|
||||
public static final int IME_RANGE_UNDERLINE = 1;
|
||||
public static final int IME_RANGE_FORECOLOR = 2;
|
||||
public static final int IME_RANGE_BACKCOLOR = 4;
|
||||
|
||||
public int mType;
|
||||
public int mAction;
|
||||
public long mTime;
|
||||
public Point mP0, mP1;
|
||||
public Rect mRect;
|
||||
public double mX, mY, mZ;
|
||||
public double mAlpha, mBeta, mGamma;
|
||||
|
||||
public int mMetaState, mFlags;
|
||||
public int mKeyCode, mUnicodeChar;
|
||||
public int mOffset, mCount;
|
||||
public String mCharacters, mCharactersExtra;
|
||||
public int mRangeType, mRangeStyles;
|
||||
public int mRangeForeColor, mRangeBackColor;
|
||||
public Location mLocation;
|
||||
public Address mAddress;
|
||||
|
||||
public int mNativeWindow;
|
||||
|
||||
public GeckoEvent() {
|
||||
mType = NATIVE_POKE;
|
||||
}
|
||||
|
||||
public GeckoEvent(int evType) {
|
||||
mType = evType;
|
||||
}
|
||||
|
||||
public GeckoEvent(KeyEvent k) {
|
||||
mType = KEY_EVENT;
|
||||
mAction = k.getAction();
|
||||
mTime = k.getEventTime();
|
||||
mMetaState = k.getMetaState();
|
||||
mFlags = k.getFlags();
|
||||
mKeyCode = k.getKeyCode();
|
||||
mUnicodeChar = k.getUnicodeChar();
|
||||
mCharacters = k.getCharacters();
|
||||
}
|
||||
|
||||
public GeckoEvent(MotionEvent m) {
|
||||
mType = MOTION_EVENT;
|
||||
mAction = m.getAction();
|
||||
mTime = m.getEventTime();
|
||||
mMetaState = m.getMetaState();
|
||||
mP0 = new Point((int)m.getX(0), (int)m.getY(0));
|
||||
mCount = m.getPointerCount();
|
||||
if (mCount > 1)
|
||||
mP1 = new Point((int)m.getX(1), (int)m.getY(1));
|
||||
}
|
||||
|
||||
public GeckoEvent(SensorEvent s) {
|
||||
|
||||
if (s.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
|
||||
mType = ACCELERATION_EVENT;
|
||||
mX = s.values[0] / SensorManager.GRAVITY_EARTH;
|
||||
mY = s.values[1] / SensorManager.GRAVITY_EARTH;
|
||||
mZ = s.values[2] / SensorManager.GRAVITY_EARTH;
|
||||
}
|
||||
else {
|
||||
mType = ORIENTATION_EVENT;
|
||||
mAlpha = -s.values[0];
|
||||
mBeta = -s.values[1];
|
||||
mGamma = -s.values[2];
|
||||
Log.i(LOGTAG, "SensorEvent type = " + s.sensor.getType() + " " + s.sensor.getName() + " " + mAlpha + " " + mBeta + " " + mGamma );
|
||||
}
|
||||
}
|
||||
|
||||
public GeckoEvent(Location l, Address a) {
|
||||
mType = LOCATION_EVENT;
|
||||
mLocation = l;
|
||||
mAddress = a;
|
||||
}
|
||||
|
||||
public GeckoEvent(int imeAction, int offset, int count) {
|
||||
mType = IME_EVENT;
|
||||
mAction = imeAction;
|
||||
mOffset = offset;
|
||||
mCount = count;
|
||||
}
|
||||
|
||||
private void InitIMERange(int action, int offset, int count,
|
||||
int rangeType, int rangeStyles,
|
||||
int rangeForeColor, int rangeBackColor) {
|
||||
mType = IME_EVENT;
|
||||
mAction = action;
|
||||
mOffset = offset;
|
||||
mCount = count;
|
||||
mRangeType = rangeType;
|
||||
mRangeStyles = rangeStyles;
|
||||
mRangeForeColor = rangeForeColor;
|
||||
mRangeBackColor = rangeBackColor;
|
||||
return;
|
||||
}
|
||||
|
||||
public GeckoEvent(int offset, int count,
|
||||
int rangeType, int rangeStyles,
|
||||
int rangeForeColor, int rangeBackColor, String text) {
|
||||
InitIMERange(IME_SET_TEXT, offset, count, rangeType, rangeStyles,
|
||||
rangeForeColor, rangeBackColor);
|
||||
mCharacters = text;
|
||||
}
|
||||
|
||||
public GeckoEvent(int offset, int count,
|
||||
int rangeType, int rangeStyles,
|
||||
int rangeForeColor, int rangeBackColor) {
|
||||
InitIMERange(IME_ADD_RANGE, offset, count, rangeType, rangeStyles,
|
||||
rangeForeColor, rangeBackColor);
|
||||
}
|
||||
|
||||
public GeckoEvent(int etype, Rect rect) {
|
||||
if (etype != DRAW) {
|
||||
mType = INVALID;
|
||||
return;
|
||||
}
|
||||
|
||||
mType = etype;
|
||||
mRect = rect;
|
||||
}
|
||||
|
||||
public GeckoEvent(int etype, int w, int h, int screenw, int screenh) {
|
||||
if (etype != SIZE_CHANGED) {
|
||||
mType = INVALID;
|
||||
return;
|
||||
}
|
||||
|
||||
mType = etype;
|
||||
|
||||
mP0 = new Point(w, h);
|
||||
mP1 = new Point(screenw, screenh);
|
||||
}
|
||||
|
||||
public GeckoEvent(String subject, String data) {
|
||||
mType = BROADCAST;
|
||||
mCharacters = subject;
|
||||
mCharactersExtra = data;
|
||||
}
|
||||
|
||||
public GeckoEvent(String uri) {
|
||||
mType = LOAD_URI;
|
||||
mCharacters = uri;
|
||||
}
|
||||
|
||||
}
|
44
mobile/android/base/GeckoEventListener.java
Normal file
@ -0,0 +1,44 @@
|
||||
/* -*- 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) 2009-2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Sriram Ramasubramanian <sriram@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 org.json.JSONObject;
|
||||
|
||||
public interface GeckoEventListener {
|
||||
public void handleMessage(String event, JSONObject message);
|
||||
}
|
1120
mobile/android/base/GeckoInputConnection.java
Normal file
195
mobile/android/base/GeckoPreferences.java
Normal file
@ -0,0 +1,195 @@
|
||||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; 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 Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Alex Pakhotin <alexp@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.util.ArrayList;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.content.res.Resources;
|
||||
import android.content.Context;
|
||||
import android.preference.*;
|
||||
import android.preference.Preference.*;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import org.json.*;
|
||||
|
||||
public class GeckoPreferences
|
||||
extends PreferenceActivity
|
||||
implements OnPreferenceChangeListener
|
||||
{
|
||||
private static final String LOGTAG = "GeckoPreferences";
|
||||
|
||||
private static Context sContext;
|
||||
private static JSONArray sJSONPrefs = null;
|
||||
private ArrayList<String> mPreferencesList = new ArrayList<String>();
|
||||
private PreferenceScreen mPreferenceScreen;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
sContext = this;
|
||||
addPreferencesFromResource(R.xml.preferences);
|
||||
mPreferenceScreen = getPreferenceScreen();
|
||||
initGroups(mPreferenceScreen);
|
||||
|
||||
// setData() must have been called already
|
||||
if (sJSONPrefs != null)
|
||||
refresh();
|
||||
}
|
||||
|
||||
private void initGroups(PreferenceGroup preferences) {
|
||||
final int count = preferences.getPreferenceCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
Preference pref = preferences.getPreference(i);
|
||||
if (pref instanceof PreferenceGroup)
|
||||
initGroups((PreferenceGroup)pref);
|
||||
else {
|
||||
pref.setOnPreferenceChangeListener(this);
|
||||
mPreferencesList.add(pref.getKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
String prefName = preference.getKey();
|
||||
setPreference(prefName, newValue);
|
||||
if (preference instanceof ListPreference)
|
||||
((ListPreference)preference).setSummary((String)newValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void setData(JSONArray jsonPrefs) {
|
||||
sJSONPrefs = jsonPrefs;
|
||||
}
|
||||
|
||||
public static boolean isLoaded() {
|
||||
return sJSONPrefs != null;
|
||||
}
|
||||
|
||||
// Update the preferences UI with our in-memory JSON preferences object
|
||||
private void refresh() {
|
||||
try {
|
||||
// set the current page URL for the "Home page" preference
|
||||
final String[] homepageValues = sContext.getResources().getStringArray(R.array.pref_homepage_values);
|
||||
final Preference homepagePref = mPreferenceScreen.findPreference("browser.startup.homepage");
|
||||
GeckoAppShell.getMainHandler().post(new Runnable() {
|
||||
public void run() {
|
||||
Tab tab = Tabs.getInstance().getSelectedTab();
|
||||
homepageValues[2] = tab.getURL();
|
||||
((ListPreference)homepagePref).setEntryValues(homepageValues);
|
||||
}
|
||||
});
|
||||
|
||||
final int length = sJSONPrefs.length();
|
||||
for (int i = 0; i < length; i++) {
|
||||
JSONObject jPref = sJSONPrefs.getJSONObject(i);
|
||||
final String prefName = jPref.getString("name");
|
||||
final String prefType = jPref.getString("type");
|
||||
final Preference pref = mPreferenceScreen.findPreference(prefName);
|
||||
|
||||
if (prefName.equals("browser.startup.homepage")) {
|
||||
final String value = jPref.getString("value");
|
||||
GeckoAppShell.getMainHandler().post(new Runnable() {
|
||||
public void run() {
|
||||
pref.setSummary(value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (pref instanceof CheckBoxPreference && "bool".equals(prefType)) {
|
||||
final boolean value = jPref.getBoolean("value");
|
||||
GeckoAppShell.getMainHandler().post(new Runnable() {
|
||||
public void run() {
|
||||
if (((CheckBoxPreference)pref).isChecked() != value)
|
||||
((CheckBoxPreference)pref).setChecked(value);
|
||||
}
|
||||
});
|
||||
} else if (pref instanceof EditTextPreference && "string".equals(prefType)) {
|
||||
final String value = jPref.getString("value");
|
||||
GeckoAppShell.getMainHandler().post(new Runnable() {
|
||||
public void run() {
|
||||
((EditTextPreference)pref).setText(value);
|
||||
}
|
||||
});
|
||||
} else if (pref instanceof ListPreference && "string".equals(prefType)) {
|
||||
final String value = jPref.getString("value");
|
||||
GeckoAppShell.getMainHandler().post(new Runnable() {
|
||||
public void run() {
|
||||
((ListPreference)pref).setValue(value);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
Log.e(LOGTAG, "Problem parsing preferences response: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setPreference(String pref, Object value) {
|
||||
// update the in-memory preferences cache
|
||||
JSONObject jsonPref = null;
|
||||
try {
|
||||
for (int i = 0; i < sJSONPrefs.length(); i++) {
|
||||
if (sJSONPrefs.getJSONObject(i).getString("name").equals(pref)) {
|
||||
jsonPref = sJSONPrefs.getJSONObject(i);
|
||||
if (value instanceof Boolean)
|
||||
jsonPref.put("value", ((Boolean)value).booleanValue());
|
||||
else if (value instanceof Integer)
|
||||
jsonPref.put("value", ((Integer)value).intValue());
|
||||
else
|
||||
jsonPref.put("value", String.valueOf(value));
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
Log.e(LOGTAG, "JSON exception: ", e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (jsonPref == null) {
|
||||
Log.e(LOGTAG, "invalid preference given to setPreference()");
|
||||
return;
|
||||
}
|
||||
|
||||
// send the Preferences:Set message to Gecko
|
||||
GeckoEvent event = new GeckoEvent("Preferences:Set", jsonPref.toString());
|
||||
GeckoAppShell.sendEventToGecko(event);
|
||||
}
|
||||
}
|
64
mobile/android/base/GeckoStateListDrawable.java
Normal file
@ -0,0 +1,64 @@
|
||||
/* -*- 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) 2009-2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Sriram Ramasubramanian <sriram@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 android.graphics.Color;
|
||||
import android.graphics.drawable.LayerDrawable;
|
||||
import android.graphics.drawable.StateListDrawable;
|
||||
import android.graphics.LightingColorFilter;
|
||||
|
||||
public class GeckoStateListDrawable extends StateListDrawable {
|
||||
private LightingColorFilter mFilter;
|
||||
|
||||
public void initializeFilter(int color) {
|
||||
mFilter = new LightingColorFilter(Color.WHITE, color);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onStateChange(int[] stateSet) {
|
||||
for (int state: stateSet) {
|
||||
if (state == android.R.attr.state_pressed || state == android.R.attr.state_focused) {
|
||||
super.onStateChange(stateSet);
|
||||
((LayerDrawable) getCurrent()).getDrawable(0).setColorFilter(mFilter);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return super.onStateChange(stateSet);
|
||||
}
|
||||
}
|
127
mobile/android/base/GeckoThread.java
Normal file
@ -0,0 +1,127 @@
|
||||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; 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) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brad Lassey <blassey@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 android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.Configuration;
|
||||
import android.util.Log;
|
||||
import android.widget.AbsoluteLayout;
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
public class GeckoThread extends Thread {
|
||||
private static final String LOGTAG = "GeckoThread";
|
||||
|
||||
Intent mIntent;
|
||||
|
||||
GeckoThread (Intent intent) {
|
||||
mIntent = intent;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
final GeckoApp app = GeckoApp.mAppContext;
|
||||
Intent intent = mIntent;
|
||||
File cacheFile = GeckoAppShell.getCacheDir();
|
||||
File libxulFile = new File(cacheFile, "libxul.so");
|
||||
|
||||
if ((!libxulFile.exists() ||
|
||||
new File(app.getApplication().getPackageResourcePath()).lastModified() >= libxulFile.lastModified())) {
|
||||
File[] libs = cacheFile.listFiles(new FilenameFilter() {
|
||||
public boolean accept(File dir, String name) {
|
||||
return name.endsWith(".so");
|
||||
}
|
||||
});
|
||||
if (libs != null) {
|
||||
for (int i = 0; i < libs.length; i++) {
|
||||
libs[i].delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// At some point while loading the gecko libs our default locale gets set
|
||||
// so just save it to locale here and reset it as default after the join
|
||||
Locale locale = Locale.getDefault();
|
||||
GeckoAppShell.loadGeckoLibs(
|
||||
app.getApplication().getPackageResourcePath());
|
||||
Locale.setDefault(locale);
|
||||
Resources res = app.getBaseContext().getResources();
|
||||
Configuration config = res.getConfiguration();
|
||||
config.locale = locale;
|
||||
res.updateConfiguration(config, res.getDisplayMetrics());
|
||||
|
||||
Log.w(LOGTAG, "zerdatime " + new Date().getTime() + " - runGecko");
|
||||
|
||||
// and then fire us up
|
||||
try {
|
||||
String uri = intent.getDataString();
|
||||
String title = uri;
|
||||
if (!app.mUserDefinedProfile &&
|
||||
(uri == null || uri.length() == 0)) {
|
||||
SharedPreferences prefs = app.getSharedPreferences("GeckoApp", app.MODE_PRIVATE);
|
||||
uri = prefs.getString("last-uri", "");
|
||||
title = prefs.getString("last-title", uri);
|
||||
}
|
||||
|
||||
final String awesomeTitle = title;
|
||||
app.mMainHandler.post(new Runnable() {
|
||||
public void run() {
|
||||
app.mBrowserToolbar.setTitle(awesomeTitle);
|
||||
}
|
||||
});
|
||||
|
||||
Log.w(LOGTAG, "RunGecko - URI = " + uri);
|
||||
|
||||
GeckoAppShell.runGecko(app.getApplication().getPackageResourcePath(),
|
||||
intent.getStringExtra("args"),
|
||||
uri);
|
||||
} catch (Exception e) {
|
||||
Log.e(LOGTAG, "top level exception", e);
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw);
|
||||
e.printStackTrace(pw);
|
||||
pw.flush();
|
||||
GeckoAppShell.reportJavaCrash(sw.toString());
|
||||
}
|
||||
}
|
||||
}
|
149
mobile/android/base/GlobalHistory.java
Normal file
@ -0,0 +1,149 @@
|
||||
/* -*- 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) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Kartikaya Gupta <kgupta@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.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.lang.ref.SoftReference;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.os.Handler;
|
||||
import android.provider.Browser;
|
||||
import android.util.Log;
|
||||
|
||||
class GlobalHistory {
|
||||
private static final String LOGTAG = "GeckoGlobalHistory";
|
||||
|
||||
private static GlobalHistory sInstance = new GlobalHistory();
|
||||
|
||||
static GlobalHistory getInstance() {
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
// this is the delay between receiving a URI check request and processing it.
|
||||
// this allows batching together multiple requests and processing them together,
|
||||
// which is more efficient.
|
||||
private static final long BATCHING_DELAY_MS = 100;
|
||||
|
||||
private final Handler mHandler; // a background thread on which we can process requests
|
||||
private final Queue<String> mPendingUris; // URIs that need to be checked
|
||||
private SoftReference<Set<String>> mVisitedCache; // cache of the visited URI list
|
||||
private final Runnable mNotifierRunnable; // off-thread runnable used to check URIs
|
||||
private boolean mProcessing; // = false // whether or not the runnable is queued/working
|
||||
|
||||
private GlobalHistory() {
|
||||
mHandler = GeckoAppShell.getHandler();
|
||||
mPendingUris = new LinkedList<String>();
|
||||
mVisitedCache = new SoftReference<Set<String>>(null);
|
||||
mNotifierRunnable = new Runnable() {
|
||||
public void run() {
|
||||
Set<String> visitedSet = mVisitedCache.get();
|
||||
if (visitedSet == null) {
|
||||
// the cache was wiped away, repopulate it
|
||||
Log.w(LOGTAG, "Rebuilding visited link set...");
|
||||
visitedSet = new HashSet<String>();
|
||||
Cursor c = GeckoApp.mAppContext.getContentResolver().query(Browser.BOOKMARKS_URI,
|
||||
new String[] { Browser.BookmarkColumns.URL },
|
||||
Browser.BookmarkColumns.BOOKMARK + "=0 AND " +
|
||||
Browser.BookmarkColumns.VISITS + ">0",
|
||||
null,
|
||||
null);
|
||||
if (c.moveToFirst()) {
|
||||
do {
|
||||
visitedSet.add(c.getString(0));
|
||||
} while (c.moveToNext());
|
||||
}
|
||||
mVisitedCache = new SoftReference<Set<String>>(visitedSet);
|
||||
c.close();
|
||||
}
|
||||
|
||||
// this runs on the same handler thread as the checkUriVisited code,
|
||||
// so no synchronization needed
|
||||
while (true) {
|
||||
String uri = mPendingUris.poll();
|
||||
if (uri == null) {
|
||||
break;
|
||||
}
|
||||
if (visitedSet.contains(uri)) {
|
||||
GeckoAppShell.notifyUriVisited(uri);
|
||||
}
|
||||
}
|
||||
mProcessing = false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void add(String uri) {
|
||||
Browser.updateVisitedHistory(GeckoApp.mAppContext.getContentResolver(), uri, true);
|
||||
Set<String> visitedSet = mVisitedCache.get();
|
||||
if (visitedSet != null) {
|
||||
visitedSet.add(uri);
|
||||
}
|
||||
GeckoAppShell.notifyUriVisited(uri);
|
||||
}
|
||||
|
||||
public void update(String uri, String title) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(Browser.BookmarkColumns.TITLE, title);
|
||||
GeckoApp.mAppContext.getContentResolver().update(
|
||||
Browser.BOOKMARKS_URI,
|
||||
values,
|
||||
Browser.BookmarkColumns.URL + " = ?",
|
||||
new String[] { uri });
|
||||
}
|
||||
|
||||
public void checkUriVisited(final String uri) {
|
||||
mHandler.post(new Runnable() {
|
||||
public void run() {
|
||||
// this runs on the same handler thread as the processing loop,
|
||||
// so synchronization needed
|
||||
mPendingUris.add(uri);
|
||||
if (mProcessing) {
|
||||
// there's already a runnable queued up or working away, so
|
||||
// no need to post another
|
||||
return;
|
||||
}
|
||||
mProcessing = true;
|
||||
mHandler.postDelayed(mNotifierRunnable, BATCHING_DELAY_MS);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
259
mobile/android/base/LauncherShortcuts.java.in
Normal file
@ -0,0 +1,259 @@
|
||||
/* -*- 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) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Vladimir Vukicevic <vladimir@pobox.com>
|
||||
* Wes Johnston <wjohnston@mozilla.com>
|
||||
* Mark Finkle <mfinkle@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 ***** */
|
||||
|
||||
#filter substitution
|
||||
package @ANDROID_PACKAGE_NAME@;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import org.json.*;
|
||||
|
||||
import org.mozilla.gecko.*;
|
||||
|
||||
import android.os.*;
|
||||
import android.content.*;
|
||||
import android.app.*;
|
||||
import android.text.*;
|
||||
import android.util.*;
|
||||
import android.widget.*;
|
||||
import android.database.sqlite.*;
|
||||
import android.database.*;
|
||||
import android.view.*;
|
||||
import android.net.Uri;
|
||||
import android.graphics.*;
|
||||
|
||||
|
||||
public class LauncherShortcuts extends Activity {
|
||||
|
||||
private ArrayList <HashMap<String, String>> mWebappsList;
|
||||
private File mWebappsFolder;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
setContentView(R.layout.launch_app_list);
|
||||
|
||||
final Intent intent = getIntent();
|
||||
final String action = intent.getAction();
|
||||
|
||||
if (Intent.ACTION_CREATE_SHORTCUT.equals(action)) {
|
||||
// Doing it as a background task, as it involves file access
|
||||
new FetchWebApps().execute();
|
||||
}
|
||||
}
|
||||
|
||||
public void onListItemClick(int id) {
|
||||
HashMap<String, String> map = mWebappsList.get(id);
|
||||
|
||||
String uri = map.get("uri").toString();
|
||||
String title = map.get("title").toString();
|
||||
String appKey = map.get("appKey").toString();
|
||||
String favicon = map.get("favicon").toString();
|
||||
|
||||
File manifestFile = new File(mWebappsFolder, appKey + "/manifest.json");
|
||||
|
||||
// Parse the contents into a string
|
||||
String manifestJson = new String();
|
||||
try {
|
||||
BufferedReader in = new BufferedReader(new FileReader(manifestFile));
|
||||
String line = new String();
|
||||
|
||||
while ((line = in.readLine()) != null) {
|
||||
manifestJson += line;
|
||||
}
|
||||
} catch (IOException e) { }
|
||||
|
||||
try {
|
||||
JSONObject manifest = (JSONObject) new JSONTokener(manifestJson).nextValue();
|
||||
uri += manifest.getString("launch_path");
|
||||
} catch (JSONException e) { }
|
||||
|
||||
Intent shortcutintent = new Intent("org.mozilla.gecko.WEBAPP");
|
||||
shortcutintent.setClass(this, App.class);
|
||||
shortcutintent.putExtra("args", "--webapp=" + uri);
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, title);
|
||||
intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutintent);
|
||||
|
||||
DisplayMetrics dm = new DisplayMetrics();
|
||||
getWindowManager().getDefaultDisplay().getMetrics(dm);
|
||||
int size;
|
||||
switch (dm.densityDpi) {
|
||||
case DisplayMetrics.DENSITY_MEDIUM:
|
||||
size = 48;
|
||||
break;
|
||||
case DisplayMetrics.DENSITY_HIGH:
|
||||
size = 72;
|
||||
break;
|
||||
default:
|
||||
size = 72;
|
||||
}
|
||||
|
||||
Bitmap bitmap = BitmapFactory.decodeFile(favicon);
|
||||
if (bitmap != null) {
|
||||
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, size, size, true);
|
||||
intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, scaledBitmap);
|
||||
}
|
||||
|
||||
// Now, return the result to the launcher
|
||||
setResult(RESULT_OK, intent);
|
||||
finish();
|
||||
}
|
||||
|
||||
private class FetchWebApps extends AsyncTask<Void, Void, Void> {
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... unused) {
|
||||
mWebappsList = null;
|
||||
|
||||
Context context = getApplicationContext();
|
||||
|
||||
File home = new File(context.getFilesDir(), "mozilla");
|
||||
if (!home.exists())
|
||||
home = new File(context.getExternalFilesDir(null).getPath(), "mozilla");
|
||||
|
||||
if (!home.exists())
|
||||
return null;
|
||||
|
||||
File profile = null;
|
||||
String[] files = home.list();
|
||||
for (String file : files) {
|
||||
if (file.endsWith(".default")) {
|
||||
profile = new File(home, file);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (profile == null)
|
||||
return null;
|
||||
|
||||
// Save the folder path to be used during click event
|
||||
mWebappsFolder = new File(profile, "webapps");
|
||||
if (!mWebappsFolder.exists())
|
||||
return null;
|
||||
|
||||
File webapps = new File(mWebappsFolder, "webapps.json");
|
||||
if (!webapps.exists())
|
||||
return null;
|
||||
|
||||
// Parse the contents into a string
|
||||
String webappsJson = new String();
|
||||
try {
|
||||
BufferedReader in = new BufferedReader(new FileReader(webapps));
|
||||
String line = new String();
|
||||
|
||||
while ((line = in.readLine()) != null) {
|
||||
webappsJson += line;
|
||||
}
|
||||
} catch (IOException e) { }
|
||||
|
||||
if (webappsJson.length() == 0)
|
||||
return null;
|
||||
|
||||
mWebappsList = new ArrayList<HashMap<String, String>>();
|
||||
|
||||
try {
|
||||
JSONObject webApps = (JSONObject) new JSONTokener(webappsJson).nextValue();
|
||||
|
||||
Iterator appKeys = webApps.keys();
|
||||
HashMap<String, String> map;
|
||||
|
||||
while (appKeys.hasNext()) {
|
||||
String appKey = appKeys.next().toString();
|
||||
JSONObject app = webApps.getJSONObject(appKey);
|
||||
|
||||
map = new HashMap<String, String>();
|
||||
map.put("appKey", appKey);
|
||||
map.put("favicon", mWebappsFolder.getPath() + "/" + appKey + "/icon.png");
|
||||
map.put("title", app.getString("title"));
|
||||
map.put("uri", app.getString("appURI"));
|
||||
|
||||
mWebappsList.add(map);
|
||||
}
|
||||
|
||||
} catch (JSONException e) {}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void unused) {
|
||||
if (mWebappsList != null) {
|
||||
AlertDialog.Builder builder;
|
||||
|
||||
if (android.os.Build.VERSION.SDK_INT >= 11) {
|
||||
builder = new AlertDialog.Builder(LauncherShortcuts.this, AlertDialog.THEME_HOLO_LIGHT);
|
||||
} else {
|
||||
builder = new AlertDialog.Builder(LauncherShortcuts.this);
|
||||
}
|
||||
|
||||
builder.setTitle(R.string.launcher_shortcuts_title);
|
||||
builder.setAdapter(new SimpleAdapter(
|
||||
LauncherShortcuts.this,
|
||||
mWebappsList,
|
||||
R.layout.launch_app_listitem,
|
||||
new String[] { "favicon", "title" },
|
||||
new int[] { R.id.favicon, R.id.title }
|
||||
), new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
dialog.dismiss();
|
||||
onListItemClick(id);
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
||||
builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
dialog.dismiss();
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
||||
builder.create().show();
|
||||
} else {
|
||||
Toast.makeText(LauncherShortcuts.this, R.string.launcher_shortcuts_empty, Toast.LENGTH_LONG).show();
|
||||
finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
469
mobile/android/base/Makefile.in
Normal file
@ -0,0 +1,469 @@
|
||||
# ***** 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 the Mozilla browser.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Mozilla Foundation
|
||||
# Portions created by the Initial Developer are Copyright (C) 2009-2010
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Vladimir Vukicevic <vladimir@pobox.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 *****
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
include $(topsrcdir)/ipc/app/defs.mk
|
||||
|
||||
DIRS = locales
|
||||
|
||||
DIST_FILES = package-name.txt
|
||||
|
||||
JAVAFILES = \
|
||||
AlertNotification.java \
|
||||
AwesomeBar.java \
|
||||
AwesomeBarTabs.java \
|
||||
BrowserToolbar.java \
|
||||
ConfirmPreference.java \
|
||||
DoorHanger.java \
|
||||
DoorHangerPopup.java \
|
||||
Favicons.java \
|
||||
GeckoApp.java \
|
||||
GeckoAppShell.java \
|
||||
GeckoConnectivityReceiver.java \
|
||||
GeckoEvent.java \
|
||||
GeckoEventListener.java \
|
||||
GeckoInputConnection.java \
|
||||
GeckoPreferences.java \
|
||||
GeckoStateListDrawable.java \
|
||||
GlobalHistory.java \
|
||||
PromptService.java \
|
||||
SurfaceLockInfo.java \
|
||||
Tab.java \
|
||||
Tabs.java \
|
||||
TabsTray.java \
|
||||
GeckoBatteryManager.java \
|
||||
GeckoThread.java \
|
||||
GeckoAsyncTask.java \
|
||||
gfx/BufferedCairoImage.java \
|
||||
gfx/CairoImage.java \
|
||||
gfx/CairoUtils.java \
|
||||
gfx/GeckoSoftwareLayerClient.java \
|
||||
gfx/InputConnectionHandler.java \
|
||||
gfx/IntSize.java \
|
||||
gfx/Layer.java \
|
||||
gfx/LayerClient.java \
|
||||
gfx/LayerController.java \
|
||||
gfx/LayerRenderer.java \
|
||||
gfx/LayerView.java \
|
||||
gfx/NinePatchTileLayer.java \
|
||||
gfx/PlaceholderLayerClient.java \
|
||||
gfx/PointUtils.java \
|
||||
gfx/RectUtils.java \
|
||||
gfx/SingleTileLayer.java \
|
||||
gfx/TextureReaper.java \
|
||||
gfx/TextLayer.java \
|
||||
gfx/TileLayer.java \
|
||||
ui/PanZoomController.java \
|
||||
ui/ViewportController.java \
|
||||
$(NULL)
|
||||
|
||||
PROCESSEDJAVAFILES = \
|
||||
App.java \
|
||||
LauncherShortcuts.java \
|
||||
NotificationHandler.java \
|
||||
Restarter.java \
|
||||
$(NULL)
|
||||
|
||||
|
||||
ifneq (,$(findstring -march=armv7,$(OS_CFLAGS)))
|
||||
MIN_CPU_VERSION=7
|
||||
else
|
||||
MIN_CPU_VERSION=5
|
||||
endif
|
||||
|
||||
ifeq (,$(ANDROID_VERSION_CODE))
|
||||
ANDROID_VERSION_CODE=$(shell $(PYTHON) $(topsrcdir)/toolkit/xre/make-platformini.py --print-buildid | cut -c1-10)
|
||||
endif
|
||||
|
||||
DEFINES += \
|
||||
-DANDROID_PACKAGE_NAME=$(ANDROID_PACKAGE_NAME) \
|
||||
-DMOZ_APP_DISPLAYNAME="$(MOZ_APP_DISPLAYNAME)" \
|
||||
-DMOZ_APP_NAME=$(MOZ_APP_NAME) \
|
||||
-DMOZ_APP_VERSION=$(MOZ_APP_VERSION) \
|
||||
-DMOZ_CHILD_PROCESS_NAME=$(MOZ_CHILD_PROCESS_NAME) \
|
||||
-DMOZ_MIN_CPU_VERSION=$(MIN_CPU_VERSION) \
|
||||
-DMOZ_CRASHREPORTER=$(MOZ_CRASHREPORTER) \
|
||||
-DANDROID_VERSION_CODE=$(ANDROID_VERSION_CODE) \
|
||||
-DMOZILLA_OFFICIAL=$(MOZILLA_OFFICIAL) \
|
||||
$(NULL)
|
||||
|
||||
GARBAGE += \
|
||||
AndroidManifest.xml \
|
||||
classes.dex \
|
||||
$(PROCESSEDJAVAFILES) \
|
||||
gecko.ap_ \
|
||||
res/values/strings.xml \
|
||||
R.java \
|
||||
$(NULL)
|
||||
|
||||
GARBAGE_DIRS += classes res
|
||||
|
||||
# Bug 567884 - Need a way to find appropriate icons during packaging
|
||||
ifeq ($(MOZ_APP_NAME),fennec)
|
||||
ICON_PATH = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/fennec_48x48.png
|
||||
ICON_PATH_HDPI = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/fennec_72x72.png
|
||||
|
||||
# we released these builds to the public with shared IDs and need to keep them
|
||||
ifeq (org.mozilla.firefox,$(ANDROID_PACKAGE_NAME))
|
||||
DEFINES += -DMOZ_ANDROID_SHARED_ID="org.mozilla.firefox.sharedID"
|
||||
else ifeq (org.mozilla.firefox_beta,$(ANDROID_PACKAGE_NAME))
|
||||
DEFINES += -DMOZ_ANDROID_SHARED_ID="org.mozilla.firefox.sharedID"
|
||||
else ifeq (org.mozilla.fennec_aurora,$(ANDROID_PACKAGE_NAME))
|
||||
DEFINES += -DMOZ_ANDROID_SHARED_ID="org.mozilla.fennec.sharedID"
|
||||
else ifeq (org.mozilla.fennec,$(ANDROID_PACKAGE_NAME))
|
||||
DEFINES += -DMOZ_ANDROID_SHARED_ID="org.mozilla.fennec.sharedID"
|
||||
endif
|
||||
|
||||
else
|
||||
ICON_PATH = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/icon48.png
|
||||
ICON_PATH_HDPI = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/icon64.png
|
||||
DEFINES += -DMOZ_ANDROID_SHARED_ID="$(ANDROID_PACKAGE_NAME).sharedID"
|
||||
endif
|
||||
|
||||
RES_LAYOUT = \
|
||||
res/layout/awesomebar_header_row.xml \
|
||||
res/layout/awesomebar_row.xml \
|
||||
res/layout/awesomebar_search.xml \
|
||||
res/layout/awesomebar_tab_indicator.xml \
|
||||
res/layout/awesomebar_tabs.xml \
|
||||
res/layout/browser_toolbar.xml \
|
||||
res/layout/doorhangerpopup.xml \
|
||||
res/layout/doorhanger.xml \
|
||||
res/layout/gecko_app.xml \
|
||||
res/layout/gecko_menu.xml \
|
||||
res/layout/launch_app_list.xml \
|
||||
res/layout/launch_app_listitem.xml \
|
||||
res/layout/notification_icon_text.xml \
|
||||
res/layout/notification_progress.xml \
|
||||
res/layout/notification_progress_text.xml \
|
||||
res/layout/tabs_row.xml \
|
||||
res/layout/tabs_tray.xml \
|
||||
res/layout/list_item_header.xml \
|
||||
res/layout/select_dialog_list.xml \
|
||||
$(NULL)
|
||||
|
||||
RES_VALUES = \
|
||||
res/values/arrays.xml \
|
||||
res/values/colors.xml \
|
||||
res/values/styles.xml \
|
||||
res/values/themes.xml \
|
||||
$(NULL)
|
||||
|
||||
RES_XML = res/xml/preferences.xml
|
||||
|
||||
RES_ANIM = \
|
||||
res/anim/grow_fade_in.xml \
|
||||
res/anim/shrink_fade_out.xml \
|
||||
$(NULL)
|
||||
|
||||
RES_DRAWABLE_MDPI_V8 = \
|
||||
res/drawable-mdpi-v8/ic_menu_bookmark_add.png \
|
||||
res/drawable-mdpi-v8/ic_menu_bookmark_remove.png \
|
||||
res/drawable-mdpi-v8/ic_menu_find_in_page.png \
|
||||
res/drawable-mdpi-v8/ic_menu_reload.png \
|
||||
res/drawable-mdpi-v8/ic_menu_save_as_pdf.png \
|
||||
res/drawable-mdpi-v8/ic_menu_share.png \
|
||||
res/drawable-mdpi-v8/tabs_normal.png \
|
||||
res/drawable-mdpi-v8/tabs_pressed.png \
|
||||
res/drawable-mdpi-v8/tabs_more.png \
|
||||
res/drawable-mdpi-v8/tabs_plus.png \
|
||||
res/drawable-mdpi-v8/address_bar_url_bg.9.png \
|
||||
res/drawable-mdpi-v8/doorhanger_arrow.png \
|
||||
res/drawable-mdpi-v8/doorhanger_bg.9.png \
|
||||
res/drawable-mdpi-v8/doorhanger_shadow_bg.9.png \
|
||||
res/drawable-mdpi-v8/doorhanger_popup_bg.9.png \
|
||||
res/drawable-mdpi-v8/site_security_lock.png \
|
||||
res/drawable-mdpi-v8/urlbar_stop.png \
|
||||
$(NULL)
|
||||
|
||||
RES_DRAWABLE_HDPI_V8 = \
|
||||
res/drawable-hdpi-v8/ic_menu_bookmark_add.png \
|
||||
res/drawable-hdpi-v8/ic_menu_bookmark_remove.png \
|
||||
res/drawable-hdpi-v8/ic_menu_find_in_page.png \
|
||||
res/drawable-hdpi-v8/ic_menu_reload.png \
|
||||
res/drawable-hdpi-v8/ic_menu_save_as_pdf.png \
|
||||
res/drawable-hdpi-v8/ic_menu_share.png \
|
||||
res/drawable-hdpi-v8/tabs_normal.png \
|
||||
res/drawable-hdpi-v8/tabs_pressed.png \
|
||||
res/drawable-hdpi-v8/tabs_more.png \
|
||||
res/drawable-hdpi-v8/tabs_plus.png \
|
||||
res/drawable-hdpi-v8/address_bar_url_bg.9.png \
|
||||
res/drawable-hdpi-v8/doorhanger_arrow.png \
|
||||
res/drawable-hdpi-v8/doorhanger_bg.9.png \
|
||||
res/drawable-hdpi-v8/doorhanger_shadow_bg.9.png \
|
||||
res/drawable-hdpi-v8/doorhanger_popup_bg.9.png \
|
||||
res/drawable-hdpi-v8/site_security_lock.png \
|
||||
res/drawable-hdpi-v8/urlbar_stop.png \
|
||||
$(NULL)
|
||||
|
||||
RES_DRAWABLE_MDPI_V9 = \
|
||||
res/drawable-mdpi-v9/ic_menu_bookmark_add.png \
|
||||
res/drawable-mdpi-v9/ic_menu_bookmark_remove.png \
|
||||
res/drawable-mdpi-v9/ic_menu_find_in_page.png \
|
||||
res/drawable-mdpi-v9/ic_menu_reload.png \
|
||||
res/drawable-mdpi-v9/ic_menu_save_as_pdf.png \
|
||||
res/drawable-mdpi-v9/ic_menu_share.png \
|
||||
$(NULL)
|
||||
|
||||
RES_DRAWABLE_HDPI_V9 = \
|
||||
res/drawable-hdpi-v9/ic_menu_bookmark_add.png \
|
||||
res/drawable-hdpi-v9/ic_menu_bookmark_remove.png \
|
||||
res/drawable-hdpi-v9/ic_menu_find_in_page.png \
|
||||
res/drawable-hdpi-v9/ic_menu_reload.png \
|
||||
res/drawable-hdpi-v9/ic_menu_save_as_pdf.png \
|
||||
res/drawable-hdpi-v9/ic_menu_share.png \
|
||||
$(NULL)
|
||||
|
||||
RES_DRAWABLE_MDPI_V11 = \
|
||||
res/drawable-mdpi-v11/ic_menu_bookmark_add.png \
|
||||
res/drawable-mdpi-v11/ic_menu_bookmark_remove.png \
|
||||
res/drawable-mdpi-v11/ic_menu_find_in_page.png \
|
||||
res/drawable-mdpi-v11/ic_menu_reload.png \
|
||||
res/drawable-mdpi-v11/ic_menu_save_as_pdf.png \
|
||||
res/drawable-mdpi-v11/ic_menu_share.png \
|
||||
res/drawable-mdpi-v11/tabs_normal.png \
|
||||
res/drawable-mdpi-v11/tabs_pressed.png \
|
||||
res/drawable-mdpi-v11/tabs_more.png \
|
||||
res/drawable-mdpi-v11/tabs_plus.png \
|
||||
res/drawable-mdpi-v11/address_bar_url_bg.9.png \
|
||||
$(NULL)
|
||||
|
||||
RES_DRAWABLE_HDPI_V11 = \
|
||||
res/drawable-hdpi-v11/ic_menu_bookmark_add.png \
|
||||
res/drawable-hdpi-v11/ic_menu_bookmark_remove.png \
|
||||
res/drawable-hdpi-v11/ic_menu_find_in_page.png \
|
||||
res/drawable-hdpi-v11/ic_menu_reload.png \
|
||||
res/drawable-hdpi-v11/ic_menu_save_as_pdf.png \
|
||||
res/drawable-hdpi-v11/ic_menu_share.png \
|
||||
res/drawable-hdpi-v11/tabs_normal.png \
|
||||
res/drawable-hdpi-v11/tabs_pressed.png \
|
||||
res/drawable-hdpi-v11/tabs_more.png \
|
||||
res/drawable-hdpi-v11/tabs_plus.png \
|
||||
res/drawable-hdpi-v11/address_bar_url_bg.9.png \
|
||||
$(NULL)
|
||||
|
||||
RES_DRAWABLE_XHDPI_V11 = \
|
||||
res/drawable-xhdpi-v11/ic_menu_bookmark_add.png \
|
||||
res/drawable-xhdpi-v11/ic_menu_bookmark_remove.png \
|
||||
res/drawable-xhdpi-v11/ic_menu_find_in_page.png \
|
||||
res/drawable-xhdpi-v11/ic_menu_reload.png \
|
||||
res/drawable-xhdpi-v11/ic_menu_save_as_pdf.png \
|
||||
res/drawable-xhdpi-v11/ic_menu_share.png \
|
||||
res/drawable-xhdpi-v11/tabs_normal.png \
|
||||
res/drawable-xhdpi-v11/tabs_pressed.png \
|
||||
res/drawable-xhdpi-v11/tabs_more.png \
|
||||
res/drawable-xhdpi-v11/tabs_plus.png \
|
||||
res/drawable-xhdpi-v11/address_bar_url_bg.9.png \
|
||||
$(NULL)
|
||||
|
||||
RES_COLOR = \
|
||||
res/color/awesomebar_tab_text.xml
|
||||
|
||||
AB_rCD = $(shell echo $(AB_CD) | sed -e s/-/-r/)
|
||||
|
||||
JAVA_CLASSPATH = $(ANDROID_SDK)/android.jar
|
||||
|
||||
DEFAULT_BRANDPATH = $(DEPTH)/$(MOZ_BRANDING_DIRECTORY)/locales/en-US/brand.dtd
|
||||
DEFAULT_STRINGSPATH = locales/en-US/android_strings.dtd
|
||||
LOCALIZED_BRANDPATH = $(DEPTH)/dist/bin/chrome/$(AB_CD)/locale/branding/brand.dtd
|
||||
LOCALIZED_STRINGSPATH = $(DEPTH)/dist/bin/chrome/android-res/res/values-$(AB_CD)/android_strings.dtd
|
||||
|
||||
ifdef MOZ_CRASHREPORTER
|
||||
PROCESSEDJAVAFILES += CrashReporter.java
|
||||
MOZ_ANDROID_DRAWABLES += mobile/android/base/resources/drawable/crash_reporter.png
|
||||
RES_LAYOUT += res/layout/crash_reporter.xml
|
||||
endif
|
||||
|
||||
MOZ_ANDROID_DRAWABLES += mobile/android/base/resources/drawable/address_bar_bg.xml \
|
||||
mobile/android/base/resources/drawable/address_bar_url_default.xml \
|
||||
mobile/android/base/resources/drawable/address_bar_url_pressed.xml \
|
||||
mobile/android/base/resources/drawable/awesomebar_tab_focus.xml \
|
||||
mobile/android/base/resources/drawable/awesomebar_tab_focus_selected.xml \
|
||||
mobile/android/base/resources/drawable/awesomebar_tab_indicator.xml \
|
||||
mobile/android/base/resources/drawable/awesomebar_tab_press.xml \
|
||||
mobile/android/base/resources/drawable/awesomebar_tab_press_selected.xml \
|
||||
mobile/android/base/resources/drawable/awesomebar_tab_selected.xml \
|
||||
mobile/android/base/resources/drawable/awesomebar_tab_unselected.xml \
|
||||
mobile/android/base/resources/drawable/desktop_notification.png \
|
||||
mobile/android/base/resources/drawable/favicon.png \
|
||||
mobile/android/base/resources/drawable/progress_spinner.xml \
|
||||
mobile/android/base/resources/drawable/progress_spinner_1.png \
|
||||
mobile/android/base/resources/drawable/progress_spinner_2.png \
|
||||
mobile/android/base/resources/drawable/progress_spinner_3.png \
|
||||
mobile/android/base/resources/drawable/progress_spinner_4.png \
|
||||
mobile/android/base/resources/drawable/progress_spinner_5.png \
|
||||
mobile/android/base/resources/drawable/progress_spinner_6.png \
|
||||
mobile/android/base/resources/drawable/progress_spinner_7.png \
|
||||
mobile/android/base/resources/drawable/progress_spinner_8.png \
|
||||
mobile/android/base/resources/drawable/progress_spinner_9.png \
|
||||
mobile/android/base/resources/drawable/progress_spinner_10.png \
|
||||
mobile/android/base/resources/drawable/progress_spinner_11.png \
|
||||
mobile/android/base/resources/drawable/progress_spinner_12.png \
|
||||
mobile/android/base/resources/drawable/progress_spinner_13.png \
|
||||
mobile/android/base/resources/drawable/progress_spinner_14.png \
|
||||
mobile/android/base/resources/drawable/progress_spinner_15.png \
|
||||
mobile/android/base/resources/drawable/progress_spinner_16.png \
|
||||
mobile/android/base/resources/drawable/progress_spinner_17.png \
|
||||
mobile/android/base/resources/drawable/progress_spinner_18.png \
|
||||
mobile/android/base/resources/drawable/start.png \
|
||||
mobile/android/base/resources/drawable/site_security_level.xml \
|
||||
mobile/android/base/resources/drawable/tab_new.png \
|
||||
mobile/android/base/resources/drawable/tab_close.png \
|
||||
mobile/android/base/resources/drawable/tabs_button.xml \
|
||||
mobile/android/base/resources/drawable/tabs_level.xml \
|
||||
mobile/android/base/resources/drawable/tabs_tray_bg.9.png \
|
||||
mobile/android/base/resources/drawable/checkerboard.png \
|
||||
mobile/android/base/resources/drawable/shadow.png \
|
||||
$(NULL)
|
||||
|
||||
|
||||
MOZ_ANDROID_DRAWABLES += $(shell if test -e $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/android-resources.mn; then cat $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/android-resources.mn | tr '\n' ' '; fi)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
ifneq ($(AB_CD),en-US)
|
||||
LOCALIZED_STRINGS_XML = res/values-$(AB_rCD)/strings.xml
|
||||
endif
|
||||
|
||||
# Override the Java settings with some specific android settings
|
||||
include $(topsrcdir)/config/android-common.mk
|
||||
|
||||
# Note that we're going to set up a dependency directly between embed_android.dex and the java files
|
||||
# Instead of on the .class files, since more than one .class file might be produced per .java file
|
||||
classes.dex: $(JAVAFILES) $(PROCESSEDJAVAFILES) R.java
|
||||
$(NSINSTALL) -D classes
|
||||
$(JAVAC) $(JAVAC_FLAGS) -Xlint:unchecked -Xlint:deprecation -d classes $(addprefix $(srcdir)/,$(JAVAFILES)) $(PROCESSEDJAVAFILES) R.java
|
||||
$(DX) --dex --output=$@ classes
|
||||
|
||||
AndroidManifest.xml $(PROCESSEDJAVAFILES) package-name.txt: % : %.in
|
||||
$(PYTHON) $(topsrcdir)/config/Preprocessor.py \
|
||||
$(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $< > $@
|
||||
|
||||
res/drawable/icon.png: $(MOZ_APP_ICON)
|
||||
$(NSINSTALL) -D res/drawable
|
||||
cp $(ICON_PATH) $@
|
||||
|
||||
res/drawable-hdpi/icon.png: $(MOZ_APP_ICON)
|
||||
$(NSINSTALL) -D res/drawable-hdpi
|
||||
cp $(ICON_PATH_HDPI) $@
|
||||
|
||||
RES_DRAWABLE = $(addprefix res/drawable/,$(notdir $(MOZ_ANDROID_DRAWABLES)))
|
||||
|
||||
$(RES_DRAWABLE): $(addprefix $(topsrcdir)/,$(MOZ_ANDROID_DRAWABLES))
|
||||
$(NSINSTALL) -D res/drawable
|
||||
$(NSINSTALL) $^ res/drawable/
|
||||
|
||||
$(RES_LAYOUT): $(subst res/,$(srcdir)/resources/,$(RES_LAYOUT))
|
||||
$(NSINSTALL) -D res/layout
|
||||
$(NSINSTALL) $^ res/layout
|
||||
|
||||
$(RES_VALUES): $(subst res/,$(srcdir)/resources/,$(RES_VALUES))
|
||||
$(NSINSTALL) -D res/values
|
||||
$(NSINSTALL) $^ res/values
|
||||
|
||||
$(RES_XML): $(subst res/,$(srcdir)/resources/,$(RES_XML))
|
||||
$(NSINSTALL) -D res/xml
|
||||
$(NSINSTALL) $(srcdir)/resources/xml/* res/xml/
|
||||
|
||||
$(RES_ANIM): $(subst res/,$(srcdir)/resources/,$(RES_ANIM))
|
||||
$(NSINSTALL) -D res/anim
|
||||
$(NSINSTALL) $(srcdir)/resources/anim/* res/anim/
|
||||
|
||||
$(RES_DRAWABLE_MDPI_V8): $(subst res/,$(srcdir)/resources/,$(RES_DRAWABLE_MDPI_V8))
|
||||
$(NSINSTALL) -D res/drawable-mdpi-v8
|
||||
$(NSINSTALL) $(srcdir)/resources/drawable-mdpi-v8/* res/drawable-mdpi-v8/
|
||||
|
||||
$(RES_DRAWABLE_HDPI_V8): $(subst res/,$(srcdir)/resources/,$(RES_DRAWABLE_HDPI_V8))
|
||||
$(NSINSTALL) -D res/drawable-hdpi-v8
|
||||
$(NSINSTALL) $(srcdir)/resources/drawable-hdpi-v8/* res/drawable-hdpi-v8/
|
||||
|
||||
$(RES_DRAWABLE_MDPI_V9): $(subst res/,$(srcdir)/resources/,$(RES_DRAWABLE_MDPI_V9))
|
||||
$(NSINSTALL) -D res/drawable-mdpi-v9
|
||||
$(NSINSTALL) $(srcdir)/resources/drawable-mdpi-v9/* res/drawable-mdpi-v9/
|
||||
|
||||
$(RES_DRAWABLE_HDPI_V9): $(subst res/,$(srcdir)/resources/,$(RES_DRAWABLE_HDPI_V9))
|
||||
$(NSINSTALL) -D res/drawable-hdpi-v9
|
||||
$(NSINSTALL) $(srcdir)/resources/drawable-hdpi-v9/* res/drawable-hdpi-v9/
|
||||
|
||||
$(RES_DRAWABLE_MDPI_V11): $(subst res/,$(srcdir)/resources/,$(RES_DRAWABLE_MDPI_V11))
|
||||
$(NSINSTALL) -D res/drawable-mdpi-v11
|
||||
$(NSINSTALL) $(srcdir)/resources/drawable-mdpi-v11/* res/drawable-mdpi-v11/
|
||||
|
||||
$(RES_DRAWABLE_HDPI_V11): $(subst res/,$(srcdir)/resources/,$(RES_DRAWABLE_HDPI_V11))
|
||||
$(NSINSTALL) -D res/drawable-hdpi-v11
|
||||
$(NSINSTALL) $(srcdir)/resources/drawable-hdpi-v11/* res/drawable-hdpi-v11/
|
||||
|
||||
$(RES_DRAWABLE_XHDPI_V11): $(subst res/,$(srcdir)/resources/,$(RES_DRAWABLE_XHDPI_V11))
|
||||
$(NSINSTALL) -D res/drawable-xhdpi-v11
|
||||
$(NSINSTALL) $(srcdir)/resources/drawable-xhdpi-v11/* res/drawable-xhdpi-v11/
|
||||
|
||||
$(RES_COLOR): $(subst res/,$(srcdir)/resources/,$(RES_COLOR))
|
||||
$(NSINSTALL) -D res/color
|
||||
$(NSINSTALL) $^ res/color
|
||||
|
||||
R.java: $(MOZ_APP_ICON) $(RES_LAYOUT) $(RES_DRAWABLE) $(RES_VALUES) $(RES_XML) $(RES_ANIM) $(RES_DRAWABLE_MDPI_V8) $(RES_DRAWABLE_HDPI_V8) $(RES_DRAWABLE_MDPI_V9) $(RES_DRAWABLE_HDPI_V9) $(RES_DRAWABLE_MDPI_V11) $(RES_DRAWABLE_HDPI_V11) $(RES_DRAWABLE_XHDPI_V11) $(RES_COLOR) res/drawable/icon.png res/drawable-hdpi/icon.png res/values/strings.xml AndroidManifest.xml
|
||||
$(AAPT) package -f -M AndroidManifest.xml -I $(ANDROID_SDK)/android.jar -S res -J . --custom-package org.mozilla.gecko
|
||||
|
||||
gecko.ap_: AndroidManifest.xml res/drawable/icon.png res/drawable-hdpi/icon.png $(RES_LAYOUT) $(RES_DRAWABLE) $(RES_VALUES) $(RES_XML) $(RES_ANIM) $(RES_DRAWABLE_MDPI_V8) $(RES_DRAWABLE_HDPI_V8) $(RES_DRAWABLE_MDPI_V9) $(RES_DRAWABLE_HDPI_V9) $(RES_DRAWABLE_MDPI_V11) $(RES_DRAWABLE_HDPI_V11) $(RES_DRAWABLE_XHDPI_V11) $(RES_COLOR) res/values/strings.xml FORCE
|
||||
$(AAPT) package -f -M AndroidManifest.xml -I $(ANDROID_SDK)/android.jar -S res -F $@
|
||||
|
||||
res/values/strings.xml: $(DEFAULT_BRANDPATH) $(DEFAULT_STRINGSPATH) $(srcdir)/strings.xml.in
|
||||
mkdir -p res/values
|
||||
$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) \
|
||||
-DBRANDPATH="$(DEFAULT_BRANDPATH)" \
|
||||
-DSTRINGSPATH="$(DEFAULT_STRINGSPATH)" \
|
||||
$(srcdir)/strings.xml.in \
|
||||
> $@
|
||||
|
||||
res/values-$(AB_rCD)/strings.xml: $(LOCALIZED_BRANDPATH) $(LOCALIZED_STRINGSPATH) $(srcdir)/strings.xml.in
|
||||
mkdir -p res/values-$(AB_rCD)
|
||||
$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) \
|
||||
-DBRANDPATH="$(call core_abspath,$(LOCALIZED_BRANDPATH))" \
|
||||
-DSTRINGSPATH="$(call core_abspath,$(LOCALIZED_STRINGSPATH))" \
|
||||
$(srcdir)/strings.xml.in \
|
||||
> $@
|
||||
|
||||
chrome:: $(LOCALIZED_STRINGS_XML)
|
||||
|
||||
libs:: classes.dex package-name.txt
|
||||
$(INSTALL) classes.dex $(FINAL_TARGET)
|
||||
$(INSTALL) package-name.txt $(FINAL_TARGET)
|
106
mobile/android/base/NotificationHandler.java.in
Normal file
@ -0,0 +1,106 @@
|
||||
/* -*- 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 Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Alex Pakhotin <alexp@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 ***** */
|
||||
|
||||
#filter substitution
|
||||
package @ANDROID_PACKAGE_NAME@;
|
||||
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Intent;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.net.Uri;
|
||||
|
||||
public class NotificationHandler
|
||||
extends BroadcastReceiver
|
||||
{
|
||||
private static final String LOGTAG = "GeckoNotificationHandler";
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent != null)
|
||||
handleIntent(context, intent);
|
||||
}
|
||||
|
||||
protected void handleIntent(Context context, Intent notificationIntent) {
|
||||
String action = notificationIntent.getAction();
|
||||
String alertName = "";
|
||||
String alertCookie = "";
|
||||
Uri data = notificationIntent.getData();
|
||||
if (data != null) {
|
||||
alertName = data.getSchemeSpecificPart();
|
||||
alertCookie = data.getFragment();
|
||||
if (alertCookie == null)
|
||||
alertCookie = "";
|
||||
}
|
||||
|
||||
Log.i(LOGTAG, "NotificationHandler.handleIntent\n" +
|
||||
"- action = '" + action + "'\n" +
|
||||
"- alertName = '" + alertName + "'\n" +
|
||||
"- alertCookie = '" + alertCookie + "'");
|
||||
|
||||
int notificationID = alertName.hashCode();
|
||||
|
||||
Log.i(LOGTAG, "Handle notification ID " + notificationID);
|
||||
|
||||
if (App.mAppContext != null) {
|
||||
// This should call the observer, if any
|
||||
App.mAppContext.handleNotification(action, alertName, alertCookie);
|
||||
} else {
|
||||
// The app is not running, just cancel this notification
|
||||
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.cancel(notificationID);
|
||||
}
|
||||
|
||||
if (App.ACTION_ALERT_CLICK.equals(action)) {
|
||||
// Start or bring to front the main activity
|
||||
Intent appIntent = new Intent(Intent.ACTION_MAIN);
|
||||
appIntent.setClassName(context, "@ANDROID_PACKAGE_NAME@.App");
|
||||
appIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
appIntent.putExtra("args", "-alert " + alertName + (alertCookie.length() > 0 ? "#" + alertCookie : ""));
|
||||
try {
|
||||
Log.i(LOGTAG, "startActivity with intent: Action='" + appIntent.getAction() + "'" +
|
||||
", args='" + appIntent.getStringExtra("args") + "'" );
|
||||
context.startActivity(appIntent);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Log.e(LOGTAG, "NotificationHandler Exception: ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
461
mobile/android/base/PromptService.java
Normal file
@ -0,0 +1,461 @@
|
||||
/* -*- 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) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Wes Johnston <wjohnston@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.List;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
import android.util.Log;
|
||||
import java.lang.String;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup.LayoutParams;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.TextView;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CheckedTextView;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ListView;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnClickListener;
|
||||
import android.content.DialogInterface.OnCancelListener;
|
||||
import android.content.DialogInterface.OnMultiChoiceClickListener;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import android.text.method.PasswordTransformationMethod;
|
||||
import android.graphics.Color;
|
||||
import android.text.InputType;
|
||||
import android.app.AlertDialog;
|
||||
|
||||
public class PromptService implements OnClickListener, OnCancelListener, OnItemClickListener {
|
||||
private static final String LOGTAG = "GeckoPromptService";
|
||||
|
||||
private PromptInput[] mInputs;
|
||||
private AlertDialog mDialog = null;
|
||||
|
||||
private class PromptButton {
|
||||
public String label = "";
|
||||
PromptButton(JSONObject aJSONButton) {
|
||||
try {
|
||||
label = aJSONButton.getString("label");
|
||||
} catch(Exception ex) { }
|
||||
}
|
||||
}
|
||||
|
||||
private class PromptInput {
|
||||
private String label = "";
|
||||
private String type = "";
|
||||
private String hint = "";
|
||||
private JSONObject mJSONInput = null;
|
||||
private View view = null;
|
||||
|
||||
public PromptInput(JSONObject aJSONInput) {
|
||||
mJSONInput = aJSONInput;
|
||||
try {
|
||||
label = aJSONInput.getString("label");
|
||||
} catch(Exception ex) { }
|
||||
try {
|
||||
type = aJSONInput.getString("type");
|
||||
} catch(Exception ex) { }
|
||||
try {
|
||||
hint = aJSONInput.getString("hint");
|
||||
} catch(Exception ex) { }
|
||||
}
|
||||
|
||||
public View getView() {
|
||||
if (type.equals("checkbox")) {
|
||||
CheckBox checkbox = new CheckBox(GeckoApp.mAppContext);
|
||||
checkbox.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
|
||||
checkbox.setText(label);
|
||||
try {
|
||||
Boolean value = mJSONInput.getBoolean("checked");
|
||||
checkbox.setChecked(value);
|
||||
} catch(Exception ex) { }
|
||||
view = (View)checkbox;
|
||||
} else if (type.equals("textbox") || this.type.equals("password")) {
|
||||
EditText input = new EditText(GeckoApp.mAppContext);
|
||||
int inputtype = InputType.TYPE_CLASS_TEXT;
|
||||
if (type.equals("password")) {
|
||||
inputtype |= InputType.TYPE_TEXT_VARIATION_PASSWORD | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
|
||||
}
|
||||
input.setInputType(inputtype);
|
||||
|
||||
try {
|
||||
String value = mJSONInput.getString("value");
|
||||
input.setText(value);
|
||||
} catch(Exception ex) { }
|
||||
|
||||
if (!hint.equals("")) {
|
||||
input.setHint(hint);
|
||||
}
|
||||
view = (View)input;
|
||||
} else if (type.equals("menulist")) {
|
||||
Spinner spinner = new Spinner(GeckoApp.mAppContext);
|
||||
try {
|
||||
String[] listitems = getStringArray(mJSONInput, "values");
|
||||
if (listitems.length > 0) {
|
||||
ArrayAdapter<String> adapter = new ArrayAdapter<String>(GeckoApp.mAppContext, android.R.layout.simple_dropdown_item_1line, listitems);
|
||||
spinner.setAdapter(adapter);
|
||||
}
|
||||
} catch(Exception ex) { }
|
||||
view = (View)spinner;
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
if (this.type.equals("checkbox")) {
|
||||
CheckBox checkbox = (CheckBox)view;
|
||||
return checkbox.isChecked() ? "true" : "false";
|
||||
} else if (type.equals("textbox") || type.equals("password")) {
|
||||
EditText edit = (EditText)view;
|
||||
return edit.getText().toString();
|
||||
} else if (type.equals("menulist")) {
|
||||
Spinner spinner = (Spinner)view;
|
||||
return Integer.toString(spinner.getSelectedItemPosition());
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public void Show(String aTitle, String aText, PromptButton[] aButtons, PromptListItem[] aMenuList, boolean aMultipleSelection) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(GeckoApp.mAppContext);
|
||||
if (!aTitle.equals("")) {
|
||||
builder.setTitle(aTitle);
|
||||
}
|
||||
|
||||
if (!aText.equals("")) {
|
||||
builder.setMessage(aText);
|
||||
}
|
||||
|
||||
int length = mInputs.length;
|
||||
if (aMenuList.length > 0) {
|
||||
int resourceId = android.R.layout.select_dialog_item;
|
||||
if (mSelected != null && mSelected.length > 0) {
|
||||
if (aMultipleSelection) {
|
||||
resourceId = android.R.layout.select_dialog_multichoice;
|
||||
} else {
|
||||
resourceId = android.R.layout.select_dialog_singlechoice;
|
||||
}
|
||||
}
|
||||
PromptListAdapter adapter = new PromptListAdapter(GeckoApp.mAppContext, resourceId, aMenuList);
|
||||
if (mSelected != null && mSelected.length > 0) {
|
||||
if (aMultipleSelection) {
|
||||
LayoutInflater inflater = GeckoApp.mAppContext.getLayoutInflater();
|
||||
adapter.listView = (ListView) inflater.inflate(R.layout.select_dialog_list, null);
|
||||
adapter.listView.setOnItemClickListener(this);
|
||||
builder.setInverseBackgroundForced(true);
|
||||
adapter.listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
|
||||
adapter.listView.setAdapter(adapter);
|
||||
builder.setView(adapter.listView);
|
||||
} else {
|
||||
int selectedIndex = -1;
|
||||
for (int i = 0; i < mSelected.length; i++) {
|
||||
if (mSelected[i]) {
|
||||
selectedIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mSelected = null;
|
||||
builder.setSingleChoiceItems(adapter, selectedIndex, this);
|
||||
}
|
||||
} else {
|
||||
builder.setAdapter(adapter, this);
|
||||
mSelected = null;
|
||||
}
|
||||
} else if (length == 1) {
|
||||
builder.setView(mInputs[0].getView());
|
||||
} else if (length > 1) {
|
||||
LinearLayout linearLayout = new LinearLayout(GeckoApp.mAppContext);
|
||||
linearLayout.setOrientation(LinearLayout.VERTICAL);
|
||||
for (int i = 0; i < length; i++) {
|
||||
View content = mInputs[i].getView();
|
||||
linearLayout.addView(content);
|
||||
}
|
||||
builder.setView((View)linearLayout);
|
||||
}
|
||||
|
||||
length = aButtons.length;
|
||||
if (length > 0) {
|
||||
builder.setPositiveButton(aButtons[0].label, this);
|
||||
}
|
||||
if (length > 1) {
|
||||
builder.setNeutralButton(aButtons[1].label, this);
|
||||
}
|
||||
if (length > 2) {
|
||||
builder.setNegativeButton(aButtons[2].label, this);
|
||||
}
|
||||
|
||||
mDialog = builder.create();
|
||||
mDialog.setOnCancelListener(this);
|
||||
mDialog.show();
|
||||
}
|
||||
|
||||
public void onClick(DialogInterface aDialog, int aWhich) {
|
||||
JSONObject ret = new JSONObject();
|
||||
try {
|
||||
int button = -1;
|
||||
ListView list = mDialog.getListView();
|
||||
if (list != null || mSelected != null) {
|
||||
button = aWhich;
|
||||
if (mSelected != null) {
|
||||
JSONArray selected = new JSONArray();
|
||||
for (int i = 0; i < mSelected.length; i++) {
|
||||
selected.put(mSelected[i]);
|
||||
}
|
||||
ret.put("button", selected);
|
||||
} else {
|
||||
ret.put("button", button);
|
||||
}
|
||||
} else {
|
||||
switch(aWhich) {
|
||||
case DialogInterface.BUTTON_POSITIVE : button = 0; break;
|
||||
case DialogInterface.BUTTON_NEUTRAL : button = 1; break;
|
||||
case DialogInterface.BUTTON_NEGATIVE : button = 2; break;
|
||||
}
|
||||
ret.put("button", button);
|
||||
}
|
||||
if (mInputs != null) {
|
||||
for (int i = 0; i < mInputs.length; i++) {
|
||||
ret.put(mInputs[i].getName(), mInputs[i].getValue());
|
||||
}
|
||||
}
|
||||
} catch(Exception ex) {
|
||||
Log.i(LOGTAG, "Error building return: " + ex);
|
||||
}
|
||||
|
||||
if (mDialog != null) {
|
||||
mDialog.dismiss();
|
||||
}
|
||||
|
||||
finishDialog(ret.toString());
|
||||
}
|
||||
|
||||
private boolean[] mSelected = null;
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
mSelected[position] = !mSelected[position];
|
||||
}
|
||||
|
||||
public void onCancel(DialogInterface aDialog) {
|
||||
JSONObject ret = new JSONObject();
|
||||
try {
|
||||
ret.put("button", -1);
|
||||
} catch(Exception ex) { }
|
||||
finishDialog(ret.toString());
|
||||
}
|
||||
|
||||
public void finishDialog(String aReturn) {
|
||||
mInputs = null;
|
||||
mDialog = null;
|
||||
mSelected = null;
|
||||
try {
|
||||
GeckoAppShell.sPromptQueue.put(aReturn);
|
||||
} catch(Exception ex) { }
|
||||
}
|
||||
|
||||
public void processMessage(JSONObject geckoObject) {
|
||||
String title = "";
|
||||
try {
|
||||
title = geckoObject.getString("title");
|
||||
} catch(Exception ex) { }
|
||||
String text = "";
|
||||
try {
|
||||
text = geckoObject.getString("text");
|
||||
} catch(Exception ex) { }
|
||||
|
||||
JSONArray buttons = new JSONArray();
|
||||
try {
|
||||
buttons = geckoObject.getJSONArray("buttons");
|
||||
} catch(Exception ex) { }
|
||||
int length = buttons.length();
|
||||
PromptButton[] promptbuttons = new PromptButton[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
try {
|
||||
promptbuttons[i] = new PromptButton(buttons.getJSONObject(i));
|
||||
} catch(Exception ex) { }
|
||||
}
|
||||
|
||||
JSONArray inputs = new JSONArray();
|
||||
try {
|
||||
inputs = geckoObject.getJSONArray("inputs");
|
||||
} catch(Exception ex) { }
|
||||
length = inputs.length();
|
||||
mInputs = new PromptInput[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
try {
|
||||
mInputs[i] = new PromptInput(inputs.getJSONObject(i));
|
||||
} catch(Exception ex) { }
|
||||
}
|
||||
|
||||
PromptListItem[] menuitems = getListItemArray(geckoObject, "listitems");
|
||||
mSelected = getBooleanArray(geckoObject, "selected");
|
||||
boolean multiple = false;
|
||||
try {
|
||||
multiple = geckoObject.getBoolean("multiple");
|
||||
} catch(Exception ex) { }
|
||||
this.Show(title, text, promptbuttons, menuitems, multiple);
|
||||
}
|
||||
|
||||
private String[] getStringArray(JSONObject aObject, String aName) {
|
||||
JSONArray items = new JSONArray();
|
||||
try {
|
||||
items = aObject.getJSONArray(aName);
|
||||
} catch(Exception ex) { }
|
||||
int length = items.length();
|
||||
String[] list = new String[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
try {
|
||||
list[i] = items.getString(i);
|
||||
} catch(Exception ex) { }
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private boolean[] getBooleanArray(JSONObject aObject, String aName) {
|
||||
JSONArray items = new JSONArray();
|
||||
try {
|
||||
items = aObject.getJSONArray(aName);
|
||||
} catch(Exception ex) { return null; }
|
||||
int length = items.length();
|
||||
boolean[] list = new boolean[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
try {
|
||||
list[i] = items.getBoolean(i);
|
||||
} catch(Exception ex) { }
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private PromptListItem[] getListItemArray(JSONObject aObject, String aName) {
|
||||
JSONArray items = new JSONArray();
|
||||
try {
|
||||
items = aObject.getJSONArray(aName);
|
||||
} catch(Exception ex) { }
|
||||
int length = items.length();
|
||||
PromptListItem[] list = new PromptListItem[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
try {
|
||||
list[i] = new PromptListItem(items.getJSONObject(i));
|
||||
} catch(Exception ex) { }
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private class PromptListItem {
|
||||
public String label = "";
|
||||
public boolean isGroup = false;
|
||||
public boolean inGroup = false;
|
||||
public boolean disabled = false;
|
||||
public int id = 0;
|
||||
PromptListItem(JSONObject aObject) {
|
||||
try { label = aObject.getString("label"); } catch(Exception ex) { }
|
||||
try { isGroup = aObject.getBoolean("isGroup"); } catch(Exception ex) { }
|
||||
try { inGroup = aObject.getBoolean("inGroup"); } catch(Exception ex) { }
|
||||
try { disabled = aObject.getBoolean("disabled"); } catch(Exception ex) { }
|
||||
try { id = aObject.getInt("id"); } catch(Exception ex) { }
|
||||
}
|
||||
}
|
||||
|
||||
public class PromptListAdapter extends ArrayAdapter<PromptListItem> {
|
||||
public ListView listView = null;
|
||||
private PromptListItem[] mList;
|
||||
private int mResourceId = -1;
|
||||
PromptListAdapter(Context context, int textViewResourceId, PromptListItem[] objects) {
|
||||
super(context, textViewResourceId, objects);
|
||||
mList = objects;
|
||||
mResourceId = textViewResourceId;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return mList.length;
|
||||
}
|
||||
|
||||
public PromptListItem getItem(int position) {
|
||||
return mList[position];
|
||||
}
|
||||
|
||||
public long getItemId(int position) {
|
||||
return mList[position].id;
|
||||
}
|
||||
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
PromptListItem item = getItem(position);
|
||||
int resourceId = mResourceId;
|
||||
if (item.isGroup) {
|
||||
resourceId = R.layout.list_item_header;
|
||||
}
|
||||
LayoutInflater inflater = GeckoApp.mAppContext.getLayoutInflater();
|
||||
View row = inflater.inflate(resourceId, null);
|
||||
if (!item.isGroup){
|
||||
try {
|
||||
CheckedTextView ct = (CheckedTextView)row.findViewById(android.R.id.text1);
|
||||
if (ct != null){
|
||||
ct.setEnabled(!item.disabled);
|
||||
ct.setClickable(item.disabled);
|
||||
|
||||
// Apparently just using ct.setChecked(true) doesn't work, so this
|
||||
// is stolen from the android source code as a way to set the checked
|
||||
// state of these items
|
||||
if (mSelected[position] && listView != null) {
|
||||
listView.setItemChecked(position, true);
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) { }
|
||||
}
|
||||
TextView t1 = (TextView) row.findViewById(android.R.id.text1);
|
||||
if (t1 != null) {
|
||||
t1.setText(item.label);
|
||||
}
|
||||
|
||||
return row;
|
||||
}
|
||||
}
|
||||
}
|
95
mobile/android/base/Restarter.java.in
Normal file
@ -0,0 +1,95 @@
|
||||
/* -*- 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):
|
||||
* Brad Lassey <blassey@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 ***** */
|
||||
|
||||
#filter substitution
|
||||
package @ANDROID_PACKAGE_NAME@;
|
||||
|
||||
import android.app.*;
|
||||
import android.content.*;
|
||||
import android.util.*;
|
||||
import android.os.*;
|
||||
import java.io.*;
|
||||
import org.mozilla.gecko.GeckoAppShell;
|
||||
|
||||
public class Restarter extends Activity {
|
||||
private static final String LOGTAG = "GeckoRestarter";
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
Log.i(LOGTAG, "trying to restart @MOZ_APP_NAME@");
|
||||
try {
|
||||
int countdown = 40;
|
||||
while (GeckoAppShell.checkForGeckoProcs() && --countdown > 0) {
|
||||
// Wait for the old process to die before we continue
|
||||
try {
|
||||
Thread.currentThread().sleep(100);
|
||||
} catch (InterruptedException ie) {}
|
||||
}
|
||||
|
||||
if (countdown <= 0) {
|
||||
// if the countdown expired, something is hung
|
||||
GeckoAppShell.killAnyZombies();
|
||||
countdown = 10;
|
||||
// wait for the kill to take effect
|
||||
while (GeckoAppShell.checkForGeckoProcs() && --countdown > 0) {
|
||||
try {
|
||||
Thread.currentThread().sleep(100);
|
||||
} catch (InterruptedException ie) {}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.i(LOGTAG, e.toString());
|
||||
}
|
||||
try {
|
||||
String action = "android.intent.action.MAIN";
|
||||
Intent intent = new Intent(action);
|
||||
intent.setClassName("@ANDROID_PACKAGE_NAME@",
|
||||
"@ANDROID_PACKAGE_NAME@.App");
|
||||
Bundle b = getIntent().getExtras();
|
||||
if (b != null)
|
||||
intent.putExtras(b);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
Log.i(LOGTAG, intent.toString());
|
||||
startActivity(intent);
|
||||
} catch (Exception e) {
|
||||
Log.i(LOGTAG, e.toString());
|
||||
}
|
||||
// Give the new process time to start before we die
|
||||
GeckoAppShell.waitForAnotherGeckoProc();
|
||||
System.exit(0);
|
||||
}
|
||||
};
|
18
mobile/android/base/SurfaceLockInfo.java
Normal file
@ -0,0 +1,18 @@
|
||||
package org.mozilla.gecko;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import java.nio.Buffer;
|
||||
|
||||
public class SurfaceLockInfo {
|
||||
public int dirtyTop;
|
||||
public int dirtyLeft;
|
||||
public int dirtyRight;
|
||||
public int dirtyBottom;
|
||||
|
||||
public int bpr;
|
||||
public int format;
|
||||
public int width;
|
||||
public int height;
|
||||
public Buffer buffer;
|
||||
public Canvas canvas;
|
||||
}
|
411
mobile/android/base/Tab.java
Normal file
@ -0,0 +1,411 @@
|
||||
/* -*- 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) 2009-2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Sriram Ramasubramanian <sriram@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 android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.provider.Browser;
|
||||
import android.util.Log;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class Tab {
|
||||
private static final String LOGTAG = "GeckoTab";
|
||||
|
||||
private int mId;
|
||||
private String mUrl;
|
||||
private String mTitle;
|
||||
private Drawable mFavicon;
|
||||
private String mFaviconUrl;
|
||||
private String mSecurityMode;
|
||||
private Drawable mThumbnail;
|
||||
private List<HistoryEntry> mHistory;
|
||||
private int mHistoryIndex;
|
||||
private boolean mLoading;
|
||||
private boolean mBookmark;
|
||||
private HashMap<String, DoorHanger> mDoorHangers;
|
||||
private long mFaviconLoadId;
|
||||
|
||||
static class HistoryEntry {
|
||||
public final String mUri;
|
||||
public String mTitle;
|
||||
|
||||
public HistoryEntry(String uri, String title) {
|
||||
mUri = uri;
|
||||
mTitle = title;
|
||||
}
|
||||
}
|
||||
|
||||
public Tab() {
|
||||
this(-1, "");
|
||||
}
|
||||
|
||||
public Tab(int id, String url) {
|
||||
mId = id;
|
||||
mUrl = url;
|
||||
mTitle = new String();
|
||||
mFavicon = null;
|
||||
mFaviconUrl = null;
|
||||
mSecurityMode = "unknown";
|
||||
mThumbnail = null;
|
||||
mHistory = new ArrayList<HistoryEntry>();
|
||||
mHistoryIndex = -1;
|
||||
mBookmark = false;
|
||||
mDoorHangers = new HashMap<String, DoorHanger>();
|
||||
mFaviconLoadId = 0;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return mId;
|
||||
}
|
||||
|
||||
public String getURL() {
|
||||
return mUrl;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return mTitle;
|
||||
}
|
||||
|
||||
public String getDisplayTitle() {
|
||||
if (mTitle != null && mTitle.length() > 0) {
|
||||
return mTitle;
|
||||
}
|
||||
|
||||
return mUrl;
|
||||
}
|
||||
|
||||
public Drawable getFavicon() {
|
||||
return mFavicon;
|
||||
}
|
||||
|
||||
public String getFaviconURL() {
|
||||
return mFaviconUrl;
|
||||
}
|
||||
|
||||
public String getSecurityMode() {
|
||||
return mSecurityMode;
|
||||
}
|
||||
|
||||
public boolean isLoading() {
|
||||
return mLoading;
|
||||
}
|
||||
|
||||
public boolean isBookmark() {
|
||||
return mBookmark;
|
||||
}
|
||||
|
||||
public void updateURL(String url) {
|
||||
if (url != null && url.length() > 0) {
|
||||
mUrl = new String(url);
|
||||
Log.i(LOGTAG, "Updated url: " + url + " for tab with id: " + mId);
|
||||
updateBookmark();
|
||||
}
|
||||
}
|
||||
|
||||
public void updateTitle(String title) {
|
||||
if (title != null && title.length() > 0) {
|
||||
mTitle = new String(title);
|
||||
} else {
|
||||
mTitle = "";
|
||||
}
|
||||
|
||||
Log.i(LOGTAG, "Updated title: " + mTitle + " for tab with id: " + mId);
|
||||
|
||||
final HistoryEntry he = getLastHistoryEntry();
|
||||
if (he != null) {
|
||||
he.mTitle = mTitle;
|
||||
GeckoAppShell.getHandler().post(new Runnable() {
|
||||
public void run() {
|
||||
GlobalHistory.getInstance().update(he.mUri, he.mTitle);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Log.e(LOGTAG, "Requested title update on empty history stack");
|
||||
}
|
||||
}
|
||||
|
||||
public void setLoading(boolean loading) {
|
||||
mLoading = loading;
|
||||
}
|
||||
|
||||
private void setBookmark(boolean bookmark) {
|
||||
mBookmark = bookmark;
|
||||
}
|
||||
|
||||
public void setFaviconLoadId(long faviconLoadId) {
|
||||
mFaviconLoadId = faviconLoadId;
|
||||
}
|
||||
|
||||
public long getFaviconLoadId() {
|
||||
return mFaviconLoadId;
|
||||
}
|
||||
|
||||
public HistoryEntry getLastHistoryEntry() {
|
||||
if (mHistory.isEmpty())
|
||||
return null;
|
||||
return mHistory.get(mHistoryIndex);
|
||||
}
|
||||
|
||||
public void updateFavicon(Drawable favicon) {
|
||||
mFavicon = favicon;
|
||||
Log.i(LOGTAG, "Updated favicon for tab with id: " + mId);
|
||||
}
|
||||
|
||||
public void updateFaviconURL(String faviconUrl) {
|
||||
mFaviconUrl = faviconUrl;
|
||||
Log.i(LOGTAG, "Updated favicon URL for tab with id: " + mId);
|
||||
}
|
||||
|
||||
public void updateSecurityMode(String mode) {
|
||||
mSecurityMode = mode;
|
||||
}
|
||||
|
||||
private void updateBookmark() {
|
||||
new CheckBookmarkTask().execute();
|
||||
}
|
||||
|
||||
public void addBookmark() {
|
||||
new AddBookmarkTask().execute();
|
||||
}
|
||||
|
||||
public void removeBookmark() {
|
||||
new RemoveBookmarkTask().execute();
|
||||
}
|
||||
|
||||
public boolean doReload() {
|
||||
if (mHistory.isEmpty())
|
||||
return false;
|
||||
GeckoEvent e = new GeckoEvent("Session:Reload", "");
|
||||
GeckoAppShell.sendEventToGecko(e);
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean doBack() {
|
||||
if (mHistoryIndex < 1) {
|
||||
return false;
|
||||
}
|
||||
GeckoEvent e = new GeckoEvent("Session:Back", "");
|
||||
GeckoAppShell.sendEventToGecko(e);
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean doStop() {
|
||||
GeckoEvent e = new GeckoEvent("Session:Stop", "");
|
||||
GeckoAppShell.sendEventToGecko(e);
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean canDoForward() {
|
||||
return (mHistoryIndex + 1 < mHistory.size());
|
||||
}
|
||||
|
||||
public boolean doForward() {
|
||||
if (mHistoryIndex + 1 >= mHistory.size()) {
|
||||
return false;
|
||||
}
|
||||
GeckoEvent e = new GeckoEvent("Session:Forward", "");
|
||||
GeckoAppShell.sendEventToGecko(e);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void addDoorHanger(String value, DoorHanger dh) {
|
||||
mDoorHangers.put(value, dh);
|
||||
}
|
||||
|
||||
public void removeDoorHanger(String value) {
|
||||
mDoorHangers.remove(value);
|
||||
}
|
||||
|
||||
public void removeAllDoorHangers() {
|
||||
mDoorHangers = new HashMap<String, DoorHanger>();
|
||||
}
|
||||
|
||||
public void removeTransientDoorHangers() {
|
||||
for (String value : mDoorHangers.keySet()) {
|
||||
DoorHanger dh = mDoorHangers.get(value);
|
||||
if (dh.shouldRemove())
|
||||
mDoorHangers.remove(value);
|
||||
}
|
||||
}
|
||||
|
||||
public DoorHanger getDoorHanger(String value) {
|
||||
if (mDoorHangers == null)
|
||||
return null;
|
||||
|
||||
if (mDoorHangers.containsKey(value))
|
||||
return mDoorHangers.get(value);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public HashMap<String, DoorHanger> getDoorHangers() {
|
||||
return mDoorHangers;
|
||||
}
|
||||
|
||||
void handleSessionHistoryMessage(String event, JSONObject message) throws JSONException {
|
||||
if (event.equals("New")) {
|
||||
final String uri = message.getString("uri");
|
||||
mHistoryIndex++;
|
||||
while (mHistory.size() > mHistoryIndex) {
|
||||
mHistory.remove(mHistoryIndex);
|
||||
}
|
||||
HistoryEntry he = new HistoryEntry(uri, null);
|
||||
mHistory.add(he);
|
||||
GeckoAppShell.getHandler().post(new Runnable() {
|
||||
public void run() {
|
||||
GlobalHistory.getInstance().add(uri);
|
||||
}
|
||||
});
|
||||
} else if (event.equals("Back")) {
|
||||
if (mHistoryIndex - 1 < 0) {
|
||||
Log.e(LOGTAG, "Received unexpected back notification");
|
||||
return;
|
||||
}
|
||||
mHistoryIndex--;
|
||||
} else if (event.equals("Forward")) {
|
||||
if (mHistoryIndex + 1 >= mHistory.size()) {
|
||||
Log.e(LOGTAG, "Received unexpected forward notification");
|
||||
return;
|
||||
}
|
||||
mHistoryIndex++;
|
||||
} else if (event.equals("Goto")) {
|
||||
int index = message.getInt("index");
|
||||
if (index < 0 || index >= mHistory.size()) {
|
||||
Log.e(LOGTAG, "Received unexpected history-goto notification");
|
||||
return;
|
||||
}
|
||||
mHistoryIndex = index;
|
||||
} else if (event.equals("Purge")) {
|
||||
mHistory.clear();
|
||||
mHistoryIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
private class CheckBookmarkTask extends GeckoAsyncTask<Void, Void, Boolean> {
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... unused) {
|
||||
ContentResolver resolver = Tabs.getInstance().getContentResolver();
|
||||
Cursor cursor = resolver.query(Browser.BOOKMARKS_URI,
|
||||
null,
|
||||
Browser.BookmarkColumns.URL + " = ? and " + Browser.BookmarkColumns.BOOKMARK + " = ?",
|
||||
new String[] { getURL(), "1" },
|
||||
Browser.BookmarkColumns.URL);
|
||||
int count = cursor.getCount();
|
||||
cursor.close();
|
||||
if (count == 1)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean isBookmark) {
|
||||
setBookmark(isBookmark.booleanValue());
|
||||
}
|
||||
}
|
||||
|
||||
private class AddBookmarkTask extends GeckoAsyncTask<Void, Void, Void> {
|
||||
@Override
|
||||
protected Void doInBackground(Void... unused) {
|
||||
ContentResolver resolver = Tabs.getInstance().getContentResolver();
|
||||
Cursor cursor = resolver.query(Browser.BOOKMARKS_URI,
|
||||
null,
|
||||
Browser.BookmarkColumns.URL + " = ?",
|
||||
new String[] { getURL() },
|
||||
Browser.BookmarkColumns.URL);
|
||||
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(Browser.BookmarkColumns.BOOKMARK, "1");
|
||||
values.put(Browser.BookmarkColumns.TITLE, getTitle());
|
||||
|
||||
if (cursor.getCount() == 1) {
|
||||
//entry exists, update the bookmark flag
|
||||
resolver.update(Browser.BOOKMARKS_URI,
|
||||
values,
|
||||
Browser.BookmarkColumns.URL + " = ?",
|
||||
new String[] { getURL() });
|
||||
} else {
|
||||
//add a new entry
|
||||
values.put(Browser.BookmarkColumns.URL, mUrl);
|
||||
resolver.insert(Browser.BOOKMARKS_URI,
|
||||
values);
|
||||
}
|
||||
|
||||
cursor.close();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void unused) {
|
||||
setBookmark(true);
|
||||
}
|
||||
}
|
||||
|
||||
private class RemoveBookmarkTask extends GeckoAsyncTask<Void, Void, Void> {
|
||||
@Override
|
||||
protected Void doInBackground(Void... unused) {
|
||||
ContentResolver resolver = Tabs.getInstance().getContentResolver();
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(Browser.BookmarkColumns.BOOKMARK, "0");
|
||||
resolver.update(Browser.BOOKMARKS_URI,
|
||||
values,
|
||||
Browser.BookmarkColumns.URL + " = ?",
|
||||
new String[] { getURL() });
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void unused) {
|
||||
setBookmark(false);
|
||||
}
|
||||
}
|
||||
}
|
176
mobile/android/base/Tabs.java
Normal file
@ -0,0 +1,176 @@
|
||||
/* -*- 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) 2009-2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Sriram Ramasubramanian <sriram@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.util.*;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.graphics.drawable.*;
|
||||
import android.util.Log;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class Tabs implements GeckoEventListener {
|
||||
private static final String LOGTAG = "GeckoTabs";
|
||||
|
||||
private static int selectedTab = -1;
|
||||
private HashMap<Integer, Tab> tabs;
|
||||
private ArrayList<Tab> order;
|
||||
private ContentResolver resolver;
|
||||
|
||||
private Tabs() {
|
||||
tabs = new HashMap<Integer, Tab>();
|
||||
order = new ArrayList<Tab>();
|
||||
GeckoAppShell.registerGeckoEventListener("SessionHistory:New", this);
|
||||
GeckoAppShell.registerGeckoEventListener("SessionHistory:Back", this);
|
||||
GeckoAppShell.registerGeckoEventListener("SessionHistory:Forward", this);
|
||||
GeckoAppShell.registerGeckoEventListener("SessionHistory:Goto", this);
|
||||
GeckoAppShell.registerGeckoEventListener("SessionHistory:Purge", this);
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return tabs.size();
|
||||
}
|
||||
|
||||
public Tab addTab(int id, String url) {
|
||||
if (tabs.containsKey(id))
|
||||
return tabs.get(id);
|
||||
|
||||
Tab tab = new Tab(id, url);
|
||||
tabs.put(id, tab);
|
||||
order.add(tab);
|
||||
Log.i(LOGTAG, "Added a tab with id: " + id + ", url: " + url);
|
||||
return tab;
|
||||
}
|
||||
|
||||
public void removeTab(int id) {
|
||||
if (tabs.containsKey(id)) {
|
||||
order.remove(getTab(id));
|
||||
tabs.remove(id);
|
||||
Log.i(LOGTAG, "Removed a tab with id: " + id);
|
||||
}
|
||||
}
|
||||
|
||||
public Tab selectTab(int id) {
|
||||
if (!tabs.containsKey(id))
|
||||
return null;
|
||||
|
||||
selectedTab = id;
|
||||
return tabs.get(id);
|
||||
}
|
||||
|
||||
public int getIndexOf(Tab tab) {
|
||||
return order.lastIndexOf(tab);
|
||||
}
|
||||
|
||||
public Tab getTabAt(int index) {
|
||||
if (index < order.size())
|
||||
return order.get(index);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public Tab getSelectedTab() {
|
||||
return tabs.get(selectedTab);
|
||||
}
|
||||
|
||||
public int getSelectedTabId() {
|
||||
return selectedTab;
|
||||
}
|
||||
|
||||
public boolean isSelectedTab(Tab tab) {
|
||||
return (tab.getId() == selectedTab);
|
||||
}
|
||||
|
||||
public Tab getTab(int id) {
|
||||
if (getCount() == 0)
|
||||
return null;
|
||||
|
||||
if (!tabs.containsKey(id))
|
||||
return null;
|
||||
|
||||
return tabs.get(id);
|
||||
}
|
||||
|
||||
public HashMap<Integer, Tab> getTabs() {
|
||||
if (getCount() == 0)
|
||||
return null;
|
||||
|
||||
return tabs;
|
||||
}
|
||||
|
||||
public ArrayList<Tab> getTabsInOrder() {
|
||||
if (getCount() == 0)
|
||||
return null;
|
||||
|
||||
return order;
|
||||
}
|
||||
|
||||
public void setContentResolver(ContentResolver resolver) {
|
||||
this.resolver = resolver;
|
||||
}
|
||||
|
||||
public ContentResolver getContentResolver() {
|
||||
return resolver;
|
||||
}
|
||||
|
||||
//Making Tabs a singleton class
|
||||
private static class TabsInstanceHolder {
|
||||
private static final Tabs INSTANCE = new Tabs();
|
||||
}
|
||||
|
||||
public static Tabs getInstance() {
|
||||
return Tabs.TabsInstanceHolder.INSTANCE;
|
||||
}
|
||||
|
||||
// GeckoEventListener implementation
|
||||
|
||||
public void handleMessage(String event, JSONObject message) {
|
||||
try {
|
||||
if (event.startsWith("SessionHistory:")) {
|
||||
Tab tab = getTab(message.getInt("tabID"));
|
||||
if (tab != null) {
|
||||
event = event.substring("SessionHistory:".length());
|
||||
tab.handleSessionHistoryMessage(event, message);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.i(LOGTAG, "handleMessage throws " + e + " for message: " + event);
|
||||
}
|
||||
}
|
||||
}
|
262
mobile/android/base/TabsTray.java
Normal file
@ -0,0 +1,262 @@
|
||||
/* -*- 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) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Sriram Ramasubramanian <sriram@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.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.Typeface;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ListView;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class TabsTray extends Activity implements GeckoApp.OnTabsChangedListener {
|
||||
|
||||
private ListView mList;
|
||||
private TabsAdapter mTabsAdapter;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
setContentView(R.layout.tabs_tray);
|
||||
|
||||
mList = (ListView) findViewById(R.id.list);
|
||||
|
||||
LinearLayout addTab = (LinearLayout) findViewById(R.id.add_tab);
|
||||
addTab.setOnClickListener(new Button.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
GeckoApp.mAppContext.addTab();
|
||||
finishActivity();
|
||||
}
|
||||
});
|
||||
|
||||
// Adding a native divider for the add-tab
|
||||
LinearLayout lastDivider = new LinearLayout(this);
|
||||
lastDivider.setOrientation(LinearLayout.HORIZONTAL);
|
||||
lastDivider.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, mList.getDividerHeight()));
|
||||
lastDivider.setBackgroundDrawable(mList.getDivider());
|
||||
addTab.addView(lastDivider, 0);
|
||||
|
||||
LinearLayout container = (LinearLayout) findViewById(R.id.container);
|
||||
container.setOnClickListener(new Button.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
finishActivity();
|
||||
}
|
||||
});
|
||||
|
||||
GeckoApp.registerOnTabsChangedListener(this);
|
||||
onTabsChanged(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
GeckoApp.unregisterOnTabsChangedListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowFocusChanged(boolean hasFocus) {
|
||||
// This function is called after the initial list is populated
|
||||
// Scrolling to the selected tab can happen here
|
||||
if (hasFocus) {
|
||||
int position = mTabsAdapter.getPositionForTab(Tabs.getInstance().getSelectedTab());
|
||||
if (position != -1)
|
||||
mList.smoothScrollToPosition(position);
|
||||
}
|
||||
}
|
||||
|
||||
public void onTabsChanged(Tab tab) {
|
||||
if (Tabs.getInstance().getCount() == 1)
|
||||
finishActivity();
|
||||
|
||||
if (mTabsAdapter == null) {
|
||||
mTabsAdapter = new TabsAdapter(this, Tabs.getInstance().getTabsInOrder());
|
||||
mList.setAdapter(mTabsAdapter);
|
||||
return;
|
||||
}
|
||||
|
||||
int position = mTabsAdapter.getPositionForTab(tab);
|
||||
if (position == -1)
|
||||
return;
|
||||
|
||||
if (Tabs.getInstance().getIndexOf(tab) == -1) {
|
||||
mTabsAdapter = new TabsAdapter(this, Tabs.getInstance().getTabsInOrder());
|
||||
mList.setAdapter(mTabsAdapter);
|
||||
} else {
|
||||
View view = mList.getChildAt(position - mList.getFirstVisiblePosition());
|
||||
mTabsAdapter.assignValues(view, tab);
|
||||
}
|
||||
}
|
||||
|
||||
void finishActivity() {
|
||||
finish();
|
||||
overridePendingTransition(0, R.anim.shrink_fade_out);
|
||||
}
|
||||
|
||||
// Adapter to bind tabs into a list
|
||||
private class TabsAdapter extends BaseAdapter {
|
||||
public TabsAdapter(Context context, ArrayList<Tab> tabs) {
|
||||
mContext = context;
|
||||
mTabs = new ArrayList<Tab>();
|
||||
for (int i = 0; i < tabs.size(); i++) {
|
||||
mTabs.add(tabs.get(i));
|
||||
}
|
||||
|
||||
mInflater = LayoutInflater.from(mContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mTabs.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab getItem(int position) {
|
||||
return mTabs.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
public int getPositionForTab(Tab tab) {
|
||||
if (mTabs == null || tab == null)
|
||||
return -1;
|
||||
|
||||
return mTabs.indexOf(tab);
|
||||
}
|
||||
|
||||
public void assignValues(View view, Tab tab) {
|
||||
if (view == null || tab == null)
|
||||
return;
|
||||
|
||||
ImageView favicon = (ImageView) view.findViewById(R.id.favicon);
|
||||
|
||||
Drawable faviconImage = tab.getFavicon();
|
||||
if (faviconImage != null)
|
||||
favicon.setImageDrawable(faviconImage);
|
||||
else
|
||||
favicon.setImageResource(R.drawable.favicon);
|
||||
|
||||
TextView title = (TextView) view.findViewById(R.id.title);
|
||||
title.setText(tab.getDisplayTitle());
|
||||
|
||||
if (Tabs.getInstance().isSelectedTab(tab))
|
||||
title.setTypeface(title.getTypeface(), Typeface.BOLD);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
|
||||
convertView = mInflater.inflate(R.layout.tabs_row, null);
|
||||
|
||||
Tab tab = mTabs.get(position);
|
||||
|
||||
RelativeLayout info = (RelativeLayout) convertView.findViewById(R.id.info);
|
||||
info.setTag("" + tab.getId());
|
||||
info.setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent("Tab:Select", "" + v.getTag()));
|
||||
finishActivity();
|
||||
}
|
||||
});
|
||||
|
||||
assignValues(convertView, tab);
|
||||
|
||||
ImageButton close = (ImageButton) convertView.findViewById(R.id.close);
|
||||
if (mTabs.size() > 1) {
|
||||
close.setTag("" + tab.getId());
|
||||
close.setOnClickListener(new Button.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
int tabId = Integer.parseInt("" + v.getTag());
|
||||
Tabs tabs = Tabs.getInstance();
|
||||
Tab tab = tabs.getTab(tabId);
|
||||
|
||||
if (tabs.isSelectedTab(tab)) {
|
||||
int index = tabs.getIndexOf(tab);
|
||||
if (index >= 1)
|
||||
index--;
|
||||
else
|
||||
index = 1;
|
||||
int id = tabs.getTabAt(index).getId();
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent("Tab:Select", "" + id));
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent("Tab:Close", "" + v.getTag()));
|
||||
} else {
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent("Tab:Close", "" + v.getTag()));
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent("Tab:Select", "" + tabs.getSelectedTabId()));
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
close.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
return convertView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyDataSetChanged() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyDataSetInvalidated() {
|
||||
}
|
||||
|
||||
private Context mContext;
|
||||
private ArrayList<Tab> mTabs;
|
||||
private LayoutInflater mInflater;
|
||||
}
|
||||
}
|
73
mobile/android/base/gfx/BufferedCairoImage.java
Normal file
@ -0,0 +1,73 @@
|
||||
/* -*- 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) 2009-2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Patrick Walton <pcwalton@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.gfx;
|
||||
|
||||
import org.mozilla.gecko.gfx.CairoImage;
|
||||
import org.mozilla.gecko.gfx.CairoUtils;
|
||||
import android.graphics.Bitmap;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/** A Cairo image that simply saves a buffer of pixel data. */
|
||||
public class BufferedCairoImage extends CairoImage {
|
||||
private ByteBuffer mBuffer;
|
||||
private int mWidth, mHeight, mFormat;
|
||||
|
||||
/** Creates a buffered Cairo image from a byte buffer. */
|
||||
public BufferedCairoImage(ByteBuffer inBuffer, int inWidth, int inHeight, int inFormat) {
|
||||
mBuffer = inBuffer; mWidth = inWidth; mHeight = inHeight; mFormat = inFormat;
|
||||
}
|
||||
|
||||
/** Creates a buffered Cairo image from an Android bitmap. */
|
||||
public BufferedCairoImage(Bitmap bitmap) {
|
||||
mFormat = CairoUtils.bitmapConfigToCairoFormat(bitmap.getConfig());
|
||||
mWidth = bitmap.getWidth();
|
||||
mHeight = bitmap.getHeight();
|
||||
mBuffer = ByteBuffer.allocateDirect(mWidth * mHeight * 4);
|
||||
bitmap.copyPixelsToBuffer(mBuffer.asIntBuffer());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer lockBuffer() { return mBuffer; }
|
||||
@Override
|
||||
public int getWidth() { return mWidth; }
|
||||
@Override
|
||||
public int getHeight() { return mHeight; }
|
||||
@Override
|
||||
public int getFormat() { return mFormat; }
|
||||
}
|
||||
|
60
mobile/android/base/gfx/CairoImage.java
Normal file
@ -0,0 +1,60 @@
|
||||
/* -*- 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) 2009-2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Patrick Walton <pcwalton@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.gfx;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/*
|
||||
* A bitmap with pixel data in one of the formats that Cairo understands.
|
||||
*/
|
||||
public abstract class CairoImage {
|
||||
public abstract ByteBuffer lockBuffer();
|
||||
public void unlockBuffer() { /* By default, a no-op. */ }
|
||||
|
||||
public abstract int getWidth();
|
||||
public abstract int getHeight();
|
||||
public abstract int getFormat();
|
||||
|
||||
public static final int FORMAT_INVALID = -1;
|
||||
public static final int FORMAT_ARGB32 = 0;
|
||||
public static final int FORMAT_RGB24 = 1;
|
||||
public static final int FORMAT_A8 = 2;
|
||||
public static final int FORMAT_A1 = 3;
|
||||
public static final int FORMAT_RGB16_565 = 4;
|
||||
}
|
||||
|
120
mobile/android/base/gfx/CairoUtils.java
Normal file
@ -0,0 +1,120 @@
|
||||
/* -*- 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) 2009-2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Patrick Walton <pcwalton@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.gfx;
|
||||
|
||||
import org.mozilla.gecko.gfx.CairoImage;
|
||||
import android.graphics.Bitmap;
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
|
||||
/**
|
||||
* Utility methods useful when displaying Cairo bitmaps using OpenGL ES.
|
||||
*/
|
||||
public class CairoUtils {
|
||||
private CairoUtils() { /* Don't call me. */ }
|
||||
|
||||
public static int cairoFormatToGLInternalFormat(int cairoFormat) {
|
||||
switch (cairoFormat) {
|
||||
case CairoImage.FORMAT_ARGB32:
|
||||
return GL10.GL_RGBA;
|
||||
case CairoImage.FORMAT_RGB24:
|
||||
case CairoImage.FORMAT_RGB16_565:
|
||||
return GL10.GL_RGB;
|
||||
case CairoImage.FORMAT_A8:
|
||||
case CairoImage.FORMAT_A1:
|
||||
throw new RuntimeException("Cairo FORMAT_A1 and FORMAT_A8 unsupported");
|
||||
default:
|
||||
throw new RuntimeException("Unknown Cairo format");
|
||||
}
|
||||
}
|
||||
|
||||
public static int cairoFormatToGLFormat(int cairoFormat) {
|
||||
switch (cairoFormat) {
|
||||
case CairoImage.FORMAT_ARGB32:
|
||||
return GL10.GL_RGBA;
|
||||
case CairoImage.FORMAT_RGB24:
|
||||
case CairoImage.FORMAT_RGB16_565:
|
||||
return GL10.GL_RGB;
|
||||
case CairoImage.FORMAT_A8:
|
||||
case CairoImage.FORMAT_A1:
|
||||
return GL10.GL_ALPHA;
|
||||
default:
|
||||
throw new RuntimeException("Unknown Cairo format");
|
||||
}
|
||||
}
|
||||
|
||||
public static int cairoFormatToGLType(int cairoFormat) {
|
||||
switch (cairoFormat) {
|
||||
case CairoImage.FORMAT_ARGB32:
|
||||
case CairoImage.FORMAT_RGB24:
|
||||
case CairoImage.FORMAT_A8:
|
||||
return GL10.GL_UNSIGNED_BYTE;
|
||||
case CairoImage.FORMAT_A1:
|
||||
throw new RuntimeException("Cairo FORMAT_A1 unsupported in Android OpenGL");
|
||||
case CairoImage.FORMAT_RGB16_565:
|
||||
return GL10.GL_UNSIGNED_SHORT_5_6_5;
|
||||
default:
|
||||
throw new RuntimeException("Unknown Cairo format");
|
||||
}
|
||||
}
|
||||
|
||||
public static int bitsPerPixelForCairoFormat(int cairoFormat) {
|
||||
switch (cairoFormat) {
|
||||
case CairoImage.FORMAT_A1: return 1;
|
||||
case CairoImage.FORMAT_A8: return 8;
|
||||
case CairoImage.FORMAT_RGB16_565: return 16;
|
||||
case CairoImage.FORMAT_RGB24: return 24;
|
||||
case CairoImage.FORMAT_ARGB32: return 32;
|
||||
default:
|
||||
throw new RuntimeException("Unknown Cairo format");
|
||||
}
|
||||
}
|
||||
|
||||
public static int bitmapConfigToCairoFormat(Bitmap.Config config) {
|
||||
if (config == null)
|
||||
return CairoImage.FORMAT_ARGB32; /* Droid Pro fix. */
|
||||
|
||||
switch (config) {
|
||||
case ALPHA_8: return CairoImage.FORMAT_A8;
|
||||
case ARGB_4444: throw new RuntimeException("ARGB_444 unsupported");
|
||||
case ARGB_8888: return CairoImage.FORMAT_ARGB32;
|
||||
case RGB_565: return CairoImage.FORMAT_RGB16_565;
|
||||
default: throw new RuntimeException("Unknown Skia bitmap config");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
285
mobile/android/base/gfx/GeckoSoftwareLayerClient.java
Normal file
@ -0,0 +1,285 @@
|
||||
/* -*- 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) 2009-2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Patrick Walton <pcwalton@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.gfx;
|
||||
|
||||
import org.mozilla.gecko.gfx.CairoImage;
|
||||
import org.mozilla.gecko.gfx.IntSize;
|
||||
import org.mozilla.gecko.gfx.LayerClient;
|
||||
import org.mozilla.gecko.gfx.LayerController;
|
||||
import org.mozilla.gecko.gfx.LayerRenderer;
|
||||
import org.mozilla.gecko.gfx.SingleTileLayer;
|
||||
import org.mozilla.gecko.ui.ViewportController;
|
||||
import org.mozilla.gecko.GeckoApp;
|
||||
import org.mozilla.gecko.GeckoAppShell;
|
||||
import org.mozilla.gecko.GeckoEvent;
|
||||
import android.content.Context;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.util.Log;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
/**
|
||||
* Transfers a software-rendered Gecko to an ImageLayer so that it can be rendered by our
|
||||
* compositor.
|
||||
*
|
||||
* TODO: Throttle down Gecko's priority when we pan and zoom.
|
||||
*/
|
||||
public class GeckoSoftwareLayerClient extends LayerClient {
|
||||
private Context mContext;
|
||||
private int mWidth, mHeight, mFormat;
|
||||
private ByteBuffer mBuffer;
|
||||
private Semaphore mBufferSemaphore;
|
||||
private SingleTileLayer mTileLayer;
|
||||
private ViewportController mViewportController;
|
||||
|
||||
private RectF mGeckoVisibleRect;
|
||||
/* The viewport rect that Gecko is currently displaying. */
|
||||
|
||||
private Rect mJSPanningToRect;
|
||||
/* The rect that we just told chrome JavaScript to pan to. */
|
||||
|
||||
private boolean mWaitingForJSPanZoom;
|
||||
/* This will be set to true if we are waiting on the chrome JavaScript to finish panning or
|
||||
* zooming before we can render. */
|
||||
|
||||
private CairoImage mCairoImage;
|
||||
|
||||
/* The initial page width and height that we use before a page is loaded. */
|
||||
private static final int PAGE_WIDTH = 980; /* Matches MobileSafari. */
|
||||
private static final int PAGE_HEIGHT = 1500;
|
||||
|
||||
public GeckoSoftwareLayerClient(Context context) {
|
||||
mContext = context;
|
||||
|
||||
mViewportController = new ViewportController(new IntSize(PAGE_WIDTH, PAGE_HEIGHT),
|
||||
new RectF(0, 0, 1, 1));
|
||||
|
||||
mWidth = LayerController.TILE_WIDTH;
|
||||
mHeight = LayerController.TILE_HEIGHT;
|
||||
mFormat = CairoImage.FORMAT_RGB16_565;
|
||||
|
||||
mBuffer = ByteBuffer.allocateDirect(mWidth * mHeight * 2);
|
||||
mBufferSemaphore = new Semaphore(1);
|
||||
|
||||
mWaitingForJSPanZoom = false;
|
||||
|
||||
mCairoImage = new CairoImage() {
|
||||
@Override
|
||||
public ByteBuffer lockBuffer() {
|
||||
try {
|
||||
mBufferSemaphore.acquire();
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return mBuffer;
|
||||
}
|
||||
@Override
|
||||
public void unlockBuffer() {
|
||||
mBufferSemaphore.release();
|
||||
}
|
||||
@Override
|
||||
public int getWidth() { return mWidth; }
|
||||
@Override
|
||||
public int getHeight() { return mHeight; }
|
||||
@Override
|
||||
public int getFormat() { return mFormat; }
|
||||
};
|
||||
|
||||
mTileLayer = new SingleTileLayer();
|
||||
}
|
||||
|
||||
/** Attaches the root layer to the layer controller so that Gecko appears. */
|
||||
@Override
|
||||
public void init() {
|
||||
getLayerController().setRoot(mTileLayer);
|
||||
render();
|
||||
}
|
||||
|
||||
public void beginDrawing() {
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: Would be cleaner if this took an android.graphics.Rect instead, but that would require
|
||||
* a little more JNI magic.
|
||||
*/
|
||||
public void endDrawing(int x, int y, int width, int height) {
|
||||
LayerController controller = getLayerController();
|
||||
if (controller == null)
|
||||
return;
|
||||
//controller.unzoom(); /* FIXME */
|
||||
controller.notifyViewOfGeometryChange();
|
||||
|
||||
mViewportController.setVisibleRect(mGeckoVisibleRect);
|
||||
|
||||
if (mGeckoVisibleRect != null) {
|
||||
RectF layerRect = mViewportController.untransformVisibleRect(mGeckoVisibleRect,
|
||||
getPageSize());
|
||||
mTileLayer.origin = new PointF(layerRect.left, layerRect.top);
|
||||
}
|
||||
|
||||
repaint(new Rect(x, y, x + width, y + height));
|
||||
}
|
||||
|
||||
/*
|
||||
* Temporary fix to allow both old and new widget APIs to access this object. See bug 703421.
|
||||
*/
|
||||
public void endDrawing(int x, int y, int width, int height, String metadata) {
|
||||
endDrawing(x, y, width, height);
|
||||
}
|
||||
|
||||
private void repaint(Rect rect) {
|
||||
mTileLayer.paintSubimage(mCairoImage, rect);
|
||||
}
|
||||
|
||||
/** Called whenever the chrome JS finishes panning or zooming to some location. */
|
||||
public void jsPanZoomCompleted(Rect rect) {
|
||||
mGeckoVisibleRect = new RectF(rect);
|
||||
if (mWaitingForJSPanZoom)
|
||||
render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquires a lock on the back buffer and returns it, blocking until it's unlocked. This
|
||||
* function is for Gecko to use.
|
||||
*/
|
||||
public ByteBuffer lockBuffer() {
|
||||
try {
|
||||
mBufferSemaphore.acquire();
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return mBuffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases the lock on the back buffer. After this call, it is forbidden for Gecko to touch
|
||||
* the buffer. This function is, again, for Gecko to use.
|
||||
*/
|
||||
public void unlockBuffer() {
|
||||
mBufferSemaphore.release();
|
||||
}
|
||||
|
||||
/** Called whenever the page changes size. */
|
||||
public void setPageSize(IntSize pageSize) {
|
||||
mViewportController.setPageSize(pageSize);
|
||||
getLayerController().setPageSize(pageSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void geometryChanged() {
|
||||
mViewportController.setVisibleRect(getTransformedVisibleRect());
|
||||
render();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntSize getPageSize() { return mViewportController.getPageSize(); }
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
LayerController layerController = getLayerController();
|
||||
RectF visibleRect = layerController.getVisibleRect();
|
||||
RectF tileRect = mViewportController.widenRect(visibleRect);
|
||||
tileRect = mViewportController.clampRect(tileRect);
|
||||
|
||||
IntSize pageSize = layerController.getPageSize();
|
||||
RectF viewportRect = mViewportController.transformVisibleRect(tileRect, pageSize);
|
||||
|
||||
/* Prevent null pointer exceptions at the start. */
|
||||
if (mGeckoVisibleRect == null)
|
||||
mGeckoVisibleRect = viewportRect;
|
||||
|
||||
if (!getLayerController().getRedrawHint())
|
||||
return;
|
||||
|
||||
/* If Gecko's visible rect is the same as our visible rect, then we can actually kick off a
|
||||
* draw event. */
|
||||
if (mGeckoVisibleRect.equals(viewportRect)) {
|
||||
mWaitingForJSPanZoom = false;
|
||||
mJSPanningToRect = null;
|
||||
GeckoAppShell.scheduleRedraw();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Otherwise, we need to get Gecko's visible rect equal to our visible rect before we can
|
||||
* safely draw. If we're just waiting for chrome JavaScript to catch up, we do nothing.
|
||||
* This check avoids bombarding the chrome JavaScript with messages. */
|
||||
int viewportRectX = (int)Math.round(viewportRect.left);
|
||||
int viewportRectY = (int)Math.round(viewportRect.top);
|
||||
Rect panToRect = new Rect(viewportRectX, viewportRectY,
|
||||
viewportRectX + LayerController.TILE_WIDTH,
|
||||
viewportRectY + LayerController.TILE_HEIGHT);
|
||||
|
||||
if (mWaitingForJSPanZoom && mJSPanningToRect != null &&
|
||||
mJSPanningToRect.equals(panToRect)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* We send Gecko a message telling it to move its visible rect to the appropriate spot and
|
||||
* set a flag to remind us to try the redraw again. */
|
||||
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent("PanZoom:PanZoom",
|
||||
"{\"x\": " + panToRect.left + ", \"y\": " + panToRect.top +
|
||||
", \"width\": " + panToRect.width() + ", \"height\": " + panToRect.height() +
|
||||
", \"zoomFactor\": " + getZoomFactor() + "}"));
|
||||
|
||||
mJSPanningToRect = panToRect;
|
||||
mWaitingForJSPanZoom = true;
|
||||
}
|
||||
|
||||
/* Returns the dimensions of the box in page coordinates that the user is viewing. */
|
||||
private RectF getTransformedVisibleRect() {
|
||||
LayerController layerController = getLayerController();
|
||||
return mViewportController.transformVisibleRect(layerController.getVisibleRect(),
|
||||
layerController.getPageSize());
|
||||
}
|
||||
|
||||
private float getZoomFactor() {
|
||||
return 1.0f; // FIXME
|
||||
/*LayerController layerController = getLayerController();
|
||||
return mViewportController.getZoomFactor(layerController.getVisibleRect(),
|
||||
layerController.getPageSize(),
|
||||
layerController.getScreenSize());*/
|
||||
}
|
||||
}
|
||||
|
15
mobile/android/base/gfx/InputConnectionHandler.java
Normal file
@ -0,0 +1,15 @@
|
||||
package org.mozilla.gecko.gfx;
|
||||
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputConnection;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
public interface InputConnectionHandler
|
||||
{
|
||||
InputConnection onCreateInputConnection(EditorInfo outAttrs);
|
||||
boolean onKeyPreIme(int keyCode, KeyEvent event);
|
||||
boolean onKeyDown(int keyCode, KeyEvent event);
|
||||
boolean onKeyLongPress(int keyCode, KeyEvent event);
|
||||
boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event);
|
||||
boolean onKeyUp(int keyCode, KeyEvent event);
|
||||
}
|
65
mobile/android/base/gfx/IntSize.java
Normal file
@ -0,0 +1,65 @@
|
||||
/* -*- 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) 2009-2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Patrick Walton <pcwalton@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.gfx;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class IntSize {
|
||||
public final int width, height;
|
||||
|
||||
public IntSize(int inWidth, int inHeight) { width = inWidth; height = inHeight; }
|
||||
|
||||
public IntSize(JSONObject json) {
|
||||
try {
|
||||
width = json.getInt("width");
|
||||
height = json.getInt("height");
|
||||
} catch (JSONException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() { return "(" + width + "," + height + ")"; }
|
||||
|
||||
public IntSize scale(float factor) {
|
||||
return new IntSize((int)Math.round(width * factor),
|
||||
(int)Math.round(height * factor));
|
||||
}
|
||||
}
|
||||
|
65
mobile/android/base/gfx/Layer.java
Normal file
@ -0,0 +1,65 @@
|
||||
/* -*- 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) 2009-2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Patrick Walton <pcwalton@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.gfx;
|
||||
|
||||
import android.graphics.PointF;
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
|
||||
public abstract class Layer {
|
||||
public PointF origin;
|
||||
|
||||
public Layer() {
|
||||
origin = new PointF(0.0f, 0.0f);
|
||||
}
|
||||
|
||||
/** Draws the layer. Automatically applies the translation. */
|
||||
public final void draw(GL10 gl) {
|
||||
gl.glPushMatrix();
|
||||
gl.glTranslatef(origin.x, origin.y, 0.0f);
|
||||
onDraw(gl);
|
||||
gl.glPopMatrix();
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses implement this method to perform drawing.
|
||||
*
|
||||
* Invariant: The current matrix mode must be GL_MODELVIEW both before and after this call.
|
||||
*/
|
||||
protected abstract void onDraw(GL10 gl);
|
||||
}
|
||||
|
63
mobile/android/base/gfx/LayerClient.java
Normal file
@ -0,0 +1,63 @@
|
||||
/* -*- 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) 2009-2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Patrick Walton <pcwalton@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.gfx;
|
||||
|
||||
import org.mozilla.gecko.gfx.IntSize;
|
||||
import org.mozilla.gecko.gfx.LayerController;
|
||||
|
||||
/**
|
||||
* A layer client provides tiles and manages other information used by the layer controller.
|
||||
*/
|
||||
public abstract class LayerClient {
|
||||
private LayerController mLayerController;
|
||||
|
||||
public abstract void geometryChanged();
|
||||
public abstract IntSize getPageSize();
|
||||
|
||||
/** Called whenever the page changes size. */
|
||||
public abstract void setPageSize(IntSize pageSize);
|
||||
|
||||
public abstract void init();
|
||||
protected abstract void render();
|
||||
|
||||
public LayerController getLayerController() { return mLayerController; }
|
||||
public void setLayerController(LayerController layerController) {
|
||||
mLayerController = layerController;
|
||||
}
|
||||
}
|
||||
|
291
mobile/android/base/gfx/LayerController.java
Normal file
@ -0,0 +1,291 @@
|
||||
/* -*- 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) 2009-2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Patrick Walton <pcwalton@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.gfx;
|
||||
|
||||
import org.mozilla.gecko.gfx.IntSize;
|
||||
import org.mozilla.gecko.gfx.Layer;
|
||||
import org.mozilla.gecko.gfx.LayerClient;
|
||||
import org.mozilla.gecko.gfx.LayerView;
|
||||
import org.mozilla.gecko.ui.PanZoomController;
|
||||
import org.mozilla.gecko.GeckoApp;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.ScaleGestureDetector;
|
||||
import android.view.View.OnTouchListener;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* The layer controller manages a tile that represents the visible page. It does panning and
|
||||
* zooming natively by delegating to a panning/zooming controller. Touch events can be dispatched
|
||||
* to a higher-level view.
|
||||
*/
|
||||
public class LayerController {
|
||||
private Layer mRootLayer; /* The root layer. */
|
||||
private LayerView mView; /* The main rendering view. */
|
||||
private Context mContext; /* The current context. */
|
||||
private RectF mVisibleRect; /* The current visible region. */
|
||||
private IntSize mScreenSize; /* The screen size of the viewport. */
|
||||
private IntSize mPageSize; /* The current page size. */
|
||||
|
||||
private PanZoomController mPanZoomController;
|
||||
/*
|
||||
* The panning and zooming controller, which interprets pan and zoom gestures for us and
|
||||
* updates our visible rect appropriately.
|
||||
*/
|
||||
|
||||
private OnTouchListener mOnTouchListener; /* The touch listener. */
|
||||
private LayerClient mLayerClient; /* The layer client. */
|
||||
|
||||
public static final int TILE_WIDTH = 1024;
|
||||
public static final int TILE_HEIGHT = 2048;
|
||||
/* NB: These must be powers of two due to the OpenGL ES 1.x restriction on NPOT textures. */
|
||||
|
||||
private static final int DANGER_ZONE_X = 150;
|
||||
private static final int DANGER_ZONE_Y = 300;
|
||||
/* If the visible rect is within the danger zone (measured in pixels from each edge of a tile),
|
||||
* we start aggressively redrawing to minimize checkerboarding. */
|
||||
|
||||
public LayerController(Context context) {
|
||||
mContext = context;
|
||||
|
||||
mVisibleRect = new RectF(0.0f, 0.0f, 1.0f, 1.0f);
|
||||
/* Gets filled in when the surface changes. */
|
||||
|
||||
mScreenSize = new IntSize(1, 1);
|
||||
mPageSize = new IntSize(LayerController.TILE_WIDTH, LayerController.TILE_HEIGHT);
|
||||
|
||||
mPanZoomController = new PanZoomController(this);
|
||||
mView = new LayerView(context, this);
|
||||
}
|
||||
|
||||
public void setRoot(Layer layer) { mRootLayer = layer; }
|
||||
|
||||
public void setLayerClient(LayerClient layerClient) {
|
||||
mLayerClient = layerClient;
|
||||
mPageSize = layerClient.getPageSize();
|
||||
layerClient.setLayerController(this);
|
||||
layerClient.init();
|
||||
}
|
||||
|
||||
public Layer getRoot() { return mRootLayer; }
|
||||
public LayerView getView() { return mView; }
|
||||
public Context getContext() { return mContext; }
|
||||
public RectF getVisibleRect() { return mVisibleRect; }
|
||||
public IntSize getScreenSize() { return mScreenSize; }
|
||||
public IntSize getPageSize() { return mPageSize; }
|
||||
|
||||
public Bitmap getCheckerboardPattern() { return getDrawable("checkerboard"); }
|
||||
public Bitmap getShadowPattern() { return getDrawable("shadow"); }
|
||||
|
||||
public GestureDetector.OnGestureListener getGestureListener() { return mPanZoomController; }
|
||||
public ScaleGestureDetector.OnScaleGestureListener getScaleGestureListener() { return mPanZoomController; }
|
||||
|
||||
private Bitmap getDrawable(String name) {
|
||||
Resources resources = mContext.getResources();
|
||||
int resourceID = resources.getIdentifier(name, "drawable", mContext.getPackageName());
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inScaled = false;
|
||||
return BitmapFactory.decodeResource(mContext.getResources(), resourceID, options);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that the zoom factor of the layer controller differs from the zoom factor of the layer
|
||||
* client (i.e. the page).
|
||||
*/
|
||||
public float getZoomFactor() { return (float)mScreenSize.width / mVisibleRect.width(); }
|
||||
|
||||
/**
|
||||
* The view calls this to indicate that the screen changed size.
|
||||
*
|
||||
* TODO: Refactor this to use an interface. Expose that interface only to the view and not
|
||||
* to the layer client. That way, the layer client won't be tempted to call this, which might
|
||||
* result in an infinite loop.
|
||||
*/
|
||||
public void setScreenSize(int width, int height) {
|
||||
float zoomFactor = getZoomFactor(); /* Must come first. */
|
||||
|
||||
mScreenSize = new IntSize(width, height);
|
||||
setVisibleRect(mVisibleRect.left, mVisibleRect.top, width / zoomFactor,
|
||||
height / zoomFactor);
|
||||
|
||||
notifyLayerClientOfGeometryChange();
|
||||
}
|
||||
|
||||
public void setNeedsDisplay() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
public void scrollTo(float x, float y) {
|
||||
setVisibleRect(x, y, mVisibleRect.width(), mVisibleRect.height());
|
||||
}
|
||||
|
||||
public void setVisibleRect(float x, float y, float width, float height) {
|
||||
mVisibleRect = new RectF(x, y, x + width, y + height);
|
||||
setNeedsDisplay();
|
||||
GeckoApp.mAppContext.repositionPluginViews(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the zoom factor to 1, adjusting the visible rect accordingly. The Gecko layer client
|
||||
* calls this function after a zoom has completed and Gecko is done rendering the new visible
|
||||
* region.
|
||||
*/
|
||||
public void unzoom() {
|
||||
float zoomFactor = getZoomFactor();
|
||||
float x = Math.round(mVisibleRect.left * zoomFactor);
|
||||
float y = Math.round(mVisibleRect.top * zoomFactor);
|
||||
mVisibleRect = new RectF(x, y, x + mScreenSize.width, y + mScreenSize.height);
|
||||
mPageSize = mPageSize.scale(zoomFactor);
|
||||
setNeedsDisplay();
|
||||
}
|
||||
|
||||
public void setPageSize(IntSize size) {
|
||||
mPageSize = size.scale(getZoomFactor());
|
||||
mView.notifyRendererOfPageSizeChange();
|
||||
}
|
||||
|
||||
public boolean post(Runnable action) { return mView.post(action); }
|
||||
|
||||
public void setOnTouchListener(OnTouchListener onTouchListener) {
|
||||
mOnTouchListener = onTouchListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* The view as well as the controller itself use this method to notify the layer client that
|
||||
* the geometry changed.
|
||||
*/
|
||||
public void notifyLayerClientOfGeometryChange() {
|
||||
if (mLayerClient != null)
|
||||
mLayerClient.geometryChanged();
|
||||
}
|
||||
|
||||
// Informs the view and the panning and zooming controller that the geometry changed.
|
||||
public void notifyViewOfGeometryChange() {
|
||||
mView.geometryChanged();
|
||||
mPanZoomController.geometryChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this controller is fine with performing a redraw operation or false if it
|
||||
* would prefer that the action didn't take place.
|
||||
*/
|
||||
public boolean getRedrawHint() {
|
||||
return aboutToCheckerboard();
|
||||
}
|
||||
|
||||
private RectF getTileRect() {
|
||||
float x = mRootLayer.origin.x, y = mRootLayer.origin.y;
|
||||
return new RectF(x, y, x + TILE_WIDTH, y + TILE_HEIGHT);
|
||||
}
|
||||
|
||||
// Returns true if a checkerboard is about to be visible.
|
||||
private boolean aboutToCheckerboard() {
|
||||
Rect pageRect = new Rect(0, 0, mPageSize.width, mPageSize.height);
|
||||
Rect adjustedPageRect = RectUtils.contract(pageRect, DANGER_ZONE_X, DANGER_ZONE_Y);
|
||||
RectF visiblePageRect = RectUtils.intersect(mVisibleRect, new RectF(adjustedPageRect));
|
||||
RectF adjustedTileRect = RectUtils.contract(getTileRect(), DANGER_ZONE_X, DANGER_ZONE_Y);
|
||||
return !adjustedTileRect.contains(visiblePageRect);
|
||||
}
|
||||
|
||||
/** Returns the given rect, clamped to the boundaries of a tile. */
|
||||
public RectF clampRect(RectF rect) {
|
||||
float x = clamp(0, rect.left, mPageSize.width - LayerController.TILE_WIDTH);
|
||||
float y = clamp(0, rect.top, mPageSize.height - LayerController.TILE_HEIGHT);
|
||||
return new RectF(x, y, x + rect.width(), y + rect.height());
|
||||
}
|
||||
|
||||
private float clamp(float min, float value, float max) {
|
||||
if (max < min)
|
||||
return min;
|
||||
return (value < min) ? min : (value > max) ? max : value;
|
||||
}
|
||||
|
||||
// Returns the coordinates of a tile, scaled by the given factor, centered on the given rect.
|
||||
private static RectF widenRect(RectF rect, float scaleFactor) {
|
||||
PointF center = new PointF(rect.centerX(), rect.centerY());
|
||||
float halfTileWidth = TILE_WIDTH * scaleFactor / 2.0f;
|
||||
float halfTileHeight = TILE_HEIGHT * scaleFactor / 2.0f;
|
||||
return new RectF(rect.centerX() - halfTileWidth, rect.centerY() - halfTileHeight,
|
||||
rect.centerX() + halfTileWidth, rect.centerY() + halfTileHeight);
|
||||
}
|
||||
|
||||
/** Returns the coordinates of a tile centered on the given rect. */
|
||||
public static RectF widenRect(RectF rect) {
|
||||
return widenRect(rect, 1.0f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a point from layer view coordinates to layer coordinates. In other words, given a
|
||||
* point measured in pixels from the top left corner of the layer view, returns the point in
|
||||
* pixels measured from the top left corner of the root layer, in the coordinate system of the
|
||||
* layer itself. This method is used by the viewport controller as part of the process of
|
||||
* translating touch events to Gecko's coordinate system.
|
||||
*/
|
||||
public PointF convertViewPointToLayerPoint(PointF viewPoint) {
|
||||
if (mRootLayer == null)
|
||||
return null;
|
||||
|
||||
// Undo the transforms.
|
||||
PointF scaledPoint = PointUtils.scale(viewPoint, 1.0f / getZoomFactor());
|
||||
return PointUtils.subtract(PointUtils.add(new PointF(mVisibleRect.left, mVisibleRect.top),
|
||||
scaledPoint),
|
||||
mRootLayer.origin);
|
||||
}
|
||||
|
||||
/*
|
||||
* Gesture detection. This is handled only at a high level in this class; we dispatch to the
|
||||
* pan/zoom controller to do the dirty work.
|
||||
*/
|
||||
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
if (mPanZoomController.onTouchEvent(event))
|
||||
return true;
|
||||
if (mOnTouchListener != null)
|
||||
return mOnTouchListener.onTouch(mView, event);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
203
mobile/android/base/gfx/LayerRenderer.java
Normal file
@ -0,0 +1,203 @@
|
||||
/* -*- 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) 2009-2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Patrick Walton <pcwalton@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.gfx;
|
||||
|
||||
import org.mozilla.gecko.gfx.BufferedCairoImage;
|
||||
import org.mozilla.gecko.gfx.IntSize;
|
||||
import org.mozilla.gecko.gfx.LayerController;
|
||||
import org.mozilla.gecko.gfx.LayerView;
|
||||
import org.mozilla.gecko.gfx.NinePatchTileLayer;
|
||||
import org.mozilla.gecko.gfx.SingleTileLayer;
|
||||
import org.mozilla.gecko.gfx.TextureReaper;
|
||||
import org.mozilla.gecko.gfx.TextLayer;
|
||||
import org.mozilla.gecko.gfx.TileLayer;
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.opengl.GLSurfaceView;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.WindowManager;
|
||||
import javax.microedition.khronos.egl.EGLConfig;
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* The layer renderer implements the rendering logic for a layer view.
|
||||
*/
|
||||
public class LayerRenderer implements GLSurfaceView.Renderer {
|
||||
private static final float BACKGROUND_COLOR_R = 0.81f;
|
||||
private static final float BACKGROUND_COLOR_G = 0.81f;
|
||||
private static final float BACKGROUND_COLOR_B = 0.81f;
|
||||
|
||||
private LayerView mView;
|
||||
private SingleTileLayer mCheckerboardLayer;
|
||||
private NinePatchTileLayer mShadowLayer;
|
||||
private TextLayer mFPSLayer;
|
||||
|
||||
// FPS display
|
||||
private long mFrameCountTimestamp;
|
||||
private int mFrameCount; // number of frames since last timestamp
|
||||
|
||||
public LayerRenderer(LayerView view) {
|
||||
mView = view;
|
||||
|
||||
/* FIXME: Layers should not be directly connected to the layer controller. */
|
||||
LayerController controller = view.getController();
|
||||
mCheckerboardLayer = new SingleTileLayer(true);
|
||||
mCheckerboardLayer.paintImage(new BufferedCairoImage(controller.getCheckerboardPattern()));
|
||||
mShadowLayer = new NinePatchTileLayer(controller);
|
||||
mShadowLayer.paintImage(new BufferedCairoImage(controller.getShadowPattern()));
|
||||
mFPSLayer = new TextLayer(new IntSize(64, 32));
|
||||
mFPSLayer.setText("-- FPS");
|
||||
|
||||
mFrameCountTimestamp = System.currentTimeMillis();
|
||||
mFrameCount = 0;
|
||||
}
|
||||
|
||||
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
|
||||
gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
gl.glClearDepthf(1.0f); /* FIXME: Is this needed? */
|
||||
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
|
||||
gl.glShadeModel(GL10.GL_SMOOTH); /* FIXME: Is this needed? */
|
||||
gl.glDisable(GL10.GL_DITHER);
|
||||
gl.glEnable(GL10.GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
public void onDrawFrame(GL10 gl) {
|
||||
checkFPS();
|
||||
TextureReaper.get().reap(gl);
|
||||
|
||||
LayerController controller = mView.getController();
|
||||
|
||||
/* Draw the background. */
|
||||
gl.glClearColor(BACKGROUND_COLOR_R, BACKGROUND_COLOR_G, BACKGROUND_COLOR_B, 1.0f);
|
||||
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
|
||||
|
||||
/* Draw the drop shadow. */
|
||||
setupPageTransform(gl);
|
||||
mShadowLayer.draw(gl);
|
||||
|
||||
/* Draw the checkerboard. */
|
||||
Rect pageRect = clampToScreen(getPageRect());
|
||||
IntSize screenSize = controller.getScreenSize();
|
||||
gl.glEnable(GL10.GL_SCISSOR_TEST);
|
||||
gl.glScissor(pageRect.left, screenSize.height - pageRect.bottom,
|
||||
pageRect.width(), pageRect.height());
|
||||
|
||||
gl.glLoadIdentity();
|
||||
mCheckerboardLayer.draw(gl);
|
||||
|
||||
/* Draw the layer the client added to us. */
|
||||
setupPageTransform(gl);
|
||||
|
||||
Layer rootLayer = controller.getRoot();
|
||||
if (rootLayer != null)
|
||||
rootLayer.draw(gl);
|
||||
|
||||
gl.glDisable(GL10.GL_SCISSOR_TEST);
|
||||
|
||||
/* Draw the FPS. */
|
||||
gl.glLoadIdentity();
|
||||
gl.glEnable(GL10.GL_BLEND);
|
||||
mFPSLayer.draw(gl);
|
||||
gl.glDisable(GL10.GL_BLEND);
|
||||
}
|
||||
|
||||
public void pageSizeChanged() {
|
||||
mShadowLayer.recreateVertexBuffers();
|
||||
}
|
||||
|
||||
private void setupPageTransform(GL10 gl) {
|
||||
LayerController controller = mView.getController();
|
||||
RectF visibleRect = controller.getVisibleRect();
|
||||
float zoomFactor = controller.getZoomFactor();
|
||||
|
||||
gl.glLoadIdentity();
|
||||
gl.glScalef(zoomFactor, zoomFactor, 1.0f);
|
||||
gl.glTranslatef(-visibleRect.left, -visibleRect.top, 0.0f);
|
||||
}
|
||||
|
||||
private Rect getPageRect() {
|
||||
LayerController controller = mView.getController();
|
||||
float zoomFactor = controller.getZoomFactor();
|
||||
RectF visibleRect = controller.getVisibleRect();
|
||||
IntSize pageSize = controller.getPageSize();
|
||||
|
||||
int x = (int)Math.round(-zoomFactor * visibleRect.left);
|
||||
int y = (int)Math.round(-zoomFactor * visibleRect.top);
|
||||
return new Rect(x, y,
|
||||
x + (int)Math.round(zoomFactor * pageSize.width),
|
||||
y + (int)Math.round(zoomFactor * pageSize.height));
|
||||
}
|
||||
|
||||
private Rect clampToScreen(Rect rect) {
|
||||
LayerController controller = mView.getController();
|
||||
IntSize screenSize = controller.getScreenSize();
|
||||
|
||||
int left = Math.max(0, rect.left);
|
||||
int top = Math.max(0, rect.top);
|
||||
int right = Math.min(screenSize.width, rect.right);
|
||||
int bottom = Math.min(screenSize.height, rect.bottom);
|
||||
return new Rect(left, top, right, bottom);
|
||||
}
|
||||
|
||||
public void onSurfaceChanged(GL10 gl, int width, int height) {
|
||||
gl.glViewport(0, 0, width, height);
|
||||
gl.glMatrixMode(GL10.GL_PROJECTION);
|
||||
gl.glLoadIdentity();
|
||||
gl.glOrthof(0.0f, (float)width, (float)height, 0.0f, -10.0f, 10.0f);
|
||||
gl.glMatrixMode(GL10.GL_MODELVIEW);
|
||||
gl.glLoadIdentity();
|
||||
|
||||
mView.setScreenSize(width, height);
|
||||
|
||||
/* TODO: Throw away tile images? */
|
||||
}
|
||||
|
||||
private void checkFPS() {
|
||||
if (System.currentTimeMillis() >= mFrameCountTimestamp + 1000) {
|
||||
mFrameCountTimestamp = System.currentTimeMillis();
|
||||
mFPSLayer.setText(mFrameCount + " FPS");
|
||||
mFrameCount = 0;
|
||||
} else {
|
||||
mFrameCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
148
mobile/android/base/gfx/LayerView.java
Normal file
@ -0,0 +1,148 @@
|
||||
/* -*- 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) 2009-2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Patrick Walton <pcwalton@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.gfx;
|
||||
|
||||
import org.mozilla.gecko.gfx.InputConnectionHandler;
|
||||
import org.mozilla.gecko.gfx.LayerController;
|
||||
import android.content.Context;
|
||||
import android.opengl.GLSurfaceView;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputConnection;
|
||||
import android.view.ScaleGestureDetector;
|
||||
|
||||
/**
|
||||
* A view rendered by the layer compositor.
|
||||
*
|
||||
* This view delegates to LayerRenderer to actually do the drawing. Its role is largely that of a
|
||||
* mediator between the LayerRenderer and the LayerController.
|
||||
*/
|
||||
public class LayerView extends GLSurfaceView {
|
||||
private Context mContext;
|
||||
private LayerController mController;
|
||||
private InputConnectionHandler mInputConnectionHandler;
|
||||
private LayerRenderer mRenderer;
|
||||
private GestureDetector mGestureDetector;
|
||||
private ScaleGestureDetector mScaleGestureDetector;
|
||||
|
||||
public LayerView(Context context, LayerController controller) {
|
||||
super(context);
|
||||
|
||||
mContext = context;
|
||||
mController = controller;
|
||||
mRenderer = new LayerRenderer(this);
|
||||
setRenderer(mRenderer);
|
||||
mGestureDetector = new GestureDetector(context, controller.getGestureListener());
|
||||
mScaleGestureDetector = new ScaleGestureDetector(context, controller.getScaleGestureListener());
|
||||
mInputConnectionHandler = null;
|
||||
|
||||
setFocusable(true);
|
||||
setFocusableInTouchMode(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
if (mGestureDetector.onTouchEvent(event))
|
||||
return true;
|
||||
mScaleGestureDetector.onTouchEvent(event);
|
||||
if (mScaleGestureDetector.isInProgress())
|
||||
return true;
|
||||
return mController.onTouchEvent(event);
|
||||
}
|
||||
|
||||
public LayerController getController() { return mController; }
|
||||
public void geometryChanged() { /* TODO: Schedule a redraw. */ }
|
||||
|
||||
public void notifyRendererOfPageSizeChange() {
|
||||
mRenderer.pageSizeChanged();
|
||||
}
|
||||
|
||||
/** The LayerRenderer calls this to indicate that the window has changed size. */
|
||||
public void setScreenSize(int width, int height) {
|
||||
mController.setScreenSize(width, height);
|
||||
}
|
||||
|
||||
public void setInputConnectionHandler(InputConnectionHandler handler) {
|
||||
mInputConnectionHandler = handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
|
||||
if (mInputConnectionHandler != null)
|
||||
return mInputConnectionHandler.onCreateInputConnection(outAttrs);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
|
||||
if (mInputConnectionHandler != null)
|
||||
return mInputConnectionHandler.onKeyPreIme(keyCode, event);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
if (mInputConnectionHandler != null)
|
||||
return mInputConnectionHandler.onKeyDown(keyCode, event);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
|
||||
if (mInputConnectionHandler != null)
|
||||
return mInputConnectionHandler.onKeyLongPress(keyCode, event);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
|
||||
if (mInputConnectionHandler != null)
|
||||
return mInputConnectionHandler.onKeyMultiple(keyCode, repeatCount, event);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyUp(int keyCode, KeyEvent event) {
|
||||
if (mInputConnectionHandler != null)
|
||||
return mInputConnectionHandler.onKeyUp(keyCode, event);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
176
mobile/android/base/gfx/NinePatchTileLayer.java
Normal file
@ -0,0 +1,176 @@
|
||||
/* -*- 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) 2009-2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Patrick Walton <pcwalton@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.gfx;
|
||||
|
||||
import org.mozilla.gecko.gfx.IntSize;
|
||||
import org.mozilla.gecko.gfx.LayerController;
|
||||
import org.mozilla.gecko.gfx.TileLayer;
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
/**
|
||||
* Encapsulates the logic needed to draw a nine-patch bitmap using OpenGL ES.
|
||||
*
|
||||
* For more information on nine-patch bitmaps, see the following document:
|
||||
* http://developer.android.com/guide/topics/graphics/2d-graphics.html#nine-patch
|
||||
*/
|
||||
public class NinePatchTileLayer extends TileLayer {
|
||||
private FloatBuffer mSideTexCoordBuffer, mSideVertexBuffer;
|
||||
private FloatBuffer mTopTexCoordBuffer, mTopVertexBuffer;
|
||||
private LayerController mLayerController;
|
||||
|
||||
private static final int PATCH_SIZE = 16;
|
||||
private static final int TEXTURE_SIZE = 48;
|
||||
|
||||
/*
|
||||
* We divide the nine-patch bitmap up into the "sides" and the "tops":
|
||||
*
|
||||
* Top
|
||||
* |
|
||||
* v
|
||||
* +---+---+---+
|
||||
* | | | |
|
||||
* | +---+ |
|
||||
* | |XXX| | <-- Side
|
||||
* | +---+ |
|
||||
* | | | |
|
||||
* +---+---+---+
|
||||
*/
|
||||
|
||||
private static final float[] SIDE_TEX_COORDS = {
|
||||
0.0f, 0.0f,
|
||||
0.25f, 0.0f,
|
||||
0.0f, 0.25f,
|
||||
0.25f, 0.25f,
|
||||
0.0f, 0.50f,
|
||||
0.25f, 0.50f,
|
||||
0.0f, 0.75f,
|
||||
0.25f, 0.75f,
|
||||
};
|
||||
|
||||
private static final float[] TOP_TEX_COORDS = {
|
||||
0.25f, 0.0f,
|
||||
0.50f, 0.0f,
|
||||
0.25f, 0.25f,
|
||||
0.50f, 0.25f,
|
||||
};
|
||||
|
||||
public NinePatchTileLayer(LayerController layerController) {
|
||||
super(false);
|
||||
|
||||
mLayerController = layerController;
|
||||
|
||||
mSideTexCoordBuffer = createBuffer(SIDE_TEX_COORDS);
|
||||
mTopTexCoordBuffer = createBuffer(TOP_TEX_COORDS);
|
||||
|
||||
recreateVertexBuffers();
|
||||
}
|
||||
|
||||
public void recreateVertexBuffers() {
|
||||
IntSize pageSize = mLayerController.getPageSize();
|
||||
|
||||
float[] sideVertices = {
|
||||
-PATCH_SIZE, -PATCH_SIZE, 0.0f,
|
||||
0.0f, -PATCH_SIZE, 0.0f,
|
||||
-PATCH_SIZE, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f,
|
||||
-PATCH_SIZE, pageSize.height, 0.0f,
|
||||
0.0f, pageSize.height, 0.0f,
|
||||
-PATCH_SIZE, PATCH_SIZE + pageSize.height, 0.0f,
|
||||
0.0f, PATCH_SIZE + pageSize.height, 0.0f
|
||||
};
|
||||
|
||||
float[] topVertices = {
|
||||
0.0f, -PATCH_SIZE, 0.0f,
|
||||
pageSize.width, -PATCH_SIZE, 0.0f,
|
||||
0.0f, 0.0f, 0.0f,
|
||||
pageSize.width, 0.0f, 0.0f
|
||||
};
|
||||
|
||||
mSideVertexBuffer = createBuffer(sideVertices);
|
||||
mTopVertexBuffer = createBuffer(topVertices);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTileDraw(GL10 gl) {
|
||||
IntSize pageSize = mLayerController.getPageSize();
|
||||
|
||||
gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
|
||||
gl.glEnable(GL10.GL_BLEND);
|
||||
|
||||
gl.glBindTexture(GL10.GL_TEXTURE_2D, getTextureID());
|
||||
|
||||
/* Left side */
|
||||
drawTriangles(gl, mSideVertexBuffer, mSideTexCoordBuffer, 8);
|
||||
|
||||
/* Top */
|
||||
drawTriangles(gl, mTopVertexBuffer, mTopTexCoordBuffer, 4);
|
||||
|
||||
/* Right side */
|
||||
gl.glMatrixMode(GL10.GL_MODELVIEW);
|
||||
gl.glPushMatrix();
|
||||
gl.glTranslatef(pageSize.width + PATCH_SIZE, 0.0f, 0.0f);
|
||||
gl.glMatrixMode(GL10.GL_TEXTURE);
|
||||
gl.glPushMatrix();
|
||||
gl.glTranslatef(0.50f, 0.0f, 0.0f);
|
||||
|
||||
drawTriangles(gl, mSideVertexBuffer, mSideTexCoordBuffer, 8);
|
||||
|
||||
gl.glMatrixMode(GL10.GL_TEXTURE);
|
||||
gl.glPopMatrix();
|
||||
gl.glMatrixMode(GL10.GL_MODELVIEW); /* Not strictly necessary, but here for clarity. */
|
||||
gl.glPopMatrix();
|
||||
|
||||
/* Bottom */
|
||||
gl.glMatrixMode(GL10.GL_MODELVIEW);
|
||||
gl.glPushMatrix();
|
||||
gl.glTranslatef(0.0f, pageSize.height + PATCH_SIZE, 0.0f);
|
||||
gl.glMatrixMode(GL10.GL_TEXTURE);
|
||||
gl.glPushMatrix();
|
||||
gl.glTranslatef(0.0f, 0.50f, 0.0f);
|
||||
|
||||
drawTriangles(gl, mTopVertexBuffer, mTopTexCoordBuffer, 4);
|
||||
|
||||
gl.glMatrixMode(GL10.GL_TEXTURE);
|
||||
gl.glPopMatrix();
|
||||
gl.glMatrixMode(GL10.GL_MODELVIEW);
|
||||
gl.glPopMatrix();
|
||||
|
||||
gl.glDisable(GL10.GL_BLEND);
|
||||
}
|
||||
}
|
130
mobile/android/base/gfx/PlaceholderLayerClient.java
Normal file
@ -0,0 +1,130 @@
|
||||
/* -*- 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) 2009-2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Patrick Walton <pcwalton@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.gfx;
|
||||
|
||||
import org.mozilla.gecko.gfx.BufferedCairoImage;
|
||||
import org.mozilla.gecko.gfx.CairoUtils;
|
||||
import org.mozilla.gecko.gfx.IntSize;
|
||||
import org.mozilla.gecko.gfx.LayerClient;
|
||||
import org.mozilla.gecko.gfx.SingleTileLayer;
|
||||
import org.mozilla.gecko.GeckoApp;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Environment;
|
||||
import android.util.Log;
|
||||
import java.io.File;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* A stand-in for Gecko that renders cached content of the previous page. We use this until Gecko
|
||||
* is up, then we hand off control to it.
|
||||
*/
|
||||
public class PlaceholderLayerClient extends LayerClient {
|
||||
private Context mContext;
|
||||
private IntSize mPageSize;
|
||||
private int mWidth, mHeight, mFormat;
|
||||
private ByteBuffer mBuffer;
|
||||
private FetchImageTask mTask;
|
||||
|
||||
private PlaceholderLayerClient(Context context) {
|
||||
mContext = context;
|
||||
mPageSize = new IntSize(995, 1250); /* TODO */
|
||||
}
|
||||
|
||||
public static PlaceholderLayerClient createInstance(Context context) {
|
||||
return new PlaceholderLayerClient(context);
|
||||
}
|
||||
|
||||
public void init() {
|
||||
mTask = new FetchImageTask();
|
||||
mTask.execute();
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
if (mTask != null) {
|
||||
mTask.cancel(false);
|
||||
mTask = null;
|
||||
}
|
||||
}
|
||||
|
||||
private class FetchImageTask extends AsyncTask<Void, Void, Void> {
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... unused) {
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inScaled = false;
|
||||
Bitmap bitmap = BitmapFactory.decodeFile(GeckoApp.getStartupBitmapFilePath(),
|
||||
options);
|
||||
if (bitmap == null)
|
||||
return null;
|
||||
|
||||
Bitmap.Config config = bitmap.getConfig();
|
||||
|
||||
mWidth = bitmap.getWidth();
|
||||
mHeight = bitmap.getHeight();
|
||||
mFormat = CairoUtils.bitmapConfigToCairoFormat(config);
|
||||
|
||||
int bpp = CairoUtils.bitsPerPixelForCairoFormat(mFormat) / 8;
|
||||
mBuffer = ByteBuffer.allocateDirect(mWidth * mHeight * bpp);
|
||||
|
||||
bitmap.copyPixelsToBuffer(mBuffer.asIntBuffer());
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void unused) {
|
||||
SingleTileLayer tileLayer = new SingleTileLayer();
|
||||
getLayerController().setRoot(tileLayer);
|
||||
tileLayer.paintImage(new BufferedCairoImage(mBuffer, mWidth, mHeight, mFormat));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void geometryChanged() { /* no-op */ }
|
||||
@Override
|
||||
public IntSize getPageSize() { return mPageSize; }
|
||||
@Override
|
||||
public void render() { /* no-op */ }
|
||||
|
||||
/** Called whenever the page changes size. */
|
||||
@Override
|
||||
public void setPageSize(IntSize pageSize) { mPageSize = pageSize; }
|
||||
}
|
||||
|
55
mobile/android/base/gfx/PointUtils.java
Normal file
@ -0,0 +1,55 @@
|
||||
/* -*- 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) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Kartikaya Gupta <kgupta@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.gfx;
|
||||
|
||||
import android.graphics.PointF;
|
||||
|
||||
public final class PointUtils {
|
||||
public static PointF add(PointF one, PointF two) {
|
||||
return new PointF(one.x + two.x, one.y + two.y);
|
||||
}
|
||||
|
||||
public static PointF subtract(PointF one, PointF two) {
|
||||
return new PointF(one.x - two.x, one.y - two.y);
|
||||
}
|
||||
|
||||
public static PointF scale(PointF point, float factor) {
|
||||
return new PointF(point.x * factor, point.y * factor);
|
||||
}
|
||||
}
|
||||
|
91
mobile/android/base/gfx/RectUtils.java
Normal file
@ -0,0 +1,91 @@
|
||||
/* -*- 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) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Kartikaya Gupta <kgupta@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.gfx;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public final class RectUtils {
|
||||
public static Rect create(JSONObject json) {
|
||||
try {
|
||||
int x = json.getInt("x");
|
||||
int y = json.getInt("y");
|
||||
int width = json.getInt("width");
|
||||
int height = json.getInt("height");
|
||||
return new Rect(x, y, x + width, y + height);
|
||||
} catch (JSONException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Rect contract(Rect rect, int lessWidth, int lessHeight) {
|
||||
float halfLessWidth = (float)lessWidth / 2.0f;
|
||||
float halfLessHeight = (float)lessHeight / 2.0f;
|
||||
return new Rect((int)Math.round((float)rect.left + halfLessWidth),
|
||||
(int)Math.round((float)rect.top + halfLessHeight),
|
||||
(int)Math.round((float)rect.right - halfLessWidth),
|
||||
(int)Math.round((float)rect.bottom - halfLessHeight));
|
||||
}
|
||||
|
||||
public static RectF contract(RectF rect, float lessWidth, float lessHeight) {
|
||||
float halfLessWidth = lessWidth / 2;
|
||||
float halfLessHeight = lessHeight / 2;
|
||||
return new RectF(rect.left + halfLessWidth,
|
||||
rect.top + halfLessHeight,
|
||||
rect.right - halfLessWidth,
|
||||
rect.bottom - halfLessHeight);
|
||||
}
|
||||
|
||||
public static RectF intersect(RectF one, RectF two) {
|
||||
float left = Math.max(one.left, two.left);
|
||||
float top = Math.max(one.top, two.top);
|
||||
float right = Math.min(one.right, two.right);
|
||||
float bottom = Math.min(one.bottom, two.bottom);
|
||||
return new RectF(left, top, Math.max(right, left), Math.max(bottom, top));
|
||||
}
|
||||
|
||||
public static RectF scale(RectF rect, float scale) {
|
||||
float x = rect.left * scale;
|
||||
float y = rect.top * scale;
|
||||
return new RectF(x, y,
|
||||
x + (rect.width() * scale),
|
||||
y + (rect.height() * scale));
|
||||
}
|
||||
}
|
107
mobile/android/base/gfx/SingleTileLayer.java
Normal file
@ -0,0 +1,107 @@
|
||||
/* -*- 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) 2009-2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Patrick Walton <pcwalton@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.gfx;
|
||||
|
||||
import org.mozilla.gecko.gfx.CairoImage;
|
||||
import org.mozilla.gecko.gfx.CairoUtils;
|
||||
import org.mozilla.gecko.gfx.IntSize;
|
||||
import org.mozilla.gecko.gfx.LayerController;
|
||||
import org.mozilla.gecko.gfx.TileLayer;
|
||||
import android.util.Log;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.FloatBuffer;
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
|
||||
/**
|
||||
* Encapsulates the logic needed to draw a single textured tile.
|
||||
*/
|
||||
public class SingleTileLayer extends TileLayer {
|
||||
private FloatBuffer mTexCoordBuffer, mVertexBuffer;
|
||||
|
||||
private static final float[] VERTICES = {
|
||||
0.0f, 0.0f, 0.0f,
|
||||
1.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f,
|
||||
1.0f, 1.0f, 0.0f
|
||||
};
|
||||
|
||||
private static final float[] TEX_COORDS = {
|
||||
0.0f, 0.0f,
|
||||
1.0f, 0.0f,
|
||||
0.0f, 1.0f,
|
||||
1.0f, 1.0f
|
||||
};
|
||||
|
||||
public SingleTileLayer() { this(false); }
|
||||
|
||||
public SingleTileLayer(boolean repeat) {
|
||||
super(repeat);
|
||||
|
||||
mVertexBuffer = createBuffer(VERTICES);
|
||||
mTexCoordBuffer = createBuffer(TEX_COORDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTileDraw(GL10 gl) {
|
||||
IntSize size = getSize();
|
||||
|
||||
if (repeats()) {
|
||||
gl.glMatrixMode(GL10.GL_TEXTURE);
|
||||
gl.glPushMatrix();
|
||||
gl.glScalef(LayerController.TILE_WIDTH / size.width,
|
||||
LayerController.TILE_HEIGHT / size.height,
|
||||
1.0f);
|
||||
|
||||
gl.glMatrixMode(GL10.GL_MODELVIEW);
|
||||
gl.glScalef(LayerController.TILE_WIDTH, LayerController.TILE_HEIGHT, 1.0f);
|
||||
} else {
|
||||
gl.glScalef(size.width, size.height, 1.0f);
|
||||
}
|
||||
|
||||
gl.glBindTexture(GL10.GL_TEXTURE_2D, getTextureID());
|
||||
drawTriangles(gl, mVertexBuffer, mTexCoordBuffer, 4);
|
||||
|
||||
if (repeats()) {
|
||||
gl.glMatrixMode(GL10.GL_TEXTURE);
|
||||
gl.glPopMatrix();
|
||||
gl.glMatrixMode(GL10.GL_MODELVIEW);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
99
mobile/android/base/gfx/TextLayer.java
Normal file
@ -0,0 +1,99 @@
|
||||
/* -*- 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) 2009-2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Patrick Walton <pcwalton@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.gfx;
|
||||
|
||||
import org.mozilla.gecko.gfx.BufferedCairoImage;
|
||||
import org.mozilla.gecko.gfx.CairoImage;
|
||||
import org.mozilla.gecko.gfx.IntSize;
|
||||
import org.mozilla.gecko.gfx.SingleTileLayer;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Typeface;
|
||||
import android.util.Log;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
/**
|
||||
* Draws text on a layer. This is used for the frame rate meter.
|
||||
*/
|
||||
public class TextLayer extends SingleTileLayer {
|
||||
private ByteBuffer mBuffer;
|
||||
private BufferedCairoImage mImage;
|
||||
private IntSize mSize;
|
||||
private String mText;
|
||||
|
||||
public TextLayer(IntSize size) {
|
||||
super(false);
|
||||
|
||||
mBuffer = ByteBuffer.allocateDirect(size.width * size.height * 4);
|
||||
mSize = size;
|
||||
mImage = new BufferedCairoImage(mBuffer, size.width, size.height,
|
||||
CairoImage.FORMAT_ARGB32);
|
||||
mText = "";
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
mText = text;
|
||||
renderText();
|
||||
paintImage(mImage);
|
||||
}
|
||||
|
||||
private void renderText() {
|
||||
Bitmap bitmap = Bitmap.createBitmap(mSize.width, mSize.height, Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
|
||||
Paint textPaint = new Paint();
|
||||
textPaint.setAntiAlias(true);
|
||||
textPaint.setColor(Color.WHITE);
|
||||
textPaint.setFakeBoldText(true);
|
||||
textPaint.setTextSize(18.0f);
|
||||
textPaint.setTypeface(Typeface.DEFAULT_BOLD);
|
||||
float width = textPaint.measureText(mText) + 18.0f;
|
||||
|
||||
Paint backgroundPaint = new Paint();
|
||||
backgroundPaint.setColor(Color.argb(127, 0, 0, 0));
|
||||
canvas.drawRect(0.0f, 0.0f, width, 18.0f + 6.0f, backgroundPaint);
|
||||
|
||||
canvas.drawText(mText, 6.0f, 18.0f, textPaint);
|
||||
|
||||
bitmap.copyPixelsToBuffer(mBuffer.asIntBuffer());
|
||||
}
|
||||
}
|
||||
|
71
mobile/android/base/gfx/TextureReaper.java
Normal file
@ -0,0 +1,71 @@
|
||||
/* -*- 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) 2009-2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Patrick Walton <pcwalton@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.gfx;
|
||||
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/** Manages a list of dead tiles, so we don't leak resources. */
|
||||
public class TextureReaper {
|
||||
private static TextureReaper sSharedInstance;
|
||||
private ArrayList<Integer> mDeadTextureIDs;
|
||||
|
||||
private TextureReaper() { mDeadTextureIDs = new ArrayList<Integer>(); }
|
||||
|
||||
public static TextureReaper get() {
|
||||
if (sSharedInstance == null)
|
||||
sSharedInstance = new TextureReaper();
|
||||
return sSharedInstance;
|
||||
}
|
||||
|
||||
public void add(int[] textureIDs) {
|
||||
for (int textureID : textureIDs)
|
||||
mDeadTextureIDs.add(textureID);
|
||||
}
|
||||
|
||||
public void reap(GL10 gl) {
|
||||
int[] deadTextureIDs = new int[mDeadTextureIDs.size()];
|
||||
for (int i = 0; i < deadTextureIDs.length; i++)
|
||||
deadTextureIDs[i] = mDeadTextureIDs.get(i);
|
||||
mDeadTextureIDs.clear();
|
||||
|
||||
gl.glDeleteTextures(deadTextureIDs.length, deadTextureIDs, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
194
mobile/android/base/gfx/TileLayer.java
Normal file
@ -0,0 +1,194 @@
|
||||
/* -*- 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) 2009-2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Patrick Walton <pcwalton@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.gfx;
|
||||
|
||||
import org.mozilla.gecko.gfx.CairoImage;
|
||||
import org.mozilla.gecko.gfx.IntSize;
|
||||
import org.mozilla.gecko.gfx.Layer;
|
||||
import org.mozilla.gecko.gfx.TextureReaper;
|
||||
import android.graphics.Rect;
|
||||
import android.util.Log;
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
import java.nio.Buffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
/**
|
||||
* Base class for tile layers, which encapsulate the logic needed to draw textured tiles in OpenGL
|
||||
* ES.
|
||||
*/
|
||||
public abstract class TileLayer extends Layer {
|
||||
private CairoImage mImage;
|
||||
private boolean mRepeat;
|
||||
private IntSize mSize;
|
||||
private int[] mTextureIDs;
|
||||
|
||||
/* The rect that needs to be uploaded to the texture.
|
||||
* This field should not be exposed to other classes, since it is
|
||||
* mutated by calls to union(), and this may lead to odd behavior
|
||||
* if other classes assume it is immutable.
|
||||
*/
|
||||
private Rect mTextureUploadRect;
|
||||
|
||||
public TileLayer(boolean repeat) {
|
||||
super();
|
||||
mRepeat = repeat;
|
||||
mTextureUploadRect = null;
|
||||
}
|
||||
|
||||
public IntSize getSize() { return mSize; }
|
||||
|
||||
protected boolean repeats() { return mRepeat; }
|
||||
protected int getTextureID() { return mTextureIDs[0]; }
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
if (mTextureIDs != null)
|
||||
TextureReaper.get().add(mTextureIDs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses implement this method to perform tile drawing.
|
||||
*
|
||||
* Invariant: The current matrix mode must be GL_MODELVIEW both before and after this call.
|
||||
*/
|
||||
protected abstract void onTileDraw(GL10 gl);
|
||||
|
||||
@Override
|
||||
protected void onDraw(GL10 gl) {
|
||||
if (mImage == null)
|
||||
return;
|
||||
if (mTextureUploadRect != null)
|
||||
uploadTexture(gl);
|
||||
|
||||
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
|
||||
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
|
||||
gl.glPushMatrix();
|
||||
|
||||
onTileDraw(gl);
|
||||
|
||||
gl.glPopMatrix();
|
||||
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
|
||||
}
|
||||
|
||||
public void paintSubimage(CairoImage image, Rect rect) {
|
||||
mImage = image;
|
||||
mTextureUploadRect = rect;
|
||||
|
||||
/*
|
||||
* Assert that the image has a power-of-two size. OpenGL ES < 2.0 doesn't support NPOT
|
||||
* textures and OpenGL ES doesn't seem to let us efficiently slice up a NPOT bitmap.
|
||||
*/
|
||||
int width = mImage.getWidth(), height = mImage.getHeight();
|
||||
assert (width & (width - 1)) == 0;
|
||||
assert (height & (height - 1)) == 0;
|
||||
}
|
||||
|
||||
public void paintImage(CairoImage image) {
|
||||
paintSubimage(image, new Rect(0, 0, image.getWidth(), image.getHeight()));
|
||||
}
|
||||
|
||||
private void uploadTexture(GL10 gl) {
|
||||
boolean newTexture = mTextureIDs == null;
|
||||
if (newTexture) {
|
||||
mTextureIDs = new int[1];
|
||||
gl.glGenTextures(mTextureIDs.length, mTextureIDs, 0);
|
||||
}
|
||||
|
||||
int width = mImage.getWidth(), height = mImage.getHeight();
|
||||
mSize = new IntSize(width, height);
|
||||
|
||||
int cairoFormat = mImage.getFormat();
|
||||
int internalFormat = CairoUtils.cairoFormatToGLInternalFormat(cairoFormat);
|
||||
int format = CairoUtils.cairoFormatToGLFormat(cairoFormat);
|
||||
int type = CairoUtils.cairoFormatToGLType(cairoFormat);
|
||||
|
||||
gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureIDs[0]);
|
||||
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
|
||||
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
|
||||
|
||||
int repeatMode = mRepeat ? GL10.GL_REPEAT : GL10.GL_CLAMP_TO_EDGE;
|
||||
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, repeatMode);
|
||||
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, repeatMode);
|
||||
|
||||
ByteBuffer buffer = mImage.lockBuffer();
|
||||
try {
|
||||
if (newTexture) {
|
||||
/* The texture is new; we have to upload the whole image. */
|
||||
gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, internalFormat, mSize.width, mSize.height, 0,
|
||||
format, type, buffer);
|
||||
} else {
|
||||
/*
|
||||
* The texture is already existing, so upload only the changed rect. We have to
|
||||
* widen to the full width of the texture because we can't count on the device
|
||||
* having support for GL_EXT_unpack_subimage, and going line-by-line is too slow.
|
||||
*/
|
||||
Buffer viewBuffer = buffer.slice();
|
||||
int bpp = CairoUtils.bitsPerPixelForCairoFormat(cairoFormat) / 8;
|
||||
viewBuffer.position(mTextureUploadRect.top * width * bpp);
|
||||
|
||||
gl.glTexSubImage2D(gl.GL_TEXTURE_2D,
|
||||
0, 0, mTextureUploadRect.top, width, mTextureUploadRect.height(),
|
||||
format, type, viewBuffer);
|
||||
}
|
||||
} finally {
|
||||
mImage.unlockBuffer();
|
||||
}
|
||||
|
||||
mTextureUploadRect = null;
|
||||
}
|
||||
|
||||
protected static FloatBuffer createBuffer(float[] values) {
|
||||
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(values.length * 4);
|
||||
byteBuffer.order(ByteOrder.nativeOrder());
|
||||
|
||||
FloatBuffer floatBuffer = byteBuffer.asFloatBuffer();
|
||||
floatBuffer.put(values);
|
||||
floatBuffer.position(0);
|
||||
return floatBuffer;
|
||||
}
|
||||
|
||||
protected static void drawTriangles(GL10 gl, FloatBuffer vertexBuffer,
|
||||
FloatBuffer texCoordBuffer, int count) {
|
||||
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
|
||||
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, texCoordBuffer);
|
||||
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, count);
|
||||
}
|
||||
}
|
||||
|
48
mobile/android/base/locales/Makefile.in
Normal file
@ -0,0 +1,48 @@
|
||||
# ***** 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
|
||||
# the 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 *****
|
||||
|
||||
DEPTH = ../../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
relativesrcdir = mobile/android/base/locales
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
DEFINES += -DAB_CD=$(AB_CD)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
72
mobile/android/base/locales/en-US/android_strings.dtd
Normal file
@ -0,0 +1,72 @@
|
||||
|
||||
<!ENTITY splash_firstrun "Setting up &brandShortName;\u2026">
|
||||
|
||||
<!ENTITY no_space_to_start_error "There is not enough space available for &brandShortName; to start.">
|
||||
<!ENTITY error_loading_file "An error occurred when trying to load files required to run &brandShortName;">
|
||||
|
||||
<!ENTITY awesomebar_all_pages_title "All Pages">
|
||||
<!ENTITY awesomebar_bookmarks_title "Bookmarks">
|
||||
<!ENTITY awesomebar_history_title "History">
|
||||
|
||||
<!ENTITY crash_reporter_title "&brandShortName; Crash Reporter">
|
||||
<!ENTITY crash_message "&brandShortName; has crashed. Your tabs should be listed on the &brandShortName; Start page when you restart.">
|
||||
<!ENTITY crash_help_message "Please help us fix this problem!">
|
||||
<!ENTITY crash_send_report_message "Send Mozilla a crash report">
|
||||
<!ENTITY crash_include_url "Include page address">
|
||||
<!ENTITY crash_close_label "Close">
|
||||
<!ENTITY crash_restart_label "Restart &brandShortName;">
|
||||
<!ENTITY sending_crash_report "Sending crash report\u2026">
|
||||
<!ENTITY exit_label "Exit">
|
||||
<!ENTITY continue_label "Continue">
|
||||
|
||||
<!ENTITY launcher_shortcuts_title "&brandShortName; Web Apps">
|
||||
<!ENTITY launcher_shortcuts_empty "No web apps were found">
|
||||
|
||||
<!ENTITY choose_file "Choose File">
|
||||
|
||||
<!ENTITY awesomebar_default_text "Enter Search or Address">
|
||||
|
||||
<!ENTITY bookmarks_title "Bookmarks">
|
||||
<!ENTITY bookmark_add "Bookmark">
|
||||
<!ENTITY bookmark_remove "Remove">
|
||||
<!ENTITY bookmark_added "Bookmark added">
|
||||
<!ENTITY bookmark_removed "Bookmark removed">
|
||||
|
||||
<!ENTITY history_today_section "Today">
|
||||
<!ENTITY history_yesterday_section "Yesterday">
|
||||
<!ENTITY history_week_section "7 days ago">
|
||||
<!ENTITY history_older_section "Older than 7 days">
|
||||
|
||||
<!ENTITY reload "Reload">
|
||||
<!ENTITY forward "Forward">
|
||||
|
||||
<!ENTITY new_tab "New Tab">
|
||||
|
||||
<!ENTITY preferences "Preferences">
|
||||
<!ENTITY preferences_title "Preferences">
|
||||
<!ENTITY pref_category_privacy "Privacy & Security">
|
||||
<!ENTITY pref_category_content "Content">
|
||||
<!ENTITY pref_do_not_track "Tell sites not to track me">
|
||||
<!ENTITY pref_telemetry "Send performance data">
|
||||
<!ENTITY pref_homepage "Home page">
|
||||
<!ENTITY pref_homepage_start "Firefox Start">
|
||||
<!ENTITY pref_homepage_blank "Blank page">
|
||||
<!ENTITY pref_homepage_current "Current page">
|
||||
<!ENTITY pref_remember_signons "Remember passwords">
|
||||
<!ENTITY pref_locale "Language">
|
||||
<!ENTITY pref_cookies "Enable cookies">
|
||||
<!ENTITY pref_zoom_reflow "Reformat text on zoom">
|
||||
<!ENTITY pref_show_images "Show images">
|
||||
<!ENTITY pref_enable_js "Enable JavaScript">
|
||||
<!ENTITY pref_char_encoding "Show character encoding">
|
||||
<!ENTITY pref_clear_history "Clear history">
|
||||
<!ENTITY pref_clear_history_confirm "Browsing history will be deleted">
|
||||
<!ENTITY pref_clear_private_data "Clear private data">
|
||||
<!ENTITY pref_clear_private_data_confirm "Browsing settings, including passwords and cookies, will be deleted">
|
||||
|
||||
<!ENTITY quit "Quit">
|
||||
|
||||
<!ENTITY addons "Add-ons">
|
||||
|
||||
<!ENTITY share "Share">
|
||||
<!ENTITY save_as_pdf "Save as PDF">
|
4
mobile/android/base/locales/jar.mn
Normal file
@ -0,0 +1,4 @@
|
||||
#filter substitution
|
||||
|
||||
android-res.jar:
|
||||
res/values-@AB_CD@/android_strings.dtd (%android_strings.dtd)
|
5
mobile/android/base/locales/l10n.ini
Normal file
@ -0,0 +1,5 @@
|
||||
[general]
|
||||
depth = ../../..
|
||||
|
||||
[compare]
|
||||
dirs = mobile/android/base
|
2
mobile/android/base/package-name.txt.in
Normal file
@ -0,0 +1,2 @@
|
||||
#filter substitution
|
||||
@ANDROID_PACKAGE_NAME@
|
17
mobile/android/base/resources/anim/grow_fade_in.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<scale android:fromXScale="1.0"
|
||||
android:toXScale="1.0"
|
||||
android:fromYScale="0.3"
|
||||
android:toYScale="1.0"
|
||||
android:pivotX="0%"
|
||||
android:pivotY="0%"
|
||||
android:duration="150"/>
|
||||
|
||||
<alpha android:interpolator="@android:anim/decelerate_interpolator"
|
||||
android:fromAlpha="0.0"
|
||||
android:toAlpha="1.0"
|
||||
android:duration="150"/>
|
||||
|
||||
</set>
|
17
mobile/android/base/resources/anim/shrink_fade_out.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<scale android:fromXScale="1.0"
|
||||
android:toXScale="1.0"
|
||||
android:fromYScale="1.0"
|
||||
android:toYScale="0.3"
|
||||
android:pivotX="0%"
|
||||
android:pivotY="0%"
|
||||
android:duration="150"/>
|
||||
|
||||
<alpha android:interpolator="@android:anim/accelerate_interpolator"
|
||||
android:fromAlpha="1.0"
|
||||
android:toAlpha="0.0"
|
||||
android:duration="150"/>
|
||||
|
||||
</set>
|
13
mobile/android/base/resources/color/awesomebar_tab_text.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<!-- Non focused state -->
|
||||
<item android:state_focused="false"
|
||||
android:state_selected="false"
|
||||
android:state_pressed="false"
|
||||
android:color="#aaaaaa"/>
|
||||
|
||||
<!-- Default text color -->
|
||||
<item android:color="#ffffff"/>
|
||||
|
||||
</selector>
|
After Width: | Height: | Size: 550 B |
After Width: | Height: | Size: 623 B |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 580 B |
After Width: | Height: | Size: 405 B |
After Width: | Height: | Size: 729 B |
After Width: | Height: | Size: 356 B |
After Width: | Height: | Size: 573 B |
BIN
mobile/android/base/resources/drawable-hdpi-v11/tabs_more.png
Normal file
After Width: | Height: | Size: 223 B |
BIN
mobile/android/base/resources/drawable-hdpi-v11/tabs_normal.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
mobile/android/base/resources/drawable-hdpi-v11/tabs_plus.png
Normal file
After Width: | Height: | Size: 175 B |
BIN
mobile/android/base/resources/drawable-hdpi-v11/tabs_pressed.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 835 B |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 82 B |
After Width: | Height: | Size: 133 B |
After Width: | Height: | Size: 140 B |
After Width: | Height: | Size: 3.0 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 1.6 KiB |
BIN
mobile/android/base/resources/drawable-hdpi-v8/ic_menu_share.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 692 B |
BIN
mobile/android/base/resources/drawable-hdpi-v8/tabs_more.png
Normal file
After Width: | Height: | Size: 348 B |
BIN
mobile/android/base/resources/drawable-hdpi-v8/tabs_normal.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
mobile/android/base/resources/drawable-hdpi-v8/tabs_plus.png
Normal file
After Width: | Height: | Size: 591 B |
BIN
mobile/android/base/resources/drawable-hdpi-v8/tabs_pressed.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
mobile/android/base/resources/drawable-hdpi-v8/urlbar_stop.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 1.1 KiB |
BIN
mobile/android/base/resources/drawable-hdpi-v9/ic_menu_share.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 550 B |
After Width: | Height: | Size: 516 B |