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
This commit is contained in:
Doug Turner 2011-11-18 10:28:17 -08:00
parent 1af2d30f95
commit 490fecdcdc
223 changed files with 14999 additions and 16 deletions

View File

@ -53,8 +53,4 @@ XPCSHELL_TESTS = tests/unit
DIRS += test
endif
ifeq ($(MOZ_WIDGET_TOOLKIT),android)
DIRS += android
endif
include $(topsrcdir)/config/rules.mk

View File

@ -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

View 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;
}
}

View 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>

View 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@";
}
};

View 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;
}
}
}

View 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);
}
}

View 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);
}
}

View 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);
}
}

View 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");
}
}

View 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;
}
}

View 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;
}
}
}
}

View 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;
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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);
}

View 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() };
}
}

View 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);
}
}

View 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;
}
}

View 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);
}

File diff suppressed because it is too large Load Diff

View 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);
}
}

View 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);
}
}

View 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());
}
}
}

View 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);
}
});
}
}

View 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();
}
}
}
}

View 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)

View 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);
}
}
}
}

View 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;
}
}
}

View 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);
}
};

View 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;
}

View 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);
}
}
}

View 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);
}
}
}

View 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;
}
}

View 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; }
}

View 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;
}

View 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");
}
}
}

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

View 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);
}

View 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));
}
}

View 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);
}

View 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;
}
}

View 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;
}
}

View 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++;
}
}
}

View 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;
}
}

View 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);
}
}

View 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; }
}

View 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);
}
}

View 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));
}
}

View 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);
}
}
}

View 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());
}
}

View 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);
}
}

View 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);
}
}

View 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

View 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 &amp; 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">

View File

@ -0,0 +1,4 @@
#filter substitution
android-res.jar:
res/values-@AB_CD@/android_strings.dtd (%android_strings.dtd)

View File

@ -0,0 +1,5 @@
[general]
depth = ../../..
[compare]
dirs = mobile/android/base

View File

@ -0,0 +1,2 @@
#filter substitution
@ANDROID_PACKAGE_NAME@

View 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>

View 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>

View 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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 550 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 623 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 580 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 405 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 729 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 356 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 573 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 835 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 692 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 348 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 591 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 550 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 516 B

Some files were not shown because too many files have changed in this diff Show More