summaryrefslogtreecommitdiff
path: root/chrome/browser
diff options
context:
space:
mode:
authorTorne (Richard Coles) <torne@google.com>2013-10-22 16:41:35 +0100
committerTorne (Richard Coles) <torne@google.com>2013-10-22 16:41:35 +0100
commit8bcbed890bc3ce4d7a057a8f32cab53fa534672e (patch)
tree1390b6675d21328859f01f50203d9bde09105298 /chrome/browser
parent116fa16b45c9efe30e785b9fc32f09780ca23bec (diff)
downloadchromium_org-8bcbed890bc3ce4d7a057a8f32cab53fa534672e.tar.gz
Merge from Chromium at DEPS revision 230120
This commit was generated by merge_to_master.py. Change-Id: I54bc06b7ee8a07092e74ce3b68c6893508349042
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/about_flags.cc56
-rw-r--r--chrome/browser/android/crash_dump_manager.cc173
-rw-r--r--chrome/browser/android/crash_dump_manager.h81
-rw-r--r--chrome/browser/android/dev_tools_server.cc128
-rw-r--r--chrome/browser/android/tab_android.cc38
-rw-r--r--chrome/browser/android/tab_android.h14
-rw-r--r--chrome/browser/app_controller_mac.mm5
-rw-r--r--chrome/browser/apps/app_browsertest.cc11
-rw-r--r--chrome/browser/apps/app_browsertest_util.cc34
-rw-r--r--chrome/browser/apps/app_browsertest_util.h4
-rw-r--r--chrome/browser/apps/web_view_browsertest.cc27
-rw-r--r--chrome/browser/apps/web_view_interactive_browsertest.cc70
-rw-r--r--chrome/browser/autocomplete/autocomplete_result.cc14
-rw-r--r--chrome/browser/autocomplete/extension_app_provider.cc3
-rw-r--r--chrome/browser/autocomplete/history_provider_util.cc6
-rw-r--r--chrome/browser/autocomplete/history_provider_util.h4
-rw-r--r--chrome/browser/autocomplete/history_url_provider.cc163
-rw-r--r--chrome/browser/autocomplete/history_url_provider.h13
-rw-r--r--chrome/browser/autocomplete/keyword_provider.cc7
-rw-r--r--chrome/browser/automation/automation_event_observers.h4
-rw-r--r--chrome/browser/automation/automation_event_observers_chromeos.cc4
-rw-r--r--chrome/browser/automation/automation_provider_observers.h10
-rw-r--r--chrome/browser/automation/automation_provider_observers_chromeos.cc5
-rw-r--r--chrome/browser/automation/testing_automation_provider.cc6
-rw-r--r--chrome/browser/background/background_mode_manager.cc2
-rw-r--r--chrome/browser/background/background_mode_manager.h6
-rw-r--r--chrome/browser/bookmarks/bookmark_model.cc15
-rw-r--r--chrome/browser/bookmarks/bookmark_model_observer.h8
-rw-r--r--chrome/browser/bookmarks/bookmark_tag_model.cc553
-rw-r--r--chrome/browser/bookmarks/bookmark_tag_model.h214
-rw-r--r--chrome/browser/bookmarks/bookmark_tag_model_observer.h76
-rw-r--r--chrome/browser/bookmarks/bookmark_tag_model_unittest.cc566
-rw-r--r--chrome/browser/browser_encoding_browsertest.cc2
-rw-r--r--chrome/browser/browser_keyevents_browsertest.cc8
-rw-r--r--chrome/browser/browser_process_impl.cc5
-rw-r--r--chrome/browser/browser_resources.grd1
-rw-r--r--chrome/browser/captive_portal/captive_portal_tab_helper.cc2
-rw-r--r--chrome/browser/captive_portal/captive_portal_tab_helper.h2
-rw-r--r--chrome/browser/captive_portal/captive_portal_tab_helper_unittest.cc65
-rw-r--r--chrome/browser/certificate_viewer.h4
-rw-r--r--chrome/browser/chrome_browser_field_trials.cc1
-rw-r--r--chrome/browser/chrome_browser_main.cc43
-rw-r--r--chrome/browser/chrome_browser_main.h3
-rw-r--r--chrome/browser/chrome_browser_main_android.cc11
-rw-r--r--chrome/browser/chrome_browser_main_android.h4
-rw-r--r--chrome/browser/chrome_browser_main_linux.cc6
-rw-r--r--chrome/browser/chrome_browser_main_mac.mm2
-rw-r--r--chrome/browser/chrome_content_browser_client.cc122
-rw-r--r--chrome/browser/chromeos/accessibility/sticky_keys_browsertest.cc144
-rw-r--r--chrome/browser/chromeos/app_mode/kiosk_profile_loader.cc6
-rw-r--r--chrome/browser/chromeos/app_mode/kiosk_profile_loader.h5
-rw-r--r--chrome/browser/chromeos/app_mode/startup_app_launcher.cc4
-rw-r--r--chrome/browser/chromeos/attestation/OWNERS1
-rw-r--r--chrome/browser/chromeos/attestation/attestation_policy_observer.cc6
-rw-r--r--chrome/browser/chromeos/attestation/attestation_policy_observer_unittest.cc26
-rw-r--r--chrome/browser/chromeos/attestation/platform_verification_flow.cc58
-rw-r--r--chrome/browser/chromeos/attestation/platform_verification_flow.h25
-rw-r--r--chrome/browser/chromeos/attestation/platform_verification_flow_unittest.cc81
-rw-r--r--chrome/browser/chromeos/boot_times_loader.cc2
-rw-r--r--chrome/browser/chromeos/chrome_browser_main_chromeos.cc77
-rw-r--r--chrome/browser/chromeos/contacts/gdata_contacts_service_unittest.cc2
-rw-r--r--chrome/browser/chromeos/display/display_preferences.cc4
-rw-r--r--chrome/browser/chromeos/display/overscan_calibrator.cc3
-rw-r--r--chrome/browser/chromeos/drive/async_file_util.cc4
-rw-r--r--chrome/browser/chromeos/drive/change_list_loader.cc32
-rw-r--r--chrome/browser/chromeos/drive/change_list_loader.h14
-rw-r--r--chrome/browser/chromeos/drive/drive.proto5
-rw-r--r--chrome/browser/chromeos/drive/drive_integration_service.cc3
-rw-r--r--chrome/browser/chromeos/drive/file_cache.cc117
-rw-r--r--chrome/browser/chromeos/drive/file_cache.h47
-rw-r--r--chrome/browser/chromeos/drive/file_cache_unittest.cc59
-rw-r--r--chrome/browser/chromeos/drive/file_system.cc79
-rw-r--r--chrome/browser/chromeos/drive/file_system.h8
-rw-r--r--chrome/browser/chromeos/drive/file_system/copy_operation_unittest.cc12
-rw-r--r--chrome/browser/chromeos/drive/file_system/download_operation_unittest.cc73
-rw-r--r--chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation.cc1
-rw-r--r--chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation_unittest.cc12
-rw-r--r--chrome/browser/chromeos/drive/file_system/open_file_operation_unittest.cc12
-rw-r--r--chrome/browser/chromeos/drive/file_system/update_operation_unittest.cc86
-rw-r--r--chrome/browser/chromeos/drive/file_system_interface.h7
-rw-r--r--chrome/browser/chromeos/drive/file_system_unittest.cc2
-rw-r--r--chrome/browser/chromeos/drive/file_system_util.cc35
-rw-r--r--chrome/browser/chromeos/drive/file_system_util.h7
-rw-r--r--chrome/browser/chromeos/drive/file_system_util_unittest.cc30
-rw-r--r--chrome/browser/chromeos/drive/resource_entry_conversion.cc5
-rw-r--r--chrome/browser/chromeos/drive/resource_entry_conversion_unittest.cc6
-rw-r--r--chrome/browser/chromeos/drive/resource_metadata.cc38
-rw-r--r--chrome/browser/chromeos/drive/resource_metadata.h6
-rw-r--r--chrome/browser/chromeos/drive/resource_metadata_storage.cc102
-rw-r--r--chrome/browser/chromeos/drive/resource_metadata_storage.h5
-rw-r--r--chrome/browser/chromeos/drive/resource_metadata_storage_unittest.cc23
-rw-r--r--chrome/browser/chromeos/drive/resource_metadata_unittest.cc75
-rw-r--r--chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.cc106
-rw-r--r--chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.h78
-rw-r--r--chrome/browser/chromeos/extensions/device_local_account_external_policy_loader_unittest.cc309
-rw-r--r--chrome/browser/chromeos/extensions/external_pref_cache_loader.h5
-rw-r--r--chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc14
-rw-r--r--chrome/browser/chromeos/extensions/wallpaper_private_api.cc76
-rw-r--r--chrome/browser/chromeos/extensions/wallpaper_private_api.h9
-rw-r--r--chrome/browser/chromeos/file_manager/file_browser_handlers.cc4
-rw-r--r--chrome/browser/chromeos/file_manager/file_tasks.cc57
-rw-r--r--chrome/browser/chromeos/file_manager/file_tasks.h10
-rw-r--r--chrome/browser/chromeos/file_manager/file_tasks_unittest.cc116
-rw-r--r--chrome/browser/chromeos/file_manager/open_with_browser.cc52
-rw-r--r--chrome/browser/chromeos/file_manager/open_with_browser.h2
-rw-r--r--chrome/browser/chromeos/file_manager/url_util.cc2
-rw-r--r--chrome/browser/chromeos/input_method/input_method_configuration_unittest.cc4
-rw-r--r--chrome/browser/chromeos/input_method/input_method_manager_impl.cc2
-rw-r--r--chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc14
-rw-r--r--chrome/browser/chromeos/kiosk_mode/kiosk_mode_idle_logout.cc2
-rw-r--r--chrome/browser/chromeos/login/app_launch_signin_screen.cc4
-rw-r--r--chrome/browser/chromeos/login/app_launch_signin_screen.h4
-rw-r--r--chrome/browser/chromeos/login/auth_sync_observer.cc3
-rw-r--r--chrome/browser/chromeos/login/authenticator.h19
-rw-r--r--chrome/browser/chromeos/login/captive_portal_view.cc3
-rw-r--r--chrome/browser/chromeos/login/chrome_restart_request.cc5
-rw-r--r--chrome/browser/chromeos/login/crash_restore_browsertest.cc6
-rw-r--r--chrome/browser/chromeos/login/eula_browsertest.cc2
-rw-r--r--chrome/browser/chromeos/login/existing_user_controller.cc22
-rw-r--r--chrome/browser/chromeos/login/existing_user_controller.h5
-rw-r--r--chrome/browser/chromeos/login/existing_user_controller_auto_login_unittest.cc1
-rw-r--r--chrome/browser/chromeos/login/existing_user_controller_browsertest.cc6
-rw-r--r--chrome/browser/chromeos/login/fake_login_utils.cc5
-rw-r--r--chrome/browser/chromeos/login/fake_login_utils.h1
-rw-r--r--chrome/browser/chromeos/login/fake_supervised_user_manager.cc58
-rw-r--r--chrome/browser/chromeos/login/fake_supervised_user_manager.h48
-rw-r--r--chrome/browser/chromeos/login/fake_user_manager.cc52
-rw-r--r--chrome/browser/chromeos/login/fake_user_manager.h28
-rw-r--r--chrome/browser/chromeos/login/login_display_host_impl.cc6
-rw-r--r--chrome/browser/chromeos/login/login_performer.cc24
-rw-r--r--chrome/browser/chromeos/login/login_performer.h5
-rw-r--r--chrome/browser/chromeos/login/login_status_consumer.cc4
-rw-r--r--chrome/browser/chromeos/login/login_status_consumer.h7
-rw-r--r--chrome/browser/chromeos/login/login_utils.cc13
-rw-r--r--chrome/browser/chromeos/login/login_utils.h1
-rw-r--r--chrome/browser/chromeos/login/login_utils_browsertest.cc31
-rw-r--r--chrome/browser/chromeos/login/managed/locally_managed_user_creation_controller.cc71
-rw-r--r--chrome/browser/chromeos/login/managed/locally_managed_user_creation_controller.h29
-rw-r--r--chrome/browser/chromeos/login/managed/locally_managed_user_creation_screen.cc171
-rw-r--r--chrome/browser/chromeos/login/managed/locally_managed_user_creation_screen.h5
-rw-r--r--chrome/browser/chromeos/login/managed/managed_user_authenticator.cc11
-rw-r--r--chrome/browser/chromeos/login/managed/supervised_user_creation_browsertest.cc19
-rw-r--r--chrome/browser/chromeos/login/mock_authenticator.cc22
-rw-r--r--chrome/browser/chromeos/login/mock_authenticator.h2
-rw-r--r--chrome/browser/chromeos/login/mock_login_status_consumer.cc10
-rw-r--r--chrome/browser/chromeos/login/mock_login_status_consumer.h15
-rw-r--r--chrome/browser/chromeos/login/mock_login_utils.cc2
-rw-r--r--chrome/browser/chromeos/login/mock_login_utils.h4
-rw-r--r--chrome/browser/chromeos/login/mock_user_manager.cc12
-rw-r--r--chrome/browser/chromeos/login/mock_user_manager.h28
-rw-r--r--chrome/browser/chromeos/login/oauth2_login_verifier.cc2
-rw-r--r--chrome/browser/chromeos/login/parallel_authenticator.cc88
-rw-r--r--chrome/browser/chromeos/login/parallel_authenticator.h20
-rw-r--r--chrome/browser/chromeos/login/parallel_authenticator_unittest.cc69
-rw-r--r--chrome/browser/chromeos/login/screen_locker.cc19
-rw-r--r--chrome/browser/chromeos/login/screen_locker.h8
-rw-r--r--chrome/browser/chromeos/login/screen_locker_browsertest.cc10
-rw-r--r--chrome/browser/chromeos/login/screen_locker_tester.cc4
-rw-r--r--chrome/browser/chromeos/login/screens/network_screen_browsertest.cc10
-rw-r--r--chrome/browser/chromeos/login/screens/update_screen.cc24
-rw-r--r--chrome/browser/chromeos/login/screens/update_screen_browsertest.cc36
-rw-r--r--chrome/browser/chromeos/login/startup_utils.cc4
-rw-r--r--chrome/browser/chromeos/login/supervised_user_manager.h88
-rw-r--r--chrome/browser/chromeos/login/supervised_user_manager_impl.cc332
-rw-r--r--chrome/browser/chromeos/login/supervised_user_manager_impl.h76
-rw-r--r--chrome/browser/chromeos/login/test_login_utils.cc1
-rw-r--r--chrome/browser/chromeos/login/test_login_utils.h1
-rw-r--r--chrome/browser/chromeos/login/user.cc23
-rw-r--r--chrome/browser/chromeos/login/user.h7
-rw-r--r--chrome/browser/chromeos/login/user_manager.h123
-rw-r--r--chrome/browser/chromeos/login/user_manager_impl.cc499
-rw-r--r--chrome/browser/chromeos/login/user_manager_impl.h101
-rw-r--r--chrome/browser/chromeos/login/wallpaper_manager.cc3
-rw-r--r--chrome/browser/chromeos/login/wallpaper_manager_unittest.cc7
-rw-r--r--chrome/browser/chromeos/login/webui_login_view.cc61
-rw-r--r--chrome/browser/chromeos/login/webui_login_view.h12
-rw-r--r--chrome/browser/chromeos/login/webui_screen_locker.cc3
-rw-r--r--chrome/browser/chromeos/login/webui_screen_locker.h4
-rw-r--r--chrome/browser/chromeos/login/wizard_controller.cc22
-rw-r--r--chrome/browser/chromeos/login/wizard_controller_browsertest.cc12
-rw-r--r--chrome/browser/chromeos/mobile_config.cc2
-rw-r--r--chrome/browser/chromeos/net/network_portal_detector.cc75
-rw-r--r--chrome/browser/chromeos/net/network_portal_detector.h23
-rw-r--r--chrome/browser/chromeos/net/network_portal_detector_impl.cc13
-rw-r--r--chrome/browser/chromeos/net/network_portal_detector_impl.h2
-rw-r--r--chrome/browser/chromeos/net/network_portal_detector_impl_unittest.cc3
-rw-r--r--chrome/browser/chromeos/net/network_portal_detector_test_impl.cc (renamed from chrome/browser/chromeos/net/network_portal_detector_stub.cc)38
-rw-r--r--chrome/browser/chromeos/net/network_portal_detector_test_impl.h (renamed from chrome/browser/chromeos/net/network_portal_detector_stub.h)18
-rw-r--r--chrome/browser/chromeos/net/onc_utils.cc27
-rw-r--r--chrome/browser/chromeos/net/onc_utils.h13
-rw-r--r--chrome/browser/chromeos/offline/offline_load_page.cc3
-rw-r--r--chrome/browser/chromeos/options/vpn_config_view.cc11
-rw-r--r--chrome/browser/chromeos/options/wifi_config_view.cc20
-rw-r--r--chrome/browser/chromeos/options/wimax_config_view.cc15
-rw-r--r--chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.cc13
-rw-r--r--chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.h4
-rw-r--r--chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.cc5
-rw-r--r--chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h4
-rw-r--r--chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc12
-rw-r--r--chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.cc8
-rw-r--r--chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h10
-rw-r--r--chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos_unittest.cc9
-rw-r--r--chrome/browser/chromeos/policy/device_local_account.h16
-rw-r--r--chrome/browser/chromeos/policy/device_local_account_browsertest.cc139
-rw-r--r--chrome/browser/chromeos/policy/device_local_account_policy_provider.cc1
-rw-r--r--chrome/browser/chromeos/policy/device_local_account_policy_service.cc355
-rw-r--r--chrome/browser/chromeos/policy/device_local_account_policy_service.h98
-rw-r--r--chrome/browser/chromeos/policy/device_local_account_policy_service_unittest.cc860
-rw-r--r--chrome/browser/chromeos/policy/device_local_account_policy_store.cc9
-rw-r--r--chrome/browser/chromeos/policy/device_local_account_policy_store.h10
-rw-r--r--chrome/browser/chromeos/policy/device_policy_cros_browser_test.cc8
-rw-r--r--chrome/browser/chromeos/policy/device_policy_cros_browser_test.h12
-rw-r--r--chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc5
-rw-r--r--chrome/browser/chromeos/policy/enrollment_handler_chromeos.h26
-rw-r--r--chrome/browser/chromeos/policy/network_configuration_updater.cc13
-rw-r--r--chrome/browser/chromeos/policy/network_configuration_updater.h5
-rw-r--r--chrome/browser/chromeos/policy/network_configuration_updater_unittest.cc96
-rw-r--r--chrome/browser/chromeos/policy/power_policy_browsertest.cc4
-rw-r--r--chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.cc5
-rw-r--r--chrome/browser/chromeos/policy/user_cloud_policy_manager_factory_chromeos.cc10
-rw-r--r--chrome/browser/chromeos/policy/user_cloud_policy_manager_factory_chromeos.h11
-rw-r--r--chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.cc30
-rw-r--r--chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.h6
-rw-r--r--chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos_unittest.cc9
-rw-r--r--chrome/browser/chromeos/policy/user_network_configuration_updater.cc9
-rw-r--r--chrome/browser/chromeos/policy/user_network_configuration_updater.h3
-rw-r--r--chrome/browser/chromeos/policy/user_policy_disk_cache.cc81
-rw-r--r--chrome/browser/chromeos/policy/user_policy_disk_cache.h12
-rw-r--r--chrome/browser/chromeos/policy/user_policy_token_loader.cc63
-rw-r--r--chrome/browser/chromeos/policy/user_policy_token_loader.h16
-rw-r--r--chrome/browser/chromeos/power/peripheral_battery_observer_browsertest.cc8
-rw-r--r--chrome/browser/chromeos/power/power_prefs_unittest.cc8
-rw-r--r--chrome/browser/chromeos/preferences.cc5
-rw-r--r--chrome/browser/chromeos/settings/device_oauth2_token_service.cc6
-rw-r--r--chrome/browser/chromeos/settings/device_oauth2_token_service_unittest.cc14
-rw-r--r--chrome/browser/chromeos/settings/device_settings_provider.cc3
-rw-r--r--chrome/browser/chromeos/settings/device_settings_test_helper.cc1
-rw-r--r--chrome/browser/chromeos/settings/session_manager_operation.cc10
-rw-r--r--chrome/browser/chromeos/settings/session_manager_operation_unittest.cc3
-rw-r--r--chrome/browser/chromeos/settings/token_encryptor.cc4
-rw-r--r--chrome/browser/chromeos/status/data_promo_notification.cc4
-rw-r--r--chrome/browser/chromeos/system/ash_system_tray_delegate.cc16
-rw-r--r--chrome/browser/chromeos/system/automatic_reboot_manager_unittest.cc5
-rw-r--r--chrome/browser/component_updater/ppapi_utils.cc1
-rw-r--r--chrome/browser/content_settings/tab_specific_content_settings.cc21
-rw-r--r--chrome/browser/crash_handler_host_linux.cc530
-rw-r--r--chrome/browser/crash_handler_host_linux.h171
-rw-r--r--chrome/browser/devtools/OWNERS2
-rw-r--r--chrome/browser/devtools/devtools_adb_bridge.cc35
-rw-r--r--chrome/browser/devtools/devtools_adb_bridge.h5
-rw-r--r--chrome/browser/devtools/devtools_file_helper.cc1
-rw-r--r--chrome/browser/devtools/devtools_sanity_browsertest.cc19
-rw-r--r--chrome/browser/devtools/devtools_window.cc5
-rw-r--r--chrome/browser/download/OWNERS3
-rw-r--r--chrome/browser/download/download_browsertest.cc1
-rw-r--r--chrome/browser/download/download_danger_prompt.cc105
-rw-r--r--chrome/browser/download/download_danger_prompt_browsertest.cc4
-rw-r--r--chrome/browser/download/download_dir_policy_handler.cc42
-rw-r--r--chrome/browser/download/download_dir_policy_handler.h30
-rw-r--r--chrome/browser/download/download_dir_policy_handler_unittest.cc35
-rw-r--r--chrome/browser/download/download_field_trial.cc71
-rw-r--r--chrome/browser/download/download_field_trial.h24
-rw-r--r--chrome/browser/download/download_field_trial_unittest.cc17
-rw-r--r--chrome/browser/download/download_item_model.cc45
-rw-r--r--chrome/browser/download/download_item_model.h4
-rw-r--r--chrome/browser/download/download_service.cc12
-rw-r--r--chrome/browser/download/download_service.h9
-rw-r--r--chrome/browser/download/download_shelf_context_menu.cc38
-rw-r--r--chrome/browser/download/download_shelf_context_menu.h2
-rw-r--r--chrome/browser/drive/drive_api_service.cc15
-rw-r--r--chrome/browser/drive/drive_api_util.cc16
-rw-r--r--chrome/browser/drive/drive_api_util.h4
-rw-r--r--chrome/browser/drive/drive_uploader.cc8
-rw-r--r--chrome/browser/drive/dummy_drive_service.cc10
-rw-r--r--chrome/browser/drive/fake_drive_service.cc5
-rw-r--r--chrome/browser/drive/fake_drive_service_unittest.cc4
-rw-r--r--chrome/browser/drive/gdata_wapi_service.cc5
-rw-r--r--chrome/browser/errorpage_browsertest.cc1
-rw-r--r--chrome/browser/extensions/active_tab_apitest.cc3
-rw-r--r--chrome/browser/extensions/activity_log/activity_log.cc16
-rw-r--r--chrome/browser/extensions/activity_log/activity_log_unittest.cc18
-rw-r--r--chrome/browser/extensions/api/api_resource.cc2
-rw-r--r--chrome/browser/extensions/api/api_resource.h4
-rw-r--r--chrome/browser/extensions/api/api_resource_manager.h4
-rw-r--r--chrome/browser/extensions/api/cast_channel/cast_channel_api.cc145
-rw-r--r--chrome/browser/extensions/api/cast_channel/cast_channel_api.h49
-rw-r--r--chrome/browser/extensions/api/cast_channel/cast_socket.cc193
-rw-r--r--chrome/browser/extensions/api/cast_channel/cast_socket.h72
-rw-r--r--chrome/browser/extensions/api/cast_channel/cast_socket_unittest.cc327
-rw-r--r--chrome/browser/extensions/api/commands/command_service.cc58
-rw-r--r--chrome/browser/extensions/api/commands/command_service.h23
-rw-r--r--chrome/browser/extensions/api/commands/command_service_browsertest.cc13
-rw-r--r--chrome/browser/extensions/api/commands/commands.cc6
-rw-r--r--chrome/browser/extensions/api/content_settings/content_settings_apitest.cc4
-rw-r--r--chrome/browser/extensions/api/declarative/declarative_rule.h41
-rw-r--r--chrome/browser/extensions/api/declarative/declarative_rule_unittest.cc61
-rw-r--r--chrome/browser/extensions/api/declarative/rules_registry_with_cache.cc3
-rw-r--r--chrome/browser/extensions/api/declarative_content/content_action.cc50
-rw-r--r--chrome/browser/extensions/api/declarative_content/content_action.h8
-rw-r--r--chrome/browser/extensions/api/declarative_content/content_action_unittest.cc41
-rw-r--r--chrome/browser/extensions/api/declarative_content/content_condition.cc1
-rw-r--r--chrome/browser/extensions/api/declarative_content/content_condition.h1
-rw-r--r--chrome/browser/extensions/api/declarative_content/content_condition_unittest.cc12
-rw-r--r--chrome/browser/extensions/api/declarative_content/content_rules_registry.cc8
-rw-r--r--chrome/browser/extensions/api/declarative_content/declarative_content_apitest.cc43
-rw-r--r--chrome/browser/extensions/api/declarative_webrequest/webrequest_action.cc1
-rw-r--r--chrome/browser/extensions/api/declarative_webrequest/webrequest_action.h1
-rw-r--r--chrome/browser/extensions/api/declarative_webrequest/webrequest_action_unittest.cc16
-rw-r--r--chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.cc1
-rw-r--r--chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.h1
-rw-r--r--chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_unittest.cc92
-rw-r--r--chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.cc2
-rw-r--r--chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc6
-rw-r--r--chrome/browser/extensions/api/developer_private/developer_private_api.cc11
-rw-r--r--chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc2
-rw-r--r--chrome/browser/extensions/api/enterprise_platform_keys_private/OWNERS3
-rw-r--r--chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.cc19
-rw-r--r--chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.h3
-rw-r--r--chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc41
-rw-r--r--chrome/browser/extensions/api/extension_action/browser_action_apitest.cc5
-rw-r--r--chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc193
-rw-r--r--chrome/browser/extensions/api/extension_action/extension_action_api.cc67
-rw-r--r--chrome/browser/extensions/api/extension_action/extension_action_api.h26
-rw-r--r--chrome/browser/extensions/api/extension_action/page_as_browser_action_apitest.cc8
-rw-r--r--chrome/browser/extensions/api/feedback_private/feedback_browsertest.cc92
-rw-r--r--chrome/browser/extensions/api/feedback_private/feedback_private_api.cc15
-rw-r--r--chrome/browser/extensions/api/feedback_private/feedback_private_api.h10
-rw-r--r--chrome/browser/extensions/api/file_handlers/app_file_handler_util.cc1
-rw-r--r--chrome/browser/extensions/api/identity/account_tracker.cc244
-rw-r--r--chrome/browser/extensions/api/identity/account_tracker.h140
-rw-r--r--chrome/browser/extensions/api/identity/account_tracker_unittest.cc504
-rw-r--r--chrome/browser/extensions/api/identity/identity_api.cc88
-rw-r--r--chrome/browser/extensions/api/identity/identity_api.h26
-rw-r--r--chrome/browser/extensions/api/identity/identity_event_router.cc73
-rw-r--r--chrome/browser/extensions/api/identity/identity_event_router.h35
-rw-r--r--chrome/browser/extensions/api/identity/identity_event_router_unittest.cc291
-rw-r--r--chrome/browser/extensions/api/identity/web_auth_flow.cc1
-rw-r--r--chrome/browser/extensions/api/identity/web_auth_flow.h1
-rw-r--r--chrome/browser/extensions/api/input_ime/input_ime_api.cc1
-rw-r--r--chrome/browser/extensions/api/management/management_apitest.cc2
-rw-r--r--chrome/browser/extensions/api/mdns/dns_sd_delegate.h1
-rw-r--r--chrome/browser/extensions/api/mdns/dns_sd_device_lister.cc82
-rw-r--r--chrome/browser/extensions/api/mdns/dns_sd_device_lister.h49
-rw-r--r--chrome/browser/extensions/api/mdns/dns_sd_registry.cc30
-rw-r--r--chrome/browser/extensions/api/mdns/dns_sd_registry.h3
-rw-r--r--chrome/browser/extensions/api/mdns/dns_sd_registry_unittest.cc37
-rw-r--r--chrome/browser/extensions/api/media_galleries/media_galleries_api.cc5
-rw-r--r--chrome/browser/extensions/api/media_galleries_private/media_galleries_private_api.cc3
-rw-r--r--chrome/browser/extensions/api/media_galleries_private/media_galleries_watch_apitest.cc2
-rw-r--r--chrome/browser/extensions/api/messaging/incognito_connectability.cc124
-rw-r--r--chrome/browser/extensions/api/messaging/incognito_connectability.h93
-rw-r--r--chrome/browser/extensions/api/messaging/message_service.cc49
-rw-r--r--chrome/browser/extensions/api/module/module.cc5
-rw-r--r--chrome/browser/extensions/api/music_manager_private/device_id_chromeos.cc4
-rw-r--r--chrome/browser/extensions/api/networking_private/networking_private_api.h54
-rw-r--r--chrome/browser/extensions/api/networking_private/networking_private_api_chromeos.cc104
-rw-r--r--chrome/browser/extensions/api/networking_private/networking_private_api_nonchromeos.cc46
-rw-r--r--chrome/browser/extensions/api/notifications/notifications_api.cc11
-rw-r--r--chrome/browser/extensions/api/permissions/permissions_api.cc6
-rw-r--r--chrome/browser/extensions/api/preference/preference_apitest.cc4
-rw-r--r--chrome/browser/extensions/api/preference/preference_helpers.cc7
-rw-r--r--chrome/browser/extensions/api/processes/processes_apitest.cc2
-rw-r--r--chrome/browser/extensions/api/socket/tcp_socket.cc73
-rw-r--r--chrome/browser/extensions/api/socket/tcp_socket.h45
-rw-r--r--chrome/browser/extensions/api/socket/udp_socket.cc28
-rw-r--r--chrome/browser/extensions/api/socket/udp_socket.h19
-rw-r--r--chrome/browser/extensions/api/sockets_tcp/tcp_socket_event_dispatcher.cc11
-rw-r--r--chrome/browser/extensions/api/sockets_tcp_server/sockets_tcp_server_api.cc298
-rw-r--r--chrome/browser/extensions/api/sockets_tcp_server/sockets_tcp_server_api.h179
-rw-r--r--chrome/browser/extensions/api/sockets_tcp_server/sockets_tcp_server_api_unittest.cc94
-rw-r--r--chrome/browser/extensions/api/sockets_tcp_server/sockets_tcp_server_apitest.cc111
-rw-r--r--chrome/browser/extensions/api/sockets_tcp_server/tcp_server_socket_event_dispatcher.cc198
-rw-r--r--chrome/browser/extensions/api/sockets_tcp_server/tcp_server_socket_event_dispatcher.h99
-rw-r--r--chrome/browser/extensions/api/system_display/display_info_provider_chromeos.cc5
-rw-r--r--chrome/browser/extensions/api/system_display/display_info_provider_chromeos_unittest.cc6
-rw-r--r--chrome/browser/extensions/api/system_indicator/system_indicator_apitest.cc2
-rw-r--r--chrome/browser/extensions/api/system_private/system_private_apitest.cc10
-rw-r--r--chrome/browser/extensions/api/system_storage/storage_info_provider.cc22
-rw-r--r--chrome/browser/extensions/api/system_storage/storage_info_provider.h6
-rw-r--r--chrome/browser/extensions/api/system_storage/system_storage_api.cc50
-rw-r--r--chrome/browser/extensions/api/system_storage/system_storage_api.h15
-rw-r--r--chrome/browser/extensions/api/system_storage/system_storage_apitest.cc46
-rw-r--r--chrome/browser/extensions/api/tab_capture/tab_capture_performancetest.cc12
-rw-r--r--chrome/browser/extensions/api/tabs/windows_event_router.cc6
-rw-r--r--chrome/browser/extensions/api/usb/usb_api.cc2
-rw-r--r--chrome/browser/extensions/api/web_navigation/web_navigation_api.cc2
-rw-r--r--chrome/browser/extensions/api/web_navigation/web_navigation_api.h2
-rw-r--r--chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc11
-rw-r--r--chrome/browser/extensions/api/web_request/web_request_apitest.cc2
-rw-r--r--chrome/browser/extensions/api/webstore_private/webstore_private_api.cc1
-rw-r--r--chrome/browser/extensions/app_background_page_apitest.cc10
-rw-r--r--chrome/browser/extensions/component_loader.cc18
-rw-r--r--chrome/browser/extensions/context_menu_matcher.cc3
-rw-r--r--chrome/browser/extensions/crx_installer.cc61
-rw-r--r--chrome/browser/extensions/crx_installer.h13
-rw-r--r--chrome/browser/extensions/crx_installer_browsertest.cc3
-rw-r--r--chrome/browser/extensions/error_console/error_console_browsertest.cc2
-rw-r--r--chrome/browser/extensions/event_router.cc7
-rw-r--r--chrome/browser/extensions/extension_browsertest.cc247
-rw-r--r--chrome/browser/extensions/extension_browsertest.h73
-rw-r--r--chrome/browser/extensions/extension_commands_global_registry_apitest.cc128
-rw-r--r--chrome/browser/extensions/extension_disabled_ui.cc5
-rw-r--r--chrome/browser/extensions/extension_function.cc46
-rw-r--r--chrome/browser/extensions/extension_function.h19
-rw-r--r--chrome/browser/extensions/extension_function_dispatcher.cc28
-rw-r--r--chrome/browser/extensions/extension_function_histogram_value.h13
-rw-r--r--chrome/browser/extensions/extension_functional_browsertest.cc45
-rw-r--r--chrome/browser/extensions/extension_host.cc2
-rw-r--r--chrome/browser/extensions/extension_install_prompt.cc7
-rw-r--r--chrome/browser/extensions/extension_install_ui_browsertest.cc5
-rw-r--r--chrome/browser/extensions/extension_keybinding_apitest_new.cc202
-rw-r--r--chrome/browser/extensions/extension_messages_apitest.cc61
-rw-r--r--chrome/browser/extensions/extension_nacl_browsertest.cc4
-rw-r--r--chrome/browser/extensions/extension_prefs.cc4
-rw-r--r--chrome/browser/extensions/extension_prefs.h9
-rw-r--r--chrome/browser/extensions/extension_process_manager.cc40
-rw-r--r--chrome/browser/extensions/extension_renderer_state.cc17
-rw-r--r--chrome/browser/extensions/extension_service.cc173
-rw-r--r--chrome/browser/extensions/extension_service.h33
-rw-r--r--chrome/browser/extensions/extension_service_unittest.cc103
-rw-r--r--chrome/browser/extensions/extension_service_unittest.h4
-rw-r--r--chrome/browser/extensions/extension_startup_browsertest.cc5
-rw-r--r--chrome/browser/extensions/extension_system.cc3
-rw-r--r--chrome/browser/extensions/extension_test_notification_observer.cc234
-rw-r--r--chrome/browser/extensions/extension_test_notification_observer.h100
-rw-r--r--chrome/browser/extensions/extension_toolbar_model.cc33
-rw-r--r--chrome/browser/extensions/extension_toolbar_model.h18
-rw-r--r--chrome/browser/extensions/extension_url_rewrite_browsertest.cc8
-rw-r--r--chrome/browser/extensions/extension_util.cc124
-rw-r--r--chrome/browser/extensions/extension_util.h49
-rw-r--r--chrome/browser/extensions/extension_web_contents_observer.cc137
-rw-r--r--chrome/browser/extensions/extension_web_contents_observer.h45
-rw-r--r--chrome/browser/extensions/extension_web_ui.cc3
-rw-r--r--chrome/browser/extensions/external_provider_impl.cc60
-rw-r--r--chrome/browser/extensions/external_provider_impl.h3
-rw-r--r--chrome/browser/extensions/global_shortcut_listener.cc124
-rw-r--r--chrome/browser/extensions/global_shortcut_listener.h130
-rw-r--r--chrome/browser/extensions/global_shortcut_listener_ozone.cc75
-rw-r--r--chrome/browser/extensions/global_shortcut_listener_ozone.h45
-rw-r--r--chrome/browser/extensions/global_shortcut_listener_win.cc228
-rw-r--r--chrome/browser/extensions/global_shortcut_listener_win.h118
-rw-r--r--chrome/browser/extensions/global_shortcut_listener_x11.cc2
-rw-r--r--chrome/browser/extensions/lazy_background_page_apitest.cc54
-rw-r--r--chrome/browser/extensions/message_handler.cc55
-rw-r--r--chrome/browser/extensions/message_handler.h43
-rw-r--r--chrome/browser/extensions/notifications_apitest.cc2
-rw-r--r--chrome/browser/extensions/page_action_browsertest.cc2
-rw-r--r--chrome/browser/extensions/policy_handlers.cc247
-rw-r--r--chrome/browser/extensions/policy_handlers.h93
-rw-r--r--chrome/browser/extensions/policy_handlers_unittest.cc283
-rw-r--r--chrome/browser/extensions/user_script_master.cc6
-rw-r--r--chrome/browser/extensions/webstore_installer.cc179
-rw-r--r--chrome/browser/extensions/webstore_installer.h51
-rw-r--r--chrome/browser/extensions/webstore_installer_unittest.cc3
-rw-r--r--chrome/browser/extensions/webstore_startup_installer_browsertest.cc19
-rw-r--r--chrome/browser/extensions/window_open_apitest.cc6
-rw-r--r--chrome/browser/favicon/favicon_service.cc53
-rw-r--r--chrome/browser/favicon/favicon_service.h17
-rw-r--r--chrome/browser/geolocation/geolocation_browsertest.cc3
-rw-r--r--chrome/browser/geolocation/geolocation_infobar_delegate.cc49
-rw-r--r--chrome/browser/geolocation/geolocation_infobar_delegate.h10
-rw-r--r--chrome/browser/geolocation/geolocation_infobar_delegate_android.cc30
-rw-r--r--chrome/browser/google_apis/auth_service.cc1
-rw-r--r--chrome/browser/google_apis/drive_api_requests_unittest.cc43
-rw-r--r--chrome/browser/google_apis/drive_entry_kinds.h1
-rw-r--r--chrome/browser/google_apis/gdata_wapi_parser.cc2
-rw-r--r--chrome/browser/google_apis/gdata_wapi_requests.cc16
-rw-r--r--chrome/browser/google_apis/gdata_wapi_requests_unittest.cc8
-rw-r--r--chrome/browser/google_apis/request_sender.h1
-rw-r--r--chrome/browser/google_apis/test_util.cc24
-rw-r--r--chrome/browser/google_apis/test_util.h8
-rw-r--r--chrome/browser/guestview/adview/adview_guest.cc2
-rw-r--r--chrome/browser/guestview/adview/adview_guest.h2
-rw-r--r--chrome/browser/guestview/webview/webview_guest.cc2
-rw-r--r--chrome/browser/guestview/webview/webview_guest.h2
-rw-r--r--chrome/browser/history/history_backend.cc94
-rw-r--r--chrome/browser/history/history_backend.h6
-rw-r--r--chrome/browser/history/history_backend_unittest.cc109
-rw-r--r--chrome/browser/history/history_service.cc28
-rw-r--r--chrome/browser/history/history_service.h18
-rw-r--r--chrome/browser/icon_loader_chromeos.cc2
-rw-r--r--chrome/browser/lifetime/application_lifetime.cc3
-rw-r--r--chrome/browser/lifetime/browser_close_manager.cc4
-rw-r--r--chrome/browser/lifetime/browser_close_manager_browsertest.cc82
-rw-r--r--chrome/browser/local_discovery/privet_device_lister_impl.cc163
-rw-r--r--chrome/browser/local_discovery/privet_device_lister_impl.h45
-rw-r--r--chrome/browser/local_discovery/privet_url_fetcher.cc9
-rw-r--r--chrome/browser/local_discovery/privet_url_fetcher.h1
-rw-r--r--chrome/browser/local_discovery/privet_url_fetcher_unittest.cc20
-rw-r--r--chrome/browser/local_discovery/service_discovery_device_lister.cc92
-rw-r--r--chrome/browser/local_discovery/service_discovery_device_lister.h63
-rw-r--r--chrome/browser/managed_mode/managed_mode_browsertest.cc3
-rw-r--r--chrome/browser/managed_mode/managed_mode_navigation_observer.cc1
-rw-r--r--chrome/browser/managed_mode/managed_mode_navigation_observer.h1
-rw-r--r--chrome/browser/managed_mode/managed_mode_resource_throttle_browsertest.cc9
-rw-r--r--chrome/browser/managed_mode/managed_user_service.cc28
-rw-r--r--chrome/browser/managed_mode/managed_user_service.h9
-rw-r--r--chrome/browser/managed_mode/managed_user_service_browsertest.cc38
-rw-r--r--chrome/browser/managed_mode/managed_user_service_unittest.cc54
-rw-r--r--chrome/browser/managed_mode/managed_user_sync_service.cc36
-rw-r--r--chrome/browser/managed_mode/managed_user_sync_service.h3
-rw-r--r--chrome/browser/managed_mode/managed_user_sync_service_unittest.cc33
-rw-r--r--chrome/browser/media/chrome_media_stream_infobar_browsertest.cc19
-rw-r--r--chrome/browser/media/chrome_webrtc_apprtc_browsertest.cc16
-rw-r--r--chrome/browser/media/chrome_webrtc_audio_quality_browsertest.cc5
-rw-r--r--chrome/browser/media/chrome_webrtc_typing_detection_browsertest.cc171
-rw-r--r--chrome/browser/media/encrypted_media_browsertest.cc227
-rw-r--r--chrome/browser/media/encrypted_media_istypesupported_browsertest.cc28
-rw-r--r--chrome/browser/media/webrtc_log_upload_list.cc22
-rw-r--r--chrome/browser/media/webrtc_log_upload_list.h12
-rw-r--r--chrome/browser/media/webrtc_log_uploader.cc24
-rw-r--r--chrome/browser/media/webrtc_log_uploader.h16
-rw-r--r--chrome/browser/media/webrtc_log_uploader_unittest.cc13
-rw-r--r--chrome/browser/media/webrtc_logging_handler_host.cc8
-rw-r--r--chrome/browser/media/webrtc_logging_handler_host.h6
-rw-r--r--chrome/browser/media_galleries/fileapi/iapps_finder_impl.cc2
-rw-r--r--chrome/browser/media_galleries/fileapi/iapps_finder_impl.h6
-rw-r--r--chrome/browser/media_galleries/fileapi/iapps_finder_impl_mac.mm25
-rw-r--r--chrome/browser/media_galleries/fileapi/iphoto_data_provider.cc25
-rw-r--r--chrome/browser/media_galleries/fileapi/iphoto_data_provider.h13
-rw-r--r--chrome/browser/media_galleries/fileapi/iphoto_file_util.cc1
-rw-r--r--chrome/browser/media_galleries/fileapi/itunes_data_provider.cc4
-rw-r--r--chrome/browser/media_galleries/fileapi/itunes_data_provider.h4
-rw-r--r--chrome/browser/media_galleries/fileapi/itunes_file_util.cc1
-rw-r--r--chrome/browser/media_galleries/fileapi/itunes_file_util_unittest.cc1
-rw-r--r--chrome/browser/media_galleries/fileapi/media_path_filter.cc1
-rw-r--r--chrome/browser/media_galleries/fileapi/picasa_data_provider_browsertest.cc8
-rw-r--r--chrome/browser/media_galleries/fileapi/picasa_file_util_unittest.cc2
-rw-r--r--chrome/browser/media_galleries/fileapi/safe_iapps_library_parser.cc176
-rw-r--r--chrome/browser/media_galleries/fileapi/safe_iapps_library_parser.h (renamed from chrome/browser/media_galleries/fileapi/safe_itunes_library_parser.h)70
-rw-r--r--chrome/browser/media_galleries/fileapi/safe_itunes_library_parser.cc117
-rw-r--r--chrome/browser/media_galleries/linux/mtp_device_object_enumerator.h15
-rw-r--r--chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac_unittest.mm11
-rw-r--r--chrome/browser/media_galleries/media_file_system_context.h5
-rw-r--r--chrome/browser/media_galleries/media_file_system_registry.cc77
-rw-r--r--chrome/browser/media_galleries/media_file_system_registry.h46
-rw-r--r--chrome/browser/media_galleries/media_file_system_registry_unittest.cc11
-rw-r--r--chrome/browser/media_galleries/media_galleries_dialog_controller.cc2
-rw-r--r--chrome/browser/media_galleries/media_galleries_test_util.cc41
-rw-r--r--chrome/browser/media_galleries/media_galleries_test_util.h7
-rw-r--r--chrome/browser/media_galleries/scoped_mtp_device_map_entry.cc18
-rw-r--r--chrome/browser/media_galleries/scoped_mtp_device_map_entry.h52
-rw-r--r--chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc20
-rw-r--r--chrome/browser/media_galleries/win/mtp_device_object_enumerator.h15
-rw-r--r--chrome/browser/metrics/metrics_log_serializer.cc33
-rw-r--r--chrome/browser/metrics/metrics_log_serializer.h23
-rw-r--r--chrome/browser/metrics/metrics_log_serializer_unittest.cc86
-rw-r--r--chrome/browser/metrics/metrics_log_unittest.cc9
-rw-r--r--chrome/browser/metrics/metrics_service.cc5
-rw-r--r--chrome/browser/metrics/perf_provider_chromeos.cc2
-rw-r--r--chrome/browser/metrics/thread_watcher_unittest.cc46
-rw-r--r--chrome/browser/metro_utils/metro_chrome_win.cc16
-rw-r--r--chrome/browser/metro_utils/metro_chrome_win.h12
-rw-r--r--chrome/browser/nacl_host/nacl_browser.cc16
-rw-r--r--chrome/browser/nacl_host/nacl_browser_delegate_impl.cc77
-rw-r--r--chrome/browser/nacl_host/nacl_browser_delegate_impl.h12
-rw-r--r--chrome/browser/nacl_host/nacl_file_host.cc59
-rw-r--r--chrome/browser/nacl_host/nacl_file_host.h2
-rw-r--r--chrome/browser/nacl_host/nacl_file_host_unittest.cc6
-rw-r--r--chrome/browser/nacl_host/nacl_host_message_filter.cc34
-rw-r--r--chrome/browser/nacl_host/nacl_host_message_filter.h3
-rw-r--r--chrome/browser/nacl_host/nacl_process_host.cc4
-rw-r--r--chrome/browser/nacl_host/nacl_process_host.h3
-rw-r--r--chrome/browser/net/OWNERS3
-rw-r--r--chrome/browser/net/net_error_tab_helper.cc2
-rw-r--r--chrome/browser/net/net_error_tab_helper.h2
-rw-r--r--chrome/browser/net/net_error_tab_helper_unittest.cc2
-rw-r--r--chrome/browser/net/predictor_tab_helper.cc17
-rw-r--r--chrome/browser/net/predictor_tab_helper.h3
-rw-r--r--chrome/browser/net/proxy_policy_handler.cc333
-rw-r--r--chrome/browser/net/proxy_policy_handler.h64
-rw-r--r--chrome/browser/net/proxy_policy_handler_unittest.cc271
-rw-r--r--chrome/browser/net/spdyproxy/OWNERS1
-rw-r--r--chrome/browser/net/spdyproxy/data_reduction_proxy_settings.cc464
-rw-r--r--chrome/browser/net/spdyproxy/data_reduction_proxy_settings.h207
-rw-r--r--chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.cc437
-rw-r--r--chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.h155
-rw-r--r--chrome/browser/net/spdyproxy/data_reduction_proxy_settings_ios.cc9
-rw-r--r--chrome/browser/net/spdyproxy/data_reduction_proxy_settings_ios.h22
-rw-r--r--chrome/browser/net/spdyproxy/data_reduction_proxy_settings_unittest.cc418
-rw-r--r--chrome/browser/net/spdyproxy/data_reduction_proxy_settings_unittest.h55
-rw-r--r--chrome/browser/net/spdyproxy/data_reduction_proxy_settings_unittest_android.cc325
-rw-r--r--chrome/browser/notifications/balloon_host.cc3
-rw-r--r--chrome/browser/notifications/desktop_notification_service.cc16
-rw-r--r--chrome/browser/notifications/desktop_notification_service.h9
-rw-r--r--chrome/browser/notifications/message_center_notification_manager.cc3
-rw-r--r--chrome/browser/notifications/message_center_settings_controller.cc4
-rw-r--r--chrome/browser/notifications/message_center_settings_controller_unittest.cc12
-rw-r--r--chrome/browser/notifications/message_center_stats_collector.cc7
-rw-r--r--chrome/browser/notifications/notification_browsertest.cc7
-rw-r--r--chrome/browser/notifications/sync_notifier/chrome_notifier_delegate.cc22
-rw-r--r--chrome/browser/notifications/sync_notifier/chrome_notifier_delegate.h16
-rw-r--r--chrome/browser/notifications/sync_notifier/chrome_notifier_service.cc43
-rw-r--r--chrome/browser/notifications/sync_notifier/chrome_notifier_service.h15
-rw-r--r--chrome/browser/notifications/welcome_notification.cc136
-rw-r--r--chrome/browser/notifications/welcome_notification.h63
-rw-r--r--chrome/browser/notifications/welcome_notification_unittest.cc235
-rw-r--r--chrome/browser/password_manager/password_generation_manager.cc103
-rw-r--r--chrome/browser/password_manager/password_generation_manager.h50
-rw-r--r--chrome/browser/password_manager/password_generation_manager_unittest.cc115
-rw-r--r--chrome/browser/password_manager/password_store.h6
-rw-r--r--chrome/browser/password_manager/password_syncable_service.cc161
-rw-r--r--chrome/browser/password_manager/password_syncable_service.h45
-rw-r--r--chrome/browser/plugins/chrome_plugin_service_filter.cc6
-rw-r--r--chrome/browser/plugins/chrome_plugin_service_filter.h3
-rw-r--r--chrome/browser/plugins/plugin_info_message_filter.cc4
-rw-r--r--chrome/browser/policy/DEPS13
-rw-r--r--chrome/browser/policy/browser_policy_connector.cc29
-rw-r--r--chrome/browser/policy/cloud/DEPS52
-rw-r--r--chrome/browser/policy/cloud/cloud_policy_constants.cc2
-rw-r--r--chrome/browser/policy/cloud/cloud_policy_core_unittest.cc14
-rw-r--r--chrome/browser/policy/cloud/cloud_policy_invalidator.cc2
-rw-r--r--chrome/browser/policy/cloud/cloud_policy_manager_browsertest.cc6
-rw-r--r--chrome/browser/policy/cloud/cloud_policy_refresh_scheduler.cc4
-rw-r--r--chrome/browser/policy/cloud/cloud_policy_refresh_scheduler.h2
-rw-r--r--chrome/browser/policy/cloud/cloud_policy_refresh_scheduler_unittest.cc1
-rw-r--r--chrome/browser/policy/cloud/cloud_policy_validator.cc12
-rw-r--r--chrome/browser/policy/cloud/cloud_policy_validator.h22
-rw-r--r--chrome/browser/policy/cloud/cloud_policy_validator_unittest.cc11
-rw-r--r--chrome/browser/policy/cloud/component_cloud_policy_service_unittest.cc8
-rw-r--r--chrome/browser/policy/cloud/component_cloud_policy_store.cc3
-rw-r--r--chrome/browser/policy/cloud/device_management_service_browsertest.cc4
-rw-r--r--chrome/browser/policy/cloud/mock_user_cloud_policy_store.cc4
-rw-r--r--chrome/browser/policy/cloud/test_request_interceptor.cc49
-rw-r--r--chrome/browser/policy/cloud/test_request_interceptor.h13
-rw-r--r--chrome/browser/policy/cloud/user_cloud_policy_invalidator_factory.cc2
-rw-r--r--chrome/browser/policy/cloud/user_cloud_policy_manager.cc5
-rw-r--r--chrome/browser/policy/cloud/user_cloud_policy_manager_factory.cc22
-rw-r--r--chrome/browser/policy/cloud/user_cloud_policy_manager_factory.h11
-rw-r--r--chrome/browser/policy/cloud/user_cloud_policy_store.cc50
-rw-r--r--chrome/browser/policy/cloud/user_cloud_policy_store.h13
-rw-r--r--chrome/browser/policy/cloud/user_cloud_policy_store_base.cc7
-rw-r--r--chrome/browser/policy/cloud/user_cloud_policy_store_base.h15
-rw-r--r--chrome/browser/policy/cloud/user_cloud_policy_store_unittest.cc29
-rw-r--r--chrome/browser/policy/cloud/user_policy_signin_service.cc5
-rw-r--r--chrome/browser/policy/cloud/user_policy_signin_service_android.cc2
-rw-r--r--chrome/browser/policy/cloud/user_policy_signin_service_base.cc9
-rw-r--r--chrome/browser/policy/cloud/user_policy_signin_service_factory.cc4
-rw-r--r--chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc2
-rw-r--r--chrome/browser/policy/configuration_policy_handler.cc851
-rw-r--r--chrome/browser/policy/configuration_policy_handler.h233
-rw-r--r--chrome/browser/policy/configuration_policy_handler_list.cc108
-rw-r--r--chrome/browser/policy/configuration_policy_handler_list.h5
-rw-r--r--chrome/browser/policy/configuration_policy_handler_list_unittest.cc54
-rw-r--r--chrome/browser/policy/configuration_policy_handler_unittest.cc205
-rw-r--r--chrome/browser/policy/configuration_policy_pref_store_unittest.cc619
-rw-r--r--chrome/browser/policy/configuration_policy_pref_store_unittest.h40
-rw-r--r--chrome/browser/policy/policy_browsertest.cc78
-rw-r--r--chrome/browser/policy/policy_statistics_collector.cc6
-rw-r--r--chrome/browser/policy/policy_statistics_collector_unittest.cc11
-rw-r--r--chrome/browser/policy/profile_policy_connector.cc4
-rw-r--r--chrome/browser/policy/profile_policy_connector.h7
-rw-r--r--chrome/browser/policy/profile_policy_connector_factory.cc11
-rw-r--r--chrome/browser/policy/profile_policy_connector_factory.h6
-rw-r--r--chrome/browser/policy/profile_policy_connector_stub.cc4
-rw-r--r--chrome/browser/policy/proto/chromeos/chrome_device_policy.proto4
-rw-r--r--chrome/browser/policy/url_blacklist_manager.cc4
-rw-r--r--chrome/browser/prefs/browser_prefs.cc1
-rw-r--r--chrome/browser/prefs/command_line_pref_store.cc2
-rw-r--r--chrome/browser/prefs/pref_metrics_service.cc2
-rw-r--r--chrome/browser/prefs/pref_model_associator.cc177
-rw-r--r--chrome/browser/prefs/pref_model_associator.h17
-rw-r--r--chrome/browser/prefs/session_startup_pref.cc65
-rw-r--r--chrome/browser/prerender/prerender_browsertest.cc122
-rw-r--r--chrome/browser/prerender/prerender_contents.cc28
-rw-r--r--chrome/browser/prerender/prerender_contents.h9
-rw-r--r--chrome/browser/prerender/prerender_field_trial.cc22
-rw-r--r--chrome/browser/prerender/prerender_field_trial.h6
-rw-r--r--chrome/browser/prerender/prerender_local_predictor.cc9
-rw-r--r--chrome/browser/prerender/prerender_local_predictor.h3
-rw-r--r--chrome/browser/prerender/prerender_manager.cc16
-rw-r--r--chrome/browser/prerender/prerender_manager.h15
-rw-r--r--chrome/browser/prerender/prerender_manager_factory.cc2
-rw-r--r--chrome/browser/prerender/prerender_render_view_host_observer.cc52
-rw-r--r--chrome/browser/prerender/prerender_render_view_host_observer.h46
-rw-r--r--chrome/browser/prerender/prerender_tab_helper.cc1
-rw-r--r--chrome/browser/prerender/prerender_tab_helper.h1
-rw-r--r--chrome/browser/prerender/prerender_util.cc157
-rw-r--r--chrome/browser/prerender/prerender_util.h9
-rw-r--r--chrome/browser/prerender/prerender_util_unittest.cc150
-rw-r--r--chrome/browser/printing/print_dialog_cloud_interative_uitest.cc284
-rw-r--r--chrome/browser/printing/print_job_worker.cc30
-rw-r--r--chrome/browser/printing/print_job_worker.h27
-rw-r--r--chrome/browser/printing/printer_query.cc21
-rw-r--r--chrome/browser/printing/printer_query.h24
-rw-r--r--chrome/browser/printing/printing_message_filter.cc7
-rw-r--r--chrome/browser/printing/printing_ui_web_contents_observer.cc20
-rw-r--r--chrome/browser/printing/printing_ui_web_contents_observer.h25
-rw-r--r--chrome/browser/profile_resetter/profile_resetter_unittest.cc2
-rw-r--r--chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc6
-rw-r--r--chrome/browser/profiles/profile_browsertest.cc1
-rw-r--r--chrome/browser/profiles/profile_impl.cc22
-rw-r--r--chrome/browser/profiles/profile_impl.h1
-rw-r--r--chrome/browser/profiles/profile_info_cache.cc18
-rw-r--r--chrome/browser/profiles/profile_info_cache.h2
-rw-r--r--chrome/browser/profiles/profile_info_cache_unittest.cc6
-rw-r--r--chrome/browser/profiles/profile_info_interface.h3
-rw-r--r--chrome/browser/profiles/profile_info_util.cc233
-rw-r--r--chrome/browser/profiles/profile_info_util.h2
-rw-r--r--chrome/browser/profiles/profile_info_util_unittest.cc54
-rw-r--r--chrome/browser/profiles/profile_manager.cc21
-rw-r--r--chrome/browser/profiles/profile_manager.h8
-rw-r--r--chrome/browser/profiles/profile_manager_unittest.cc79
-rw-r--r--chrome/browser/profiles/profiles_state.cc26
-rw-r--r--chrome/browser/profiles/profiles_state.h6
-rw-r--r--chrome/browser/renderer_host/chrome_render_view_host_observer.cc250
-rw-r--r--chrome/browser/renderer_host/chrome_render_view_host_observer.h61
-rw-r--r--chrome/browser/renderer_host/pepper/device_id_fetcher.cc4
-rw-r--r--chrome/browser/renderer_host/pepper/pepper_extensions_common_message_filter.cc28
-rw-r--r--chrome/browser/renderer_host/pepper/pepper_platform_verification_message_filter.cc25
-rw-r--r--chrome/browser/renderer_host/pepper/pepper_platform_verification_message_filter.h4
-rw-r--r--chrome/browser/resources/chromeos/about_sys.html3
-rw-r--r--chrome/browser/resources/chromeos/cryptohome.html2
-rw-r--r--chrome/browser/resources/chromeos/diagnostics/main.js67
-rw-r--r--chrome/browser/resources/chromeos/drive_internals.html2
-rw-r--r--chrome/browser/resources/chromeos/drive_internals.js2
-rw-r--r--chrome/browser/resources/chromeos/login/bubble.js2
-rw-r--r--chrome/browser/resources/chromeos/login/header_bar.js3
-rw-r--r--chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.css48
-rw-r--r--chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.html25
-rw-r--r--chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.js363
-rw-r--r--chrome/browser/resources/chromeos/login/user_pod_row.css3
-rw-r--r--chrome/browser/resources/chromeos/login/user_pod_row.js2
-rw-r--r--chrome/browser/resources/chromeos/login/user_pod_template.html6
-rw-r--r--chrome/browser/resources/chromeos/wallpaper_manager/js/util.js3
-rw-r--r--chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_manager.js7
-rw-r--r--chrome/browser/resources/downloads/downloads.css4
-rw-r--r--chrome/browser/resources/downloads/downloads.js110
-rw-r--r--chrome/browser/resources/extensions/extension_command_list.js34
-rw-r--r--chrome/browser/resources/extensions/extension_commands_overlay.css5
-rw-r--r--chrome/browser/resources/extensions/extension_commands_overlay.html1
-rw-r--r--chrome/browser/resources/feedback/js/feedback.js5
-rw-r--r--chrome/browser/resources/file_manager/css/file_manager.css11
-rw-r--r--chrome/browser/resources/file_manager/css/file_types.css14
-rw-r--r--chrome/browser/resources/file_manager/css/gallery.css12
-rw-r--r--chrome/browser/resources/file_manager/js/background.js1
-rw-r--r--chrome/browser/resources/file_manager/js/file_grid.js5
-rw-r--r--chrome/browser/resources/file_manager/js/file_manager.js149
-rw-r--r--chrome/browser/resources/file_manager/js/file_operation_manager.js89
-rw-r--r--chrome/browser/resources/file_manager/js/file_selection.js41
-rw-r--r--chrome/browser/resources/file_manager/js/file_tasks.js3
-rw-r--r--chrome/browser/resources/file_manager/js/file_transfer_controller.js1
-rw-r--r--chrome/browser/resources/file_manager/js/file_type.js2
-rw-r--r--chrome/browser/resources/file_manager/js/main_scripts.js1
-rw-r--r--chrome/browser/resources/file_manager/js/progress_center.js272
-rw-r--r--chrome/browser/resources/file_manager/js/progress_center_common.js11
-rw-r--r--chrome/browser/resources/file_manager/js/tree.css.js2
-rw-r--r--chrome/browser/resources/file_manager/js/ui/conflict_dialog.js135
-rw-r--r--chrome/browser/resources/file_manager/js/ui/file_manager_ui.js104
-rw-r--r--chrome/browser/resources/file_manager/js/ui/progress_center_panel.js14
-rw-r--r--chrome/browser/resources/file_manager/js/util.js4
-rw-r--r--chrome/browser/resources/file_manager/main.html3
-rw-r--r--chrome/browser/resources/file_manager/manifest.json15
-rw-r--r--chrome/browser/resources/gaia_auth/inline_injected.js5
-rw-r--r--chrome/browser/resources/gaia_auth/main.css6
-rw-r--r--chrome/browser/resources/gaia_auth/main.js16
-rw-r--r--chrome/browser/resources/gaia_auth_host/gaia_auth_host.js5
-rw-r--r--chrome/browser/resources/google_now/background.js100
-rw-r--r--chrome/browser/resources/google_now/background_test_util.js2
-rw-r--r--chrome/browser/resources/google_now/background_unittest.gtestjs56
-rw-r--r--chrome/browser/resources/google_now/manifest.json11
-rw-r--r--chrome/browser/resources/google_now/utility.js24
-rw-r--r--chrome/browser/resources/history/history.js28
-rw-r--r--chrome/browser/resources/inspect/OWNERS1
-rw-r--r--chrome/browser/resources/inspect/inspect.css5
-rw-r--r--chrome/browser/resources/inspect/inspect.js4
-rw-r--r--chrome/browser/resources/media/webrtc_logs.css5
-rw-r--r--chrome/browser/resources/media/webrtc_logs.html12
-rw-r--r--chrome/browser/resources/media/webrtc_logs.js9
-rw-r--r--chrome/browser/resources/net_internals/cros_log_analyzer_view.html2
-rw-r--r--chrome/browser/resources/net_internals/cros_log_visualizer_view.html2
-rw-r--r--chrome/browser/resources/options/browser_options.css9
-rw-r--r--chrome/browser/resources/options/browser_options.html40
-rw-r--r--chrome/browser/resources/options/browser_options.js4
-rw-r--r--chrome/browser/resources/options/chromeos/internet_detail.js40
-rw-r--r--chrome/browser/resources/options/options_page.js34
-rw-r--r--chrome/browser/resources/options/startup_overlay.html2
-rw-r--r--chrome/browser/resources/options/startup_overlay.js4
-rw-r--r--chrome/browser/resources/options/startup_section.html2
-rw-r--r--chrome/browser/resources/plugin_metadata/plugins_win.json38
-rw-r--r--chrome/browser/resources/print_preview/print_preview.css2
-rw-r--r--chrome/browser/resources/ssl/blocking.css29
-rw-r--r--chrome/browser/resources/ssl/blocking.html51
-rw-r--r--chrome/browser/resources/ssl/blocking.js25
-rw-r--r--chrome/browser/resources/ssl/images/1x/locked_page.pngbin0 -> 5389 bytes
-rw-r--r--chrome/browser/resources/ssl/images/2x/locked_page.pngbin0 -> 10760 bytes
-rw-r--r--chrome/browser/resources/ssl/roadblock.html91
-rw-r--r--chrome/browser/resources/ssl/roadblock.js41
-rw-r--r--chrome/browser/resources/ssl/ssl_errors_common.js44
-rw-r--r--chrome/browser/search/hotword_service.cc15
-rw-r--r--chrome/browser/search/hotword_service.h26
-rw-r--r--chrome/browser/search/hotword_service_factory.cc54
-rw-r--r--chrome/browser/search/hotword_service_factory.h40
-rw-r--r--chrome/browser/search/search.cc42
-rw-r--r--chrome/browser/search/search_unittest.cc22
-rw-r--r--chrome/browser/search_engines/OWNERS5
-rw-r--r--chrome/browser/search_engines/default_search_policy_handler.cc323
-rw-r--r--chrome/browser/search_engines/default_search_policy_handler.h79
-rw-r--r--chrome/browser/search_engines/default_search_policy_handler_unittest.cc294
-rw-r--r--chrome/browser/sessions/better_session_restore_browsertest.cc187
-rw-r--r--chrome/browser/sessions/session_data_deleter.cc169
-rw-r--r--chrome/browser/sessions/session_data_deleter.h15
-rw-r--r--chrome/browser/sessions/session_service.cc12
-rw-r--r--chrome/browser/sessions/session_service_factory.cc3
-rw-r--r--chrome/browser/sessions/tab_restore_browsertest.cc8
-rw-r--r--chrome/browser/signin/account_reconcilor.cc15
-rw-r--r--chrome/browser/signin/account_reconcilor.h30
-rw-r--r--chrome/browser/signin/account_reconcilor_factory.cc41
-rw-r--r--chrome/browser/signin/account_reconcilor_factory.h40
-rw-r--r--chrome/browser/signin/account_reconcilor_unittest.cc52
-rw-r--r--chrome/browser/signin/fake_profile_oauth2_token_service.cc11
-rw-r--r--chrome/browser/signin/fake_profile_oauth2_token_service.h5
-rw-r--r--chrome/browser/signin/signin_browsertest.cc1
-rw-r--r--chrome/browser/signin/signin_promo.cc11
-rw-r--r--chrome/browser/ssl/ssl_blocking_page.cc170
-rw-r--r--chrome/browser/ssl/ssl_browser_tests.cc1
-rw-r--r--chrome/browser/ssl/ssl_error_info.cc21
-rw-r--r--chrome/browser/ssl/ssl_error_info.h2
-rw-r--r--chrome/browser/storage_monitor/image_capture_device.mm20
-rw-r--r--chrome/browser/storage_monitor/storage_monitor_chromeos_unittest.cc3
-rw-r--r--chrome/browser/sync/profile_sync_service_android.cc1
-rw-r--r--chrome/browser/sync/profile_sync_service_preference_unittest.cc167
-rw-r--r--chrome/browser/sync/test/integration/single_client_managed_user_settings_sync_test.cc9
-rw-r--r--chrome/browser/sync/test/integration/sync_extension_helper.cc17
-rw-r--r--chrome/browser/sync_file_system/drive_backend/drive_backend_constants.cc6
-rw-r--r--chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h6
-rw-r--r--chrome/browser/sync_file_system/drive_backend/drive_backend_util.cc109
-rw-r--r--chrome/browser/sync_file_system/drive_backend/drive_backend_util.h44
-rw-r--r--chrome/browser/sync_file_system/drive_backend/metadata_database.cc94
-rw-r--r--chrome/browser/sync_file_system/drive_backend/metadata_database.h1
-rw-r--r--chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc10
-rw-r--r--chrome/browser/sync_file_system/drive_backend/register_app_task.cc2
-rw-r--r--chrome/browser/sync_file_system/drive_backend/register_app_task_unittest.cc319
-rw-r--r--chrome/browser/sync_file_system/drive_backend/sync_engine_initializer_unittest.cc20
-rw-r--r--chrome/browser/sync_file_system/drive_backend_v1/drive_file_sync_service_fake_unittest.cc2
-rw-r--r--chrome/browser/sync_file_system/drive_backend_v1/fake_drive_service_helper.cc84
-rw-r--r--chrome/browser/sync_file_system/drive_backend_v1/fake_drive_service_helper.h3
-rw-r--r--chrome/browser/sync_file_system/local/sync_file_system_backend.cc12
-rw-r--r--chrome/browser/sync_file_system/local/syncable_file_system_unittest.cc20
-rw-r--r--chrome/browser/sync_file_system/sync_file_system_test_util.cc35
-rw-r--r--chrome/browser/sync_file_system/sync_file_system_test_util.h22
-rw-r--r--chrome/browser/tab_contents/background_contents.cc3
-rw-r--r--chrome/browser/tab_contents/navigation_metrics_recorder.cc24
-rw-r--r--chrome/browser/tab_contents/navigation_metrics_recorder.h3
-rw-r--r--chrome/browser/task_manager/background_resource_provider.cc22
-rw-r--r--chrome/browser/task_manager/renderer_resource.cc10
-rw-r--r--chrome/browser/task_manager/renderer_resource.h8
-rw-r--r--chrome/browser/task_manager/task_manager_browsertest.cc14
-rw-r--r--chrome/browser/themes/theme_service.cc24
-rw-r--r--chrome/browser/themes/theme_service_unittest.cc50
-rw-r--r--chrome/browser/ui/android/infobars/infobar_android.cc7
-rw-r--r--chrome/browser/ui/android/infobars/infobar_android.h2
-rw-r--r--chrome/browser/ui/android/infobars/translate_infobar.cc2
-rw-r--r--chrome/browser/ui/android/tab_model/tab_model.h3
-rw-r--r--chrome/browser/ui/android/tab_model/tab_model_unittest.cc3
-rw-r--r--chrome/browser/ui/app_list/app_context_menu.cc4
-rw-r--r--chrome/browser/ui/app_list/app_list_controller_delegate.cc26
-rw-r--r--chrome/browser/ui/app_list/app_list_controller_delegate.h8
-rw-r--r--chrome/browser/ui/app_list/app_list_service_impl.cc2
-rw-r--r--chrome/browser/ui/app_list/app_list_service_mac.mm25
-rw-r--r--chrome/browser/ui/app_list/app_list_service_unittest.cc2
-rw-r--r--chrome/browser/ui/app_list/app_list_view_delegate.cc7
-rw-r--r--chrome/browser/ui/app_list/app_list_view_delegate.h3
-rw-r--r--chrome/browser/ui/app_list/extension_app_item.cc29
-rw-r--r--chrome/browser/ui/app_list/extension_app_item.h5
-rw-r--r--chrome/browser/ui/app_list/extension_app_model_builder.cc39
-rw-r--r--chrome/browser/ui/app_list/extension_app_model_builder.h13
-rw-r--r--chrome/browser/ui/app_list/search/app_search_provider.cc3
-rw-r--r--chrome/browser/ui/app_list/search/app_search_provider_unittest.cc1
-rw-r--r--chrome/browser/ui/app_list/search/common/dictionary_data_store.cc92
-rw-r--r--chrome/browser/ui/app_list/search/common/dictionary_data_store.h74
-rw-r--r--chrome/browser/ui/app_list/search/history_data_store.cc94
-rw-r--r--chrome/browser/ui/app_list/search/history_data_store.h21
-rw-r--r--chrome/browser/ui/app_list/search/history_data_store_unittest.cc2
-rw-r--r--chrome/browser/ui/app_list/search/people/people_result.cc29
-rw-r--r--chrome/browser/ui/app_list/search/people/people_result.h12
-rw-r--r--chrome/browser/ui/ash/app_list/app_list_controller_ash.cc5
-rw-r--r--chrome/browser/ui/ash/app_list/app_list_controller_ash.h1
-rw-r--r--chrome/browser/ui/ash/ash_keyboard_controller_proxy.cc2
-rw-r--r--chrome/browser/ui/ash/chrome_shell_delegate.cc19
-rw-r--r--chrome/browser/ui/ash/chrome_shell_delegate.h1
-rw-r--r--chrome/browser/ui/ash/chrome_shell_delegate_browsertest.cc16
-rw-r--r--chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc6
-rw-r--r--chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc6
-rw-r--r--chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc47
-rw-r--r--chrome/browser/ui/ash/multi_user_window_manager.cc13
-rw-r--r--chrome/browser/ui/ash/multi_user_window_manager.h3
-rw-r--r--chrome/browser/ui/ash/multi_user_window_manager_unittest.cc3
-rw-r--r--chrome/browser/ui/ash/session_state_delegate_chromeos.cc16
-rw-r--r--chrome/browser/ui/ash/session_state_delegate_chromeos.h4
-rw-r--r--chrome/browser/ui/ash/session_state_delegate_views.cc8
-rw-r--r--chrome/browser/ui/ash/session_state_delegate_views.h4
-rw-r--r--chrome/browser/ui/autofill/autofill_dialog_controller_browsertest.cc137
-rw-r--r--chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc140
-rw-r--r--chrome/browser/ui/autofill/autofill_dialog_controller_impl.h19
-rw-r--r--chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc233
-rw-r--r--chrome/browser/ui/autofill/autofill_dialog_types.h4
-rw-r--r--chrome/browser/ui/autofill/autofill_dialog_view_delegate.h9
-rw-r--r--chrome/browser/ui/autofill/autofill_popup_controller_impl.cc6
-rw-r--r--chrome/browser/ui/autofill/generated_credit_card_bubble_controller.h8
-rw-r--r--chrome/browser/ui/autofill/generated_credit_card_bubble_controller_unittest.cc34
-rw-r--r--chrome/browser/ui/autofill/mock_autofill_dialog_view_delegate.cc11
-rw-r--r--chrome/browser/ui/autofill/mock_autofill_dialog_view_delegate.h21
-rw-r--r--chrome/browser/ui/autofill/test_generated_credit_card_bubble_controller.cc50
-rw-r--r--chrome/browser/ui/autofill/test_generated_credit_card_bubble_controller.h51
-rw-r--r--chrome/browser/ui/browser.cc7
-rw-r--r--chrome/browser/ui/browser_close_browsertest.cc21
-rw-r--r--chrome/browser/ui/browser_command_controller.cc31
-rw-r--r--chrome/browser/ui/browser_dialogs.h8
-rw-r--r--chrome/browser/ui/browser_focus_uitest.cc13
-rw-r--r--chrome/browser/ui/browser_navigator.cc37
-rw-r--r--chrome/browser/ui/browser_tab_contents.cc2
-rw-r--r--chrome/browser/ui/browser_window.h4
-rw-r--r--chrome/browser/ui/chrome_pages.cc3
-rw-r--r--chrome/browser/ui/cocoa/apps/native_app_window_cocoa.h15
-rw-r--r--chrome/browser/ui/cocoa/apps/native_app_window_cocoa.mm42
-rw-r--r--chrome/browser/ui/cocoa/autofill/autofill_account_chooser.h1
-rw-r--r--chrome/browser/ui/cocoa/autofill/autofill_account_chooser.mm2
-rw-r--r--chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.h1
-rw-r--r--chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm72
-rw-r--r--chrome/browser/ui/cocoa/autofill/autofill_overlay_controller.mm7
-rw-r--r--chrome/browser/ui/cocoa/autofill/autofill_section_container.mm48
-rw-r--r--chrome/browser/ui/cocoa/autofill/autofill_sign_in_container.h7
-rw-r--r--chrome/browser/ui/cocoa/autofill/autofill_sign_in_container.mm33
-rw-r--r--chrome/browser/ui/cocoa/autofill/autofill_textfield.mm7
-rw-r--r--chrome/browser/ui/cocoa/browser/avatar_button_controller_unittest.mm38
-rw-r--r--chrome/browser/ui/cocoa/browser_window_cocoa.h3
-rw-r--r--chrome/browser/ui/cocoa/browser_window_cocoa.mm16
-rw-r--r--chrome/browser/ui/cocoa/download/download_item_controller.mm2
-rw-r--r--chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm38
-rw-r--r--chrome/browser/ui/cocoa/first_run_dialog.mm2
-rw-r--r--chrome/browser/ui/cocoa/infobars/infobar_cocoa.h6
-rw-r--r--chrome/browser/ui/cocoa/infobars/infobar_cocoa.mm7
-rw-r--r--chrome/browser/ui/cocoa/infobars/infobar_container_controller.mm9
-rw-r--r--chrome/browser/ui/cocoa/infobars/infobar_controller.h5
-rw-r--r--chrome/browser/ui/cocoa/infobars/infobar_controller.mm9
-rw-r--r--chrome/browser/ui/content_settings/content_setting_bubble_model.cc2
-rw-r--r--chrome/browser/ui/extensions/application_launch.cc214
-rw-r--r--chrome/browser/ui/extensions/application_launch.h11
-rw-r--r--chrome/browser/ui/gtk/apps/native_app_window_gtk.cc51
-rw-r--r--chrome/browser/ui/gtk/apps/native_app_window_gtk.h2
-rw-r--r--chrome/browser/ui/gtk/browser_actions_toolbar_gtk.cc61
-rw-r--r--chrome/browser/ui/gtk/browser_actions_toolbar_gtk.h4
-rw-r--r--chrome/browser/ui/gtk/browser_window_gtk.cc5
-rw-r--r--chrome/browser/ui/gtk/browser_window_gtk.h3
-rw-r--r--chrome/browser/ui/gtk/create_application_shortcuts_dialog_gtk.cc30
-rw-r--r--chrome/browser/ui/gtk/create_application_shortcuts_dialog_gtk.h17
-rw-r--r--chrome/browser/ui/gtk/download/download_item_gtk.cc23
-rw-r--r--chrome/browser/ui/gtk/first_run_dialog.cc4
-rw-r--r--chrome/browser/ui/gtk/global_menu_bar.cc1
-rw-r--r--chrome/browser/ui/panels/panel_host.cc3
-rw-r--r--chrome/browser/ui/prefs/prefs_tab_helper.cc154
-rw-r--r--chrome/browser/ui/prefs/prefs_tab_helper.h1
-rw-r--r--chrome/browser/ui/prefs/prefs_tab_helper_browsertest.cc142
-rw-r--r--chrome/browser/ui/search/instant_page.cc2
-rw-r--r--chrome/browser/ui/search/instant_page.h2
-rw-r--r--chrome/browser/ui/search/search_ipc_router.cc23
-rw-r--r--chrome/browser/ui/search/search_tab_helper.cc1
-rw-r--r--chrome/browser/ui/search/search_tab_helper.h1
-rw-r--r--chrome/browser/ui/startup/startup_browser_creator_browsertest.cc8
-rw-r--r--chrome/browser/ui/sync/one_click_signin_helper.cc2
-rw-r--r--chrome/browser/ui/tab_contents/core_tab_helper.cc100
-rw-r--r--chrome/browser/ui/tab_contents/core_tab_helper.h5
-rw-r--r--chrome/browser/ui/tabs/tab_strip_model.cc3
-rw-r--r--chrome/browser/ui/toolbar/wrench_menu_model.cc1
-rw-r--r--chrome/browser/ui/translate/language_combobox_model.cc33
-rw-r--r--chrome/browser/ui/translate/language_combobox_model.h37
-rw-r--r--chrome/browser/ui/translate/translate_bubble_model.h89
-rw-r--r--chrome/browser/ui/translate/translate_bubble_model_impl.cc82
-rw-r--r--chrome/browser/ui/translate/translate_bubble_model_impl.h48
-rw-r--r--chrome/browser/ui/translate/translate_bubble_view_state_transition.cc27
-rw-r--r--chrome/browser/ui/translate/translate_bubble_view_state_transition.h39
-rw-r--r--chrome/browser/ui/view_ids.h1
-rw-r--r--chrome/browser/ui/views/app_list/win/app_list_controller_delegate_win.cc28
-rw-r--r--chrome/browser/ui/views/app_list/win/app_list_controller_delegate_win.h4
-rw-r--r--chrome/browser/ui/views/app_list/win/app_list_service_win.cc21
-rw-r--r--chrome/browser/ui/views/apps/native_app_window_views.cc16
-rw-r--r--chrome/browser/ui/views/apps/native_app_window_views.h3
-rw-r--r--chrome/browser/ui/views/autofill/autofill_dialog_views.cc169
-rw-r--r--chrome/browser/ui/views/autofill/autofill_dialog_views.h36
-rw-r--r--chrome/browser/ui/views/autofill/autofill_dialog_views_unittest.cc186
-rw-r--r--chrome/browser/ui/views/autofill/decorated_textfield.cc44
-rw-r--r--chrome/browser/ui/views/autofill/decorated_textfield.h16
-rw-r--r--chrome/browser/ui/views/avatar_menu_bubble_view.h1
-rw-r--r--chrome/browser/ui/views/avatar_menu_button_browsertest.cc89
-rw-r--r--chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc4
-rw-r--r--chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc2
-rw-r--r--chrome/browser/ui/views/browser_actions_container.cc50
-rw-r--r--chrome/browser/ui/views/browser_actions_container.h11
-rw-r--r--chrome/browser/ui/views/browser_dialogs.h10
-rw-r--r--chrome/browser/ui/views/constrained_window_views.cc10
-rw-r--r--chrome/browser/ui/views/constrained_window_views_unittest.cc47
-rw-r--r--chrome/browser/ui/views/desktop_media_picker_views.cc20
-rw-r--r--chrome/browser/ui/views/download/download_item_view.cc4
-rw-r--r--chrome/browser/ui/views/download/download_started_animation_views.cc9
-rw-r--r--chrome/browser/ui/views/external_tab_container_win.cc1
-rw-r--r--chrome/browser/ui/views/external_tab_container_win.h1
-rw-r--r--chrome/browser/ui/views/frame/browser_frame.cc19
-rw-r--r--chrome/browser/ui/views/frame/browser_frame.h4
-rw-r--r--chrome/browser/ui/views/frame/browser_non_client_frame_view.cc48
-rw-r--r--chrome/browser/ui/views/frame/browser_non_client_frame_view.h18
-rw-r--r--chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc58
-rw-r--r--chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h11
-rw-r--r--chrome/browser/ui/views/frame/browser_view.cc27
-rw-r--r--chrome/browser/ui/views/frame/browser_view.h14
-rw-r--r--chrome/browser/ui/views/frame/browser_view_layout.cc3
-rw-r--r--chrome/browser/ui/views/frame/glass_browser_frame_view.cc75
-rw-r--r--chrome/browser/ui/views/frame/glass_browser_frame_view.h6
-rw-r--r--chrome/browser/ui/views/frame/global_menu_bar_x11.cc4
-rw-r--r--chrome/browser/ui/views/frame/immersive_mode_controller_ash_unittest.cc4
-rw-r--r--chrome/browser/ui/views/frame/opaque_browser_frame_view.cc25
-rw-r--r--chrome/browser/ui/views/frame/opaque_browser_frame_view.h2
-rw-r--r--chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc35
-rw-r--r--chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h3
-rw-r--r--chrome/browser/ui/views/frame/opaque_browser_frame_view_layout_delegate.h3
-rw-r--r--chrome/browser/ui/views/frame/opaque_browser_frame_view_layout_unittest.cc35
-rw-r--r--chrome/browser/ui/views/frame/system_menu_model_builder.cc46
-rw-r--r--chrome/browser/ui/views/frame/system_menu_model_builder.h3
-rw-r--r--chrome/browser/ui/views/importer/import_lock_dialog_view.cc4
-rw-r--r--chrome/browser/ui/views/login_prompt_views.cc2
-rw-r--r--chrome/browser/ui/views/message_center/message_center_frame_view.cc9
-rw-r--r--chrome/browser/ui/views/message_center/web_notification_tray.cc4
-rw-r--r--chrome/browser/ui/views/new_avatar_button.cc128
-rw-r--r--chrome/browser/ui/views/new_avatar_button.h44
-rw-r--r--chrome/browser/ui/views/new_avatar_menu_button_browsertest.cc123
-rw-r--r--chrome/browser/ui/views/notifications/balloon_view_views.cc3
-rw-r--r--chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc10
-rw-r--r--chrome/browser/ui/views/omnibox/omnibox_view_views.cc2
-rw-r--r--chrome/browser/ui/views/panels/panel_frame_view.cc1
-rw-r--r--chrome/browser/ui/views/panels/panel_view.cc2
-rw-r--r--chrome/browser/ui/views/profile_chooser_view.cc21
-rw-r--r--chrome/browser/ui/views/profile_chooser_view.h5
-rw-r--r--chrome/browser/ui/views/speech_recognition_bubble_views.cc2
-rw-r--r--chrome/browser/ui/views/stubs_aura.cc31
-rw-r--r--chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc2
-rw-r--r--chrome/browser/ui/views/tabs/dragged_tab_view.cc1
-rw-r--r--chrome/browser/ui/views/tabs/tab_drag_controller.cc22
-rw-r--r--chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc8
-rw-r--r--chrome/browser/ui/views/tabs/tab_strip.cc5
-rw-r--r--chrome/browser/ui/views/toolbar_view.cc11
-rw-r--r--chrome/browser/ui/views/translate/translate_bubble_view.cc753
-rw-r--r--chrome/browser/ui/views/translate/translate_bubble_view.h176
-rw-r--r--chrome/browser/ui/views/translate/translate_bubble_view_unittest.cc256
-rw-r--r--chrome/browser/ui/webui/chromeos/diagnostics/diagnostics_ui.cc32
-rw-r--r--chrome/browser/ui/webui/chromeos/drive_internals_ui.cc11
-rw-r--r--chrome/browser/ui/webui/chromeos/imageburner/imageburner_ui.cc1
-rw-r--r--chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc2
-rw-r--r--chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc20
-rw-r--r--chrome/browser/ui/webui/chromeos/login/locally_managed_user_creation_screen_handler.cc64
-rw-r--r--chrome/browser/ui/webui/chromeos/login/locally_managed_user_creation_screen_handler.h20
-rw-r--r--chrome/browser/ui/webui/chromeos/login/network_state_informer.cc15
-rw-r--r--chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc2
-rw-r--r--chrome/browser/ui/webui/chromeos/mobile_setup_ui.cc79
-rw-r--r--chrome/browser/ui/webui/chromeos/mobile_setup_ui.h19
-rw-r--r--chrome/browser/ui/webui/chromeos/network_ui.cc1
-rw-r--r--chrome/browser/ui/webui/chromeos/sim_unlock_ui.cc1
-rw-r--r--chrome/browser/ui/webui/devtools_ui.cc13
-rw-r--r--chrome/browser/ui/webui/downloads_dom_handler.cc16
-rw-r--r--chrome/browser/ui/webui/downloads_ui.cc1
-rw-r--r--chrome/browser/ui/webui/downloads_ui_browsertest.cc15
-rw-r--r--chrome/browser/ui/webui/downloads_ui_browsertest.h8
-rw-r--r--chrome/browser/ui/webui/downloads_ui_browsertest.js4
-rw-r--r--chrome/browser/ui/webui/extensions/command_handler.cc31
-rw-r--r--chrome/browser/ui/webui/extensions/command_handler.h4
-rw-r--r--chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc130
-rw-r--r--chrome/browser/ui/webui/extensions/extension_settings_browsertest.h46
-rw-r--r--chrome/browser/ui/webui/extensions/extension_settings_browsertest.js49
-rw-r--r--chrome/browser/ui/webui/extensions/extension_settings_handler.cc13
-rw-r--r--chrome/browser/ui/webui/inline_login_ui.cc104
-rw-r--r--chrome/browser/ui/webui/inspect_ui.cc16
-rw-r--r--chrome/browser/ui/webui/inspect_ui.h4
-rw-r--r--chrome/browser/ui/webui/local_discovery/local_discovery_ui_browsertest.cc3
-rw-r--r--chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.cc1
-rw-r--r--chrome/browser/ui/webui/media/webrtc_logs_ui.cc62
-rw-r--r--chrome/browser/ui/webui/media/webrtc_logs_ui.h3
-rw-r--r--chrome/browser/ui/webui/net_internals/net_internals_ui.cc9
-rw-r--r--chrome/browser/ui/webui/ntp/app_launcher_handler.cc12
-rw-r--r--chrome/browser/ui/webui/options/browser_options_handler.cc30
-rw-r--r--chrome/browser/ui/webui/options/browser_options_handler.h1
-rw-r--r--chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc65
-rw-r--r--chrome/browser/ui/webui/options/manage_profile_handler.cc10
-rw-r--r--chrome/browser/ui/webui/options/manage_profile_handler.h1
-rw-r--r--chrome/browser/ui/webui/options/options_ui.cc30
-rw-r--r--chrome/browser/ui/webui/options/options_ui.h18
-rw-r--r--chrome/browser/ui/webui/options/options_ui_browsertest.cc80
-rw-r--r--chrome/browser/ui/webui/print_preview/print_preview_handler.cc71
-rw-r--r--chrome/browser/ui/webui/print_preview/print_preview_handler.h16
-rw-r--r--chrome/browser/ui/webui/print_preview/print_preview_ui.cc2
-rw-r--r--chrome/browser/ui/window_sizer/window_sizer_ash_uitest.cc8
-rw-r--r--chrome/browser/unload_browsertest.cc22
-rw-r--r--chrome/browser/web_applications/web_app_mac.mm43
1091 files changed, 29901 insertions, 14393 deletions
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index ec224ae8ab..7730526eb3 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -397,6 +397,15 @@ const Experiment kExperiments[] = {
switches::kDisableAcceleratedOverflowScroll)
},
{
+ "force-universal-accelerated-composited-scrolling",
+ IDS_FLAGS_FORCE_UNIVERSAL_ACCELERATED_OVERFLOW_SCROLL_MODE_NAME,
+ IDS_FLAGS_FORCE_UNIVERSAL_ACCELERATED_OVERFLOW_SCROLL_MODE_DESCRIPTION,
+ kOsAll,
+ ENABLE_DISABLE_VALUE_TYPE(
+ switches::kEnableUniversalAcceleratedOverflowScroll,
+ switches::kDisableUniversalAcceleratedOverflowScroll)
+ },
+ {
"present-with-GDI",
IDS_FLAGS_PRESENT_WITH_GDI_NAME,
IDS_FLAGS_PRESENT_WITH_GDI_DESCRIPTION,
@@ -1499,7 +1508,9 @@ const Experiment kExperiments[] = {
IDS_FLAGS_ENABLE_GOOGLE_NOW_INTEGRATION_NAME,
IDS_FLAGS_ENABLE_GOOGLE_NOW_INTEGRATION_DESCRIPTION,
kOsWin | kOsCrOS | kOsMac,
- SINGLE_VALUE_TYPE(switches::kEnableGoogleNowIntegration)
+ ENABLE_DISABLE_VALUE_TYPE(
+ switches::kEnableGoogleNowIntegration,
+ switches::kDisableGoogleNowIntegration)
},
#endif
#if defined(OS_CHROMEOS)
@@ -1643,6 +1654,13 @@ const Experiment kExperiments[] = {
ENABLE_DISABLE_VALUE_TYPE(switches::kEnableStickyKeys,
switches::kDisableStickyKeys)
},
+ {
+ "ash-enable-autoclick",
+ IDS_FLAGS_ENABLE_AUTOCLICK_NAME,
+ IDS_FLAGS_ENABLE_AUTOCLICK_DESCRIPTION,
+ kOsCrOS,
+ SINGLE_VALUE_TYPE(ash::switches::kAshEnableAutoclick)
+ },
#endif
{
"enable-web-midi",
@@ -1659,6 +1677,13 @@ const Experiment kExperiments[] = {
SINGLE_VALUE_TYPE(switches::kNewProfileManagement)
},
{
+ "enable-inline-signin",
+ IDS_FLAGS_ENABLE_INLINE_SIGNIN_NAME,
+ IDS_FLAGS_ENABLE_INLINE_SIGNIN_DESCRIPTION,
+ kOsMac | kOsWin | kOsLinux,
+ SINGLE_VALUE_TYPE(switches::kEnableInlineSignin)
+ },
+ {
"enable-gaia-profile-info",
IDS_FLAGS_ENABLE_GAIA_PROFILE_INFO_NAME,
IDS_FLAGS_ENABLE_GAIA_PROFILE_INFO_DESCRIPTION,
@@ -1667,10 +1692,10 @@ const Experiment kExperiments[] = {
},
{
"disable-app-launcher",
- IDS_FLAGS_DISABLE_APP_LIST_NAME,
- IDS_FLAGS_DISABLE_APP_LIST_DESCRIPTION,
+ IDS_FLAGS_RESET_APP_LIST_INSTALL_STATE_NAME,
+ IDS_FLAGS_RESET_APP_LIST_INSTALL_STATE_DESCRIPTION,
kOsMac | kOsWin,
- SINGLE_VALUE_TYPE(switches::kDisableAppList)
+ SINGLE_VALUE_TYPE(switches::kResetAppListInstallState)
},
#if defined(ENABLE_APP_LIST)
{
@@ -1751,6 +1776,22 @@ const Experiment kExperiments[] = {
SINGLE_VALUE_TYPE(cc::switches::kDisableCompositorTouchHitTesting),
},
{
+ "enable-accelerated-scrollable-frames",
+ IDS_FLAGS_ENABLE_ACCELERATED_SCROLLABLE_FRAMES_NAME,
+ IDS_FLAGS_ENABLE_ACCELERATED_SCROLLABLE_FRAMES_DESCRIPTION,
+ kOsAll,
+ ENABLE_DISABLE_VALUE_TYPE(switches::kEnableAcceleratedScrollableFrames,
+ switches::kDisableAcceleratedScrollableFrames)
+ },
+ {
+ "enable-composited-scrolling-for-frames",
+ IDS_FLAGS_ENABLE_COMPOSITED_SCROLLING_FOR_FRAMES_NAME,
+ IDS_FLAGS_ENABLE_COMPOSITED_SCROLLING_FOR_FRAMES_DESCRIPTION,
+ kOsAll,
+ ENABLE_DISABLE_VALUE_TYPE(switches::kEnableCompositedScrollingForFrames,
+ switches::kDisableCompositedScrollingForFrames)
+ },
+ {
"enable-streamlined-hosted-apps",
IDS_FLAGS_ENABLE_STREAMLINED_HOSTED_APPS_NAME,
IDS_FLAGS_ENABLE_STREAMLINED_HOSTED_APPS_DESCRIPTION,
@@ -1758,6 +1799,13 @@ const Experiment kExperiments[] = {
SINGLE_VALUE_TYPE(switches::kEnableStreamlinedHostedApps)
},
{
+ "enable-ephemeral-apps",
+ IDS_FLAGS_ENABLE_EPHEMERAL_APPS_NAME,
+ IDS_FLAGS_ENABLE_EPHEMERAL_APPS_DESCRIPTION,
+ kOsWin | kOsCrOS,
+ SINGLE_VALUE_TYPE(switches::kEnableEphemeralApps)
+ },
+ {
"enable-service-worker",
IDS_FLAGS_ENABLE_SERVICE_WORKER_NAME,
IDS_FLAGS_ENABLE_SERVICE_WORKER_DESCRIPTION,
diff --git a/chrome/browser/android/crash_dump_manager.cc b/chrome/browser/android/crash_dump_manager.cc
deleted file mode 100644
index 5604f689af..0000000000
--- a/chrome/browser/android/crash_dump_manager.cc
+++ /dev/null
@@ -1,173 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/android/crash_dump_manager.h"
-
-#include "base/bind.h"
-#include "base/file_util.h"
-#include "base/format_macros.h"
-#include "base/logging.h"
-#include "base/path_service.h"
-#include "base/posix/global_descriptors.h"
-#include "base/process/process.h"
-#include "base/rand_util.h"
-#include "base/stl_util.h"
-#include "base/strings/stringprintf.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/common/descriptors_android.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/child_process_data.h"
-#include "content/public/browser/file_descriptor_info.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_types.h"
-#include "content/public/browser/render_process_host.h"
-
-using content::BrowserThread;
-
-// static
-CrashDumpManager* CrashDumpManager::instance_ = NULL;
-
-// static
-CrashDumpManager* CrashDumpManager::GetInstance() {
- return instance_;
-}
-
-CrashDumpManager::CrashDumpManager() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(!instance_);
-
- instance_ = this;
-
- notification_registrar_.Add(this,
- content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
- content::NotificationService::AllSources());
- notification_registrar_.Add(this,
- content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
- content::NotificationService::AllSources());
-
- BrowserChildProcessObserver::Add(this);
-}
-
-CrashDumpManager::~CrashDumpManager() {
- instance_ = NULL;
-
- BrowserChildProcessObserver::Remove(this);
-}
-
-int CrashDumpManager::CreateMinidumpFile(int child_process_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER));
- base::FilePath minidump_path;
- if (!file_util::CreateTemporaryFile(&minidump_path))
- return base::kInvalidPlatformFileValue;
-
- base::PlatformFileError error;
- // We need read permission as the minidump is generated in several phases
- // and needs to be read at some point.
- int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ |
- base::PLATFORM_FILE_WRITE;
- base::PlatformFile minidump_file =
- base::CreatePlatformFile(minidump_path, flags, NULL, &error);
- if (minidump_file == base::kInvalidPlatformFileValue) {
- LOG(ERROR) << "Failed to create temporary file, crash won't be reported.";
- return base::kInvalidPlatformFileValue;
- }
-
- {
- base::AutoLock auto_lock(child_process_id_to_minidump_path_lock_);
- DCHECK(!ContainsKey(child_process_id_to_minidump_path_, child_process_id));
- child_process_id_to_minidump_path_[child_process_id] = minidump_path;
- }
- return minidump_file;
-}
-
-void CrashDumpManager::ProcessMinidump(const base::FilePath& minidump_path,
- base::ProcessHandle pid) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- int64 file_size = 0;
- int r = file_util::GetFileSize(minidump_path, &file_size);
- DCHECK(r) << "Failed to retrieve size for minidump "
- << minidump_path.value();
-
- if (file_size == 0) {
- // Empty minidump, this process did not crash. Just remove the file.
- r = base::DeleteFile(minidump_path, false);
- DCHECK(r) << "Failed to delete temporary minidump file "
- << minidump_path.value();
- return;
- }
-
- // We are dealing with a valid minidump. Copy it to the crash report
- // directory from where Java code will upload it later on.
- base::FilePath crash_dump_dir;
- r = PathService::Get(chrome::DIR_CRASH_DUMPS, &crash_dump_dir);
- if (!r) {
- NOTREACHED() << "Failed to retrieve the crash dump directory.";
- return;
- }
-
- const uint64 rand = base::RandUint64();
- const std::string filename =
- base::StringPrintf("chromium-renderer-minidump-%016" PRIx64 ".dmp%d",
- rand, pid);
- base::FilePath dest_path = crash_dump_dir.Append(filename);
- r = base::Move(minidump_path, dest_path);
- if (!r) {
- LOG(ERROR) << "Failed to move crash dump from " << minidump_path.value()
- << " to " << dest_path.value();
- base::DeleteFile(minidump_path, false);
- return;
- }
- LOG(INFO) << "Crash minidump successfully generated: " <<
- crash_dump_dir.Append(filename).value();
-}
-
-void CrashDumpManager::BrowserChildProcessHostDisconnected(
- const content::ChildProcessData& data) {
- OnChildExit(data.id, data.handle);
-}
-
-void CrashDumpManager::BrowserChildProcessCrashed(
- const content::ChildProcessData& data) {
- OnChildExit(data.id, data.handle);
-}
-
-void CrashDumpManager::Observe(int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) {
- switch (type) {
- case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED:
- // NOTIFICATION_RENDERER_PROCESS_TERMINATED is sent when the renderer
- // process is cleanly shutdown. However, we need to fallthrough so that
- // we close the minidump_fd we kept open.
- case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
- content::RenderProcessHost* rph =
- content::Source<content::RenderProcessHost>(source).ptr();
- OnChildExit(rph->GetID(), rph->GetHandle());
- break;
- }
- default:
- NOTREACHED();
- return;
- }
-}
-
-void CrashDumpManager::OnChildExit(int child_process_id,
- base::ProcessHandle pid) {
- base::FilePath minidump_path;
- {
- base::AutoLock auto_lock(child_process_id_to_minidump_path_lock_);
- ChildProcessIDToMinidumpPath::iterator iter =
- child_process_id_to_minidump_path_.find(child_process_id);
- if (iter == child_process_id_to_minidump_path_.end()) {
- // We might get a NOTIFICATION_RENDERER_PROCESS_TERMINATED and a
- // NOTIFICATION_RENDERER_PROCESS_CLOSED.
- return;
- }
- minidump_path = iter->second;
- child_process_id_to_minidump_path_.erase(iter);
- }
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(&CrashDumpManager::ProcessMinidump, minidump_path, pid));
-}
diff --git a/chrome/browser/android/crash_dump_manager.h b/chrome/browser/android/crash_dump_manager.h
deleted file mode 100644
index 16c24a00bb..0000000000
--- a/chrome/browser/android/crash_dump_manager.h
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_ANDROID_CRASH_DUMP_MANAGER_H_
-#define CHROME_BROWSER_ANDROID_CRASH_DUMP_MANAGER_H_
-
-#include <map>
-
-#include "base/files/file_path.h"
-#include "base/platform_file.h"
-#include "base/process/process.h"
-#include "base/synchronization/lock.h"
-#include "content/public/browser/browser_child_process_observer.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-
-namespace content {
-class RenderProcessHost;
-}
-
-// This class manages the crash minidumps.
-// On Android, because of process isolation, each renderer process runs with a
-// different UID. As a result, we cannot generate the minidumps in the browser
-// (as the browser process does not have access to some system files for the
-// crashed process). So the minidump is generated in the renderer process.
-// Since the isolated process cannot open files, we provide it on creation with
-// a file descriptor where to write the minidump in the event of a crash.
-// This class creates these file descriptors and associates them with render
-// processes and take the appropriate action when the render process terminates.
-class CrashDumpManager : public content::BrowserChildProcessObserver,
- public content::NotificationObserver {
- public:
- // This object is a singleton created and owned by the
- // ChromeBrowserMainPartsAndroid.
- static CrashDumpManager* GetInstance();
-
- virtual ~CrashDumpManager();
-
- // Returns a file descriptor that should be used to generate a minidump for
- // the process |child_process_id|.
- int CreateMinidumpFile(int child_process_id);
-
- private:
- friend class ChromeBrowserMainPartsAndroid;
-
- // Should be created on the UI thread.
- CrashDumpManager();
-
- typedef std::map<int, base::FilePath> ChildProcessIDToMinidumpPath;
-
- static void ProcessMinidump(const base::FilePath& minidump_path,
- base::ProcessHandle pid);
-
- // content::BrowserChildProcessObserver implementation:
- virtual void BrowserChildProcessHostDisconnected(
- const content::ChildProcessData& data) OVERRIDE;
- virtual void BrowserChildProcessCrashed(
- const content::ChildProcessData& data) OVERRIDE;
-
- // NotificationObserver implementation:
- virtual void Observe(int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) OVERRIDE;
-
- // Called on child process exit (including crash).
- void OnChildExit(int child_process_id, base::ProcessHandle pid);
-
- content::NotificationRegistrar notification_registrar_;
-
- // This map should only be accessed with its lock aquired as it is accessed
- // from the PROCESS_LAUNCHER and UI threads.
- base::Lock child_process_id_to_minidump_path_lock_;
- ChildProcessIDToMinidumpPath child_process_id_to_minidump_path_;
-
- static CrashDumpManager* instance_;
-
- DISALLOW_COPY_AND_ASSIGN(CrashDumpManager);
-};
-
-#endif // CHROME_BROWSER_ANDROID_CRASH_DUMP_MANAGER_H_
diff --git a/chrome/browser/android/dev_tools_server.cc b/chrome/browser/android/dev_tools_server.cc
index 87014f8dc0..a716d0d82a 100644
--- a/chrome/browser/android/dev_tools_server.cc
+++ b/chrome/browser/android/dev_tools_server.cc
@@ -15,7 +15,9 @@
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
+#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/android/tab_android.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/devtools/devtools_adb_bridge.h"
#include "chrome/browser/history/top_sites.h"
@@ -30,7 +32,6 @@
#include "content/public/browser/devtools_target.h"
#include "content/public/browser/favicon_status.h"
#include "content/public/browser/navigation_entry.h"
-#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/common/content_switches.h"
@@ -44,7 +45,6 @@
#include "webkit/common/user_agent/user_agent_util.h"
using content::DevToolsAgentHost;
-using content::RenderViewHost;
using content::WebContents;
namespace {
@@ -56,9 +56,36 @@ const char kTetheringSocketName[] = "chrome_devtools_tethering_%d_%d";
const char kTargetTypePage[] = "page";
+bool FindTab(const std::string& str_id,
+ TabModel** model_result,
+ int* index_result) {
+ int id;
+ if (!base::StringToInt(str_id, &id))
+ return false;
+
+ for (TabModelList::const_iterator iter = TabModelList::begin();
+ iter != TabModelList::end(); ++iter) {
+ TabModel* model = *iter;
+ for (int i = 0; i < model->GetTabCount(); ++i) {
+ TabAndroid* tab = model->GetTabAt(i);
+ if (id == tab->GetAndroidId()) {
+ *model_result = model;
+ *index_result = i;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
class Target : public content::DevToolsTarget {
public:
- explicit Target(WebContents* web_contents);
+ // Constructor for a tab with a valid WebContents.
+ Target(int id, WebContents* web_contents);
+
+ // Constructor for a tab unloaded from memory.
+ Target(int id, const string16& title, const GURL& url);
virtual std::string GetId() const OVERRIDE { return id_; }
virtual std::string GetType() const OVERRIDE { return kTargetTypePage; }
@@ -69,17 +96,12 @@ class Target : public content::DevToolsTarget {
virtual base::TimeTicks GetLastActivityTime() const OVERRIDE {
return last_activity_time_;
}
- virtual bool IsAttached() const OVERRIDE {
- return agent_host_->IsAttached();
- }
- virtual scoped_refptr<DevToolsAgentHost> GetAgentHost() const OVERRIDE {
- return agent_host_;
- }
+ virtual bool IsAttached() const OVERRIDE;
+ virtual scoped_refptr<DevToolsAgentHost> GetAgentHost() const OVERRIDE;
virtual bool Activate() const OVERRIDE;
virtual bool Close() const OVERRIDE;
private:
- scoped_refptr<DevToolsAgentHost> agent_host_;
std::string id_;
std::string title_;
GURL url_;
@@ -87,10 +109,8 @@ class Target : public content::DevToolsTarget {
base::TimeTicks last_activity_time_;
};
-Target::Target(WebContents* web_contents) {
- agent_host_ =
- DevToolsAgentHost::GetOrCreateFor(web_contents->GetRenderViewHost());
- id_ = agent_host_->GetId();
+Target::Target(int id, WebContents* web_contents) {
+ id_ = base::IntToString(id);
title_ = UTF16ToUTF8(net::EscapeForHTML(web_contents->GetTitle()));
url_ = web_contents->GetURL();
content::NavigationController& controller = web_contents->GetController();
@@ -100,22 +120,56 @@ Target::Target(WebContents* web_contents) {
last_activity_time_ = web_contents->GetLastSelectedTime();
}
-bool Target::Activate() const {
- RenderViewHost* rvh = agent_host_->GetRenderViewHost();
- if (!rvh)
+Target::Target(int id, const string16& title, const GURL& url) {
+ id_ = base::IntToString(id);
+ title_ = UTF16ToUTF8(net::EscapeForHTML(title));
+ url_ = url;
+}
+
+bool Target::IsAttached() const {
+ TabModel* model;
+ int index;
+ if (!FindTab(id_, &model, &index))
return false;
- WebContents* web_contents = WebContents::FromRenderViewHost(rvh);
+ WebContents* web_contents = model->GetWebContentsAt(index);
if (!web_contents)
return false;
- web_contents->GetDelegate()->ActivateContents(web_contents);
+ return DevToolsAgentHost::IsDebuggerAttached(web_contents);
+}
+
+scoped_refptr<DevToolsAgentHost> Target::GetAgentHost() const {
+ TabModel* model;
+ int index;
+ if (!FindTab(id_, &model, &index))
+ return NULL;
+ WebContents* web_contents = model->GetWebContentsAt(index);
+ if (!web_contents) {
+ // The tab has been pushed out of memory, pull it back.
+ TabAndroid* tab = model->GetTabAt(index);
+ tab->RestoreIfNeeded();
+ web_contents = model->GetWebContentsAt(index);
+ if (!web_contents)
+ return NULL;
+ }
+ content::RenderViewHost* rvh = web_contents->GetRenderViewHost();
+ return rvh ? DevToolsAgentHost::GetOrCreateFor(rvh) : NULL;
+}
+
+bool Target::Activate() const {
+ TabModel* model;
+ int index;
+ if (!FindTab(id_, &model, &index))
+ return false;
+ model->SetActiveIndex(index);
return true;
}
bool Target::Close() const {
- RenderViewHost* rvh = agent_host_->GetRenderViewHost();
- if (!rvh)
+ TabModel* model;
+ int index;
+ if (!FindTab(id_, &model, &index))
return false;
- rvh->ClosePage();
+ model->CloseTabAt(index);
return true;
}
@@ -169,18 +223,32 @@ class DevToolsServerDelegate : public content::DevToolsHttpHandlerDelegate {
tab_model->CreateTabForTesting(GURL(content::kAboutBlankURL));
if (!web_contents)
return scoped_ptr<content::DevToolsTarget>();
- return scoped_ptr<content::DevToolsTarget>(new Target(web_contents));
+
+ for (int i = 0; i < tab_model->GetTabCount(); ++i) {
+ if (web_contents != tab_model->GetWebContentsAt(i))
+ continue;
+ TabAndroid* tab = tab_model->GetTabAt(i);
+ return scoped_ptr<content::DevToolsTarget>(
+ new Target(tab->GetAndroidId(), web_contents));
+ }
+
+ return scoped_ptr<content::DevToolsTarget>();
}
virtual void EnumerateTargets(TargetCallback callback) OVERRIDE {
TargetList targets;
- std::vector<RenderViewHost*> rvh_list =
- DevToolsAgentHost::GetValidRenderViewHosts();
- for (std::vector<RenderViewHost*>::iterator it = rvh_list.begin();
- it != rvh_list.end(); ++it) {
- WebContents* web_contents = WebContents::FromRenderViewHost(*it);
- if (web_contents)
- targets.push_back(new Target(web_contents));
+ for (TabModelList::const_iterator iter = TabModelList::begin();
+ iter != TabModelList::end(); ++iter) {
+ TabModel* model = *iter;
+ for (int i = 0; i < model->GetTabCount(); ++i) {
+ TabAndroid* tab = model->GetTabAt(i);
+ WebContents* web_contents = model->GetWebContentsAt(i);
+ targets.push_back(
+ web_contents ?
+ new Target(tab->GetAndroidId(), web_contents) :
+ new Target(
+ tab->GetAndroidId(), tab->GetTitle(), tab->GetURL()));
+ }
}
callback.Run(targets);
}
diff --git a/chrome/browser/android/tab_android.cc b/chrome/browser/android/tab_android.cc
index dcf9a93789..c63c105bfb 100644
--- a/chrome/browser/android/tab_android.cc
+++ b/chrome/browser/android/tab_android.cc
@@ -135,7 +135,6 @@ TabAndroid* TabAndroid::GetNativeTab(JNIEnv* env, jobject obj) {
TabAndroid::TabAndroid(JNIEnv* env, jobject obj)
: weak_java_tab_(env, obj),
session_tab_id_(),
- android_tab_id_(-1),
synced_tab_delegate_(new browser_sync::SyncedTabDelegateAndroid(this)) {
Java_TabBase_setNativePtr(env, obj, reinterpret_cast<jint>(this));
}
@@ -149,6 +148,40 @@ TabAndroid::~TabAndroid() {
Java_TabBase_clearNativePtr(env, obj.obj());
}
+int TabAndroid::GetAndroidId() const {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
+ if (obj.is_null())
+ return -1;
+ return Java_TabBase_getId(env, obj.obj());
+}
+
+string16 TabAndroid::GetTitle() const {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
+ if (obj.is_null())
+ return string16();
+ return base::android::ConvertJavaStringToUTF16(
+ Java_TabBase_getTitle(env, obj.obj()));
+}
+
+GURL TabAndroid::GetURL() const {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
+ if (obj.is_null())
+ return GURL::EmptyGURL();
+ return GURL(base::android::ConvertJavaStringToUTF8(
+ Java_TabBase_getUrl(env, obj.obj())));
+}
+
+bool TabAndroid::RestoreIfNeeded() {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj = weak_java_tab_.get(env);
+ if (obj.is_null())
+ return false;
+ return Java_TabBase_restoreIfNeeded(env, obj.obj());
+}
+
content::ContentViewCore* TabAndroid::GetContentViewCore() const {
if (!web_contents())
return NULL;
@@ -224,12 +257,9 @@ void TabAndroid::Observe(int type,
void TabAndroid::InitWebContents(JNIEnv* env,
jobject obj,
- jint tab_id,
jboolean incognito,
jobject jcontent_view_core,
jobject jweb_contents_delegate) {
- android_tab_id_ = tab_id;
-
content::ContentViewCore* content_view_core =
content::ContentViewCore::GetNativeContentViewCore(env,
jcontent_view_core);
diff --git a/chrome/browser/android/tab_android.h b/chrome/browser/android/tab_android.h
index e3a6c29ff3..31e326637c 100644
--- a/chrome/browser/android/tab_android.h
+++ b/chrome/browser/android/tab_android.h
@@ -56,7 +56,16 @@ class TabAndroid : public CoreTabHelperDelegate,
// Return specific id information regarding this TabAndroid.
const SessionID& session_id() const { return session_tab_id_; }
- int android_id() const { return android_tab_id_; }
+ int GetAndroidId() const;
+
+ // Return the tab title.
+ string16 GetTitle() const;
+
+ // Return the tab url.
+ GURL GetURL() const;
+
+ // Restore the tab if it was unloaded from memory.
+ bool RestoreIfNeeded();
// Helper methods to make it easier to access objects from the associated
// WebContents. Can return NULL.
@@ -123,10 +132,10 @@ class TabAndroid : public CoreTabHelperDelegate,
virtual void InitWebContents(JNIEnv* env,
jobject obj,
- jint tab_id,
jboolean incognito,
jobject jcontent_view_core,
jobject jweb_contents_delegate);
+
virtual void DestroyWebContents(JNIEnv* env,
jobject obj,
jboolean delete_native);
@@ -146,7 +155,6 @@ class TabAndroid : public CoreTabHelperDelegate,
JavaObjectWeakGlobalRef weak_java_tab_;
SessionID session_tab_id_;
- int android_tab_id_;
content::NotificationRegistrar notification_registrar_;
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm
index 34736e6251..3895ceb51d 100644
--- a/chrome/browser/app_controller_mac.mm
+++ b/chrome/browser/app_controller_mac.mm
@@ -760,8 +760,9 @@ class AppControllerProfileObserver : public ProfileInfoCacheObserver {
DownloadManager* download_manager =
(download_service->HasCreatedDownloadManager() ?
BrowserContext::GetDownloadManager(profiles[i]) : NULL);
- if (download_manager && download_manager->InProgressCount() > 0) {
- int downloadCount = download_manager->InProgressCount();
+ if (download_manager &&
+ download_manager->NonMaliciousInProgressCount() > 0) {
+ int downloadCount = download_manager->NonMaliciousInProgressCount();
if ([self userWillWaitForInProgressDownloads:downloadCount]) {
// Create a new browser window (if necessary) and navigate to the
// downloads page if the user chooses to wait.
diff --git a/chrome/browser/apps/app_browsertest.cc b/chrome/browser/apps/app_browsertest.cc
index e93de75ec4..b47ffd2868 100644
--- a/chrome/browser/apps/app_browsertest.cc
+++ b/chrome/browser/apps/app_browsertest.cc
@@ -51,8 +51,8 @@
#include "chrome/browser/chromeos/login/mock_user_manager.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/fake_dbus_thread_manager.h"
#include "chromeos/dbus/fake_power_manager_client.h"
-#include "chromeos/dbus/mock_dbus_thread_manager_without_gmock.h"
#endif
using apps::ShellWindow;
@@ -187,7 +187,9 @@ bool CopyTestDataAndSetCommandLineArg(
return true;
}
+#if !defined(OS_CHROMEOS)
const char kTestFilePath[] = "platform_apps/launch_files/test.txt";
+#endif
} // namespace
@@ -1219,7 +1221,8 @@ IN_PROC_BROWSER_TEST_F(PlatformAppIncognitoBrowserTest, IncognitoComponentApp) {
ASSERT_TRUE(registry != NULL);
registry->AddObserver(this);
- OpenApplication(AppLaunchParams(incognito_profile, file_manager, 0));
+ OpenApplication(AppLaunchParams(
+ incognito_profile, file_manager, 0, chrome::HOST_DESKTOP_TYPE_NATIVE));
while (!ContainsKey(opener_app_ids_, file_manager->id())) {
content::RunAllPendingInMessageLoop();
@@ -1237,8 +1240,8 @@ class RestartDeviceTest : public PlatformAppBrowserTest {
virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
PlatformAppBrowserTest::SetUpInProcessBrowserTestFixture();
- chromeos::MockDBusThreadManagerWithoutGMock* dbus_manager =
- new chromeos::MockDBusThreadManagerWithoutGMock;
+ chromeos::FakeDBusThreadManager* dbus_manager =
+ new chromeos::FakeDBusThreadManager;
chromeos::DBusThreadManager::InitializeForTesting(dbus_manager);
power_manager_client_ = dbus_manager->fake_power_manager_client();
}
diff --git a/chrome/browser/apps/app_browsertest_util.cc b/chrome/browser/apps/app_browsertest_util.cc
index 6b75b5ce41..24a161cd81 100644
--- a/chrome/browser/apps/app_browsertest_util.cc
+++ b/chrome/browser/apps/app_browsertest_util.cc
@@ -16,6 +16,7 @@
#include "chrome/browser/ui/extensions/application_launch.h"
#include "chrome/common/chrome_switches.h"
#include "content/public/browser/notification_service.h"
+#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_utils.h"
#include "extensions/common/switches.h"
@@ -40,6 +41,21 @@ void PlatformAppBrowserTest::SetUpCommandLine(CommandLine* command_line) {
command_line->AppendSwitchASCII(::switches::kEventPageSuspendingTime, "1");
}
+// static
+ShellWindow* PlatformAppBrowserTest::GetFirstShellWindowForBrowser(
+ Browser* browser) {
+ ShellWindowRegistry* app_registry =
+ ShellWindowRegistry::Get(browser->profile());
+ const ShellWindowRegistry::ShellWindowList& shell_windows =
+ app_registry->shell_windows();
+
+ ShellWindowRegistry::const_iterator iter = shell_windows.begin();
+ if (iter != shell_windows.end())
+ return *iter;
+
+ return NULL;
+}
+
const Extension* PlatformAppBrowserTest::LoadAndLaunchPlatformApp(
const char* name) {
content::WindowedNotificationObserver app_loaded_observer(
@@ -96,16 +112,7 @@ WebContents* PlatformAppBrowserTest::GetFirstShellWindowWebContents() {
}
ShellWindow* PlatformAppBrowserTest::GetFirstShellWindow() {
- ShellWindowRegistry* app_registry =
- ShellWindowRegistry::Get(browser()->profile());
- const ShellWindowRegistry::ShellWindowList& shell_windows =
- app_registry->shell_windows();
-
- ShellWindowRegistry::const_iterator iter = shell_windows.begin();
- if (iter != shell_windows.end())
- return *iter;
-
- return NULL;
+ return GetFirstShellWindowForBrowser(browser());
}
size_t PlatformAppBrowserTest::RunGetWindowsFunctionForExtension(
@@ -171,11 +178,10 @@ ShellWindow* PlatformAppBrowserTest::CreateShellWindowFromParams(
}
void PlatformAppBrowserTest::CloseShellWindow(ShellWindow* window) {
- content::WindowedNotificationObserver destroyed_observer(
- content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
- content::NotificationService::AllSources());
+ content::WebContentsDestroyedWatcher destroyed_watcher(
+ window->web_contents());
window->GetBaseWindow()->Close();
- destroyed_observer.Wait();
+ destroyed_watcher.Wait();
}
void PlatformAppBrowserTest::CallAdjustBoundsToBeVisibleOnScreenForShellWindow(
diff --git a/chrome/browser/apps/app_browsertest_util.h b/chrome/browser/apps/app_browsertest_util.h
index 2b9d958f92..72e314d4ad 100644
--- a/chrome/browser/apps/app_browsertest_util.h
+++ b/chrome/browser/apps/app_browsertest_util.h
@@ -14,6 +14,7 @@ namespace content {
class WebContents;
}
+class Browser;
class CommandLine;
namespace extensions {
@@ -25,6 +26,9 @@ class PlatformAppBrowserTest : public ExtensionApiTest {
virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE;
+ // Gets the first shell window that is found for a given browser.
+ static apps::ShellWindow* GetFirstShellWindowForBrowser(Browser* browser);
+
protected:
// Runs the app named |name| out of the platform_apps subdirectory. Waits
// until it is launched.
diff --git a/chrome/browser/apps/web_view_browsertest.cc b/chrome/browser/apps/web_view_browsertest.cc
index ae0db65808..09f23521ca 100644
--- a/chrome/browser/apps/web_view_browsertest.cc
+++ b/chrome/browser/apps/web_view_browsertest.cc
@@ -680,6 +680,13 @@ IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestChromeExtensionURL) {
"web_view/shim");
}
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestInvalidChromeExtensionURL) {
+ TestHelper("testInvalidChromeExtensionURL",
+ "DoneShimTest.PASSED",
+ "DoneShimTest.FAILED",
+ "web_view/shim");
+}
+
IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestEventName) {
TestHelper("testEventName",
"DoneShimTest.PASSED",
@@ -855,8 +862,17 @@ IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestWebRequestAPIGoogleProperty) {
"web_view/shim");
}
-IN_PROC_BROWSER_TEST_F(WebViewTest,
- Shim_TestWebRequestListenerSurvivesReparenting) {
+// This test is disabled due to being flaky. http://crbug.com/309451
+#if defined(OS_WIN)
+#define MAYBE_Shim_TestWebRequestListenerSurvivesReparenting \
+ DISABLED_Shim_TestWebRequestListenerSurvivesReparenting
+#else
+#define MAYBE_Shim_TestWebRequestListenerSurvivesReparenting \
+ Shim_TestWebRequestListenerSurvivesReparenting
+#endif
+IN_PROC_BROWSER_TEST_F(
+ WebViewTest,
+ MAYBE_Shim_TestWebRequestListenerSurvivesReparenting) {
TestHelper("testWebRequestListenerSurvivesReparenting",
"DoneShimTest.PASSED",
"DoneShimTest.FAILED",
@@ -958,9 +974,8 @@ IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestRemoveWebviewOnExit) {
ASSERT_TRUE(guest_loaded_listener.WaitUntilSatisfied());
- content::WindowedNotificationObserver observer(
- content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
- content::Source<content::WebContents>(source->GetWebContents()));
+ content::WebContentsDestroyedWatcher destroyed_watcher(
+ source->GetWebContents());
// Tell the embedder to kill the guest.
EXPECT_TRUE(content::ExecuteScript(
@@ -968,7 +983,7 @@ IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestRemoveWebviewOnExit) {
"removeWebviewOnExitDoCrash();"));
// Wait until the guest WebContents is destroyed.
- observer.Wait();
+ destroyed_watcher.Wait();
}
// Remove <webview> immediately after navigating it.
diff --git a/chrome/browser/apps/web_view_interactive_browsertest.cc b/chrome/browser/apps/web_view_interactive_browsertest.cc
index 1be9879148..e62c07ecab 100644
--- a/chrome/browser/apps/web_view_interactive_browsertest.cc
+++ b/chrome/browser/apps/web_view_interactive_browsertest.cc
@@ -370,8 +370,11 @@ class WebViewInteractiveTest
void DragTestStep1() {
// Move mouse to start of text.
MoveMouseInsideWindow(gfx::Point(45, 8));
+ MoveMouseInsideWindow(gfx::Point(45, 9));
SendMouseEvent(ui_controls::LEFT, ui_controls::DOWN);
- MoveMouseInsideWindow(gfx::Point(76, 12));
+
+ MoveMouseInsideWindow(gfx::Point(74, 12));
+ MoveMouseInsideWindow(gfx::Point(78, 12));
// Now wait a bit before moving mouse to initiate drag/drop.
base::MessageLoop::current()->PostDelayedTask(
@@ -400,18 +403,20 @@ class WebViewInteractiveTest
// This is because of the nature of drag and drop code (esp. the
// MessageLoop) in it.
- // Now verify we got a drop and correct drop data.
+ // Now check if we got a drop and read the drop data.
+ embedder_web_contents_ = GetFirstShellWindowWebContents();
ExtensionTestMessageListener drop_listener("guest-got-drop", false);
- EXPECT_TRUE(content::ExecuteScript(guest_web_contents_,
- "window.pingEmbedder()"));
+ EXPECT_TRUE(content::ExecuteScript(embedder_web_contents_,
+ "window.checkIfGuestGotDrop()"));
EXPECT_TRUE(drop_listener.WaitUntilSatisfied());
std::string last_drop_data;
EXPECT_TRUE(content::ExecuteScriptAndExtractString(
- embedder_web_contents_,
- "window.domAutomationController.send(getLastDropData())",
- &last_drop_data));
- EXPECT_EQ(last_drop_data, "Drop me");
+ embedder_web_contents_,
+ "window.domAutomationController.send(getLastDropData())",
+ &last_drop_data));
+
+ last_drop_data_ = last_drop_data;
}
protected:
@@ -422,6 +427,7 @@ class WebViewInteractiveTest
bool first_click_;
// Only used in drag/drop test.
base::Closure quit_closure_;
+ std::string last_drop_data_;
};
// ui_test_utils::SendMouseMoveSync doesn't seem to work on OS_MACOSX, and
@@ -678,24 +684,48 @@ IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, DISABLED_PopupPositioningMoved) {
// Drag and drop inside a webview is currently only enabled for linux and mac,
// but the tests don't work on anything except chromeos for now. This is because
// of simulating mouse drag code's dependency on platforms.
-//
-// Disabled because of flake on CrOS: http://crbug.com/161112
#if defined(OS_CHROMEOS)
+// This test is flaky. See crbug.com/309032
IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, DISABLED_DragDropWithinWebView) {
- SetupTest(
- "web_view/dnd_within_webview",
- "/extensions/platform_apps/web_view/dnd_within_webview/guest.html");
+ ExtensionTestMessageListener guest_connected_listener("connected", false);
+ LoadAndLaunchPlatformApp("web_view/dnd_within_webview");
+ ASSERT_TRUE(guest_connected_listener.WaitUntilSatisfied());
+
ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(GetPlatformAppWindow()));
+ gfx::Rect offset;
+ embedder_web_contents_ = GetFirstShellWindowWebContents();
+ embedder_web_contents_->GetView()->GetContainerBounds(&offset);
+ corner_ = gfx::Point(offset.x(), offset.y());
+
+ // In the drag drop test we add 20px padding to the page body because on
+ // windows if we get too close to the edge of the window the resize cursor
+ // appears and we start dragging the window edge.
+ corner_.Offset(20, 20);
+
// Flush any pending events to make sure we start with a clean slate.
content::RunAllPendingInMessageLoop();
- base::RunLoop run_loop;
- quit_closure_ = run_loop.QuitClosure();
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&WebViewInteractiveTest::DragTestStep1,
- base::Unretained(this)));
- run_loop.Run();
+ for (;;) {
+ base::RunLoop run_loop;
+ quit_closure_ = run_loop.QuitClosure();
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&WebViewInteractiveTest::DragTestStep1,
+ base::Unretained(this)));
+ run_loop.Run();
+
+ if (last_drop_data_ == "Drop me")
+ break;
+
+ LOG(INFO) << "Drag was cancelled in interactive_test, restarting drag";
+
+ // Reset state for next try.
+ ExtensionTestMessageListener reset_listener("resetStateReply", false);
+ EXPECT_TRUE(content::ExecuteScript(embedder_web_contents_,
+ "window.resetState()"));
+ ASSERT_TRUE(reset_listener.WaitUntilSatisfied());
+ }
+ ASSERT_EQ("Drop me", last_drop_data_);
}
#endif // (defined(OS_CHROMEOS))
diff --git a/chrome/browser/autocomplete/autocomplete_result.cc b/chrome/browser/autocomplete/autocomplete_result.cc
index 95bee29ba2..54ced3fa18 100644
--- a/chrome/browser/autocomplete/autocomplete_result.cc
+++ b/chrome/browser/autocomplete/autocomplete_result.cc
@@ -179,8 +179,18 @@ void AutocompleteResult::SortAndCull(const AutocompleteInput& input,
matches_.resize(num_matches);
default_match_ = matches_.begin();
- DCHECK((default_match_ == matches_.end()) ||
- default_match_->allowed_to_be_default_match);
+
+ if (default_match_ != matches_.end()) {
+ DCHECK(default_match_->allowed_to_be_default_match);
+ // We shouldn't get query matches for URL inputs, or non-query matches
+ // for query inputs.
+ if (AutocompleteMatch::IsSearchType(default_match_->type)) {
+ DCHECK_NE(AutocompleteInput::URL, input.type());
+ } else {
+ DCHECK_NE(AutocompleteInput::QUERY, input.type());
+ DCHECK_NE(AutocompleteInput::FORCED_QUERY, input.type());
+ }
+ }
// Set the alternate nav URL.
alternate_nav_url_ = (default_match_ == matches_.end()) ?
diff --git a/chrome/browser/autocomplete/extension_app_provider.cc b/chrome/browser/autocomplete/extension_app_provider.cc
index 468839d9d1..56f0fd095d 100644
--- a/chrome/browser/autocomplete/extension_app_provider.cc
+++ b/chrome/browser/autocomplete/extension_app_provider.cc
@@ -12,6 +12,7 @@
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system_factory.h"
+#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/history/history_service.h"
#include "chrome/browser/history/history_service_factory.h"
#include "chrome/browser/history/url_database.h"
@@ -161,7 +162,7 @@ void ExtensionAppProvider::RefreshAppList() {
// provider is currently only used in the app launcher.
if (profile_->IsOffTheRecord() &&
- !extension_service->CanLoadInIncognito(app))
+ !extension_util::CanLoadInIncognito(app, extension_service))
continue;
GURL launch_url = app->is_platform_app() ?
diff --git a/chrome/browser/autocomplete/history_provider_util.cc b/chrome/browser/autocomplete/history_provider_util.cc
index b7c8d458cb..371d7b948c 100644
--- a/chrome/browser/autocomplete/history_provider_util.cc
+++ b/chrome/browser/autocomplete/history_provider_util.cc
@@ -12,7 +12,8 @@ HistoryMatch::HistoryMatch()
: url_info(),
input_location(string16::npos),
match_in_scheme(false),
- innermost_match(true) {
+ innermost_match(true),
+ promoted(false) {
}
HistoryMatch::HistoryMatch(const URLRow& url_info,
@@ -22,7 +23,8 @@ HistoryMatch::HistoryMatch(const URLRow& url_info,
: url_info(url_info),
input_location(input_location),
match_in_scheme(match_in_scheme),
- innermost_match(innermost_match) {
+ innermost_match(innermost_match),
+ promoted(false) {
}
bool HistoryMatch::EqualsGURL(const HistoryMatch& h, const GURL& url) {
diff --git a/chrome/browser/autocomplete/history_provider_util.h b/chrome/browser/autocomplete/history_provider_util.h
index 866a477bc8..d6b04da534 100644
--- a/chrome/browser/autocomplete/history_provider_util.h
+++ b/chrome/browser/autocomplete/history_provider_util.h
@@ -50,6 +50,10 @@ struct HistoryMatch {
// "x", no scheme in our prefix list (or "www.") begins with x, so all
// matches are, vacuously, "innermost matches".
bool innermost_match;
+
+ // When sorting, all promoted matches should appear before all non-promoted
+ // matches, regardless of other properties of the match.
+ bool promoted;
};
typedef std::deque<HistoryMatch> HistoryMatches;
diff --git a/chrome/browser/autocomplete/history_url_provider.cc b/chrome/browser/autocomplete/history_url_provider.cc
index a29f827111..05e00176d9 100644
--- a/chrome/browser/autocomplete/history_url_provider.cc
+++ b/chrome/browser/autocomplete/history_url_provider.cc
@@ -48,7 +48,9 @@ namespace {
//
// It's OK to call this function with both |create_if_necessary| and
// |promote| false, in which case we'll do nothing.
-void CreateOrPromoteMatch(const history::URLRow& info,
+//
+// Returns whether the match exists regardless if it was promoted/created.
+bool CreateOrPromoteMatch(const history::URLRow& info,
size_t input_location,
bool match_in_scheme,
history::HistoryMatches* matches,
@@ -61,12 +63,12 @@ void CreateOrPromoteMatch(const history::URLRow& info,
// Rotate it to the front if the caller wishes.
if (promote)
std::rotate(matches->begin(), i, i + 1);
- return;
+ return true;
}
}
if (!create_if_necessary)
- return;
+ return false;
// No entry, so create one.
history::HistoryMatch match(info, input_location, match_in_scheme, true);
@@ -74,6 +76,8 @@ void CreateOrPromoteMatch(const history::URLRow& info,
matches->push_front(match);
else
matches->push_back(match);
+
+ return true;
}
// Given the user's |input| and a |match| created from it, reduce the match's
@@ -105,6 +109,10 @@ GURL ConvertToHostOnly(const history::HistoryMatch& match,
// Acts like the > operator for URLInfo classes.
bool CompareHistoryMatch(const history::HistoryMatch& a,
const history::HistoryMatch& b) {
+ // A promoted match is better than non-promoted.
+ if (a.promoted != b.promoted)
+ return a.promoted;
+
// A URL that has been typed at all is better than one that has never been
// typed. (Note "!"s on each side)
if (!a.url_info.typed_count() != !b.url_info.typed_count())
@@ -132,6 +140,41 @@ bool CompareHistoryMatch(const history::HistoryMatch& a,
return a.url_info.last_visit() > b.url_info.last_visit();
}
+// Sorts and dedups the given list of matches.
+void SortAndDedupMatches(history::HistoryMatches* matches) {
+ // Sort by quality, best first.
+ std::sort(matches->begin(), matches->end(), &CompareHistoryMatch);
+
+ // Remove duplicate matches (caused by the search string appearing in one of
+ // the prefixes as well as after it). Consider the following scenario:
+ //
+ // User has visited "http://http.com" once and "http://htaccess.com" twice.
+ // User types "http". The autocomplete search with prefix "http://" returns
+ // the first host, while the search with prefix "" returns both hosts. Now
+ // we sort them into rank order:
+ // http://http.com (innermost_match)
+ // http://htaccess.com (!innermost_match, url_info.visit_count == 2)
+ // http://http.com (!innermost_match, url_info.visit_count == 1)
+ //
+ // The above scenario tells us we can't use std::unique(), since our
+ // duplicates are not always sequential. It also tells us we should remove
+ // the lower-quality duplicate(s), since otherwise the returned results won't
+ // be ordered correctly. This is easy to do: we just always remove the later
+ // element of a duplicate pair.
+ // Be careful! Because the vector contents may change as we remove elements,
+ // we use an index instead of an iterator in the outer loop, and don't
+ // precalculate the ending position.
+ for (size_t i = 0; i < matches->size(); ++i) {
+ for (history::HistoryMatches::iterator j(matches->begin() + i + 1);
+ j != matches->end(); ) {
+ if ((*matches)[i].url_info.url() == j->url_info.url())
+ j = matches->erase(j);
+ else
+ ++j;
+ }
+ }
+}
+
// Extracts typed_count, visit_count, and last_visited time from the
// URLRow and puts them in the additional info field of the |match|
// for display in about:omnibox.
@@ -490,8 +533,8 @@ void HistoryURLProvider::DoAutocomplete(history::HistoryBackend* backend,
}
// Create sorted list of suggestions.
- CullPoorMatches(&history_matches, params);
- SortMatches(&history_matches);
+ CullPoorMatches(*params, &history_matches);
+ SortAndDedupMatches(&history_matches);
PromoteOrCreateShorterSuggestion(db, *params, have_what_you_typed_match,
what_you_typed_match, &history_matches);
@@ -512,7 +555,7 @@ void HistoryURLProvider::DoAutocomplete(history::HistoryBackend* backend,
params->matches.push_back(what_you_typed_match);
} else if (params->prevent_inline_autocomplete ||
history_matches.empty() ||
- !PromoteMatchForInlineAutocomplete(params, history_matches.front())) {
+ !PromoteMatchForInlineAutocomplete(history_matches.front(), params)) {
// Failed to promote any URLs for inline autocompletion. Use the What You
// Typed match, if we have it.
first_match = 0;
@@ -555,7 +598,7 @@ void HistoryURLProvider::DoAutocomplete(history::HistoryBackend* backend,
// less than the previous match.
relevance = (relevance > 0) ? (relevance - 1) :
CalculateRelevance(NORMAL, history_matches.size() - 1 - i);
- AutocompleteMatch ac_match = HistoryMatchToACMatch(params, match,
+ AutocompleteMatch ac_match = HistoryMatchToACMatch(*params, match,
NORMAL, relevance);
params->matches.push_back(ac_match);
}
@@ -809,17 +852,19 @@ bool HistoryURLProvider::CanFindIntranetURL(
}
bool HistoryURLProvider::PromoteMatchForInlineAutocomplete(
- HistoryURLProviderParams* params,
- const history::HistoryMatch& match) {
- // Promote the first match if it's been typed at least n times, where n == 1
- // for "simple" (host-only) URLs and n == 2 for others. We set a higher bar
- // for these long URLs because it's less likely that users will want to visit
- // them again. Even though we don't increment the typed_count for pasted-in
- // URLs, if the user manually edits the URL or types some long thing in by
- // hand, we wouldn't want to immediately start autocompleting it.
- if (!match.url_info.typed_count() ||
- ((match.url_info.typed_count() == 1) &&
- !match.IsHostOnly()))
+ const history::HistoryMatch& match,
+ HistoryURLProviderParams* params) {
+ // Promote the first match if it's been marked for promotion or typed at least
+ // n times, where n == 1 for "simple" (host-only) URLs and n == 2 for others.
+ // We set a higher bar for these long URLs because it's less likely that users
+ // will want to visit them again. Even though we don't increment the
+ // typed_count for pasted-in URLs, if the user manually edits the URL or types
+ // some long thing in by hand, we wouldn't want to immediately start
+ // autocompleting it.
+ if (!match.promoted &&
+ (!match.url_info.typed_count() ||
+ ((match.url_info.typed_count() == 1) &&
+ !match.IsHostOnly())))
return false;
// In the case where the user has typed "foo.com" and visited (but not typed)
@@ -830,7 +875,7 @@ bool HistoryURLProvider::PromoteMatchForInlineAutocomplete(
// future pass from suggesting the exact input as a better match.
if (params) {
params->dont_suggest_exact_input = true;
- params->matches.push_back(HistoryMatchToACMatch(params, match,
+ params->matches.push_back(HistoryMatchToACMatch(*params, match,
INLINE_AUTOCOMPLETE, CalculateRelevance(INLINE_AUTOCOMPLETE, 0)));
}
return true;
@@ -907,69 +952,23 @@ void HistoryURLProvider::PromoteOrCreateShorterSuggestion(
// Promote or add the desired URL to the list of matches.
bool ensure_can_inline =
- promote && PromoteMatchForInlineAutocomplete(NULL, match);
- CreateOrPromoteMatch(info, match.input_location, match.match_in_scheme,
- matches, create_shorter_match_, promote);
- if (ensure_can_inline) {
- // If |match| was inline-autocompletable and we're promoting something to
- // replace it, make sure the promoted item is also inline-autocompletable.
- // Setting the typed_count to 2 is sufficient to guarantee this (and is safe
- // because by this point all sorting has already happened and the only thing
- // checking the typed_count will be PromoteMatchForInlineAutocomplete()).
- //
- // We have to do this here rather than changing |info| before calling
- // EnsureMatchPresent() because if EnsureMatchPresent() merely moves an
- // existing match to the front, it will ignore the typed_count in |info|.
- // But we set |ensure_can_inline| above because |match| is a reference and
- // thus checking it here would examine the wrong match.
- matches->front().url_info.set_typed_count(2);
- }
-}
-
-void HistoryURLProvider::SortMatches(history::HistoryMatches* matches) const {
- // Sort by quality, best first.
- std::sort(matches->begin(), matches->end(), &CompareHistoryMatch);
-
- // Remove duplicate matches (caused by the search string appearing in one of
- // the prefixes as well as after it). Consider the following scenario:
- //
- // User has visited "http://http.com" once and "http://htaccess.com" twice.
- // User types "http". The autocomplete search with prefix "http://" returns
- // the first host, while the search with prefix "" returns both hosts. Now
- // we sort them into rank order:
- // http://http.com (innermost_match)
- // http://htaccess.com (!innermost_match, url_info.visit_count == 2)
- // http://http.com (!innermost_match, url_info.visit_count == 1)
- //
- // The above scenario tells us we can't use std::unique(), since our
- // duplicates are not always sequential. It also tells us we should remove
- // the lower-quality duplicate(s), since otherwise the returned results won't
- // be ordered correctly. This is easy to do: we just always remove the later
- // element of a duplicate pair.
- // Be careful! Because the vector contents may change as we remove elements,
- // we use an index instead of an iterator in the outer loop, and don't
- // precalculate the ending position.
- for (size_t i = 0; i < matches->size(); ++i) {
- for (history::HistoryMatches::iterator j(matches->begin() + i + 1);
- j != matches->end(); ) {
- if ((*matches)[i].url_info.url() == j->url_info.url())
- j = matches->erase(j);
- else
- ++j;
- }
- }
+ promote && PromoteMatchForInlineAutocomplete(match, NULL);
+ ensure_can_inline &= CreateOrPromoteMatch(info, match.input_location,
+ match.match_in_scheme, matches, create_shorter_match_, promote);
+ if (ensure_can_inline)
+ matches->front().promoted = true;
}
void HistoryURLProvider::CullPoorMatches(
- history::HistoryMatches* matches,
- HistoryURLProviderParams* params) const {
+ const HistoryURLProviderParams& params,
+ history::HistoryMatches* matches) const {
const base::Time& threshold(history::AutocompleteAgeThreshold());
for (history::HistoryMatches::iterator i(matches->begin());
i != matches->end(); ) {
if (RowQualifiesAsSignificant(i->url_info, threshold) &&
- !(params->default_search_provider &&
- params->default_search_provider->IsSearchURLUsingTermsData(
- i->url_info.url(), *params->search_terms_data.get()))) {
+ !(params.default_search_provider &&
+ params.default_search_provider->IsSearchURLUsingTermsData(
+ i->url_info.url(), *params.search_terms_data.get()))) {
++i;
} else {
i = matches->erase(i);
@@ -1038,7 +1037,7 @@ size_t HistoryURLProvider::RemoveSubsequentMatchesOf(
}
AutocompleteMatch HistoryURLProvider::HistoryMatchToACMatch(
- HistoryURLProviderParams* params,
+ const HistoryURLProviderParams& params,
const history::HistoryMatch& history_match,
MatchType match_type,
int relevance) {
@@ -1049,18 +1048,18 @@ AutocompleteMatch HistoryURLProvider::HistoryMatchToACMatch(
match.destination_url = info.url();
DCHECK(match.destination_url.is_valid());
size_t inline_autocomplete_offset =
- history_match.input_location + params->input.text().length();
+ history_match.input_location + params.input.text().length();
std::string languages = (match_type == WHAT_YOU_TYPED) ?
- std::string() : params->languages;
+ std::string() : params.languages;
const net::FormatUrlTypes format_types = net::kFormatUrlOmitAll &
- ~((params->trim_http && !history_match.match_in_scheme) ?
+ ~((params.trim_http && !history_match.match_in_scheme) ?
0 : net::kFormatUrlOmitHTTP);
match.fill_into_edit =
AutocompleteInput::FormattedStringWithEquivalentMeaning(info.url(),
net::FormatUrl(info.url(), languages, format_types,
net::UnescapeRule::SPACES, NULL, NULL,
&inline_autocomplete_offset));
- if (!params->prevent_inline_autocomplete &&
+ if (!params.prevent_inline_autocomplete &&
(inline_autocomplete_offset != string16::npos)) {
DCHECK(inline_autocomplete_offset <= match.fill_into_edit.length());
match.inline_autocompletion =
@@ -1068,7 +1067,7 @@ AutocompleteMatch HistoryURLProvider::HistoryMatchToACMatch(
}
// The latter part of the test effectively asks "is the inline completion
// empty?" (i.e., is this match effectively the what-you-typed match?).
- match.allowed_to_be_default_match = !params->prevent_inline_autocomplete ||
+ match.allowed_to_be_default_match = !params.prevent_inline_autocomplete ||
((inline_autocomplete_offset != string16::npos) &&
(inline_autocomplete_offset >= match.fill_into_edit.length()));
@@ -1088,7 +1087,7 @@ AutocompleteMatch HistoryURLProvider::HistoryMatchToACMatch(
&match.contents_class);
}
match.description = info.title();
- AutocompleteMatch::ClassifyMatchInString(params->input.text(),
+ AutocompleteMatch::ClassifyMatchInString(params.input.text(),
info.title(),
ACMatchClassification::NONE,
&match.description_class);
diff --git a/chrome/browser/autocomplete/history_url_provider.h b/chrome/browser/autocomplete/history_url_provider.h
index a46884e531..0ae0030a68 100644
--- a/chrome/browser/autocomplete/history_url_provider.h
+++ b/chrome/browser/autocomplete/history_url_provider.h
@@ -254,8 +254,8 @@ class HistoryURLProvider : public HistoryProvider {
// Determines if |match| is suitable for inline autocomplete. If so, and if
// |params| is non-NULL, promotes the match. Returns whether |match| is
// suitable for inline autocomplete.
- bool PromoteMatchForInlineAutocomplete(HistoryURLProviderParams* params,
- const history::HistoryMatch& match);
+ bool PromoteMatchForInlineAutocomplete(const history::HistoryMatch& match,
+ HistoryURLProviderParams* params);
// Sees if a shorter version of the best match should be created, and if so
// places it at the front of |matches|. This can suggest history URLs that
@@ -270,17 +270,14 @@ class HistoryURLProvider : public HistoryProvider {
const AutocompleteMatch& what_you_typed_match,
history::HistoryMatches* matches);
- // Sorts the given list of matches.
- void SortMatches(history::HistoryMatches* matches) const;
-
// Removes results that have been rarely typed or visited, and not any time
// recently. The exact parameters for this heuristic can be found in the
// function body. Also culls results corresponding to queries from the default
// search engine. These are low-quality, difficult-to-understand matches for
// users, and the SearchProvider should surface past queries in a better way
// anyway.
- void CullPoorMatches(history::HistoryMatches* matches,
- HistoryURLProviderParams* params) const;
+ void CullPoorMatches(const HistoryURLProviderParams& params,
+ history::HistoryMatches* matches) const;
// Removes results that redirect to each other, leaving at most |max_results|
// results.
@@ -302,7 +299,7 @@ class HistoryURLProvider : public HistoryProvider {
// Converts a line from the database into an autocomplete match for display.
AutocompleteMatch HistoryMatchToACMatch(
- HistoryURLProviderParams* params,
+ const HistoryURLProviderParams& params,
const history::HistoryMatch& history_match,
MatchType match_type,
int relevance);
diff --git a/chrome/browser/autocomplete/keyword_provider.cc b/chrome/browser/autocomplete/keyword_provider.cc
index d07e27f789..50020fcc90 100644
--- a/chrome/browser/autocomplete/keyword_provider.cc
+++ b/chrome/browser/autocomplete/keyword_provider.cc
@@ -16,6 +16,7 @@
#include "chrome/browser/extensions/api/omnibox/omnibox_api.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_service.h"
@@ -204,7 +205,8 @@ string16 KeywordProvider::GetKeywordForText(const string16& text) const {
GetExtensionById(template_url->GetExtensionId(), false);
if (!extension ||
(profile_->IsOffTheRecord() &&
- !extension_service->IsIncognitoEnabled(extension->id())))
+ !extension_util::IsIncognitoEnabled(extension->id(),
+ extension_service)))
return string16();
}
@@ -281,7 +283,8 @@ void KeywordProvider::Start(const AutocompleteInput& input,
service->GetExtensionById(template_url->GetExtensionId(), false);
bool enabled =
extension && (!profile_->IsOffTheRecord() ||
- service->IsIncognitoEnabled(extension->id()));
+ extension_util::IsIncognitoEnabled(extension->id(),
+ service));
if (!enabled) {
i = matches.erase(i);
continue;
diff --git a/chrome/browser/automation/automation_event_observers.h b/chrome/browser/automation/automation_event_observers.h
index 73460ec67f..03c2af5b13 100644
--- a/chrome/browser/automation/automation_event_observers.h
+++ b/chrome/browser/automation/automation_event_observers.h
@@ -89,8 +89,8 @@ class LoginEventObserver
// chromeos::LoginStatusConsumer:
virtual void OnLoginFailure(const chromeos::LoginFailure& error) OVERRIDE;
- virtual void OnLoginSuccess(const chromeos::UserContext& user_context,
- bool pending_requests, bool using_oauth) OVERRIDE;
+ virtual void OnLoginSuccess(
+ const chromeos::UserContext& user_context) OVERRIDE;
private:
base::WeakPtr<AutomationProvider> automation_;
diff --git a/chrome/browser/automation/automation_event_observers_chromeos.cc b/chrome/browser/automation/automation_event_observers_chromeos.cc
index f2a33bfb68..21eb366c25 100644
--- a/chrome/browser/automation/automation_event_observers_chromeos.cc
+++ b/chrome/browser/automation/automation_event_observers_chromeos.cc
@@ -27,9 +27,7 @@ void LoginEventObserver::OnLoginFailure(const chromeos::LoginFailure& error) {
}
void LoginEventObserver::OnLoginSuccess(
- const chromeos::UserContext& user_context,
- bool pending_requests,
- bool using_oauth) {
+ const chromeos::UserContext& user_context) {
// Profile changes after login. Ensure AutomationProvider refers to
// the correct one.
if (automation_) {
diff --git a/chrome/browser/automation/automation_provider_observers.h b/chrome/browser/automation/automation_provider_observers.h
index 198389e5e8..b6639ece18 100644
--- a/chrome/browser/automation/automation_provider_observers.h
+++ b/chrome/browser/automation/automation_provider_observers.h
@@ -671,10 +671,7 @@ class LoginObserver : public chromeos::LoginStatusConsumer {
virtual void OnLoginFailure(const chromeos::LoginFailure& error);
- virtual void OnLoginSuccess(
- const chromeos::UserContext& user_context,
- bool pending_requests,
- bool using_oauth);
+ virtual void OnLoginSuccess(const chromeos::UserContext& user_context);
private:
chromeos::ExistingUserController* controller_;
@@ -760,10 +757,7 @@ class ScreenUnlockObserver : public ScreenLockUnlockObserver,
virtual void OnLoginFailure(const chromeos::LoginFailure& error);
- virtual void OnLoginSuccess(
- const chromeos::UserContext& user_context,
- bool pending_requests,
- bool using_oauth) {}
+ virtual void OnLoginSuccess(const chromeos::UserContext& user_context) {}
private:
DISALLOW_COPY_AND_ASSIGN(ScreenUnlockObserver);
diff --git a/chrome/browser/automation/automation_provider_observers_chromeos.cc b/chrome/browser/automation/automation_provider_observers_chromeos.cc
index 49f430800e..7ca37982b3 100644
--- a/chrome/browser/automation/automation_provider_observers_chromeos.cc
+++ b/chrome/browser/automation/automation_provider_observers_chromeos.cc
@@ -73,10 +73,7 @@ void LoginObserver::OnLoginFailure(const chromeos::LoginFailure& error) {
delete this;
}
-void LoginObserver::OnLoginSuccess(
- const chromeos::UserContext& user_context,
- bool pending_requests,
- bool using_oauth) {
+void LoginObserver::OnLoginSuccess(const chromeos::UserContext& user_context) {
controller_->set_login_status_consumer(NULL);
AutomationJSONReply(automation_.get(), reply_message_.release())
.SendSuccess(NULL);
diff --git a/chrome/browser/automation/testing_automation_provider.cc b/chrome/browser/automation/testing_automation_provider.cc
index ce44e8f043..a15f5d3fc9 100644
--- a/chrome/browser/automation/testing_automation_provider.cc
+++ b/chrome/browser/automation/testing_automation_provider.cc
@@ -58,6 +58,7 @@
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/extensions/extension_tab_util.h"
+#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/extensions/unpacked_installer.h"
#include "chrome/browser/extensions/updater/extension_updater.h"
#include "chrome/browser/history/history_service_factory.h"
@@ -3576,7 +3577,7 @@ void TestingAutomationProvider::GetExtensionsInfo(DictionaryValue* args,
Manifest::IsUnpackedLocation(location));
extension_value->SetBoolean("is_enabled", service->IsExtensionEnabled(id));
extension_value->SetBoolean("allowed_in_incognito",
- service->IsIncognitoEnabled(id));
+ extension_util::IsIncognitoEnabled(id, service));
extension_value->SetBoolean(
"has_page_action",
extension_action_manager->GetPageAction(*extension) != NULL);
@@ -3684,7 +3685,8 @@ void TestingAutomationProvider::SetExtensionStateById(
AutomationJSONReply(this, reply_message).SendSuccess(NULL);
}
- service->SetIsIncognitoEnabled(extension->id(), allow_in_incognito);
+ extension_util::SetIsIncognitoEnabled(
+ extension->id(), service, allow_in_incognito);
}
// See TriggerPageActionById() in chrome/test/pyautolib/pyauto.py
diff --git a/chrome/browser/background/background_mode_manager.cc b/chrome/browser/background/background_mode_manager.cc
index 7fd24c08fb..b1ffcd17cb 100644
--- a/chrome/browser/background/background_mode_manager.cc
+++ b/chrome/browser/background/background_mode_manager.cc
@@ -262,7 +262,7 @@ void BackgroundModeManager::LaunchBackgroundApplication(
OpenApplication(AppLaunchParams(profile, extension, NEW_FOREGROUND_TAB));
}
-bool BackgroundModeManager::IsBackgroundModeActiveForTest() {
+bool BackgroundModeManager::IsBackgroundModeActive() {
return in_background_mode_;
}
diff --git a/chrome/browser/background/background_mode_manager.h b/chrome/browser/background/background_mode_manager.h
index 118d38693a..0494f5a2ab 100644
--- a/chrome/browser/background/background_mode_manager.h
+++ b/chrome/browser/background/background_mode_manager.h
@@ -60,6 +60,9 @@ class BackgroundModeManager
static void LaunchBackgroundApplication(Profile* profile,
const extensions::Extension* extension);
+ // Returns true if background mode is active.
+ virtual bool IsBackgroundModeActive();
+
// For testing purposes.
int NumberOfBackgroundModeData();
@@ -246,9 +249,6 @@ class BackgroundModeManager
// (virtual to allow overriding in tests).
virtual bool IsBackgroundModePrefEnabled() const;
- // Returns true if background mode is active. Used only by tests.
- bool IsBackgroundModeActiveForTest();
-
// Turns off background mode if it's currently enabled.
void DisableBackgroundMode();
diff --git a/chrome/browser/bookmarks/bookmark_model.cc b/chrome/browser/bookmarks/bookmark_model.cc
index f118e55cbf..9e4156e6af 100644
--- a/chrome/browser/bookmarks/bookmark_model.cc
+++ b/chrome/browser/bookmarks/bookmark_model.cc
@@ -496,14 +496,29 @@ void BookmarkModel::SetURL(const BookmarkNode* node, const GURL& url) {
void BookmarkModel::SetNodeMetaInfo(const BookmarkNode* node,
const std::string& key,
const std::string& value) {
+ // TODO(noyau): Right now the notification is send even if the meta info
+ // doesn't change. Checking first with the current API will decode the meta
+ // info twice, a non optimal solution.
+ FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
+ OnWillChangeBookmarkMetaInfo(this, node));
+
if (AsMutable(node)->SetMetaInfo(key, value) && store_.get())
store_->ScheduleSave();
+
+ FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
+ BookmarkMetaInfoChanged(this, node));
}
void BookmarkModel::DeleteNodeMetaInfo(const BookmarkNode* node,
const std::string& key) {
+ FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
+ OnWillChangeBookmarkMetaInfo(this, node));
+
if (AsMutable(node)->DeleteMetaInfo(key) && store_.get())
store_->ScheduleSave();
+
+ FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
+ BookmarkMetaInfoChanged(this, node));
}
void BookmarkModel::SetDateAdded(const BookmarkNode* node,
diff --git a/chrome/browser/bookmarks/bookmark_model_observer.h b/chrome/browser/bookmarks/bookmark_model_observer.h
index 31bd2e7197..aea1a0ad2e 100644
--- a/chrome/browser/bookmarks/bookmark_model_observer.h
+++ b/chrome/browser/bookmarks/bookmark_model_observer.h
@@ -57,6 +57,14 @@ class BookmarkModelObserver {
virtual void BookmarkNodeChanged(BookmarkModel* model,
const BookmarkNode* node) = 0;
+ // Invoked before the metainfo of a node is changed.
+ virtual void OnWillChangeBookmarkMetaInfo(BookmarkModel* model,
+ const BookmarkNode* node) {}
+
+ // Invoked when the metainfo on a node changes.
+ virtual void BookmarkMetaInfoChanged(BookmarkModel* model,
+ const BookmarkNode* node) {}
+
// Invoked when a favicon has been loaded or changed.
virtual void BookmarkNodeFaviconChanged(BookmarkModel* model,
const BookmarkNode* node) = 0;
diff --git a/chrome/browser/bookmarks/bookmark_tag_model.cc b/chrome/browser/bookmarks/bookmark_tag_model.cc
new file mode 100644
index 0000000000..9a7dec2cb6
--- /dev/null
+++ b/chrome/browser/bookmarks/bookmark_tag_model.cc
@@ -0,0 +1,553 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/bookmarks/bookmark_tag_model.h"
+
+#include "base/auto_reset.h"
+#include "base/json/json_string_value_serializer.h"
+#include "base/observer_list.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/bookmarks/bookmark_model_factory.h"
+#include "chrome/browser/bookmarks/bookmark_tag_model_observer.h"
+#include "ui/base/models/tree_node_iterator.h"
+
+namespace {
+// The key used to store the tag list in the metainfo of a bookmark.
+const char* TAG_KEY = "TAG_KEY";
+
+// Comparator to sort tags by usage.
+struct TagComparator {
+ TagComparator(std::map<BookmarkTag, unsigned int>& tags) : tags_(tags) {
+ }
+ ~TagComparator() {}
+
+ bool operator()(const BookmarkTag& a, const BookmarkTag& b) {
+ return (tags_[a] < tags_[b]);
+ }
+
+ std::map<BookmarkTag, unsigned int>& tags_;
+};
+
+// The tags are currently stored in the BookmarkNode's metaInfo in JSON
+// format. This function extracts the info from there and returns it in
+// digestible format.
+// If the Bookmark was never tagged before it is implicitely tagged with the
+// title of all its ancestors in the BookmarkModel.
+std::set<BookmarkTag> ExtractTagsFromBookmark(const BookmarkNode* bookmark) {
+ // This is awful BTW. Metainfo is itself an encoded JSON, and here we decode
+ // another layer.
+
+ // Retrieve the encodedData from the bookmark. If there is no encoded data
+ // at all returns the name of all the ancestors as separate tags.
+ std::string encoded;
+ if (!bookmark->GetMetaInfo(TAG_KEY, &encoded)) {
+ std::set<BookmarkTag> tags;
+ const BookmarkNode* folder = bookmark->parent();
+ while (folder && folder->type() == BookmarkNode::FOLDER) {
+ BookmarkTag trimmed_tag = CollapseWhitespace(folder->GetTitle(), true);
+ if (!trimmed_tag.empty())
+ tags.insert(trimmed_tag);
+ folder = folder->parent();
+ }
+ return tags;
+ }
+
+ // Decode into a base::Value. If the data is not encoded properly as a list
+ // return an empty result.
+ JSONStringValueSerializer serializer(&encoded);
+ int error_code = 0;
+ std::string error_message;
+ scoped_ptr<base::Value> result(serializer.Deserialize(&error_code,
+ &error_message));
+
+ if (error_code || !result->IsType(base::Value::TYPE_LIST))
+ return std::set<BookmarkTag>();
+
+ base::ListValue* list = NULL;
+ if (!result->GetAsList(&list) || list->empty())
+ return std::set<BookmarkTag>();
+
+ // Build the set.
+ std::set<BookmarkTag> return_value;
+
+ for (base::ListValue::iterator it = list->begin();
+ it != list->end(); ++it) {
+ base::Value* item = *it;
+ BookmarkTag tag;
+ if (!item->GetAsString(&tag))
+ continue;
+ return_value.insert(tag);
+ }
+ return return_value;
+}
+} // namespace
+
+BookmarkTagModel::BookmarkTagModel(BookmarkModel* bookmark_model)
+ : bookmark_model_(bookmark_model),
+ loaded_(false),
+ observers_(ObserverList<BookmarkTagModelObserver>::NOTIFY_EXISTING_ONLY),
+ inhibit_change_notifications_(false) {
+ bookmark_model_->AddObserver(this);
+ if (bookmark_model_->loaded())
+ Load();
+}
+
+BookmarkTagModel::~BookmarkTagModel() {
+ if (bookmark_model_)
+ bookmark_model_->RemoveObserver(this);
+}
+
+// BookmarkModel forwarding.
+
+void BookmarkTagModel::AddObserver(BookmarkTagModelObserver* observer) {
+ observers_.AddObserver(observer);
+}
+
+void BookmarkTagModel::RemoveObserver(BookmarkTagModelObserver* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void BookmarkTagModel::BeginExtensiveChanges() {
+ DCHECK(bookmark_model_);
+ bookmark_model_->BeginExtensiveChanges();
+}
+
+void BookmarkTagModel::EndExtensiveChanges() {
+ DCHECK(bookmark_model_);
+ bookmark_model_->EndExtensiveChanges();
+}
+
+bool BookmarkTagModel::IsDoingExtensiveChanges() const {
+ DCHECK(bookmark_model_);
+ return bookmark_model_->IsDoingExtensiveChanges();
+}
+
+void BookmarkTagModel::Remove(const BookmarkNode* bookmark) {
+ DCHECK(bookmark_model_);
+ DCHECK(loaded_);
+ const BookmarkNode* parent = bookmark->parent();
+ bookmark_model_->Remove(parent, parent->GetIndexOf(bookmark));
+}
+
+void BookmarkTagModel::RemoveAll() {
+ DCHECK(bookmark_model_);
+ DCHECK(loaded_);
+ bookmark_model_->RemoveAll();
+}
+
+const gfx::Image& BookmarkTagModel::GetFavicon(const BookmarkNode* bookmark) {
+ DCHECK(bookmark_model_);
+ DCHECK(loaded_);
+ return bookmark_model_->GetFavicon(bookmark);
+}
+
+void BookmarkTagModel::SetTitle(const BookmarkNode* bookmark,
+ const string16& title) {
+ DCHECK(bookmark_model_);
+ DCHECK(loaded_);
+ bookmark_model_->SetTitle(bookmark, title);
+}
+
+void BookmarkTagModel::SetURL(const BookmarkNode* bookmark, const GURL& url) {
+ DCHECK(bookmark_model_);
+ DCHECK(loaded_);
+ bookmark_model_->SetURL(bookmark, url);
+}
+
+void BookmarkTagModel::SetDateAdded(const BookmarkNode* bookmark,
+ base::Time date_added) {
+ DCHECK(bookmark_model_);
+ DCHECK(loaded_);
+ bookmark_model_->SetDateAdded(bookmark, date_added);
+}
+
+const BookmarkNode*
+ BookmarkTagModel::GetMostRecentlyAddedBookmarkForURL(const GURL& url) {
+ DCHECK(bookmark_model_);
+ DCHECK(loaded_);
+ return bookmark_model_->GetMostRecentlyAddedNodeForURL(url);
+}
+
+// Tags specific code.
+
+const BookmarkNode* BookmarkTagModel::AddURL(
+ const string16& title,
+ const GURL& url,
+ const std::set<BookmarkTag>& tags) {
+ DCHECK(bookmark_model_);
+ DCHECK(loaded_);
+
+ const BookmarkNode* bookmark;
+ {
+ base::AutoReset<bool> inhibitor(&inhibit_change_notifications_, true);
+ const BookmarkNode* parent = bookmark_model_->GetParentForNewNodes();
+ bookmark = bookmark_model_->AddURL(parent, 0, title, url);
+ AddTagsToBookmark(tags, bookmark);
+ }
+ FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_,
+ BookmarkNodeAdded(this, bookmark));
+
+ return bookmark;
+}
+
+std::set<BookmarkTag> BookmarkTagModel::GetTagsForBookmark(
+ const BookmarkNode* bookmark) {
+ DCHECK(loaded_);
+ return bookmark_to_tags_[bookmark];
+}
+
+void BookmarkTagModel::AddTagsToBookmark(
+ const std::set<BookmarkTag>& tags,
+ const BookmarkNode* bookmark) {
+ DCHECK(bookmark_model_);
+ std::set<BookmarkTag> all_tags(GetTagsForBookmark(bookmark));
+ for (std::set<BookmarkTag>::const_iterator it = tags.begin();
+ it != tags.end(); ++it) {
+ BookmarkTag trimmed_tag = CollapseWhitespace(*it, true);
+ if (trimmed_tag.empty())
+ continue;
+ all_tags.insert(trimmed_tag);
+ }
+ SetTagsOnBookmark(all_tags, bookmark);
+}
+
+void BookmarkTagModel::AddTagsToBookmarks(
+ const std::set<BookmarkTag>& tags,
+ const std::set<const BookmarkNode*>& bookmarks) {
+ for (std::set<const BookmarkNode*>::const_iterator it = bookmarks.begin();
+ it != bookmarks.end(); ++it) {
+ AddTagsToBookmark(tags, *it);
+ }
+}
+
+void BookmarkTagModel::RemoveTagsFromBookmark(
+ const std::set<BookmarkTag>& tags,
+ const BookmarkNode* bookmark) {
+ std::set<BookmarkTag> all_tags(GetTagsForBookmark(bookmark));
+ for (std::set<BookmarkTag>::const_iterator it = tags.begin();
+ it != tags.end(); ++it) {
+ all_tags.erase(*it);
+ }
+ SetTagsOnBookmark(all_tags, bookmark);
+}
+
+void BookmarkTagModel::RemoveTagsFromBookmarks(
+ const std::set<BookmarkTag>& tags,
+ const std::set<const BookmarkNode*>& bookmarks){
+ for (std::set<const BookmarkNode*>::const_iterator it = bookmarks.begin();
+ it != bookmarks.end(); ++it) {
+ RemoveTagsFromBookmark(tags, *it);
+ }
+}
+
+std::set<const BookmarkNode*> BookmarkTagModel::BookmarksForTags(
+ const std::set<BookmarkTag>& tags) {
+ DCHECK(loaded_);
+ // Count for each tags how many times a bookmark appeared.
+ std::map<const BookmarkNode*, size_t> bookmark_counts;
+ for (std::set<BookmarkTag>::const_iterator it = tags.begin();
+ it != tags.end(); ++it) {
+ const std::set<const BookmarkNode*>& subset(tag_to_bookmarks_[*it]);
+ for (std::set<const BookmarkNode*>::const_iterator tag_it = subset.begin();
+ tag_it != subset.end(); ++tag_it) {
+ bookmark_counts[*tag_it] += 1;
+ }
+ }
+ // Keep only the bookmarks that appeared in all the tags.
+ std::set<const BookmarkNode*> common_bookmarks;
+ for (std::map<const BookmarkNode*, size_t>::iterator it =
+ bookmark_counts.begin(); it != bookmark_counts.end(); ++it) {
+ if (it->second == tags.size())
+ common_bookmarks.insert(it->first);
+ }
+ return common_bookmarks;
+}
+
+std::set<const BookmarkNode*> BookmarkTagModel::BookmarksForTag(
+ const BookmarkTag& tag) {
+ DCHECK(!tag.empty());
+ return tag_to_bookmarks_[tag];
+}
+
+std::vector<BookmarkTag> BookmarkTagModel::TagsRelatedToTag(
+ const BookmarkTag& tag) {
+ DCHECK(loaded_);
+ std::map<BookmarkTag, unsigned int> tags;
+
+ if (tag.empty()) {
+ // Returns all the tags.
+ for (std::map<const BookmarkTag, std::set<const BookmarkNode*> >::iterator
+ it = tag_to_bookmarks_.begin(); it != tag_to_bookmarks_.end(); ++it) {
+ tags[it->first] = it->second.size();
+ }
+ } else {
+ std::set<const BookmarkNode*> bookmarks(BookmarksForTag(tag));
+
+ for (std::set<const BookmarkNode*>::iterator it = bookmarks.begin();
+ it != bookmarks.end(); ++it) {
+ const std::set<BookmarkTag>& subset(bookmark_to_tags_[*it]);
+ for (std::set<BookmarkTag>::const_iterator tag_it = subset.begin();
+ tag_it != subset.end(); ++tag_it) {
+ tags[*tag_it] += 1;
+ }
+ }
+ tags.erase(tag); // A tag is not related to itself.
+ }
+
+ std::vector<BookmarkTag> sorted_tags;
+ for (std::map<BookmarkTag, unsigned int>::iterator it = tags.begin();
+ it != tags.end(); ++it) {
+ sorted_tags.push_back(it->first);
+ }
+ std::sort(sorted_tags.begin(), sorted_tags.end(), TagComparator(tags));
+ return sorted_tags;
+}
+
+// BookmarkModelObserver methods.
+
+void BookmarkTagModel::Loaded(BookmarkModel* model, bool ids_reassigned) {
+ Load();
+}
+
+void BookmarkTagModel::BookmarkModelBeingDeleted(BookmarkModel* model) {
+ DCHECK(bookmark_model_);
+ FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_,
+ BookmarkTagModelBeingDeleted(this));
+ bookmark_model_ = NULL;
+}
+
+void BookmarkTagModel::BookmarkNodeMoved(BookmarkModel* model,
+ const BookmarkNode* old_parent,
+ int old_index,
+ const BookmarkNode* new_parent,
+ int new_index) {
+ DCHECK(loaded_);
+ const BookmarkNode* bookmark = new_parent->GetChild(new_index);
+ if (bookmark->is_folder()) {
+ ReloadDescendants(bookmark);
+ } else if (bookmark->is_url()) {
+ std::string encoded;
+ if (!bookmark->GetMetaInfo(TAG_KEY, &encoded)) {
+ // The bookmark moved and the system currently use its ancestors name as a
+ // poor approximation for tags.
+ FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_,
+ OnWillChangeBookmarkTags(this, bookmark));
+ RemoveBookmark(bookmark);
+ LoadBookmark(bookmark);
+ FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_,
+ BookmarkTagsChanged(this, bookmark));
+ }
+ }
+}
+
+void BookmarkTagModel::BookmarkNodeAdded(BookmarkModel* model,
+ const BookmarkNode* parent,
+ int index) {
+ DCHECK(loaded_);
+ const BookmarkNode* bookmark = parent->GetChild(index);
+ if (!bookmark->is_url())
+ return;
+ LoadBookmark(bookmark);
+
+ if (!inhibit_change_notifications_)
+ FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_,
+ BookmarkNodeAdded(this, bookmark));
+}
+
+void BookmarkTagModel::OnWillRemoveBookmarks(BookmarkModel* model,
+ const BookmarkNode* parent,
+ int old_index,
+ const BookmarkNode* node) {
+ DCHECK(loaded_);
+ if (!node->is_url())
+ return;
+ RemoveBookmark(node);
+ FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_,
+ OnWillRemoveBookmarks(this, node));
+}
+
+void BookmarkTagModel::BookmarkNodeRemoved(BookmarkModel* model,
+ const BookmarkNode* parent,
+ int old_index,
+ const BookmarkNode* node) {
+ DCHECK(loaded_);
+ if (!node->is_url())
+ return;
+ FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_,
+ BookmarkNodeRemoved(this, node));
+}
+
+void BookmarkTagModel::OnWillChangeBookmarkNode(BookmarkModel* model,
+ const BookmarkNode* node) {
+ DCHECK(loaded_);
+ if (!node->is_url() || inhibit_change_notifications_)
+ return;
+ FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_,
+ OnWillChangeBookmarkNode(this, node));
+}
+
+void BookmarkTagModel::BookmarkNodeChanged(BookmarkModel* model,
+ const BookmarkNode* node) {
+ DCHECK(loaded_);
+ if (node->is_folder()) {
+ // A folder title changed. This may change the tags on all the descendants
+ // still using the default tag list of all ancestors.
+ ReloadDescendants(node);
+ } else if (node->is_url()) {
+ if (!inhibit_change_notifications_)
+ FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_,
+ BookmarkNodeChanged(this, node));
+ }
+}
+
+void BookmarkTagModel::OnWillChangeBookmarkMetaInfo(BookmarkModel* model,
+ const BookmarkNode* node) {
+ DCHECK(loaded_);
+ if (!node->is_url() || inhibit_change_notifications_)
+ return;
+ FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_,
+ OnWillChangeBookmarkTags(this, node));
+}
+
+void BookmarkTagModel::BookmarkMetaInfoChanged(BookmarkModel* model,
+ const BookmarkNode* node) {
+ DCHECK(loaded_);
+ if (!node->is_url())
+ return;
+ RemoveBookmark(node);
+ LoadBookmark(node);
+ if (!inhibit_change_notifications_)
+ FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_,
+ BookmarkTagsChanged(this, node));
+}
+
+void BookmarkTagModel::BookmarkNodeFaviconChanged(BookmarkModel* model,
+ const BookmarkNode* node) {
+ DCHECK(loaded_);
+ if (!node->is_url())
+ return;
+ FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_,
+ BookmarkNodeFaviconChanged(this, node));
+}
+
+void BookmarkTagModel::OnWillReorderBookmarkNode(BookmarkModel* model,
+ const BookmarkNode* node) {
+ // This model doesn't care.
+}
+
+void BookmarkTagModel::BookmarkNodeChildrenReordered(BookmarkModel* model,
+ const BookmarkNode* node) {
+ // This model doesn't care.
+}
+
+void BookmarkTagModel::ExtensiveBookmarkChangesBeginning(BookmarkModel* model) {
+ DCHECK(loaded_);
+ FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_,
+ ExtensiveBookmarkChangesBeginning(this));
+}
+
+void BookmarkTagModel::ExtensiveBookmarkChangesEnded(BookmarkModel* model) {
+ DCHECK(loaded_);
+ FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_,
+ ExtensiveBookmarkChangesEnded(this));
+}
+
+void BookmarkTagModel::OnWillRemoveAllBookmarks(BookmarkModel* model) {
+ DCHECK(loaded_);
+ FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_,
+ OnWillRemoveAllBookmarks(this));
+}
+
+void BookmarkTagModel::BookmarkAllNodesRemoved(BookmarkModel* model){
+ DCHECK(loaded_);
+ tag_to_bookmarks_.clear();
+ bookmark_to_tags_.clear();
+ FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_,
+ BookmarkAllNodesRemoved(this));
+}
+
+// Private methods.
+
+void BookmarkTagModel::SetTagsOnBookmark(const std::set<BookmarkTag>& tags,
+ const BookmarkNode* bookmark) {
+ DCHECK(bookmark_model_);
+ DCHECK(loaded_);
+
+ // Build a ListValue.
+ std::vector<BookmarkTag> tag_vector(tags.begin(), tags.end());
+ base::ListValue list;
+ list.AppendStrings(tag_vector);
+
+ // Encodes it.
+ std::string encoded;
+ JSONStringValueSerializer serializer(&encoded);
+
+ // Pushes it in the bookmark's metainfo. Even if the tag list is empty the
+ // empty list must be put on the node to avoid reverting to the tag list
+ // derived from the hierarchy.
+ // The internal caches of the BookmarkTagModel are updated when the
+ // notification from the BookmarkModel is received.
+ serializer.Serialize(list);
+ bookmark_model_->SetNodeMetaInfo(bookmark, TAG_KEY, encoded);
+}
+
+void BookmarkTagModel::Load() {
+ DCHECK(bookmark_model_);
+ DCHECK(!loaded_);
+ ui::TreeNodeIterator<const BookmarkNode> iterator(
+ bookmark_model_->root_node());
+ while (iterator.has_next()) {
+ const BookmarkNode* bookmark = iterator.Next();
+ if (bookmark->is_url())
+ LoadBookmark(bookmark);
+ }
+ loaded_ = true;
+ FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_,
+ Loaded(this));
+}
+
+void BookmarkTagModel::ReloadDescendants(const BookmarkNode* folder) {
+ DCHECK(folder->is_folder());
+ ExtensiveChanges scoped(ExtensiveChanges(this));
+ ui::TreeNodeIterator<const BookmarkNode> iterator(folder);
+ while (iterator.has_next()) {
+ const BookmarkNode* bookmark = iterator.Next();
+ if (bookmark->is_url()) {
+ FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_,
+ OnWillChangeBookmarkTags(this, bookmark));
+ RemoveBookmark(bookmark);
+ LoadBookmark(bookmark);
+ FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_,
+ BookmarkTagsChanged(this, bookmark));
+ }
+ }
+}
+
+void BookmarkTagModel::LoadBookmark(const BookmarkNode* bookmark) {
+ DCHECK(bookmark_model_);
+ DCHECK(bookmark->is_url());
+ std::set<BookmarkTag> tags(ExtractTagsFromBookmark(bookmark));
+
+ bookmark_to_tags_[bookmark] = tags;
+ for (std::set<BookmarkTag>::iterator it = tags.begin();
+ it != tags.end(); ++it) {
+ tag_to_bookmarks_[*it].insert(bookmark);
+ }
+}
+
+void BookmarkTagModel::RemoveBookmark(const BookmarkNode* bookmark) {
+ DCHECK(bookmark_model_);
+ DCHECK(bookmark->is_url());
+ std::set<BookmarkTag> tags(bookmark_to_tags_[bookmark]);
+ bookmark_to_tags_.erase(bookmark);
+
+ for (std::set<BookmarkTag>::iterator it = tags.begin();
+ it != tags.end(); ++it) {
+ tag_to_bookmarks_[*it].erase(bookmark);
+ // Remove the tags no longer used.
+ if (!tag_to_bookmarks_[*it].size())
+ tag_to_bookmarks_.erase(*it);
+ }
+}
diff --git a/chrome/browser/bookmarks/bookmark_tag_model.h b/chrome/browser/bookmarks/bookmark_tag_model.h
new file mode 100644
index 0000000000..b30e565cc3
--- /dev/null
+++ b/chrome/browser/bookmarks/bookmark_tag_model.h
@@ -0,0 +1,214 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_BOOKMARKS_BOOKMARK_TAG_MODEL_H_
+#define CHROME_BROWSER_BOOKMARKS_BOOKMARK_TAG_MODEL_H_
+
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/bookmarks/bookmark_model_observer.h"
+
+class BookmarkTagModelObserver;
+
+typedef string16 BookmarkTag;
+
+// BookmarTagModel provides a way to access and manipulate bookmarks in a
+// non-hierarchical way. BookmarkTagModel view the bookmarks as a flat list,
+// and each one can be marked with a collection of tags (tags are simply
+// strings).
+//
+// BookmarkTagModel converts on demand the data from an existing BookmarkModel
+// to its view of the world by considering all the titles of all the ancestors
+// as tags. This view is frozen on an individual bookmarks when the
+// BookmarkTagModel performs a change on the tags of this bookmarks.
+//
+// The Bookmark's meta info is used for storage.
+//
+// An observer may be attached to a BookmarkTagModel to observe relevant events.
+//
+// TODO(noyau): The meta info data is not preserved by copy/paste or drag and
+// drop, this means that bookmarks will loose their tag information if
+// manipulated that way.
+//
+class BookmarkTagModel : public BookmarkModelObserver {
+ public:
+ explicit BookmarkTagModel(BookmarkModel* bookmark_model);
+ virtual ~BookmarkTagModel();
+
+ // Returns true if the model finished loading.
+ bool loaded() const { return loaded_; }
+
+ // Add and remove observers on this object.
+ void AddObserver(BookmarkTagModelObserver* observer);
+ void RemoveObserver(BookmarkTagModelObserver* observer);
+
+ // Brackets an extensive set of changes, such as during import or sync, so
+ // observers can delay any expensive UI updates until it's finished.
+ class ExtensiveChanges {
+ public:
+ friend class BookmarkTagModel;
+ explicit ExtensiveChanges(BookmarkTagModel* model) : model_(model) {
+ model_->BeginExtensiveChanges();
+ }
+ private:
+ ~ExtensiveChanges() {
+ model_->EndExtensiveChanges();
+ }
+
+ BookmarkTagModel* model_;
+ };
+
+ // Returns true if this bookmark model is currently in a mode where extensive
+ // changes might happen, such as for import and sync. This is helpful for
+ // observers that are created after the mode has started, and want to check
+ // state during their own initializer.
+ bool IsDoingExtensiveChanges() const;
+
+ // Removes the given |BookmarkNode|. Observers are notified immediately.
+ void Remove(const BookmarkNode* bookmark);
+
+ // Removes all the bookmark nodes. Observers are only notified when all nodes
+ // have been removed. There is no notification for individual node removals.
+ void RemoveAll();
+
+ // Returns the favicon for |node|. If the favicon has not yet been
+ // loaded it is loaded and the observer of the model notified when done.
+ const gfx::Image& GetFavicon(const BookmarkNode* bookmark);
+
+ // Sets the title of |node|.
+ void SetTitle(const BookmarkNode* bookmark, const string16& title);
+
+ // Sets the URL of |node|.
+ void SetURL(const BookmarkNode* bookmark, const GURL& url);
+
+ // Sets the date added time of |node|.
+ void SetDateAdded(const BookmarkNode* bookmark, base::Time date_added);
+
+ // Returns the most recently added bookmark for the |url|. Returns NULL if
+ // |url| is not bookmarked.
+ const BookmarkNode* GetMostRecentlyAddedBookmarkForURL(const GURL& url);
+
+ // Creates a new bookmark.
+ const BookmarkNode* AddURL(const string16& title,
+ const GURL& url,
+ const std::set<BookmarkTag>& tags);
+
+ // Adds the |tags| to the tag list of the |bookmark|.
+ void AddTagsToBookmark(const std::set<BookmarkTag>& tags,
+ const BookmarkNode* bookmark);
+
+ // Same but to a whole collection of |bookmarks|.
+ void AddTagsToBookmarks(const std::set<BookmarkTag>& tags,
+ const std::set<const BookmarkNode*>& bookmarks);
+
+ // Remove the |tags| from the tag list of the |bookmark|. If the bookmark
+ // is not tagged with one or more of the tags, these are ignored.
+ void RemoveTagsFromBookmark(const std::set<BookmarkTag>& tags,
+ const BookmarkNode* bookmark);
+
+ // Same but to a whole collection of |bookmarks|.
+ void RemoveTagsFromBookmarks(const std::set<BookmarkTag>& tags,
+ const std::set<const BookmarkNode*>& bookmarks);
+
+ // Returns all the tags set on a specific |bookmark|.
+ std::set<BookmarkTag> GetTagsForBookmark(const BookmarkNode* bookmark);
+
+ // Returns the bookmarks marked with all the given |tags|.
+ std::set<const BookmarkNode*> BookmarksForTags(
+ const std::set<BookmarkTag>& tags);
+
+ // Returns the bookmarks marked with the given |tag|.
+ std::set<const BookmarkNode*> BookmarksForTag(const BookmarkTag& tag);
+
+ // Returns all tags related to the parent |tag|. If |tag| is null this method
+ // will returns and sort all tags in the system. A related tag is a tag used
+ // on one or more of the bookmarks tagged with |tag|. The returned tags are
+ // ordered from the most common to the rarest one.
+ std::vector<BookmarkTag> TagsRelatedToTag(const BookmarkTag& tag);
+
+ // All the BookmarkModelObserver methods. See there for details.
+ virtual void Loaded(BookmarkModel* model, bool ids_reassigned) OVERRIDE;
+ virtual void BookmarkModelBeingDeleted(BookmarkModel* model) OVERRIDE;
+ virtual void BookmarkNodeMoved(BookmarkModel* model,
+ const BookmarkNode* old_parent,
+ int old_index,
+ const BookmarkNode* new_parent,
+ int new_index) OVERRIDE;
+ virtual void BookmarkNodeAdded(BookmarkModel* model,
+ const BookmarkNode* parent,
+ int index) OVERRIDE;
+ virtual void OnWillRemoveBookmarks(BookmarkModel* model,
+ const BookmarkNode* parent,
+ int old_index,
+ const BookmarkNode* node) OVERRIDE;
+ virtual void BookmarkNodeRemoved(BookmarkModel* model,
+ const BookmarkNode* parent,
+ int old_index,
+ const BookmarkNode* node) OVERRIDE;
+ virtual void OnWillChangeBookmarkNode(BookmarkModel* model,
+ const BookmarkNode* node) OVERRIDE;
+ virtual void BookmarkNodeChanged(BookmarkModel* model,
+ const BookmarkNode* node) OVERRIDE;
+ virtual void OnWillChangeBookmarkMetaInfo(BookmarkModel* model,
+ const BookmarkNode* node) OVERRIDE;
+ virtual void BookmarkMetaInfoChanged(BookmarkModel* model,
+ const BookmarkNode* node) OVERRIDE;
+ virtual void BookmarkNodeFaviconChanged(BookmarkModel* model,
+ const BookmarkNode* node) OVERRIDE;
+ virtual void OnWillReorderBookmarkNode(BookmarkModel* model,
+ const BookmarkNode* node) OVERRIDE;
+ virtual void BookmarkNodeChildrenReordered(BookmarkModel* model,
+ const BookmarkNode* node) OVERRIDE;
+ virtual void ExtensiveBookmarkChangesBeginning(BookmarkModel* model) OVERRIDE;
+ virtual void ExtensiveBookmarkChangesEnded(BookmarkModel* model) OVERRIDE;
+ virtual void OnWillRemoveAllBookmarks(BookmarkModel* model) OVERRIDE;
+ virtual void BookmarkAllNodesRemoved(BookmarkModel* model) OVERRIDE;
+
+ private:
+ // Notifies the observers that an extensive set of changes is about to happen,
+ // such as during import or sync, so they can delay any expensive UI updates
+ // until it's finished.
+ void BeginExtensiveChanges();
+ void EndExtensiveChanges();
+
+ // Encode the tags in a format suitable for the BookmarkNode's metaInfo and
+ // set or replace the value.
+ void SetTagsOnBookmark(const std::set<BookmarkTag>& tags,
+ const BookmarkNode* bookmark);
+
+ // Build the caches of tag to bookmarks and bookmarks to tag for faster
+ // access to the data. Load() is called from the constructor if possible, or
+ // as soon as possible after that.
+ void Load();
+
+ // Discard tag information for all descendants of a given folder node and
+ // rebuild the cache for them.
+ void ReloadDescendants(const BookmarkNode* folder);
+
+ // Clear the local cache of all mentions of |bookmark|.
+ void RemoveBookmark(const BookmarkNode* bookmark);
+
+ // Extract the tags from |bookmark| and insert it in the local cache.
+ void LoadBookmark(const BookmarkNode* bookmark);
+
+ // The model from where the data is permanently stored.
+ BookmarkModel* bookmark_model_;
+
+ // True if the model is fully loaded.
+ bool loaded_;
+
+ // The observers.
+ ObserverList<BookmarkTagModelObserver> observers_;
+
+ // Local cache for quick access.
+ std::map<const BookmarkTag, std::set<const BookmarkNode*> > tag_to_bookmarks_;
+ std::map<const BookmarkNode*, std::set<BookmarkTag> > bookmark_to_tags_;
+
+ // Set to true during the creation of a new bookmark in order to send only the
+ // proper notification.
+ bool inhibit_change_notifications_;
+
+ DISALLOW_COPY_AND_ASSIGN(BookmarkTagModel);
+};
+
+#endif // CHROME_BROWSER_BOOKMARKS_BOOKMARK_TAG_MODEL_H_
diff --git a/chrome/browser/bookmarks/bookmark_tag_model_observer.h b/chrome/browser/bookmarks/bookmark_tag_model_observer.h
new file mode 100644
index 0000000000..4c1df21e85
--- /dev/null
+++ b/chrome/browser/bookmarks/bookmark_tag_model_observer.h
@@ -0,0 +1,76 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_BOOKMARKS_BOOKMARK_TAG_MODEL_OBSERVER_H_
+#define CHROME_BROWSER_BOOKMARKS_BOOKMARK_TAG_MODEL_OBSERVER_H_
+
+class BookmarkTagModel;
+class BookmarkNode;
+
+// Observer for the BookmarkTagModel.
+class BookmarkTagModelObserver {
+ public:
+ // Invoked when the model has finished loading.
+ virtual void Loaded(BookmarkTagModel* model) = 0;
+
+ // Invoked from the destructor of the BookmarkTagModel.
+ virtual void BookmarkTagModelBeingDeleted(BookmarkTagModel* model) {}
+
+ // Invoked when a node has been added.
+ virtual void BookmarkNodeAdded(BookmarkTagModel* model,
+ const BookmarkNode* bookmark) = 0;
+
+ // Invoked before a node is removed.
+ // |node| is the node to be removed.
+ virtual void OnWillRemoveBookmarks(BookmarkTagModel* model,
+ const BookmarkNode* bookmark) {}
+
+ // Invoked when a node has been removed, |node| is the node that was removed.
+ virtual void BookmarkNodeRemoved(BookmarkTagModel* model,
+ const BookmarkNode* bookmark) = 0;
+
+ // Invoked before the title or url of a node is changed.
+ virtual void OnWillChangeBookmarkNode(BookmarkTagModel* model,
+ const BookmarkNode* bookmark) {}
+
+ // Invoked when the title or url of a node changes.
+ virtual void BookmarkNodeChanged(BookmarkTagModel* model,
+ const BookmarkNode* bookmark) = 0;
+
+ // Invoked before changing the tags of a node.
+ virtual void OnWillChangeBookmarkTags(BookmarkTagModel* model,
+ const BookmarkNode* bookmark) {}
+
+ // Invoked when tags are changed on a bookmark.
+ virtual void BookmarkTagsChanged(BookmarkTagModel* model,
+ const BookmarkNode* bookmark) = 0;
+
+ // Invoked when a favicon has been loaded or changed.
+ virtual void BookmarkNodeFaviconChanged(BookmarkTagModel* model,
+ const BookmarkNode* node) = 0;
+
+ // Invoked before an extensive set of model changes is about to begin.
+ // This tells UI intensive observers to wait until the updates finish to
+ // update themselves.
+ // These methods should only be used for imports and sync.
+ // Observers should still respond to BookmarkNodeRemoved immediately,
+ // to avoid holding onto stale node pointers.
+ virtual void ExtensiveBookmarkChangesBeginning(BookmarkTagModel* model) {}
+
+ // Invoked after an extensive set of model changes has ended.
+ // This tells observers to update themselves if they were waiting for the
+ // update to finish.
+ virtual void ExtensiveBookmarkChangesEnded(BookmarkTagModel* model) {}
+
+ // Invoked before all non-permanent bookmark nodes are removed.
+ virtual void OnWillRemoveAllBookmarks(BookmarkTagModel* model) {}
+
+ // Invoked when all non-permanent bookmark nodes have been removed.
+ virtual void BookmarkAllNodesRemoved(BookmarkTagModel* model) = 0;
+
+ protected:
+ virtual ~BookmarkTagModelObserver() {}
+};
+
+#endif // CHROME_BROWSER_BOOKMARKS_BOOKMARK_TAG_MODEL_OBSERVER_H_
diff --git a/chrome/browser/bookmarks/bookmark_tag_model_unittest.cc b/chrome/browser/bookmarks/bookmark_tag_model_unittest.cc
new file mode 100644
index 0000000000..fa5cc98f84
--- /dev/null
+++ b/chrome/browser/bookmarks/bookmark_tag_model_unittest.cc
@@ -0,0 +1,566 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/bookmarks/bookmark_tag_model.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/bookmarks/bookmark_tag_model_observer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+
+namespace {
+
+static struct {
+ const std::string input_tag;
+ const std::string expected_tag;
+} whitespace_test_cases[] = {
+ // Newlines.
+ {"foo\nbar", "foo bar"},
+ {"foo\n\nbar", "foo bar"},
+ {"foo\n\n\nbar", "foo bar"},
+ {"foo\r\nbar", "foo bar"},
+ {"foo\r\n\r\nbar", "foo bar"},
+ {"\nfoo\nbar\n", "foo bar"},
+ // Spaces.
+ {"foo bar", "foo bar"},
+ {" foo bar ", "foo bar"},
+ {" foo bar ", "foo bar"},
+ // Tabs.
+ {"\tfoo\tbar\t", "foo bar"},
+ {"\tfoo bar\t", "foo bar"},
+ // Mixed cases.
+ {"\tfoo\nbar\t", "foo bar"},
+ {"\tfoo\r\nbar\t", "foo bar"},
+ {" foo\tbar\n", "foo bar"},
+ {"\t foo \t bar \t", "foo bar"},
+ {"\n foo\r\n\tbar\n \t", "foo bar"},
+};
+
+enum ObserverCounts {
+ OBSERVER_COUNTS_ADD = 0,
+ OBSERVER_COUNTS_BEFORE_REMOVE,
+ OBSERVER_COUNTS_REMOVE,
+ OBSERVER_COUNTS_BEFORE_CHANGE,
+ OBSERVER_COUNTS_CHANGE,
+ OBSERVER_COUNTS_BEFORE_TAG_CHANGE,
+ OBSERVER_COUNTS_TAG_CHANGE,
+ OBSERVER_COUNTS_FAVICON_CHANGE,
+ OBSERVER_COUNTS_EXTENSIVE_CHANGE_BEGIN,
+ OBSERVER_COUNTS_EXTENSIVE_CHANGE_END,
+ OBSERVER_COUNTS_BEFORE_REMOVE_ALL,
+ OBSERVER_COUNTS_REMOVE_ALL,
+ OBSERVER_COUNTS_TOTAL_NUMBER_OF_COUNTS
+};
+
+const std::string count_name[] = {
+ "OBSERVER_COUNTS_ADD",
+ "OBSERVER_COUNTS_BEFORE_REMOVE",
+ "OBSERVER_COUNTS_REMOVE",
+ "OBSERVER_COUNTS_BEFORE_CHANGE",
+ "OBSERVER_COUNTS_CHANGE",
+ "OBSERVER_COUNTS_BEFORE_TAG_CHANGE",
+ "OBSERVER_COUNTS_TAG_CHANGE",
+ "OBSERVER_COUNTS_FAVICON_CHANGE",
+ "OBSERVER_COUNTS_EXTENSIVE_CHANGE_BEGIN",
+ "OBSERVER_COUNTS_EXTENSIVE_CHANGE_END",
+ "OBSERVER_COUNTS_BEFORE_REMOVE_ALL",
+ "OBSERVER_COUNTS_REMOVE_ALL"
+};
+
+
+class BookmarkTagModelTest
+ : public testing::Test, public BookmarkTagModelObserver {
+ public:
+ struct ObserverDetails {
+ ObserverDetails() : bookmark_(NULL) {}
+
+ void Set(const BookmarkNode* bookmark,
+ const std::set<BookmarkTag>& tags) {
+ bookmark_ = bookmark;
+ tags_ = tags;
+ }
+
+ void ExpectEquals(const BookmarkNode* bookmark,
+ const std::set<BookmarkTag>& tags) {
+ EXPECT_EQ(bookmark_, bookmark);
+ EXPECT_EQ(tags_, tags);
+ }
+
+ private:
+ const BookmarkNode* bookmark_;
+ std::set<BookmarkTag> tags_;
+ };
+
+ BookmarkTagModelTest() : model_(NULL),
+ tag_model_(new BookmarkTagModel(&model_)) {
+ tag_model_->AddObserver(this);
+ ClearCounts();
+ }
+
+ virtual ~BookmarkTagModelTest() {
+ }
+
+ // BookmarkTagModelObserver methods.
+
+ virtual void Loaded(BookmarkTagModel* model) OVERRIDE {
+ // We never load from the db, so that this should never get invoked.
+ NOTREACHED();
+ }
+
+ // Invoked when a node has been added.
+ virtual void BookmarkNodeAdded(BookmarkTagModel* model,
+ const BookmarkNode* bookmark) OVERRIDE {
+ ++counts_[OBSERVER_COUNTS_ADD];
+ observer_details_.Set(bookmark, model->GetTagsForBookmark(bookmark));
+ }
+
+ // Invoked before a node is removed.
+ // |node| is the node to be removed.
+ virtual void OnWillRemoveBookmarks(BookmarkTagModel* model,
+ const BookmarkNode* bookmark) OVERRIDE {
+ ++counts_[OBSERVER_COUNTS_BEFORE_REMOVE];
+ }
+
+ // Invoked when a node has been removed, the item may still be starred though.
+ // |node| is the node that was removed.
+ virtual void BookmarkNodeRemoved(BookmarkTagModel* model,
+ const BookmarkNode* bookmark) OVERRIDE {
+ ++counts_[OBSERVER_COUNTS_REMOVE];
+ }
+
+ // Invoked before the title or url of a node is changed.
+ virtual void OnWillChangeBookmarkNode(BookmarkTagModel* model,
+ const BookmarkNode* bookmark) OVERRIDE {
+ ++counts_[OBSERVER_COUNTS_BEFORE_CHANGE];
+ }
+
+ // Invoked when the title or url of a node changes.
+ virtual void BookmarkNodeChanged(BookmarkTagModel* model,
+ const BookmarkNode* bookmark) OVERRIDE {
+ ++counts_[OBSERVER_COUNTS_CHANGE];
+ observer_details_.Set(bookmark, model->GetTagsForBookmark(bookmark));
+ }
+
+ virtual void OnWillChangeBookmarkTags(BookmarkTagModel* model,
+ const BookmarkNode* bookmark) OVERRIDE {
+ ++counts_[OBSERVER_COUNTS_BEFORE_TAG_CHANGE];
+ }
+
+ virtual void BookmarkTagsChanged(BookmarkTagModel* model,
+ const BookmarkNode* bookmark) OVERRIDE {
+ ++counts_[OBSERVER_COUNTS_TAG_CHANGE];
+ observer_details_.Set(bookmark, model->GetTagsForBookmark(bookmark));
+ }
+
+ virtual void BookmarkNodeFaviconChanged(BookmarkTagModel* model,
+ const BookmarkNode* node) OVERRIDE {
+ ++counts_[OBSERVER_COUNTS_FAVICON_CHANGE];
+ }
+
+ virtual void ExtensiveBookmarkChangesBeginning(BookmarkTagModel* model)
+ OVERRIDE {
+ ++counts_[OBSERVER_COUNTS_EXTENSIVE_CHANGE_BEGIN];
+ }
+
+ virtual void ExtensiveBookmarkChangesEnded(BookmarkTagModel* model) OVERRIDE {
+ ++counts_[OBSERVER_COUNTS_EXTENSIVE_CHANGE_END];
+ }
+
+ virtual void OnWillRemoveAllBookmarks(BookmarkTagModel* model) OVERRIDE {
+ ++counts_[OBSERVER_COUNTS_BEFORE_REMOVE_ALL];
+ }
+
+ virtual void BookmarkAllNodesRemoved(BookmarkTagModel* model) OVERRIDE {
+ ++counts_[OBSERVER_COUNTS_REMOVE_ALL];
+ }
+
+ void ClearCounts() {
+ for (unsigned int i = 0; i < OBSERVER_COUNTS_TOTAL_NUMBER_OF_COUNTS; ++i)
+ counts_[i] = 0;
+ }
+
+ void AssertAndClearObserverCount(ObserverCounts count, int expected) {
+ ASSERT_EQ(expected, counts_[count]) << count_name[count];
+ counts_[count] = 0;
+ }
+
+ void AssertAllCountsClear() {
+ for (unsigned int i = 0; i < OBSERVER_COUNTS_TOTAL_NUMBER_OF_COUNTS; ++i)
+ ASSERT_EQ(0, counts_[i]) << count_name[i];
+ }
+
+ const BookmarkNode* AddURLWithTags(
+ const std::string& name,
+ const std::set<BookmarkTag>& tags) {
+ const string16 title(ASCIIToUTF16(name));
+ const GURL url("http://" + name + ".com");
+
+ return tag_model_->AddURL(title, url, tags);
+ }
+
+ protected:
+ BookmarkModel model_;
+ scoped_ptr<BookmarkTagModel> tag_model_;
+ ObserverDetails observer_details_;
+
+ private:
+ int counts_[OBSERVER_COUNTS_TOTAL_NUMBER_OF_COUNTS];
+
+ DISALLOW_COPY_AND_ASSIGN(BookmarkTagModelTest);
+};
+
+TEST_F(BookmarkTagModelTest, InitialState) {
+ std::vector<BookmarkTag> tags(tag_model_->TagsRelatedToTag(base::string16()));
+ EXPECT_EQ(0UL, tags.size());
+}
+
+TEST_F(BookmarkTagModelTest, AddURL) {
+ std::set<BookmarkTag> tags;
+ tags.insert(ASCIIToUTF16("bar"));
+ tags.insert(ASCIIToUTF16("baz"));
+
+ AddURLWithTags("orly", tags);
+ const BookmarkNode* new_node = AddURLWithTags("foo", tags);
+ AssertAndClearObserverCount(OBSERVER_COUNTS_ADD, 2);
+ AssertAllCountsClear();
+
+ observer_details_.ExpectEquals(new_node, tags);
+
+ EXPECT_EQ(2UL, tag_model_->BookmarksForTag(ASCIIToUTF16("bar")).size());
+ EXPECT_EQ(2UL, tag_model_->BookmarksForTag(ASCIIToUTF16("baz")).size());
+ EXPECT_EQ(tags, tag_model_->GetTagsForBookmark(new_node));
+
+ std::vector<BookmarkTag> alltags(
+ tag_model_->TagsRelatedToTag(base::string16()));
+ EXPECT_EQ(2UL, alltags.size());
+}
+
+TEST_F(BookmarkTagModelTest, RelatedTo) {
+ std::set<BookmarkTag> tags;
+ tags.insert(ASCIIToUTF16("bar"));
+ tags.insert(ASCIIToUTF16("baz"));
+
+ AddURLWithTags("orly", tags);
+ AddURLWithTags("foo", tags);
+ AssertAndClearObserverCount(OBSERVER_COUNTS_ADD, 2);
+ AssertAllCountsClear();
+
+ std::vector<BookmarkTag> bartags(tag_model_->TagsRelatedToTag(
+ ASCIIToUTF16("bar")));
+ EXPECT_EQ(1UL, bartags.size());
+ std::vector<BookmarkTag> baztags(tag_model_->TagsRelatedToTag(
+ ASCIIToUTF16("baz")));
+ EXPECT_EQ(1UL, baztags.size());
+}
+
+TEST_F(BookmarkTagModelTest, AddURLWithWhitespaceTitle) {
+ std::set<BookmarkTag> tags;
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(whitespace_test_cases); ++i) {
+ const BookmarkNode* new_node = AddURLWithTags(
+ whitespace_test_cases[i].input_tag, tags);
+
+ EXPECT_EQ(ASCIIToUTF16(whitespace_test_cases[i].expected_tag),
+ new_node->GetTitle());
+ EXPECT_EQ(BookmarkNode::URL, new_node->type());
+ }
+}
+
+TEST_F(BookmarkTagModelTest, CheckTagsWithWhitespace) {
+ std::set<BookmarkTag> tags;
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(whitespace_test_cases); ++i)
+ tags.insert(ASCIIToUTF16(whitespace_test_cases[i].input_tag));
+
+ AddURLWithTags("foo", tags);
+
+ std::vector<BookmarkTag> alltags(tag_model_->TagsRelatedToTag(
+ base::string16()));
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(whitespace_test_cases); ++i) {
+ EXPECT_EQ(0UL, tag_model_->BookmarksForTag(
+ ASCIIToUTF16(whitespace_test_cases[i].input_tag)).size());
+ EXPECT_EQ(1UL, tag_model_->BookmarksForTag(
+ ASCIIToUTF16(whitespace_test_cases[i].expected_tag)).size());
+ }
+}
+
+TEST_F(BookmarkTagModelTest, RemoveURL) {
+ std::set<BookmarkTag> tags;
+ tags.insert(ASCIIToUTF16("bar"));
+ tags.insert(ASCIIToUTF16("baz"));
+
+ const BookmarkNode* new_node = AddURLWithTags("foo", tags);
+ const BookmarkNode* new_node2 = AddURLWithTags("flou", tags);
+ ClearCounts();
+
+ tag_model_->Remove(new_node);
+ tag_model_->Remove(new_node2);
+ AssertAndClearObserverCount(OBSERVER_COUNTS_BEFORE_REMOVE, 2);
+ AssertAndClearObserverCount(OBSERVER_COUNTS_REMOVE, 2);
+ AssertAllCountsClear();
+
+ std::vector<BookmarkTag> alltags(tag_model_->TagsRelatedToTag(
+ base::string16()));
+ EXPECT_EQ(0UL, alltags.size());
+}
+
+TEST_F(BookmarkTagModelTest, AddTagToBookmarks) {
+ std::set<BookmarkTag> tags;
+ tags.insert(ASCIIToUTF16("bar"));
+ tags.insert(ASCIIToUTF16("baz"));
+
+ std::set<const BookmarkNode*> bookmarks;
+ bookmarks.insert(AddURLWithTags("foo", tags));
+ bookmarks.insert(AddURLWithTags("flou", tags));
+ ClearCounts();
+
+ std::set<BookmarkTag> new_tags;
+ new_tags.insert(ASCIIToUTF16("new_bar"));
+ new_tags.insert(ASCIIToUTF16("new_baz"));
+
+ tag_model_->AddTagsToBookmarks(new_tags, bookmarks);
+ AssertAndClearObserverCount(OBSERVER_COUNTS_BEFORE_TAG_CHANGE, 2);
+ AssertAndClearObserverCount(OBSERVER_COUNTS_TAG_CHANGE, 2);
+ AssertAllCountsClear();
+
+ std::vector<BookmarkTag> alltags(tag_model_->TagsRelatedToTag(
+ base::string16()));
+ EXPECT_EQ(4UL, alltags.size());
+}
+
+TEST_F(BookmarkTagModelTest, AddTagToBookmark) {
+ std::set<BookmarkTag> tags;
+ tags.insert(ASCIIToUTF16("bar"));
+ tags.insert(ASCIIToUTF16("baz"));
+
+ const BookmarkNode* bookmark = AddURLWithTags("foo", tags);
+ ClearCounts();
+
+ std::set<BookmarkTag> new_tags;
+ new_tags.insert(ASCIIToUTF16("new_bar"));
+ new_tags.insert(ASCIIToUTF16("new_baz"));
+
+ tag_model_->AddTagsToBookmark(new_tags, bookmark);
+ AssertAndClearObserverCount(OBSERVER_COUNTS_BEFORE_TAG_CHANGE, 1);
+ AssertAndClearObserverCount(OBSERVER_COUNTS_TAG_CHANGE, 1);
+ AssertAllCountsClear();
+
+ std::vector<BookmarkTag> alltags(tag_model_->TagsRelatedToTag(
+ base::string16()));
+ EXPECT_EQ(4UL, alltags.size());
+}
+
+TEST_F(BookmarkTagModelTest, RemoveTagFromBookmarks) {
+ std::set<BookmarkTag> tags;
+ tags.insert(ASCIIToUTF16("bar"));
+ tags.insert(ASCIIToUTF16("baz"));
+
+ std::set<const BookmarkNode*> bookmarks;
+
+ bookmarks.insert(AddURLWithTags("foo", tags));
+ bookmarks.insert(AddURLWithTags("flou", tags));
+ ClearCounts();
+
+ tag_model_->RemoveTagsFromBookmarks(tags, bookmarks);
+ AssertAndClearObserverCount(OBSERVER_COUNTS_BEFORE_TAG_CHANGE, 2);
+ AssertAndClearObserverCount(OBSERVER_COUNTS_TAG_CHANGE, 2);
+ AssertAllCountsClear();
+
+ std::vector<BookmarkTag> alltags(tag_model_->TagsRelatedToTag(
+ base::string16()));
+ EXPECT_EQ(0UL, alltags.size());
+}
+
+TEST_F(BookmarkTagModelTest, RemoveTagFromBookmark) {
+ std::set<BookmarkTag> tags;
+ tags.insert(ASCIIToUTF16("bar"));
+ tags.insert(ASCIIToUTF16("baz"));
+
+ const BookmarkNode* bookmark = AddURLWithTags("foo", tags);
+ ClearCounts();
+
+ tag_model_->RemoveTagsFromBookmark(tags, bookmark);
+ AssertAndClearObserverCount(OBSERVER_COUNTS_BEFORE_TAG_CHANGE, 1);
+ AssertAndClearObserverCount(OBSERVER_COUNTS_TAG_CHANGE, 1);
+ AssertAllCountsClear();
+
+ std::vector<BookmarkTag> alltags(tag_model_->TagsRelatedToTag(
+ base::string16()));
+ EXPECT_EQ(0UL, alltags.size());
+}
+
+TEST_F(BookmarkTagModelTest, RemoveAll) {
+ std::set<BookmarkTag> tags;
+ tags.insert(ASCIIToUTF16("bar"));
+ tags.insert(ASCIIToUTF16("baz"));
+
+ AddURLWithTags("foo", tags);
+ ClearCounts();
+
+ model_.RemoveAll();
+ AssertAndClearObserverCount(OBSERVER_COUNTS_EXTENSIVE_CHANGE_BEGIN, 1);
+ AssertAndClearObserverCount(OBSERVER_COUNTS_BEFORE_REMOVE_ALL, 1);
+ AssertAndClearObserverCount(OBSERVER_COUNTS_REMOVE_ALL, 1);
+ AssertAndClearObserverCount(OBSERVER_COUNTS_EXTENSIVE_CHANGE_END, 1);
+ AssertAllCountsClear();
+
+ std::vector<BookmarkTag> alltags(tag_model_->TagsRelatedToTag(
+ base::string16()));
+ EXPECT_EQ(0UL, alltags.size());
+}
+
+TEST_F(BookmarkTagModelTest, DuplicateFolders) {
+ const BookmarkNode* left = model_.AddFolder(model_.bookmark_bar_node(), 0,
+ ASCIIToUTF16("left"));
+ const BookmarkNode* right = model_.AddFolder(model_.bookmark_bar_node(), 0,
+ ASCIIToUTF16("right"));
+ const BookmarkNode* left_handed = model_.AddFolder(left, 0,
+ ASCIIToUTF16("handed"));
+ const BookmarkNode* right_handed = model_.AddFolder(right, 0,
+ ASCIIToUTF16("handed"));
+ model_.AddURL(
+ left_handed, 0, ASCIIToUTF16("red"), GURL("http://random.com"));
+ model_.AddURL(
+ right_handed, 0, ASCIIToUTF16("der"), GURL("http://random.com"));
+
+ EXPECT_EQ(2UL, tag_model_->BookmarksForTag(ASCIIToUTF16("handed")).size());
+ EXPECT_EQ(1UL, tag_model_->BookmarksForTag(ASCIIToUTF16("left")).size());
+ EXPECT_EQ(1UL, tag_model_->BookmarksForTag(ASCIIToUTF16("right")).size());
+ std::set<BookmarkTag> tags;
+ tags.insert(ASCIIToUTF16("left"));
+ tags.insert(ASCIIToUTF16("handed"));
+ EXPECT_EQ(1UL, tag_model_->BookmarksForTags(tags).size());
+}
+
+class PreloadedBookmarkTagModelTest : public BookmarkTagModelTest {
+ public:
+ PreloadedBookmarkTagModelTest() : BookmarkTagModelTest() {
+ PopulateUnderlyingModel();
+ }
+
+ void PopulateUnderlyingModel() {
+ ClearCounts();
+ top_node_ = model_.AddURL(model_.bookmark_bar_node(), 0,
+ ASCIIToUTF16("Tagless"), GURL("http://example.com"));
+ folder_1_ = model_.AddFolder(model_.bookmark_bar_node(), 0,
+ ASCIIToUTF16("folder1"));
+ one_tag_ = model_.AddURL(folder_1_, 0, ASCIIToUTF16("OneTag"),
+ GURL("http://random.com"));
+ folder_2_ = model_.AddFolder(folder_1_, 0, ASCIIToUTF16("folder2"));
+ two_tags_ = model_.AddURL(folder_2_, 0, ASCIIToUTF16("TwoTags"),
+ GURL("http://moveit.com"));
+ AssertAndClearObserverCount(OBSERVER_COUNTS_ADD, 3);
+ AssertAllCountsClear();
+ }
+
+ void AssertModelMatches() {
+ EXPECT_EQ(2UL, tag_model_->BookmarksForTag(ASCIIToUTF16("folder1")).size());
+ EXPECT_EQ(1UL, tag_model_->BookmarksForTag(ASCIIToUTF16("folder2")).size());
+
+ std::set<BookmarkTag> tags;
+ tags.insert(ASCIIToUTF16("folder1"));
+ EXPECT_EQ(tags, tag_model_->GetTagsForBookmark(one_tag_));
+
+ tags.insert(ASCIIToUTF16("folder2"));
+ const BookmarkNode* two_tags = tag_model_->
+ GetMostRecentlyAddedBookmarkForURL(GURL("http://moveit.com"));
+ EXPECT_EQ(tags, tag_model_->GetTagsForBookmark(two_tags));
+
+ std::vector<BookmarkTag> alltags(tag_model_->TagsRelatedToTag(
+ base::string16()));
+ EXPECT_EQ(2UL, alltags.size());
+ }
+
+ protected:
+ const BookmarkNode* folder_1_;
+ const BookmarkNode* folder_2_;
+ const BookmarkNode* top_node_;
+ const BookmarkNode* one_tag_;
+ const BookmarkNode* two_tags_;
+
+ DISALLOW_COPY_AND_ASSIGN(PreloadedBookmarkTagModelTest);
+};
+
+TEST_F(PreloadedBookmarkTagModelTest, InitialState) {
+ AssertAllCountsClear();
+ AssertModelMatches();
+}
+
+TEST_F(PreloadedBookmarkTagModelTest, FromExistingState) {
+ tag_model_.reset(new BookmarkTagModel(&model_));
+ tag_model_->AddObserver(this);
+ AssertAllCountsClear();
+ AssertModelMatches();
+}
+
+TEST_F(PreloadedBookmarkTagModelTest, BookmarkChange) {
+ AssertAllCountsClear();
+ tag_model_->SetTitle(top_node_, ASCIIToUTF16("newname"));
+ AssertAndClearObserverCount(OBSERVER_COUNTS_BEFORE_CHANGE, 1);
+ AssertAndClearObserverCount(OBSERVER_COUNTS_CHANGE, 1);
+ AssertAllCountsClear();
+}
+
+TEST_F(PreloadedBookmarkTagModelTest, UnchangedBookmarkMove) {
+ AssertAllCountsClear();
+ model_.Move(top_node_, folder_2_, 0);
+ AssertAndClearObserverCount(OBSERVER_COUNTS_BEFORE_TAG_CHANGE, 1);
+ AssertAndClearObserverCount(OBSERVER_COUNTS_TAG_CHANGE, 1);
+ AssertAllCountsClear();
+}
+
+TEST_F(PreloadedBookmarkTagModelTest, ChangedBookmarkMove) {
+ std::set<BookmarkTag> tags;
+ tags.insert(ASCIIToUTF16("bar"));
+
+ AssertAllCountsClear();
+ tag_model_->AddTagsToBookmark(tags, top_node_);
+ AssertAndClearObserverCount(OBSERVER_COUNTS_BEFORE_TAG_CHANGE, 1);
+ AssertAndClearObserverCount(OBSERVER_COUNTS_TAG_CHANGE, 1);
+ AssertAllCountsClear();
+
+ model_.Move(top_node_, folder_2_, 0);
+ AssertAllCountsClear();
+}
+
+TEST_F(PreloadedBookmarkTagModelTest, DuplicateBookmark) {
+ EXPECT_EQ(2UL, tag_model_->BookmarksForTag(folder_1_->GetTitle()).size());
+ model_.AddURL(folder_1_, 0, one_tag_->GetTitle(), one_tag_->url());
+ EXPECT_EQ(3UL, tag_model_->BookmarksForTag(folder_1_->GetTitle()).size());
+}
+
+TEST_F(PreloadedBookmarkTagModelTest, NamelessFolders) {
+ const BookmarkNode* folder = model_.AddFolder(model_.bookmark_bar_node(), 0,
+ ASCIIToUTF16(""));
+ model_.AddURL(folder, 0, ASCIIToUTF16("StillNotag"),
+ GURL("http://random.com"));
+ AssertModelMatches();
+}
+
+TEST_F(PreloadedBookmarkTagModelTest, FolderNameChange) {
+ EXPECT_EQ(2UL, tag_model_->BookmarksForTag(folder_1_->GetTitle()).size());
+ model_.SetTitle(folder_1_, ASCIIToUTF16("Bummer"));
+ AssertAndClearObserverCount(OBSERVER_COUNTS_EXTENSIVE_CHANGE_BEGIN, 1);
+ AssertAndClearObserverCount(OBSERVER_COUNTS_EXTENSIVE_CHANGE_END, 1);
+ AssertAndClearObserverCount(OBSERVER_COUNTS_BEFORE_TAG_CHANGE, 2);
+ AssertAndClearObserverCount(OBSERVER_COUNTS_TAG_CHANGE, 2);
+ AssertAllCountsClear();
+
+ EXPECT_EQ(2UL, tag_model_->BookmarksForTag(folder_1_->GetTitle()).size());
+}
+
+TEST_F(PreloadedBookmarkTagModelTest, FolderMoved) {
+ EXPECT_EQ(2UL, tag_model_->BookmarksForTag(folder_1_->GetTitle()).size());
+ model_.Move(folder_2_, model_.bookmark_bar_node(), 0);
+ AssertAndClearObserverCount(OBSERVER_COUNTS_EXTENSIVE_CHANGE_BEGIN, 1);
+ AssertAndClearObserverCount(OBSERVER_COUNTS_EXTENSIVE_CHANGE_END, 1);
+ AssertAndClearObserverCount(OBSERVER_COUNTS_BEFORE_TAG_CHANGE, 1);
+ AssertAndClearObserverCount(OBSERVER_COUNTS_TAG_CHANGE, 1);
+ AssertAllCountsClear();
+
+ EXPECT_EQ(1UL, tag_model_->BookmarksForTag(folder_1_->GetTitle()).size());
+}
+
+} // namespace
diff --git a/chrome/browser/browser_encoding_browsertest.cc b/chrome/browser/browser_encoding_browsertest.cc
index beca6a06af..1f7a289b16 100644
--- a/chrome/browser/browser_encoding_browsertest.cc
+++ b/chrome/browser/browser_encoding_browsertest.cc
@@ -221,7 +221,7 @@ IN_PROC_BROWSER_TEST_F(BrowserEncodingTest, TestOverrideEncoding) {
// http://crbug.com/2927 for more details.
//
// This test fails frequently on the win_rel trybot. See http://crbug.com/122053
-#if defined(OS_WIN) || defined(OS_MACOSX)
+#if defined(OS_WIN)
#define MAYBE_TestEncodingAutoDetect DISABLED_TestEncodingAutoDetect
#else
#define MAYBE_TestEncodingAutoDetect TestEncodingAutoDetect
diff --git a/chrome/browser/browser_keyevents_browsertest.cc b/chrome/browser/browser_keyevents_browsertest.cc
index 77f10c4783..0a2580839f 100644
--- a/chrome/browser/browser_keyevents_browsertest.cc
+++ b/chrome/browser/browser_keyevents_browsertest.cc
@@ -723,10 +723,8 @@ IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, MAYBE_ReservedAccelerators) {
// Reserved accelerators can't be suppressed.
ASSERT_NO_FATAL_FAILURE(SuppressAllEvents(1, true));
- content::WindowedNotificationObserver wait_for_tab_closed(
- content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
- content::Source<content::WebContents>(
- browser()->tab_strip_model()->GetWebContentsAt(1)));
+ content::WebContentsDestroyedWatcher destroyed_watcher(
+ browser()->tab_strip_model()->GetWebContentsAt(1));
// Press Ctrl/Cmd+W, which will close the tab.
#if defined(OS_MACOSX)
@@ -737,7 +735,7 @@ IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, MAYBE_ReservedAccelerators) {
browser(), ui::VKEY_W, true, false, false, false));
#endif
- ASSERT_NO_FATAL_FAILURE(wait_for_tab_closed.Wait());
+ ASSERT_NO_FATAL_FAILURE(destroyed_watcher.Wait());
EXPECT_EQ(1, browser()->tab_strip_model()->count());
}
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index 6825a2e2ec..51abfe83a5 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -373,9 +373,12 @@ void BrowserProcessImpl::EndSession() {
MetricsService* metrics = g_browser_process->metrics_service();
if (metrics && local_state()) {
metrics->RecordStartOfSessionEnd();
-
+#if !defined(OS_CHROMEOS)
// MetricsService lazily writes to prefs, force it to write now.
+ // On ChromeOS, chrome gets killed when hangs, so no need to
+ // commit prefs::kStabilitySessionEndCompleted change immediately.
local_state()->CommitPendingWrite();
+#endif
}
// http://crbug.com/125207
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 346fdb3d12..e45cef652c 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -70,6 +70,7 @@
</if>
<structure name="IDR_READER_OUT_OF_DATE_HTML" file="resources\reader_out_of_date.html" flattenhtml="true" type="chrome_html" />
<structure name="IDR_SSL_ROAD_BLOCK_HTML" file="resources\ssl\roadblock.html" flattenhtml="true" type="chrome_html" />
+ <structure name="IDR_SSL_BLOCKING_HTML" file="resources\ssl\blocking.html" flattenhtml="true" type="chrome_html" />
<structure name="IDR_SAFE_BROWSING_MALWARE_BLOCK_V2" file="resources\safe_browsing\malware_block_v2.html" flattenhtml="true" type="chrome_html" />
</structures>
<includes>
diff --git a/chrome/browser/captive_portal/captive_portal_tab_helper.cc b/chrome/browser/captive_portal/captive_portal_tab_helper.cc
index 46c9af173a..d28f275395 100644
--- a/chrome/browser/captive_portal/captive_portal_tab_helper.cc
+++ b/chrome/browser/captive_portal/captive_portal_tab_helper.cc
@@ -98,6 +98,7 @@ void CaptivePortalTabHelper::DidStartProvisionalLoadForFrame(
void CaptivePortalTabHelper::DidCommitProvisionalLoadForFrame(
int64 frame_id,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& url,
content::PageTransition transition_type,
@@ -127,6 +128,7 @@ void CaptivePortalTabHelper::DidCommitProvisionalLoadForFrame(
void CaptivePortalTabHelper::DidFailProvisionalLoad(
int64 frame_id,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& validated_url,
int error_code,
diff --git a/chrome/browser/captive_portal/captive_portal_tab_helper.h b/chrome/browser/captive_portal/captive_portal_tab_helper.h
index dec16d2a64..5e0a989df3 100644
--- a/chrome/browser/captive_portal/captive_portal_tab_helper.h
+++ b/chrome/browser/captive_portal/captive_portal_tab_helper.h
@@ -79,6 +79,7 @@ class CaptivePortalTabHelper
virtual void DidCommitProvisionalLoadForFrame(
int64 frame_id,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& url,
content::PageTransition transition_type,
@@ -86,6 +87,7 @@ class CaptivePortalTabHelper
virtual void DidFailProvisionalLoad(
int64 frame_id,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& validated_url,
int error_code,
diff --git a/chrome/browser/captive_portal/captive_portal_tab_helper_unittest.cc b/chrome/browser/captive_portal/captive_portal_tab_helper_unittest.cc
index 39c081a051..c4c156d9df 100644
--- a/chrome/browser/captive_portal/captive_portal_tab_helper_unittest.cc
+++ b/chrome/browser/captive_portal/captive_portal_tab_helper_unittest.cc
@@ -91,7 +91,8 @@ class CaptivePortalTabHelperTest : public ChromeRenderViewHostTestHarness {
EXPECT_CALL(mock_reloader(), OnLoadCommitted(net::OK)).Times(1);
tab_helper().DidCommitProvisionalLoadForFrame(
- 1, true, url, content::PAGE_TRANSITION_LINK, render_view_host);
+ 1, string16(), true, url, content::PAGE_TRANSITION_LINK,
+ render_view_host);
}
// Simulates a connection timeout while requesting |url|.
@@ -102,7 +103,8 @@ class CaptivePortalTabHelperTest : public ChromeRenderViewHostTestHarness {
1, -1, true, url, false, false, render_view_host);
tab_helper().DidFailProvisionalLoad(
- 1, true, url, net::ERR_TIMED_OUT, string16(), render_view_host);
+ 1, string16(), true, url, net::ERR_TIMED_OUT, string16(),
+ render_view_host);
// Provisional load starts for the error page.
tab_helper().DidStartProvisionalLoadForFrame(
@@ -110,7 +112,7 @@ class CaptivePortalTabHelperTest : public ChromeRenderViewHostTestHarness {
EXPECT_CALL(mock_reloader(), OnLoadCommitted(net::ERR_TIMED_OUT)).Times(1);
tab_helper().DidCommitProvisionalLoadForFrame(
- 1, true, GURL(kErrorPageUrl), content::PAGE_TRANSITION_LINK,
+ 1, string16(), true, GURL(kErrorPageUrl), content::PAGE_TRANSITION_LINK,
render_view_host);
}
@@ -125,7 +127,8 @@ class CaptivePortalTabHelperTest : public ChromeRenderViewHostTestHarness {
EXPECT_CALL(mock_reloader(), OnAbort()).Times(1);
if (navigation_type == kSameProcess) {
tab_helper().DidFailProvisionalLoad(
- 1, true, url, net::ERR_ABORTED, string16(), render_view_host);
+ 1, string16(), true, url, net::ERR_ABORTED, string16(),
+ render_view_host);
} else {
// For interrupted provisional cross-process navigations, the
// RenderViewHost is destroyed without sending a DidFailProvisionalLoad
@@ -147,7 +150,8 @@ class CaptivePortalTabHelperTest : public ChromeRenderViewHostTestHarness {
1, -1, true, url, false, false, render_view_host);
tab_helper().DidFailProvisionalLoad(
- 1, true, url, net::ERR_TIMED_OUT, string16(), render_view_host);
+ 1, string16(), true, url, net::ERR_TIMED_OUT, string16(),
+ render_view_host);
// Start event for the error page.
tab_helper().DidStartProvisionalLoadForFrame(
@@ -156,7 +160,8 @@ class CaptivePortalTabHelperTest : public ChromeRenderViewHostTestHarness {
EXPECT_CALL(mock_reloader(), OnAbort()).Times(1);
if (navigation_type == kSameProcess) {
tab_helper().DidFailProvisionalLoad(
- 1, true, url, net::ERR_ABORTED, string16(), render_view_host);
+ 1, string16(), true, url, net::ERR_ABORTED, string16(),
+ render_view_host);
} else {
// For interrupted provisional cross-process navigations, the
// RenderViewHost is destroyed without sending a DidFailProvisionalLoad
@@ -244,7 +249,7 @@ TEST_F(CaptivePortalTabHelperTest, HttpTimeoutLinkDoctor) {
EXPECT_CALL(mock_reloader(), OnLoadCommitted(net::OK)).Times(1);
tab_helper().DidCommitProvisionalLoadForFrame(
- 1, true, GURL(kErrorPageUrl), content::PAGE_TRANSITION_LINK,
+ 1, string16(), true, GURL(kErrorPageUrl), content::PAGE_TRANSITION_LINK,
render_view_host1());
tab_helper().DidStopLoading(render_view_host1());
}
@@ -327,12 +332,12 @@ TEST_F(CaptivePortalTabHelperTest, UnexpectedProvisionalLoad) {
// The cross-process navigation fails.
tab_helper().DidFailProvisionalLoad(
- 1, true, cross_process_url, net::ERR_FAILED, string16(),
+ 1, string16(), true, cross_process_url, net::ERR_FAILED, string16(),
render_view_host2());
// The same-site navigation finally is aborted.
tab_helper().DidFailProvisionalLoad(
- 1, true, same_site_url, net::ERR_ABORTED, string16(),
+ 1, string16(), true, same_site_url, net::ERR_ABORTED, string16(),
render_view_host1());
// The provisional load starts for the error page for the cross-process
@@ -342,7 +347,7 @@ TEST_F(CaptivePortalTabHelperTest, UnexpectedProvisionalLoad) {
EXPECT_CALL(mock_reloader(), OnLoadCommitted(net::ERR_FAILED)).Times(1);
tab_helper().DidCommitProvisionalLoadForFrame(
- 1, true, GURL(kErrorPageUrl), content::PAGE_TRANSITION_TYPED,
+ 1, string16(), true, GURL(kErrorPageUrl), content::PAGE_TRANSITION_TYPED,
render_view_host2());
}
@@ -369,7 +374,7 @@ TEST_F(CaptivePortalTabHelperTest, UnexpectedCommit) {
// The cross-process navigation fails.
tab_helper().DidFailProvisionalLoad(
- 1, true, cross_process_url, net::ERR_FAILED, string16(),
+ 1, string16(), true, cross_process_url, net::ERR_FAILED, string16(),
render_view_host2());
// The same-site navigation succeeds.
@@ -378,7 +383,7 @@ TEST_F(CaptivePortalTabHelperTest, UnexpectedCommit) {
OnLoadStart(same_site_url.SchemeIsSecure())).Times(1);
EXPECT_CALL(mock_reloader(), OnLoadCommitted(net::OK)).Times(1);
tab_helper().DidCommitProvisionalLoadForFrame(
- 1, true, same_site_url, content::PAGE_TRANSITION_LINK,
+ 1, string16(), true, same_site_url, content::PAGE_TRANSITION_LINK,
render_view_host1());
}
@@ -390,23 +395,27 @@ TEST_F(CaptivePortalTabHelperTest, HttpsSubframe) {
tab_helper().DidStartProvisionalLoadForFrame(
1, -1, false, url, false, false, render_view_host1());
tab_helper().DidCommitProvisionalLoadForFrame(
- 1, false, url, content::PAGE_TRANSITION_LINK, render_view_host1());
+ 1, string16(), false, url, content::PAGE_TRANSITION_LINK,
+ render_view_host1());
// Timeout.
tab_helper().DidStartProvisionalLoadForFrame(
2, -1, false, url, false, false, render_view_host1());
tab_helper().DidFailProvisionalLoad(
- 2, false, url, net::ERR_TIMED_OUT, string16(), render_view_host1());
+ 2, string16(), false, url, net::ERR_TIMED_OUT, string16(),
+ render_view_host1());
tab_helper().DidStartProvisionalLoadForFrame(
2, -1, false, url, true, false, render_view_host1());
tab_helper().DidFailProvisionalLoad(
- 2, false, url, net::ERR_ABORTED, string16(), render_view_host1());
+ 2, string16(), false, url, net::ERR_ABORTED, string16(),
+ render_view_host1());
// Abort.
tab_helper().DidStartProvisionalLoadForFrame(
3, -1, false, url, false, false, render_view_host1());
tab_helper().DidFailProvisionalLoad(
- 3, false, url, net::ERR_ABORTED, string16(), render_view_host1());
+ 3, string16(), false, url, net::ERR_ABORTED, string16(),
+ render_view_host1());
}
// Simulates a subframe erroring out at the same time as a provisional load,
@@ -428,10 +437,10 @@ TEST_F(CaptivePortalTabHelperTest, HttpsSubframeParallelError) {
// Loads return errors.
tab_helper().DidFailProvisionalLoad(
- frame_id, true, url, net::ERR_UNEXPECTED, string16(),
+ frame_id, string16(), true, url, net::ERR_UNEXPECTED, string16(),
render_view_host1());
tab_helper().DidFailProvisionalLoad(
- subframe_id, false, url, net::ERR_TIMED_OUT, string16(),
+ subframe_id, string16(), false, url, net::ERR_TIMED_OUT, string16(),
render_view_host1());
// Provisional load starts for the error pages.
@@ -442,11 +451,11 @@ TEST_F(CaptivePortalTabHelperTest, HttpsSubframeParallelError) {
// Error page load finishes.
tab_helper().DidCommitProvisionalLoadForFrame(
- subframe_id, false, url, content::PAGE_TRANSITION_AUTO_SUBFRAME,
- render_view_host1());
+ subframe_id, string16(), false, url,
+ content::PAGE_TRANSITION_AUTO_SUBFRAME, render_view_host1());
EXPECT_CALL(mock_reloader(), OnLoadCommitted(net::ERR_UNEXPECTED)).Times(1);
tab_helper().DidCommitProvisionalLoadForFrame(
- frame_id, true, url, content::PAGE_TRANSITION_LINK,
+ frame_id, string16(), true, url, content::PAGE_TRANSITION_LINK,
render_view_host1());
}
@@ -463,7 +472,7 @@ TEST_F(CaptivePortalTabHelperTest, HttpToHttpsRedirectTimeout) {
render_view_host1()->GetProcess()->GetID());
tab_helper().DidFailProvisionalLoad(
- 1, true, https_url, net::ERR_TIMED_OUT, string16(),
+ 1, string16(), true, https_url, net::ERR_TIMED_OUT, string16(),
render_view_host1());
// Provisional load starts for the error page.
@@ -472,7 +481,7 @@ TEST_F(CaptivePortalTabHelperTest, HttpToHttpsRedirectTimeout) {
EXPECT_CALL(mock_reloader(), OnLoadCommitted(net::ERR_TIMED_OUT)).Times(1);
tab_helper().DidCommitProvisionalLoadForFrame(
- 1, true, GURL(kErrorPageUrl), content::PAGE_TRANSITION_LINK,
+ 1, string16(), true, GURL(kErrorPageUrl), content::PAGE_TRANSITION_LINK,
render_view_host1());
}
@@ -491,7 +500,7 @@ TEST_F(CaptivePortalTabHelperTest, HttpsToHttpRedirect) {
EXPECT_CALL(mock_reloader(), OnLoadCommitted(net::OK)).Times(1);
tab_helper().DidCommitProvisionalLoadForFrame(
- 1, true, http_url, content::PAGE_TRANSITION_LINK,
+ 1, string16(), true, http_url, content::PAGE_TRANSITION_LINK,
render_view_host1());
}
@@ -509,7 +518,7 @@ TEST_F(CaptivePortalTabHelperTest, HttpToHttpRedirect) {
EXPECT_CALL(mock_reloader(), OnLoadCommitted(net::OK)).Times(1);
tab_helper().DidCommitProvisionalLoadForFrame(
- 1, true, http_url, content::PAGE_TRANSITION_LINK,
+ 1, string16(), true, http_url, content::PAGE_TRANSITION_LINK,
render_view_host1());
}
@@ -526,7 +535,7 @@ TEST_F(CaptivePortalTabHelperTest, SubframeRedirect) {
EXPECT_CALL(mock_reloader(), OnLoadCommitted(net::OK)).Times(1);
tab_helper().DidCommitProvisionalLoadForFrame(
- 1, true, GURL(kErrorPageUrl), content::PAGE_TRANSITION_LINK,
+ 1, string16(), true, GURL(kErrorPageUrl), content::PAGE_TRANSITION_LINK,
render_view_host1());
}
@@ -544,7 +553,7 @@ TEST_F(CaptivePortalTabHelperTest, OtherRenderViewHostRedirect) {
render_view_host2()->GetProcess()->GetID());
tab_helper().DidFailProvisionalLoad(
- 1, true, https_url, net::ERR_TIMED_OUT, string16(),
+ 1, string16(), true, https_url, net::ERR_TIMED_OUT, string16(),
render_view_host1());
// Provisional load starts for the error page.
@@ -553,7 +562,7 @@ TEST_F(CaptivePortalTabHelperTest, OtherRenderViewHostRedirect) {
EXPECT_CALL(mock_reloader(), OnLoadCommitted(net::ERR_TIMED_OUT)).Times(1);
tab_helper().DidCommitProvisionalLoadForFrame(
- 1, true, GURL(kErrorPageUrl), content::PAGE_TRANSITION_LINK,
+ 1, string16(), true, GURL(kErrorPageUrl), content::PAGE_TRANSITION_LINK,
render_view_host1());
}
diff --git a/chrome/browser/certificate_viewer.h b/chrome/browser/certificate_viewer.h
index 940ab15b91..9b31e02213 100644
--- a/chrome/browser/certificate_viewer.h
+++ b/chrome/browser/certificate_viewer.h
@@ -12,10 +12,8 @@ class WebContents;
}
namespace net {
-
class X509Certificate;
-
-} // namespace net
+}
// Opens a certificate viewer under |parent| to display the certificate from
// the |CertStore| with id |cert_id|.
diff --git a/chrome/browser/chrome_browser_field_trials.cc b/chrome/browser/chrome_browser_field_trials.cc
index 19a69f63f8..c22f495020 100644
--- a/chrome/browser/chrome_browser_field_trials.cc
+++ b/chrome/browser/chrome_browser_field_trials.cc
@@ -59,6 +59,7 @@ void ChromeBrowserFieldTrials::InstantiateDynamicTrials() {
base::FieldTrialList::FindValue("Test0PercentDefault");
// The following trials are used from renderer process.
// Mark here so they will be sync-ed.
+ base::FieldTrialList::FindValue("CLD1VsCLD2");
base::FieldTrialList::FindValue("DateExtensionEnabled");
base::FieldTrialList::FindValue("MouseEventPreconnect");
// Activate the autocomplete dynamic field trials.
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index 47e8c9e7e4..0e14596fc4 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -53,7 +53,7 @@
#include "chrome/browser/defaults.h"
#include "chrome/browser/extensions/extension_protocols.h"
#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/message_handler.h"
+#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/extensions/startup_helper.h"
#include "chrome/browser/first_run/first_run.h"
#include "chrome/browser/first_run/upgrade_util.h"
@@ -71,6 +71,7 @@
#include "chrome/browser/metrics/tracking_synchronizer.h"
#include "chrome/browser/metrics/variations/variations_http_header_provider.h"
#include "chrome/browser/metrics/variations/variations_service.h"
+#include "chrome/browser/nacl_host/nacl_browser.h"
#include "chrome/browser/nacl_host/nacl_browser_delegate_impl.h"
#include "chrome/browser/nacl_host/nacl_process_host.h"
#include "chrome/browser/net/chrome_net_log.h"
@@ -91,7 +92,6 @@
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/profiles/profiles_state.h"
-#include "chrome/browser/renderer_host/chrome_render_view_host_observer.h"
#include "chrome/browser/service/service_process_control.h"
#include "chrome/browser/shell_integration.h"
#include "chrome/browser/three_d_api_observer.h"
@@ -381,6 +381,12 @@ void RegisterComponentsForUpdate(const CommandLine& command_line) {
RegisterRecoveryComponent(cus, g_browser_process->local_state());
RegisterPepperFlashComponent(cus);
RegisterSwiftShaderComponent(cus);
+#endif
+
+ g_browser_process->pnacl_component_installer()->RegisterPnaclComponent(
+ cus, command_line);
+
+#if !defined(OS_CHROMEOS)
RegisterWidevineCdmComponent(cus);
// CRLSetFetcher attempts to load a CRL set from either the local disk or
@@ -389,9 +395,6 @@ void RegisterComponentsForUpdate(const CommandLine& command_line) {
g_browser_process->crl_set_fetcher()->StartInitialLoad(cus);
#endif
- g_browser_process->pnacl_component_installer()->RegisterPnaclComponent(
- cus, command_line);
-
cus->Start();
}
@@ -500,17 +503,6 @@ class LoadCompleteListener : public content::NotificationObserver {
DISALLOW_COPY_AND_ASSIGN(LoadCompleteListener);
};
-void RenderViewHostCreated(content::RenderViewHost* render_view_host) {
- content::SiteInstance* site_instance = render_view_host->GetSiteInstance();
- Profile* profile = Profile::FromBrowserContext(
- site_instance->GetBrowserContext());
-
- new ChromeRenderViewHostObserver(render_view_host,
- profile->GetNetworkPredictor());
- new extensions::MessageHandler(render_view_host);
-}
-
-
} // namespace
namespace chrome_browser {
@@ -536,7 +528,6 @@ ChromeBrowserMainParts::ChromeBrowserMainParts(
shutdown_watcher_(new ShutdownWatcherHelper()),
startup_timer_(new performance_monitor::StartupTimer()),
browser_field_trials_(parameters.command_line),
- rvh_callback_(base::Bind(&RenderViewHostCreated)),
translate_manager_(NULL),
profile_(NULL),
run_message_loop_(true),
@@ -552,13 +543,9 @@ ChromeBrowserMainParts::ChromeBrowserMainParts(
// a ChromeNetworkDelegate attached that selectively allows cookies again.
if (!disable_enforcing_cookie_policies_for_tests_)
net::URLRequest::SetDefaultCookiePolicyToBlock();
-
- content::RenderViewHost::AddCreatedCallback(rvh_callback_);
}
ChromeBrowserMainParts::~ChromeBrowserMainParts() {
- content::RenderViewHost::RemoveCreatedCallback(rvh_callback_);
-
for (int i = static_cast<int>(chrome_extra_parts_.size())-1; i >= 0; --i)
delete chrome_extra_parts_[i];
chrome_extra_parts_.clear();
@@ -1274,6 +1261,14 @@ int ChromeBrowserMainParts::PreMainMessageLoopRunImpl() {
content::WebUIControllerFactory::RegisterFactory(
ChromeWebUIControllerFactory::GetInstance());
+ // NaClBrowserDelegateImpl is accessed inside PostProfileInit().
+ // So make sure to create it before that.
+#if !defined(DISABLE_NACL)
+ NaClBrowserDelegateImpl* delegate = new NaClBrowserDelegateImpl(
+ extensions::ExtensionSystem::Get(profile_)->info_map());
+ NaClBrowser::SetDelegate(delegate);
+#endif
+
// TODO(stevenjb): Move WIN and MACOSX specific code to appropriate Parts.
// (requires supporting early exit).
PostProfileInit();
@@ -1440,7 +1435,11 @@ int ChromeBrowserMainParts::PreMainMessageLoopRunImpl() {
parsed_command_line().GetSwitchValuePath(
switches::kPnaclDir));
}
- NaClProcessHost::EarlyStartup(new NaClBrowserDelegateImpl);
+
+ content::BrowserThread::PostTask(
+ content::BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(NaClProcessHost::EarlyStartup));
#endif
// Make sure initial prefs are recorded
diff --git a/chrome/browser/chrome_browser_main.h b/chrome/browser/chrome_browser_main.h
index 22c4526bd9..cf5cd7aee3 100644
--- a/chrome/browser/chrome_browser_main.h
+++ b/chrome/browser/chrome_browser_main.h
@@ -16,7 +16,6 @@
#include "chrome/browser/task_profiler/auto_tracking.h"
#include "chrome/browser/ui/startup/startup_browser_creator.h"
#include "content/public/browser/browser_main_parts.h"
-#include "content/public/browser/render_view_host.h"
#include "content/public/common/main_function_params.h"
class ActiveTabTracker;
@@ -154,8 +153,6 @@ class ChromeBrowserMainParts : public content::BrowserMainParts {
ChromeBrowserFieldTrials browser_field_trials_;
- content::RenderViewHost::CreatedCallback rvh_callback_;
-
// Vector of additional ChromeBrowserMainExtraParts.
// Parts are deleted in the inverse order they are added.
std::vector<ChromeBrowserMainExtraParts*> chrome_extra_parts_;
diff --git a/chrome/browser/chrome_browser_main_android.cc b/chrome/browser/chrome_browser_main_android.cc
index bf96e89768..0acfb7ed5c 100644
--- a/chrome/browser/chrome_browser_main_android.cc
+++ b/chrome/browser/chrome_browser_main_android.cc
@@ -8,9 +8,10 @@
#include "base/debug/trace_event.h"
#include "base/path_service.h"
#include "cc/base/switches.h"
-#include "chrome/app/breakpad_linux.h"
-#include "chrome/browser/android/crash_dump_manager.h"
+#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
+#include "components/breakpad/app/breakpad_linux.h"
+#include "components/breakpad/browser/crash_dump_manager_android.h"
#include "content/public/browser/android/compositor.h"
#include "content/public/common/main_function_params.h"
#include "net/android/network_change_notifier_factory_android.h"
@@ -43,8 +44,10 @@ void ChromeBrowserMainPartsAndroid::PreProfileInit() {
switches::kEnableCrashReporterForTesting);
if (breakpad_enabled) {
- InitCrashReporter();
- crash_dump_manager_.reset(new CrashDumpManager());
+ breakpad::InitCrashReporter();
+ base::FilePath crash_dump_dir;
+ PathService::Get(chrome::DIR_CRASH_DUMPS, &crash_dump_dir);
+ crash_dump_manager_.reset(new breakpad::CrashDumpManager(crash_dump_dir));
}
ChromeBrowserMainParts::PreProfileInit();
diff --git a/chrome/browser/chrome_browser_main_android.h b/chrome/browser/chrome_browser_main_android.h
index b498db5113..a7f31a9327 100644
--- a/chrome/browser/chrome_browser_main_android.h
+++ b/chrome/browser/chrome_browser_main_android.h
@@ -7,7 +7,9 @@
#include "chrome/browser/chrome_browser_main.h"
+namespace breakpad {
class CrashDumpManager;
+}
class ChromeBrowserMainPartsAndroid : public ChromeBrowserMainParts {
public:
@@ -24,7 +26,7 @@ class ChromeBrowserMainPartsAndroid : public ChromeBrowserMainParts {
private:
scoped_ptr<base::MessageLoop> main_message_loop_;
- scoped_ptr<CrashDumpManager> crash_dump_manager_;
+ scoped_ptr<breakpad::CrashDumpManager> crash_dump_manager_;
DISALLOW_COPY_AND_ASSIGN(ChromeBrowserMainPartsAndroid);
};
diff --git a/chrome/browser/chrome_browser_main_linux.cc b/chrome/browser/chrome_browser_main_linux.cc
index 5e0cf2a0a6..835afa4ac1 100644
--- a/chrome/browser/chrome_browser_main_linux.cc
+++ b/chrome/browser/chrome_browser_main_linux.cc
@@ -9,12 +9,12 @@
#include "base/command_line.h"
#include "base/linux_util.h"
#include "base/prefs/pref_service.h"
-#include "chrome/app/breakpad_linux.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/metrics/metrics_service.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/env_vars.h"
#include "chrome/common/pref_names.h"
+#include "components/breakpad/app/breakpad_linux.h"
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/settings/cros_settings.h"
@@ -122,7 +122,7 @@ void ChromeBrowserMainPartsLinux::PreProfileInit() {
#endif
if (IsCrashReportingEnabled(local_state()))
- InitCrashReporter();
+ breakpad::InitCrashReporter();
ChromeBrowserMainPartsPosix::PreProfileInit();
}
@@ -131,5 +131,5 @@ void ChromeBrowserMainPartsLinux::PostProfileInit() {
ChromeBrowserMainPartsPosix::PostProfileInit();
g_browser_process->metrics_service()->RecordBreakpadRegistration(
- IsCrashReporterEnabled());
+ breakpad::IsCrashReporterEnabled());
}
diff --git a/chrome/browser/chrome_browser_main_mac.mm b/chrome/browser/chrome_browser_main_mac.mm
index 98b225e020..1cea6afb96 100644
--- a/chrome/browser/chrome_browser_main_mac.mm
+++ b/chrome/browser/chrome_browser_main_mac.mm
@@ -23,7 +23,7 @@
#include "chrome/browser/metrics/metrics_service.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
-#include "components/breakpad/breakpad_mac.h"
+#include "components/breakpad/app/breakpad_mac.h"
#include "content/public/common/main_function_params.h"
#include "content/public/common/result_codes.h"
#include "ui/base/l10n/l10n_util_mac.h"
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 49fe6b1d5b..e4347f8edd 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -48,6 +48,8 @@
#include "chrome/browser/guestview/webview/webview_guest.h"
#include "chrome/browser/media/media_capture_devices_dispatcher.h"
#include "chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.h"
+#include "chrome/browser/nacl_host/nacl_browser.h"
+#include "chrome/browser/nacl_host/nacl_browser_delegate_impl.h"
#include "chrome/browser/nacl_host/nacl_host_message_filter.h"
#include "chrome/browser/nacl_host/nacl_process_host.h"
#include "chrome/browser/net/chrome_net_log.h"
@@ -91,6 +93,7 @@
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/env_vars.h"
#include "chrome/common/extensions/background_info.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_process_policy.h"
@@ -149,7 +152,7 @@
#elif defined(OS_MACOSX)
#include "chrome/browser/chrome_browser_main_mac.h"
#include "chrome/browser/spellchecker/spellcheck_message_filter_mac.h"
-#include "components/breakpad/breakpad_mac.h"
+#include "components/breakpad/app/breakpad_mac.h"
#elif defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/chrome_browser_main_chromeos.h"
#include "chrome/browser/chromeos/drive/file_system_backend_delegate.h"
@@ -161,19 +164,20 @@
#elif defined(OS_LINUX)
#include "chrome/browser/chrome_browser_main_linux.h"
#elif defined(OS_ANDROID)
-#include "chrome/browser/android/crash_dump_manager.h"
#include "chrome/browser/android/webapps/single_tab_mode_tab_helper.h"
#include "chrome/browser/chrome_browser_main_android.h"
#include "chrome/browser/media/encrypted_media_message_filter_android.h"
#include "chrome/common/descriptors_android.h"
+#include "components/breakpad/browser/crash_dump_manager_android.h"
#elif defined(OS_POSIX)
#include "chrome/browser/chrome_browser_main_posix.h"
#endif
#if defined(OS_POSIX) && !defined(OS_MACOSX)
+#include "base/debug/leak_annotations.h"
#include "base/linux_util.h"
-#include "chrome/app/breakpad_linux.h"
-#include "chrome/browser/crash_handler_host_linux.h"
+#include "components/breakpad/app/breakpad_linux.h"
+#include "components/breakpad/browser/crash_handler_host_linux.h"
#endif
#if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
@@ -182,6 +186,7 @@
#if defined(OS_ANDROID)
#include "ui/base/ui_base_paths.h"
+#include "ui/gfx/android/device_display_info.h"
#endif
#if defined(USE_NSS)
@@ -250,10 +255,6 @@ using extensions::Extension;
using extensions::Manifest;
using message_center::NotifierId;
-#if defined(OS_MACOSX)
-using breakpad::IsCrashReporterEnabled;
-#endif
-
namespace {
// Cached version of the locale so we can return the locale on the I/O
@@ -479,6 +480,8 @@ bool CertMatchesFilter(const net::X509Certificate& cert,
void FillFontFamilyMap(const PrefService* prefs,
const char* map_name,
webkit_glue::ScriptFontFamilyMap* map) {
+ // TODO: Get rid of the brute-force scan over possible (font family / script)
+ // combinations - see http://crbug.com/308095.
for (size_t i = 0; i < prefs::kWebKitScriptsForFontFamilyMapsLength; ++i) {
const char* script = prefs::kWebKitScriptsForFontFamilyMaps[i];
std::string pref_name = base::StringPrintf("%s.%s", map_name, script);
@@ -489,27 +492,58 @@ void FillFontFamilyMap(const PrefService* prefs,
}
#if defined(OS_POSIX) && !defined(OS_MACOSX)
+breakpad::CrashHandlerHostLinux* CreateCrashHandlerHost(
+ const std::string& process_type) {
+ base::FilePath dumps_path;
+ PathService::Get(chrome::DIR_CRASH_DUMPS, &dumps_path);
+ {
+ ANNOTATE_SCOPED_MEMORY_LEAK;
+ breakpad::CrashHandlerHostLinux* crash_handler =
+ new breakpad::CrashHandlerHostLinux(
+ process_type, dumps_path, getenv(env_vars::kHeadless) == NULL);
+ crash_handler->StartUploaderThread();
+ return crash_handler;
+ }
+}
+
int GetCrashSignalFD(const CommandLine& command_line) {
if (command_line.HasSwitch(switches::kExtensionProcess)) {
- ExtensionCrashHandlerHostLinux* crash_handler =
- ExtensionCrashHandlerHostLinux::GetInstance();
+ static breakpad::CrashHandlerHostLinux* crash_handler = NULL;
+ if (!crash_handler)
+ crash_handler = CreateCrashHandlerHost("extension");
return crash_handler->GetDeathSignalSocket();
}
std::string process_type =
command_line.GetSwitchValueASCII(switches::kProcessType);
- if (process_type == switches::kRendererProcess)
- return RendererCrashHandlerHostLinux::GetInstance()->GetDeathSignalSocket();
+ if (process_type == switches::kRendererProcess) {
+ static breakpad::CrashHandlerHostLinux* crash_handler = NULL;
+ if (!crash_handler)
+ crash_handler = CreateCrashHandlerHost(process_type);
+ return crash_handler->GetDeathSignalSocket();
+ }
- if (process_type == switches::kPluginProcess)
- return PluginCrashHandlerHostLinux::GetInstance()->GetDeathSignalSocket();
+ if (process_type == switches::kPluginProcess) {
+ static breakpad::CrashHandlerHostLinux* crash_handler = NULL;
+ if (!crash_handler)
+ crash_handler = CreateCrashHandlerHost(process_type);
+ return crash_handler->GetDeathSignalSocket();
+ }
- if (process_type == switches::kPpapiPluginProcess)
- return PpapiCrashHandlerHostLinux::GetInstance()->GetDeathSignalSocket();
+ if (process_type == switches::kPpapiPluginProcess) {
+ static breakpad::CrashHandlerHostLinux* crash_handler = NULL;
+ if (!crash_handler)
+ crash_handler = CreateCrashHandlerHost(process_type);
+ return crash_handler->GetDeathSignalSocket();
+ }
- if (process_type == switches::kGpuProcess)
- return GpuCrashHandlerHostLinux::GetInstance()->GetDeathSignalSocket();
+ if (process_type == switches::kGpuProcess) {
+ static breakpad::CrashHandlerHostLinux* crash_handler = NULL;
+ if (!crash_handler)
+ crash_handler = CreateCrashHandlerHost(process_type);
+ return crash_handler->GetDeathSignalSocket();
+ }
return -1;
}
@@ -549,6 +583,7 @@ void HandleBlockedPopupOnUIThread(const BlockedWindowParams& params) {
}
#if defined(OS_ANDROID)
+
void HandleSingleTabModeBlockOnUIThread(const BlockedWindowParams& params) {
WebContents* web_contents =
tab_util::GetWebContentsByID(params.render_process_id(),
@@ -558,6 +593,33 @@ void HandleSingleTabModeBlockOnUIThread(const BlockedWindowParams& params) {
SingleTabModeTabHelper::FromWebContents(web_contents)->HandleOpenUrl(params);
}
+
+float GetFontScaleMultiplier(const PrefService* prefs) {
+ if (prefs->GetBoolean(prefs::kWebKitFontScaleFactorQuirk)) {
+ // The value of kWebKitFontScaleFactor passed by Chrome for Android already
+ // includes the multiplier.
+ return 1.0f;
+ }
+
+ static const float kMinFSM = 1.05f;
+ static const int kWidthForMinFSM = 320;
+ static const float kMaxFSM = 1.3f;
+ static const int kWidthForMaxFSM = 800;
+
+ gfx::DeviceDisplayInfo info;
+ int minWidth = info.GetSmallestDIPWidth();
+
+ if (minWidth <= kWidthForMinFSM)
+ return kMinFSM;
+ if (minWidth >= kWidthForMaxFSM)
+ return kMaxFSM;
+
+ // The font scale multiplier varies linearly between kMinFSM and kMaxFSM.
+ float ratio = static_cast<float>(minWidth - kWidthForMinFSM) /
+ (kWidthForMaxFSM - kWidthForMinFSM);
+ return ratio * (kMaxFSM - kMinFSM) + kMinFSM;
+}
+
#endif // defined(OS_ANDROID)
} // namespace
@@ -863,17 +925,15 @@ void ChromeContentBrowserClient::RenderProcessHostCreated(
host->AddFilter(new TtsMessageFilter(id, profile));
#if defined(ENABLE_WEBRTC)
WebRtcLoggingHandlerHost* webrtc_logging_handler_host =
- new WebRtcLoggingHandlerHost();
+ new WebRtcLoggingHandlerHost(profile);
host->AddFilter(webrtc_logging_handler_host);
host->SetUserData(host, new base::UserDataAdapter<WebRtcLoggingHandlerHost>(
webrtc_logging_handler_host));
#endif
#if !defined(DISABLE_NACL)
- ExtensionInfoMap* extension_info_map =
- extensions::ExtensionSystem::Get(profile)->info_map();
host->AddFilter(new NaClHostMessageFilter(
id, profile->IsOffTheRecord(),
- profile->GetPath(), extension_info_map,
+ profile->GetPath(),
context));
#endif
#if defined(OS_ANDROID)
@@ -1333,7 +1393,7 @@ std::string ChromeContentBrowserClient::GetCanonicalEncodingNameByAliasName(
void ChromeContentBrowserClient::AppendExtraCommandLineSwitches(
CommandLine* command_line, int child_process_id) {
#if defined(OS_POSIX)
- if (IsCrashReporterEnabled()) {
+ if (breakpad::IsCrashReporterEnabled()) {
std::string enable_crash_reporter;
GoogleUpdateSettings::GetMetricsId(&enable_crash_reporter);
#if !defined(OS_MACOSX)
@@ -1424,6 +1484,7 @@ void ChromeContentBrowserClient::AppendExtraCommandLineSwitches(
autofill::switches::kEnableExperimentalFormFilling,
autofill::switches::kEnableInteractiveAutocomplete,
autofill::switches::kEnablePasswordGeneration,
+ autofill::switches::kNoAutofillNecessaryForPasswordGeneration,
extensions::switches::kAllowLegacyExtensionManifests,
extensions::switches::kAllowScriptingGallery,
extensions::switches::kEnableExperimentalExtensionApis,
@@ -1444,7 +1505,6 @@ void ChromeContentBrowserClient::AppendExtraCommandLineSwitches(
switches::kEnableAdviewSrcAttribute,
switches::kEnableAppWindowControls,
switches::kEnableBenchmarking,
- switches::kEnableIPCFuzzing,
switches::kEnableNaCl,
switches::kEnableNetBenchmarking,
switches::kEnableWatchdog,
@@ -2090,6 +2150,9 @@ void ChromeContentBrowserClient::OverrideWebkitPrefs(
rvh->GetProcess()->GetBrowserContext());
PrefService* prefs = profile->GetPrefs();
+ // Fill per-script font preferences. These are not registered on Android
+ // - http://crbug.com/308033.
+#if !defined(OS_ANDROID)
FillFontFamilyMap(prefs, prefs::kWebKitStandardFontFamilyMap,
&web_prefs->standard_font_family_map);
FillFontFamilyMap(prefs, prefs::kWebKitFixedFontFamilyMap,
@@ -2104,6 +2167,7 @@ void ChromeContentBrowserClient::OverrideWebkitPrefs(
&web_prefs->fantasy_font_family_map);
FillFontFamilyMap(prefs, prefs::kWebKitPictographFontFamilyMap,
&web_prefs->pictograph_font_family_map);
+#endif
web_prefs->default_font_size =
prefs->GetInteger(prefs::kWebKitDefaultFontSize);
@@ -2157,8 +2221,9 @@ void ChromeContentBrowserClient::OverrideWebkitPrefs(
web_prefs->allow_running_insecure_content =
prefs->GetBoolean(prefs::kWebKitAllowRunningInsecureContent);
#if defined(OS_ANDROID)
- web_prefs->font_scale_factor =
- static_cast<float>(prefs->GetDouble(prefs::kWebKitFontScaleFactor));
+ web_prefs->text_autosizing_font_scale_factor =
+ static_cast<float>(prefs->GetDouble(prefs::kWebKitFontScaleFactor)) *
+ GetFontScaleMultiplier(prefs);
web_prefs->force_enable_zoom =
prefs->GetBoolean(prefs::kWebKitForceEnableZoom);
#endif
@@ -2493,8 +2558,9 @@ void ChromeContentBrowserClient::GetAdditionalMappedFilesForChildProcess(
mappings->push_back(FileDescriptorInfo(kAndroidUIResourcesPakDescriptor,
FileDescriptor(f, true)));
- if (IsCrashReporterEnabled()) {
- f = CrashDumpManager::GetInstance()->CreateMinidumpFile(child_process_id);
+ if (breakpad::IsCrashReporterEnabled()) {
+ f = breakpad::CrashDumpManager::GetInstance()->CreateMinidumpFile(
+ child_process_id);
if (f == base::kInvalidPlatformFileValue) {
LOG(ERROR) << "Failed to create file for minidump, crash reporting will "
"be disabled for this process.";
diff --git a/chrome/browser/chromeos/accessibility/sticky_keys_browsertest.cc b/chrome/browser/chromeos/accessibility/sticky_keys_browsertest.cc
new file mode 100644
index 0000000000..8743980e43
--- /dev/null
+++ b/chrome/browser/chromeos/accessibility/sticky_keys_browsertest.cc
@@ -0,0 +1,144 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/shell.h"
+#include "ash/system/tray/system_tray.h"
+#include "base/command_line.h"
+#include "base/prefs/pref_service.h"
+#include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/view_ids.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/interactive_test_utils.h"
+#include "ui/aura/root_window.h"
+#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/gfx/native_widget_types.h"
+
+namespace chromeos {
+
+class StickyKeysBrowserTest : public InProcessBrowserTest {
+ protected:
+ StickyKeysBrowserTest() {}
+ virtual ~StickyKeysBrowserTest() {}
+
+ void EnableStickyKeys() {
+ AccessibilityManager::Get()->EnableStickyKeys(true);
+ }
+
+ void DisableStickyKeys() {
+ AccessibilityManager::Get()->EnableStickyKeys(false);
+ }
+
+ ash::SystemTray* GetSystemTray() {
+ return ash::Shell::GetInstance()->GetPrimarySystemTray();
+ }
+
+ void SendKeyPress(ui::KeyboardCode key) {
+ gfx::NativeWindow root_window =
+ ash::Shell::GetInstance()->GetPrimaryRootWindow();
+ ASSERT_TRUE(
+ ui_test_utils::SendKeyPressToWindowSync(root_window,
+ key,
+ false, // control
+ false, // shift
+ false, // alt
+ false)); // command
+ }
+
+ content::NotificationRegistrar registrar_;
+
+ DISALLOW_COPY_AND_ASSIGN(StickyKeysBrowserTest);
+};
+
+IN_PROC_BROWSER_TEST_F(StickyKeysBrowserTest, OpenTrayMenu) {
+ EnableStickyKeys();
+
+ // Open system tray bubble with shortcut.
+ SendKeyPress(ui::VKEY_MENU); // alt key.
+ SendKeyPress(ui::VKEY_SHIFT);
+ SendKeyPress(ui::VKEY_S);
+ EXPECT_TRUE(GetSystemTray()->HasSystemBubble());
+
+ // Hide system bubble.
+ GetSystemTray()->CloseSystemBubble();
+ EXPECT_FALSE(GetSystemTray()->HasSystemBubble());
+
+ // Pressing S again should not reopen the bubble.
+ SendKeyPress(ui::VKEY_S);
+ EXPECT_FALSE(GetSystemTray()->HasSystemBubble());
+
+ // With sticky keys disabled, we will fail to perform the shortcut.
+ DisableStickyKeys();
+ SendKeyPress(ui::VKEY_MENU); // alt key.
+ SendKeyPress(ui::VKEY_SHIFT);
+ SendKeyPress(ui::VKEY_S);
+ EXPECT_FALSE(GetSystemTray()->HasSystemBubble());
+}
+
+IN_PROC_BROWSER_TEST_F(StickyKeysBrowserTest, OpenNewTabs) {
+ // Lock the modifier key.
+ EnableStickyKeys();
+ SendKeyPress(ui::VKEY_CONTROL);
+ SendKeyPress(ui::VKEY_CONTROL);
+
+ // In the locked state, pressing 't' should open a new tab each time.
+ TabStripModel* tab_strip_model = browser()->tab_strip_model();
+ int tab_count = 1;
+ for (; tab_count < 5; ++tab_count) {
+ EXPECT_EQ(tab_count, tab_strip_model->count());
+ SendKeyPress(ui::VKEY_T);
+ }
+
+ // Unlock the modifier key and shortcut should no longer activate.
+ SendKeyPress(ui::VKEY_CONTROL);
+ SendKeyPress(ui::VKEY_T);
+ EXPECT_EQ(tab_count, tab_strip_model->count());
+
+ // Shortcut should not work after disabling sticky keys.
+ DisableStickyKeys();
+ SendKeyPress(ui::VKEY_CONTROL);
+ SendKeyPress(ui::VKEY_CONTROL);
+ SendKeyPress(ui::VKEY_T);
+ EXPECT_EQ(tab_count, tab_strip_model->count());
+}
+
+// TODO(tengs): Enable this test once sticky keys has been fixed to
+// support mouse events (crbug.com/308659).
+IN_PROC_BROWSER_TEST_F(StickyKeysBrowserTest, DISABLED_CtrlClickHomeButton) {
+ // Show home page button.
+ browser()->profile()->GetPrefs()->SetBoolean(prefs::kShowHomeButton, true);
+ TabStripModel* tab_strip_model = browser()->tab_strip_model();
+ int tab_count = 1;
+ EXPECT_EQ(tab_count, tab_strip_model->count());
+
+ // Test sticky keys with modified mouse click action.
+ EnableStickyKeys();
+ SendKeyPress(ui::VKEY_CONTROL);
+ ui_test_utils::ClickOnView(browser(), VIEW_ID_HOME_BUTTON);
+ EXPECT_EQ(++tab_count, tab_strip_model->count());
+ ui_test_utils::ClickOnView(browser(), VIEW_ID_HOME_BUTTON);
+ EXPECT_EQ(tab_count, tab_strip_model->count());
+
+ // Test locked modifier key with mouse click.
+ SendKeyPress(ui::VKEY_CONTROL);
+ SendKeyPress(ui::VKEY_CONTROL);
+ for (; tab_count < 5; ++tab_count) {
+ ui_test_utils::ClickOnView(browser(), VIEW_ID_HOME_BUTTON);
+ EXPECT_EQ(tab_count, tab_strip_model->count());
+ }
+ SendKeyPress(ui::VKEY_CONTROL);
+ ui_test_utils::ClickOnView(browser(), VIEW_ID_HOME_BUTTON);
+ EXPECT_EQ(tab_count, tab_strip_model->count());
+
+ // Test disabling sticky keys prevent modified mouse click.
+ DisableStickyKeys();
+ SendKeyPress(ui::VKEY_CONTROL);
+ ui_test_utils::ClickOnView(browser(), VIEW_ID_HOME_BUTTON);
+ EXPECT_EQ(tab_count, tab_strip_model->count());
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/app_mode/kiosk_profile_loader.cc b/chrome/browser/chromeos/app_mode/kiosk_profile_loader.cc
index 2cb1a73354..a354ed0767 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_profile_loader.cc
+++ b/chrome/browser/chromeos/app_mode/kiosk_profile_loader.cc
@@ -180,17 +180,13 @@ void KioskProfileLoader::ReportLaunchResult(KioskAppLaunchError::Error error) {
}
}
-void KioskProfileLoader::OnLoginSuccess(
- const UserContext& user_context,
- bool pending_requests,
- bool using_oauth) {
+void KioskProfileLoader::OnLoginSuccess(const UserContext& user_context) {
// LoginPerformer will delete itself.
login_performer_->set_delegate(NULL);
ignore_result(login_performer_.release());
LoginUtils::Get()->PrepareProfile(user_context,
std::string(), // display email
- false, // using_oauth
false, // has_cookies
false, // has_active_session
this);
diff --git a/chrome/browser/chromeos/app_mode/kiosk_profile_loader.h b/chrome/browser/chromeos/app_mode/kiosk_profile_loader.h
index 46d47eb761..9f28103f5e 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_profile_loader.h
+++ b/chrome/browser/chromeos/app_mode/kiosk_profile_loader.h
@@ -51,10 +51,7 @@ class KioskProfileLoader : public LoginPerformer::Delegate,
void ReportLaunchResult(KioskAppLaunchError::Error error);
// LoginPerformer::Delegate overrides
- virtual void OnLoginSuccess(
- const UserContext& user_context,
- bool pending_requests,
- bool using_oauth) OVERRIDE;
+ virtual void OnLoginSuccess(const UserContext& user_context) OVERRIDE;
virtual void OnLoginFailure(const LoginFailure& error) OVERRIDE;
virtual void WhiteListCheckFailed(const std::string& email) OVERRIDE;
virtual void PolicyLoadFailed() OVERRIDE;
diff --git a/chrome/browser/chromeos/app_mode/startup_app_launcher.cc b/chrome/browser/chromeos/app_mode/startup_app_launcher.cc
index 01fd0f5fc8..da60c3c1ef 100644
--- a/chrome/browser/chromeos/app_mode/startup_app_launcher.cc
+++ b/chrome/browser/chromeos/app_mode/startup_app_launcher.cc
@@ -27,7 +27,7 @@
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/manifest_handlers/kiosk_mode_info.h"
-#include "chromeos/cryptohome/cryptohome_library.h"
+#include "chromeos/cryptohome/system_salt_getter.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_service.h"
#include "google_apis/gaia/gaia_auth_consumer.h"
@@ -284,7 +284,7 @@ void StartupAppLauncher::OnReadyToLaunch() {
// Defer app launch until system salt is loaded to make sure that identity
// api works with the enterprise kiosk app.
// TODO(xiyuan): Use async GetSystemSalt after merging to M31.
- const std::string system_salt = CryptohomeLibrary::Get()->GetSystemSaltSync();
+ const std::string system_salt = SystemSaltGetter::Get()->GetSystemSaltSync();
if (system_salt.empty()) {
const int64 kRequestSystemSaltDelayMs = 500;
BrowserThread::PostDelayedTask(
diff --git a/chrome/browser/chromeos/attestation/OWNERS b/chrome/browser/chromeos/attestation/OWNERS
index cd1c574925..a48744dcca 100644
--- a/chrome/browser/chromeos/attestation/OWNERS
+++ b/chrome/browser/chromeos/attestation/OWNERS
@@ -1,2 +1,3 @@
mnissler@chromium.org
pastarmovj@chromium.org
+bartfab@chromium.org
diff --git a/chrome/browser/chromeos/attestation/attestation_policy_observer.cc b/chrome/browser/chromeos/attestation/attestation_policy_observer.cc
index 2734706100..9aab2644c2 100644
--- a/chrome/browser/chromeos/attestation/attestation_policy_observer.cc
+++ b/chrome/browser/chromeos/attestation/attestation_policy_observer.cc
@@ -27,8 +27,6 @@
namespace {
-const char kEnterpriseMachineKey[] = "attest-ent-machine";
-
// The number of days before a certificate expires during which it is
// considered 'expiring soon' and replacement is initiated. The Chrome OS CA
// issues certificates with an expiry of at least two years. This value has
@@ -172,6 +170,7 @@ void AttestationPolicyObserver::Start() {
weak_factory_.GetWeakPtr());
cryptohome_client_->TpmAttestationDoesKeyExist(
KEY_DEVICE,
+ std::string(), // Not used.
kEnterpriseMachineKey,
base::Bind(DBusBoolRedirectCallback,
on_does_exist,
@@ -200,6 +199,7 @@ void AttestationPolicyObserver::GetNewCertificate() {
void AttestationPolicyObserver::GetExistingCertificate() {
cryptohome_client_->TpmAttestationGetCertificate(
KEY_DEVICE,
+ std::string(), // Not used.
kEnterpriseMachineKey,
base::Bind(DBusStringCallback,
base::Bind(&AttestationPolicyObserver::CheckCertificateExpiry,
@@ -257,6 +257,7 @@ void AttestationPolicyObserver::GetKeyPayload(
base::Callback<void(const std::string&)> callback) {
cryptohome_client_->TpmAttestationGetKeyPayload(
KEY_DEVICE,
+ std::string(), // Not used.
kEnterpriseMachineKey,
base::Bind(DBusStringCallback,
callback,
@@ -285,6 +286,7 @@ void AttestationPolicyObserver::MarkAsUploaded(const std::string& key_payload) {
}
cryptohome_client_->TpmAttestationSetKeyPayload(
KEY_DEVICE,
+ std::string(), // Not used.
kEnterpriseMachineKey,
new_payload,
base::Bind(DBusBoolRedirectCallback,
diff --git a/chrome/browser/chromeos/attestation/attestation_policy_observer_unittest.cc b/chrome/browser/chromeos/attestation/attestation_policy_observer_unittest.cc
index 8e592dc4d7..6338ca9c12 100644
--- a/chrome/browser/chromeos/attestation/attestation_policy_observer_unittest.cc
+++ b/chrome/browser/chromeos/attestation/attestation_policy_observer_unittest.cc
@@ -148,20 +148,20 @@ class AttestationPolicyObserverTest : public ::testing::Test {
bool key_exists = (mock_options & MOCK_KEY_EXISTS);
// Setup expected key / cert queries.
if (key_exists) {
- EXPECT_CALL(cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _))
- .WillRepeatedly(WithArgs<2>(Invoke(DBusCallbackTrue)));
- EXPECT_CALL(cryptohome_client_, TpmAttestationGetCertificate(_, _, _))
- .WillRepeatedly(WithArgs<2>(Invoke(FakeDBusData(certificate))));
+ EXPECT_CALL(cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _, _))
+ .WillRepeatedly(WithArgs<3>(Invoke(DBusCallbackTrue)));
+ EXPECT_CALL(cryptohome_client_, TpmAttestationGetCertificate(_, _, _, _))
+ .WillRepeatedly(WithArgs<3>(Invoke(FakeDBusData(certificate))));
} else {
- EXPECT_CALL(cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _))
- .WillRepeatedly(WithArgs<2>(Invoke(DBusCallbackFalse)));
+ EXPECT_CALL(cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _, _))
+ .WillRepeatedly(WithArgs<3>(Invoke(DBusCallbackFalse)));
}
// Setup expected key payload queries.
bool key_uploaded = (mock_options & MOCK_KEY_UPLOADED);
std::string payload = CreatePayload();
- EXPECT_CALL(cryptohome_client_, TpmAttestationGetKeyPayload(_, _, _))
- .WillRepeatedly(WithArgs<2>(Invoke(
+ EXPECT_CALL(cryptohome_client_, TpmAttestationGetKeyPayload(_, _, _, _))
+ .WillRepeatedly(WithArgs<3>(Invoke(
FakeDBusData(key_uploaded ? payload : ""))));
// Setup expected key uploads. Use WillOnce() so StrictMock will trigger an
@@ -175,8 +175,8 @@ class AttestationPolicyObserverTest : public ::testing::Test {
UploadCertificate(new_key ? "fake_cert" : certificate, _))
.WillOnce(WithArgs<1>(Invoke(StatusCallbackSuccess)));
EXPECT_CALL(cryptohome_client_,
- TpmAttestationSetKeyPayload(_, _, payload, _))
- .WillOnce(WithArgs<3>(Invoke(DBusCallbackTrue)));
+ TpmAttestationSetKeyPayload(_, _, _, payload, _))
+ .WillOnce(WithArgs<4>(Invoke(DBusCallbackTrue)));
}
// Setup expected key generations. Again use WillOnce(). Key generation is
@@ -297,9 +297,9 @@ TEST_F(AttestationPolicyObserverTest, IgnoreUnknownCertFormat) {
TEST_F(AttestationPolicyObserverTest, DBusFailureRetry) {
SetupMocks(MOCK_NEW_KEY, "");
// Simulate a DBus failure.
- EXPECT_CALL(cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _))
- .WillOnce(WithArgs<2>(Invoke(DBusCallbackError)))
- .WillRepeatedly(WithArgs<2>(Invoke(DBusCallbackFalse)));
+ EXPECT_CALL(cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _, _))
+ .WillOnce(WithArgs<3>(Invoke(DBusCallbackError)))
+ .WillRepeatedly(WithArgs<3>(Invoke(DBusCallbackFalse)));
Run();
}
diff --git a/chrome/browser/chromeos/attestation/platform_verification_flow.cc b/chrome/browser/chromeos/attestation/platform_verification_flow.cc
index ab2a53b151..d6ef3ace1e 100644
--- a/chrome/browser/chromeos/attestation/platform_verification_flow.cc
+++ b/chrome/browser/chromeos/attestation/platform_verification_flow.cc
@@ -10,26 +10,24 @@
#include "chrome/browser/chromeos/attestation/attestation_ca_client.h"
#include "chrome/browser/chromeos/attestation/attestation_signed_data.pb.h"
#include "chrome/browser/chromeos/attestation/platform_verification_dialog.h"
+#include "chrome/browser/chromeos/login/user.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/prefs/scoped_user_pref_update.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "chromeos/attestation/attestation_flow.h"
#include "chromeos/cryptohome/async_method_caller.h"
#include "chromeos/dbus/cryptohome_client.h"
#include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/system/statistics_provider.h"
#include "components/user_prefs/pref_registry_syncable.h"
#include "components/user_prefs/user_prefs.h"
+#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/user_metrics.h"
#include "content/public/browser/web_contents.h"
namespace {
-// A switch which allows consent to be given on the command line.
-// TODO(dkrahn): Remove this when UI has been implemented (crbug.com/270908).
-const char kAutoApproveSwitch[] =
- "auto-approve-platform-verification-consent-prompts";
// A callback method to handle DBus errors.
void DBusCallback(const base::Callback<void(bool)>& on_success,
@@ -67,12 +65,7 @@ class DefaultDelegate : public PlatformVerificationFlow::Delegate {
content::WebContents* web_contents,
const PlatformVerificationFlow::Delegate::ConsentCallback& callback)
OVERRIDE {
- if (CommandLine::ForCurrentProcess()->HasSwitch(kAutoApproveSwitch)) {
- LOG(WARNING) << "PlatformVerificationFlow: Automatic approval enabled.";
- callback.Run(PlatformVerificationFlow::CONSENT_RESPONSE_ALLOW);
- } else {
- PlatformVerificationDialog::ShowDialog(web_contents, callback);
- }
+ PlatformVerificationDialog::ShowDialog(web_contents, callback);
}
private:
@@ -84,7 +77,6 @@ PlatformVerificationFlow::PlatformVerificationFlow()
async_caller_(cryptohome::AsyncMethodCaller::GetInstance()),
cryptohome_client_(DBusThreadManager::Get()->GetCryptohomeClient()),
user_manager_(UserManager::Get()),
- statistics_provider_(system::StatisticsProvider::GetInstance()),
delegate_(NULL),
testing_prefs_(NULL),
weak_factory_(this) {
@@ -104,13 +96,11 @@ PlatformVerificationFlow::PlatformVerificationFlow(
cryptohome::AsyncMethodCaller* async_caller,
CryptohomeClient* cryptohome_client,
UserManager* user_manager,
- system::StatisticsProvider* statistics_provider,
Delegate* delegate)
: attestation_flow_(attestation_flow),
async_caller_(async_caller),
cryptohome_client_(cryptohome_client),
user_manager_(user_manager),
- statistics_provider_(statistics_provider),
delegate_(delegate),
testing_prefs_(NULL),
weak_factory_(this) {
@@ -143,28 +133,6 @@ void PlatformVerificationFlow::ChallengePlatformKey(
cryptohome_client_->TpmAttestationIsEnrolled(dbus_callback);
}
-void PlatformVerificationFlow::CheckPlatformState(
- const base::Callback<void(bool result)>& callback) {
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
- std::string stat_value;
- if (!statistics_provider_->GetMachineStatistic(system::kDevSwitchBootMode,
- &stat_value)) {
- LOG(ERROR) << __func__ << ": Failed to get boot mode statistic.";
- callback.Run(false);
- return;
- }
- if (stat_value != "0") {
- LOG(INFO) << __func__ << ": Statistic indicates developer mode.";
- callback.Run(false);
- return;
- }
- BoolDBusMethodCallback dbus_callback = base::Bind(
- &DBusCallback,
- callback,
- base::Bind(callback, false));
- cryptohome_client_->TpmAttestationIsPrepared(dbus_callback);
-}
-
void PlatformVerificationFlow::CheckConsent(content::WebContents* web_contents,
const std::string& service_id,
const std::string& challenge,
@@ -238,21 +206,29 @@ void PlatformVerificationFlow::OnConsentResponse(
// At this point all user interaction is complete and we can proceed with the
// certificate request.
+ chromeos::User* user = GetUser(web_contents);
+ if (!user) {
+ ReportError(callback, INTERNAL_ERROR);
+ LOG(ERROR) << "Profile does not map to a valid user.";
+ return;
+ }
AttestationFlow::CertificateCallback certificate_callback = base::Bind(
&PlatformVerificationFlow::OnCertificateReady,
weak_factory_.GetWeakPtr(),
+ user->email(),
service_id,
challenge,
callback);
attestation_flow_->GetCertificate(
PROFILE_CONTENT_PROTECTION_CERTIFICATE,
- user_manager_->GetActiveUser()->email(),
+ user->email(),
service_id,
false, // Don't force a new key.
certificate_callback);
}
void PlatformVerificationFlow::OnCertificateReady(
+ const std::string& user_id,
const std::string& service_id,
const std::string& challenge,
const ChallengeCallback& callback,
@@ -272,6 +248,7 @@ void PlatformVerificationFlow::OnCertificateReady(
std::string key_name = kContentProtectionKeyPrefix;
key_name += service_id;
async_caller_->TpmAttestationSignSimpleChallenge(KEY_USER,
+ user_id,
key_name,
challenge,
cryptohome_callback);
@@ -315,6 +292,13 @@ const GURL& PlatformVerificationFlow::GetURL(
return web_contents->GetLastCommittedURL();
}
+User* PlatformVerificationFlow::GetUser(content::WebContents* web_contents) {
+ if (!web_contents)
+ return user_manager_->GetActiveUser();
+ return user_manager_->GetUserByProfile(
+ Profile::FromBrowserContext(web_contents->GetBrowserContext()));
+}
+
bool PlatformVerificationFlow::IsAttestationEnabled(
content::WebContents* web_contents) {
// Check the device policy for the feature.
diff --git a/chrome/browser/chromeos/attestation/platform_verification_flow.h b/chrome/browser/chromeos/attestation/platform_verification_flow.h
index 8ba3b874f7..64f3627464 100644
--- a/chrome/browser/chromeos/attestation/platform_verification_flow.h
+++ b/chrome/browser/chromeos/attestation/platform_verification_flow.h
@@ -31,10 +31,7 @@ namespace chromeos {
class CryptohomeClient;
class UserManager;
-
-namespace system {
-class StatisticsProvider;
-}
+class User;
namespace attestation {
@@ -112,7 +109,6 @@ class PlatformVerificationFlow {
cryptohome::AsyncMethodCaller* async_caller,
CryptohomeClient* cryptohome_client,
UserManager* user_manager,
- system::StatisticsProvider* statistics_provider,
Delegate* delegate);
virtual ~PlatformVerificationFlow();
@@ -132,13 +128,6 @@ class PlatformVerificationFlow {
const std::string& challenge,
const ChallengeCallback& callback);
- // Performs a quick check to see if platform verification is reasonably
- // expected to succeed. The result of the check will be sent to the given
- // |callback|. If the |result| is true, then platform verification is
- // expected to succeed. However, this result is not authoritative either true
- // or false. If an error occurs, |result| will be false.
- void CheckPlatformState(const base::Callback<void(bool result)>& callback);
-
static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* prefs);
void set_testing_prefs(PrefService* testing_prefs) {
@@ -174,11 +163,13 @@ class PlatformVerificationFlow {
// A callback called when an attestation certificate request operation
// completes. |service_id|, |challenge|, and |callback| are the same as in
- // ChallengePlatformKey. |operation_success| is true iff the certificate
+ // ChallengePlatformKey. |user_id| identifies the user for which the
+ // certificate was requested. |operation_success| is true iff the certificate
// request operation succeeded. |certificate| holds the certificate for the
// platform key on success. If the certificate request was successful, this
// method invokes a request to sign the challenge.
- void OnCertificateReady(const std::string& service_id,
+ void OnCertificateReady(const std::string& user_id,
+ const std::string& service_id,
const std::string& challenge,
const ChallengeCallback& callback,
bool operation_success,
@@ -205,6 +196,11 @@ class PlatformVerificationFlow {
// set explicitly using set_testing_url(), then this value is always returned.
const GURL& GetURL(content::WebContents* web_contents);
+ // Gets the user associated with the given |web_contents|. NULL may be
+ // returned. If |web_contents| is NULL (e.g. during testing), then the
+ // current active user will be returned.
+ User* GetUser(content::WebContents* web_contents);
+
// Checks whether policy or profile settings associated with |web_contents|
// have attestation for content protection explicitly disabled.
bool IsAttestationEnabled(content::WebContents* web_contents);
@@ -242,7 +238,6 @@ class PlatformVerificationFlow {
cryptohome::AsyncMethodCaller* async_caller_;
CryptohomeClient* cryptohome_client_;
UserManager* user_manager_;
- system::StatisticsProvider* statistics_provider_;
Delegate* delegate_;
scoped_ptr<Delegate> default_delegate_;
PrefService* testing_prefs_;
diff --git a/chrome/browser/chromeos/attestation/platform_verification_flow_unittest.cc b/chrome/browser/chromeos/attestation/platform_verification_flow_unittest.cc
index 660f6f4ccc..728b1e822c 100644
--- a/chrome/browser/chromeos/attestation/platform_verification_flow_unittest.cc
+++ b/chrome/browser/chromeos/attestation/platform_verification_flow_unittest.cc
@@ -20,7 +20,6 @@
#include "chromeos/cryptohome/mock_async_method_caller.h"
#include "chromeos/dbus/fake_cryptohome_client.h"
#include "chromeos/settings/cros_settings_names.h"
-#include "chromeos/system/mock_statistics_provider.h"
#include "content/public/test/test_browser_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -124,33 +123,22 @@ class PlatformVerificationFlowTest : public ::testing::Test {
ui_thread_(content::BrowserThread::UI, &message_loop_),
certificate_success_(true),
sign_challenge_success_(true),
- result_(PlatformVerificationFlow::INTERNAL_ERROR),
- check_state_result_(false) {}
+ result_(PlatformVerificationFlow::INTERNAL_ERROR) {}
void SetUp() {
// Configure a user for the mock user manager.
mock_user_manager_.SetActiveUser(kTestEmail);
- // Configure the statistics provider to report verified mode.
- EXPECT_CALL(mock_statistics_provider_,
- GetMachineStatistic(system::kDevSwitchBootMode, _))
- .WillRepeatedly(DoAll(SetArgumentPointee<1>(std::string("0")),
- Return(true)));
-
// Create a verifier for tests to call.
verifier_.reset(new PlatformVerificationFlow(&mock_attestation_flow_,
&mock_async_caller_,
&fake_cryptohome_client_,
&mock_user_manager_,
- &mock_statistics_provider_,
&fake_delegate_));
// Create callbacks for tests to use with verifier_.
callback_ = base::Bind(&PlatformVerificationFlowTest::FakeChallengeCallback,
base::Unretained(this));
- check_state_callback_ = base::Bind(
- &PlatformVerificationFlowTest::FakeCheckStateCallback,
- base::Unretained(this));
// Configure the test pref service.
pref_service_.registry()->RegisterBooleanPref(prefs::kEnableDRM, true);
@@ -197,9 +185,10 @@ class PlatformVerificationFlowTest : public ::testing::Test {
std::string expected_key_name = std::string(kContentProtectionKeyPrefix) +
std::string(kTestID);
EXPECT_CALL(mock_async_caller_,
- TpmAttestationSignSimpleChallenge(KEY_USER, expected_key_name,
+ TpmAttestationSignSimpleChallenge(KEY_USER, kTestEmail,
+ expected_key_name,
kTestChallenge, _))
- .WillRepeatedly(WithArgs<3>(Invoke(
+ .WillRepeatedly(WithArgs<4>(Invoke(
this, &PlatformVerificationFlowTest::FakeSignChallenge)));
}
@@ -230,10 +219,6 @@ class PlatformVerificationFlowTest : public ::testing::Test {
certificate_ = certificate;
}
- void FakeCheckStateCallback(bool result) {
- check_state_result_ = result;
- }
-
std::string CreateFakeResponseProto() {
SignedData pb;
pb.set_data(kTestSignedData);
@@ -250,7 +235,6 @@ class PlatformVerificationFlowTest : public ::testing::Test {
cryptohome::MockAsyncMethodCaller mock_async_caller_;
CustomFakeCryptohomeClient fake_cryptohome_client_;
MockUserManager mock_user_manager_;
- system::MockStatisticsProvider mock_statistics_provider_;
FakeDelegate fake_delegate_;
TestingPrefServiceSimple pref_service_;
CrosSettingsProvider* device_settings_provider_;
@@ -271,8 +255,6 @@ class PlatformVerificationFlowTest : public ::testing::Test {
std::string challenge_salt_;
std::string challenge_signature_;
std::string certificate_;
- base::Callback<void(bool result)> check_state_callback_;
- bool check_state_result_;
};
TEST_F(PlatformVerificationFlowTest, SuccessNoConsent) {
@@ -396,60 +378,5 @@ TEST_F(PlatformVerificationFlowTest, ConsentNoResponse) {
EXPECT_EQ(PlatformVerificationFlow::USER_REJECTED, result_);
}
-TEST_F(PlatformVerificationFlowTest, FastCheck) {
- verifier_->CheckPlatformState(check_state_callback_);
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(check_state_result_);
-}
-
-TEST_F(PlatformVerificationFlowTest, FastCheckNoStat) {
- // Configure the stats provider to fail.
- EXPECT_CALL(mock_statistics_provider_,
- GetMachineStatistic(system::kDevSwitchBootMode, _))
- .WillRepeatedly(Return(false));
-
- verifier_->CheckPlatformState(check_state_callback_);
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(check_state_result_);
-}
-
-TEST_F(PlatformVerificationFlowTest, FastCheckStatDevMode) {
- // Configure the stats provider to fail.
- EXPECT_CALL(mock_statistics_provider_,
- GetMachineStatistic(system::kDevSwitchBootMode, _))
- .WillRepeatedly(DoAll(SetArgumentPointee<1>(std::string("1")),
- Return(true)));
-
- verifier_->CheckPlatformState(check_state_callback_);
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(check_state_result_);
-}
-
-TEST_F(PlatformVerificationFlowTest, FastCheckStatInvalidMode) {
- // Configure the stats provider to fail.
- EXPECT_CALL(mock_statistics_provider_,
- GetMachineStatistic(system::kDevSwitchBootMode, _))
- .WillRepeatedly(DoAll(SetArgumentPointee<1>(std::string("INVALID")),
- Return(true)));
-
- verifier_->CheckPlatformState(check_state_callback_);
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(check_state_result_);
-}
-
-TEST_F(PlatformVerificationFlowTest, FastCheckNoAttestation) {
- fake_cryptohome_client_.set_attestation_prepared(false);
- verifier_->CheckPlatformState(check_state_callback_);
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(check_state_result_);
-}
-
-TEST_F(PlatformVerificationFlowTest, FastCheckDBusFailure) {
- fake_cryptohome_client_.set_call_status(DBUS_METHOD_CALL_FAILURE);
- verifier_->CheckPlatformState(check_state_callback_);
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(check_state_result_);
-}
-
} // namespace attestation
} // namespace chromeos
diff --git a/chrome/browser/chromeos/boot_times_loader.cc b/chrome/browser/chromeos/boot_times_loader.cc
index 223259676d..f7ee861929 100644
--- a/chrome/browser/chromeos/boot_times_loader.cc
+++ b/chrome/browser/chromeos/boot_times_loader.cc
@@ -86,8 +86,6 @@ static const base::FilePath::CharType kUptimePrefix[] = FPL("uptime-");
static const base::FilePath::CharType kDiskPrefix[] = FPL("disk-");
// Name of the time that Chrome's main() is called.
static const base::FilePath::CharType kChromeMain[] = FPL("chrome-main");
-// Delay in milliseconds between file read attempts.
-static const int64 kReadAttemptDelayMs = 250;
// Delay in milliseconds before writing the login times to disk.
static const int64 kLoginTimeWriteDelayMs = 3000;
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index 56915828aa..e5559b1a1d 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -82,7 +82,7 @@
#include "chromeos/chromeos_paths.h"
#include "chromeos/chromeos_switches.h"
#include "chromeos/cryptohome/async_method_caller.h"
-#include "chromeos/cryptohome/cryptohome_library.h"
+#include "chromeos/cryptohome/system_salt_getter.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/power_policy_controller.h"
#include "chromeos/dbus/session_manager_client.h"
@@ -102,6 +102,8 @@
#include "net/base/network_change_notifier.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context_getter.h"
+#include "ui/base/touch/touch_device.h"
+#include "ui/events/event_utils.h"
// Exclude X11 dependents for ozone
#if defined(USE_X11)
@@ -138,8 +140,7 @@ class StubLogin : public LoginStatusConsumer,
public LoginUtils::Delegate {
public:
StubLogin(std::string username, std::string password)
- : pending_requests_(false),
- profile_prepared_(false) {
+ : profile_prepared_(false) {
authenticator_ = LoginUtils::Get()->CreateAuthenticator(this);
authenticator_.get()->AuthenticateToLogin(
g_browser_process->profile_manager()->GetDefaultProfile(),
@@ -157,19 +158,15 @@ class StubLogin : public LoginStatusConsumer,
delete this;
}
- virtual void OnLoginSuccess(const UserContext& user_context,
- bool pending_requests,
- bool using_oauth) OVERRIDE {
- pending_requests_ = pending_requests;
+ virtual void OnLoginSuccess(const UserContext& user_context) OVERRIDE {
if (!profile_prepared_) {
// Will call OnProfilePrepared in the end.
LoginUtils::Get()->PrepareProfile(user_context,
std::string(), // display_email
- using_oauth,
false, // has_cookies
true, // has_active_session
this);
- } else if (!pending_requests) {
+ } else {
delete this;
}
}
@@ -178,12 +175,10 @@ class StubLogin : public LoginStatusConsumer,
virtual void OnProfilePrepared(Profile* profile) OVERRIDE {
profile_prepared_ = true;
LoginUtils::Get()->DoBrowserLaunch(profile, NULL);
- if (!pending_requests_)
- delete this;
+ delete this;
}
scoped_refptr<Authenticator> authenticator_;
- bool pending_requests_;
bool profile_prepared_;
};
@@ -268,7 +263,7 @@ class DBusServices {
CrosDBusService::Initialize();
LoginState::Initialize();
- CryptohomeLibrary::Initialize();
+ SystemSaltGetter::Initialize();
CertLoader::Initialize();
// This function and SystemKeyEventListener use InputMethodManager.
@@ -315,7 +310,7 @@ class DBusServices {
disks::DiskMountManager::Shutdown();
input_method::Shutdown();
- CryptohomeLibrary::Shutdown();
+ SystemSaltGetter::Shutdown();
LoginState::Shutdown();
CrosDBusService::Shutdown();
@@ -575,6 +570,26 @@ void ChromeBrowserMainPartsChromeos::PostProfileInit() {
UserManager::Get()->RestoreActiveSessions();
}
+ // Initialize the network portal detector for Chrome OS. The network
+ // portal detector starts to listen for notifications from
+ // NetworkStateHandler and initiates captive portal detection for
+ // active networks. Shoule be called before call to
+ // OptionallyRunChromeOSLoginManager, because it depends on
+ // NetworkPortalDetector.
+ NetworkPortalDetector::Initialize();
+ {
+ NetworkPortalDetector* detector = NetworkPortalDetector::Get();
+#if defined(GOOGLE_CHROME_BUILD)
+ bool is_official_build = true;
+#else
+ bool is_official_build = false;
+#endif
+ // Enable portal detector if EULA was previously accepted or if
+ // this is an unofficial build.
+ if (!is_official_build || StartupUtils::IsEulaAccepted())
+ detector->Enable(true);
+ }
+
// Tests should be able to tune login manager before showing it.
// Thus only show login manager in normal (non-testing) mode.
if (!parameters().ui_task ||
@@ -593,23 +608,6 @@ void ChromeBrowserMainPartsChromeos::PostProfileInit() {
peripheral_battery_observer_.reset(new PeripheralBatteryObserver());
- // Initialize the network portal detector for Chrome OS. The network portal
- // detector starts to listen for notifications from NetworkStateHandler and
- // initiates captive portal detection for active networks.
- NetworkPortalDetector* detector = NetworkPortalDetector::GetInstance();
- if (NetworkPortalDetector::IsEnabledInCommandLine() && detector) {
- detector->Init();
-#if defined(GOOGLE_CHROME_BUILD)
- bool is_official_build = true;
-#else
- bool is_official_build = false;
-#endif
- // Enable portal detector if EULA was previously accepted or if
- // this is an unofficial build.
- if (!is_official_build || StartupUtils::IsEulaAccepted())
- detector->Enable(true);
- }
-
display_configuration_observer_.reset(
new DisplayConfigurationObserver());
@@ -646,6 +644,13 @@ void ChromeBrowserMainPartsChromeos::PreBrowserStart() {
// adjusting the oom priority.
g_browser_process->platform_part()->oom_priority_manager()->Start();
+ // Turn on natural scroll if we have a touch screen.
+ if (ui::IsTouchDevicePresent()) {
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ chromeos::switches::kNaturalScrollDefault);
+ ui::SetNaturalScroll(true);
+ }
+
ChromeBrowserMainPartsLinux::PreBrowserStart();
}
@@ -678,10 +683,6 @@ void ChromeBrowserMainPartsChromeos::PostMainMessageLoopRun() {
if (NetworkChangeNotifierFactoryChromeos::GetInstance())
NetworkChangeNotifierFactoryChromeos::GetInstance()->Shutdown();
- NetworkPortalDetector* detector = NetworkPortalDetector::GetInstance();
- if (NetworkPortalDetector::IsEnabledInCommandLine() && detector)
- detector->Shutdown();
-
// Destroy UI related classes before destroying services that they may
// depend on.
data_promo_notification_.reset();
@@ -748,6 +749,12 @@ void ChromeBrowserMainPartsChromeos::PostMainMessageLoopRun() {
// http://crbug.com/243364).
ChromeBrowserMainPartsLinux::PostMainMessageLoopRun();
+ // Called after
+ // ChromeBrowserMainPartsLinux::PostMainMessageLoopRun() to be
+ // executed after execution of chrome::CloseAsh(), because some
+ // parts of WebUI depends on NetworkPortalDetector.
+ NetworkPortalDetector::Shutdown();
+
UserManager::Destroy();
}
diff --git a/chrome/browser/chromeos/contacts/gdata_contacts_service_unittest.cc b/chrome/browser/chromeos/contacts/gdata_contacts_service_unittest.cc
index a739d50e8f..3dbcae3151 100644
--- a/chrome/browser/chromeos/contacts/gdata_contacts_service_unittest.cc
+++ b/chrome/browser/chromeos/contacts/gdata_contacts_service_unittest.cc
@@ -31,8 +31,6 @@ using content::BrowserThread;
namespace contacts {
namespace {
-const char kTestGDataAuthToken[] = "testtoken";
-
// Filename of JSON feed containing contact groups.
const char kGroupsFeedFilename[] = "/groups.json";
diff --git a/chrome/browser/chromeos/display/display_preferences.cc b/chrome/browser/chromeos/display/display_preferences.cc
index b7a1659034..09d6c39d47 100644
--- a/chrome/browser/chromeos/display/display_preferences.cc
+++ b/chrome/browser/chromeos/display/display_preferences.cc
@@ -4,7 +4,6 @@
#include "chrome/browser/chromeos/display/display_preferences.h"
-#include "ash/display/display_controller.h"
#include "ash/display/display_layout_store.h"
#include "ash/display/display_manager.h"
#include "ash/display/display_pref_util.h"
@@ -277,8 +276,7 @@ void StoreDisplayPrefs() {
}
void SetCurrentDisplayLayout(const ash::DisplayLayout& layout) {
- ash::DisplayController* display_controller = GetDisplayController();
- display_controller->SetLayoutForCurrentDisplays(layout);
+ GetDisplayManager()->SetLayoutForCurrentDisplays(layout);
}
void LoadDisplayPreferences(bool first_run_after_boot) {
diff --git a/chrome/browser/chromeos/display/overscan_calibrator.cc b/chrome/browser/chromeos/display/overscan_calibrator.cc
index 1e8f37ab56..ed4adaeeb7 100644
--- a/chrome/browser/chromeos/display/overscan_calibrator.cc
+++ b/chrome/browser/chromeos/display/overscan_calibrator.cc
@@ -17,9 +17,6 @@
namespace chromeos {
namespace {
-// The opacity for the grey out borders.
-const float kBorderOpacity = 0.5;
-
// The opacity for the arrows of the overscan calibration.
const float kArrowOpacity = 0.8;
diff --git a/chrome/browser/chromeos/drive/async_file_util.cc b/chrome/browser/chromeos/drive/async_file_util.cc
index bcd4161ec3..4e9a03a82b 100644
--- a/chrome/browser/chromeos/drive/async_file_util.cc
+++ b/chrome/browser/chromeos/drive/async_file_util.cc
@@ -282,8 +282,6 @@ void AsyncFileUtil::CopyFileLocal(
const StatusCallback& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- // TODO(hidehiko): Support option.
-
base::FilePath src_path = util::ExtractDrivePathFromFileSystemUrl(src_url);
base::FilePath dest_path = util::ExtractDrivePathFromFileSystemUrl(dest_url);
if (src_path.empty() || dest_path.empty()) {
@@ -309,8 +307,6 @@ void AsyncFileUtil::MoveFileLocal(
const StatusCallback& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- // TODO(hidehiko): Support option.
-
base::FilePath src_path = util::ExtractDrivePathFromFileSystemUrl(src_url);
base::FilePath dest_path = util::ExtractDrivePathFromFileSystemUrl(dest_url);
if (src_path.empty() || dest_path.empty()) {
diff --git a/chrome/browser/chromeos/drive/change_list_loader.cc b/chrome/browser/chromeos/drive/change_list_loader.cc
index 19184b12ad..f9718595e2 100644
--- a/chrome/browser/chromeos/drive/change_list_loader.cc
+++ b/chrome/browser/chromeos/drive/change_list_loader.cc
@@ -389,19 +389,6 @@ void ChangeListLoader::LoadIfNeeded(
Load(directory_fetch_info, callback);
}
-void ChangeListLoader::LoadDirectoryFromServer(
- const std::string& directory_resource_id,
- const FileOperationCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(!callback.is_null());
-
- scheduler_->GetAboutResource(
- base::Bind(&ChangeListLoader::LoadDirectoryFromServerAfterGetAbout,
- weak_ptr_factory_.GetWeakPtr(),
- directory_resource_id,
- callback));
-}
-
void ChangeListLoader::Load(const DirectoryFetchInfo& directory_fetch_info,
const FileOperationCallback& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -677,25 +664,6 @@ void ChangeListLoader::LoadChangeListFromServerAfterUpdate() {
OnLoadFromServerComplete());
}
-void ChangeListLoader::LoadDirectoryFromServerAfterGetAbout(
- const std::string& directory_resource_id,
- const FileOperationCallback& callback,
- google_apis::GDataErrorCode status,
- scoped_ptr<google_apis::AboutResource> about_resource) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(!callback.is_null());
-
- if (GDataToFileError(status) == FILE_ERROR_OK) {
- DCHECK(about_resource);
- last_known_remote_changestamp_ = about_resource->largest_change_id();
- root_folder_id_ = about_resource->root_folder_id();
- }
-
- DoLoadDirectoryFromServer(
- DirectoryFetchInfo(directory_resource_id, last_known_remote_changestamp_),
- callback);
-}
-
void ChangeListLoader::CheckChangestampAndLoadDirectoryIfNeeded(
const DirectoryFetchInfo& directory_fetch_info,
int64 local_changestamp,
diff --git a/chrome/browser/chromeos/drive/change_list_loader.h b/chrome/browser/chromeos/drive/change_list_loader.h
index d4e2a604ec..32141d0936 100644
--- a/chrome/browser/chromeos/drive/change_list_loader.h
+++ b/chrome/browser/chromeos/drive/change_list_loader.h
@@ -98,12 +98,6 @@ class ChangeListLoader {
void LoadIfNeeded(const DirectoryFetchInfo& directory_fetch_info,
const FileOperationCallback& callback);
- // Loads the directory content from the server, without comparing the
- // changestamps. The purpose of this function is to update thumbnail URLs
- // in the directory which can stale over time.
- void LoadDirectoryFromServer(const std::string& directory_resource_id,
- const FileOperationCallback& callback);
-
private:
// Starts the resource metadata loading and calls |callback| when it's
// done. |directory_fetch_info| is used for fast fetch. If there is already
@@ -184,14 +178,6 @@ class ChangeListLoader {
// ================= Implementation for directory loading =================
- // Part of LoadDirectoryFromServer(), called after the current remote
- // changestamp is obtained as |about_resource|.
- void LoadDirectoryFromServerAfterGetAbout(
- const std::string& directory_resource_id,
- const FileOperationCallback& callback,
- google_apis::GDataErrorCode status,
- scoped_ptr<google_apis::AboutResource> about_resource);
-
// Compares the directory's changestamp and |last_known_remote_changestamp_|.
// Starts DoLoadDirectoryFromServer() if the local data is old and runs
// |callback| when finished. If it is up to date, calls back immediately.
diff --git a/chrome/browser/chromeos/drive/drive.proto b/chrome/browser/chromeos/drive/drive.proto
index dc4fa55bf7..c72c49c3bc 100644
--- a/chrome/browser/chromeos/drive/drive.proto
+++ b/chrome/browser/chromeos/drive/drive.proto
@@ -23,10 +23,7 @@ message PlatformFileInfoProto {
// File specific info, which is a part of ResourceEntry.
message FileSpecificInfo {
- // This URL points to a thumbnail image. The thumbnail URL is not permanent
- // as it's not protected by authentication. See crbug.com/127697 for how
- // stale thumbnail URLs are handled.
- optional string thumbnail_url = 1;
+ // The argument with ID 1 (thumbnail_url) had been used, but got deleted.
// This URL is used for opening hosted documents with Google Drive's web
// interface.
diff --git a/chrome/browser/chromeos/drive/drive_integration_service.cc b/chrome/browser/chromeos/drive/drive_integration_service.cc
index 28d2ab04fa..9e4dbd1c64 100644
--- a/chrome/browser/chromeos/drive/drive_integration_service.cc
+++ b/chrome/browser/chromeos/drive/drive_integration_service.cc
@@ -115,9 +115,6 @@ FileError InitializeMetadata(
file_util::FILE_PERMISSION_EXECUTE_BY_GROUP |
file_util::FILE_PERMISSION_EXECUTE_BY_OTHERS);
- util::MigrateCacheFilesFromOldDirectories(cache_root_directory,
- kCacheFileDirectory);
-
if (!metadata_storage->Initialize()) {
LOG(WARNING) << "Failed to initialize the metadata storage.";
return FILE_ERROR_FAILED;
diff --git a/chrome/browser/chromeos/drive/file_cache.cc b/chrome/browser/chromeos/drive/file_cache.cc
index 148d716f75..ca614c3268 100644
--- a/chrome/browser/chromeos/drive/file_cache.cc
+++ b/chrome/browser/chromeos/drive/file_cache.cc
@@ -16,6 +16,7 @@
#include "chrome/browser/chromeos/drive/drive.pb.h"
#include "chrome/browser/chromeos/drive/file_system_util.h"
#include "chrome/browser/chromeos/drive/resource_metadata_storage.h"
+#include "chrome/browser/drive/drive_api_util.h"
#include "chromeos/chromeos_constants.h"
#include "content/public/browser/browser_thread.h"
@@ -69,16 +70,6 @@ void RunGetFileFromCacheCallback(const GetFileFromCacheCallback& callback,
callback.Run(error, *file_path);
}
-// Runs callback with pointers dereferenced.
-// Used to implement GetCacheEntry().
-void RunGetCacheEntryCallback(const GetCacheEntryCallback& callback,
- FileCacheEntry* cache_entry,
- bool success) {
- DCHECK(cache_entry);
- DCHECK(!callback.is_null());
- callback.Run(success, *cache_entry);
-}
-
} // namespace
FileCache::FileCache(ResourceMetadataStorage* storage,
@@ -114,23 +105,6 @@ bool FileCache::IsUnderFileCacheDirectory(const base::FilePath& path) const {
return cache_file_directory_.IsParent(path);
}
-void FileCache::GetCacheEntryOnUIThread(const std::string& id,
- const GetCacheEntryCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(!callback.is_null());
-
- FileCacheEntry* cache_entry = new FileCacheEntry;
- base::PostTaskAndReplyWithResult(
- blocking_task_runner_.get(),
- FROM_HERE,
- base::Bind(&FileCache::GetCacheEntry,
- base::Unretained(this),
- id,
- cache_entry),
- base::Bind(
- &RunGetCacheEntryCallback, callback, base::Owned(cache_entry)));
-}
-
bool FileCache::GetCacheEntry(const std::string& id, FileCacheEntry* entry) {
DCHECK(entry);
AssertOnSequencedWorkerPool();
@@ -194,25 +168,6 @@ FileError FileCache::GetFile(const std::string& id,
return FILE_ERROR_OK;
}
-void FileCache::StoreOnUIThread(const std::string& id,
- const std::string& md5,
- const base::FilePath& source_path,
- FileOperationType file_operation_type,
- const FileOperationCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(!callback.is_null());
-
- base::PostTaskAndReplyWithResult(blocking_task_runner_.get(),
- FROM_HERE,
- base::Bind(&FileCache::Store,
- base::Unretained(this),
- id,
- md5,
- source_path,
- file_operation_type),
- callback);
-}
-
FileError FileCache::Store(const std::string& id,
const std::string& md5,
const base::FilePath& source_path,
@@ -341,18 +296,6 @@ void FileCache::MarkAsUnmountedOnUIThread(
callback);
}
-void FileCache::MarkDirtyOnUIThread(const std::string& id,
- const FileOperationCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(!callback.is_null());
-
- base::PostTaskAndReplyWithResult(
- blocking_task_runner_.get(),
- FROM_HERE,
- base::Bind(&FileCache::MarkDirty, base::Unretained(this), id),
- callback);
-}
-
FileError FileCache::MarkDirty(const std::string& id) {
AssertOnSequencedWorkerPool();
@@ -399,18 +342,6 @@ FileError FileCache::ClearDirty(const std::string& id, const std::string& md5) {
FILE_ERROR_OK : FILE_ERROR_FAILED;
}
-void FileCache::RemoveOnUIThread(const std::string& id,
- const FileOperationCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(!callback.is_null());
-
- base::PostTaskAndReplyWithResult(
- blocking_task_runner_.get(),
- FROM_HERE,
- base::Bind(&FileCache::Remove, base::Unretained(this), id),
- callback);
-}
-
FileError FileCache::Remove(const std::string& id) {
AssertOnSequencedWorkerPool();
@@ -461,7 +392,8 @@ bool FileCache::ClearAll() {
bool FileCache::Initialize() {
AssertOnSequencedWorkerPool();
- RenameCacheFilesToNewFormat();
+ if (!RenameCacheFilesToNewFormat())
+ return false;
if (storage_->cache_file_scan_is_needed()) {
CacheMap cache_map;
@@ -494,11 +426,8 @@ bool FileCache::CanonicalizeIDs(
for (; !it->IsAtEnd(); it->Advance()) {
const std::string id_canonicalized = id_canonicalizer.Run(it->GetID());
if (id_canonicalized != it->GetID()) {
- // Replace the existing entry and rename the file when needed.
- const base::FilePath path_old = GetCacheFilePath(it->GetID());
- const base::FilePath path_new = GetCacheFilePath(id_canonicalized);
+ // Replace the existing entry.
if (!storage_->RemoveCacheEntry(it->GetID()) ||
- (base::PathExists(path_old) && !base::Move(path_old, path_new)) ||
!storage_->PutCacheEntry(id_canonicalized, it->GetValue()))
return false;
}
@@ -595,27 +524,25 @@ bool FileCache::HasEnoughSpaceFor(int64 num_bytes,
return (free_space >= num_bytes);
}
-void FileCache::RenameCacheFilesToNewFormat() {
- // First, remove all files with multiple extensions just in case.
- {
- base::FileEnumerator enumerator(cache_file_directory_,
- false, // not recursive
- base::FileEnumerator::FILES,
- "*.*.*");
- for (base::FilePath current = enumerator.Next(); !current.empty();
- current = enumerator.Next())
- base::DeleteFile(current, false /* recursive */);
- }
-
- // Rename files.
- {
- base::FileEnumerator enumerator(cache_file_directory_,
- false, // not recursive
- base::FileEnumerator::FILES);
- for (base::FilePath current = enumerator.Next(); !current.empty();
- current = enumerator.Next())
- base::Move(current, current.RemoveExtension());
+bool FileCache::RenameCacheFilesToNewFormat() {
+ base::FileEnumerator enumerator(cache_file_directory_,
+ false, // not recursive
+ base::FileEnumerator::FILES);
+ for (base::FilePath current = enumerator.Next(); !current.empty();
+ current = enumerator.Next()) {
+ base::FilePath new_path = current.RemoveExtension();
+ if (!new_path.Extension().empty()) {
+ // Delete files with multiple extensions.
+ if (!base::DeleteFile(current, false /* recursive */))
+ return false;
+ continue;
+ }
+ const std::string& id = GetIdFromPath(new_path);
+ new_path = GetCacheFilePath(util::CanonicalizeResourceId(id));
+ if (new_path != current && !base::Move(current, new_path))
+ return false;
}
+ return true;
}
} // namespace internal
diff --git a/chrome/browser/chromeos/drive/file_cache.h b/chrome/browser/chromeos/drive/file_cache.h
index 2084ee3764..ba6aa1af8f 100644
--- a/chrome/browser/chromeos/drive/file_cache.h
+++ b/chrome/browser/chromeos/drive/file_cache.h
@@ -25,13 +25,6 @@ namespace drive {
class FileCacheEntry;
-// Callback for GetCacheEntry.
-// |success| indicates if the operation was successful.
-// |cache_entry| is the obtained cache entry. On failure, |cache_state| is
-// set to TEST_CACHE_STATE_NONE.
-typedef base::Callback<void(bool success, const FileCacheEntry& cache_entry)>
- GetCacheEntryCallback;
-
namespace internal {
// Callback for GetFileFromCache.
@@ -81,16 +74,8 @@ class FileCache {
// Can be called on any thread.
bool IsUnderFileCacheDirectory(const base::FilePath& path) const;
- // Gets the cache entry for file corresponding to |id| and runs
- // |callback| with true and the entry found if entry exists in cache map.
- // Otherwise, runs |callback| with false.
- // |callback| must not be null.
- // Must be called on the UI thread.
- void GetCacheEntryOnUIThread(const std::string& id,
- const GetCacheEntryCallback& callback);
-
- // Gets the cache entry by the given ID.
- // See also GetCacheEntryOnUIThread().
+ // Gets the cache entry for file corresponding to |id| and returns true if
+ // entry exists in cache map.
bool GetCacheEntry(const std::string& id, FileCacheEntry* entry);
// Returns an object to iterate over entries.
@@ -107,16 +92,6 @@ class FileCache {
// |cache_file_path| must not be null.
FileError GetFile(const std::string& id, base::FilePath* cache_file_path);
- // Runs Store() on |blocking_task_runner_|, and calls |callback| with
- // the result asynchronously.
- // |callback| must not be null.
- // Must be called on the UI thread.
- void StoreOnUIThread(const std::string& id,
- const std::string& md5,
- const base::FilePath& source_path,
- FileOperationType file_operation_type,
- const FileOperationCallback& callback);
-
// Stores |source_path| as a cache of the remote content of the file
// with |id| and |md5|.
FileError Store(const std::string& id,
@@ -161,27 +136,13 @@ class FileCache {
void MarkAsUnmountedOnUIThread(const base::FilePath& file_path,
const FileOperationCallback& callback);
- // Runs MarkDirty() on |blocking_task_runner_|, and calls |callback| with the
- // result asynchronously.
- // |callback| must not be null.
- // Must be called on the UI thread.
- void MarkDirtyOnUIThread(const std::string& id,
- const FileOperationCallback& callback);
-
// Marks the specified entry dirty.
FileError MarkDirty(const std::string& id);
// Clears dirty state of the specified entry and updates its MD5.
FileError ClearDirty(const std::string& id, const std::string& md5);
- // Runs Remove() on |blocking_task_runner_| and runs |callback| with the
- // result.
- // Must be called on the UI thread.
- void RemoveOnUIThread(const std::string& id,
- const FileOperationCallback& callback);
-
// Removes the specified cache entry and delete cache files if available.
- // Synchronous version of RemoveOnUIThread().
FileError Remove(const std::string& id);
// Removes all the files in the cache directory and cache entries in DB.
@@ -232,9 +193,9 @@ class FileCache {
// bytes, while keeping kMinFreeSpace bytes on the disk.
bool HasEnoughSpaceFor(int64 num_bytes, const base::FilePath& path);
- // Renames cache files from old "id.md5" format to the new format.
+ // Renames cache files from old "prefix:id.md5" format to the new format.
// TODO(hashimoto): Remove this method at some point.
- void RenameCacheFilesToNewFormat();
+ bool RenameCacheFilesToNewFormat();
const base::FilePath cache_file_directory_;
diff --git a/chrome/browser/chromeos/drive/file_cache_unittest.cc b/chrome/browser/chromeos/drive/file_cache_unittest.cc
index d0f7d17925..d2c88104ff 100644
--- a/chrome/browser/chromeos/drive/file_cache_unittest.cc
+++ b/chrome/browser/chromeos/drive/file_cache_unittest.cc
@@ -106,9 +106,13 @@ class FileCacheTestOnUIThread : public testing::Test {
expected_cache_state_ = expected_cache_state;
FileError error = FILE_ERROR_OK;
- cache_->StoreOnUIThread(
- id, md5, source_path,
- FileCache::FILE_OPERATION_COPY,
+ base::PostTaskAndReplyWithResult(
+ blocking_task_runner_,
+ FROM_HERE,
+ base::Bind(&internal::FileCache::Store,
+ base::Unretained(cache_.get()),
+ id, md5, source_path,
+ FileCache::FILE_OPERATION_COPY),
google_apis::test_util::CreateCopyResultCallback(&error));
test_util::RunBlockingPoolTask();
@@ -125,8 +129,12 @@ class FileCacheTestOnUIThread : public testing::Test {
expected_error_ = expected_error;
FileError error = FILE_ERROR_OK;
- cache_->RemoveOnUIThread(
- id,
+ base::PostTaskAndReplyWithResult(
+ blocking_task_runner_,
+ FROM_HERE,
+ base::Bind(&internal::FileCache::Remove,
+ base::Unretained(cache_.get()),
+ id),
google_apis::test_util::CreateCopyResultCallback(&error));
test_util::RunBlockingPoolTask();
VerifyRemoveFromCache(error, id);
@@ -179,8 +187,12 @@ class FileCacheTestOnUIThread : public testing::Test {
expected_cache_state_ = expected_cache_state;
FileError error = FILE_ERROR_OK;
- cache_->MarkDirtyOnUIThread(
- id,
+ base::PostTaskAndReplyWithResult(
+ blocking_task_runner_,
+ FROM_HERE,
+ base::Bind(&internal::FileCache::MarkDirty,
+ base::Unretained(cache_.get()),
+ id),
google_apis::test_util::CreateCopyResultCallback(&error));
test_util::RunBlockingPoolTask();
@@ -310,9 +322,14 @@ class FileCacheTestOnUIThread : public testing::Test {
bool GetCacheEntryFromOriginThread(const std::string& id,
FileCacheEntry* cache_entry) {
bool result = false;
- cache_->GetCacheEntryOnUIThread(
- id,
- google_apis::test_util::CreateCopyResultCallback(&result, cache_entry));
+ base::PostTaskAndReplyWithResult(
+ blocking_task_runner_,
+ FROM_HERE,
+ base::Bind(&internal::FileCache::GetCacheEntry,
+ base::Unretained(cache_.get()),
+ id,
+ cache_entry),
+ google_apis::test_util::CreateCopyResultCallback(&result));
test_util::RunBlockingPoolTask();
return result;
}
@@ -721,8 +738,8 @@ class FileCacheTest : public testing::Test {
ASSERT_TRUE(cache_->Initialize());
}
- static void RenameCacheFilesToNewFormat(FileCache* cache) {
- cache->RenameCacheFilesToNewFormat();
+ static bool RenameCacheFilesToNewFormat(FileCache* cache) {
+ return cache->RenameCacheFilesToNewFormat();
}
content::TestBrowserThreadBundle thread_bundle_;
@@ -892,7 +909,6 @@ TEST_F(FileCacheTest, CanonicalizeIDs) {
EXPECT_TRUE(file_util::CreateTemporaryFileInDir(temp_dir_.path(), &file));
EXPECT_EQ(FILE_ERROR_OK,
cache_->Store(id, md5, file, FileCache::FILE_OPERATION_COPY));
- EXPECT_TRUE(base::PathExists(file_directory.AppendASCII(id)));
// Canonicalize IDs.
EXPECT_TRUE(cache_->CanonicalizeIDs(id_canonicalizer));
@@ -901,16 +917,15 @@ TEST_F(FileCacheTest, CanonicalizeIDs) {
FileCacheEntry entry;
EXPECT_FALSE(cache_->GetCacheEntry(id, &entry));
EXPECT_TRUE(cache_->GetCacheEntry(canonicalized_id, &entry));
- EXPECT_TRUE(base::PathExists(file_directory.AppendASCII(canonicalized_id)));
}
TEST_F(FileCacheTest, RenameCacheFilesToNewFormat) {
const base::FilePath file_directory =
temp_dir_.path().AppendASCII(kCacheFileDirectory);
- // File with an old style "<ID>.<MD5>" name.
+ // File with an old style "<prefix>:<ID>.<MD5>" name.
ASSERT_TRUE(google_apis::test_util::WriteStringToFile(
- file_directory.AppendASCII("id_koo.md5"), "koo"));
+ file_directory.AppendASCII("file:id_koo.md5"), "koo"));
// File with multiple extensions should be removed.
ASSERT_TRUE(google_apis::test_util::WriteStringToFile(
@@ -919,27 +934,27 @@ TEST_F(FileCacheTest, RenameCacheFilesToNewFormat) {
file_directory.AppendASCII("id_kyu.md5"), "kyu"));
// Rename and verify the result.
- RenameCacheFilesToNewFormat(cache_.get());
+ EXPECT_TRUE(RenameCacheFilesToNewFormat(cache_.get()));
std::string contents;
EXPECT_TRUE(base::ReadFileToString(file_directory.AppendASCII("id_koo"),
- &contents));
+ &contents));
EXPECT_EQ("koo", contents);
contents.clear();
EXPECT_TRUE(base::ReadFileToString(file_directory.AppendASCII("id_kyu"),
- &contents));
+ &contents));
EXPECT_EQ("kyu", contents);
// Rename again.
- RenameCacheFilesToNewFormat(cache_.get());
+ EXPECT_TRUE(RenameCacheFilesToNewFormat(cache_.get()));
// Files with new style names are not affected.
contents.clear();
EXPECT_TRUE(base::ReadFileToString(file_directory.AppendASCII("id_koo"),
- &contents));
+ &contents));
EXPECT_EQ("koo", contents);
contents.clear();
EXPECT_TRUE(base::ReadFileToString(file_directory.AppendASCII("id_kyu"),
- &contents));
+ &contents));
EXPECT_EQ("kyu", contents);
}
diff --git a/chrome/browser/chromeos/drive/file_system.cc b/chrome/browser/chromeos/drive/file_system.cc
index 0162221cf6..a8ee65dd2b 100644
--- a/chrome/browser/chromeos/drive/file_system.cc
+++ b/chrome/browser/chromeos/drive/file_system.cc
@@ -8,7 +8,6 @@
#include "base/file_util.h"
#include "base/platform_file.h"
#include "base/prefs/pref_service.h"
-#include "base/threading/sequenced_worker_pool.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/drive/change_list_loader.h"
#include "chrome/browser/chromeos/drive/change_list_processor.h"
@@ -38,7 +37,6 @@
#include "chrome/browser/google_apis/drive_api_parser.h"
#include "chrome/common/pref_names.h"
#include "content/public/browser/browser_thread.h"
-#include "net/http/http_status_code.h"
using content::BrowserThread;
@@ -195,45 +193,6 @@ void GetFileCallbackToFileOperationCallbackAdapter(
callback.Run(error);
}
-// Checks whether the |url| passed to the constructor is accessible. If it is
-// not, invokes |on_stale_closure|.
-class StaleURLChecker : public net::URLFetcherDelegate {
- public:
- StaleURLChecker(const GURL& url, const base::Closure& on_stale_closure)
- : on_stale_closure_(on_stale_closure) {
- fetcher_.reset(net::URLFetcher::Create(url, net::URLFetcher::HEAD, this));
- fetcher_->SetRequestContext(g_browser_process->system_request_context());
- fetcher_->Start();
- }
-
- virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE {
- int code = source->GetResponseCode();
- if (code == net::HTTP_FORBIDDEN)
- on_stale_closure_.Run();
- delete this;
- }
-
- private:
- scoped_ptr<net::URLFetcher> fetcher_;
- const base::Closure on_stale_closure_;
-};
-
-// Checks the first thumbnail URL in |entries| whether it is still available
-// by sending a HEAD request. If it's stale, invokes |on_stale_closure|.
-void CheckStaleThumbnailURL(ResourceEntryVector* entries,
- const base::Closure& on_stale_closure) {
- const char kImageThumbnailDomain[] = "googleusercontent.com";
- for (size_t i = 0; i < entries->size(); ++i) {
- const std::string& url =
- entries->at(i).file_specific_info().thumbnail_url();
- if (url.find(kImageThumbnailDomain) != std::string::npos) {
- // The stale URL checker deletes itself.
- new StaleURLChecker(GURL(url), on_stale_closure);
- break;
- }
- }
-}
-
// Clears |resource_metadata| and |cache|.
FileError ResetOnBlockingPool(internal::ResourceMetadata* resource_metadata,
internal::FileCache* cache) {
@@ -792,14 +751,6 @@ void FileSystem::ReadDirectoryByPathAfterRead(
filtered->push_back(entries->at(i));
}
- // Thumbnail URLs are short-lived. We check the validness of the URL in
- // background, and refresh the metadata for the directory if necessary.
- // TODO(kinaba): Remove this hack by using persistent URLs crbug.com/254025.
- CheckStaleThumbnailURL(filtered.get(),
- base::Bind(&FileSystem::RefreshDirectory,
- weak_ptr_factory_.GetWeakPtr(),
- directory_path));
-
callback.Run(FILE_ERROR_OK, filtered.Pass());
}
@@ -1041,34 +992,4 @@ void FileSystem::OpenFile(const base::FilePath& file_path,
open_file_operation_->OpenFile(file_path, open_mode, mime_type, callback);
}
-void FileSystem::RefreshDirectory(const base::FilePath& directory_path) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- resource_metadata_->GetResourceEntryByPathOnUIThread(
- directory_path,
- base::Bind(&FileSystem::RefreshDirectoryAfterGetResourceEntry,
- weak_ptr_factory_.GetWeakPtr(),
- directory_path));
-}
-
-void FileSystem::RefreshDirectoryAfterGetResourceEntry(
- const base::FilePath& directory_path,
- FileError error,
- scoped_ptr<ResourceEntry> entry) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- if (error != FILE_ERROR_OK || !entry->file_info().is_directory())
- return;
-
- // Do not load special directories. Just return.
- const std::string& id = entry->resource_id();
- if (util::IsSpecialResourceId(id))
- return;
-
- util::Log(logging::LOG_INFO,
- "Thumbnail refresh for %s", directory_path.AsUTF8Unsafe().c_str());
- change_list_loader_->LoadDirectoryFromServer(
- id, base::Bind(&util::EmptyFileOperationCallback));
-}
-
} // namespace drive
diff --git a/chrome/browser/chromeos/drive/file_system.h b/chrome/browser/chromeos/drive/file_system.h
index 07e4479fbc..4f79ed6def 100644
--- a/chrome/browser/chromeos/drive/file_system.h
+++ b/chrome/browser/chromeos/drive/file_system.h
@@ -36,6 +36,7 @@ class JobScheduler;
namespace internal {
class ChangeListLoader;
+class FileCache;
class ResourceMetadata;
class SyncClient;
} // namespace internal
@@ -256,13 +257,6 @@ class FileSystem : public FileSystemInterface,
google_apis::GDataErrorCode status,
const GURL& share_url);
- // Reloads the metadata for the directory to refresh stale thumbnail URLs.
- void RefreshDirectory(const base::FilePath& directory_path);
- void RefreshDirectoryAfterGetResourceEntry(
- const base::FilePath& directory_path,
- FileError error,
- scoped_ptr<ResourceEntry> entry);
-
// Used to get Drive related preferences.
PrefService* pref_service_;
diff --git a/chrome/browser/chromeos/drive/file_system/copy_operation_unittest.cc b/chrome/browser/chromeos/drive/file_system/copy_operation_unittest.cc
index 2afd3edc77..1c43ac9ac8 100644
--- a/chrome/browser/chromeos/drive/file_system/copy_operation_unittest.cc
+++ b/chrome/browser/chromeos/drive/file_system/copy_operation_unittest.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/chromeos/drive/file_system/copy_operation.h"
#include "base/file_util.h"
+#include "base/task_runner_util.h"
#include "chrome/browser/chromeos/drive/file_system/operation_test_base.h"
#include "chrome/browser/chromeos/drive/file_system_util.h"
#include "chrome/browser/drive/drive_api_util.h"
@@ -60,9 +61,14 @@ TEST_F(CopyOperationTest, TransferFileFromLocalToRemote_RegularFile) {
GetLocalId(remote_dest_path)));
FileCacheEntry cache_entry;
bool found = false;
- cache()->GetCacheEntryOnUIThread(
- GetLocalId(remote_dest_path),
- google_apis::test_util::CreateCopyResultCallback(&found, &cache_entry));
+ base::PostTaskAndReplyWithResult(
+ blocking_task_runner(),
+ FROM_HERE,
+ base::Bind(&internal::FileCache::GetCacheEntry,
+ base::Unretained(cache()),
+ GetLocalId(remote_dest_path),
+ &cache_entry),
+ google_apis::test_util::CreateCopyResultCallback(&found));
test_util::RunBlockingPoolTask();
EXPECT_TRUE(found);
EXPECT_TRUE(cache_entry.is_present());
diff --git a/chrome/browser/chromeos/drive/file_system/download_operation_unittest.cc b/chrome/browser/chromeos/drive/file_system/download_operation_unittest.cc
index 282336a6a3..cbb75ded13 100644
--- a/chrome/browser/chromeos/drive/file_system/download_operation_unittest.cc
+++ b/chrome/browser/chromeos/drive/file_system/download_operation_unittest.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/chromeos/drive/file_system/download_operation.h"
#include "base/file_util.h"
+#include "base/task_runner_util.h"
#include "chrome/browser/chromeos/drive/fake_free_disk_space_getter.h"
#include "chrome/browser/chromeos/drive/file_cache.h"
#include "chrome/browser/chromeos/drive/file_system/operation_test_base.h"
@@ -117,9 +118,13 @@ TEST_F(DownloadOperationTest,
ASSERT_TRUE(google_apis::test_util::WriteStringToFile(tmp_file, content));
FileError error = FILE_ERROR_FAILED;
- cache()->StoreOnUIThread(
- "<id>", "<md5>", tmp_file,
- internal::FileCache::FILE_OPERATION_COPY,
+ base::PostTaskAndReplyWithResult(
+ blocking_task_runner(),
+ FROM_HERE,
+ base::Bind(&internal::FileCache::Store,
+ base::Unretained(cache()),
+ "<id>", "<md5>", tmp_file,
+ internal::FileCache::FILE_OPERATION_COPY),
google_apis::test_util::CreateCopyResultCallback(&error));
test_util::RunBlockingPoolTask();
EXPECT_EQ(FILE_ERROR_OK, error);
@@ -147,10 +152,14 @@ TEST_F(DownloadOperationTest,
// The cache entry should be removed in order to free up space.
FileCacheEntry cache_entry;
bool result = true;
- cache()->GetCacheEntryOnUIThread(
- "<id>",
- google_apis::test_util::CreateCopyResultCallback(&result,
- &cache_entry));
+ base::PostTaskAndReplyWithResult(
+ blocking_task_runner(),
+ FROM_HERE,
+ base::Bind(&internal::FileCache::GetCacheEntry,
+ base::Unretained(cache()),
+ "<id>",
+ &cache_entry),
+ google_apis::test_util::CreateCopyResultCallback(&result));
test_util::RunBlockingPoolTask();
ASSERT_FALSE(result);
}
@@ -196,11 +205,15 @@ TEST_F(DownloadOperationTest, EnsureFileDownloadedByPath_FromCache) {
// Store something as cached version of this file.
FileError error = FILE_ERROR_OK;
- cache()->StoreOnUIThread(
- GetLocalId(file_in_root),
- src_entry.file_specific_info().md5(),
- temp_file,
- internal::FileCache::FILE_OPERATION_COPY,
+ base::PostTaskAndReplyWithResult(
+ blocking_task_runner(),
+ FROM_HERE,
+ base::Bind(&internal::FileCache::Store,
+ base::Unretained(cache()),
+ GetLocalId(file_in_root),
+ src_entry.file_specific_info().md5(),
+ temp_file,
+ internal::FileCache::FILE_OPERATION_COPY),
google_apis::test_util::CreateCopyResultCallback(&error));
test_util::RunBlockingPoolTask();
EXPECT_EQ(FILE_ERROR_OK, error);
@@ -359,11 +372,15 @@ TEST_F(DownloadOperationTest, EnsureFileDownloadedByLocalId_FromCache) {
// Store something as cached version of this file.
FileError error = FILE_ERROR_FAILED;
- cache()->StoreOnUIThread(
- GetLocalId(file_in_root),
- src_entry.file_specific_info().md5(),
- temp_file,
- internal::FileCache::FILE_OPERATION_COPY,
+ base::PostTaskAndReplyWithResult(
+ blocking_task_runner(),
+ FROM_HERE,
+ base::Bind(&internal::FileCache::Store,
+ base::Unretained(cache()),
+ GetLocalId(file_in_root),
+ src_entry.file_specific_info().md5(),
+ temp_file,
+ internal::FileCache::FILE_OPERATION_COPY),
google_apis::test_util::CreateCopyResultCallback(&error));
test_util::RunBlockingPoolTask();
EXPECT_EQ(FILE_ERROR_OK, error);
@@ -402,16 +419,24 @@ TEST_F(DownloadOperationTest, EnsureFileDownloadedByPath_DirtyCache) {
// Store the file as a cache, marking it to be dirty.
FileError error = FILE_ERROR_FAILED;
- cache()->StoreOnUIThread(
- GetLocalId(file_in_root),
- src_entry.file_specific_info().md5(),
- dirty_file,
- internal::FileCache::FILE_OPERATION_COPY,
+ base::PostTaskAndReplyWithResult(
+ blocking_task_runner(),
+ FROM_HERE,
+ base::Bind(&internal::FileCache::Store,
+ base::Unretained(cache()),
+ GetLocalId(file_in_root),
+ src_entry.file_specific_info().md5(),
+ dirty_file,
+ internal::FileCache::FILE_OPERATION_COPY),
google_apis::test_util::CreateCopyResultCallback(&error));
test_util::RunBlockingPoolTask();
EXPECT_EQ(FILE_ERROR_OK, error);
- cache()->MarkDirtyOnUIThread(
- GetLocalId(file_in_root),
+ base::PostTaskAndReplyWithResult(
+ blocking_task_runner(),
+ FROM_HERE,
+ base::Bind(&internal::FileCache::MarkDirty,
+ base::Unretained(cache()),
+ GetLocalId(file_in_root)),
google_apis::test_util::CreateCopyResultCallback(&error));
test_util::RunBlockingPoolTask();
EXPECT_EQ(FILE_ERROR_OK, error);
diff --git a/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation.cc b/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation.cc
index fb5a79ef80..e1964a4efb 100644
--- a/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation.cc
+++ b/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation.cc
@@ -6,6 +6,7 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
+#include "chrome/browser/chromeos/drive/file_cache.h"
#include "chrome/browser/chromeos/drive/file_system/create_file_operation.h"
#include "chrome/browser/chromeos/drive/file_system/download_operation.h"
#include "chrome/browser/chromeos/drive/file_system/operation_observer.h"
diff --git a/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation_unittest.cc b/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation_unittest.cc
index a234111513..4efa89b893 100644
--- a/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation_unittest.cc
+++ b/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation_unittest.cc
@@ -8,6 +8,7 @@
#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/run_loop.h"
+#include "base/task_runner_util.h"
#include "chrome/browser/chromeos/drive/drive.pb.h"
#include "chrome/browser/chromeos/drive/file_errors.h"
#include "chrome/browser/chromeos/drive/file_system/operation_test_base.h"
@@ -92,9 +93,14 @@ TEST_F(GetFileForSavingOperationTest, GetFileForSaving_Exist) {
// Checks that it presents in cache and marked dirty.
bool success = false;
FileCacheEntry cache_entry;
- cache()->GetCacheEntryOnUIThread(
- GetLocalId(drive_path),
- google_apis::test_util::CreateCopyResultCallback(&success, &cache_entry));
+ base::PostTaskAndReplyWithResult(
+ blocking_task_runner(),
+ FROM_HERE,
+ base::Bind(&internal::FileCache::GetCacheEntry,
+ base::Unretained(cache()),
+ GetLocalId(drive_path),
+ &cache_entry),
+ google_apis::test_util::CreateCopyResultCallback(&success));
test_util::RunBlockingPoolTask();
EXPECT_TRUE(success);
EXPECT_TRUE(cache_entry.is_present());
diff --git a/chrome/browser/chromeos/drive/file_system/open_file_operation_unittest.cc b/chrome/browser/chromeos/drive/file_system/open_file_operation_unittest.cc
index 3a7eba4e92..8bfdeb4d05 100644
--- a/chrome/browser/chromeos/drive/file_system/open_file_operation_unittest.cc
+++ b/chrome/browser/chromeos/drive/file_system/open_file_operation_unittest.cc
@@ -9,6 +9,7 @@
#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/memory/scoped_ptr.h"
+#include "base/task_runner_util.h"
#include "chrome/browser/chromeos/drive/drive.pb.h"
#include "chrome/browser/chromeos/drive/file_errors.h"
#include "chrome/browser/chromeos/drive/file_system/operation_test_base.h"
@@ -168,9 +169,14 @@ TEST_F(OpenFileOperationTest, OpenOrCreateExistingFile) {
bool success = false;
FileCacheEntry cache_entry;
- cache()->GetCacheEntryOnUIThread(
- src_entry.local_id(),
- google_apis::test_util::CreateCopyResultCallback(&success, &cache_entry));
+ base::PostTaskAndReplyWithResult(
+ blocking_task_runner(),
+ FROM_HERE,
+ base::Bind(&internal::FileCache::GetCacheEntry,
+ base::Unretained(cache()),
+ src_entry.local_id(),
+ &cache_entry),
+ google_apis::test_util::CreateCopyResultCallback(&success));
test_util::RunBlockingPoolTask();
EXPECT_TRUE(success);
EXPECT_TRUE(cache_entry.is_present());
diff --git a/chrome/browser/chromeos/drive/file_system/update_operation_unittest.cc b/chrome/browser/chromeos/drive/file_system/update_operation_unittest.cc
index f194efa711..4964acfaf6 100644
--- a/chrome/browser/chromeos/drive/file_system/update_operation_unittest.cc
+++ b/chrome/browser/chromeos/drive/file_system/update_operation_unittest.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/chromeos/drive/file_system/update_operation.h"
+#include "base/task_runner_util.h"
#include "chrome/browser/chromeos/drive/file_system/operation_test_base.h"
#include "chrome/browser/chromeos/drive/file_system_interface.h"
#include "chrome/browser/drive/fake_drive_service.h"
@@ -50,17 +51,25 @@ TEST_F(UpdateOperationTest, UpdateFileByLocalId_PersistentFile) {
// First store a file to cache.
error = FILE_ERROR_FAILED;
- cache()->StoreOnUIThread(
- local_id, kMd5, kTestFile,
- internal::FileCache::FILE_OPERATION_COPY,
+ base::PostTaskAndReplyWithResult(
+ blocking_task_runner(),
+ FROM_HERE,
+ base::Bind(&internal::FileCache::Store,
+ base::Unretained(cache()),
+ local_id, kMd5, kTestFile,
+ internal::FileCache::FILE_OPERATION_COPY),
google_apis::test_util::CreateCopyResultCallback(&error));
test_util::RunBlockingPoolTask();
EXPECT_EQ(FILE_ERROR_OK, error);
// Add the dirty bit.
error = FILE_ERROR_FAILED;
- cache()->MarkDirtyOnUIThread(
- local_id,
+ base::PostTaskAndReplyWithResult(
+ blocking_task_runner(),
+ FROM_HERE,
+ base::Bind(&internal::FileCache::MarkDirty,
+ base::Unretained(cache()),
+ local_id),
google_apis::test_util::CreateCopyResultCallback(&error));
test_util::RunBlockingPoolTask();
EXPECT_EQ(FILE_ERROR_OK, error);
@@ -95,9 +104,14 @@ TEST_F(UpdateOperationTest, UpdateFileByLocalId_PersistentFile) {
// Make sure that the cache is no longer dirty.
bool success = false;
FileCacheEntry cache_entry;
- cache()->GetCacheEntryOnUIThread(
- local_id,
- google_apis::test_util::CreateCopyResultCallback(&success, &cache_entry));
+ base::PostTaskAndReplyWithResult(
+ blocking_task_runner(),
+ FROM_HERE,
+ base::Bind(&internal::FileCache::GetCacheEntry,
+ base::Unretained(cache()),
+ local_id,
+ &cache_entry),
+ google_apis::test_util::CreateCopyResultCallback(&success));
test_util::RunBlockingPoolTask();
ASSERT_TRUE(success);
EXPECT_FALSE(cache_entry.is_dirty());
@@ -128,17 +142,25 @@ TEST_F(UpdateOperationTest, UpdateFileByLocalId_Md5) {
// First store a file to cache.
FileError error = FILE_ERROR_FAILED;
- cache()->StoreOnUIThread(
- local_id, kMd5, kTestFile,
- internal::FileCache::FILE_OPERATION_COPY,
+ base::PostTaskAndReplyWithResult(
+ blocking_task_runner(),
+ FROM_HERE,
+ base::Bind(&internal::FileCache::Store,
+ base::Unretained(cache()),
+ local_id, kMd5, kTestFile,
+ internal::FileCache::FILE_OPERATION_COPY),
google_apis::test_util::CreateCopyResultCallback(&error));
test_util::RunBlockingPoolTask();
EXPECT_EQ(FILE_ERROR_OK, error);
// Add the dirty bit.
error = FILE_ERROR_FAILED;
- cache()->MarkDirtyOnUIThread(
- local_id,
+ base::PostTaskAndReplyWithResult(
+ blocking_task_runner(),
+ FROM_HERE,
+ base::Bind(&internal::FileCache::MarkDirty,
+ base::Unretained(cache()),
+ local_id),
google_apis::test_util::CreateCopyResultCallback(&error));
test_util::RunBlockingPoolTask();
EXPECT_EQ(FILE_ERROR_OK, error);
@@ -173,17 +195,26 @@ TEST_F(UpdateOperationTest, UpdateFileByLocalId_Md5) {
// Make sure that the cache is no longer dirty.
bool success = false;
FileCacheEntry cache_entry;
- cache()->GetCacheEntryOnUIThread(
- local_id,
- google_apis::test_util::CreateCopyResultCallback(&success, &cache_entry));
+ base::PostTaskAndReplyWithResult(
+ blocking_task_runner(),
+ FROM_HERE,
+ base::Bind(&internal::FileCache::GetCacheEntry,
+ base::Unretained(cache()),
+ local_id,
+ &cache_entry),
+ google_apis::test_util::CreateCopyResultCallback(&success));
test_util::RunBlockingPoolTask();
ASSERT_TRUE(success);
EXPECT_FALSE(cache_entry.is_dirty());
// Again mark the cache file dirty.
error = FILE_ERROR_FAILED;
- cache()->MarkDirtyOnUIThread(
- local_id,
+ base::PostTaskAndReplyWithResult(
+ blocking_task_runner(),
+ FROM_HERE,
+ base::Bind(&internal::FileCache::MarkDirty,
+ base::Unretained(cache()),
+ local_id),
google_apis::test_util::CreateCopyResultCallback(&error));
test_util::RunBlockingPoolTask();
EXPECT_EQ(FILE_ERROR_OK, error);
@@ -205,17 +236,26 @@ TEST_F(UpdateOperationTest, UpdateFileByLocalId_Md5) {
// Make sure that the cache is no longer dirty.
success = false;
- cache()->GetCacheEntryOnUIThread(
- local_id,
- google_apis::test_util::CreateCopyResultCallback(&success, &cache_entry));
+ base::PostTaskAndReplyWithResult(
+ blocking_task_runner(),
+ FROM_HERE,
+ base::Bind(&internal::FileCache::GetCacheEntry,
+ base::Unretained(cache()),
+ local_id,
+ &cache_entry),
+ google_apis::test_util::CreateCopyResultCallback(&success));
test_util::RunBlockingPoolTask();
ASSERT_TRUE(success);
EXPECT_FALSE(cache_entry.is_dirty());
// Once again mark the cache file dirty.
error = FILE_ERROR_FAILED;
- cache()->MarkDirtyOnUIThread(
- local_id,
+ base::PostTaskAndReplyWithResult(
+ blocking_task_runner(),
+ FROM_HERE,
+ base::Bind(&internal::FileCache::MarkDirty,
+ base::Unretained(cache()),
+ local_id),
google_apis::test_util::CreateCopyResultCallback(&error));
test_util::RunBlockingPoolTask();
EXPECT_EQ(FILE_ERROR_OK, error);
diff --git a/chrome/browser/chromeos/drive/file_system_interface.h b/chrome/browser/chromeos/drive/file_system_interface.h
index 59373eeea1..93870eb80e 100644
--- a/chrome/browser/chromeos/drive/file_system_interface.h
+++ b/chrome/browser/chromeos/drive/file_system_interface.h
@@ -10,7 +10,6 @@
#include "base/memory/scoped_ptr.h"
#include "chrome/browser/chromeos/drive/drive.pb.h"
-#include "chrome/browser/chromeos/drive/file_cache.h"
#include "chrome/browser/chromeos/drive/file_system_metadata.h"
#include "chrome/browser/chromeos/drive/resource_metadata.h"
#include "chrome/browser/google_apis/base_requests.h"
@@ -120,6 +119,12 @@ typedef base::Callback<void(FileError error,
const base::FilePath& file_path)>
MarkMountedCallback;
+// Callback for GetCacheEntryByPath.
+// |success| indicates if the operation was successful.
+// |cache_entry| is the obtained cache entry.
+typedef base::Callback<void(bool success, const FileCacheEntry& cache_entry)>
+ GetCacheEntryCallback;
+
// The mode of opening a file.
enum OpenMode {
// Open the file if exists. If not, failed.
diff --git a/chrome/browser/chromeos/drive/file_system_unittest.cc b/chrome/browser/chromeos/drive/file_system_unittest.cc
index 9715fb6036..29623b0654 100644
--- a/chrome/browser/chromeos/drive/file_system_unittest.cc
+++ b/chrome/browser/chromeos/drive/file_system_unittest.cc
@@ -33,8 +33,6 @@
namespace drive {
namespace {
-const int64 kLotsOfSpace = internal::kMinFreeSpace * 10;
-
// Counts the number of invocation, and if it increased up to |expected_counter|
// quits the current message loop by calling |quit|.
void AsyncInitializationCallback(
diff --git a/chrome/browser/chromeos/drive/file_system_util.cc b/chrome/browser/chromeos/drive/file_system_util.cc
index db13b712cb..40acfd7440 100644
--- a/chrome/browser/chromeos/drive/file_system_util.cc
+++ b/chrome/browser/chromeos/drive/file_system_util.cc
@@ -10,7 +10,6 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/file_util.h"
-#include "base/files/file_enumerator.h"
#include "base/files/file_path.h"
#include "base/files/scoped_platform_file_closer.h"
#include "base/i18n/icu_string_conversions.h"
@@ -101,19 +100,6 @@ std::string ReadStringFromGDocFile(const base::FilePath& file_path,
return result;
}
-// Moves all files under |directory_from| to |directory_to|.
-void MoveAllFilesFromDirectory(const base::FilePath& directory_from,
- const base::FilePath& directory_to) {
- base::FileEnumerator enumerator(directory_from, false, // not recursive
- base::FileEnumerator::FILES);
- for (base::FilePath file_from = enumerator.Next(); !file_from.empty();
- file_from = enumerator.Next()) {
- const base::FilePath file_to = directory_to.Append(file_from.BaseName());
- if (!base::PathExists(file_to)) // Do not overwrite existing files.
- base::Move(file_from, file_to);
- }
-}
-
// Returns DriveIntegrationService instance, if Drive is enabled.
// Otherwise, NULL.
DriveIntegrationService* GetIntegrationServiceByProfile(Profile* profile) {
@@ -323,27 +309,6 @@ std::string NormalizeFileName(const std::string& input) {
return output;
}
-void MigrateCacheFilesFromOldDirectories(
- const base::FilePath& cache_root_directory,
- const base::FilePath::StringType& cache_file_directory_name) {
- const base::FilePath persistent_directory =
- cache_root_directory.AppendASCII("persistent");
- const base::FilePath tmp_directory =
- cache_root_directory.AppendASCII("tmp");
- if (!base::PathExists(persistent_directory))
- return;
-
- const base::FilePath cache_file_directory =
- cache_root_directory.Append(cache_file_directory_name);
-
- // Move all files inside "persistent" to "files".
- MoveAllFilesFromDirectory(persistent_directory, cache_file_directory);
- base::DeleteFile(persistent_directory, true /* recursive */);
-
- // Move all files inside "tmp" to "files".
- MoveAllFilesFromDirectory(tmp_directory, cache_file_directory);
-}
-
void PrepareWritableFileAndRun(Profile* profile,
const base::FilePath& path,
const PrepareWritableFileCallback& callback) {
diff --git a/chrome/browser/chromeos/drive/file_system_util.h b/chrome/browser/chromeos/drive/file_system_util.h
index a10e497faf..8af03ec908 100644
--- a/chrome/browser/chromeos/drive/file_system_util.h
+++ b/chrome/browser/chromeos/drive/file_system_util.h
@@ -141,13 +141,6 @@ std::string NormalizeFileName(const std::string& input);
// profile.
base::FilePath GetCacheRootPath(Profile* profile);
-// Migrates cache files from old "persistent" and "tmp" directories to the new
-// "files" directory (see crbug.com/248905).
-// TODO(hashimoto): Remove this function at some point.
-void MigrateCacheFilesFromOldDirectories(
- const base::FilePath& cache_root_directory,
- const base::FilePath::StringType& cache_file_directory_name);
-
// Callback type for PrepareWritableFileAndRun.
typedef base::Callback<void (FileError, const base::FilePath& path)>
PrepareWritableFileCallback;
diff --git a/chrome/browser/chromeos/drive/file_system_util_unittest.cc b/chrome/browser/chromeos/drive/file_system_util_unittest.cc
index a8b597943c..b298a10c4e 100644
--- a/chrome/browser/chromeos/drive/file_system_util_unittest.cc
+++ b/chrome/browser/chromeos/drive/file_system_util_unittest.cc
@@ -180,36 +180,6 @@ TEST(FileSystemUtilTest, GetCacheRootPath) {
util::GetCacheRootPath(&profile));
}
-TEST(FileSystemUtilTest, MigrateCacheFilesFromOldDirectories) {
- base::ScopedTempDir temp_dir;
- ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
-
- const base::FilePath persistent_directory =
- temp_dir.path().AppendASCII("persistent");
- const base::FilePath tmp_directory = temp_dir.path().AppendASCII("tmp");
- const base::FilePath files_directory =
- temp_dir.path().AppendASCII("files");
-
- // Prepare directories.
- ASSERT_TRUE(file_util::CreateDirectory(persistent_directory));
- ASSERT_TRUE(file_util::CreateDirectory(tmp_directory));
- ASSERT_TRUE(file_util::CreateDirectory(files_directory));
-
- // Put some files.
- ASSERT_TRUE(google_apis::test_util::WriteStringToFile(
- persistent_directory.AppendASCII("foo.abc"), "foo"));
- ASSERT_TRUE(google_apis::test_util::WriteStringToFile(
- tmp_directory.AppendASCII("bar.123"), "bar"));
-
- // Migrate.
- MigrateCacheFilesFromOldDirectories(temp_dir.path(),
- FILE_PATH_LITERAL("files"));
-
- EXPECT_FALSE(base::PathExists(persistent_directory));
- EXPECT_TRUE(base::PathExists(files_directory.AppendASCII("foo.abc")));
- EXPECT_TRUE(base::PathExists(files_directory.AppendASCII("bar.123")));
-}
-
TEST(FileSystemUtilTest, NeedsNamespaceMigration) {
// Not Drive cases.
EXPECT_FALSE(NeedsNamespaceMigration(
diff --git a/chrome/browser/chromeos/drive/resource_entry_conversion.cc b/chrome/browser/chromeos/drive/resource_entry_conversion.cc
index e0a7cd957c..20aa9783b5 100644
--- a/chrome/browser/chromeos/drive/resource_entry_conversion.cc
+++ b/chrome/browser/chromeos/drive/resource_entry_conversion.cc
@@ -101,11 +101,6 @@ bool ConvertToResourceEntry(const google_apis::ResourceEntry& input,
file_specific_info->set_content_mime_type(input.content_mime_type());
file_specific_info->set_is_hosted_document(input.is_hosted_document());
- const google_apis::Link* thumbnail_link =
- input.GetLinkByType(google_apis::Link::LINK_THUMBNAIL);
- if (thumbnail_link)
- file_specific_info->set_thumbnail_url(thumbnail_link->href().spec());
-
const google_apis::Link* alternate_link =
input.GetLinkByType(google_apis::Link::LINK_ALTERNATE);
if (alternate_link)
diff --git a/chrome/browser/chromeos/drive/resource_entry_conversion_unittest.cc b/chrome/browser/chromeos/drive/resource_entry_conversion_unittest.cc
index 95b573aa7a..f49277f6f7 100644
--- a/chrome/browser/chromeos/drive/resource_entry_conversion_unittest.cc
+++ b/chrome/browser/chromeos/drive/resource_entry_conversion_unittest.cc
@@ -78,8 +78,6 @@ TEST(ResourceEntryConversionTest, ConvertToResourceEntry_File) {
EXPECT_EQ("audio/mpeg",
entry.file_specific_info().content_mime_type());
EXPECT_FALSE(entry.file_specific_info().is_hosted_document());
- EXPECT_EQ("",
- entry.file_specific_info().thumbnail_url());
EXPECT_EQ("https://file_link_alternate/",
entry.file_specific_info().alternate_url());
@@ -162,8 +160,6 @@ TEST(ResourceEntryConversionTest,
EXPECT_EQ("text/html",
entry.file_specific_info().content_mime_type());
EXPECT_TRUE(entry.file_specific_info().is_hosted_document());
- EXPECT_EQ("https://3_document_thumbnail_link/",
- entry.file_specific_info().thumbnail_url());
EXPECT_EQ("https://3_document_alternate_link/",
entry.file_specific_info().alternate_url());
@@ -316,8 +312,6 @@ TEST(ResourceEntryConversionTest,
EXPECT_EQ("text/html",
entry.file_specific_info().content_mime_type());
EXPECT_TRUE(entry.file_specific_info().is_hosted_document());
- EXPECT_EQ("",
- entry.file_specific_info().thumbnail_url());
EXPECT_EQ("https://alternate/document%3Adeleted_in_root_id/edit",
entry.file_specific_info().alternate_url());
diff --git a/chrome/browser/chromeos/drive/resource_metadata.cc b/chrome/browser/chromeos/drive/resource_metadata.cc
index de07b4d250..b0e5f87358 100644
--- a/chrome/browser/chromeos/drive/resource_metadata.cc
+++ b/chrome/browser/chromeos/drive/resource_metadata.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/chromeos/drive/resource_metadata.h"
+#include "base/guid.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/sys_info.h"
@@ -161,6 +162,7 @@ FileError ResourceMetadata::SetLargestChangestamp(int64 value) {
FileError ResourceMetadata::AddEntry(const ResourceEntry& entry,
std::string* out_id) {
DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
+ DCHECK(entry.local_id().empty());
if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path()))
return FILE_ERROR_NO_LOCAL_SPACE;
@@ -177,8 +179,13 @@ FileError ResourceMetadata::AddEntry(const ResourceEntry& entry,
!parent.file_info().is_directory())
return FILE_ERROR_NOT_FOUND;
- // TODO(hashimoto): Generate local ID here. crbug.com/26051
- const std::string local_id = entry.resource_id();
+ // Generate unique local ID.
+ std::string local_id;
+ ResourceEntry existing_entry;
+ do {
+ local_id = base::GenerateGUID();
+ } while (storage_->GetEntry(local_id, &existing_entry));
+
ResourceEntry new_entry(entry);
new_entry.set_local_id(local_id);
@@ -208,24 +215,6 @@ FileError ResourceMetadata::RemoveEntry(const std::string& id) {
return FILE_ERROR_OK;
}
-void ResourceMetadata::GetResourceEntryByIdOnUIThread(
- const std::string& id,
- const GetResourceEntryCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(!callback.is_null());
-
- scoped_ptr<ResourceEntry> entry(new ResourceEntry);
- ResourceEntry* entry_ptr = entry.get();
- base::PostTaskAndReplyWithResult(
- blocking_task_runner_.get(),
- FROM_HERE,
- base::Bind(&ResourceMetadata::GetResourceEntryById,
- base::Unretained(this),
- id,
- entry_ptr),
- base::Bind(&RunGetResourceEntryCallback, callback, base::Passed(&entry)));
-}
-
FileError ResourceMetadata::GetResourceEntryById(const std::string& id,
ResourceEntry* out_entry) {
DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
@@ -415,13 +404,8 @@ FileError ResourceMetadata::GetIdByResourceId(const std::string& resource_id,
std::string* out_local_id) {
DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
- // TODO(hashimoto): Implement the real resource ID to local ID look up.
- // crbug.com/260514
- ResourceEntry entry;
- FileError error = GetResourceEntryById(resource_id, &entry);
- if (error == FILE_ERROR_OK)
- *out_local_id = resource_id;
- return error;
+ return storage_->GetIdByResourceId(resource_id, out_local_id) ?
+ FILE_ERROR_OK : FILE_ERROR_NOT_FOUND;
}
bool ResourceMetadata::PutEntryUnderDirectory(const ResourceEntry& entry) {
diff --git a/chrome/browser/chromeos/drive/resource_metadata.h b/chrome/browser/chromeos/drive/resource_metadata.h
index aa40bed61f..e669114490 100644
--- a/chrome/browser/chromeos/drive/resource_metadata.h
+++ b/chrome/browser/chromeos/drive/resource_metadata.h
@@ -73,12 +73,6 @@ class ResourceMetadata {
FileError RemoveEntry(const std::string& id);
// Finds an entry (a file or a directory) by |id|.
- // |callback| must not be null.
- // Must be called on the UI thread.
- void GetResourceEntryByIdOnUIThread(const std::string& id,
- const GetResourceEntryCallback& callback);
-
- // Synchronous version of GetResourceEntryByIdOnUIThread().
FileError GetResourceEntryById(const std::string& id,
ResourceEntry* out_entry);
diff --git a/chrome/browser/chromeos/drive/resource_metadata_storage.cc b/chrome/browser/chromeos/drive/resource_metadata_storage.cc
index 528998a779..948e737f4e 100644
--- a/chrome/browser/chromeos/drive/resource_metadata_storage.cc
+++ b/chrome/browser/chromeos/drive/resource_metadata_storage.cc
@@ -42,6 +42,9 @@ const char kDBKeyDelimeter = '\0';
// String used as a suffix of a key for a cache entry.
const char kCacheEntryKeySuffix[] = "CACHE";
+// String used as a prefix of a key for a resource-ID-to-local-ID entry.
+const char kIdEntryKeyPrefix[] = "ID";
+
// Returns a string to be used as the key for the header.
std::string GetHeaderDBKey() {
std::string key;
@@ -77,6 +80,30 @@ bool IsCacheEntryKey(const leveldb::Slice& key) {
return key_substring.compare(expected_suffix) == 0;
}
+// Returns a string to be used as a key for a resource-ID-to-local-ID entry.
+std::string GetIdEntryKey(const std::string& resource_id) {
+ std::string key;
+ key.push_back(kDBKeyDelimeter);
+ key.append(kIdEntryKeyPrefix);
+ key.push_back(kDBKeyDelimeter);
+ key.append(resource_id);
+ return key;
+}
+
+// Returns true if |key| is a key for a resource-ID-to-local-ID entry.
+bool IsIdEntryKey(const leveldb::Slice& key) {
+ // A resource-ID-to-local-ID entry key should start with
+ // |kDBKeyDelimeter + kIdEntryKeyPrefix + kDBKeyDelimeter|.
+ const leveldb::Slice expected_prefix(kIdEntryKeyPrefix,
+ arraysize(kIdEntryKeyPrefix) - 1);
+ if (key.size() < 2 + expected_prefix.size())
+ return false;
+ const leveldb::Slice key_substring(key.data() + 1, expected_prefix.size());
+ return key[0] == kDBKeyDelimeter &&
+ key_substring.compare(expected_prefix) == 0 &&
+ key[expected_prefix.size() + 1] == kDBKeyDelimeter;
+}
+
// Converts leveldb::Status to DBInitStatus.
DBInitStatus LevelDBStatusToDBInitStatus(const leveldb::Status status) {
if (status.ok())
@@ -411,30 +438,49 @@ bool ResourceMetadataStorage::PutEntry(const ResourceEntry& entry) {
const std::string& id = entry.local_id();
DCHECK(!id.empty());
+ // Try to get existing entry.
std::string serialized_entry;
- if (!entry.SerializeToString(&serialized_entry)) {
- DLOG(ERROR) << "Failed to serialize the entry: " << id;
+ leveldb::Status status = resource_map_->Get(leveldb::ReadOptions(),
+ leveldb::Slice(id),
+ &serialized_entry);
+ if (!status.ok() && !status.IsNotFound()) // Unexpected errors.
+ return false;
+
+ ResourceEntry old_entry;
+ if (status.ok() && !old_entry.ParseFromString(serialized_entry))
return false;
- }
+ // Construct write batch.
leveldb::WriteBatch batch;
// Remove from the old parent.
- ResourceEntry old_entry;
- if (GetEntry(id, &old_entry) && !old_entry.parent_local_id().empty()) {
+ if (!old_entry.parent_local_id().empty()) {
batch.Delete(GetChildEntryKey(old_entry.parent_local_id(),
old_entry.base_name()));
}
-
// Add to the new parent.
if (!entry.parent_local_id().empty())
batch.Put(GetChildEntryKey(entry.parent_local_id(), entry.base_name()), id);
+ // Refresh resource-ID-to-local-ID mapping entry.
+ if (old_entry.resource_id() != entry.resource_id()) {
+ // Resource ID should not change.
+ DCHECK(old_entry.resource_id().empty() || entry.resource_id().empty());
+
+ if (!old_entry.resource_id().empty())
+ batch.Delete(GetIdEntryKey(old_entry.resource_id()));
+ if (!entry.resource_id().empty())
+ batch.Put(GetIdEntryKey(entry.resource_id()), id);
+ }
+
// Put the entry itself.
+ if (!entry.SerializeToString(&serialized_entry)) {
+ DLOG(ERROR) << "Failed to serialize the entry: " << id;
+ return false;
+ }
batch.Put(id, serialized_entry);
- const leveldb::Status status = resource_map_->Write(leveldb::WriteOptions(),
- &batch);
+ status = resource_map_->Write(leveldb::WriteOptions(), &batch);
return status.ok();
}
@@ -464,6 +510,10 @@ bool ResourceMetadataStorage::RemoveEntry(const std::string& id) {
if (!entry.parent_local_id().empty())
batch.Delete(GetChildEntryKey(entry.parent_local_id(), entry.base_name()));
+ // Remove resource ID-local ID mapping entry.
+ if (!entry.resource_id().empty())
+ batch.Delete(GetIdEntryKey(entry.resource_id()));
+
// Remove the entry itself.
batch.Delete(id);
@@ -561,6 +611,19 @@ ResourceMetadataStorage::GetCacheEntryIterator() {
return make_scoped_ptr(new CacheEntryIterator(it.Pass()));
}
+bool ResourceMetadataStorage::GetIdByResourceId(
+ const std::string& resource_id,
+ std::string* out_id) {
+ base::ThreadRestrictions::AssertIOAllowed();
+ DCHECK(!resource_id.empty());
+
+ const leveldb::Status status = resource_map_->Get(
+ leveldb::ReadOptions(),
+ leveldb::Slice(GetIdEntryKey(resource_id)),
+ out_id);
+ return status.ok();
+}
+
ResourceMetadataStorage::~ResourceMetadataStorage() {
base::ThreadRestrictions::AssertIOAllowed();
}
@@ -625,6 +688,9 @@ bool ResourceMetadataStorage::CheckValidity() {
//
// <key> : <value>
// "\0HEADER" : ResourceMetadataHeader
+ // "\0ID\0|resource ID 1|" : Local ID associated to resource ID 1.
+ // "\0ID\0|resource ID 2|" : Local ID associated to resource ID 2.
+ // ...
// "|ID of A|" : ResourceEntry for entry A.
// "|ID of A|\0CACHE" : FileCacheEntry for entry A.
// "|ID of A|\0|child name 1|\0" : ID of the 1st child entry of entry A.
@@ -649,7 +715,7 @@ bool ResourceMetadataStorage::CheckValidity() {
size_t num_entries_with_parent = 0;
size_t num_child_entries = 0;
ResourceEntry entry;
- std::string serialized_parent_entry;
+ std::string serialized_entry;
std::string child_id;
for (it->Next(); it->Valid(); it->Next()) {
// Count child entries.
@@ -662,6 +728,22 @@ bool ResourceMetadataStorage::CheckValidity() {
if (IsCacheEntryKey(it->key()))
continue;
+ // Check if resource-ID-to-local-ID mapping is stored correctly.
+ if (IsIdEntryKey(it->key())) {
+ leveldb::Status status = resource_map_->Get(
+ options,
+ it->value(),
+ &serialized_entry);
+ if (!status.ok() ||
+ !entry.ParseFromString(serialized_entry) ||
+ entry.resource_id().empty() ||
+ leveldb::Slice(GetIdEntryKey(entry.resource_id())) != it->key()) {
+ DLOG(ERROR) << "Broken ID entry. status = " << status.ToString();
+ return false;
+ }
+ continue;
+ }
+
// Check if stored data is broken.
if (!entry.ParseFromArray(it->value().data(), it->value().size())) {
DLOG(ERROR) << "Broken entry detected";
@@ -673,7 +755,7 @@ bool ResourceMetadataStorage::CheckValidity() {
leveldb::Status status = resource_map_->Get(
options,
leveldb::Slice(entry.parent_local_id()),
- &serialized_parent_entry);
+ &serialized_entry);
if (!status.ok()) {
DLOG(ERROR) << "Can't get parent entry. status = " << status.ToString();
return false;
diff --git a/chrome/browser/chromeos/drive/resource_metadata_storage.h b/chrome/browser/chromeos/drive/resource_metadata_storage.h
index 05d7ef28eb..04a2224f29 100644
--- a/chrome/browser/chromeos/drive/resource_metadata_storage.h
+++ b/chrome/browser/chromeos/drive/resource_metadata_storage.h
@@ -36,7 +36,7 @@ class ResourceMetadataStorage {
public:
// This should be incremented when incompatibility change is made to DB
// format.
- static const int kDBVersion = 10;
+ static const int kDBVersion = 11;
// Object to iterate over entries stored in this storage.
class Iterator {
@@ -157,6 +157,9 @@ class ResourceMetadataStorage {
// Returns an object to iterate over cache entries stored in this storage.
scoped_ptr<CacheEntryIterator> GetCacheEntryIterator();
+ // Returns the local ID associated with the given resource ID.
+ bool GetIdByResourceId(const std::string& resource_id, std::string* out_id);
+
private:
friend class ResourceMetadataStorageTest;
diff --git a/chrome/browser/chromeos/drive/resource_metadata_storage_unittest.cc b/chrome/browser/chromeos/drive/resource_metadata_storage_unittest.cc
index 9dbd6dda13..f4cbfb6665 100644
--- a/chrome/browser/chromeos/drive/resource_metadata_storage_unittest.cc
+++ b/chrome/browser/chromeos/drive/resource_metadata_storage_unittest.cc
@@ -246,6 +246,29 @@ TEST_F(ResourceMetadataStorageTest, CacheEntryIterator) {
EXPECT_EQ(entries.size(), num_entries);
}
+TEST_F(ResourceMetadataStorageTest, GetIdByResourceId) {
+ const std::string local_id = "local_id";
+ const std::string resource_id = "resource_id";
+
+ // Resource ID to local ID mapping is not stored yet.
+ std::string id;
+ EXPECT_FALSE(storage_->GetIdByResourceId(resource_id, &id));
+
+ // Put an entry with the resource ID.
+ ResourceEntry entry;
+ entry.set_local_id(local_id);
+ entry.set_resource_id(resource_id);
+ EXPECT_TRUE(storage_->PutEntry(entry));
+
+ // Can get local ID by resource ID.
+ EXPECT_TRUE(storage_->GetIdByResourceId(resource_id, &id));
+ EXPECT_EQ(local_id, id);
+
+ // Resource ID to local ID mapping is removed.
+ EXPECT_TRUE(storage_->RemoveEntry(local_id));
+ EXPECT_FALSE(storage_->GetIdByResourceId(resource_id, &id));
+}
+
TEST_F(ResourceMetadataStorageTest, GetChildren) {
const std::string parents_id[] = { "mercury", "venus", "mars", "jupiter",
"saturn" };
diff --git a/chrome/browser/chromeos/drive/resource_metadata_unittest.cc b/chrome/browser/chromeos/drive/resource_metadata_unittest.cc
index b5a279eeec..c8b660f09b 100644
--- a/chrome/browser/chromeos/drive/resource_metadata_unittest.cc
+++ b/chrome/browser/chromeos/drive/resource_metadata_unittest.cc
@@ -195,56 +195,6 @@ class ResourceMetadataTestOnUIThread : public testing::Test {
resource_metadata_;
};
-TEST_F(ResourceMetadataTestOnUIThread, GetResourceEntryById_RootDirectory) {
- // Look up the root directory by its resource ID.
- FileError error = FILE_ERROR_FAILED;
- scoped_ptr<ResourceEntry> entry;
- resource_metadata_->GetResourceEntryByIdOnUIThread(
- util::kDriveGrandRootSpecialResourceId,
- google_apis::test_util::CreateCopyResultCallback(&error, &entry));
- test_util::RunBlockingPoolTask();
- EXPECT_EQ(FILE_ERROR_OK, error);
- ASSERT_TRUE(entry.get());
- EXPECT_EQ("drive", entry->base_name());
-}
-
-TEST_F(ResourceMetadataTestOnUIThread, GetResourceEntryById) {
- // Get file4 by path.
- FileError error = FILE_ERROR_FAILED;
- std::string local_id;
- base::PostTaskAndReplyWithResult(
- blocking_task_runner_,
- FROM_HERE,
- base::Bind(&ResourceMetadata::GetIdByPath,
- base::Unretained(resource_metadata_.get()),
- base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"),
- &local_id),
- google_apis::test_util::CreateCopyResultCallback(&error));
- test_util::RunBlockingPoolTask();
- EXPECT_EQ(FILE_ERROR_OK, error);
-
- // Confirm that an existing file is found.
- error = FILE_ERROR_FAILED;
- scoped_ptr<ResourceEntry> entry;
- resource_metadata_->GetResourceEntryByIdOnUIThread(
- local_id,
- google_apis::test_util::CreateCopyResultCallback(&error, &entry));
- test_util::RunBlockingPoolTask();
- EXPECT_EQ(FILE_ERROR_OK, error);
- ASSERT_TRUE(entry.get());
- EXPECT_EQ("file4", entry->base_name());
-
- // Confirm that a non existing file is not found.
- error = FILE_ERROR_FAILED;
- entry.reset();
- resource_metadata_->GetResourceEntryByIdOnUIThread(
- "file:non_existing",
- google_apis::test_util::CreateCopyResultCallback(&error, &entry));
- test_util::RunBlockingPoolTask();
- EXPECT_EQ(FILE_ERROR_NOT_FOUND, error);
- EXPECT_FALSE(entry.get());
-}
-
TEST_F(ResourceMetadataTestOnUIThread, GetResourceEntryByPath) {
// Confirm that an existing file is found.
FileError error = FILE_ERROR_FAILED;
@@ -612,6 +562,31 @@ TEST_F(ResourceMetadataTest, RemoveEntry) {
util::kDriveGrandRootSpecialResourceId));
}
+TEST_F(ResourceMetadataTest, GetResourceEntryById_RootDirectory) {
+ // Look up the root directory by its ID.
+ ResourceEntry entry;
+ EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
+ util::kDriveGrandRootSpecialResourceId, &entry));
+ EXPECT_EQ("drive", entry.base_name());
+}
+
+TEST_F(ResourceMetadataTest, GetResourceEntryById) {
+ // Get file4 by path.
+ std::string local_id;
+ EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
+ base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"), &local_id));
+
+ // Confirm that an existing file is found.
+ ResourceEntry entry;
+ EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
+ local_id, &entry));
+ EXPECT_EQ("file4", entry.base_name());
+
+ // Confirm that a non existing file is not found.
+ EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->GetResourceEntryById(
+ "file:non_existing", &entry));
+}
+
TEST_F(ResourceMetadataTest, Iterate) {
scoped_ptr<ResourceMetadata::Iterator> it = resource_metadata_->GetIterator();
ASSERT_TRUE(it);
diff --git a/chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.cc b/chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.cc
new file mode 100644
index 0000000000..0505894a6e
--- /dev/null
+++ b/chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.cc
@@ -0,0 +1,106 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.h"
+
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/prefs/pref_value_map.h"
+#include "base/values.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/extensions/policy_handlers.h"
+#include "chrome/browser/policy/policy_map.h"
+#include "chrome/common/pref_names.h"
+#include "net/url_request/url_request_context_getter.h"
+
+namespace chromeos {
+
+DeviceLocalAccountExternalPolicyLoader::
+ DeviceLocalAccountExternalPolicyLoader(policy::CloudPolicyStore* store,
+ const base::FilePath& cache_dir)
+ : store_(store),
+ cache_dir_(cache_dir) {
+}
+
+bool DeviceLocalAccountExternalPolicyLoader::IsCacheRunning() const {
+ return external_cache_;
+}
+
+void DeviceLocalAccountExternalPolicyLoader::StartCache(
+ const scoped_refptr<base::SequencedTaskRunner>& cache_task_runner) {
+ DCHECK(!external_cache_);
+ store_->AddObserver(this);
+ external_cache_.reset(new ExternalCache(
+ cache_dir_,
+ g_browser_process->system_request_context(),
+ cache_task_runner,
+ this,
+ true /* always_check_updates */,
+ false /* wait_for_cache_initialization */));
+
+ if (store_->is_initialized())
+ UpdateExtensionListFromStore();
+}
+
+void DeviceLocalAccountExternalPolicyLoader::StopCache(
+ const base::Closure& callback) {
+ if (external_cache_) {
+ external_cache_->Shutdown(callback);
+ external_cache_.reset();
+ store_->RemoveObserver(this);
+ }
+
+ base::DictionaryValue empty_prefs;
+ OnExtensionListsUpdated(&empty_prefs);
+}
+
+void DeviceLocalAccountExternalPolicyLoader::StartLoading() {
+ if (prefs_)
+ LoadFinished();
+}
+
+void DeviceLocalAccountExternalPolicyLoader::OnStoreLoaded(
+ policy::CloudPolicyStore* store) {
+ DCHECK(external_cache_);
+ DCHECK_EQ(store_, store);
+ UpdateExtensionListFromStore();
+}
+
+void DeviceLocalAccountExternalPolicyLoader::OnStoreError(
+ policy::CloudPolicyStore* store) {
+ DCHECK(external_cache_);
+ DCHECK_EQ(store_, store);
+}
+
+void DeviceLocalAccountExternalPolicyLoader::OnExtensionListsUpdated(
+ const base::DictionaryValue* prefs) {
+ DCHECK(external_cache_ || prefs->empty());
+ prefs_.reset(prefs->DeepCopy());
+ LoadFinished();
+}
+
+DeviceLocalAccountExternalPolicyLoader::
+ ~DeviceLocalAccountExternalPolicyLoader() {
+ DCHECK(!external_cache_);
+}
+
+void DeviceLocalAccountExternalPolicyLoader::UpdateExtensionListFromStore() {
+ scoped_ptr<base::DictionaryValue> prefs(new base::DictionaryValue);
+ const policy::PolicyMap& policy_map = store_->policy_map();
+ extensions::ExtensionInstallForcelistPolicyHandler policy_handler;
+ if (policy_handler.CheckPolicySettings(policy_map, NULL)) {
+ PrefValueMap pref_value_map;
+ policy_handler.ApplyPolicySettings(policy_map, &pref_value_map);
+ const base::Value* value = NULL;
+ const base::DictionaryValue* dict = NULL;
+ if (pref_value_map.GetValue(prefs::kExtensionInstallForceList, &value) &&
+ value->GetAsDictionary(&dict)) {
+ prefs.reset(dict->DeepCopy());
+ }
+ }
+
+ external_cache_->UpdateExtensionsList(prefs.Pass());
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.h b/chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.h
new file mode 100644
index 0000000000..c9abf5d0d8
--- /dev/null
+++ b/chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.h
@@ -0,0 +1,78 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_EXTENSIONS_DEVICE_LOCAL_ACCOUNT_EXTERNAL_POLICY_LOADER_H_
+#define CHROME_BROWSER_CHROMEOS_EXTENSIONS_DEVICE_LOCAL_ACCOUNT_EXTERNAL_POLICY_LOADER_H_
+
+#include "base/basictypes.h"
+#include "base/callback_forward.h"
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/sequenced_task_runner.h"
+#include "chrome/browser/chromeos/extensions/external_cache.h"
+#include "chrome/browser/extensions/external_loader.h"
+#include "chrome/browser/policy/cloud/cloud_policy_store.h"
+
+namespace chromeos {
+
+// A specialization of the ExternalLoader that serves external extensions from
+// the enterprise policy force-install list. This class is used for device-local
+// accounts in place of the ExternalPolicyLoader. The difference is that while
+// the ExternalPolicyLoader requires extensions to be downloaded on-the-fly,
+// this class caches them, allowing for offline installation.
+class DeviceLocalAccountExternalPolicyLoader
+ : public extensions::ExternalLoader,
+ public policy::CloudPolicyStore::Observer,
+ public ExternalCache::Delegate {
+ public:
+ // The list of force-installed extensions will be read from |store| and the
+ // extensions will be cached in the |cache_dir_|.
+ DeviceLocalAccountExternalPolicyLoader(policy::CloudPolicyStore* store,
+ const base::FilePath& cache_dir);
+
+ // While running, the cache requires exclusive write access to the
+ // |cache_dir_|.
+ bool IsCacheRunning() const;
+
+ // Start the cache. This method must only be invoked when there are no pending
+ // write operations to |cache_dir_| on any thread and none will be initiated
+ // while the cache is running.
+ void StartCache(
+ const scoped_refptr<base::SequencedTaskRunner>& cache_task_runner);
+
+ // Stop the cache. The |callback| will be invoked when the cache has shut down
+ // completely and write access to the |cache_dir_| is permitted again.
+ void StopCache(const base::Closure& callback);
+
+ // extensions::ExternalLoader:
+ virtual void StartLoading() OVERRIDE;
+
+ // policy::CloudPolicyStore::Observer:
+ virtual void OnStoreLoaded(policy::CloudPolicyStore* store) OVERRIDE;
+ virtual void OnStoreError(policy::CloudPolicyStore* store) OVERRIDE;
+
+ // ExternalCache::Delegate:
+ virtual void OnExtensionListsUpdated(
+ const base::DictionaryValue* prefs) OVERRIDE;
+
+ private:
+ // If the cache was started, it must be stopped before |this| is destroyed.
+ virtual ~DeviceLocalAccountExternalPolicyLoader();
+
+ // Pass the current list of force-installed extensions from the |store_| to
+ // the |external_cache_|.
+ void UpdateExtensionListFromStore();
+
+ policy::CloudPolicyStore* store_;
+ const base::FilePath cache_dir_;
+ scoped_ptr<ExternalCache> external_cache_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeviceLocalAccountExternalPolicyLoader);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_EXTENSIONS_DEVICE_LOCAL_ACCOUNT_EXTERNAL_POLICY_LOADER_H_
diff --git a/chrome/browser/chromeos/extensions/device_local_account_external_policy_loader_unittest.cc b/chrome/browser/chromeos/extensions/device_local_account_external_policy_loader_unittest.cc
new file mode 100644
index 0000000000..27a70cd711
--- /dev/null
+++ b/chrome/browser/chromeos/extensions/device_local_account_external_policy_loader_unittest.cc
@@ -0,0 +1,309 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.h"
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "base/path_service.h"
+#include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
+#include "base/values.h"
+#include "base/version.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/extensions/external_provider_impl.h"
+#include "chrome/browser/extensions/external_provider_interface.h"
+#include "chrome/browser/extensions/updater/extension_downloader.h"
+#include "chrome/browser/policy/cloud/mock_cloud_policy_store.h"
+#include "chrome/browser/policy/policy_map.h"
+#include "chrome/browser/policy/policy_types.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_constants.h"
+#include "chrome/test/base/testing_browser_process.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_source.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "content/public/test/test_utils.h"
+#include "extensions/common/manifest.h"
+#include "net/url_request/test_url_fetcher_factory.h"
+#include "net/url_request/url_fetcher_delegate.h"
+#include "net/url_request/url_request_context_getter.h"
+#include "net/url_request/url_request_test_util.h"
+#include "policy/policy_constants.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+using ::testing::InvokeWithoutArgs;
+using ::testing::Mock;
+using ::testing::_;
+
+namespace chromeos {
+
+namespace {
+
+const char kCacheDir[] = "cache";
+const char kExtensionId[] = "ldnnhddmnhbkjipkidpdiheffobcpfmf";
+const char kExtensionUpdateManifest[] =
+ "extensions/good_v1_update_manifest.xml";
+const char kExtensionCRXSourceDir[] = "extensions";
+const char kExtensionCRXFile[] = "good.crx";
+const char kExtensionCRXVersion[] = "1.0.0.0";
+
+class MockExternalPolicyProviderVisitor
+ : public extensions::ExternalProviderInterface::VisitorInterface {
+ public:
+ MockExternalPolicyProviderVisitor();
+ virtual ~MockExternalPolicyProviderVisitor();
+
+ MOCK_METHOD6(OnExternalExtensionFileFound,
+ bool(const std::string&,
+ const base::Version*,
+ const base::FilePath&,
+ extensions::Manifest::Location,
+ int,
+ bool));
+ MOCK_METHOD5(OnExternalExtensionUpdateUrlFound,
+ bool(const std::string&,
+ const GURL&,
+ extensions::Manifest::Location,
+ int,
+ bool));
+ MOCK_METHOD1(OnExternalProviderReady,
+ void(const extensions::ExternalProviderInterface* provider));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockExternalPolicyProviderVisitor);
+};
+
+MockExternalPolicyProviderVisitor::MockExternalPolicyProviderVisitor() {
+}
+
+MockExternalPolicyProviderVisitor::~MockExternalPolicyProviderVisitor() {
+}
+
+} // namespace
+
+class DeviceLocalAccountExternalPolicyLoaderTest : public testing::Test {
+ protected:
+ DeviceLocalAccountExternalPolicyLoaderTest();
+ virtual ~DeviceLocalAccountExternalPolicyLoaderTest();
+
+ virtual void SetUp() OVERRIDE;
+ virtual void TearDown() OVERRIDE;
+
+ void VerifyAndResetVisitorCallExpectations();
+ void SetForceInstallListPolicy();
+
+ content::TestBrowserThreadBundle thread_bundle_;
+ base::ScopedTempDir temp_dir_;
+ base::FilePath cache_dir_;
+ policy::MockCloudPolicyStore store_;
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
+ base::FilePath test_dir_;
+
+ scoped_refptr<DeviceLocalAccountExternalPolicyLoader> loader_;
+ MockExternalPolicyProviderVisitor visitor_;
+ scoped_ptr<extensions::ExternalProviderImpl> provider_;
+};
+
+DeviceLocalAccountExternalPolicyLoaderTest::
+ DeviceLocalAccountExternalPolicyLoaderTest()
+ : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {
+}
+
+DeviceLocalAccountExternalPolicyLoaderTest::
+ ~DeviceLocalAccountExternalPolicyLoaderTest() {
+}
+
+void DeviceLocalAccountExternalPolicyLoaderTest::SetUp() {
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ cache_dir_ = temp_dir_.path().Append(kCacheDir);
+ ASSERT_TRUE(file_util::CreateDirectoryAndGetError(cache_dir_, NULL));
+ request_context_getter_ =
+ new net::TestURLRequestContextGetter(base::MessageLoopProxy::current());
+ TestingBrowserProcess::GetGlobal()->SetSystemRequestContext(
+ request_context_getter_.get());
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir_));
+
+ loader_ = new DeviceLocalAccountExternalPolicyLoader(&store_, cache_dir_);
+ provider_.reset(new extensions::ExternalProviderImpl(
+ &visitor_,
+ loader_,
+ NULL,
+ extensions::Manifest::EXTERNAL_POLICY,
+ extensions::Manifest::EXTERNAL_POLICY_DOWNLOAD,
+ extensions::Extension::NO_FLAGS));
+
+ content::RenderProcessHost::SetRunRendererInProcess(true);
+
+ VerifyAndResetVisitorCallExpectations();
+}
+
+void DeviceLocalAccountExternalPolicyLoaderTest::TearDown() {
+ content::RenderProcessHost::SetRunRendererInProcess(false);
+ TestingBrowserProcess::GetGlobal()->SetSystemRequestContext(NULL);
+}
+
+void DeviceLocalAccountExternalPolicyLoaderTest::
+ VerifyAndResetVisitorCallExpectations() {
+ Mock::VerifyAndClearExpectations(&visitor_);
+ EXPECT_CALL(visitor_, OnExternalExtensionFileFound(_, _, _, _, _, _))
+ .Times(0);
+ EXPECT_CALL(visitor_, OnExternalExtensionUpdateUrlFound(_, _, _, _, _))
+ .Times(0);
+ EXPECT_CALL(visitor_, OnExternalProviderReady(_))
+ .Times(0);
+}
+
+void DeviceLocalAccountExternalPolicyLoaderTest::SetForceInstallListPolicy() {
+ scoped_ptr<base::ListValue> forcelist(new base::ListValue);
+ forcelist->AppendString("invalid");
+ forcelist->AppendString(base::StringPrintf(
+ "%s;%s",
+ kExtensionId,
+ extension_urls::GetWebstoreUpdateUrl().spec().c_str()));
+ store_.policy_map_.Set(policy::key::kExtensionInstallForcelist,
+ policy::POLICY_LEVEL_MANDATORY,
+ policy::POLICY_SCOPE_USER,
+ forcelist.release(),
+ NULL);
+ store_.NotifyStoreLoaded();
+}
+
+// Verifies that when the cache is not explicitly started, the loader does not
+// serve any extensions, even if the force-install list policy is set or a load
+// is manually requested.
+TEST_F(DeviceLocalAccountExternalPolicyLoaderTest, CacheNotStarted) {
+ // Set the force-install list policy.
+ SetForceInstallListPolicy();
+
+ // Manually request a load.
+ loader_->StartLoading();
+
+ EXPECT_FALSE(loader_->IsCacheRunning());
+ EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting());
+}
+
+// Verifies that the cache can be started and stopped correctly.
+TEST_F(DeviceLocalAccountExternalPolicyLoaderTest, ForceInstallListEmpty) {
+ // Set an empty force-install list policy.
+ store_.NotifyStoreLoaded();
+
+ // Start the cache. Verify that the loader announces an empty extension list.
+ EXPECT_CALL(visitor_, OnExternalProviderReady(provider_.get()))
+ .Times(1);
+ loader_->StartCache(base::MessageLoopProxy::current());
+ VerifyAndResetVisitorCallExpectations();
+
+ // Stop the cache. Verify that the loader announces an empty extension list.
+ EXPECT_CALL(visitor_, OnExternalProviderReady(provider_.get()))
+ .Times(1);
+ base::RunLoop run_loop;
+ loader_->StopCache(run_loop.QuitClosure());
+ VerifyAndResetVisitorCallExpectations();
+
+ // Spin the loop until the cache shutdown callback is invoked. Verify that at
+ // that point, no further file I/O tasks are pending.
+ run_loop.Run();
+ EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting());
+}
+
+// Verifies that when a force-install list policy referencing an extension is
+// set and the cache is started, the loader downloads, caches and serves the
+// extension.
+TEST_F(DeviceLocalAccountExternalPolicyLoaderTest, ForceInstallListSet) {
+ // Set a force-install list policy that contains an invalid entry (which
+ // should be ignored) and a valid reference to an extension.
+ SetForceInstallListPolicy();
+
+ // Start the cache.
+ loader_->StartCache(base::MessageLoopProxy::current());
+
+ // Spin the loop, allowing the loader to process the force-install list.
+ // Verify that the loader announces an empty extension list.
+ net::TestURLFetcherFactory factory;
+ EXPECT_CALL(visitor_, OnExternalProviderReady(provider_.get()))
+ .Times(1);
+ base::MessageLoop::current()->RunUntilIdle();
+
+ // Verify that a downloader has started and is attempting to download an
+ // update manifest.
+ net::TestURLFetcher* fetcher = factory.GetFetcherByID(
+ extensions::ExtensionDownloader::kManifestFetcherId);
+ ASSERT_TRUE(fetcher);
+ ASSERT_TRUE(fetcher->delegate());
+
+ // Return a manifest to the downloader.
+ std::string manifest;
+ EXPECT_TRUE(base::ReadFileToString(test_dir_.Append(kExtensionUpdateManifest),
+ &manifest));
+ fetcher->set_response_code(200);
+ fetcher->SetResponseString(manifest);
+ fetcher->delegate()->OnURLFetchComplete(fetcher);
+
+ // Wait for the manifest to be parsed.
+ content::WindowedNotificationObserver(
+ chrome::NOTIFICATION_EXTENSION_UPDATE_FOUND,
+ content::NotificationService::AllSources()).Wait();
+
+ // Verify that the downloader is attempting to download a CRX file.
+ fetcher = factory.GetFetcherByID(
+ extensions::ExtensionDownloader::kExtensionFetcherId);
+ ASSERT_TRUE(fetcher);
+ ASSERT_TRUE(fetcher->delegate());
+
+ // Create a temporary CRX file and return its path to the downloader.
+ EXPECT_TRUE(base::CopyFile(
+ test_dir_.Append(kExtensionCRXSourceDir).Append(kExtensionCRXFile),
+ temp_dir_.path().Append(kExtensionCRXFile)));
+ fetcher->set_response_code(200);
+ fetcher->SetResponseFilePath(temp_dir_.path().Append(kExtensionCRXFile));
+ fetcher->delegate()->OnURLFetchComplete(fetcher);
+
+ // Spin the loop. Verify that the loader announces the presence of a new CRX
+ // file, served from the cache directory.
+ const base::FilePath cached_crx_path = cache_dir_.Append(base::StringPrintf(
+ "%s-%s.crx", kExtensionId, kExtensionCRXVersion));
+ base::RunLoop cache_run_loop;
+ EXPECT_CALL(visitor_, OnExternalExtensionFileFound(
+ kExtensionId,
+ _,
+ cached_crx_path,
+ extensions::Manifest::EXTERNAL_POLICY,
+ _,
+ _));
+ EXPECT_CALL(visitor_, OnExternalProviderReady(provider_.get()))
+ .Times(1)
+ .WillOnce(InvokeWithoutArgs(&cache_run_loop, &base::RunLoop::Quit));
+ cache_run_loop.Run();
+ VerifyAndResetVisitorCallExpectations();
+
+ // Verify that the CRX file actually exists in the cache directory and its
+ // contents matches the file returned to the downloader.
+ EXPECT_TRUE(base::ContentsEqual(
+ test_dir_.Append(kExtensionCRXSourceDir).Append(kExtensionCRXFile),
+ cached_crx_path));
+
+ // Stop the cache. Verify that the loader announces an empty extension list.
+ EXPECT_CALL(visitor_, OnExternalProviderReady(provider_.get()))
+ .Times(1);
+ base::RunLoop shutdown_run_loop;
+ loader_->StopCache(shutdown_run_loop.QuitClosure());
+ VerifyAndResetVisitorCallExpectations();
+
+ // Spin the loop until the cache shutdown callback is invoked. Verify that at
+ // that point, no further file I/O tasks are pending.
+ shutdown_run_loop.Run();
+ EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting());
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/extensions/external_pref_cache_loader.h b/chrome/browser/chromeos/extensions/external_pref_cache_loader.h
index 16a08ff050..e448182a07 100644
--- a/chrome/browser/chromeos/extensions/external_pref_cache_loader.h
+++ b/chrome/browser/chromeos/extensions/external_pref_cache_loader.h
@@ -9,9 +9,8 @@
namespace chromeos {
-// A specialization of the ExternalPrefCacheLoader that caches crx files for
-// external extensions with update URL in common place for all users on the
-// machine.
+// A specialization of the ExternalPrefLoader that caches crx files for external
+// extensions with update URL in a common place for all users on the machine.
class ExternalPrefCacheLoader : public extensions::ExternalPrefLoader {
public:
// All instances of ExternalPrefCacheLoader use the same cache so
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
index 443ccf0ac1..21a775939a 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
@@ -116,7 +116,6 @@ bool FileBrowserPrivateGetStringsFunction::RunImpl() {
SET_STRING("ACTION_OPEN_GSLIDES", IDS_FILE_BROWSER_ACTION_OPEN_GSLIDES);
SET_STRING("ACTION_WATCH", IDS_FILE_BROWSER_ACTION_WATCH);
SET_STRING("ACTION_LISTEN", IDS_FILE_BROWSER_ACTION_LISTEN);
- SET_STRING("INSTALL_CRX", IDS_FILE_BROWSER_INSTALL_CRX);
SET_STRING("SEND_TO_DRIVE", IDS_FILE_BROWSER_SEND_TO_DRIVE);
SET_STRING("GALLERY_NO_IMAGES", IDS_FILE_BROWSER_GALLERY_NO_IMAGES);
@@ -239,6 +238,17 @@ bool FileBrowserPrivateGetStringsFunction::RunImpl() {
SET_STRING("PHOTO_IMPORT_MY_PHOTOS_DIRECTORY_NAME",
IDS_FILE_BROWSER_PHOTO_IMPORT_MY_PHOTOS_DIRECTORY_NAME);
+ SET_STRING("CONFLICT_DIALOG_TITLE",
+ IDS_FILE_BROWSER_CONFLICT_DIALOG_TITLE);
+ SET_STRING("CONFLICT_DIALOG_MESSAGE",
+ IDS_FILE_BROWSER_CONFLICT_DIALOG_MESSAGE);
+ SET_STRING("CONFLICT_DIALOG_KEEP_BOTH",
+ IDS_FILE_BROWSER_CONFLICT_DIALOG_KEEP_BOTH);
+ SET_STRING("CONFLICT_DIALOG_REPLACE",
+ IDS_FILE_BROWSER_CONFLICT_DIALOG_REPLACE);
+ SET_STRING("CONFLICT_DIALOG_APPLY_TO_ALL",
+ IDS_FILE_BROWSER_CONFLICT_DIALOG_APPLY_TO_ALL);
+
SET_STRING("CONFIRM_OVERWRITE_FILE", IDS_FILE_BROWSER_CONFIRM_OVERWRITE_FILE);
SET_STRING("FILE_ALREADY_EXISTS", IDS_FILE_BROWSER_FILE_ALREADY_EXISTS);
SET_STRING("DIRECTORY_ALREADY_EXISTS",
@@ -452,6 +462,8 @@ bool FileBrowserPrivateGetStringsFunction::RunImpl() {
IDS_FILE_BROWSER_GDRAW_DOCUMENT_FILE_TYPE);
SET_STRING("GTABLE_DOCUMENT_FILE_TYPE",
IDS_FILE_BROWSER_GTABLE_DOCUMENT_FILE_TYPE);
+ SET_STRING("GFORM_DOCUMENT_FILE_TYPE",
+ IDS_FILE_BROWSER_GFORM_DOCUMENT_FILE_TYPE);
SET_STRING("GLINK_DOCUMENT_FILE_TYPE",
IDS_FILE_BROWSER_GLINK_DOCUMENT_FILE_TYPE);
diff --git a/chrome/browser/chromeos/extensions/wallpaper_private_api.cc b/chrome/browser/chromeos/extensions/wallpaper_private_api.cc
index 1fcd5d4821..b89dedfc7c 100644
--- a/chrome/browser/chromeos/extensions/wallpaper_private_api.cc
+++ b/chrome/browser/chromeos/extensions/wallpaper_private_api.cc
@@ -45,7 +45,6 @@ namespace get_thumbnail = wallpaper_private::GetThumbnail;
namespace save_thumbnail = wallpaper_private::SaveThumbnail;
namespace get_offline_wallpaper_list =
wallpaper_private::GetOfflineWallpaperList;
-typedef extensions::api::wallpaper_private::WallpaperSource WallpaperSource;
namespace {
@@ -227,31 +226,16 @@ bool WallpaperPrivateSetWallpaperIfExistsFunction::RunImpl() {
ash::WallpaperResolution resolution = ash::Shell::GetInstance()->
desktop_background_controller()->GetAppropriateResolution();
- if (params->source == wallpaper_private::WALLPAPER_SOURCE_ONLINE) {
- type_ = chromeos::User::ONLINE;
- std::string file_name = GURL(params->url).ExtractFileName();
- CHECK(PathService::Get(chrome::DIR_CHROMEOS_WALLPAPERS,
- &wallpaper_path));
- fallback_path = wallpaper_path.Append(file_name);
- if (params->layout != wallpaper_private::WALLPAPER_LAYOUT_STRETCH &&
- resolution == ash::WALLPAPER_RESOLUTION_SMALL) {
- file_name = base::FilePath(file_name).InsertBeforeExtension(
- chromeos::kSmallWallpaperSuffix).value();
- }
- wallpaper_path = wallpaper_path.Append(file_name);
- } else {
- type_ = chromeos::User::CUSTOMIZED;
- std::string file_name = params->url;
- std::string username_hash =
- chromeos::UserManager::Get()->GetLoggedInUser()->username_hash();
- const char* sub_dir = (resolution == ash::WALLPAPER_RESOLUTION_SMALL) ?
- chromeos::kSmallWallpaperSubDir : chromeos::kLargeWallpaperSubDir;
- wallpaper_path = chromeos::WallpaperManager::Get()->GetCustomWallpaperPath(
- sub_dir, username_hash, file_name);
-
- fallback_path = chromeos::WallpaperManager::Get()->GetCustomWallpaperPath(
- chromeos::kOriginalWallpaperSubDir, username_hash, file_name);
+ std::string file_name = GURL(params->url).ExtractFileName();
+ CHECK(PathService::Get(chrome::DIR_CHROMEOS_WALLPAPERS,
+ &wallpaper_path));
+ fallback_path = wallpaper_path.Append(file_name);
+ if (params->layout != wallpaper_private::WALLPAPER_LAYOUT_STRETCH &&
+ resolution == ash::WALLPAPER_RESOLUTION_SMALL) {
+ file_name = base::FilePath(file_name).InsertBeforeExtension(
+ chromeos::kSmallWallpaperSuffix).value();
}
+ wallpaper_path = wallpaper_path.Append(file_name);
sequence_token_ = BrowserThread::GetBlockingPool()->
GetNamedSequenceToken(chromeos::kWallpaperSequenceTokenName);
@@ -311,7 +295,7 @@ void WallpaperPrivateSetWallpaperIfExistsFunction::OnWallpaperDecoded(
chromeos::WallpaperInfo info = {
params->url,
layout,
- type_,
+ chromeos::User::ONLINE,
base::Time::Now().LocalMidnight()
};
std::string email = chromeos::UserManager::Get()->GetLoggedInUser()->email();
@@ -613,7 +597,7 @@ bool WallpaperPrivateGetThumbnailFunction::RunImpl() {
base::FilePath thumbnail_path;
std::string email = chromeos::UserManager::Get()->GetLoggedInUser()->email();
- if (params->source == wallpaper_private::WALLPAPER_SOURCE_ONLINE) {
+ if (params->source == get_thumbnail::Params::SOURCE_ONLINE) {
std::string file_name = GURL(params->url_or_file).ExtractFileName();
CHECK(PathService::Get(chrome::DIR_CHROMEOS_WALLPAPER_THUMBNAILS,
&thumbnail_path));
@@ -743,12 +727,6 @@ WallpaperPrivateGetOfflineWallpaperListFunction::
}
bool WallpaperPrivateGetOfflineWallpaperListFunction::RunImpl() {
- scoped_ptr<get_offline_wallpaper_list::Params> params(
- get_offline_wallpaper_list::Params::Create(*args_));
- EXTENSION_FUNCTION_VALIDATE(params);
-
- std::string email = chromeos::UserManager::Get()->GetLoggedInUser()->email();
-
sequence_token_ = BrowserThread::GetBlockingPool()->
GetNamedSequenceToken(chromeos::kWallpaperSequenceTokenName);
scoped_refptr<base::SequencedTaskRunner> task_runner =
@@ -758,31 +736,25 @@ bool WallpaperPrivateGetOfflineWallpaperListFunction::RunImpl() {
task_runner->PostTask(FROM_HERE,
base::Bind(&WallpaperPrivateGetOfflineWallpaperListFunction::GetList,
- this, email, params->source));
+ this));
return true;
}
-void WallpaperPrivateGetOfflineWallpaperListFunction::GetList(
- const std::string& email,
- WallpaperSource source) {
+void WallpaperPrivateGetOfflineWallpaperListFunction::GetList() {
DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
sequence_token_));
std::vector<std::string> file_list;
- // TODO(bshe): This api function is only used for ONLINE wallpapers. Remove
- // source.
- if (source == wallpaper_private::WALLPAPER_SOURCE_ONLINE) {
- base::FilePath wallpaper_dir;
- CHECK(PathService::Get(chrome::DIR_CHROMEOS_WALLPAPERS, &wallpaper_dir));
- if (base::DirectoryExists(wallpaper_dir)) {
- base::FileEnumerator files(wallpaper_dir, false,
- base::FileEnumerator::FILES);
- for (base::FilePath current = files.Next(); !current.empty();
- current = files.Next()) {
- std::string file_name = current.BaseName().RemoveExtension().value();
- // Do not add file name of small resolution wallpaper to the list.
- if (!EndsWith(file_name, chromeos::kSmallWallpaperSuffix, true))
- file_list.push_back(current.BaseName().value());
- }
+ base::FilePath wallpaper_dir;
+ CHECK(PathService::Get(chrome::DIR_CHROMEOS_WALLPAPERS, &wallpaper_dir));
+ if (base::DirectoryExists(wallpaper_dir)) {
+ base::FileEnumerator files(wallpaper_dir, false,
+ base::FileEnumerator::FILES);
+ for (base::FilePath current = files.Next(); !current.empty();
+ current = files.Next()) {
+ std::string file_name = current.BaseName().RemoveExtension().value();
+ // Do not add file name of small resolution wallpaper to the list.
+ if (!EndsWith(file_name, chromeos::kSmallWallpaperSuffix, true))
+ file_list.push_back(current.BaseName().value());
}
}
BrowserThread::PostTask(
diff --git a/chrome/browser/chromeos/extensions/wallpaper_private_api.h b/chrome/browser/chromeos/extensions/wallpaper_private_api.h
index f73c8fa612..91ba2dac93 100644
--- a/chrome/browser/chromeos/extensions/wallpaper_private_api.h
+++ b/chrome/browser/chromeos/extensions/wallpaper_private_api.h
@@ -7,7 +7,6 @@
#include "base/threading/sequenced_worker_pool.h"
#include "chrome/browser/chromeos/extensions/wallpaper_function_base.h"
-#include "chrome/browser/chromeos/login/user.h"
#include "chrome/common/extensions/api/wallpaper_private.h"
#include "net/url_request/url_fetcher_delegate.h"
@@ -56,9 +55,6 @@ class WallpaperPrivateSetWallpaperIfExistsFunction
scoped_ptr<extensions::api::wallpaper_private::SetWallpaperIfExists::Params>
params;
- // Type of the loaded wallpaper.
- chromeos::User::WallpaperType type_;
-
// Sequence token associated with wallpaper operations. Shared with
// WallpaperManager.
base::SequencedWorkerPool::SequenceToken sequence_token_;
@@ -274,9 +270,8 @@ class WallpaperPrivateGetOfflineWallpaperListFunction
virtual bool RunImpl() OVERRIDE;
private:
- // Enumerates the list of files in wallpaper directory of given |source|.
- void GetList(const std::string& email,
- extensions::api::wallpaper_private::WallpaperSource source);
+ // Enumerates the list of files in online wallpaper directory.
+ void GetList();
// Sends the list of files to extension api caller. If no files or no
// directory, sends empty list.
diff --git a/chrome/browser/chromeos/file_manager/file_browser_handlers.cc b/chrome/browser/chromeos/file_manager/file_browser_handlers.cc
index 1af7759226..54ea3af837 100644
--- a/chrome/browser/chromeos/file_manager/file_browser_handlers.cc
+++ b/chrome/browser/chromeos/file_manager/file_browser_handlers.cc
@@ -17,6 +17,7 @@
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/extensions/lazy_background_task_queue.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser_finder.h"
@@ -105,7 +106,7 @@ FileBrowserHandlerList FindFileBrowserHandlersForURL(
++iter) {
const Extension* extension = iter->get();
if (profile->IsOffTheRecord() &&
- !service->IsIncognitoEnabled(extension->id()))
+ !extension_util::IsIncognitoEnabled(extension->id(), service))
continue;
FileBrowserHandler::List* handler_list =
@@ -445,7 +446,6 @@ bool ShouldBeOpenedWithBrowser(const std::string& extension_id,
(action_id == "view-pdf" ||
action_id == "view-swf" ||
action_id == "view-in-browser" ||
- action_id == "install-crx" ||
action_id == "open-hosted-generic" ||
action_id == "open-hosted-gdoc" ||
action_id == "open-hosted-gsheet" ||
diff --git a/chrome/browser/chromeos/file_manager/file_tasks.cc b/chrome/browser/chromeos/file_manager/file_tasks.cc
index 4bb9e0a929..6468508ccb 100644
--- a/chrome/browser/chromeos/file_manager/file_tasks.cc
+++ b/chrome/browser/chromeos/file_manager/file_tasks.cc
@@ -11,6 +11,7 @@
#include "chrome/browser/chromeos/drive/drive_app_registry.h"
#include "chrome/browser/chromeos/drive/file_system_util.h"
#include "chrome/browser/chromeos/drive/file_task_executor.h"
+#include "chrome/browser/chromeos/file_manager/app_id.h"
#include "chrome/browser/chromeos/file_manager/file_browser_handlers.h"
#include "chrome/browser/chromeos/file_manager/fileapi_util.h"
#include "chrome/browser/chromeos/file_manager/open_util.h"
@@ -21,6 +22,7 @@
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/extensions/extension_tab_util.h"
+#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
#include "chrome/common/extensions/api/file_browser_handlers/file_browser_handler.h"
@@ -50,9 +52,6 @@ const char kDriveAppTaskType[] = "drive";
// Drive apps always use the action ID.
const char kDriveAppActionID[] = "open-with";
-// Default icon path for drive docs.
-const char kDefaultIcon[] = "images/filetype_generic.png";
-
// Converts a TaskType to a string.
std::string TaskTypeToString(TaskType task_type) {
switch (task_type) {
@@ -112,6 +111,29 @@ bool FileBrowserHasAccessPermissionForFiles(
return true;
}
+// Returns true if path_mime_set contains a Google document.
+bool ContainsGoogleDocument(const PathAndMimeTypeSet& path_mime_set) {
+ for (PathAndMimeTypeSet::const_iterator iter = path_mime_set.begin();
+ iter != path_mime_set.end(); ++iter) {
+ if (google_apis::ResourceEntry::ClassifyEntryKindByFileExtension(
+ iter->first) &
+ google_apis::ResourceEntry::KIND_OF_GOOGLE_DOCUMENT) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// Leaves tasks handled by the file manger itself as is and removes all others.
+void KeepOnlyFileManagerInternalTasks(std::vector<FullTaskDescriptor>* tasks) {
+ std::vector<FullTaskDescriptor> filtered;
+ for (size_t i = 0; i < tasks->size(); ++i) {
+ if ((*tasks)[i].task_descriptor().app_id == kFileManagerAppId)
+ filtered.push_back((*tasks)[i]);
+ }
+ tasks->swap(filtered);
+}
+
} // namespace
FullTaskDescriptor::FullTaskDescriptor(
@@ -298,17 +320,6 @@ void FindDriveAppTasks(
std::vector<FullTaskDescriptor>* result_list) {
DCHECK(result_list);
- // Check if path_mime_set contains a google document. Return immediately if
- // it's found.
- for (PathAndMimeTypeSet::const_iterator iter = path_mime_set.begin();
- iter != path_mime_set.end(); ++iter) {
- if (google_apis::ResourceEntry::ClassifyEntryKindByFileExtension(
- iter->first) &
- google_apis::ResourceEntry::KIND_OF_GOOGLE_DOCUMENT) {
- return;
- }
- }
-
bool is_first = true;
typedef std::map<std::string, drive::DriveAppInfo> DriveAppInfoMap;
DriveAppInfoMap drive_app_map;
@@ -390,7 +401,7 @@ void FindFileHandlerTasks(
continue;
if (profile->IsOffTheRecord() &&
- !service->IsIncognitoEnabled(extension->id()))
+ !extension_util::IsIncognitoEnabled(extension->id(), service))
continue;
typedef std::vector<const extensions::FileHandlerInfo*> FileHandlerList;
@@ -480,20 +491,18 @@ void FindAllTypesOfTasks(
// Find and append file handler tasks. We know there aren't duplicates
// because Drive apps and platform apps are entirely different kinds of
// tasks.
- FindFileHandlerTasks(profile,
- path_mime_set,
- result_list);
+ FindFileHandlerTasks(profile, path_mime_set, result_list);
// Find and append file browser handler tasks. We know there aren't
// duplicates because "file_browser_handlers" and "file_handlers" shouldn't
// be used in the same manifest.json.
- FindFileBrowserHandlerTasks(profile,
- file_urls,
- result_list);
+ FindFileBrowserHandlerTasks(profile, file_urls, result_list);
+
+ // Google documents can only be handled by internal handlers.
+ if (ContainsGoogleDocument(path_mime_set))
+ KeepOnlyFileManagerInternalTasks(result_list);
- ChooseAndSetDefaultTask(*profile->GetPrefs(),
- path_mime_set,
- result_list);
+ ChooseAndSetDefaultTask(*profile->GetPrefs(), path_mime_set, result_list);
}
void ChooseAndSetDefaultTask(const PrefService& pref_service,
diff --git a/chrome/browser/chromeos/file_manager/file_tasks.h b/chrome/browser/chromeos/file_manager/file_tasks.h
index 23e69c3c31..8e2e777b61 100644
--- a/chrome/browser/chromeos/file_manager/file_tasks.h
+++ b/chrome/browser/chromeos/file_manager/file_tasks.h
@@ -258,10 +258,6 @@ typedef extensions::app_file_handler_util::PathAndMimeTypeSet
// Finds the Drive app tasks that can be used with the given |path_mime_set|
// from |drive_app_registry|, and append them to the |result_list|.
// Drive app tasks will be found only if all of the files are on Drive.
-//
-// If |path_mime_set| contains a Google document, no Drive app tasks are
-// returned. This is to avoid dups since Files.app already provides an
-// internal handler for Google documents.
void FindDriveAppTasks(const drive::DriveAppRegistry& drive_app_registry,
const PathAndMimeTypeSet& path_mime_set,
std::vector<FullTaskDescriptor>* result_list);
@@ -286,6 +282,12 @@ void FindFileBrowserHandlerTasks(
// Drive app tasks will be found only if all of the files are on Drive.
// |drive_app_registry| can be NULL if the drive app registry is not
// present.
+//
+// If |path_mime_set| contains a Google document, only the internal tasks of
+// Files.app (i.e., tasks having the app ID of Files.app) are listed.
+// This is to avoid dups between Drive app tasks and an internal handler that
+// Files.app provides, and to avoid listing normal file handler and file browser
+// handler tasks, which can handle only normal files.
void FindAllTypesOfTasks(
Profile* profile,
const drive::DriveAppRegistry* drive_app_registry,
diff --git a/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc b/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc
index 598ff0a103..0d2612ebe1 100644
--- a/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc
+++ b/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc
@@ -253,41 +253,6 @@ TEST(FileManagerFileTasksTest, FindDriveAppTasks) {
ASSERT_TRUE(tasks.empty());
}
-TEST(FileManagerFileTasksTest, FindDriveAppTasks_GoogleDocument) {
- // For DriveAppRegistry, which checks CurrentlyOn(BrowserThread::UI).
- content::TestBrowserThreadBundle thread_bundle;
-
- // Foo.app can handle ".gdoc" files.
- scoped_ptr<google_apis::AppResource> foo_app(new google_apis::AppResource);
- foo_app->set_product_url(
- GURL("https://chrome.google.com/webstore/detail/foo_app_id"));
- foo_app->set_application_id("foo_app_id");
- foo_app->set_name("Foo");
- foo_app->set_object_type("foo_object_type");
- ScopedVector<std::string> foo_extensions;
- foo_extensions.push_back(new std::string("gdoc")); // Not ".gdoc"
- foo_app->set_primary_file_extensions(foo_extensions.Pass());
-
- // Prepare DriveAppRegistry from Foo.app.
- ScopedVector<google_apis::AppResource> app_resources;
- app_resources.push_back(foo_app.release());
- google_apis::AppList app_list;
- app_list.set_items(app_resources.Pass());
- drive::DriveAppRegistry drive_app_registry(NULL);
- drive_app_registry.UpdateFromAppList(app_list);
-
- // Find apps for a ".gdoc file". Foo.app can handle it but should not be
- // found, as it should be rejected.
- PathAndMimeTypeSet path_mime_set;
- path_mime_set.insert(
- std::make_pair(
- drive::util::GetDriveMountPointPath().AppendASCII("foo.gdoc"),
- "application/vnd.google-apps.document"));
- std::vector<FullTaskDescriptor> tasks;
- FindDriveAppTasks(drive_app_registry, path_mime_set, &tasks);
- EXPECT_TRUE(tasks.empty());
-}
-
// Test that the right task is chosen from multiple choices per mime types
// and file extensions.
TEST(FileManagerFileTasksTest, ChooseAndSetDefaultTask_MultipleTasks) {
@@ -686,5 +651,86 @@ TEST_F(FileManagerFileTasksComplexTest, FindAllTypesOfTasks) {
EXPECT_EQ(kBazId, app_ids[2]);
}
+TEST_F(FileManagerFileTasksComplexTest, FindAllTypesOfTasks_GoogleDocument) {
+ // kFooId and kBarId copied from FindFileHandlerTasks test above.
+ const char kFooId[] = "hhgbjpmdppecanaaogonaigmmifgpaph";
+ const char kBarId[] = "odlhccgofgkadkkhcmhgnhgahonahoca";
+
+ // Foo.app can handle ".gdoc" files.
+ scoped_ptr<google_apis::AppResource> foo_app(new google_apis::AppResource);
+ foo_app->set_product_url(
+ GURL("https://chrome.google.com/webstore/detail/foo_app"));
+ foo_app->set_application_id(kFooId);
+ foo_app->set_name("Foo");
+ foo_app->set_object_type("foo_object_type");
+ ScopedVector<std::string> foo_extensions;
+ foo_extensions.push_back(new std::string("gdoc")); // Not ".gdoc"
+ foo_app->set_primary_file_extensions(foo_extensions.Pass());
+
+ // Prepare DriveAppRegistry from Foo.app.
+ ScopedVector<google_apis::AppResource> app_resources;
+ app_resources.push_back(foo_app.release());
+ google_apis::AppList app_list;
+ app_list.set_items(app_resources.Pass());
+ drive::DriveAppRegistry drive_app_registry(NULL);
+ drive_app_registry.UpdateFromAppList(app_list);
+
+ // Bar.app can handle ".gdoc" files.
+ // This is an extension (file browser handler).
+ extensions::ExtensionBuilder bar_app;
+ bar_app.SetManifest(extensions::DictionaryBuilder()
+ .Set("name", "Bar")
+ .Set("version", "1.0.0")
+ .Set("manifest_version", 2)
+ .Set("file_browser_handlers",
+ extensions::ListBuilder()
+ .Append(extensions::DictionaryBuilder()
+ .Set("id", "open")
+ .Set("default_title", "open")
+ .Set("file_filters",
+ extensions::ListBuilder()
+ .Append("filesystem:*.gdoc")))));
+ bar_app.SetID(kBarId);
+ extension_service_->AddExtension(bar_app.Build().get());
+
+ // Files.app can handle ".gdoc" files.
+ // The ID "kFileManagerAppId" used here is precisely the one that identifies
+ // the Chrome OS Files.app application.
+ extensions::ExtensionBuilder files_app;
+ files_app.SetManifest(extensions::DictionaryBuilder()
+ .Set("name", "Files")
+ .Set("version", "1.0.0")
+ .Set("manifest_version", 2)
+ .Set("file_browser_handlers",
+ extensions::ListBuilder()
+ .Append(extensions::DictionaryBuilder()
+ .Set("id", "open")
+ .Set("default_title", "open")
+ .Set("file_filters",
+ extensions::ListBuilder()
+ .Append("filesystem:*.gdoc")))));
+ files_app.SetID(kFileManagerAppId);
+ extension_service_->AddExtension(files_app.Build().get());
+
+ // Find apps for a ".gdoc file". Only the built-in handler of Files.apps
+ // should be found.
+ PathAndMimeTypeSet path_mime_set;
+ std::vector<GURL> file_urls;
+ path_mime_set.insert(
+ std::make_pair(
+ drive::util::GetDriveMountPointPath().AppendASCII("foo.gdoc"),
+ "application/vnd.google-apps.document"));
+ file_urls.push_back(GURL("filesystem:chrome-extension://id/dir/foo.gdoc"));
+
+ std::vector<FullTaskDescriptor> tasks;
+ FindAllTypesOfTasks(&test_profile_,
+ &drive_app_registry,
+ path_mime_set,
+ file_urls,
+ &tasks);
+ ASSERT_EQ(1U, tasks.size());
+ EXPECT_EQ(kFileManagerAppId, tasks[0].task_descriptor().app_id);
+}
+
} // namespace file_tasks
} // namespace file_manager.
diff --git a/chrome/browser/chromeos/file_manager/open_with_browser.cc b/chrome/browser/chromeos/file_manager/open_with_browser.cc
index fddb999b38..0ee88143a8 100644
--- a/chrome/browser/chromeos/file_manager/open_with_browser.cc
+++ b/chrome/browser/chromeos/file_manager/open_with_browser.cc
@@ -10,14 +10,8 @@
#include "base/path_service.h"
#include "base/threading/sequenced_worker_pool.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/chromeos/drive/drive.pb.h"
-#include "chrome/browser/chromeos/drive/file_system.h"
#include "chrome/browser/chromeos/drive/file_system_util.h"
#include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
-#include "chrome/browser/extensions/crx_installer.h"
-#include "chrome/browser/extensions/extension_install_prompt.h"
-#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/plugins/plugin_prefs.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
@@ -42,7 +36,6 @@ namespace file_manager {
namespace util {
namespace {
-const base::FilePath::CharType kCRXExtension[] = FILE_PATH_LITERAL(".crx");
const base::FilePath::CharType kPdfExtension[] = FILE_PATH_LITERAL(".pdf");
const base::FilePath::CharType kSwfExtension[] = FILE_PATH_LITERAL(".swf");
@@ -126,36 +119,6 @@ void OpenNewTab(Profile* profile, const GURL& url) {
browser->window()->Show();
}
-void InstallCRX(Profile* profile, const base::FilePath& file_path) {
- DCHECK(profile);
-
- ExtensionService* service =
- extensions::ExtensionSystem::Get(profile)->extension_service();
- CHECK(service);
-
- scoped_refptr<extensions::CrxInstaller> installer(
- extensions::CrxInstaller::Create(
- service,
- scoped_ptr<ExtensionInstallPrompt>(new ExtensionInstallPrompt(
- profile, NULL, NULL))));
- installer->set_error_on_unsupported_requirements(true);
- installer->set_is_gallery_install(false);
- installer->set_allow_silent_install(false);
- installer->InstallCrx(file_path);
-}
-
-// Called when a crx file on Drive was downloaded.
-void OnCRXDownloadCallback(Profile* profile,
- drive::FileError error,
- const base::FilePath& file,
- scoped_ptr<drive::ResourceEntry> entry) {
- DCHECK(profile);
-
- if (error != drive::FILE_ERROR_OK)
- return;
- InstallCRX(profile, file);
-}
-
// Reads the alternate URL from a GDoc file. When it fails, returns a file URL
// for |file_path| as fallback.
// Note that an alternate url is a URL to open a hosted document.
@@ -204,21 +167,6 @@ bool OpenFileWithBrowser(Profile* profile, const base::FilePath& file_path) {
return true;
}
- if (file_path.MatchesExtension(kCRXExtension)) {
- if (drive::util::IsUnderDriveMountPoint(file_path)) {
- drive::FileSystemInterface* file_system =
- drive::util::GetFileSystemByProfile(profile);
- if (!file_system)
- return false;
- file_system->GetFileByPath(
- drive::util::ExtractDrivePath(file_path),
- base::Bind(&OnCRXDownloadCallback, profile));
- } else {
- InstallCRX(profile, file_path);
- }
- return true;
- }
-
// Failed to open the file of unknown type.
LOG(WARNING) << "Unknown file type: " << file_path.value();
return false;
diff --git a/chrome/browser/chromeos/file_manager/open_with_browser.h b/chrome/browser/chromeos/file_manager/open_with_browser.h
index 6f9395a1c8..acb678a86a 100644
--- a/chrome/browser/chromeos/file_manager/open_with_browser.h
+++ b/chrome/browser/chromeos/file_manager/open_with_browser.h
@@ -9,7 +9,6 @@
#include "base/files/file_path.h"
-class Browser;
class Profile;
namespace file_manager {
@@ -21,7 +20,6 @@ namespace util {
// - If there is no active browser window, open it.
// - If the file is a Drive hosted document, the hosted document will be
// opened in the browser by extracting the right URL for the file.
-// - If the file is a CRX file, the CRX file will be installed.
// - If the file is on Drive, the file will be downloaded from Drive as
// needed.
//
diff --git a/chrome/browser/chromeos/file_manager/url_util.cc b/chrome/browser/chromeos/file_manager/url_util.cc
index fecf759a1e..ff703e83f5 100644
--- a/chrome/browser/chromeos/file_manager/url_util.cc
+++ b/chrome/browser/chromeos/file_manager/url_util.cc
@@ -113,8 +113,6 @@ GURL GetFileManagerMainPageUrlWithParams(
std::string json_args;
base::JSONWriter::Write(&arg_value, &json_args);
- // kChromeUIFileManagerURL could not be used since query parameters are not
- // supported for it.
std::string url = GetFileManagerMainPageUrl().spec() + '?' +
net::EscapeUrlEncodedData(json_args,
false); // Space to %20 instead of +.
diff --git a/chrome/browser/chromeos/input_method/input_method_configuration_unittest.cc b/chrome/browser/chromeos/input_method/input_method_configuration_unittest.cc
index a5aaae41ba..77bd6ae92a 100644
--- a/chrome/browser/chromeos/input_method/input_method_configuration_unittest.cc
+++ b/chrome/browser/chromeos/input_method/input_method_configuration_unittest.cc
@@ -5,7 +5,7 @@
#include "chrome/browser/chromeos/input_method/input_method_configuration.h"
#include "chrome/browser/chromeos/input_method/mock_input_method_manager.h"
#include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/mock_dbus_thread_manager_without_gmock.h"
+#include "chromeos/dbus/fake_dbus_thread_manager.h"
#include "content/public/browser/browser_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -16,7 +16,7 @@ class InputMethodConfigurationTest : public testing::Test {
public:
virtual void SetUp() {
chromeos::DBusThreadManager::InitializeForTesting(
- new chromeos::MockDBusThreadManagerWithoutGMock());
+ new chromeos::FakeDBusThreadManager());
}
virtual void TearDown() {
diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
index 7624f75dec..13d39be633 100644
--- a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
+++ b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
@@ -32,8 +32,6 @@ namespace input_method {
namespace {
-const char nacl_mozc_us_id[] =
- "_comp_ime_fpfbhcjppmaeaijcidgiibchfbnhbeljnacl_mozc_us";
const char nacl_mozc_jp_id[] =
"_comp_ime_fpfbhcjppmaeaijcidgiibchfbnhbeljnacl_mozc_jp";
diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc b/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc
index cd5c49b310..45f3780b0a 100644
--- a/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc
+++ b/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc
@@ -15,8 +15,8 @@
#include "base/message_loop/message_loop.h"
#include "chrome/browser/chromeos/input_method/mock_candidate_window_controller.h"
#include "chrome/browser/chromeos/input_method/mock_ibus_controller.h"
+#include "chromeos/dbus/fake_dbus_thread_manager.h"
#include "chromeos/dbus/ibus/mock_ibus_client.h"
-#include "chromeos/dbus/mock_dbus_thread_manager_without_gmock.h"
#include "chromeos/ime/extension_ime_util.h"
#include "chromeos/ime/fake_input_method_delegate.h"
#include "chromeos/ime/mock_component_extension_ime_manager_delegate.h"
@@ -61,10 +61,10 @@ class InputMethodManagerImplTest : public testing::Test {
mock_ibus_daemon_controller_ = new chromeos::MockIBusDaemonController();
chromeos::IBusDaemonController::InitializeForTesting(
mock_ibus_daemon_controller_);
- mock_dbus_thread_manager_ =
- new chromeos::MockDBusThreadManagerWithoutGMock();
+ fake_dbus_thread_manager_ =
+ new chromeos::FakeDBusThreadManager();
chromeos::DBusThreadManager::InitializeForTesting(
- mock_dbus_thread_manager_);
+ fake_dbus_thread_manager_);
delegate_ = new FakeInputMethodDelegate();
manager_.reset(new InputMethodManagerImpl(
scoped_ptr<InputMethodDelegate>(delegate_)));
@@ -151,9 +151,9 @@ class InputMethodManagerImplTest : public testing::Test {
// Helper function to initialize IBus bus connection for testing. Do not use
// ibus related mocks before calling this function.
void InitIBusBus() {
- mock_dbus_thread_manager_->InitIBusBus("dummy address",
+ fake_dbus_thread_manager_->InitIBusBus("dummy address",
base::Bind(&base::DoNothing));
- mock_ibus_client_ = mock_dbus_thread_manager_->mock_ibus_client();
+ mock_ibus_client_ = fake_dbus_thread_manager_->mock_ibus_client();
mock_ibus_daemon_controller_->EmulateConnect();
}
@@ -164,7 +164,7 @@ class InputMethodManagerImplTest : public testing::Test {
MockIBusDaemonController* mock_ibus_daemon_controller_;
scoped_ptr<MockIMEEngineHandler> mock_engine_handler_;
MockIBusClient* mock_ibus_client_;
- MockDBusThreadManagerWithoutGMock* mock_dbus_thread_manager_;
+ FakeDBusThreadManager* fake_dbus_thread_manager_;
MockXKeyboard* xkeyboard_;
base::MessageLoop message_loop_;
MockComponentExtIMEManagerDelegate* mock_delegate_;
diff --git a/chrome/browser/chromeos/kiosk_mode/kiosk_mode_idle_logout.cc b/chrome/browser/chromeos/kiosk_mode/kiosk_mode_idle_logout.cc
index 47cc5a9a3b..d005433b5a 100644
--- a/chrome/browser/chromeos/kiosk_mode/kiosk_mode_idle_logout.cc
+++ b/chrome/browser/chromeos/kiosk_mode/kiosk_mode_idle_logout.cc
@@ -22,8 +22,6 @@ namespace chromeos {
namespace {
-const int64 kLoginIdleTimeout = 100; // seconds
-
static base::LazyInstance<KioskModeIdleLogout>
g_kiosk_mode_idle_logout = LAZY_INSTANCE_INITIALIZER;
diff --git a/chrome/browser/chromeos/login/app_launch_signin_screen.cc b/chrome/browser/chromeos/login/app_launch_signin_screen.cc
index 06f17a795d..2092480262 100644
--- a/chrome/browser/chromeos/login/app_launch_signin_screen.cc
+++ b/chrome/browser/chromeos/login/app_launch_signin_screen.cc
@@ -196,9 +196,7 @@ void AppLaunchSigninScreen::OnLoginFailure(const LoginFailure& error) {
HelpAppLauncher::HELP_CANT_ACCESS_ACCOUNT_OFFLINE);
}
-void AppLaunchSigninScreen::OnLoginSuccess(const UserContext& user_context,
- bool pending_requests,
- bool using_oauth) {
+void AppLaunchSigninScreen::OnLoginSuccess(const UserContext& user_context) {
delegate_->OnOwnerSigninSuccess();
}
diff --git a/chrome/browser/chromeos/login/app_launch_signin_screen.h b/chrome/browser/chromeos/login/app_launch_signin_screen.h
index 7b2ac1536e..dc5b2f423e 100644
--- a/chrome/browser/chromeos/login/app_launch_signin_screen.h
+++ b/chrome/browser/chromeos/login/app_launch_signin_screen.h
@@ -84,9 +84,7 @@ class AppLaunchSigninScreen
// LoginStatusConsumer implementation:
virtual void OnLoginFailure(const LoginFailure& error) OVERRIDE;
- virtual void OnLoginSuccess(const UserContext& user_context,
- bool pending_requests,
- bool using_oauth) OVERRIDE;
+ virtual void OnLoginSuccess(const UserContext& user_context) OVERRIDE;
OobeUI* oobe_ui_;
Delegate* delegate_;
diff --git a/chrome/browser/chromeos/login/auth_sync_observer.cc b/chrome/browser/chromeos/login/auth_sync_observer.cc
index e2dd8a072d..4c623c2bee 100644
--- a/chrome/browser/chromeos/login/auth_sync_observer.cc
+++ b/chrome/browser/chromeos/login/auth_sync_observer.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/chromeos/login/auth_sync_observer.h"
#include "base/prefs/pref_service.h"
+#include "chrome/browser/chromeos/login/supervised_user_manager.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/profile_sync_service_factory.h"
@@ -58,7 +59,7 @@ void AuthSyncObserver::OnStateChanged() {
std::string sync_id =
profile_->GetPrefs()->GetString(prefs::kManagedUserId);
const User* user =
- UserManager::Get()->FindLocallyManagedUserBySyncId(sync_id);
+ UserManager::Get()->GetSupervisedUserManager()->FindBySyncId(sync_id);
if (user)
email = user->email();
}
diff --git a/chrome/browser/chromeos/login/authenticator.h b/chrome/browser/chromeos/login/authenticator.h
index b20a35bd17..f061803683 100644
--- a/chrome/browser/chromeos/login/authenticator.h
+++ b/chrome/browser/chromeos/login/authenticator.h
@@ -19,11 +19,10 @@ namespace chromeos {
struct UserContext;
// An interface for objects that will authenticate a Chromium OS user.
-// When authentication successfully completes, will call
-// consumer_->OnLoginSuccess() on the UI thread.
-// On failure, will call consumer_->OnLoginFailure() on the UI thread.
-// On password change detected, will call
-// consumer_->OnPasswordChangeDetected() on the UI thread.
+// Callbacks will be called on the UI thread:
+// 1. On successful authentication, will call consumer_->OnLoginSuccess().
+// 2. On failure, will call consumer_->OnLoginFailure().
+// 3. On password change, will call consumer_->OnPasswordChangeDetected().
class Authenticator : public base::RefCountedThreadSafe<Authenticator> {
public:
explicit Authenticator(LoginStatusConsumer* consumer);
@@ -42,8 +41,7 @@ class Authenticator : public base::RefCountedThreadSafe<Authenticator> {
// Given a user credentials in |user_context|, this method attempts to
// authenticate to unlock the computer.
// Must be called on the UI thread.
- virtual void AuthenticateToUnlock(
- const UserContext& user_context) = 0;
+ virtual void AuthenticateToUnlock(const UserContext& user_context) = 0;
// Initiates locally managed user login.
virtual void LoginAsLocallyManagedUser(
@@ -65,11 +63,8 @@ class Authenticator : public base::RefCountedThreadSafe<Authenticator> {
// Completes retail mode login.
virtual void OnRetailModeLoginSuccess() = 0;
- // Notifies caller that login was successful.
- // |request_pending| is true if we still plan to call consumer_ with the
- // results of more requests.
- // Must be called on the UI thread.
- virtual void OnLoginSuccess(bool request_pending) = 0;
+ // Notifies caller that login was successful. Must be called on the UI thread.
+ virtual void OnLoginSuccess() = 0;
// Must be called on the UI thread.
virtual void OnLoginFailure(const LoginFailure& error) = 0;
diff --git a/chrome/browser/chromeos/login/captive_portal_view.cc b/chrome/browser/chromeos/login/captive_portal_view.cc
index c6dc73e634..96f348ff6a 100644
--- a/chrome/browser/chromeos/login/captive_portal_view.cc
+++ b/chrome/browser/chromeos/login/captive_portal_view.cc
@@ -77,8 +77,7 @@ views::NonClientFrameView* CaptivePortalView::CreateNonClientFrameView(
return views::DialogDelegate::CreateNewStyleFrameView(widget,
force_opaque_border);
}
- ash::CustomFrameViewAsh* frame = new ash::CustomFrameViewAsh;
- frame->Init(widget);
+ ash::CustomFrameViewAsh* frame = new ash::CustomFrameViewAsh(widget);
// Always use "active" look.
frame->SetInactiveRenderingDisabled(true);
return frame;
diff --git a/chrome/browser/chromeos/login/chrome_restart_request.cc b/chrome/browser/chromeos/login/chrome_restart_request.cc
index 742583849e..e921b95409 100644
--- a/chrome/browser/chromeos/login/chrome_restart_request.cc
+++ b/chrome/browser/chromeos/login/chrome_restart_request.cc
@@ -54,9 +54,6 @@ const char kGuestModeLoggingLevel[] = "1";
// Format of command line switch.
const char kSwitchFormatString[] = " --%s=\"%s\"";
-// User name which is used in the Guest session.
-const char kGuestUserName[] = "";
-
// Derives the new command line from |base_command_line| by doing the following:
// - Forward a given switches list to new command;
// - Set start url if given;
@@ -89,6 +86,7 @@ std::string DeriveCommandLine(const GURL& start_url,
::switches::kDisableThreadedCompositing,
::switches::kDisableTouchDragDrop,
::switches::kDisableTouchEditing,
+ ::switches::kDisableUniversalAcceleratedOverflowScroll,
::switches::kDisableWebKitMediaSource,
::switches::kDisableAcceleratedFixedRootBackground,
::switches::kEnableAcceleratedFixedRootBackground,
@@ -106,6 +104,7 @@ std::string DeriveCommandLine(const GURL& start_url,
::switches::kEnableThreadedCompositing,
::switches::kEnableTouchDragDrop,
::switches::kEnableTouchEditing,
+ ::switches::kEnableUniversalAcceleratedOverflowScroll,
::switches::kEnableViewport,
::switches::kForceDeviceScaleFactor,
::switches::kGpuStartupDialog,
diff --git a/chrome/browser/chromeos/login/crash_restore_browsertest.cc b/chrome/browser/chromeos/login/crash_restore_browsertest.cc
index 6062fd8a49..d956d39aa5 100644
--- a/chrome/browser/chromeos/login/crash_restore_browsertest.cc
+++ b/chrome/browser/chromeos/login/crash_restore_browsertest.cc
@@ -14,8 +14,8 @@
#include "chrome/test/base/in_process_browser_test.h"
#include "chromeos/chromeos_switches.h"
#include "chromeos/dbus/cryptohome_client.h"
+#include "chromeos/dbus/fake_dbus_thread_manager.h"
#include "chromeos/dbus/fake_session_manager_client.h"
-#include "chromeos/dbus/mock_dbus_thread_manager_without_gmock.h"
#include "chromeos/dbus/session_manager_client.h"
#include "content/public/test/test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -47,8 +47,8 @@ class CrashRestoreSimpleTest : public InProcessBrowserTest {
virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
// Redirect session_manager DBus calls to FakeSessionManagerClient.
- MockDBusThreadManagerWithoutGMock* dbus_thread_manager =
- new MockDBusThreadManagerWithoutGMock();
+ FakeDBusThreadManager* dbus_thread_manager =
+ new FakeDBusThreadManager();
session_manager_client_ =
dbus_thread_manager->fake_session_manager_client();
DBusThreadManager::InitializeForTesting(dbus_thread_manager);
diff --git a/chrome/browser/chromeos/login/eula_browsertest.cc b/chrome/browser/chromeos/login/eula_browsertest.cc
index 412ddb5c91..e1cb49f1d4 100644
--- a/chrome/browser/chromeos/login/eula_browsertest.cc
+++ b/chrome/browser/chromeos/login/eula_browsertest.cc
@@ -22,7 +22,9 @@ namespace {
const char kEULAURL[] =
"https://www.google.com/intl/en-US/chrome/eula_text.html";
const char kFakeOnlineEULA[] = "No obligations at all";
+#if defined(GOOGLE_CHROME_BUILD)
const char kOfflineEULAWarning[] = "A copy of the Google Terms of Service";
+#endif
class TermsOfServiceProcessBrowserTest : public InProcessBrowserTest {
};
diff --git a/chrome/browser/chromeos/login/existing_user_controller.cc b/chrome/browser/chromeos/login/existing_user_controller.cc
index cfe8624c5c..ceef789e26 100644
--- a/chrome/browser/chromeos/login/existing_user_controller.cc
+++ b/chrome/browser/chromeos/login/existing_user_controller.cc
@@ -66,9 +66,6 @@ namespace chromeos {
namespace {
-// Major version where we still show GSG as "Release Notes" after the update.
-const long int kReleaseNotesTargetRelease = 19;
-
// URL for account creation.
const char kCreateAccountURL[] =
"https://accounts.google.com/NewAccount?service=mail";
@@ -84,9 +81,6 @@ const long int kAuthCacheTransferDelayMs = 2000;
// Delay for restarting the ui if safe-mode login has failed.
const long int kSafeModeRestartUiDelayMs = 30000;
-// Delay for rebooting machine if TPM critical error was encountered.
-const long int kCriticalErrorRebootDelayMs = 3500;
-
// Makes a call to the policy subsystem to reload the policy when we detect
// authentication change.
void RefreshPoliciesOnUIThread() {
@@ -749,10 +743,7 @@ void ExistingUserController::OnLoginFailure(const LoginFailure& failure) {
display_email_.clear();
}
-void ExistingUserController::OnLoginSuccess(
- const UserContext& user_context,
- bool pending_requests,
- bool using_oauth) {
+void ExistingUserController::OnLoginSuccess(const UserContext& user_context) {
is_login_in_progress_ = false;
offline_failed_ = false;
login_display_->set_signin_completed(true);
@@ -778,7 +769,6 @@ void ExistingUserController::OnLoginSuccess(
// Will call OnProfilePrepared() in the end.
LoginUtils::Get()->PrepareProfile(user_context,
display_email_,
- using_oauth,
has_cookies,
false, // Start session for user.
this);
@@ -824,13 +814,9 @@ void ExistingUserController::OnProfilePrepared(Profile* profile) {
LoginUtils::Get()->DoBrowserLaunch(profile, host_);
host_ = NULL;
}
- // Inform |login_status_consumer_| about successful login. Set most
- // parameters to empty since they're not needed.
- if (login_status_consumer_) {
- login_status_consumer_->OnLoginSuccess(UserContext(),
- false, // pending_requests
- false); // using_oauth
- }
+ // Inform |login_status_consumer_| about successful login.
+ if (login_status_consumer_)
+ login_status_consumer_->OnLoginSuccess(UserContext());
login_display_->OnFadeOut();
}
diff --git a/chrome/browser/chromeos/login/existing_user_controller.h b/chrome/browser/chromeos/login/existing_user_controller.h
index 80fbcd5545..ace3e0595a 100644
--- a/chrome/browser/chromeos/login/existing_user_controller.h
+++ b/chrome/browser/chromeos/login/existing_user_controller.h
@@ -134,10 +134,7 @@ class ExistingUserController : public LoginDisplay::Delegate,
// LoginPerformer::Delegate implementation:
virtual void OnLoginFailure(const LoginFailure& error) OVERRIDE;
- virtual void OnLoginSuccess(
- const UserContext& user_context,
- bool pending_requests,
- bool using_oauth) OVERRIDE;
+ virtual void OnLoginSuccess(const UserContext& user_context) OVERRIDE;
virtual void OnOffTheRecordLoginSuccess() OVERRIDE;
virtual void OnPasswordChangeDetected() OVERRIDE;
virtual void WhiteListCheckFailed(const std::string& email) OVERRIDE;
diff --git a/chrome/browser/chromeos/login/existing_user_controller_auto_login_unittest.cc b/chrome/browser/chromeos/login/existing_user_controller_auto_login_unittest.cc
index 03c5638d66..e0a9ba01bf 100644
--- a/chrome/browser/chromeos/login/existing_user_controller_auto_login_unittest.cc
+++ b/chrome/browser/chromeos/login/existing_user_controller_auto_login_unittest.cc
@@ -34,7 +34,6 @@ namespace {
const char kAutoLoginAccountId[] = "public_session_user@localhost";
// These values are only used to test the configuration. They don't
// delay the test.
-const int kAutoLoginNoDelay = 0;
const int kAutoLoginDelay1 = 60000;
const int kAutoLoginDelay2 = 180000;
diff --git a/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc b/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc
index 70b8084982..2b75231684 100644
--- a/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc
+++ b/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc
@@ -240,7 +240,7 @@ IN_PROC_BROWSER_TEST_P(ExistingUserControllerTest, ExistingUserLogin) {
.WillOnce(WithArg<0>(CreateAuthenticator(kUsername, kPassword)));
EXPECT_CALL(*mock_login_utils_,
PrepareProfile(UserContext(kUsername, kPassword, "", kUsername),
- _, _, _, _, _))
+ _, _, _, _))
.Times(1)
.WillOnce(InvokeWithoutArgs(&profile_prepared_cb_,
&base::Callback<void(void)>::Run));
@@ -309,7 +309,7 @@ IN_PROC_BROWSER_TEST_P(ExistingUserControllerTest,
kPassword,
std::string(),
kNewUsername),
- _, _, _, _, _))
+ _, _, _, _))
.Times(1)
.WillOnce(InvokeWithoutArgs(&profile_prepared_cb_,
&base::Callback<void(void)>::Run));
@@ -433,7 +433,7 @@ class ExistingUserControllerPublicSessionTest
.WillOnce(WithArg<0>(CreateAuthenticator(username, password)));
EXPECT_CALL(*mock_login_utils_,
PrepareProfile(UserContext(username, password, "", username),
- _, _, _, _, _))
+ _, _, _, _))
.Times(1)
.WillOnce(InvokeWithoutArgs(&profile_prepared_cb_,
&base::Callback<void(void)>::Run));
diff --git a/chrome/browser/chromeos/login/fake_login_utils.cc b/chrome/browser/chromeos/login/fake_login_utils.cc
index e5e5b06272..cd573deb4f 100644
--- a/chrome/browser/chromeos/login/fake_login_utils.cc
+++ b/chrome/browser/chromeos/login/fake_login_utils.cc
@@ -11,6 +11,7 @@
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/chromeos/login/login_display_host.h"
#include "chrome/browser/chromeos/login/mock_authenticator.h"
+#include "chrome/browser/chromeos/login/supervised_user_manager.h"
#include "chrome/browser/first_run/first_run.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/startup/startup_browser_creator.h"
@@ -55,7 +56,6 @@ void FakeLoginUtils::DoBrowserLaunch(Profile* profile,
void FakeLoginUtils::PrepareProfile(const UserContext& user_context,
const std::string& display_email,
- bool using_oauth,
bool has_cookies,
bool has_active_session,
LoginUtils::Delegate* delegate) {
@@ -76,7 +76,8 @@ void FakeLoginUtils::PrepareProfile(const UserContext& user_context,
if (UserManager::Get()->IsLoggedInAsLocallyManagedUser()) {
User* active_user = UserManager::Get()->GetActiveUser();
std::string managed_user_sync_id =
- UserManager::Get()->GetManagedUserSyncId(active_user->email());
+ UserManager::Get()->GetSupervisedUserManager()->
+ GetUserSyncId(active_user->email());
if (managed_user_sync_id.empty())
managed_user_sync_id = "DUMMY ID";
profile->GetPrefs()->SetString(prefs::kManagedUserId,
diff --git a/chrome/browser/chromeos/login/fake_login_utils.h b/chrome/browser/chromeos/login/fake_login_utils.h
index 2cf4c29150..23a834e838 100644
--- a/chrome/browser/chromeos/login/fake_login_utils.h
+++ b/chrome/browser/chromeos/login/fake_login_utils.h
@@ -24,7 +24,6 @@ class FakeLoginUtils : public LoginUtils {
LoginDisplayHost* login_host) OVERRIDE;
virtual void PrepareProfile(const UserContext& user_context,
const std::string& display_email,
- bool using_oauth,
bool has_cookies,
bool has_active_session,
LoginUtils::Delegate* delegate) OVERRIDE;
diff --git a/chrome/browser/chromeos/login/fake_supervised_user_manager.cc b/chrome/browser/chromeos/login/fake_supervised_user_manager.cc
new file mode 100644
index 0000000000..6310d9e80b
--- /dev/null
+++ b/chrome/browser/chromeos/login/fake_supervised_user_manager.cc
@@ -0,0 +1,58 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/login/fake_supervised_user_manager.h"
+
+#include <string>
+
+namespace chromeos {
+
+FakeSupervisedUserManager::FakeSupervisedUserManager() {}
+
+FakeSupervisedUserManager::~FakeSupervisedUserManager() {
+}
+
+const User* FakeSupervisedUserManager::CreateUserRecord(
+ const std::string& manager_id,
+ const std::string& local_user_id,
+ const std::string& sync_user_id,
+ const string16& display_name) {
+ return NULL;
+}
+
+std::string FakeSupervisedUserManager::GenerateUserId() {
+ return std::string();
+}
+
+const User* FakeSupervisedUserManager::FindByDisplayName(
+ const string16& display_name) const {
+ return NULL;
+}
+
+const User* FakeSupervisedUserManager::FindBySyncId(
+ const std::string& sync_id) const {
+ return NULL;
+}
+
+std::string FakeSupervisedUserManager::GetUserSyncId(
+ const std::string& managed_user_id) const {
+ return std::string();
+}
+
+string16 FakeSupervisedUserManager::GetManagerDisplayName(
+ const std::string& managed_user_id) const {
+ return string16();
+}
+
+std::string FakeSupervisedUserManager::GetManagerUserId(
+ const std::string& managed_user_id) const {
+ return std::string();
+}
+
+std::string FakeSupervisedUserManager::GetManagerDisplayEmail(
+ const std::string& managed_user_id) const {
+ return std::string();
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/fake_supervised_user_manager.h b/chrome/browser/chromeos/login/fake_supervised_user_manager.h
new file mode 100644
index 0000000000..a291ade8df
--- /dev/null
+++ b/chrome/browser/chromeos/login/fake_supervised_user_manager.h
@@ -0,0 +1,48 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_FAKE_SUPERVISED_USER_MANAGER_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_FAKE_SUPERVISED_USER_MANAGER_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "chrome/browser/chromeos/login/supervised_user_manager.h"
+
+namespace chromeos {
+
+// Fake supervised user manager with a barebones implementation.
+class FakeSupervisedUserManager : public SupervisedUserManager {
+ public:
+ FakeSupervisedUserManager();
+ virtual ~FakeSupervisedUserManager();
+
+ virtual const User* CreateUserRecord(
+ const std::string& manager_id,
+ const std::string& local_user_id,
+ const std::string& sync_user_id,
+ const string16& display_name) OVERRIDE;
+ virtual std::string GenerateUserId() OVERRIDE;
+ virtual const User* FindByDisplayName(const string16& display_name) const
+ OVERRIDE;
+ virtual const User* FindBySyncId(const std::string& sync_id) const OVERRIDE;
+ virtual std::string GetUserSyncId(const std::string& user_id) const OVERRIDE;
+ virtual string16 GetManagerDisplayName(const std::string& user_id) const
+ OVERRIDE;
+ virtual std::string GetManagerUserId(const std::string& user_id) const
+ OVERRIDE;
+ virtual std::string GetManagerDisplayEmail(const std::string& user_id) const
+ OVERRIDE;
+ virtual void StartCreationTransaction(const string16& display_name)
+ OVERRIDE {}
+ virtual void SetCreationTransactionUserId(const std::string& user_id)
+ OVERRIDE {}
+ virtual void CommitCreationTransaction() OVERRIDE {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FakeSupervisedUserManager);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_LOGIN_FAKE_SUPERVISED_USER_MANAGER_H_
diff --git a/chrome/browser/chromeos/login/fake_user_manager.cc b/chrome/browser/chromeos/login/fake_user_manager.cc
index 2cb93e72f9..f5b1e7e059 100644
--- a/chrome/browser/chromeos/login/fake_user_manager.cc
+++ b/chrome/browser/chromeos/login/fake_user_manager.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/chromeos/login/fake_user_manager.h"
+#include "chrome/browser/chromeos/login/fake_supervised_user_manager.h"
+
namespace {
// As defined in /chromeos/dbus/cryptohome_client.cc.
@@ -13,7 +15,9 @@ static const char kUserIdHashSuffix[] = "-hash";
namespace chromeos {
-FakeUserManager::FakeUserManager() : primary_user_(NULL) {}
+FakeUserManager::FakeUserManager()
+ : supervised_user_manager_(new FakeSupervisedUserManager),
+ primary_user_(NULL) {}
FakeUserManager::~FakeUserManager() {
// Can't use STLDeleteElements because of the private destructor of User.
@@ -107,6 +111,10 @@ void FakeUserManager::UpdateUserAccountData(const std::string&, const string16&,
// Not implemented
}
+SupervisedUserManager* FakeUserManager::GetSupervisedUserManager() {
+ return supervised_user_manager_.get();
+}
+
UserImageManager* FakeUserManager::GetUserImageManager() {
return NULL;
}
@@ -123,18 +131,6 @@ const std::string& FakeUserManager::GetOwnerEmail() {
return owner_email_;
}
-const User* FakeUserManager::CreateLocallyManagedUserRecord(
- const std::string& manager_id,
- const std::string& local_user_id,
- const std::string& sync_user_id,
- const string16& display_name) {
- return NULL;
-}
-
-std::string FakeUserManager::GenerateUniqueLocallyManagedUserId() {
- return std::string();
-}
-
bool FakeUserManager::IsKnownUser(const std::string& email) const {
return true;
}
@@ -143,16 +139,6 @@ const User* FakeUserManager::FindUser(const std::string& email) const {
return NULL;
}
-const User* FakeUserManager::FindLocallyManagedUser(
- const string16& display_name) const {
- return NULL;
-}
-
-const User* FakeUserManager::FindLocallyManagedUserBySyncId(
- const std::string& sync_id) const {
- return NULL;
-}
-
const User* FakeUserManager::GetLoggedInUser() const {
return NULL;
}
@@ -179,26 +165,6 @@ std::string FakeUserManager::GetUserDisplayEmail(
return std::string();
}
-std::string FakeUserManager::GetManagedUserSyncId(
- const std::string& managed_user_id) const {
- return std::string();
-}
-
-string16 FakeUserManager::GetManagerDisplayNameForManagedUser(
- const std::string& managed_user_id) const {
- return string16();
-}
-
-std::string FakeUserManager::GetManagerUserIdForManagedUser(
- const std::string& managed_user_id) const {
- return std::string();
-}
-
-std::string FakeUserManager::GetManagerDisplayEmailForManagedUser(
- const std::string& managed_user_id) const {
- return std::string();
-}
-
bool FakeUserManager::IsCurrentUserOwner() const {
return false;
}
diff --git a/chrome/browser/chromeos/login/fake_user_manager.h b/chrome/browser/chromeos/login/fake_user_manager.h
index 0a6671b674..2423a6f26f 100644
--- a/chrome/browser/chromeos/login/fake_user_manager.h
+++ b/chrome/browser/chromeos/login/fake_user_manager.h
@@ -7,6 +7,7 @@
#include <string>
+#include "base/memory/scoped_ptr.h"
#include "chrome/browser/chromeos/login/user.h"
#include "chrome/browser/chromeos/login/user_flow.h"
#include "chrome/browser/chromeos/login/user_image.h"
@@ -14,6 +15,8 @@
namespace chromeos {
+class FakeSupervisedUserManager;
+
// Fake user manager with a barebones implementation. Users can be added
// and set as logged in, and those users can be returned.
class FakeUserManager : public UserManager {
@@ -50,27 +53,18 @@ class FakeUserManager : public UserManager {
// Not implemented.
virtual void Shutdown() OVERRIDE {}
virtual UserImageManager* GetUserImageManager() OVERRIDE;
+ virtual SupervisedUserManager* GetSupervisedUserManager() OVERRIDE;
virtual const UserList& GetLRULoggedInUsers() OVERRIDE;
virtual UserList GetUnlockUsers() const OVERRIDE;
virtual const std::string& GetOwnerEmail() OVERRIDE;
virtual void SwitchActiveUser(const std::string& email) OVERRIDE {}
virtual void SessionStarted() OVERRIDE {}
virtual void RestoreActiveSessions() OVERRIDE {}
- virtual const User* CreateLocallyManagedUserRecord(
- const std::string& manager_id,
- const std::string& local_user_id,
- const std::string& sync_user_id,
- const string16& display_name) OVERRIDE;
- virtual std::string GenerateUniqueLocallyManagedUserId() OVERRIDE;
virtual void RemoveUser(const std::string& email,
RemoveUserDelegate* delegate) OVERRIDE {}
virtual void RemoveUserFromList(const std::string& email) OVERRIDE {}
virtual bool IsKnownUser(const std::string& email) const OVERRIDE;
virtual const User* FindUser(const std::string& email) const OVERRIDE;
- virtual const User* FindLocallyManagedUser(
- const string16& display_name) const OVERRIDE;
- virtual const User* FindLocallyManagedUserBySyncId(
- const std::string& sync_id) const OVERRIDE;
virtual const User* GetLoggedInUser() const OVERRIDE;
virtual User* GetLoggedInUser() OVERRIDE;
virtual const User* GetPrimaryUser() const OVERRIDE;
@@ -84,14 +78,6 @@ class FakeUserManager : public UserManager {
const std::string& display_email) OVERRIDE {}
virtual std::string GetUserDisplayEmail(
const std::string& username) const OVERRIDE;
- virtual std::string GetManagedUserSyncId(
- const std::string& managed_user_id) const OVERRIDE;
- virtual string16 GetManagerDisplayNameForManagedUser(
- const std::string& managed_user_id) const OVERRIDE;
- virtual std::string GetManagerUserIdForManagedUser(
- const std::string& managed_user_id) const OVERRIDE;
- virtual std::string GetManagerDisplayEmailForManagedUser(
- const std::string& managed_user_id) const OVERRIDE;
virtual bool IsCurrentUserOwner() const OVERRIDE;
virtual bool IsCurrentUserNew() const OVERRIDE;
virtual bool IsCurrentUserNonCryptohomeDataEphemeral() const OVERRIDE;
@@ -109,11 +95,6 @@ class FakeUserManager : public UserManager {
virtual bool HasBrowserRestarted() const OVERRIDE;
virtual bool IsUserNonCryptohomeDataEphemeral(
const std::string& email) const OVERRIDE;
- virtual void StartLocallyManagedUserCreationTransaction(
- const string16& display_name) OVERRIDE {}
- virtual void SetLocallyManagedUserCreationTransactionUserId(
- const std::string& email) OVERRIDE {}
- virtual void CommitLocallyManagedUserCreationTransaction() OVERRIDE {}
virtual void SetUserFlow(const std::string& email, UserFlow* flow) OVERRIDE {}
virtual UserFlow* GetCurrentUserFlow() const OVERRIDE;
virtual UserFlow* GetUserFlow(const std::string& email) const OVERRIDE;
@@ -145,6 +126,7 @@ class FakeUserManager : public UserManager {
// We use this internal function for const-correctness.
User* GetActiveUserInternal() const;
+ scoped_ptr<FakeSupervisedUserManager> supervised_user_manager_;
UserList user_list_;
UserList logged_in_users_;
std::string owner_email_;
diff --git a/chrome/browser/chromeos/login/login_display_host_impl.cc b/chrome/browser/chromeos/login/login_display_host_impl.cc
index b5673dfd45..5095ad8797 100644
--- a/chrome/browser/chromeos/login/login_display_host_impl.cc
+++ b/chrome/browser/chromeos/login/login_display_host_impl.cc
@@ -10,7 +10,7 @@
#include "ash/desktop_background/user_wallpaper_delegate.h"
#include "ash/shell.h"
#include "ash/shell_window_ids.h"
-#include "ash/wm/frame_painter.h"
+#include "ash/wm/header_painter.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/debug/trace_event.h"
@@ -765,7 +765,7 @@ void LoginDisplayHostImpl::StartPostponedWebUI() {
void LoginDisplayHostImpl::InitLoginWindowAndView() {
if (login_window_)
return;
- ash::FramePainter::SetSoloWindowHeadersEnabled(false);
+ ash::HeaderPainter::SetSoloWindowHeadersEnabled(false);
views::Widget::InitParams params(
views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
@@ -808,7 +808,7 @@ void LoginDisplayHostImpl::InitLoginWindowAndView() {
void LoginDisplayHostImpl::ResetLoginWindowAndView() {
if (!login_window_)
return;
- ash::FramePainter::SetSoloWindowHeadersEnabled(true);
+ ash::HeaderPainter::SetSoloWindowHeadersEnabled(true);
login_window_->Close();
login_window_ = NULL;
login_view_ = NULL;
diff --git a/chrome/browser/chromeos/login/login_performer.cc b/chrome/browser/chromeos/login/login_performer.cc
index e8537d1f63..365704f512 100644
--- a/chrome/browser/chromeos/login/login_performer.cc
+++ b/chrome/browser/chromeos/login/login_performer.cc
@@ -90,32 +90,14 @@ void LoginPerformer::OnRetailModeLoginSuccess(
LoginStatusConsumer::OnRetailModeLoginSuccess(user_context);
}
-void LoginPerformer::OnLoginSuccess(
- const UserContext& user_context,
- bool pending_requests,
- bool using_oauth) {
+void LoginPerformer::OnLoginSuccess(const UserContext& user_context) {
content::RecordAction(UserMetricsAction("Login_Success"));
- // The value of |pending_requests| indicates:
- // 0 - New regular user, login success offline and online.
- // - or -
- // Existing regular user, login success offline and online, offline
- // authentication took longer than online authentication.
- // - or -
- // Public account user, login successful.
- // 1 - Existing regular user, login success offline only.
- UMA_HISTOGRAM_ENUMERATION("Login.SuccessReason", pending_requests, 2);
-
- VLOG(1) << "LoginSuccess hash: " << user_context.username_hash
- << ", pending_requests " << pending_requests;
+ VLOG(1) << "LoginSuccess hash: " << user_context.username_hash;
DCHECK(delegate_);
// After delegate_->OnLoginSuccess(...) is called, delegate_ releases
// LoginPerformer ownership. LP now manages it's lifetime on its own.
- DCHECK(!pending_requests);
base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
-
- delegate_->OnLoginSuccess(user_context,
- pending_requests,
- using_oauth);
+ delegate_->OnLoginSuccess(user_context);
}
void LoginPerformer::OnOffTheRecordLoginSuccess() {
diff --git a/chrome/browser/chromeos/login/login_performer.h b/chrome/browser/chromeos/login/login_performer.h
index d96ebcfd38..379a4588a0 100644
--- a/chrome/browser/chromeos/login/login_performer.h
+++ b/chrome/browser/chromeos/login/login_performer.h
@@ -54,10 +54,7 @@ class LoginPerformer : public LoginStatusConsumer,
virtual void OnLoginFailure(const LoginFailure& error) OVERRIDE;
virtual void OnRetailModeLoginSuccess(
const UserContext& user_context) OVERRIDE;
- virtual void OnLoginSuccess(
- const UserContext& user_context,
- bool pending_requests,
- bool using_oauth) OVERRIDE;
+ virtual void OnLoginSuccess(const UserContext& user_context) OVERRIDE;
virtual void OnOffTheRecordLoginSuccess() OVERRIDE;
virtual void OnPasswordChangeDetected() OVERRIDE;
diff --git a/chrome/browser/chromeos/login/login_status_consumer.cc b/chrome/browser/chromeos/login/login_status_consumer.cc
index d6db996dd4..923e54d5e7 100644
--- a/chrome/browser/chromeos/login/login_status_consumer.cc
+++ b/chrome/browser/chromeos/login/login_status_consumer.cc
@@ -9,9 +9,7 @@ namespace chromeos {
void LoginStatusConsumer::OnRetailModeLoginSuccess(
const UserContext& user_context) {
- OnLoginSuccess(user_context,
- false, // pending_requests
- false); // using_oauth
+ OnLoginSuccess(user_context);
}
void LoginStatusConsumer::OnPasswordChangeDetected() {
diff --git a/chrome/browser/chromeos/login/login_status_consumer.h b/chrome/browser/chromeos/login/login_status_consumer.h
index 9f1b14d8cd..fccbaa4af3 100644
--- a/chrome/browser/chromeos/login/login_status_consumer.h
+++ b/chrome/browser/chromeos/login/login_status_consumer.h
@@ -119,12 +119,7 @@ class LoginStatusConsumer {
// OnLoginSuccess with the magic |kRetailModeUserEMail| constant.
virtual void OnRetailModeLoginSuccess(const UserContext& user_context);
// The current login attempt has succeeded for |user_context|.
- // If |pending_requests| is false, we're totally done.
- // If it's true, we will still have some more results to report later.
- virtual void OnLoginSuccess(
- const UserContext& user_context,
- bool pending_requests,
- bool using_oauth) = 0;
+ virtual void OnLoginSuccess(const UserContext& user_context) = 0;
// The current guest login attempt has succeeded.
virtual void OnOffTheRecordLoginSuccess() {}
// The same password didn't work both online and offline.
diff --git a/chrome/browser/chromeos/login/login_utils.cc b/chrome/browser/chromeos/login/login_utils.cc
index d11cb5a65a..aaebc2513b 100644
--- a/chrome/browser/chromeos/login/login_utils.cc
+++ b/chrome/browser/chromeos/login/login_utils.cc
@@ -41,6 +41,7 @@
#include "chrome/browser/chromeos/login/parallel_authenticator.h"
#include "chrome/browser/chromeos/login/profile_auth_data.h"
#include "chrome/browser/chromeos/login/screen_locker.h"
+#include "chrome/browser/chromeos/login/supervised_user_manager.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/extensions/extension_service.h"
@@ -104,8 +105,7 @@ class LoginUtilsImpl
public base::SupportsWeakPtr<LoginUtilsImpl> {
public:
LoginUtilsImpl()
- : using_oauth_(false),
- has_web_auth_cookies_(false),
+ : has_web_auth_cookies_(false),
delegate_(NULL),
should_restore_auth_session_(false),
exit_after_session_restore_(false),
@@ -124,7 +124,6 @@ class LoginUtilsImpl
virtual void PrepareProfile(
const UserContext& user_context,
const std::string& display_email,
- bool using_oauth,
bool has_cookies,
bool has_active_session,
LoginUtils::Delegate* delegate) OVERRIDE;
@@ -193,7 +192,6 @@ class LoginUtilsImpl
void AttemptExit(Profile* profile);
UserContext user_context_;
- bool using_oauth_;
// True if the authentication profile's cookie jar should contain
// authentication cookies from the authentication extension log in flow.
@@ -315,7 +313,6 @@ void LoginUtilsImpl::DoBrowserLaunch(Profile* profile,
void LoginUtilsImpl::PrepareProfile(
const UserContext& user_context,
const std::string& display_email,
- bool using_oauth,
bool has_cookies,
bool has_active_session,
LoginUtils::Delegate* delegate) {
@@ -347,7 +344,6 @@ void LoginUtilsImpl::PrepareProfile(
user_context_ = user_context;
- using_oauth_ = using_oauth;
has_web_auth_cookies_ = has_cookies;
delegate_ = delegate;
InitSessionRestoreStrategy();
@@ -374,7 +370,8 @@ void LoginUtilsImpl::InitProfilePreferences(Profile* user_profile,
if (UserManager::Get()->IsLoggedInAsLocallyManagedUser()) {
User* active_user = UserManager::Get()->GetActiveUser();
std::string managed_user_sync_id =
- UserManager::Get()->GetManagedUserSyncId(active_user->email());
+ UserManager::Get()->GetSupervisedUserManager()->
+ GetUserSyncId(active_user->email());
// TODO(ibraaaa): Remove that when 97% of our users are using M31.
// http://crbug.com/276163
@@ -461,7 +458,7 @@ void LoginUtilsImpl::UserProfileInitialized(Profile* user_profile) {
BootTimesLoader* btl = BootTimesLoader::Get();
btl->AddLoginTimeMarker("UserProfileGotten", false);
- if (using_oauth_) {
+ if (user_context_.using_oauth) {
// Transfer proxy authentication cache, cookies (optionally) and server
// bound certs from the profile that was used for authentication. This
// profile contains cookies that auth extension should have already put in
diff --git a/chrome/browser/chromeos/login/login_utils.h b/chrome/browser/chromeos/login/login_utils.h
index b000403fd0..0e6438371e 100644
--- a/chrome/browser/chromeos/login/login_utils.h
+++ b/chrome/browser/chromeos/login/login_utils.h
@@ -70,7 +70,6 @@ class LoginUtils {
virtual void PrepareProfile(
const UserContext& user_context,
const std::string& display_email,
- bool using_oauth,
bool has_cookies,
bool has_active_session,
Delegate* delegate) = 0;
diff --git a/chrome/browser/chromeos/login/login_utils_browsertest.cc b/chrome/browser/chromeos/login/login_utils_browsertest.cc
index a182cb27dd..465b33e977 100644
--- a/chrome/browser/chromeos/login/login_utils_browsertest.cc
+++ b/chrome/browser/chromeos/login/login_utils_browsertest.cc
@@ -42,9 +42,9 @@
#include "chrome/test/base/scoped_testing_local_state.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chromeos/chromeos_switches.h"
-#include "chromeos/cryptohome/cryptohome_library.h"
#include "chromeos/cryptohome/mock_async_method_caller.h"
-#include "chromeos/dbus/mock_dbus_thread_manager_without_gmock.h"
+#include "chromeos/cryptohome/system_salt_getter.h"
+#include "chromeos/dbus/fake_dbus_thread_manager.h"
#include "chromeos/disks/disk_mount_manager.h"
#include "chromeos/disks/mock_disk_mount_manager.h"
#include "chromeos/login/login_state.h"
@@ -84,19 +84,10 @@ using ::testing::SetArgPointee;
using ::testing::_;
using content::BrowserThread;
-const char kTrue[] = "true";
-const char kFalse[] = "false";
const char kDomain[] = "domain.com";
const char kUsername[] = "user@domain.com";
-const char kMode[] = "enterprise";
const char kDeviceId[] = "100200300";
const char kUsernameOtherDomain[] = "user@other.com";
-const char kAttributeOwned[] = "enterprise.owned";
-const char kAttributeOwner[] = "enterprise.user";
-const char kAttributeConsumerKiosk[] = "consumer.app_kiosk_enabled";
-const char kAttrEnterpriseDomain[] = "enterprise.domain";
-const char kAttrEnterpriseMode[] = "enterprise.mode";
-const char kAttrEnterpriseDeviceId[] = "enterprise.device_id";
const char kOAuthTokenCookie[] = "oauth_token=1234";
@@ -213,9 +204,9 @@ class LoginUtilsTest : public testing::Test,
// DBusThreadManager should be initialized before io_thread_state_, as
// DBusThreadManager is used from chromeos::ProxyConfigServiceImpl,
// which is part of io_thread_state_.
- DBusThreadManager::InitializeForTesting(&mock_dbus_thread_manager_);
+ DBusThreadManager::InitializeForTesting(&fake_dbus_thread_manager_);
- CryptohomeLibrary::Initialize();
+ SystemSaltGetter::Initialize();
LoginState::Initialize();
EXPECT_CALL(mock_statistics_provider_, GetMachineStatistic(_, _))
@@ -279,7 +270,7 @@ class LoginUtilsTest : public testing::Test,
input_method::Shutdown();
LoginState::Shutdown();
- CryptohomeLibrary::Shutdown();
+ SystemSaltGetter::Shutdown();
// These trigger some tasks that have to run while BrowserThread::UI
// exists. Delete all the profiles before deleting the connector.
@@ -356,9 +347,7 @@ class LoginUtilsTest : public testing::Test,
FAIL() << "OnLoginFailure not expected";
}
- virtual void OnLoginSuccess(const UserContext& user_context,
- bool pending_requests,
- bool using_oauth) OVERRIDE {
+ virtual void OnLoginSuccess(const UserContext& user_context) OVERRIDE {
FAIL() << "OnLoginSuccess not expected";
}
@@ -403,8 +392,8 @@ class LoginUtilsTest : public testing::Test,
const bool kHasCookies = false;
const bool kHasActiveSession = false;
LoginUtils::Get()->PrepareProfile(
- UserContext(username, "password", std::string(), username),
- std::string(), kUsingOAuth, kHasCookies, kHasActiveSession, this);
+ UserContext(username, "password", std::string(), username, kUsingOAuth),
+ std::string(), kHasCookies, kHasActiveSession, this);
device_settings_test_helper.Flush();
RunUntilIdle();
@@ -478,7 +467,7 @@ class LoginUtilsTest : public testing::Test,
scoped_ptr<content::TestBrowserThread> io_thread_;
scoped_ptr<IOThread> io_thread_state_;
- MockDBusThreadManagerWithoutGMock mock_dbus_thread_manager_;
+ FakeDBusThreadManager fake_dbus_thread_manager_;
input_method::MockInputMethodManager* mock_input_method_manager_;
disks::MockDiskMountManager mock_disk_mount_manager_;
net::TestURLFetcherFactory test_url_fetcher_factory_;
@@ -489,7 +478,7 @@ class LoginUtilsTest : public testing::Test,
policy::BrowserPolicyConnector* connector_;
- // Initialized after |mock_dbus_thread_manager_| is set up.
+ // Initialized after |fake_dbus_thread_manager_| is set up.
scoped_ptr<ScopedTestDeviceSettingsService> test_device_settings_service_;
scoped_ptr<ScopedTestCrosSettings> test_cros_settings_;
scoped_ptr<ScopedTestUserManager> test_user_manager_;
diff --git a/chrome/browser/chromeos/login/managed/locally_managed_user_creation_controller.cc b/chrome/browser/chromeos/login/managed/locally_managed_user_creation_controller.cc
index 9ed61d1964..f8fc7aff08 100644
--- a/chrome/browser/chromeos/login/managed/locally_managed_user_creation_controller.cc
+++ b/chrome/browser/chromeos/login/managed/locally_managed_user_creation_controller.cc
@@ -15,6 +15,7 @@
#include "base/values.h"
#include "chrome/browser/chromeos/login/managed/locally_managed_user_constants.h"
#include "chrome/browser/chromeos/login/mount_manager.h"
+#include "chrome/browser/chromeos/login/supervised_user_manager.h"
#include "chrome/browser/chromeos/login/user.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/lifetime/application_lifetime.h"
@@ -31,7 +32,6 @@ namespace chromeos {
namespace {
-const int kDummyAvatarIndex = -111;
const int kMasterKeySize = 32;
const int kUserCreationTimeoutSeconds = 30; // 30 seconds.
@@ -48,11 +48,16 @@ bool StoreManagedUserFiles(const std::string& token,
} // namespace
+// static
+const int LocallyManagedUserCreationController::kDummyAvatarIndex = -111;
+
LocallyManagedUserCreationController::StatusConsumer::~StatusConsumer() {}
LocallyManagedUserCreationController::UserCreationContext::UserCreationContext()
- : token_acquired(false),
+ : avatar_index(kDummyAvatarIndex),
+ token_acquired(false),
token_succesfully_written(false),
+ creation_type(NEW_USER),
manager_profile(NULL) {}
LocallyManagedUserCreationController::UserCreationContext::
@@ -78,11 +83,30 @@ LocallyManagedUserCreationController::~LocallyManagedUserCreationController() {
current_controller_ = NULL;
}
-void LocallyManagedUserCreationController::SetUpCreation(string16 display_name,
- std::string password) {
+void LocallyManagedUserCreationController::SetUpCreation(
+ const string16& display_name,
+ const std::string& password,
+ int avatar_index) {
DCHECK(creation_context_);
creation_context_->display_name = display_name;
creation_context_->password = password;
+ creation_context_->avatar_index = avatar_index;
+}
+
+void LocallyManagedUserCreationController::StartImport(
+ const string16& display_name,
+ const std::string& password,
+ int avatar_index,
+ const std::string& sync_id,
+ const std::string& master_key) {
+ DCHECK(creation_context_);
+ creation_context_->creation_type = USER_IMPORT;
+ creation_context_->display_name = display_name;
+ creation_context_->password = password;
+ creation_context_->avatar_index = avatar_index;
+ creation_context_->sync_user_id = sync_id;
+ creation_context_->master_key = master_key;
+ StartCreation();
}
void LocallyManagedUserCreationController::SetManagerProfile(
@@ -107,23 +131,24 @@ void LocallyManagedUserCreationController::StartCreation() {
FROM_HERE, base::TimeDelta::FromSeconds(kUserCreationTimeoutSeconds),
this,
&LocallyManagedUserCreationController::CreationTimedOut);
+ SupervisedUserManager* manager =
+ UserManager::Get()->GetSupervisedUserManager();
+ manager->StartCreationTransaction(creation_context_->display_name);
- UserManager::Get()->StartLocallyManagedUserCreationTransaction(
- creation_context_->display_name);
+ creation_context_->local_user_id = manager->GenerateUserId();
- creation_context_->local_user_id =
- UserManager::Get()->GenerateUniqueLocallyManagedUserId();
- creation_context_->sync_user_id =
- ManagedUserRegistrationUtility::GenerateNewManagedUserId();
+ if (creation_context_->creation_type == NEW_USER) {
+ creation_context_->sync_user_id =
+ ManagedUserRegistrationUtility::GenerateNewManagedUserId();
+ }
- UserManager::Get()->CreateLocallyManagedUserRecord(
+ manager->CreateUserRecord(
creation_context_->manager_id,
creation_context_->local_user_id,
creation_context_->sync_user_id,
creation_context_->display_name);
- UserManager::Get()->SetLocallyManagedUserCreationTransactionUserId(
- creation_context_->local_user_id);
+ manager->SetCreationTransactionUserId(creation_context_->local_user_id);
VLOG(1) << "Creating cryptohome";
authenticator_ = new ManagedUserAuthenticator(this);
authenticator_->AuthenticateToCreate(creation_context_->local_user_id,
@@ -155,12 +180,15 @@ void LocallyManagedUserCreationController::OnMountSuccess(
const std::string& mount_hash) {
creation_context_->mount_hash = mount_hash;
- // Generate master password.
- char master_key_bytes[kMasterKeySize];
- crypto::RandBytes(&master_key_bytes, sizeof(master_key_bytes));
- creation_context_->master_key = StringToLowerASCII(base::HexEncode(
- reinterpret_cast<const void*>(master_key_bytes),
- sizeof(master_key_bytes)));
+ if (creation_context_->creation_type == NEW_USER) {
+ // Generate master password.
+ char master_key_bytes[kMasterKeySize];
+ crypto::RandBytes(&master_key_bytes, sizeof(master_key_bytes));
+ creation_context_->master_key = StringToLowerASCII(base::HexEncode(
+ reinterpret_cast<const void*>(master_key_bytes),
+ sizeof(master_key_bytes)));
+ }
+
VLOG(1) << "Adding master key";
authenticator_->AddMasterKey(creation_context_->local_user_id,
creation_context_->password,
@@ -174,7 +202,7 @@ void LocallyManagedUserCreationController::OnAddKeySuccess() {
VLOG(1) << "Creating user on server";
ManagedUserRegistrationInfo info(creation_context_->display_name,
- kDummyAvatarIndex);
+ creation_context_->avatar_index);
info.master_key = creation_context_->master_key;
timeout_timer_.Stop();
creation_context_->registration_utility->Register(
@@ -252,7 +280,8 @@ void LocallyManagedUserCreationController::OnManagedUserFilesStored(
// sync service fails to use it.
UserManager::Get()->SaveUserOAuthStatus(creation_context_->local_user_id,
User::OAUTH2_TOKEN_STATUS_VALID);
- UserManager::Get()->CommitLocallyManagedUserCreationTransaction();
+ UserManager::Get()->GetSupervisedUserManager()->
+ CommitCreationTransaction();
if (consumer_)
consumer_->OnCreationSuccess();
}
diff --git a/chrome/browser/chromeos/login/managed/locally_managed_user_creation_controller.h b/chrome/browser/chromeos/login/managed/locally_managed_user_creation_controller.h
index 1793092229..ce50959235 100644
--- a/chrome/browser/chromeos/login/managed/locally_managed_user_creation_controller.h
+++ b/chrome/browser/chromeos/login/managed/locally_managed_user_creation_controller.h
@@ -34,6 +34,11 @@ namespace chromeos {
class LocallyManagedUserCreationController
: public ManagedUserAuthenticator::AuthStatusConsumer {
public:
+ // This constant is used to indicate that user does not have one of default
+ // avatars: either he has no chromeos avatar at all, or has an external
+ // image as an avatar.
+ static const int kDummyAvatarIndex;
+
enum ErrorCode {
NO_ERROR,
CRYPTOHOME_NO_MOUNT,
@@ -65,7 +70,21 @@ class LocallyManagedUserCreationController
return current_controller_;
}
- void SetUpCreation(string16 display_name, std::string password);
+ // Set up controller for creating new supervised user with |display_name|,
+ // |password| and avatar indexed by |avatar_index|. StartCreation() have to
+ // be called to actually start creating user.
+ void SetUpCreation(const string16& display_name,
+ const std::string& password,
+ int avatar_index);
+
+ // Configures and initiates importing existing supervised user to this device.
+ // Existing user is identified by |sync_id|, has |display_name|, |password|,
+ // |avatar_index|. The master key for cryptohome is a |master_key|.
+ void StartImport(const string16& display_name,
+ const std::string& password,
+ int avatar_index,
+ const std::string& sync_id,
+ const std::string& master_key);
void SetManagerProfile(Profile* manager_profile);
void StartCreation();
void CancelCreation();
@@ -73,12 +92,19 @@ class LocallyManagedUserCreationController
std::string GetManagedUserId();
private:
+ // Indicates if we create new user, or import an existing one.
+ enum CreationType {
+ NEW_USER,
+ USER_IMPORT,
+ };
+
// Contains information necessary for new user creation.
struct UserCreationContext {
UserCreationContext();
~UserCreationContext();
string16 display_name;
+ int avatar_index;
std::string manager_id;
std::string local_user_id; // Used to identify cryptohome.
std::string sync_user_id; // Used to identify user in manager's sync data.
@@ -88,6 +114,7 @@ class LocallyManagedUserCreationController
bool token_acquired;
std::string token;
bool token_succesfully_written;
+ CreationType creation_type;
Profile* manager_profile;
scoped_ptr<ManagedUserRegistrationUtility> registration_utility;
};
diff --git a/chrome/browser/chromeos/login/managed/locally_managed_user_creation_screen.cc b/chrome/browser/chromeos/login/managed/locally_managed_user_creation_screen.cc
index d683060132..043a53678e 100644
--- a/chrome/browser/chromeos/login/managed/locally_managed_user_creation_screen.cc
+++ b/chrome/browser/chromeos/login/managed/locally_managed_user_creation_screen.cc
@@ -6,15 +6,21 @@
#include "ash/desktop_background/desktop_background_controller.h"
#include "ash/shell.h"
+#include "base/command_line.h"
+#include "base/rand_util.h"
#include "base/values.h"
#include "chrome/browser/chromeos/camera_detector.h"
#include "chrome/browser/chromeos/login/existing_user_controller.h"
#include "chrome/browser/chromeos/login/managed/locally_managed_user_creation_controller.h"
#include "chrome/browser/chromeos/login/screens/error_screen.h"
#include "chrome/browser/chromeos/login/screens/screen_observer.h"
+#include "chrome/browser/chromeos/login/supervised_user_manager.h"
#include "chrome/browser/chromeos/login/user_image.h"
#include "chrome/browser/chromeos/login/user_image_manager.h"
#include "chrome/browser/chromeos/login/wizard_controller.h"
+#include "chrome/browser/managed_mode/managed_user_sync_service.h"
+#include "chrome/browser/managed_mode/managed_user_sync_service_factory.h"
+#include "chrome/common/chrome_switches.h"
#include "chromeos/network/network_state.h"
#include "content/public/browser/browser_thread.h"
#include "grit/generated_resources.h"
@@ -26,6 +32,17 @@ namespace chromeos {
namespace {
+// Key for (boolean) value that indicates that user already exists on device.
+const char kUserExists[] = "exists";
+// Key for value that indicates why user can not be imported.
+const char kUserConflict[] = "conflict";
+// User is already imported.
+const char kUserConflictImported[] = "imported";
+// There is another supervised user with same name.
+const char kUserConflictName[] = "name";
+
+const char kAvatarURLKey[] = "avatarurl";
+const char kRandomAvatarKey[] = "randomAvatar";
const char kNameOfIntroScreen[] = "intro";
const char kNameOfNewUserParametersScreen[] = "username";
@@ -79,6 +96,7 @@ LocallyManagedUserCreationScreen::~LocallyManagedUserCreationScreen() {
actor_->SetDelegate(NULL);
if (image_decoder_.get())
image_decoder_->set_delegate(NULL);
+ NetworkPortalDetector::Get()->RemoveObserver(this);
}
void LocallyManagedUserCreationScreen::PrepareToShow() {
@@ -97,9 +115,8 @@ void LocallyManagedUserCreationScreen::Show() {
actor_->ShowIntroPage();
}
- NetworkPortalDetector* detector = NetworkPortalDetector::GetInstance();
- if (detector && !on_error_screen_)
- detector->AddAndFireObserver(this);
+ if (!on_error_screen_)
+ NetworkPortalDetector::Get()->AddAndFireObserver(this);
on_error_screen_ = false;
}
@@ -142,9 +159,8 @@ void LocallyManagedUserCreationScreen::ShowInitialScreen() {
void LocallyManagedUserCreationScreen::Hide() {
if (actor_)
actor_->Hide();
- NetworkPortalDetector* detector = NetworkPortalDetector::GetInstance();
- if (detector && !on_error_screen_)
- detector->RemoveObserver(this);
+ if (!on_error_screen_)
+ NetworkPortalDetector::Get()->RemoveObserver(this);
}
std::string LocallyManagedUserCreationScreen::GetName() const {
@@ -176,10 +192,57 @@ void LocallyManagedUserCreationScreen::CreateManagedUser(
const string16& display_name,
const std::string& managed_user_password) {
DCHECK(controller_.get());
- controller_->SetUpCreation(display_name, managed_user_password);
+ int image;
+ if (selected_image_ == User::kExternalImageIndex)
+ // TODO(dzhioev): crbug/249660
+ image = LocallyManagedUserCreationController::kDummyAvatarIndex;
+ else
+ image = selected_image_;
+ controller_->SetUpCreation(display_name, managed_user_password, image);
controller_->StartCreation();
}
+void LocallyManagedUserCreationScreen::ImportManagedUser(
+ const std::string& user_id) {
+ DCHECK(controller_.get());
+ DCHECK(existing_users_.get());
+ VLOG(1) << "Importing user " << user_id;
+ DictionaryValue* user_info;
+ if (!existing_users_->GetDictionary(user_id, &user_info)) {
+ LOG(ERROR) << "Can not import non-existing user " << user_id;
+ return;
+ }
+ string16 display_name;
+ std::string master_key;
+ std::string avatar;
+ bool exists;
+ int avatar_index = LocallyManagedUserCreationController::kDummyAvatarIndex;
+ user_info->GetString(ManagedUserSyncService::kName, &display_name);
+ user_info->GetString(ManagedUserSyncService::kMasterKey, &master_key);
+ user_info->GetString(ManagedUserSyncService::kChromeOsAvatar, &avatar);
+ user_info->GetBoolean(kUserExists, &exists);
+
+ // We should not get here with existing user selected, so just display error.
+ if (exists) {
+ actor_->ShowErrorPage(
+ l10n_util::GetStringUTF16(
+ IDS_CREATE_LOCALLY_MANAGED_USER_GENERIC_ERROR_TITLE),
+ l10n_util::GetStringUTF16(
+ IDS_CREATE_LOCALLY_MANAGED_USER_GENERIC_ERROR),
+ l10n_util::GetStringUTF16(
+ IDS_CREATE_LOCALLY_MANAGED_USER_GENERIC_ERROR_BUTTON));
+ return;
+ }
+
+ ManagedUserSyncService::GetAvatarIndex(avatar, &avatar_index);
+
+ controller_->StartImport(display_name,
+ std::string(),
+ avatar_index,
+ user_id,
+ master_key);
+}
+
void LocallyManagedUserCreationScreen::OnManagerLoginFailure() {
if (actor_)
actor_->ShowManagerPasswordError();
@@ -196,7 +259,17 @@ void LocallyManagedUserCreationScreen::OnManagerFullyAuthenticated(
controller_->SetManagerProfile(manager_profile);
if (actor_)
actor_->ShowUsernamePage();
+
last_page_ = kNameOfNewUserParametersScreen;
+
+ CommandLine* command_line = CommandLine::ForCurrentProcess();
+ if (!command_line->HasSwitch(::switches::kAllowCreateExistingManagedUsers))
+ return;
+
+ ManagedUserSyncServiceFactory::GetForProfile(manager_profile)->
+ GetManagedUsersAsync(base::Bind(
+ &LocallyManagedUserCreationScreen::OnGetManagedUsers,
+ weak_factory_.GetWeakPtr()));
}
void LocallyManagedUserCreationScreen::OnManagerCryptohomeAuthenticated() {
@@ -260,6 +333,28 @@ void LocallyManagedUserCreationScreen::OnLongCreationWarning() {
}
}
+bool LocallyManagedUserCreationScreen::FindUserByDisplayName(
+ const string16& display_name,
+ std::string *out_id) const {
+ if (!existing_users_.get())
+ return false;
+ for (base::DictionaryValue::Iterator it(*existing_users_.get());
+ !it.IsAtEnd(); it.Advance()) {
+ const base::DictionaryValue* user_info =
+ static_cast<const base::DictionaryValue*>(&it.value());
+ string16 user_display_name;
+ if (user_info->GetString(ManagedUserSyncService::kName,
+ &user_display_name)) {
+ if (display_name == user_display_name) {
+ if (out_id)
+ *out_id = it.key();
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
// TODO(antrim) : this is an explicit code duplications with UserImageScreen.
// It should be removed by issue 251179.
@@ -306,6 +401,68 @@ void LocallyManagedUserCreationScreen::OnCameraPresenceCheckDone() {
}
}
+void LocallyManagedUserCreationScreen::OnGetManagedUsers(
+ const base::DictionaryValue* users) {
+ // Copy for passing to WebUI, contains only id, name and avatar URL.
+ scoped_ptr<base::ListValue> ui_users(new base::ListValue());
+ SupervisedUserManager* supervised_user_manager =
+ UserManager::Get()->GetSupervisedUserManager();
+
+ // Stored copy, contains all necessary information.
+ existing_users_.reset(new base::DictionaryValue());
+ for (base::DictionaryValue::Iterator it(*users); !it.IsAtEnd();
+ it.Advance()) {
+ // Copy that would be stored in this class.
+ base::DictionaryValue* local_copy =
+ static_cast<base::DictionaryValue*>(it.value().DeepCopy());
+ // Copy that would be passed to WebUI. It has some extra values for
+ // displaying, but does not contain sensitive data, such as master password.
+ base::DictionaryValue* ui_copy =
+ static_cast<base::DictionaryValue*>(new base::DictionaryValue());
+
+ int avatar_index = LocallyManagedUserCreationController::kDummyAvatarIndex;
+ std::string chromeos_avatar;
+ if (local_copy->GetString(ManagedUserSyncService::kChromeOsAvatar,
+ &chromeos_avatar) &&
+ !chromeos_avatar.empty() &&
+ ManagedUserSyncService::GetAvatarIndex(
+ chromeos_avatar, &avatar_index)) {
+ ui_copy->SetString(kAvatarURLKey, GetDefaultImageUrl(avatar_index));
+ } else {
+ int i = base::RandInt(kFirstDefaultImageIndex, kDefaultImagesCount - 1);
+ local_copy->SetString(
+ ManagedUserSyncService::kChromeOsAvatar,
+ ManagedUserSyncService::BuildAvatarString(i));
+ local_copy->SetBoolean(kRandomAvatarKey, true);
+ ui_copy->SetString(kAvatarURLKey, GetDefaultImageUrl(i));
+ }
+
+ local_copy->SetBoolean(kUserExists, false);
+ ui_copy->SetBoolean(kUserExists, false);
+
+ string16 display_name;
+ local_copy->GetString(ManagedUserSyncService::kName, &display_name);
+
+ if (supervised_user_manager->FindBySyncId(it.key())) {
+ local_copy->SetBoolean(kUserExists, true);
+ ui_copy->SetBoolean(kUserExists, true);
+ local_copy->SetString(kUserConflict, kUserConflictImported);
+ ui_copy->SetString(kUserConflict, kUserConflictImported);
+ } else if (supervised_user_manager->FindByDisplayName(display_name)) {
+ local_copy->SetBoolean(kUserExists, true);
+ ui_copy->SetBoolean(kUserExists, true);
+ local_copy->SetString(kUserConflict, kUserConflictName);
+ ui_copy->SetString(kUserConflict, kUserConflictName);
+ }
+ ui_copy->SetString(ManagedUserSyncService::kName, display_name);
+ ui_copy->SetString("id", it.key());
+
+ existing_users_->Set(it.key(), local_copy);
+ ui_users->Append(ui_copy);
+ }
+ actor_->ShowExistingManagedUsers(ui_users.get());
+}
+
void LocallyManagedUserCreationScreen::OnPhotoTaken(
const std::string& raw_data) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
diff --git a/chrome/browser/chromeos/login/managed/locally_managed_user_creation_screen.h b/chrome/browser/chromeos/login/managed/locally_managed_user_creation_screen.h
index 6e97595504..43be20b000 100644
--- a/chrome/browser/chromeos/login/managed/locally_managed_user_creation_screen.h
+++ b/chrome/browser/chromeos/login/managed/locally_managed_user_creation_screen.h
@@ -70,11 +70,14 @@ class LocallyManagedUserCreationScreen
virtual void CreateManagedUser(
const string16& display_name,
const std::string& managed_user_password) OVERRIDE;
+ virtual void ImportManagedUser(const std::string& user_id) OVERRIDE;
virtual void AuthenticateManager(
const std::string& manager_id,
const std::string& manager_password) OVERRIDE;
virtual void AbortFlow() OVERRIDE;
virtual void FinishFlow() OVERRIDE;
+ virtual bool FindUserByDisplayName(const string16& display_name,
+ std::string *out_id) const OVERRIDE;
virtual void OnPageSelected(const std::string& page) OVERRIDE;
// LocallyManagedUserController::StatusConsumer overrides.
@@ -106,11 +109,13 @@ class LocallyManagedUserCreationScreen
private:
void ApplyPicture();
void OnCameraPresenceCheckDone();
+ void OnGetManagedUsers(const base::DictionaryValue* users);
base::WeakPtrFactory<LocallyManagedUserCreationScreen> weak_factory_;
LocallyManagedUserCreationScreenHandler* actor_;
scoped_ptr<LocallyManagedUserCreationController> controller_;
+ scoped_ptr<base::DictionaryValue> existing_users_;
bool on_error_screen_;
std::string last_page_;
diff --git a/chrome/browser/chromeos/login/managed/managed_user_authenticator.cc b/chrome/browser/chromeos/login/managed/managed_user_authenticator.cc
index fa4363cb93..5fae224d67 100644
--- a/chrome/browser/chromeos/login/managed/managed_user_authenticator.cc
+++ b/chrome/browser/chromeos/login/managed/managed_user_authenticator.cc
@@ -10,7 +10,7 @@
#include "chrome/browser/chromeos/boot_times_loader.h"
#include "chrome/browser/chromeos/login/parallel_authenticator.h"
#include "chromeos/cryptohome/async_method_caller.h"
-#include "chromeos/cryptohome/cryptohome_library.h"
+#include "chromeos/cryptohome/system_salt_getter.h"
#include "chromeos/dbus/cryptohome_client.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "content/public/browser/browser_thread.h"
@@ -24,9 +24,6 @@ namespace chromeos {
namespace {
-// Milliseconds until we timeout our attempt to hit ClientLogin.
-const int kClientLoginTimeoutMs = 10000;
-
// Records status and calls resolver->Resolve().
void TriggerResolve(ManagedUserAuthenticator::AuthAttempt* attempt,
scoped_refptr<ManagedUserAuthenticator> resolver,
@@ -111,7 +108,7 @@ void ManagedUserAuthenticator::AuthenticateToMount(
current_state_.reset(new ManagedUserAuthenticator::AuthAttempt(
canonicalized, password, false));
- CryptohomeLibrary::Get()->GetSystemSalt(
+ SystemSaltGetter::Get()->GetSystemSalt(
base::Bind(&Mount,
current_state_.get(),
scoped_refptr<ManagedUserAuthenticator>(this),
@@ -126,7 +123,7 @@ void ManagedUserAuthenticator::AuthenticateToCreate(
current_state_.reset(new ManagedUserAuthenticator::AuthAttempt(
canonicalized, password, false));
- CryptohomeLibrary::Get()->GetSystemSalt(
+ SystemSaltGetter::Get()->GetSystemSalt(
base::Bind(&Mount,
current_state_.get(),
scoped_refptr<ManagedUserAuthenticator>(this),
@@ -142,7 +139,7 @@ void ManagedUserAuthenticator::AddMasterKey(
current_state_.reset(new ManagedUserAuthenticator::AuthAttempt(
canonicalized, password, true));
- CryptohomeLibrary::Get()->GetSystemSalt(
+ SystemSaltGetter::Get()->GetSystemSalt(
base::Bind(&AddKey,
current_state_.get(),
scoped_refptr<ManagedUserAuthenticator>(this),
diff --git a/chrome/browser/chromeos/login/managed/supervised_user_creation_browsertest.cc b/chrome/browser/chromeos/login/managed/supervised_user_creation_browsertest.cc
index 4d3aade154..def99d6198 100644
--- a/chrome/browser/chromeos/login/managed/supervised_user_creation_browsertest.cc
+++ b/chrome/browser/chromeos/login/managed/supervised_user_creation_browsertest.cc
@@ -15,7 +15,7 @@
#include "chrome/browser/chromeos/login/login_manager_test.h"
#include "chrome/browser/chromeos/login/startup_utils.h"
#include "chrome/browser/chromeos/login/webui_login_view.h"
-#include "chrome/browser/chromeos/net/network_portal_detector_stub.h"
+#include "chrome/browser/chromeos/net/network_portal_detector_test_impl.h"
#include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h"
#include "chrome/browser/managed_mode/managed_user_registration_utility.h"
#include "chrome/browser/managed_mode/managed_user_registration_utility_stub.h"
@@ -46,7 +46,7 @@ class SupervisedUserTest : public chromeos::LoginManagerTest {
protected:
SupervisedUserTest() : LoginManagerTest(true),
mock_async_method_caller_(NULL),
- network_portal_detector_stub_(NULL),
+ network_portal_detector_(NULL),
registration_utility_stub_(NULL) {
}
@@ -70,15 +70,14 @@ class SupervisedUserTest : public chromeos::LoginManagerTest {
// Setup network portal detector to return online state for both
// ethernet and wifi networks. Ethernet is an active network by
// default.
- network_portal_detector_stub_ =
- static_cast<NetworkPortalDetectorStub*>(
- NetworkPortalDetector::GetInstance());
+ network_portal_detector_ = new NetworkPortalDetectorTestImpl();
+ NetworkPortalDetector::InitializeForTesting(network_portal_detector_);
NetworkPortalDetector::CaptivePortalState online_state;
online_state.status = NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE;
online_state.response_code = 204;
- network_portal_detector_stub_->SetDefaultNetworkPathForTesting(
+ network_portal_detector_->SetDefaultNetworkPathForTesting(
kStubEthernetServicePath);
- network_portal_detector_stub_->SetDetectionResultsForTesting(
+ network_portal_detector_->SetDetectionResultsForTesting(
kStubEthernetServicePath, online_state);
}
@@ -93,6 +92,10 @@ class SupervisedUserTest : public chromeos::LoginManagerTest {
LoginManagerTest::TearDown();
}
+ virtual void TearDownInProcessBrowserTestFixture() OVERRIDE {
+ NetworkPortalDetector::Shutdown();
+ }
+
void JSEval(const std::string& script) {
EXPECT_TRUE(content::ExecuteScript(web_contents(), script));
}
@@ -126,7 +129,7 @@ class SupervisedUserTest : public chromeos::LoginManagerTest {
protected:
cryptohome::MockAsyncMethodCaller* mock_async_method_caller_;
- NetworkPortalDetectorStub* network_portal_detector_stub_;
+ NetworkPortalDetectorTestImpl* network_portal_detector_;
ManagedUserRegistrationUtilityStub* registration_utility_stub_;
scoped_ptr<ScopedTestingManagedUserRegistrationUtility> scoped_utility_;
diff --git a/chrome/browser/chromeos/login/mock_authenticator.cc b/chrome/browser/chromeos/login/mock_authenticator.cc
index da3b14159e..696db2c344 100644
--- a/chrome/browser/chromeos/login/mock_authenticator.cc
+++ b/chrome/browser/chromeos/login/mock_authenticator.cc
@@ -17,7 +17,7 @@ void MockAuthenticator::AuthenticateToLogin(Profile* profile,
if (expected_username_ == user_context.username &&
expected_password_ == user_context.password) {
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(&MockAuthenticator::OnLoginSuccess, this, false));
+ base::Bind(&MockAuthenticator::OnLoginSuccess, this));
return;
}
GoogleServiceAuthError error(
@@ -31,7 +31,7 @@ void MockAuthenticator::CompleteLogin(Profile* profile,
const UserContext& user_context) {
CHECK_EQ(expected_username_, user_context.username);
CHECK_EQ(expected_password_, user_context.password);
- OnLoginSuccess(false);
+ OnLoginSuccess();
}
void MockAuthenticator::AuthenticateToUnlock(
@@ -44,9 +44,7 @@ void MockAuthenticator::LoginAsLocallyManagedUser(
consumer_->OnLoginSuccess(UserContext(expected_username_,
std::string(),
std::string(),
- user_context.username), // username_hash
- false,
- false);
+ user_context.username)); // hash
}
void MockAuthenticator::LoginRetailMode() {
@@ -60,9 +58,7 @@ void MockAuthenticator::LoginAsPublicAccount(const std::string& username) {
consumer_->OnLoginSuccess(UserContext(expected_username_,
std::string(),
std::string(),
- expected_username_),
- false,
- false);
+ expected_username_));
}
void MockAuthenticator::LoginAsKioskAccount(
@@ -70,9 +66,7 @@ void MockAuthenticator::LoginAsKioskAccount(
consumer_->OnLoginSuccess(UserContext(expected_username_,
std::string(),
std::string(),
- expected_username_),
- false,
- false);
+ expected_username_));
}
void MockAuthenticator::LoginOffTheRecord() {
@@ -86,15 +80,13 @@ void MockAuthenticator::OnRetailModeLoginSuccess() {
expected_username_));
}
-void MockAuthenticator::OnLoginSuccess(bool request_pending) {
+void MockAuthenticator::OnLoginSuccess() {
// If we want to be more like the real thing, we could save username
// in AuthenticateToLogin, but there's not much of a point.
consumer_->OnLoginSuccess(UserContext(expected_username_,
expected_password_,
std::string(),
- expected_username_),
- request_pending,
- false);
+ expected_username_));
}
void MockAuthenticator::OnLoginFailure(const LoginFailure& failure) {
diff --git a/chrome/browser/chromeos/login/mock_authenticator.h b/chrome/browser/chromeos/login/mock_authenticator.h
index e810bcf0df..12e22e44a3 100644
--- a/chrome/browser/chromeos/login/mock_authenticator.h
+++ b/chrome/browser/chromeos/login/mock_authenticator.h
@@ -43,7 +43,7 @@ class MockAuthenticator : public Authenticator {
virtual void OnRetailModeLoginSuccess() OVERRIDE;
- virtual void OnLoginSuccess(bool request_pending) OVERRIDE;
+ virtual void OnLoginSuccess() OVERRIDE;
virtual void OnLoginFailure(const LoginFailure& failure) OVERRIDE;
diff --git a/chrome/browser/chromeos/login/mock_login_status_consumer.cc b/chrome/browser/chromeos/login/mock_login_status_consumer.cc
index 6b666c8403..f648cd019b 100644
--- a/chrome/browser/chromeos/login/mock_login_status_consumer.cc
+++ b/chrome/browser/chromeos/login/mock_login_status_consumer.cc
@@ -39,18 +39,12 @@ void MockConsumer::OnGuestSuccessQuitAndFail() {
}
// static
-void MockConsumer::OnSuccessQuit(
- const UserContext& user_context,
- bool pending_requests,
- bool using_oauth) {
+void MockConsumer::OnSuccessQuit(const UserContext& user_context) {
base::MessageLoop::current()->Quit();
}
// static
-void MockConsumer::OnSuccessQuitAndFail(
- const UserContext& user_context,
- bool pending_requests,
- bool using_oauth) {
+void MockConsumer::OnSuccessQuitAndFail(const UserContext& user_context) {
ADD_FAILURE() << "Login should NOT have succeeded!";
base::MessageLoop::current()->Quit();
}
diff --git a/chrome/browser/chromeos/login/mock_login_status_consumer.h b/chrome/browser/chromeos/login/mock_login_status_consumer.h
index 1c0237b723..1ef80dc307 100644
--- a/chrome/browser/chromeos/login/mock_login_status_consumer.h
+++ b/chrome/browser/chromeos/login/mock_login_status_consumer.h
@@ -19,10 +19,7 @@ class MockConsumer : public LoginStatusConsumer {
MOCK_METHOD1(OnLoginFailure, void(const LoginFailure& error));
MOCK_METHOD1(OnRetailModeLoginSuccess, void(
const UserContext& user_context));
- MOCK_METHOD3(OnLoginSuccess, void(
- const UserContext& user_context,
- bool pending_requests,
- bool using_oauth));
+ MOCK_METHOD1(OnLoginSuccess, void(const UserContext& user_context));
MOCK_METHOD0(OnOffTheRecordLoginSuccess, void(void));
MOCK_METHOD0(OnPasswordChangeDetected, void(void));
@@ -38,14 +35,8 @@ class MockConsumer : public LoginStatusConsumer {
static void OnGuestSuccessQuitAndFail();
// Compatible with LoginStatusConsumer::OnLoginSuccess()
- static void OnSuccessQuit(
- const UserContext& user_context,
- bool pending_requests,
- bool using_oauth);
- static void OnSuccessQuitAndFail(
- const UserContext& user_context,
- bool pending_requests,
- bool using_oauth);
+ static void OnSuccessQuit(const UserContext& user_context);
+ static void OnSuccessQuitAndFail(const UserContext& user_context);
// Compatible with LoginStatusConsumer::OnLoginFailure()
static void OnFailQuit(const LoginFailure& error);
diff --git a/chrome/browser/chromeos/login/mock_login_utils.cc b/chrome/browser/chromeos/login/mock_login_utils.cc
index cb28297d13..1adc516177 100644
--- a/chrome/browser/chromeos/login/mock_login_utils.cc
+++ b/chrome/browser/chromeos/login/mock_login_utils.cc
@@ -19,7 +19,7 @@ void MockLoginUtils::DelegateToFake() {
FakeLoginUtils* fake = fake_login_utils_.get();
ON_CALL(*this, DoBrowserLaunch(_, _))
.WillByDefault(Invoke(fake, &FakeLoginUtils::DoBrowserLaunch));
- ON_CALL(*this, PrepareProfile(_, _, _, _, _, _))
+ ON_CALL(*this, PrepareProfile(_, _, _, _, _))
.WillByDefault(Invoke(fake, &FakeLoginUtils::PrepareProfile));
ON_CALL(*this, CreateAuthenticator(_))
.WillByDefault(Invoke(fake, &FakeLoginUtils::CreateAuthenticator));
diff --git a/chrome/browser/chromeos/login/mock_login_utils.h b/chrome/browser/chromeos/login/mock_login_utils.h
index c01726e36d..269ac493af 100644
--- a/chrome/browser/chromeos/login/mock_login_utils.h
+++ b/chrome/browser/chromeos/login/mock_login_utils.h
@@ -31,9 +31,9 @@ class MockLoginUtils : public LoginUtils {
virtual ~MockLoginUtils();
MOCK_METHOD2(DoBrowserLaunch, void(Profile*, LoginDisplayHost*));
- MOCK_METHOD6(PrepareProfile,
+ MOCK_METHOD5(PrepareProfile,
void(const UserContext&, const std::string&,
- bool, bool, bool, LoginUtils::Delegate*));
+ bool, bool, LoginUtils::Delegate*));
MOCK_METHOD1(DelegateDeleted, void(LoginUtils::Delegate*));
MOCK_METHOD1(CompleteOffTheRecordLogin, void(const GURL&));
MOCK_METHOD1(SetFirstLoginPrefs, void(PrefService*));
diff --git a/chrome/browser/chromeos/login/mock_user_manager.cc b/chrome/browser/chromeos/login/mock_user_manager.cc
index dc4af28438..59bb2737e3 100644
--- a/chrome/browser/chromeos/login/mock_user_manager.cc
+++ b/chrome/browser/chromeos/login/mock_user_manager.cc
@@ -4,10 +4,14 @@
#include "chrome/browser/chromeos/login/mock_user_manager.h"
+#include "chrome/browser/chromeos/login/fake_supervised_user_manager.h"
+
namespace chromeos {
-MockUserManager::MockUserManager() : user_(NULL),
- user_flow_(new DefaultUserFlow()) {}
+MockUserManager::MockUserManager()
+ : user_(NULL),
+ user_flow_(new DefaultUserFlow()),
+ supervised_user_manager_(new FakeSupervisedUserManager()) {}
MockUserManager::~MockUserManager() {
delete user_;
@@ -53,6 +57,10 @@ UserImageManager* MockUserManager::GetUserImageManager() {
return user_image_manager_.get();
}
+SupervisedUserManager* MockUserManager::GetSupervisedUserManager() {
+ return supervised_user_manager_.get();
+}
+
// Creates a new User instance.
void MockUserManager::SetActiveUser(const std::string& email) {
delete user_;
diff --git a/chrome/browser/chromeos/login/mock_user_manager.h b/chrome/browser/chromeos/login/mock_user_manager.h
index dc1c2e6f3b..eb3710c39e 100644
--- a/chrome/browser/chromeos/login/mock_user_manager.h
+++ b/chrome/browser/chromeos/login/mock_user_manager.h
@@ -18,6 +18,8 @@
namespace chromeos {
+class FakeSupervisedUserManager;
+
class MockUserManager : public UserManager {
public:
MockUserManager();
@@ -36,9 +38,6 @@ class MockUserManager : public UserManager {
MOCK_METHOD1(RemoveUserFromList, void(const std::string&));
MOCK_CONST_METHOD1(IsKnownUser, bool(const std::string&));
MOCK_CONST_METHOD1(FindUser, const User*(const std::string&));
- MOCK_CONST_METHOD1(FindLocallyManagedUser, const User*(const string16&));
- MOCK_CONST_METHOD1(FindLocallyManagedUserBySyncId,
- const User*(const std::string&));
MOCK_METHOD2(SaveUserOAuthStatus, void(const std::string&,
User::OAuthTokenStatus));
MOCK_METHOD2(SaveUserDisplayName, void(const std::string&,
@@ -75,25 +74,6 @@ class MockUserManager : public UserManager {
MOCK_METHOD0(NotifyLocalStateChanged, void(void));
MOCK_METHOD2(SetUserFlow, void(const std::string&, UserFlow*));
MOCK_METHOD1(ResetUserFlow, void(const std::string&));
- MOCK_METHOD4(CreateLocallyManagedUserRecord, const User*(
- const std::string&,
- const std::string&,
- const std::string&,
- const string16&));
- MOCK_CONST_METHOD1(GetManagedUserSyncId, std::string(
- const std::string& managed_user_id));
- MOCK_CONST_METHOD1(GetManagerDisplayNameForManagedUser, string16(
- const std::string&));
- MOCK_CONST_METHOD1(GetManagerUserIdForManagedUser, std::string(
- const std::string&));
- MOCK_CONST_METHOD1(GetManagerDisplayEmailForManagedUser, std::string(
- const std::string&));
- MOCK_METHOD0(GenerateUniqueLocallyManagedUserId, std::string(void));
- MOCK_METHOD1(StartLocallyManagedUserCreationTransaction,
- void(const string16&));
- MOCK_METHOD1(SetLocallyManagedUserCreationTransactionUserId,
- void(const std::string&));
- MOCK_METHOD0(CommitLocallyManagedUserCreationTransaction, void(void));
MOCK_METHOD2(GetAppModeChromeClientOAuthInfo, bool(std::string*,
std::string*));
@@ -116,6 +96,7 @@ class MockUserManager : public UserManager {
virtual User* GetUserByProfile(Profile* profile) const OVERRIDE;
virtual UserImageManager* GetUserImageManager() OVERRIDE;
+ virtual SupervisedUserManager* GetSupervisedUserManager() OVERRIDE;
virtual UserFlow* GetCurrentUserFlow() const OVERRIDE;
virtual UserFlow* GetUserFlow(const std::string&) const OVERRIDE;
@@ -130,8 +111,9 @@ class MockUserManager : public UserManager {
User* CreatePublicAccountUser(const std::string& email);
User* user_;
- scoped_ptr<MockUserImageManager> user_image_manager_;
scoped_ptr<UserFlow> user_flow_;
+ scoped_ptr<MockUserImageManager> user_image_manager_;
+ scoped_ptr<FakeSupervisedUserManager> supervised_user_manager_;
UserList user_list_;
};
diff --git a/chrome/browser/chromeos/login/oauth2_login_verifier.cc b/chrome/browser/chromeos/login/oauth2_login_verifier.cc
index 64f21d6d51..dca159f4f2 100644
--- a/chrome/browser/chromeos/login/oauth2_login_verifier.cc
+++ b/chrome/browser/chromeos/login/oauth2_login_verifier.cc
@@ -62,7 +62,7 @@ void OAuth2LoginVerifier::VerifyProfileTokens(Profile* profile) {
// portal.
const NetworkState* default_network =
NetworkHandler::Get()->network_state_handler()->DefaultNetwork();
- NetworkPortalDetector* detector = NetworkPortalDetector::GetInstance();
+ NetworkPortalDetector* detector = NetworkPortalDetector::Get();
NetworkPortalDetector::CaptivePortalState state =
detector->GetCaptivePortalState(default_network);
if (!default_network ||
diff --git a/chrome/browser/chromeos/login/parallel_authenticator.cc b/chrome/browser/chromeos/login/parallel_authenticator.cc
index 202cd39f48..f866c5b640 100644
--- a/chrome/browser/chromeos/login/parallel_authenticator.cc
+++ b/chrome/browser/chromeos/login/parallel_authenticator.cc
@@ -19,7 +19,7 @@
#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/common/chrome_switches.h"
#include "chromeos/cryptohome/async_method_caller.h"
-#include "chromeos/cryptohome/cryptohome_library.h"
+#include "chromeos/cryptohome/system_salt_getter.h"
#include "chromeos/dbus/cryptohome_client.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/login/login_state.h"
@@ -201,7 +201,6 @@ ParallelAuthenticator::ParallelAuthenticator(LoginStatusConsumer* consumer)
already_reported_success_(false),
owner_is_verified_(false),
user_can_login_(false),
- using_oauth_(true),
remove_user_data_on_failure_(false),
delayed_login_failure_(NULL) {
}
@@ -223,19 +222,11 @@ void ParallelAuthenticator::AuthenticateToLogin(
// Reset the verified flag.
owner_is_verified_ = false;
- CryptohomeLibrary::Get()->GetSystemSalt(
+ SystemSaltGetter::Get()->GetSystemSalt(
base::Bind(&Mount,
current_state_.get(),
scoped_refptr<ParallelAuthenticator>(this),
cryptohome::MOUNT_FLAGS_NONE));
- // ClientLogin authentication check should happen immediately here.
- // We should not try OAuthLogin check until the profile loads.
- if (!using_oauth_) {
- // Initiate ClientLogin-based post authentication.
- current_online_.reset(new OnlineAttempt(current_state_.get(),
- this));
- current_online_->Initiate(profile);
- }
}
void ParallelAuthenticator::CompleteLogin(Profile* profile,
@@ -252,29 +243,18 @@ void ParallelAuthenticator::CompleteLogin(Profile* profile,
// Reset the verified flag.
owner_is_verified_ = false;
- CryptohomeLibrary::Get()->GetSystemSalt(
+ SystemSaltGetter::Get()->GetSystemSalt(
base::Bind(&Mount,
current_state_.get(),
scoped_refptr<ParallelAuthenticator>(this),
cryptohome::MOUNT_FLAGS_NONE));
- if (!using_oauth_) {
- // Test automation needs to disable oauth, but that leads to other
- // services not being able to fetch a token, leading to browser crashes.
- // So initiate ClientLogin-based post authentication.
- // TODO(xiyuan): This should not be required.
- // Context: http://crbug.com/201374
- current_online_.reset(new OnlineAttempt(current_state_.get(),
- this));
- current_online_->Initiate(profile);
- } else {
- // For login completion from extension, we just need to resolve the current
- // auth attempt state, the rest of OAuth related tasks will be done in
- // parallel.
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&ParallelAuthenticator::ResolveLoginCompletionStatus, this));
- }
+ // For login completion from extension, we just need to resolve the current
+ // auth attempt state, the rest of OAuth related tasks will be done in
+ // parallel.
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&ParallelAuthenticator::ResolveLoginCompletionStatus, this));
}
void ParallelAuthenticator::AuthenticateToUnlock(
@@ -285,7 +265,7 @@ void ParallelAuthenticator::AuthenticateToUnlock(
user_context.password));
remove_user_data_on_failure_ = false;
check_key_attempted_ = true;
- CryptohomeLibrary::Get()->GetSystemSalt(
+ SystemSaltGetter::Get()->GetSystemSalt(
base::Bind(&CheckKey,
current_state_.get(),
scoped_refptr<ParallelAuthenticator>(this)));
@@ -302,7 +282,7 @@ void ParallelAuthenticator::LoginAsLocallyManagedUser(
User::USER_TYPE_LOCALLY_MANAGED,
false));
remove_user_data_on_failure_ = false;
- CryptohomeLibrary::Get()->GetSystemSalt(
+ SystemSaltGetter::Get()->GetSystemSalt(
base::Bind(&Mount,
current_state_.get(),
scoped_refptr<ParallelAuthenticator>(this),
@@ -355,7 +335,7 @@ void ParallelAuthenticator::LoginAsPublicAccount(const std::string& username) {
false));
remove_user_data_on_failure_ = false;
ephemeral_mount_attempted_ = true;
- CryptohomeLibrary::Get()->GetSystemSalt(
+ SystemSaltGetter::Get()->GetSystemSalt(
base::Bind(&Mount,
current_state_.get(),
scoped_refptr<ParallelAuthenticator>(this),
@@ -392,7 +372,7 @@ void ParallelAuthenticator::OnRetailModeLoginSuccess() {
consumer_->OnRetailModeLoginSuccess(current_state_->user_context);
}
-void ParallelAuthenticator::OnLoginSuccess(bool request_pending) {
+void ParallelAuthenticator::OnLoginSuccess() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
VLOG(1) << "Login success";
// Send notification of success
@@ -406,9 +386,7 @@ void ParallelAuthenticator::OnLoginSuccess(bool request_pending) {
already_reported_success_ = true;
}
if (consumer_)
- consumer_->OnLoginSuccess(current_state_->user_context,
- request_pending,
- using_oauth_);
+ consumer_->OnLoginSuccess(current_state_->user_context);
}
void ParallelAuthenticator::OnOffTheRecordLoginSuccess() {
@@ -455,7 +433,7 @@ void ParallelAuthenticator::RecoverEncryptedData(
const std::string& old_password) {
migrate_attempted_ = true;
current_state_->ResetCryptohomeStatus();
- CryptohomeLibrary::Get()->GetSystemSalt(
+ SystemSaltGetter::Get()->GetSystemSalt(
base::Bind(&Migrate,
current_state_.get(),
scoped_refptr<ParallelAuthenticator>(this),
@@ -518,7 +496,6 @@ void ParallelAuthenticator::OnOwnershipChecked(bool is_owner) {
void ParallelAuthenticator::Resolve() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- bool request_pending = false;
int mount_flags = cryptohome::MOUNT_FLAGS_NONE;
ParallelAuthenticator::AuthState state = ResolveState();
VLOG(1) << "Resolved state to: " << state;
@@ -582,7 +559,7 @@ void ParallelAuthenticator::Resolve() {
mount_flags |= cryptohome::CREATE_IF_MISSING;
case RECOVER_MOUNT:
current_state_->ResetCryptohomeStatus();
- CryptohomeLibrary::Get()->GetSystemSalt(
+ SystemSaltGetter::Get()->GetSystemSalt(
base::Bind(&Mount,
current_state_.get(),
scoped_refptr<ParallelAuthenticator>(this),
@@ -600,14 +577,6 @@ void ParallelAuthenticator::Resolve() {
break;
case OFFLINE_LOGIN:
VLOG(2) << "Offline login";
- // Marking request_pending to false when using OAuth because OAuth related
- // tasks are performed after user profile is mounted and are not performed
- // by ParallelAuthenticator.
- // TODO(xiyuan): Revert this when we support Gaia in lock screen and
- // start to use ParallelAuthenticator's VerifyOAuth1AccessToken again.
- request_pending = using_oauth_ ?
- false :
- !current_state_->online_complete();
// Fall through.
case UNLOCK:
VLOG(2) << "Unlock";
@@ -616,12 +585,11 @@ void ParallelAuthenticator::Resolve() {
VLOG(2) << "Online login";
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
- base::Bind(&ParallelAuthenticator::OnLoginSuccess, this,
- request_pending));
+ base::Bind(&ParallelAuthenticator::OnLoginSuccess, this));
break;
case DEMO_LOGIN:
VLOG(2) << "Retail mode login";
- using_oauth_ = false;
+ current_state_->user_context.using_oauth = false;
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&ParallelAuthenticator::OnRetailModeLoginSuccess, this));
@@ -633,18 +601,16 @@ void ParallelAuthenticator::Resolve() {
break;
case KIOSK_ACCOUNT_LOGIN:
case PUBLIC_ACCOUNT_LOGIN:
- using_oauth_ = false;
+ current_state_->user_context.using_oauth = false;
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
- base::Bind(&ParallelAuthenticator::OnLoginSuccess, this, false));
+ base::Bind(&ParallelAuthenticator::OnLoginSuccess, this));
break;
case LOCALLY_MANAGED_USER_LOGIN:
- using_oauth_ = false;
- // TODO(nkostylev): Figure out whether there's need to call
- // a separate success method here.
+ current_state_->user_context.using_oauth = false;
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
- base::Bind(&ParallelAuthenticator::OnLoginSuccess, this, false));
+ base::Bind(&ParallelAuthenticator::OnLoginSuccess, this));
break;
case LOGIN_FAILED:
current_state_->ResetCryptohomeStatus();
@@ -761,12 +727,10 @@ ParallelAuthenticator::ResolveCryptohomeFailureState() {
return FAILED_TPM;
}
- // Return intermediate states in the following cases:
- // 1. When there is a parallel online attempt to resolve them later;
- // This is the case with legacy ClientLogin flow;
- // 2. When there is an online result to use;
- // This is the case after user finishes Gaia login;
- if (current_online_.get() || current_state_->online_complete()) {
+ // Return intermediate states in the following case:
+ // when there is an online result to use;
+ // This is the case after user finishes Gaia login;
+ if (current_state_->online_complete()) {
if (current_state_->cryptohome_code() ==
cryptohome::MOUNT_ERROR_KEY_FAILURE) {
// If we tried a mount but they used the wrong key, we may need to
diff --git a/chrome/browser/chromeos/login/parallel_authenticator.h b/chrome/browser/chromeos/login/parallel_authenticator.h
index 24a6ed1223..05e887e419 100644
--- a/chrome/browser/chromeos/login/parallel_authenticator.h
+++ b/chrome/browser/chromeos/login/parallel_authenticator.h
@@ -15,7 +15,6 @@
#include "chrome/browser/chromeos/login/auth_attempt_state.h"
#include "chrome/browser/chromeos/login/auth_attempt_state_resolver.h"
#include "chrome/browser/chromeos/login/authenticator.h"
-#include "chrome/browser/chromeos/login/online_attempt.h"
#include "chrome/browser/chromeos/login/test_attempt_state.h"
#include "chrome/browser/chromeos/settings/device_settings_service.h"
#include "google_apis/gaia/gaia_auth_consumer.h"
@@ -111,8 +110,7 @@ class ParallelAuthenticator : public Authenticator,
// user_context. This will never contact the server even if it's online.
// The auth result is sent to LoginStatusConsumer in a same way as
// AuthenticateToLogin does.
- virtual void AuthenticateToUnlock(
- const UserContext& user_context) OVERRIDE;
+ virtual void AuthenticateToUnlock(const UserContext& user_context) OVERRIDE;
// Initiates locally managed user login.
// Creates cryptohome if missing or mounts existing one and
@@ -141,7 +139,7 @@ class ParallelAuthenticator : public Authenticator,
// These methods must be called on the UI thread, as they make DBus calls
// and also call back to the login UI.
virtual void OnRetailModeLoginSuccess() OVERRIDE;
- virtual void OnLoginSuccess(bool request_pending) OVERRIDE;
+ virtual void OnLoginSuccess() OVERRIDE;
virtual void OnLoginFailure(const LoginFailure& error) OVERRIDE;
virtual void RecoverEncryptedData(
const std::string& old_password) OVERRIDE;
@@ -200,21 +198,11 @@ class ParallelAuthenticator : public Authenticator,
// Must be called on the IO thread.
AuthState ResolveOnlineSuccessState(AuthState offline_state);
- // Used to disable oauth, used for testing.
- void set_using_oauth(bool value) {
- using_oauth_ = value;
- }
-
// Used for testing.
void set_attempt_state(TestAttemptState* new_state) { // takes ownership.
current_state_.reset(new_state);
}
- // Sets an online attempt for testing.
- void set_online_attempt(OnlineAttempt* attempt) {
- current_online_.reset(attempt);
- }
-
// Used for testing to set the expected state of an owner check.
void SetOwnerState(bool owner_check_finished, bool check_result);
@@ -231,7 +219,6 @@ class ParallelAuthenticator : public Authenticator,
void ResolveLoginCompletionStatus();
scoped_ptr<AuthAttemptState> current_state_;
- scoped_ptr<OnlineAttempt> current_online_;
bool migrate_attempted_;
bool remove_attempted_;
bool resync_attempted_;
@@ -250,9 +237,6 @@ class ParallelAuthenticator : public Authenticator,
bool owner_is_verified_;
bool user_can_login_;
- // True if we use OAuth-based authentication flow.
- bool using_oauth_;
-
// Flag indicating to delete the user's cryptohome the login fails.
bool remove_user_data_on_failure_;
diff --git a/chrome/browser/chromeos/login/parallel_authenticator_unittest.cc b/chrome/browser/chromeos/login/parallel_authenticator_unittest.cc
index fcbb9c7188..8b8ab4e8fb 100644
--- a/chrome/browser/chromeos/login/parallel_authenticator_unittest.cc
+++ b/chrome/browser/chromeos/login/parallel_authenticator_unittest.cc
@@ -24,10 +24,10 @@
#include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h"
#include "chrome/test/base/testing_profile.h"
#include "chromeos/chromeos_switches.h"
-#include "chromeos/cryptohome/cryptohome_library.h"
#include "chromeos/cryptohome/mock_async_method_caller.h"
+#include "chromeos/cryptohome/system_salt_getter.h"
#include "chromeos/dbus/fake_cryptohome_client.h"
-#include "chromeos/dbus/mock_dbus_thread_manager_without_gmock.h"
+#include "chromeos/dbus/fake_dbus_thread_manager.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "google_apis/gaia/mock_url_fetcher_factory.h"
#include "net/base/net_errors.h"
@@ -43,14 +43,6 @@ using ::testing::_;
namespace chromeos {
-class TestOnlineAttempt : public OnlineAttempt {
- public:
- TestOnlineAttempt(AuthAttemptState* state,
- AuthAttemptStateResolver* resolver)
- : OnlineAttempt(state, resolver) {
- }
-};
-
class ParallelAuthenticatorTest : public testing::Test {
public:
ParallelAuthenticatorTest()
@@ -58,11 +50,11 @@ class ParallelAuthenticatorTest : public testing::Test {
password_("fakepass"),
hash_ascii_(ParallelAuthenticator::HashPassword(
password_,
- CryptohomeLibrary::ConvertRawSaltToHexString(
+ SystemSaltGetter::ConvertRawSaltToHexString(
FakeCryptohomeClient::GetStubSystemSalt()))),
user_manager_enabler_(new MockUserManager),
mock_caller_(NULL),
- mock_dbus_thread_manager_(new MockDBusThreadManagerWithoutGMock) {
+ fake_dbus_thread_manager_(new FakeDBusThreadManager) {
}
virtual ~ParallelAuthenticatorTest() {
@@ -75,9 +67,9 @@ class ParallelAuthenticatorTest : public testing::Test {
mock_caller_ = new cryptohome::MockAsyncMethodCaller;
cryptohome::AsyncMethodCaller::InitializeForTesting(mock_caller_);
- // Ownership of mock_dbus_thread_manager_ is taken.
- DBusThreadManager::InitializeForTesting(mock_dbus_thread_manager_);
- CryptohomeLibrary::Initialize();
+ // Ownership of fake_dbus_thread_manager_ is taken.
+ DBusThreadManager::InitializeForTesting(fake_dbus_thread_manager_);
+ SystemSaltGetter::Initialize();
auth_ = new ParallelAuthenticator(&consumer_);
state_.reset(new TestAttemptState(UserContext(username_,
@@ -91,7 +83,7 @@ class ParallelAuthenticatorTest : public testing::Test {
// Tears down the test fixture.
virtual void TearDown() {
- CryptohomeLibrary::Shutdown();
+ SystemSaltGetter::Shutdown();
DBusThreadManager::Shutdown();
cryptohome::AsyncMethodCaller::Shutdown();
@@ -124,7 +116,7 @@ class ParallelAuthenticatorTest : public testing::Test {
// Allow test to fail and exit gracefully, even if OnLoginSuccess()
// wasn't supposed to happen.
void FailOnLoginSuccess() {
- ON_CALL(consumer_, OnLoginSuccess(_, _, _))
+ ON_CALL(consumer_, OnLoginSuccess(_))
.WillByDefault(Invoke(MockConsumer::OnSuccessQuitAndFail));
}
@@ -154,9 +146,8 @@ class ParallelAuthenticatorTest : public testing::Test {
EXPECT_CALL(consumer_, OnLoginSuccess(UserContext(username,
password,
std::string(),
- username_hash_),
- pending,
- true /* using_oauth */))
+ username_hash_,
+ true /* using_oauth */)))
.WillOnce(Invoke(MockConsumer::OnSuccessQuit))
.RetiresOnSaturation();
}
@@ -192,10 +183,6 @@ class ParallelAuthenticatorTest : public testing::Test {
auth_->SetOwnerState(owner_check_finished, check_result);
}
- void FakeOnlineAttempt() {
- auth_->set_online_attempt(new TestOnlineAttempt(state_.get(), auth_.get()));
- }
-
content::TestBrowserThreadBundle thread_bundle_;
std::string username_;
@@ -213,20 +200,20 @@ class ParallelAuthenticatorTest : public testing::Test {
MockConsumer consumer_;
scoped_refptr<ParallelAuthenticator> auth_;
scoped_ptr<TestAttemptState> state_;
- MockDBusThreadManagerWithoutGMock* mock_dbus_thread_manager_;
+ FakeDBusThreadManager* fake_dbus_thread_manager_;
};
TEST_F(ParallelAuthenticatorTest, OnLoginSuccess) {
EXPECT_CALL(consumer_, OnLoginSuccess(UserContext(username_,
password_,
std::string(),
- username_hash_),
- false, true /* using oauth */))
+ username_hash_,
+ true /* using oauth */)))
.Times(1)
.RetiresOnSaturation();
SetAttemptState(auth_.get(), state_.release());
- auth_->OnLoginSuccess(false);
+ auth_->OnLoginSuccess();
}
TEST_F(ParallelAuthenticatorTest, OnPasswordChangeDetected) {
@@ -242,17 +229,6 @@ TEST_F(ParallelAuthenticatorTest, ResolveNothingDone) {
SetAndResolveState(auth_.get(), state_.release()));
}
-TEST_F(ParallelAuthenticatorTest, ResolvePossiblePwChange) {
- // Set a fake online attempt so that we return intermediate cryptohome state.
- FakeOnlineAttempt();
-
- // Set up state as though a cryptohome mount attempt has occurred
- // and been rejected.
- state_->PresetCryptohomeStatus(false, cryptohome::MOUNT_ERROR_KEY_FAILURE);
-
- EXPECT_EQ(ParallelAuthenticator::POSSIBLE_PW_CHANGE,
- SetAndResolveState(auth_.get(), state_.release()));
-}
TEST_F(ParallelAuthenticatorTest, ResolvePossiblePwChangeToFailedMount) {
// Set up state as though a cryptohome mount attempt has occurred
@@ -314,7 +290,7 @@ TEST_F(ParallelAuthenticatorTest, ResolveOwnerNeededFailedMount) {
ExpectLoginFailure(failure);
FakeCryptohomeClient* fake_cryptohome_client =
- mock_dbus_thread_manager_->fake_cryptohome_client();
+ fake_dbus_thread_manager_->fake_cryptohome_client();
fake_cryptohome_client->set_unmount_result(true);
CrosSettingsProvider* device_settings_provider;
@@ -539,19 +515,6 @@ TEST_F(ParallelAuthenticatorTest, DriveDataRecoverButFail) {
base::MessageLoop::current()->Run();
}
-TEST_F(ParallelAuthenticatorTest, ResolveNoMount) {
- // Set a fake online attempt so that we return intermediate cryptohome state.
- FakeOnlineAttempt();
-
- // Set up state as though a cryptohome mount attempt has occurred
- // and been rejected because the user doesn't exist.
- state_->PresetCryptohomeStatus(false,
- cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST);
-
- EXPECT_EQ(ParallelAuthenticator::NO_MOUNT,
- SetAndResolveState(auth_.get(), state_.release()));
-}
-
TEST_F(ParallelAuthenticatorTest, ResolveNoMountToFailedMount) {
// Set up state as though a cryptohome mount attempt has occurred
// and been rejected because the user doesn't exist.
diff --git a/chrome/browser/chromeos/login/screen_locker.cc b/chrome/browser/chromeos/login/screen_locker.cc
index 5410f80c04..6fbdd0d83b 100644
--- a/chrome/browser/chromeos/login/screen_locker.cc
+++ b/chrome/browser/chromeos/login/screen_locker.cc
@@ -186,10 +186,7 @@ void ScreenLocker::OnLoginFailure(const LoginFailure& error) {
login_status_consumer_->OnLoginFailure(error);
}
-void ScreenLocker::OnLoginSuccess(
- const UserContext& user_context,
- bool pending_requests,
- bool using_oauth) {
+void ScreenLocker::OnLoginSuccess(const UserContext& user_context) {
incorrect_passwords_count_ = 0;
if (authentication_start_time_.is_null()) {
if (!user_context.username.empty())
@@ -227,9 +224,7 @@ void ScreenLocker::OnLoginSuccess(
}
authentication_capture_.reset(new AuthenticationParametersCapture());
- authentication_capture_->username = user_context.username;
- authentication_capture_->pending_requests = pending_requests;
- authentication_capture_->using_oauth = using_oauth;
+ authentication_capture_->user_context = user_context;
// Add guard for case when something get broken in call chain to unlock
// for sure.
@@ -251,11 +246,11 @@ void ScreenLocker::UnlockOnLoginSuccess() {
if (login_status_consumer_) {
login_status_consumer_->OnLoginSuccess(
- UserContext(authentication_capture_->username,
- std::string(), // password
- std::string()), // auth_code
- authentication_capture_->pending_requests,
- authentication_capture_->using_oauth);
+ UserContext(authentication_capture_->user_context.username,
+ authentication_capture_->user_context.password,
+ authentication_capture_->user_context.auth_code,
+ authentication_capture_->user_context.username_hash,
+ authentication_capture_->user_context.using_oauth));
}
authentication_capture_.reset();
weak_factory_.InvalidateWeakPtrs();
diff --git a/chrome/browser/chromeos/login/screen_locker.h b/chrome/browser/chromeos/login/screen_locker.h
index aabe07d2b2..f73a365d23 100644
--- a/chrome/browser/chromeos/login/screen_locker.h
+++ b/chrome/browser/chromeos/login/screen_locker.h
@@ -52,9 +52,7 @@ class ScreenLocker : public LoginStatusConsumer {
// LoginStatusConsumer implements:
virtual void OnLoginFailure(const chromeos::LoginFailure& error) OVERRIDE;
- virtual void OnLoginSuccess(const UserContext& user_context,
- bool pending_requests,
- bool using_oauth) OVERRIDE;
+ virtual void OnLoginSuccess(const UserContext& user_context) OVERRIDE;
// Does actual unlocking once authentication is successful and all blocking
// animations are done.
@@ -120,9 +118,7 @@ class ScreenLocker : public LoginStatusConsumer {
friend class ScreenLockerDelegate;
struct AuthenticationParametersCapture {
- std::string username;
- bool pending_requests;
- bool using_oauth;
+ UserContext user_context;
};
virtual ~ScreenLocker();
diff --git a/chrome/browser/chromeos/login/screen_locker_browsertest.cc b/chrome/browser/chromeos/login/screen_locker_browsertest.cc
index df3c0a70ef..0b3ad8bf20 100644
--- a/chrome/browser/chromeos/login/screen_locker_browsertest.cc
+++ b/chrome/browser/chromeos/login/screen_locker_browsertest.cc
@@ -19,8 +19,8 @@
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "chromeos/chromeos_switches.h"
+#include "chromeos/dbus/fake_dbus_thread_manager.h"
#include "chromeos/dbus/fake_session_manager_client.h"
-#include "chromeos/dbus/mock_dbus_thread_manager_without_gmock.h"
#include "content/public/browser/notification_service.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -116,12 +116,12 @@ class ScreenLockerTest : public InProcessBrowserTest {
private:
virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
- MockDBusThreadManagerWithoutGMock* mock_dbus_thread_manager =
- new MockDBusThreadManagerWithoutGMock;
- DBusThreadManager::InitializeForTesting(mock_dbus_thread_manager);
+ FakeDBusThreadManager* fake_dbus_thread_manager =
+ new FakeDBusThreadManager;
+ DBusThreadManager::InitializeForTesting(fake_dbus_thread_manager);
InProcessBrowserTest::SetUpInProcessBrowserTestFixture();
fake_session_manager_client_ =
- mock_dbus_thread_manager->fake_session_manager_client();
+ fake_dbus_thread_manager->fake_session_manager_client();
zero_duration_mode_.reset(new ui::ScopedAnimationDurationScaleMode(
ui::ScopedAnimationDurationScaleMode::ZERO_DURATION));
}
diff --git a/chrome/browser/chromeos/login/screen_locker_tester.cc b/chrome/browser/chromeos/login/screen_locker_tester.cc
index 33ce5b124b..928931efe4 100644
--- a/chrome/browser/chromeos/login/screen_locker_tester.cc
+++ b/chrome/browser/chromeos/login/screen_locker_tester.cc
@@ -44,9 +44,7 @@ class LoginAttemptObserver : public chromeos::LoginStatusConsumer {
}
virtual void OnLoginSuccess(
- const chromeos::UserContext& credentials,
- bool pending_requests,
- bool using_oauth) OVERRIDE {
+ const chromeos::UserContext& credentials) OVERRIDE {
LoginAttempted();
}
diff --git a/chrome/browser/chromeos/login/screens/network_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/network_screen_browsertest.cc
index a69145b72b..94af181b81 100644
--- a/chrome/browser/chromeos/login/screens/network_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/screens/network_screen_browsertest.cc
@@ -10,8 +10,8 @@
#include "chrome/browser/chromeos/login/wizard_controller.h"
#include "chrome/browser/chromeos/login/wizard_in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
+#include "chromeos/dbus/fake_dbus_thread_manager.h"
#include "chromeos/dbus/fake_session_manager_client.h"
-#include "chromeos/dbus/mock_dbus_thread_manager_without_gmock.h"
#include "content/public/test/test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -53,11 +53,11 @@ class NetworkScreenTest : public WizardInProcessBrowserTest {
virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
WizardInProcessBrowserTest::SetUpInProcessBrowserTestFixture();
- MockDBusThreadManagerWithoutGMock* mock_dbus_thread_manager =
- new MockDBusThreadManagerWithoutGMock;
- DBusThreadManager::InitializeForTesting(mock_dbus_thread_manager);
+ FakeDBusThreadManager* fake_dbus_thread_manager =
+ new FakeDBusThreadManager;
+ DBusThreadManager::InitializeForTesting(fake_dbus_thread_manager);
fake_session_manager_client_ =
- mock_dbus_thread_manager->fake_session_manager_client();
+ fake_dbus_thread_manager->fake_session_manager_client();
}
virtual void SetUpOnMainThread() OVERRIDE {
diff --git a/chrome/browser/chromeos/login/screens/update_screen.cc b/chrome/browser/chromeos/login/screens/update_screen.cc
index 4469c120e0..8e4b07a7a4 100644
--- a/chrome/browser/chromeos/login/screens/update_screen.cc
+++ b/chrome/browser/chromeos/login/screens/update_screen.cc
@@ -41,19 +41,12 @@ const int kProgressComplete = 100;
// Defines what part of update progress does download part takes.
const int kDownloadProgressIncrement = 60;
-// Considering 10px shadow from each side.
-const int kUpdateScreenWidth = 580;
-const int kUpdateScreenHeight = 305;
-
const char kUpdateDeadlineFile[] = "/tmp/update-check-response-deadline";
// Minimum timestep between two consecutive measurements for the
// download rate.
const base::TimeDelta kMinTimeStep = base::TimeDelta::FromSeconds(1);
-// Minimum allowed progress between two consecutive ETAs.
-const double kMinProgressStep = 1e-3;
-
// Smooth factor that is used for the average downloading speed
// estimation.
// avg_speed = smooth_factor * cur_speed + (1.0 - smooth_factor) * avg_speed.
@@ -122,6 +115,7 @@ UpdateScreen::UpdateScreen(
UpdateScreen::~UpdateScreen() {
DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this);
+ NetworkPortalDetector::Get()->RemoveObserver(this);
GetInstanceSet().erase(this);
if (actor_)
actor_->SetDelegate(NULL);
@@ -258,12 +252,11 @@ void UpdateScreen::OnPortalDetectionCompleted(
state.status == NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE) &&
is_first_detection_notification_) {
is_first_detection_notification_ = false;
- NetworkPortalDetector* detector = NetworkPortalDetector::GetInstance();
base::MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(
base::IgnoreResult(&NetworkPortalDetector::StartDetectionIfIdle),
- base::Unretained(detector)));
+ base::Unretained(NetworkPortalDetector::Get())));
return;
}
is_first_detection_notification_ = false;
@@ -289,12 +282,10 @@ void UpdateScreen::OnPortalDetectionCompleted(
}
void UpdateScreen::StartNetworkCheck() {
- NetworkPortalDetector* detector = NetworkPortalDetector::GetInstance();
-
// If portal detector is enabled and portal detection before AU is
// allowed, initiate network state check. Otherwise, directly
// proceed to update.
- if (!NetworkPortalDetector::IsEnabledInCommandLine() || !detector ||
+ if (!NetworkPortalDetector::Get()->IsEnabled() ||
!IsBlockingUpdateEnabledInCommandLine()) {
StartUpdateCheck();
return;
@@ -302,7 +293,7 @@ void UpdateScreen::StartNetworkCheck() {
state_ = STATE_FIRST_PORTAL_CHECK;
is_first_detection_notification_ = true;
is_first_portal_notification_ = true;
- detector->AddAndFireObserver(this);
+ NetworkPortalDetector::Get()->AddAndFireObserver(this);
}
void UpdateScreen::CancelUpdate() {
@@ -335,8 +326,7 @@ void UpdateScreen::PrepareToShow() {
void UpdateScreen::ExitUpdate(UpdateScreen::ExitReason reason) {
DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this);
- if (NetworkPortalDetector::GetInstance())
- NetworkPortalDetector::GetInstance()->RemoveObserver(this);
+ NetworkPortalDetector::Get()->RemoveObserver(this);
switch (reason) {
case REASON_UPDATE_CANCELED:
@@ -488,9 +478,7 @@ ErrorScreen* UpdateScreen::GetErrorScreen() {
}
void UpdateScreen::StartUpdateCheck() {
- NetworkPortalDetector* detector = NetworkPortalDetector::GetInstance();
- if (detector)
- detector->RemoveObserver(this);
+ NetworkPortalDetector::Get()->RemoveObserver(this);
if (state_ == STATE_ERROR)
HideErrorMessage();
state_ = STATE_UPDATE;
diff --git a/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc
index 0935de6f9b..55915ab00c 100644
--- a/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc
@@ -10,10 +10,10 @@
#include "chrome/browser/chromeos/login/wizard_controller.h"
#include "chrome/browser/chromeos/login/wizard_in_process_browser_test.h"
#include "chrome/browser/chromeos/net/network_portal_detector.h"
-#include "chrome/browser/chromeos/net/network_portal_detector_stub.h"
+#include "chrome/browser/chromeos/net/network_portal_detector_test_impl.h"
#include "chromeos/chromeos_switches.h"
+#include "chromeos/dbus/fake_dbus_thread_manager.h"
#include "chromeos/dbus/fake_update_engine_client.h"
-#include "chromeos/dbus/mock_dbus_thread_manager_without_gmock.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -37,25 +37,24 @@ class UpdateScreenTest : public WizardInProcessBrowserTest {
public:
UpdateScreenTest() : WizardInProcessBrowserTest("update"),
fake_update_engine_client_(NULL),
- network_portal_detector_stub_(NULL) {
+ network_portal_detector_(NULL) {
}
protected:
virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
- MockDBusThreadManagerWithoutGMock* mock_dbus_thread_manager =
- new MockDBusThreadManagerWithoutGMock;
- DBusThreadManager::InitializeForTesting(mock_dbus_thread_manager);
+ FakeDBusThreadManager* fake_dbus_thread_manager =
+ new FakeDBusThreadManager;
+ DBusThreadManager::InitializeForTesting(fake_dbus_thread_manager);
WizardInProcessBrowserTest::SetUpInProcessBrowserTestFixture();
fake_update_engine_client_
- = mock_dbus_thread_manager->fake_update_engine_client();
+ = fake_dbus_thread_manager->fake_update_engine_client();
// Setup network portal detector to return online state for both
// ethernet and wifi networks. Ethernet is an active network by
// default.
- network_portal_detector_stub_ =
- static_cast<NetworkPortalDetectorStub*>(
- NetworkPortalDetector::GetInstance());
+ network_portal_detector_ = new NetworkPortalDetectorTestImpl();
+ NetworkPortalDetector::InitializeForTesting(network_portal_detector_);
NetworkPortalDetector::CaptivePortalState online_state;
online_state.status = NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE;
online_state.response_code = 204;
@@ -87,27 +86,28 @@ class UpdateScreenTest : public WizardInProcessBrowserTest {
}
virtual void TearDownInProcessBrowserTestFixture() OVERRIDE {
+ NetworkPortalDetector::Shutdown();
WizardInProcessBrowserTest::TearDownInProcessBrowserTestFixture();
DBusThreadManager::Shutdown();
}
void SetDefaultNetworkPath(const std::string& service_path) {
- DCHECK(network_portal_detector_stub_);
- network_portal_detector_stub_->SetDefaultNetworkPathForTesting(
+ DCHECK(network_portal_detector_);
+ network_portal_detector_->SetDefaultNetworkPathForTesting(
service_path);
}
void SetDetectionResults(
const std::string& service_path,
const NetworkPortalDetector::CaptivePortalState& state) {
- DCHECK(network_portal_detector_stub_);
- network_portal_detector_stub_->SetDetectionResultsForTesting(service_path,
- state);
+ DCHECK(network_portal_detector_);
+ network_portal_detector_->SetDetectionResultsForTesting(service_path,
+ state);
}
void NotifyPortalDetectionCompleted() {
- DCHECK(network_portal_detector_stub_);
- network_portal_detector_stub_->NotifyObserversForTesting();
+ DCHECK(network_portal_detector_);
+ network_portal_detector_->NotifyObserversForTesting();
}
FakeUpdateEngineClient* fake_update_engine_client_;
@@ -115,7 +115,7 @@ class UpdateScreenTest : public WizardInProcessBrowserTest {
scoped_ptr<MockErrorScreenActor> mock_error_screen_actor_;
scoped_ptr<MockErrorScreen> mock_error_screen_;
UpdateScreen* update_screen_;
- NetworkPortalDetectorStub* network_portal_detector_stub_;
+ NetworkPortalDetectorTestImpl* network_portal_detector_;
private:
DISALLOW_COPY_AND_ASSIGN(UpdateScreenTest);
diff --git a/chrome/browser/chromeos/login/startup_utils.cc b/chrome/browser/chromeos/login/startup_utils.cc
index a32c9877b4..229d38b3b7 100644
--- a/chrome/browser/chromeos/login/startup_utils.cc
+++ b/chrome/browser/chromeos/login/startup_utils.cc
@@ -30,10 +30,6 @@ const char kOobeComplete[] = "OobeComplete";
// A boolean pref of the device registered flag (second part after first login).
const char kDeviceRegistered[] = "DeviceRegistered";
-// Time in seconds that we wait for the device to reboot.
-// If reboot didn't happen, ask user to reboot device manually.
-const int kWaitForRebootTimeSec = 3;
-
// Saves boolean "Local State" preference and forces its persistence to disk.
void SaveBoolPreferenceForced(const char* pref_name, bool value) {
PrefService* prefs = g_browser_process->local_state();
diff --git a/chrome/browser/chromeos/login/supervised_user_manager.h b/chrome/browser/chromeos/login/supervised_user_manager.h
new file mode 100644
index 0000000000..880c989c75
--- /dev/null
+++ b/chrome/browser/chromeos/login/supervised_user_manager.h
@@ -0,0 +1,88 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_SUPERVISED_USER_MANAGER_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_SUPERVISED_USER_MANAGER_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+
+class PrefRegistrySimple;
+
+namespace chromeos {
+
+class User;
+
+// Base class for SupervisedUserManagerImpl - provides a mechanism for getting
+// and setting specific values for supervised users, as well as additional
+// lookup methods that make sense only for supervised users.
+class SupervisedUserManager {
+ public:
+ // Registers user manager preferences.
+ static void RegisterPrefs(PrefRegistrySimple* registry);
+
+ SupervisedUserManager() {}
+ virtual ~SupervisedUserManager() {}
+
+ // Creates supervised user with given |display_name| and |local_user_id|
+ // and persists that to user list. Also links this user identified by
+ // |sync_user_id| to manager with a |manager_id|.
+ // Returns created user, or existing user if there already
+ // was locally managed user with such display name.
+ // TODO(antrim): Refactor into a single struct to have only 1 getter.
+ virtual const User* CreateUserRecord(
+ const std::string& manager_id,
+ const std::string& local_user_id,
+ const std::string& sync_user_id,
+ const string16& display_name) = 0;
+
+ // Generates unique user ID for supervised user.
+ virtual std::string GenerateUserId() = 0;
+
+ // Returns the supervised user with the given |display_name| if found in
+ // the persistent list. Returns |NULL| otherwise.
+ virtual const User* FindByDisplayName(const string16& display_name) const = 0;
+
+ // Returns the supervised user with the given |sync_id| if found in
+ // the persistent list. Returns |NULL| otherwise.
+ virtual const User* FindBySyncId(const std::string& sync_id) const = 0;
+
+ // Returns sync_user_id for supervised user with |user_id| or empty string if
+ // such user is not found or it doesn't have user_id defined.
+ virtual std::string GetUserSyncId(const std::string& user_id) const = 0;
+
+ // Returns the display name for manager of user |user_id| if it is known
+ // (was previously set by a |SaveUserDisplayName| call).
+ // Otherwise, returns a manager id.
+ virtual string16 GetManagerDisplayName(const std::string& user_id) const = 0;
+
+ // Returns the user id for manager of user |user_id| if it is known (user is
+ // actually a managed user).
+ // Otherwise, returns an empty string.
+ virtual std::string GetManagerUserId(const std::string& user_id) const = 0;
+
+ // Returns the display email for manager of user |user_id| if it is known
+ // (user is actually a managed user).
+ // Otherwise, returns an empty string.
+ virtual std::string GetManagerDisplayEmail(const std::string& user_id)
+ const = 0;
+
+ // Create a record about starting supervised user creation transaction.
+ virtual void StartCreationTransaction(const string16& display_name) = 0;
+
+ // Add user id to supervised user creation transaction record.
+ virtual void SetCreationTransactionUserId(const std::string& user_id) = 0;
+
+ // Remove locally managed user creation transaction record.
+ virtual void CommitCreationTransaction() = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SupervisedUserManager);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_LOGIN_SUPERVISED_USER_MANAGER_H_
diff --git a/chrome/browser/chromeos/login/supervised_user_manager_impl.cc b/chrome/browser/chromeos/login/supervised_user_manager_impl.cc
new file mode 100644
index 0000000000..d5533ec9ea
--- /dev/null
+++ b/chrome/browser/chromeos/login/supervised_user_manager_impl.cc
@@ -0,0 +1,332 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/login/supervised_user_manager_impl.h"
+
+#include "base/prefs/pref_registry_simple.h"
+#include "base/prefs/pref_service.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/chromeos/login/user_manager_impl.h"
+#include "chrome/browser/prefs/scoped_user_pref_update.h"
+#include "chromeos/settings/cros_settings_names.h"
+#include "content/public/browser/browser_thread.h"
+#include "google_apis/gaia/gaia_auth_util.h"
+
+using content::BrowserThread;
+
+namespace {
+
+// A map from locally managed user local user id to sync user id.
+const char kManagedUserSyncId[] =
+ "ManagedUserSyncId";
+
+// A map from locally managed user id to manager user id.
+const char kManagedUserManagers[] =
+ "ManagedUserManagers";
+
+// A map from locally managed user id to manager display name.
+const char kManagedUserManagerNames[] =
+ "ManagedUserManagerNames";
+
+// A map from locally managed user id to manager display e-mail.
+const char kManagedUserManagerDisplayEmails[] =
+ "ManagedUserManagerDisplayEmails";
+
+// A vector pref of the locally managed accounts defined on this device, that
+// had not logged in yet.
+const char kLocallyManagedUsersFirstRun[] = "LocallyManagedUsersFirstRun";
+
+// A pref of the next id for locally managed users generation.
+const char kLocallyManagedUsersNextId[] =
+ "LocallyManagedUsersNextId";
+
+// A pref of the next id for locally managed users generation.
+const char kLocallyManagedUserCreationTransactionDisplayName[] =
+ "LocallyManagedUserCreationTransactionDisplayName";
+
+// A pref of the next id for locally managed users generation.
+const char kLocallyManagedUserCreationTransactionUserId[] =
+ "LocallyManagedUserCreationTransactionUserId";
+
+} // namespace
+
+namespace chromeos {
+
+// static
+void SupervisedUserManager::RegisterPrefs(PrefRegistrySimple* registry) {
+ registry->RegisterListPref(kLocallyManagedUsersFirstRun);
+ registry->RegisterIntegerPref(kLocallyManagedUsersNextId, 0);
+ registry->RegisterStringPref(
+ kLocallyManagedUserCreationTransactionDisplayName, "");
+ registry->RegisterStringPref(
+ kLocallyManagedUserCreationTransactionUserId, "");
+ registry->RegisterDictionaryPref(kManagedUserSyncId);
+ registry->RegisterDictionaryPref(kManagedUserManagers);
+ registry->RegisterDictionaryPref(kManagedUserManagerNames);
+ registry->RegisterDictionaryPref(kManagedUserManagerDisplayEmails);
+}
+
+SupervisedUserManagerImpl::SupervisedUserManagerImpl(UserManagerImpl* owner)
+ : owner_(owner),
+ cros_settings_(CrosSettings::Get()) {
+ // SupervisedUserManager instance should be used only on UI thread.
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+}
+
+SupervisedUserManagerImpl::~SupervisedUserManagerImpl() {
+}
+
+std::string SupervisedUserManagerImpl::GenerateUserId() {
+ int counter = g_browser_process->local_state()->
+ GetInteger(kLocallyManagedUsersNextId);
+ std::string id;
+ bool user_exists;
+ do {
+ id = base::StringPrintf("%d@%s", counter,
+ UserManager::kLocallyManagedUserDomain);
+ counter++;
+ user_exists = (NULL != owner_->FindUser(id));
+ DCHECK(!user_exists);
+ if (user_exists) {
+ LOG(ERROR) << "Supervised user with id " << id << " already exists.";
+ }
+ } while (user_exists);
+
+ g_browser_process->local_state()->
+ SetInteger(kLocallyManagedUsersNextId, counter);
+
+ g_browser_process->local_state()->CommitPendingWrite();
+ return id;
+}
+
+const User* SupervisedUserManagerImpl::CreateUserRecord(
+ const std::string& manager_id,
+ const std::string& local_user_id,
+ const std::string& sync_user_id,
+ const string16& display_name) {
+ const User* user = FindByDisplayName(display_name);
+ DCHECK(!user);
+ if (user)
+ return user;
+ const User* manager = owner_->FindUser(manager_id);
+ CHECK(manager);
+
+ PrefService* local_state = g_browser_process->local_state();
+
+ User* new_user = User::CreateLocallyManagedUser(local_user_id);
+
+ owner_->AddUserRecord(new_user);
+
+ ListPrefUpdate prefs_new_users_update(local_state,
+ kLocallyManagedUsersFirstRun);
+ DictionaryPrefUpdate sync_id_update(local_state, kManagedUserSyncId);
+ DictionaryPrefUpdate manager_update(local_state, kManagedUserManagers);
+ DictionaryPrefUpdate manager_name_update(local_state,
+ kManagedUserManagerNames);
+ DictionaryPrefUpdate manager_email_update(local_state,
+ kManagedUserManagerDisplayEmails);
+
+ prefs_new_users_update->Insert(0, new base::StringValue(local_user_id));
+
+ sync_id_update->SetWithoutPathExpansion(local_user_id,
+ new base::StringValue(sync_user_id));
+ manager_update->SetWithoutPathExpansion(local_user_id,
+ new base::StringValue(manager->email()));
+ manager_name_update->SetWithoutPathExpansion(local_user_id,
+ new base::StringValue(manager->GetDisplayName()));
+ manager_email_update->SetWithoutPathExpansion(local_user_id,
+ new base::StringValue(manager->display_email()));
+
+ owner_->SaveUserDisplayName(local_user_id, display_name);
+
+ g_browser_process->local_state()->CommitPendingWrite();
+ return new_user;
+}
+
+std::string SupervisedUserManagerImpl::GetUserSyncId(const std::string& user_id)
+ const {
+ PrefService* local_state = g_browser_process->local_state();
+ const DictionaryValue* sync_ids =
+ local_state->GetDictionary(kManagedUserSyncId);
+ std::string result;
+ sync_ids->GetStringWithoutPathExpansion(user_id, &result);
+ return result;
+}
+
+string16 SupervisedUserManagerImpl::GetManagerDisplayName(
+ const std::string& user_id) const {
+ PrefService* local_state = g_browser_process->local_state();
+ const DictionaryValue* manager_names =
+ local_state->GetDictionary(kManagedUserManagerNames);
+ string16 result;
+ if (manager_names->GetStringWithoutPathExpansion(user_id, &result) &&
+ !result.empty())
+ return result;
+ return UTF8ToUTF16(GetManagerDisplayEmail(user_id));
+}
+
+std::string SupervisedUserManagerImpl::GetManagerUserId(
+ const std::string& user_id) const {
+ PrefService* local_state = g_browser_process->local_state();
+ const DictionaryValue* manager_ids =
+ local_state->GetDictionary(kManagedUserManagers);
+ std::string result;
+ manager_ids->GetStringWithoutPathExpansion(user_id, &result);
+ return result;
+}
+
+std::string SupervisedUserManagerImpl::GetManagerDisplayEmail(
+ const std::string& user_id) const {
+ PrefService* local_state = g_browser_process->local_state();
+ const DictionaryValue* manager_mails =
+ local_state->GetDictionary(kManagedUserManagerDisplayEmails);
+ std::string result;
+ if (manager_mails->GetStringWithoutPathExpansion(user_id, &result) &&
+ !result.empty()) {
+ return result;
+ }
+ return GetManagerUserId(user_id);
+}
+
+const User* SupervisedUserManagerImpl::FindByDisplayName(
+ const string16& display_name) const {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ const UserList& users = owner_->GetUsers();
+ for (UserList::const_iterator it = users.begin(); it != users.end(); ++it) {
+ if (((*it)->GetType() == User::USER_TYPE_LOCALLY_MANAGED) &&
+ ((*it)->display_name() == display_name)) {
+ return *it;
+ }
+ }
+ return NULL;
+}
+
+const User* SupervisedUserManagerImpl::FindBySyncId(
+ const std::string& sync_id) const {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ const UserList& users = owner_->GetUsers();
+ for (UserList::const_iterator it = users.begin(); it != users.end(); ++it) {
+ if (((*it)->GetType() == User::USER_TYPE_LOCALLY_MANAGED) &&
+ (GetUserSyncId((*it)->email()) == sync_id)) {
+ return *it;
+ }
+ }
+ return NULL;
+}
+
+void SupervisedUserManagerImpl::StartCreationTransaction(
+ const string16& display_name) {
+ g_browser_process->local_state()->
+ SetString(kLocallyManagedUserCreationTransactionDisplayName,
+ UTF16ToASCII(display_name));
+ g_browser_process->local_state()->CommitPendingWrite();
+}
+
+void SupervisedUserManagerImpl::SetCreationTransactionUserId(
+ const std::string& email) {
+ g_browser_process->local_state()->
+ SetString(kLocallyManagedUserCreationTransactionUserId,
+ email);
+ g_browser_process->local_state()->CommitPendingWrite();
+}
+
+void SupervisedUserManagerImpl::CommitCreationTransaction() {
+ g_browser_process->local_state()->
+ ClearPref(kLocallyManagedUserCreationTransactionDisplayName);
+ g_browser_process->local_state()->
+ ClearPref(kLocallyManagedUserCreationTransactionUserId);
+ g_browser_process->local_state()->CommitPendingWrite();
+}
+
+bool SupervisedUserManagerImpl::HasFailedUserCreationTransaction() {
+ return !(g_browser_process->local_state()->
+ GetString(kLocallyManagedUserCreationTransactionDisplayName).
+ empty());
+}
+
+void SupervisedUserManagerImpl::RollbackUserCreationTransaction() {
+ PrefService* prefs = g_browser_process->local_state();
+
+ std::string display_name = prefs->
+ GetString(kLocallyManagedUserCreationTransactionDisplayName);
+ std::string user_id = prefs->
+ GetString(kLocallyManagedUserCreationTransactionUserId);
+
+ LOG(WARNING) << "Cleaning up transaction for "
+ << display_name << "/" << user_id;
+
+ if (user_id.empty()) {
+ // Not much to do - just remove transaction.
+ prefs->ClearPref(kLocallyManagedUserCreationTransactionDisplayName);
+ return;
+ }
+
+ if (gaia::ExtractDomainName(user_id) !=
+ UserManager::kLocallyManagedUserDomain) {
+ LOG(WARNING) << "Clean up transaction for non-locally managed user found :"
+ << user_id << ", will not remove data";
+ prefs->ClearPref(kLocallyManagedUserCreationTransactionDisplayName);
+ prefs->ClearPref(kLocallyManagedUserCreationTransactionUserId);
+ return;
+ }
+
+ owner_->RemoveUser(user_id, NULL);
+
+ prefs->ClearPref(kLocallyManagedUserCreationTransactionDisplayName);
+ prefs->ClearPref(kLocallyManagedUserCreationTransactionUserId);
+ prefs->CommitPendingWrite();
+}
+
+void SupervisedUserManagerImpl::RemoveNonCryptohomeData(
+ const std::string& user_id) {
+ PrefService* prefs = g_browser_process->local_state();
+ ListPrefUpdate prefs_new_users_update(prefs, kLocallyManagedUsersFirstRun);
+ prefs_new_users_update->Remove(base::StringValue(user_id), NULL);
+
+ DictionaryPrefUpdate managers_update(prefs, kManagedUserManagers);
+ managers_update->RemoveWithoutPathExpansion(user_id, NULL);
+
+ DictionaryPrefUpdate manager_names_update(prefs,
+ kManagedUserManagerNames);
+ manager_names_update->RemoveWithoutPathExpansion(user_id, NULL);
+
+ DictionaryPrefUpdate manager_emails_update(prefs,
+ kManagedUserManagerDisplayEmails);
+ manager_emails_update->RemoveWithoutPathExpansion(user_id, NULL);
+}
+
+bool SupervisedUserManagerImpl::CheckForFirstRun(const std::string& user_id) {
+ ListPrefUpdate prefs_new_users_update(g_browser_process->local_state(),
+ kLocallyManagedUsersFirstRun);
+ return prefs_new_users_update->Remove(base::StringValue(user_id), NULL);
+}
+
+void SupervisedUserManagerImpl::UpdateManagerName(const std::string& manager_id,
+ const string16& new_display_name) {
+ PrefService* local_state = g_browser_process->local_state();
+
+ const DictionaryValue* manager_ids =
+ local_state->GetDictionary(kManagedUserManagers);
+
+ DictionaryPrefUpdate manager_name_update(local_state,
+ kManagedUserManagerNames);
+ for (DictionaryValue::Iterator it(*manager_ids); !it.IsAtEnd();
+ it.Advance()) {
+ std::string user_id;
+ bool has_manager_id = it.value().GetAsString(&user_id);
+ DCHECK(has_manager_id);
+ if (user_id == manager_id) {
+ manager_name_update->SetWithoutPathExpansion(
+ it.key(),
+ new base::StringValue(new_display_name));
+ }
+ }
+}
+
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/supervised_user_manager_impl.h b/chrome/browser/chromeos/login/supervised_user_manager_impl.h
new file mode 100644
index 0000000000..e598006547
--- /dev/null
+++ b/chrome/browser/chromeos/login/supervised_user_manager_impl.h
@@ -0,0 +1,76 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_SUPERVISED_USER_MANAGER_IMPL_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_SUPERVISED_USER_MANAGER_IMPL_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "chrome/browser/chromeos/login/supervised_user_manager.h"
+
+namespace chromeos {
+
+class CrosSettings;
+class UserManagerImpl;
+
+// Implementation of the UserManager.
+class SupervisedUserManagerImpl
+ : public SupervisedUserManager {
+ public:
+ virtual ~SupervisedUserManagerImpl();
+
+ virtual const User* CreateUserRecord(
+ const std::string& manager_id,
+ const std::string& local_user_id,
+ const std::string& sync_user_id,
+ const string16& display_name) OVERRIDE;
+ virtual std::string GenerateUserId() OVERRIDE;
+ virtual const User* FindByDisplayName(const string16& display_name) const
+ OVERRIDE;
+ virtual const User* FindBySyncId(const std::string& sync_id) const OVERRIDE;
+ virtual std::string GetUserSyncId(const std::string& user_id) const OVERRIDE;
+ virtual string16 GetManagerDisplayName(const std::string& user_id) const
+ OVERRIDE;
+ virtual std::string GetManagerUserId(const std::string& user_id) const
+ OVERRIDE;
+ virtual std::string GetManagerDisplayEmail(const std::string& user_id) const
+ OVERRIDE;
+ virtual void StartCreationTransaction(const string16& display_name) OVERRIDE;
+ virtual void SetCreationTransactionUserId(const std::string& user_id)
+ OVERRIDE;
+ virtual void CommitCreationTransaction() OVERRIDE;
+
+ private:
+ friend class UserManager;
+ friend class UserManagerImpl;
+
+ explicit SupervisedUserManagerImpl(UserManagerImpl* owner);
+
+ // Returns true if there is non-committed user creation transaction.
+ bool HasFailedUserCreationTransaction();
+
+ // Attempts to clean up data that could be left from failed user creation.
+ void RollbackUserCreationTransaction();
+
+ void RemoveNonCryptohomeData(const std::string& user_id);
+
+ bool CheckForFirstRun(const std::string& user_id);
+
+ // Update name if this user is manager of some managed users.
+ void UpdateManagerName(const std::string& manager_id,
+ const string16& new_display_name);
+
+ UserManagerImpl* owner_;
+
+ // Interface to the signed settings store.
+ CrosSettings* cros_settings_;
+
+ DISALLOW_COPY_AND_ASSIGN(SupervisedUserManagerImpl);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_LOGIN_SUPERVISED_USER_MANAGER_IMPL_H_
diff --git a/chrome/browser/chromeos/login/test_login_utils.cc b/chrome/browser/chromeos/login/test_login_utils.cc
index 74cca19590..750e7735e6 100644
--- a/chrome/browser/chromeos/login/test_login_utils.cc
+++ b/chrome/browser/chromeos/login/test_login_utils.cc
@@ -20,7 +20,6 @@ TestLoginUtils::~TestLoginUtils() {}
void TestLoginUtils::PrepareProfile(
const UserContext& credentials,
const std::string& display_email,
- bool using_oauth,
bool has_cookies,
bool has_active_session,
Delegate* delegate) {
diff --git a/chrome/browser/chromeos/login/test_login_utils.h b/chrome/browser/chromeos/login/test_login_utils.h
index f1fd4fb849..9f27300727 100644
--- a/chrome/browser/chromeos/login/test_login_utils.h
+++ b/chrome/browser/chromeos/login/test_login_utils.h
@@ -29,7 +29,6 @@ class TestLoginUtils : public LoginUtils {
LoginDisplayHost* login_host) OVERRIDE {}
virtual void PrepareProfile(const UserContext& credentials,
const std::string& display_email,
- bool using_oauth,
bool has_cookies,
bool has_active_session,
Delegate* delegate) OVERRIDE;
diff --git a/chrome/browser/chromeos/login/user.cc b/chrome/browser/chromeos/login/user.cc
index e2cedfc23d..33b38e27ec 100644
--- a/chrome/browser/chromeos/login/user.cc
+++ b/chrome/browser/chromeos/login/user.cc
@@ -104,7 +104,7 @@ class PublicAccountUser : public User {
DISALLOW_COPY_AND_ASSIGN(PublicAccountUser);
};
-UserContext::UserContext() {
+UserContext::UserContext() : using_oauth(true) {
}
UserContext::UserContext(const std::string& username,
@@ -112,7 +112,8 @@ UserContext::UserContext(const std::string& username,
const std::string& auth_code)
: username(username),
password(password),
- auth_code(auth_code) {
+ auth_code(auth_code),
+ using_oauth(true) {
}
UserContext::UserContext(const std::string& username,
@@ -122,7 +123,20 @@ UserContext::UserContext(const std::string& username,
: username(username),
password(password),
auth_code(auth_code),
- username_hash(username_hash) {
+ username_hash(username_hash),
+ using_oauth(true) {
+}
+
+UserContext::UserContext(const std::string& username,
+ const std::string& password,
+ const std::string& auth_code,
+ const std::string& username_hash,
+ bool using_oauth)
+ : username(username),
+ password(password),
+ auth_code(auth_code),
+ username_hash(username_hash),
+ using_oauth(using_oauth) {
}
UserContext::~UserContext() {
@@ -132,7 +146,8 @@ bool UserContext::operator==(const UserContext& context) const {
return context.username == username &&
context.password == password &&
context.auth_code == auth_code &&
- context.username_hash == username_hash;
+ context.username_hash == username_hash &&
+ context.using_oauth == using_oauth;
}
string16 User::GetDisplayName() const {
diff --git a/chrome/browser/chromeos/login/user.h b/chrome/browser/chromeos/login/user.h
index 60b8670e4f..c8a15b5dd1 100644
--- a/chrome/browser/chromeos/login/user.h
+++ b/chrome/browser/chromeos/login/user.h
@@ -32,12 +32,18 @@ struct UserContext {
const std::string& password,
const std::string& auth_code,
const std::string& username_hash);
+ UserContext(const std::string& username,
+ const std::string& password,
+ const std::string& auth_code,
+ const std::string& username_hash,
+ bool using_oauth);
virtual ~UserContext();
bool operator==(const UserContext& context) const;
std::string username;
std::string password;
std::string auth_code;
std::string username_hash;
+ bool using_oauth;
};
// A class representing information about a previously logged in user.
@@ -163,6 +169,7 @@ class User {
virtual bool is_active() const;
protected:
+ friend class SupervisedUserManagerImpl;
friend class UserManagerImpl;
friend class UserImageManagerImpl;
// For testing:
diff --git a/chrome/browser/chromeos/login/user_manager.h b/chrome/browser/chromeos/login/user_manager.h
index 139fcb2287..4e59d378b6 100644
--- a/chrome/browser/chromeos/login/user_manager.h
+++ b/chrome/browser/chromeos/login/user_manager.h
@@ -16,6 +16,7 @@ namespace chromeos {
class RemoveUserDelegate;
class UserImageManager;
+class SupervisedUserManager;
// Base class for UserManagerImpl - provides a mechanism for discovering users
// who have logged into this Chrome OS device before and updating that list.
@@ -102,6 +103,7 @@ class UserManager {
virtual ~UserManager();
virtual UserImageManager* GetUserImageManager() = 0;
+ virtual SupervisedUserManager* GetSupervisedUserManager() = 0;
// Returns a list of users who have logged into this device previously. This
// is sorted by last login date with the most recent user at the beginning.
@@ -125,17 +127,17 @@ class UserManager {
// no owner for the device.
virtual const std::string& GetOwnerEmail() = 0;
- // Indicates that a user with the given |email| has just logged in. The
+ // Indicates that a user with the given |user_id| has just logged in. The
// persistent list is updated accordingly if the user is not ephemeral.
// |browser_restart| is true when reloading Chrome after crash to distinguish
// from normal sign in flow.
// |username_hash| is used to identify homedir mount point.
- virtual void UserLoggedIn(const std::string& email,
+ virtual void UserLoggedIn(const std::string& user_id,
const std::string& username_hash,
bool browser_restart) = 0;
- // Switches to active user identified by |email|. User has to be logged in.
- virtual void SwitchActiveUser(const std::string& email) = 0;
+ // Switches to active user identified by |user_id|. User has to be logged in.
+ virtual void SwitchActiveUser(const std::string& user_id) = 0;
// Called when browser session is started i.e. after
// browser_creator.LaunchBrowser(...) was called after user sign in.
@@ -153,48 +155,23 @@ class UserManager {
// and notifies observers.
virtual void RestoreActiveSessions() = 0;
- // Creates locally managed user with given |display_name| and|local_user_id|
- // and persists that to user list. Also links this user identified by
- // |sync_user_id| to manager with a |manager_id|.
- // Returns created user, or existing user if there already
- // was locally managed user with such display name.
- // TODO(antrim): Refactor into a single struct to have only 1 getter.
- virtual const User* CreateLocallyManagedUserRecord(
- const std::string& manager_id,
- const std::string& local_user_id,
- const std::string& sync_user_id,
- const string16& display_name) = 0;
-
- // Generates unique username for locally managed user.
- virtual std::string GenerateUniqueLocallyManagedUserId() = 0;
-
// Removes the user from the device. Note, it will verify that the given user
// isn't the owner, so calling this method for the owner will take no effect.
// Note, |delegate| can be NULL.
- virtual void RemoveUser(const std::string& email,
+ virtual void RemoveUser(const std::string& user_id,
RemoveUserDelegate* delegate) = 0;
// Removes the user from the persistent list only. Also removes the user's
// picture.
- virtual void RemoveUserFromList(const std::string& email) = 0;
+ virtual void RemoveUserFromList(const std::string& user_id) = 0;
- // Returns true if a user with the given email address is found in the
- // persistent list or currently logged in as ephemeral.
- virtual bool IsKnownUser(const std::string& email) const = 0;
+ // Returns true if a user with the given user id is found in the persistent
+ // list or currently logged in as ephemeral.
+ virtual bool IsKnownUser(const std::string& user_id) const = 0;
- // Returns the user with the given email address if found in the persistent
+ // Returns the user with the given user id if found in the persistent
// list or currently logged in as ephemeral. Returns |NULL| otherwise.
- virtual const User* FindUser(const std::string& email) const = 0;
-
- // Returns the locally managed user with the given |display_name| if found in
- // the persistent list. Returns |NULL| otherwise.
- virtual const User* FindLocallyManagedUser(
- const string16& display_name) const = 0;
-
- // Returns the locally managed user with the given |sync_id| if found in
- // the persistent list. Returns |NULL| otherwise.
- virtual const User* FindLocallyManagedUserBySyncId(
- const std::string& sync_id) const = 0;
+ virtual const User* FindUser(const std::string& user_id) const = 0;
// Returns the logged-in user.
// TODO(nkostylev): Deprecate this call, move clients to GetActiveUser().
@@ -217,59 +194,35 @@ class UserManager {
// Saves user's oauth token status in local state preferences.
virtual void SaveUserOAuthStatus(
- const std::string& username,
+ const std::string& user_id,
User::OAuthTokenStatus oauth_token_status) = 0;
// Saves user's displayed name in local state preferences.
// Ignored If there is no such user.
- virtual void SaveUserDisplayName(const std::string& username,
+ virtual void SaveUserDisplayName(const std::string& user_id,
const string16& display_name) = 0;
// Updates data upon User Account download.
- virtual void UpdateUserAccountData(const std::string& username,
+ virtual void UpdateUserAccountData(const std::string& user_id,
const string16& display_name,
const std::string& locale) = 0;
- // Returns the display name for user |username| if it is known (was
+ // Returns the display name for user |user_id| if it is known (was
// previously set by a |SaveUserDisplayName| call).
// Otherwise, returns an empty string.
virtual string16 GetUserDisplayName(
- const std::string& username) const = 0;
+ const std::string& user_id) const = 0;
// Saves user's displayed (non-canonical) email in local state preferences.
// Ignored If there is no such user.
- virtual void SaveUserDisplayEmail(const std::string& username,
+ virtual void SaveUserDisplayEmail(const std::string& user_id,
const std::string& display_email) = 0;
- // Returns the display email for user |username| if it is known (was
+ // Returns the display email for user |user_id| if it is known (was
// previously set by a |SaveUserDisplayEmail| call).
- // Otherwise, returns |username| itself.
+ // Otherwise, returns |user_id| itself.
virtual std::string GetUserDisplayEmail(
- const std::string& username) const = 0;
-
- // Returns sync_user_id for locally managed user with |managed_user_id| or
- // empty string if such user is not found or it doesn't have
- // sync_user_id defined.
- virtual std::string GetManagedUserSyncId(
- const std::string& managed_user_id) const = 0;
-
- // Returns the display name for manager of user |managed_user_id| if it is
- // known (was previously set by a |SaveUserDisplayName| call).
- // Otherwise, returns a manager id.
- virtual string16 GetManagerDisplayNameForManagedUser(
- const std::string& managed_user_id) const = 0;
-
- // Returns the user id for manager of user |managed_user_id| if it is known
- // (user is actually a managed user).
- // Otherwise, returns an empty string.
- virtual std::string GetManagerUserIdForManagedUser(
- const std::string& managed_user_id) const = 0;
-
- // Returns the display email for manager of user |managed_user_id| if it is
- // known (user is actually a managed user).
- // Otherwise, returns an empty string.
- virtual std::string GetManagerDisplayEmailForManagedUser(
- const std::string& managed_user_id) const = 0;
+ const std::string& user_id) const = 0;
// Returns true if current user is an owner.
virtual bool IsCurrentUserOwner() const = 0;
@@ -323,41 +276,30 @@ class UserManager {
// user's session.
virtual bool HasBrowserRestarted() const = 0;
- // Returns true if data stored or cached for the user with the given email
+ // Returns true if data stored or cached for the user with the given user id
// address outside that user's cryptohome (wallpaper, avatar, OAuth token
// status, display name, display email) is to be treated as ephemeral.
virtual bool IsUserNonCryptohomeDataEphemeral(
- const std::string& email) const = 0;
-
- // Create a record about starting locally managed user creation transaction.
- virtual void StartLocallyManagedUserCreationTransaction(
- const string16& display_name) = 0;
-
- // Add user id to locally managed user creation transaction record.
- virtual void SetLocallyManagedUserCreationTransactionUserId(
- const std::string& email) = 0;
-
- // Remove locally managed user creation transaction record.
- virtual void CommitLocallyManagedUserCreationTransaction() = 0;
+ const std::string& user_id) const = 0;
- // Method that allows to set |flow| for user identified by |email|.
+ // Method that allows to set |flow| for user identified by |user_id|.
// Flow should be set before login attempt.
// Takes ownership of the |flow|, |flow| will be deleted in case of login
// failure.
- virtual void SetUserFlow(const std::string& email, UserFlow* flow) = 0;
+ virtual void SetUserFlow(const std::string& user_id, UserFlow* flow) = 0;
// Return user flow for current user. Returns instance of DefaultUserFlow if
// no flow was defined for current user, or user is not logged in.
// Returned value should not be cached.
virtual UserFlow* GetCurrentUserFlow() const = 0;
- // Return user flow for user identified by |email|. Returns instance of
+ // Return user flow for user identified by |user_id|. Returns instance of
// DefaultUserFlow if no flow was defined for user.
// Returned value should not be cached.
- virtual UserFlow* GetUserFlow(const std::string& email) const = 0;
+ virtual UserFlow* GetUserFlow(const std::string& user_id) const = 0;
- // Resets user flow for user identified by |email|.
- virtual void ResetUserFlow(const std::string& email) = 0;
+ // Resets user flow for user identified by |user_id|.
+ virtual void ResetUserFlow(const std::string& user_id) = 0;
// Gets/sets chrome oauth client id and secret for kiosk app mode. The default
// values can be overridden with kiosk auth file.
@@ -379,8 +321,9 @@ class UserManager {
// Returns true if locally managed users allowed.
virtual bool AreLocallyManagedUsersAllowed() const = 0;
- // Returns profile dir for the user identified by |email|.
- virtual base::FilePath GetUserProfileDir(const std::string& email) const = 0;
+ // Returns profile dir for the user identified by |user_id|.
+ virtual base::FilePath GetUserProfileDir(const std::string& user_id)
+ const = 0;
// Changes browser locale (selects best suitable locale from different
// user settings).
diff --git a/chrome/browser/chromeos/login/user_manager_impl.cc b/chrome/browser/chromeos/login/user_manager_impl.cc
index 2066d8ea36..e332863a81 100644
--- a/chrome/browser/chromeos/login/user_manager_impl.cc
+++ b/chrome/browser/chromeos/login/user_manager_impl.cc
@@ -35,6 +35,7 @@
#include "chrome/browser/chromeos/login/multi_profile_first_run_notification.h"
#include "chrome/browser/chromeos/login/multi_profile_user_controller.h"
#include "chrome/browser/chromeos/login/remove_user_delegate.h"
+#include "chrome/browser/chromeos/login/supervised_user_manager_impl.h"
#include "chrome/browser/chromeos/login/user_image_manager_impl.h"
#include "chrome/browser/chromeos/login/wizard_controller.h"
#include "chrome/browser/chromeos/policy/device_local_account.h"
@@ -69,13 +70,13 @@ using content::BrowserThread;
namespace chromeos {
struct UpdateUserAccountDataCallbackData {
- UpdateUserAccountDataCallbackData(const std::string& username,
+ UpdateUserAccountDataCallbackData(const std::string& user_id,
const string16& display_name,
const std::string& raw_locale)
- : username_(username),
+ : user_id_(user_id),
display_name_(display_name),
raw_locale_(raw_locale) {}
- std::string username_;
+ std::string user_id_;
string16 display_name_;
std::string raw_locale_;
std::string resolved_locale_;
@@ -90,38 +91,6 @@ const char kRegularUsers[] = "LoggedInUsers";
// A vector pref of the public accounts defined on this device.
const char kPublicAccounts[] = "PublicAccounts";
-// A map from locally managed user local user id to sync user id.
-const char kManagedUserSyncId[] =
- "ManagedUserSyncId";
-
-// A map from locally managed user id to manager user id.
-const char kManagedUserManagers[] =
- "ManagedUserManagers";
-
-// A map from locally managed user id to manager display name.
-const char kManagedUserManagerNames[] =
- "ManagedUserManagerNames";
-
-// A map from locally managed user id to manager display e-mail.
-const char kManagedUserManagerDisplayEmails[] =
- "ManagedUserManagerDisplayEmails";
-
-// A vector pref of the locally managed accounts defined on this device, that
-// had not logged in yet.
-const char kLocallyManagedUsersFirstRun[] = "LocallyManagedUsersFirstRun";
-
-// A pref of the next id for locally managed users generation.
-const char kLocallyManagedUsersNextId[] =
- "LocallyManagedUsersNextId";
-
-// A pref of the next id for locally managed users generation.
-const char kLocallyManagedUserCreationTransactionDisplayName[] =
- "LocallyManagedUserCreationTransactionDisplayName";
-
-// A pref of the next id for locally managed users generation.
-const char kLocallyManagedUserCreationTransactionUserId[] =
- "LocallyManagedUserCreationTransactionUserId";
-
// A string pref that gets set when a public account is removed but a user is
// currently logged into that account, requiring the account's data to be
// removed after logout.
@@ -238,22 +207,12 @@ static void UpdateUserAccountDataImplCheckAndResolveLocale(
void UserManager::RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterListPref(kRegularUsers);
registry->RegisterListPref(kPublicAccounts);
- registry->RegisterListPref(kLocallyManagedUsersFirstRun);
- registry->RegisterIntegerPref(kLocallyManagedUsersNextId, 0);
registry->RegisterStringPref(kPublicAccountPendingDataRemoval, "");
- registry->RegisterStringPref(
- kLocallyManagedUserCreationTransactionDisplayName, "");
- registry->RegisterStringPref(
- kLocallyManagedUserCreationTransactionUserId, "");
registry->RegisterStringPref(kLastLoggedInRegularUser, "");
registry->RegisterDictionaryPref(kUserOAuthTokenStatus);
registry->RegisterDictionaryPref(kUserDisplayName);
registry->RegisterDictionaryPref(kUserDisplayEmail);
- registry->RegisterDictionaryPref(kManagedUserSyncId);
- registry->RegisterDictionaryPref(kManagedUserManagers);
- registry->RegisterDictionaryPref(kManagedUserManagerNames);
- registry->RegisterDictionaryPref(kManagedUserManagerDisplayEmails);
-
+ SupervisedUserManager::RegisterPrefs(registry);
SessionLengthLimiter::RegisterPrefs(registry);
}
@@ -270,6 +229,7 @@ UserManagerImpl::UserManagerImpl()
is_current_user_ephemeral_regular_user_(false),
ephemeral_users_enabled_(false),
user_image_manager_(new UserImageManagerImpl),
+ supervised_user_manager_(new SupervisedUserManagerImpl(this)),
manager_creation_time_(base::TimeTicks::Now()),
multi_profile_first_run_notification_(
new MultiProfileFirstRunNotification) {
@@ -329,6 +289,10 @@ UserImageManager* UserManagerImpl::GetUserImageManager() {
return user_image_manager_.get();
}
+SupervisedUserManager* UserManagerImpl::GetSupervisedUserManager() {
+ return supervised_user_manager_.get();
+}
+
const UserList& UserManagerImpl::GetUsers() const {
const_cast<UserManagerImpl*>(this)->EnsureUsersLoaded();
return users_;
@@ -377,7 +341,7 @@ const std::string& UserManagerImpl::GetOwnerEmail() {
return owner_email_;
}
-void UserManagerImpl::UserLoggedIn(const std::string& email,
+void UserManagerImpl::UserLoggedIn(const std::string& user_id,
const std::string& username_hash,
bool browser_restart) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -385,7 +349,7 @@ void UserManagerImpl::UserLoggedIn(const std::string& email,
if (!CommandLine::ForCurrentProcess()->HasSwitch(::switches::kMultiProfiles))
DCHECK(!IsUserLoggedIn());
- User* user = FindUserInListAndModify(email);
+ User* user = FindUserInListAndModify(user_id);
if (active_user_ && user) {
user->set_is_logged_in(true);
user->set_username_hash(username_hash);
@@ -400,32 +364,32 @@ void UserManagerImpl::UserLoggedIn(const std::string& email,
}
policy::DeviceLocalAccount::Type device_local_account_type;
- if (email == UserManager::kGuestUserName) {
+ if (user_id == UserManager::kGuestUserName) {
GuestUserLoggedIn();
- } else if (email == UserManager::kRetailModeUserName) {
+ } else if (user_id == UserManager::kRetailModeUserName) {
RetailModeUserLoggedIn();
- } else if (policy::IsDeviceLocalAccountUser(email,
+ } else if (policy::IsDeviceLocalAccountUser(user_id,
&device_local_account_type) &&
device_local_account_type ==
policy::DeviceLocalAccount::TYPE_KIOSK_APP) {
- KioskAppLoggedIn(email);
+ KioskAppLoggedIn(user_id);
} else {
EnsureUsersLoaded();
if (user && user->GetType() == User::USER_TYPE_PUBLIC_ACCOUNT) {
PublicAccountUserLoggedIn(user);
} else if ((user && user->GetType() == User::USER_TYPE_LOCALLY_MANAGED) ||
- (!user && gaia::ExtractDomainName(email) ==
+ (!user && gaia::ExtractDomainName(user_id) ==
UserManager::kLocallyManagedUserDomain)) {
- LocallyManagedUserLoggedIn(email);
- } else if (browser_restart && email == g_browser_process->local_state()->
+ LocallyManagedUserLoggedIn(user_id);
+ } else if (browser_restart && user_id == g_browser_process->local_state()->
GetString(kPublicAccountPendingDataRemoval)) {
- PublicAccountUserLoggedIn(User::CreatePublicAccountUser(email));
- } else if (email != owner_email_ && !user &&
+ PublicAccountUserLoggedIn(User::CreatePublicAccountUser(user_id));
+ } else if (user_id != owner_email_ && !user &&
(AreEphemeralUsersEnabled() || browser_restart)) {
- RegularUserLoggedInAsEphemeral(email);
+ RegularUserLoggedInAsEphemeral(user_id);
} else {
- RegularUserLoggedIn(email);
+ RegularUserLoggedIn(user_id);
}
// Initialize the session length limiter and start it only if
@@ -445,7 +409,7 @@ void UserManagerImpl::UserLoggedIn(const std::string& email,
if (!primary_user_) {
primary_user_ = active_user_;
if (primary_user_->GetType() == User::USER_TYPE_REGULAR)
- SendRegularUserLoginMetrics(email);
+ SendRegularUserLoginMetrics(user_id);
}
UMA_HISTOGRAM_ENUMERATION("UserManager.LoginUserType",
@@ -457,16 +421,16 @@ void UserManagerImpl::UserLoggedIn(const std::string& email,
}
g_browser_process->local_state()->SetString(kLastLoggedInRegularUser,
- (active_user_->GetType() == User::USER_TYPE_REGULAR) ? email : "");
+ (active_user_->GetType() == User::USER_TYPE_REGULAR) ? user_id : "");
NotifyOnLogin();
}
-void UserManagerImpl::SwitchActiveUser(const std::string& email) {
+void UserManagerImpl::SwitchActiveUser(const std::string& user_id) {
if (!CommandLine::ForCurrentProcess()->HasSwitch(::switches::kMultiProfiles))
return;
- User* user = FindUserAndModify(email);
+ User* user = FindUserAndModify(user_id);
if (!user) {
NOTREACHED() << "Switching to a non-existing user";
return;
@@ -520,122 +484,11 @@ void UserManagerImpl::SessionStarted() {
}
}
-std::string UserManagerImpl::GenerateUniqueLocallyManagedUserId() {
- int counter = g_browser_process->local_state()->
- GetInteger(kLocallyManagedUsersNextId);
- std::string id;
- bool user_exists;
- do {
- id = base::StringPrintf("%d@%s", counter, kLocallyManagedUserDomain);
- counter++;
- user_exists = (NULL != FindUser(id));
- DCHECK(!user_exists);
- if (user_exists) {
- LOG(ERROR) << "Locally managed user with id " << id << " already exists.";
- }
- } while (user_exists);
-
- g_browser_process->local_state()->
- SetInteger(kLocallyManagedUsersNextId, counter);
-
- g_browser_process->local_state()->CommitPendingWrite();
- return id;
-}
-
-const User* UserManagerImpl::CreateLocallyManagedUserRecord(
- const std::string& manager_id,
- const std::string& local_user_id,
- const std::string& sync_user_id,
- const string16& display_name) {
- const User* user = FindLocallyManagedUser(display_name);
- DCHECK(!user);
- if (user)
- return user;
-
- PrefService* local_state = g_browser_process->local_state();
-
- User* new_user = User::CreateLocallyManagedUser(local_user_id);
- ListPrefUpdate prefs_users_update(local_state, kRegularUsers);
- prefs_users_update->Insert(0, new base::StringValue(local_user_id));
- ListPrefUpdate prefs_new_users_update(local_state,
- kLocallyManagedUsersFirstRun);
- prefs_new_users_update->Insert(0, new base::StringValue(local_user_id));
- users_.insert(users_.begin(), new_user);
-
- const User* manager = FindUser(manager_id);
- CHECK(manager);
-
- DictionaryPrefUpdate sync_id_update(local_state, kManagedUserSyncId);
- DictionaryPrefUpdate manager_update(local_state, kManagedUserManagers);
- DictionaryPrefUpdate manager_name_update(local_state,
- kManagedUserManagerNames);
- DictionaryPrefUpdate manager_email_update(local_state,
- kManagedUserManagerDisplayEmails);
- sync_id_update->SetWithoutPathExpansion(local_user_id,
- new base::StringValue(sync_user_id));
- manager_update->SetWithoutPathExpansion(local_user_id,
- new base::StringValue(manager->email()));
- manager_name_update->SetWithoutPathExpansion(local_user_id,
- new base::StringValue(manager->GetDisplayName()));
- manager_email_update->SetWithoutPathExpansion(local_user_id,
- new base::StringValue(manager->display_email()));
-
- SaveUserDisplayName(local_user_id, display_name);
- g_browser_process->local_state()->CommitPendingWrite();
- return new_user;
-}
-
-std::string UserManagerImpl::GetManagedUserSyncId(
- const std::string& managed_user_id) const {
- PrefService* local_state = g_browser_process->local_state();
- const DictionaryValue* sync_user_ids =
- local_state->GetDictionary(kManagedUserSyncId);
- std::string result;
- sync_user_ids->GetStringWithoutPathExpansion(managed_user_id, &result);
- return result;
-}
-
-string16 UserManagerImpl::GetManagerDisplayNameForManagedUser(
- const std::string& managed_user_id) const {
- PrefService* local_state = g_browser_process->local_state();
-
- const DictionaryValue* manager_names =
- local_state->GetDictionary(kManagedUserManagerNames);
- string16 result;
- if (manager_names->GetStringWithoutPathExpansion(managed_user_id, &result) &&
- !result.empty())
- return result;
- return UTF8ToUTF16(GetManagerDisplayEmailForManagedUser(managed_user_id));
-}
-
-std::string UserManagerImpl::GetManagerUserIdForManagedUser(
- const std::string& managed_user_id) const {
- PrefService* local_state = g_browser_process->local_state();
- const DictionaryValue* manager_ids =
- local_state->GetDictionary(kManagedUserManagers);
- std::string result;
- manager_ids->GetStringWithoutPathExpansion(managed_user_id, &result);
- return result;
-}
-
-std::string UserManagerImpl::GetManagerDisplayEmailForManagedUser(
- const std::string& managed_user_id) const {
- PrefService* local_state = g_browser_process->local_state();
- const DictionaryValue* manager_mails =
- local_state->GetDictionary(kManagedUserManagerDisplayEmails);
- std::string result;
- if (manager_mails->GetStringWithoutPathExpansion(managed_user_id, &result) &&
- !result.empty()) {
- return result;
- }
- return GetManagerUserIdForManagedUser(managed_user_id);
-}
-
-void UserManagerImpl::RemoveUser(const std::string& email,
+void UserManagerImpl::RemoveUser(const std::string& user_id,
RemoveUserDelegate* delegate) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- const User* user = FindUser(email);
+ const User* user = FindUser(user_id);
if (!user || (user->GetType() != User::USER_TYPE_REGULAR &&
user->GetType() != User::USER_TYPE_LOCALLY_MANAGED))
return;
@@ -651,57 +504,32 @@ void UserManagerImpl::RemoveUser(const std::string& email,
// Sanity check: do not allow any of the the logged in users to be removed.
for (UserList::const_iterator it = logged_in_users_.begin();
it != logged_in_users_.end(); ++it) {
- if ((*it)->email() == email)
+ if ((*it)->email() == user_id)
return;
}
- RemoveUserInternal(email, delegate);
+ RemoveUserInternal(user_id, delegate);
}
-void UserManagerImpl::RemoveUserFromList(const std::string& email) {
+void UserManagerImpl::RemoveUserFromList(const std::string& user_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
EnsureUsersLoaded();
- RemoveNonCryptohomeData(email);
- delete RemoveRegularOrLocallyManagedUserFromList(email);
+ RemoveNonCryptohomeData(user_id);
+ User* user = RemoveRegularOrLocallyManagedUserFromList(user_id);
+ delete user;
// Make sure that new data is persisted to Local State.
g_browser_process->local_state()->CommitPendingWrite();
}
-bool UserManagerImpl::IsKnownUser(const std::string& email) const {
- return FindUser(email) != NULL;
+bool UserManagerImpl::IsKnownUser(const std::string& user_id) const {
+ return FindUser(user_id) != NULL;
}
-const User* UserManagerImpl::FindUser(const std::string& email) const {
+const User* UserManagerImpl::FindUser(const std::string& user_id) const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (active_user_ && active_user_->email() == email)
+ if (active_user_ && active_user_->email() == user_id)
return active_user_;
- return FindUserInList(email);
-}
-
-const User* UserManagerImpl::FindLocallyManagedUser(
- const string16& display_name) const {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- const UserList& users = GetUsers();
- for (UserList::const_iterator it = users.begin(); it != users.end(); ++it) {
- if (((*it)->GetType() == User::USER_TYPE_LOCALLY_MANAGED) &&
- ((*it)->display_name() == display_name)) {
- return *it;
- }
- }
- return NULL;
-}
-
-const User* UserManagerImpl::FindLocallyManagedUserBySyncId(
- const std::string& sync_id) const {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- const UserList& users = GetUsers();
- for (UserList::const_iterator it = users.begin(); it != users.end(); ++it) {
- if (((*it)->GetType() == User::USER_TYPE_LOCALLY_MANAGED) &&
- (GetManagedUserSyncId((*it)->email()) == sync_id)) {
- return *it;
- }
- }
- return NULL;
+ return FindUserInList(user_id);
}
const User* UserManagerImpl::GetLoggedInUser() const {
@@ -746,31 +574,31 @@ User* UserManagerImpl::GetUserByProfile(Profile* profile) const {
}
void UserManagerImpl::SaveUserOAuthStatus(
- const std::string& username,
+ const std::string& user_id,
User::OAuthTokenStatus oauth_token_status) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DVLOG(1) << "Saving user OAuth token status in Local State";
- User* user = FindUserAndModify(username);
+ User* user = FindUserAndModify(user_id);
if (user)
user->set_oauth_token_status(oauth_token_status);
- GetUserFlow(username)->HandleOAuthTokenStatusChange(oauth_token_status);
+ GetUserFlow(user_id)->HandleOAuthTokenStatusChange(oauth_token_status);
// Do not update local store if data stored or cached outside the user's
// cryptohome is to be treated as ephemeral.
- if (IsUserNonCryptohomeDataEphemeral(username))
+ if (IsUserNonCryptohomeDataEphemeral(user_id))
return;
PrefService* local_state = g_browser_process->local_state();
DictionaryPrefUpdate oauth_status_update(local_state, kUserOAuthTokenStatus);
- oauth_status_update->SetWithoutPathExpansion(username,
+ oauth_status_update->SetWithoutPathExpansion(user_id,
new base::FundamentalValue(static_cast<int>(oauth_token_status)));
}
User::OAuthTokenStatus UserManagerImpl::LoadUserOAuthStatus(
- const std::string& username) const {
+ const std::string& user_id) const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
PrefService* local_state = g_browser_process->local_state();
@@ -779,11 +607,11 @@ User::OAuthTokenStatus UserManagerImpl::LoadUserOAuthStatus(
int oauth_token_status = User::OAUTH_TOKEN_STATUS_UNKNOWN;
if (prefs_oauth_status &&
prefs_oauth_status->GetIntegerWithoutPathExpansion(
- username, &oauth_token_status)) {
+ user_id, &oauth_token_status)) {
User::OAuthTokenStatus result =
static_cast<User::OAuthTokenStatus>(oauth_token_status);
if (result == User::OAUTH2_TOKEN_STATUS_INVALID)
- GetUserFlow(username)->HandleOAuthTokenStatusChange(result);
+ GetUserFlow(user_id)->HandleOAuthTokenStatusChange(result);
return result;
}
return User::OAUTH_TOKEN_STATUS_UNKNOWN;
@@ -834,30 +662,14 @@ void UserManagerImpl::UpdateUserAccountDataImplCallback(
username,
new base::StringValue(display_name));
- // Update name if this user is manager of some managed users.
- const DictionaryValue* manager_ids =
- local_state->GetDictionary(kManagedUserManagers);
-
- DictionaryPrefUpdate manager_name_update(local_state,
- kManagedUserManagerNames);
- for (DictionaryValue::Iterator it(*manager_ids); !it.IsAtEnd();
- it.Advance()) {
- std::string manager_id;
- bool has_manager_id = it.value().GetAsString(&manager_id);
- DCHECK(has_manager_id);
- if (manager_id == username) {
- manager_name_update->SetWithoutPathExpansion(
- it.key(),
- new base::StringValue(display_name));
- }
- }
+ supervised_user_manager_->UpdateManagerName(username, display_name);
}
// Proxy for the previous call.
void UserManagerImpl::UpdateUserAccountDataImplCallbackDecorator(
const scoped_ptr<UpdateUserAccountDataCallbackData>& data) {
UpdateUserAccountDataImplCallback(
- data->username_, data->display_name_, &(data->resolved_locale_));
+ data->user_id_, data->display_name_, &(data->resolved_locale_));
}
void UserManagerImpl::UpdateUserAccountDataImpl(const std::string& username,
@@ -1134,19 +946,19 @@ bool UserManagerImpl::HasBrowserRestarted() const {
}
bool UserManagerImpl::IsUserNonCryptohomeDataEphemeral(
- const std::string& email) const {
+ const std::string& user_id) const {
// Data belonging to the guest, retail mode and stub users is always
// ephemeral.
- if (email == UserManager::kGuestUserName ||
- email == UserManager::kRetailModeUserName ||
- email == kStubUser) {
+ if (user_id == UserManager::kGuestUserName ||
+ user_id == UserManager::kRetailModeUserName ||
+ user_id == kStubUser) {
return true;
}
// Data belonging to the owner, anyone found on the user list and obsolete
// public accounts whose data has not been removed yet is not ephemeral.
- if (email == owner_email_ || FindUserInList(email) ||
- email == g_browser_process->local_state()->
+ if (user_id == owner_email_ || FindUserInList(user_id) ||
+ user_id == g_browser_process->local_state()->
GetString(kPublicAccountPendingDataRemoval)) {
return false;
}
@@ -1156,7 +968,7 @@ bool UserManagerImpl::IsUserNonCryptohomeDataEphemeral(
// was enabled.
// - or -
// b) The user logged into any other account type.
- if (IsUserLoggedIn() && (email == GetLoggedInUser()->email()) &&
+ if (IsUserLoggedIn() && (user_id == GetLoggedInUser()->email()) &&
(is_current_user_ephemeral_regular_user_ || !IsLoggedInAsRegularUser())) {
return true;
}
@@ -1224,8 +1036,8 @@ void UserManagerImpl::EnsureUsersLoaded() {
users_loaded_ = true;
// Clean up user list first.
- if (HasFailedLocallyManagedUserCreationTransaction())
- RollbackLocallyManagedUserCreationTransaction();
+ if (supervised_user_manager_->HasFailedUserCreationTransaction())
+ supervised_user_manager_->RollbackUserCreationTransaction();
PrefService* local_state = g_browser_process->local_state();
const ListValue* prefs_regular_users = local_state->GetList(kRegularUsers);
@@ -1336,26 +1148,26 @@ UserList& UserManagerImpl::GetUsersAndModify() {
return users_;
}
-User* UserManagerImpl::FindUserAndModify(const std::string& email) {
+User* UserManagerImpl::FindUserAndModify(const std::string& user_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (active_user_ && active_user_->email() == email)
+ if (active_user_ && active_user_->email() == user_id)
return active_user_;
- return FindUserInListAndModify(email);
+ return FindUserInListAndModify(user_id);
}
-const User* UserManagerImpl::FindUserInList(const std::string& email) const {
+const User* UserManagerImpl::FindUserInList(const std::string& user_id) const {
const UserList& users = GetUsers();
for (UserList::const_iterator it = users.begin(); it != users.end(); ++it) {
- if ((*it)->email() == email)
+ if ((*it)->email() == user_id)
return *it;
}
return NULL;
}
-User* UserManagerImpl::FindUserInListAndModify(const std::string& email) {
+User* UserManagerImpl::FindUserInListAndModify(const std::string& user_id) {
UserList& users = GetUsersAndModify();
for (UserList::iterator it = users.begin(); it != users.end(); ++it) {
- if ((*it)->email() == email)
+ if ((*it)->email() == user_id)
return *it;
}
return NULL;
@@ -1373,63 +1185,66 @@ void UserManagerImpl::GuestUserLoggedIn() {
false);
}
-void UserManagerImpl::RegularUserLoggedIn(const std::string& email) {
+void UserManagerImpl::AddUserRecord(User* user) {
+ // Add the user to the front of the user list.
+ ListPrefUpdate prefs_users_update(g_browser_process->local_state(),
+ kRegularUsers);
+ prefs_users_update->Insert(0, new base::StringValue(user->email()));
+ users_.insert(users_.begin(), user);
+}
+
+void UserManagerImpl::RegularUserLoggedIn(const std::string& user_id) {
// Remove the user from the user list.
- active_user_ = RemoveRegularOrLocallyManagedUserFromList(email);
+ active_user_ = RemoveRegularOrLocallyManagedUserFromList(user_id);
// If the user was not found on the user list, create a new user.
is_current_user_new_ = !active_user_;
if (!active_user_) {
- active_user_ = User::CreateRegularUser(email);
- active_user_->set_oauth_token_status(LoadUserOAuthStatus(email));
+ active_user_ = User::CreateRegularUser(user_id);
+ active_user_->set_oauth_token_status(LoadUserOAuthStatus(user_id));
SaveUserDisplayName(active_user_->email(),
UTF8ToUTF16(active_user_->GetAccountName(true)));
- WallpaperManager::Get()->SetInitialUserWallpaper(email, true);
+ WallpaperManager::Get()->SetInitialUserWallpaper(user_id, true);
}
- // Add the user to the front of the user list.
- ListPrefUpdate prefs_users_update(g_browser_process->local_state(),
- kRegularUsers);
- prefs_users_update->Insert(0, new base::StringValue(email));
- users_.insert(users_.begin(), active_user_);
+ AddUserRecord(active_user_);
- user_image_manager_->UserLoggedIn(email, is_current_user_new_, false);
+ user_image_manager_->UserLoggedIn(user_id, is_current_user_new_, false);
WallpaperManager::Get()->EnsureLoggedInUserWallpaperLoaded();
- default_pinned_apps_field_trial::SetupForUser(email, is_current_user_new_);
+ default_pinned_apps_field_trial::SetupForUser(user_id, is_current_user_new_);
// Make sure that new data is persisted to Local State.
g_browser_process->local_state()->CommitPendingWrite();
}
-void UserManagerImpl::RegularUserLoggedInAsEphemeral(const std::string& email) {
+void UserManagerImpl::RegularUserLoggedInAsEphemeral(
+ const std::string& user_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
is_current_user_new_ = true;
is_current_user_ephemeral_regular_user_ = true;
- active_user_ = User::CreateRegularUser(email);
- user_image_manager_->UserLoggedIn(email, is_current_user_new_, false);
- WallpaperManager::Get()->SetInitialUserWallpaper(email, false);
+ active_user_ = User::CreateRegularUser(user_id);
+ user_image_manager_->UserLoggedIn(user_id, is_current_user_new_, false);
+ WallpaperManager::Get()->SetInitialUserWallpaper(user_id, false);
}
void UserManagerImpl::LocallyManagedUserLoggedIn(
- const std::string& username) {
+ const std::string& user_id) {
// TODO(nkostylev): Refactor, share code with RegularUserLoggedIn().
// Remove the user from the user list.
- active_user_ = RemoveRegularOrLocallyManagedUserFromList(username);
+ active_user_ = RemoveRegularOrLocallyManagedUserFromList(user_id);
// If the user was not found on the user list, create a new user.
if (!active_user_) {
is_current_user_new_ = true;
- active_user_ = User::CreateLocallyManagedUser(username);
+ active_user_ = User::CreateLocallyManagedUser(user_id);
// Leaving OAuth token status at the default state = unknown.
- WallpaperManager::Get()->SetInitialUserWallpaper(username, true);
+ WallpaperManager::Get()->SetInitialUserWallpaper(user_id, true);
} else {
- ListPrefUpdate prefs_new_users_update(g_browser_process->local_state(),
- kLocallyManagedUsersFirstRun);
- if (prefs_new_users_update->Remove(base::StringValue(username), NULL)) {
+ if (supervised_user_manager_->CheckForFirstRun(user_id)) {
is_current_user_new_ = true;
- WallpaperManager::Get()->SetInitialUserWallpaper(username, true);
+ WallpaperManager::Get()->SetInitialUserWallpaper(user_id, true);
} else {
is_current_user_new_ = false;
}
@@ -1438,7 +1253,7 @@ void UserManagerImpl::LocallyManagedUserLoggedIn(
// Add the user to the front of the user list.
ListPrefUpdate prefs_users_update(g_browser_process->local_state(),
kRegularUsers);
- prefs_users_update->Insert(0, new base::StringValue(username));
+ prefs_users_update->Insert(0, new base::StringValue(user_id));
users_.insert(users_.begin(), active_user_);
// Now that user is in the list, save display name.
@@ -1447,7 +1262,7 @@ void UserManagerImpl::LocallyManagedUserLoggedIn(
active_user_->GetDisplayName());
}
- user_image_manager_->UserLoggedIn(username, is_current_user_new_, true);
+ user_image_manager_->UserLoggedIn(user_id, is_current_user_new_, true);
WallpaperManager::Get()->EnsureLoggedInUserWallpaperLoaded();
// Make sure that new data is persisted to Local State.
@@ -1548,37 +1363,25 @@ void UserManagerImpl::UpdateOwnership() {
SetCurrentUserIsOwner(is_owner);
}
-void UserManagerImpl::RemoveNonCryptohomeData(const std::string& email) {
- WallpaperManager::Get()->RemoveUserWallpaperInfo(email);
- user_image_manager_->DeleteUserImage(email);
+void UserManagerImpl::RemoveNonCryptohomeData(const std::string& user_id) {
+ WallpaperManager::Get()->RemoveUserWallpaperInfo(user_id);
+ user_image_manager_->DeleteUserImage(user_id);
PrefService* prefs = g_browser_process->local_state();
DictionaryPrefUpdate prefs_oauth_update(prefs, kUserOAuthTokenStatus);
int oauth_status;
- prefs_oauth_update->GetIntegerWithoutPathExpansion(email, &oauth_status);
- prefs_oauth_update->RemoveWithoutPathExpansion(email, NULL);
+ prefs_oauth_update->GetIntegerWithoutPathExpansion(user_id, &oauth_status);
+ prefs_oauth_update->RemoveWithoutPathExpansion(user_id, NULL);
DictionaryPrefUpdate prefs_display_name_update(prefs, kUserDisplayName);
- prefs_display_name_update->RemoveWithoutPathExpansion(email, NULL);
+ prefs_display_name_update->RemoveWithoutPathExpansion(user_id, NULL);
DictionaryPrefUpdate prefs_display_email_update(prefs, kUserDisplayEmail);
- prefs_display_email_update->RemoveWithoutPathExpansion(email, NULL);
-
- ListPrefUpdate prefs_new_users_update(prefs, kLocallyManagedUsersFirstRun);
- prefs_new_users_update->Remove(base::StringValue(email), NULL);
+ prefs_display_email_update->RemoveWithoutPathExpansion(user_id, NULL);
- DictionaryPrefUpdate managers_update(prefs, kManagedUserManagers);
- managers_update->RemoveWithoutPathExpansion(email, NULL);
+ supervised_user_manager_->RemoveNonCryptohomeData(user_id);
- DictionaryPrefUpdate manager_names_update(prefs,
- kManagedUserManagerNames);
- manager_names_update->RemoveWithoutPathExpansion(email, NULL);
-
- DictionaryPrefUpdate manager_emails_update(prefs,
- kManagedUserManagerDisplayEmails);
- manager_emails_update->RemoveWithoutPathExpansion(email, NULL);
-
- multi_profile_user_controller_->RemoveCachedValue(email);
+ multi_profile_user_controller_->RemoveCachedValue(user_id);
}
User* UserManagerImpl::RemoveRegularOrLocallyManagedUserFromList(
@@ -1737,74 +1540,6 @@ void UserManagerImpl::UpdatePublicAccountDisplayName(
SaveUserDisplayName(username, UTF8ToUTF16(display_name));
}
-void UserManagerImpl::StartLocallyManagedUserCreationTransaction(
- const string16& display_name) {
- g_browser_process->local_state()->
- SetString(kLocallyManagedUserCreationTransactionDisplayName,
- UTF16ToASCII(display_name));
- g_browser_process->local_state()->CommitPendingWrite();
-}
-
-void UserManagerImpl::SetLocallyManagedUserCreationTransactionUserId(
- const std::string& email) {
- g_browser_process->local_state()->
- SetString(kLocallyManagedUserCreationTransactionUserId,
- email);
- g_browser_process->local_state()->CommitPendingWrite();
-}
-
-void UserManagerImpl::CommitLocallyManagedUserCreationTransaction() {
- g_browser_process->local_state()->
- ClearPref(kLocallyManagedUserCreationTransactionDisplayName);
- g_browser_process->local_state()->
- ClearPref(kLocallyManagedUserCreationTransactionUserId);
- g_browser_process->local_state()->CommitPendingWrite();
-}
-
-bool UserManagerImpl::HasFailedLocallyManagedUserCreationTransaction() {
- return !(g_browser_process->local_state()->
- GetString(kLocallyManagedUserCreationTransactionDisplayName).
- empty());
-}
-
-void UserManagerImpl::RollbackLocallyManagedUserCreationTransaction() {
- PrefService* prefs = g_browser_process->local_state();
-
- std::string display_name = prefs->
- GetString(kLocallyManagedUserCreationTransactionDisplayName);
- std::string user_id = prefs->
- GetString(kLocallyManagedUserCreationTransactionUserId);
-
- LOG(WARNING) << "Cleaning up transaction for "
- << display_name << "/" << user_id;
-
- if (user_id.empty()) {
- // Not much to do - just remove transaction.
- prefs->ClearPref(kLocallyManagedUserCreationTransactionDisplayName);
- return;
- }
-
- if (gaia::ExtractDomainName(user_id) != kLocallyManagedUserDomain) {
- LOG(WARNING) << "Clean up transaction for non-locally managed user found :"
- << user_id << ", will not remove data";
- prefs->ClearPref(kLocallyManagedUserCreationTransactionDisplayName);
- prefs->ClearPref(kLocallyManagedUserCreationTransactionUserId);
- return;
- }
-
- ListPrefUpdate prefs_users_update(prefs, kRegularUsers);
- prefs_users_update->Remove(base::StringValue(user_id), NULL);
-
- RemoveNonCryptohomeData(user_id);
-
- cryptohome::AsyncMethodCaller::GetInstance()->AsyncRemove(
- user_id, base::Bind(&OnRemoveUserComplete, user_id));
-
- prefs->ClearPref(kLocallyManagedUserCreationTransactionDisplayName);
- prefs->ClearPref(kLocallyManagedUserCreationTransactionUserId);
- prefs->CommitPendingWrite();
-}
-
UserFlow* UserManagerImpl::GetCurrentUserFlow() const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (!IsUserLoggedIn())
@@ -1812,23 +1547,23 @@ UserFlow* UserManagerImpl::GetCurrentUserFlow() const {
return GetUserFlow(GetLoggedInUser()->email());
}
-UserFlow* UserManagerImpl::GetUserFlow(const std::string& email) const {
+UserFlow* UserManagerImpl::GetUserFlow(const std::string& user_id) const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- FlowMap::const_iterator it = specific_flows_.find(email);
+ FlowMap::const_iterator it = specific_flows_.find(user_id);
if (it != specific_flows_.end())
return it->second;
return GetDefaultUserFlow();
}
-void UserManagerImpl::SetUserFlow(const std::string& email, UserFlow* flow) {
+void UserManagerImpl::SetUserFlow(const std::string& user_id, UserFlow* flow) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- ResetUserFlow(email);
- specific_flows_[email] = flow;
+ ResetUserFlow(user_id);
+ specific_flows_[user_id] = flow;
}
-void UserManagerImpl::ResetUserFlow(const std::string& email) {
+void UserManagerImpl::ResetUserFlow(const std::string& user_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- FlowMap::iterator it = specific_flows_.find(email);
+ FlowMap::iterator it = specific_flows_.find(user_id);
if (it != specific_flows_.end()) {
delete it->second;
specific_flows_.erase(it);
@@ -1868,14 +1603,14 @@ bool UserManagerImpl::AreLocallyManagedUsersAllowed() const {
}
base::FilePath UserManagerImpl::GetUserProfileDir(
- const std::string& email) const {
+ const std::string& user_id) const {
// TODO(dpolukhin): Remove Chrome OS specific profile path logic from
// ProfileManager and use only this function to construct profile path.
// TODO(nkostylev): Cleanup profile dir related code paths crbug.com/294233
base::FilePath profile_dir;
const CommandLine& command_line = *CommandLine::ForCurrentProcess();
if (command_line.HasSwitch(::switches::kMultiProfiles)) {
- const User* user = FindUser(email);
+ const User* user = FindUser(user_id);
if (user && !user->username_hash().empty()) {
profile_dir = base::FilePath(
chrome::kProfileDirPrefix + user->username_hash());
@@ -2041,9 +1776,9 @@ void UserManagerImpl::RestorePendingUserSessions() {
LoginUtils::Get()->PrepareProfile(UserContext(user_id,
std::string(), // password
std::string(), // auth_code
- user_id_hash),
+ user_id_hash,
+ false), // using_oauth
std::string(), // display_email
- false, // using_oauth
false, // has_cookies
true, // has_active_session
this);
@@ -2052,7 +1787,7 @@ void UserManagerImpl::RestorePendingUserSessions() {
}
}
-void UserManagerImpl::SendRegularUserLoginMetrics(const std::string& email) {
+void UserManagerImpl::SendRegularUserLoginMetrics(const std::string& user_id) {
// If this isn't the first time Chrome was run after the system booted,
// assume that Chrome was restarted because a previous session ended.
if (!CommandLine::ForCurrentProcess()->HasSwitch(
@@ -2061,7 +1796,7 @@ void UserManagerImpl::SendRegularUserLoginMetrics(const std::string& email) {
g_browser_process->local_state()->GetString(kLastLoggedInRegularUser);
const base::TimeDelta time_to_login =
base::TimeTicks::Now() - manager_creation_time_;
- if (!last_email.empty() && email != last_email &&
+ if (!last_email.empty() && user_id != last_email &&
time_to_login.InSeconds() <= kLogoutToLoginDelayMaxSec) {
UMA_HISTOGRAM_CUSTOM_COUNTS("UserManager.LogoutToLoginDelay",
time_to_login.InSeconds(), 0, kLogoutToLoginDelayMaxSec, 50);
diff --git a/chrome/browser/chromeos/login/user_manager_impl.h b/chrome/browser/chromeos/login/user_manager_impl.h
index 238f0c8be8..df38699fa7 100644
--- a/chrome/browser/chromeos/login/user_manager_impl.h
+++ b/chrome/browser/chromeos/login/user_manager_impl.h
@@ -39,6 +39,7 @@ namespace chromeos {
class MultiProfileFirstRunNotification;
class MultiProfileUserController;
class RemoveUserDelegate;
+class SupervisedUserManagerImpl;
class SessionLengthLimiter;
struct UpdateUserAccountDataCallbackData;
@@ -56,27 +57,24 @@ class UserManagerImpl
// UserManager implementation:
virtual void Shutdown() OVERRIDE;
virtual UserImageManager* GetUserImageManager() OVERRIDE;
+ virtual SupervisedUserManager* GetSupervisedUserManager() OVERRIDE;
virtual const UserList& GetUsers() const OVERRIDE;
virtual UserList GetUsersAdmittedForMultiProfile() const OVERRIDE;
virtual const UserList& GetLoggedInUsers() const OVERRIDE;
virtual const UserList& GetLRULoggedInUsers() OVERRIDE;
virtual UserList GetUnlockUsers() const OVERRIDE;
virtual const std::string& GetOwnerEmail() OVERRIDE;
- virtual void UserLoggedIn(const std::string& email,
- const std::string& username_hash,
+ virtual void UserLoggedIn(const std::string& user_id,
+ const std::string& user_id_hash,
bool browser_restart) OVERRIDE;
- virtual void SwitchActiveUser(const std::string& email) OVERRIDE;
+ virtual void SwitchActiveUser(const std::string& user_id) OVERRIDE;
virtual void RestoreActiveSessions() OVERRIDE;
virtual void SessionStarted() OVERRIDE;
- virtual void RemoveUser(const std::string& email,
+ virtual void RemoveUser(const std::string& user_id,
RemoveUserDelegate* delegate) OVERRIDE;
- virtual void RemoveUserFromList(const std::string& email) OVERRIDE;
- virtual bool IsKnownUser(const std::string& email) const OVERRIDE;
- virtual const User* FindUser(const std::string& email) const OVERRIDE;
- virtual const User* FindLocallyManagedUser(
- const string16& display_name) const OVERRIDE;
- virtual const User* FindLocallyManagedUserBySyncId(
- const std::string& sync_id) const OVERRIDE;
+ virtual void RemoveUserFromList(const std::string& user_id) OVERRIDE;
+ virtual bool IsKnownUser(const std::string& user_id) const OVERRIDE;
+ virtual const User* FindUser(const std::string& user_id) const OVERRIDE;
virtual const User* GetLoggedInUser() const OVERRIDE;
virtual User* GetLoggedInUser() OVERRIDE;
virtual const User* GetActiveUser() const OVERRIDE;
@@ -84,27 +82,19 @@ class UserManagerImpl
virtual const User* GetPrimaryUser() const OVERRIDE;
virtual User* GetUserByProfile(Profile* profile) const OVERRIDE;
virtual void SaveUserOAuthStatus(
- const std::string& username,
+ const std::string& user_id,
User::OAuthTokenStatus oauth_token_status) OVERRIDE;
- virtual void SaveUserDisplayName(const std::string& username,
+ virtual void SaveUserDisplayName(const std::string& user_id,
const string16& display_name) OVERRIDE;
- virtual void UpdateUserAccountData(const std::string& username,
+ virtual void UpdateUserAccountData(const std::string& user_id,
const string16& display_name,
const std::string& locale) OVERRIDE;
virtual string16 GetUserDisplayName(
- const std::string& username) const OVERRIDE;
- virtual void SaveUserDisplayEmail(const std::string& username,
+ const std::string& user_id) const OVERRIDE;
+ virtual void SaveUserDisplayEmail(const std::string& user_id,
const std::string& display_email) OVERRIDE;
virtual std::string GetUserDisplayEmail(
- const std::string& username) const OVERRIDE;
- virtual std::string GetManagedUserSyncId(
- const std::string& managed_user_id) const OVERRIDE;
- virtual string16 GetManagerDisplayNameForManagedUser(
- const std::string& managed_user_id) const OVERRIDE;
- virtual std::string GetManagerUserIdForManagedUser(
- const std::string& managed_user_id) const OVERRIDE;
- virtual std::string GetManagerDisplayEmailForManagedUser(
- const std::string& managed_user_id) const OVERRIDE;
+ const std::string& user_id) const OVERRIDE;
virtual bool IsCurrentUserOwner() const OVERRIDE;
virtual bool IsCurrentUserNew() const OVERRIDE;
virtual bool IsCurrentUserNonCryptohomeDataEphemeral() const OVERRIDE;
@@ -121,7 +111,7 @@ class UserManagerImpl
virtual bool UserSessionsRestored() const OVERRIDE;
virtual bool HasBrowserRestarted() const OVERRIDE;
virtual bool IsUserNonCryptohomeDataEphemeral(
- const std::string& email) const OVERRIDE;
+ const std::string& user_id) const OVERRIDE;
virtual void AddObserver(UserManager::Observer* obs) OVERRIDE;
virtual void RemoveObserver(UserManager::Observer* obs) OVERRIDE;
virtual void AddSessionStateObserver(
@@ -129,22 +119,11 @@ class UserManagerImpl
virtual void RemoveSessionStateObserver(
UserManager::UserSessionStateObserver* obs) OVERRIDE;
virtual void NotifyLocalStateChanged() OVERRIDE;
- virtual const User* CreateLocallyManagedUserRecord(
- const std::string& manager_id,
- const std::string& local_user_id,
- const std::string& sync_user_id,
- const string16& display_name) OVERRIDE;
- virtual std::string GenerateUniqueLocallyManagedUserId() OVERRIDE;
- virtual void StartLocallyManagedUserCreationTransaction(
- const string16& display_name) OVERRIDE;
- virtual void SetLocallyManagedUserCreationTransactionUserId(
- const std::string& email) OVERRIDE;
- virtual void CommitLocallyManagedUserCreationTransaction() OVERRIDE;
virtual UserFlow* GetCurrentUserFlow() const OVERRIDE;
- virtual UserFlow* GetUserFlow(const std::string& email) const OVERRIDE;
- virtual void SetUserFlow(const std::string& email, UserFlow* flow) OVERRIDE;
- virtual void ResetUserFlow(const std::string& email) OVERRIDE;
+ virtual UserFlow* GetUserFlow(const std::string& user_id) const OVERRIDE;
+ virtual void SetUserFlow(const std::string& user_id, UserFlow* flow) OVERRIDE;
+ virtual void ResetUserFlow(const std::string& user_id) OVERRIDE;
virtual bool GetAppModeChromeClientOAuthInfo(
std::string* chrome_client_id,
std::string* chrome_client_secret) OVERRIDE;
@@ -153,7 +132,7 @@ class UserManagerImpl
const std::string& chrome_client_secret) OVERRIDE;
virtual bool AreLocallyManagedUsersAllowed() const OVERRIDE;
virtual base::FilePath GetUserProfileDir(
- const std::string& email) const OVERRIDE;
+ const std::string& user_id) const OVERRIDE;
// content::NotificationObserver implementation.
virtual void Observe(int type,
@@ -168,6 +147,7 @@ class UserManagerImpl
OVERRIDE;
private:
+ friend class SupervisedUserManagerImpl;
friend class UserManager;
friend class WallpaperManager;
friend class UserManagerTest;
@@ -199,26 +179,26 @@ class UserManagerImpl
// Returns the user with the given email address if found in the persistent
// list or currently logged in as ephemeral. Returns |NULL| otherwise.
// Same as FindUser but returns non-const pointer to User object.
- User* FindUserAndModify(const std::string& email);
+ User* FindUserAndModify(const std::string& user_id);
// Returns the user with the given email address if found in the persistent
// list. Returns |NULL| otherwise.
- const User* FindUserInList(const std::string& email) const;
+ const User* FindUserInList(const std::string& user_id) const;
// Same as FindUserInList but returns non-const pointer to User object.
- User* FindUserInListAndModify(const std::string& email);
+ User* FindUserInListAndModify(const std::string& user_id);
// Indicates that a user just logged in as guest.
void GuestUserLoggedIn();
// Indicates that a regular user just logged in.
- void RegularUserLoggedIn(const std::string& email);
+ void RegularUserLoggedIn(const std::string& user_id);
// Indicates that a regular user just logged in as ephemeral.
- void RegularUserLoggedInAsEphemeral(const std::string& email);
+ void RegularUserLoggedInAsEphemeral(const std::string& user_id);
// Indicates that a locally managed user just logged in.
- void LocallyManagedUserLoggedIn(const std::string& username);
+ void LocallyManagedUserLoggedIn(const std::string& user_id);
// Indicates that a user just logged into a public session.
void PublicAccountUserLoggedIn(User* user);
@@ -234,7 +214,7 @@ class UserManagerImpl
void NotifyOnLogin();
// Reads user's oauth token status from local state preferences.
- User::OAuthTokenStatus LoadUserOAuthStatus(const std::string& username) const;
+ User::OAuthTokenStatus LoadUserOAuthStatus(const std::string& user_id) const;
void SetCurrentUserIsOwner(bool is_current_user_owner);
@@ -243,12 +223,12 @@ class UserManagerImpl
// Removes data stored or cached outside the user's cryptohome (wallpaper,
// avatar, OAuth token status, display name, display email).
- void RemoveNonCryptohomeData(const std::string& email);
+ void RemoveNonCryptohomeData(const std::string& user_id);
// Removes a regular or locally managed user from the user list.
// Returns the user if found or NULL otherwise.
// Also removes the user from the persistent user list.
- User* RemoveRegularOrLocallyManagedUserFromList(const std::string& username);
+ User* RemoveRegularOrLocallyManagedUserFromList(const std::string& user_id);
// If data for a public account is marked as pending removal and the user is
// no longer logged into that account, removes the data.
@@ -271,7 +251,7 @@ class UserManagerImpl
// Updates the display name for public account |username| from policy settings
// associated with that username.
- void UpdatePublicAccountDisplayName(const std::string& username);
+ void UpdatePublicAccountDisplayName(const std::string& user_id);
// Notifies the UI about a change to the user list.
void NotifyUserListChanged();
@@ -291,12 +271,6 @@ class UserManagerImpl
// Notifies observers that user pending sessions restore has finished.
void NotifyPendingUserSessionsRestoreFinished();
- // Returns true if there is non-committed user creation transaction.
- bool HasFailedLocallyManagedUserCreationTransaction();
-
- // Attempts to clean up data that could be left from failed user creation.
- void RollbackLocallyManagedUserCreationTransaction();
-
// Lazily creates default user flow.
UserFlow* GetDefaultUserFlow() const;
@@ -306,6 +280,10 @@ class UserManagerImpl
// Insert |user| at the front of the LRU user list..
void SetLRUUser(User* user);
+ // Adds |user| to users list, and adds it to front of LRU list. It is assumed
+ // that there is no user with same id.
+ void AddUserRecord(User* user);
+
// Callback to process RetrieveActiveSessions() request results.
void OnRestoreActiveSessions(
const SessionManagerClient::ActiveSessionsMap& sessions,
@@ -318,17 +296,17 @@ class UserManagerImpl
void RestorePendingUserSessions();
// Sends metrics in response to a regular user logging in.
- void SendRegularUserLoginMetrics(const std::string& email);
+ void SendRegularUserLoginMetrics(const std::string& user_id);
// UpdateUserAccountData() + SaveUserDisplayName() .
- void UpdateUserAccountDataImpl(const std::string& username,
+ void UpdateUserAccountDataImpl(const std::string& user_id,
const string16& display_name,
const std::string* locale);
// Account locale needs to be translated to device locale.
// This might be called as callback after FILE thread translates locale.
void UpdateUserAccountDataImplCallback(
- const std::string& username,
+ const std::string& user_id,
const string16& display_name,
const std::string* resolved_account_locale);
@@ -424,6 +402,9 @@ class UserManagerImpl
// User avatar manager.
scoped_ptr<UserImageManagerImpl> user_image_manager_;
+ // Supervised user manager.
+ scoped_ptr<SupervisedUserManagerImpl> supervised_user_manager_;
+
// Session length limiter.
scoped_ptr<SessionLengthLimiter> session_length_limiter_;
diff --git a/chrome/browser/chromeos/login/wallpaper_manager.cc b/chrome/browser/chromeos/login/wallpaper_manager.cc
index 7fafe4dd2a..eead099677 100644
--- a/chrome/browser/chromeos/login/wallpaper_manager.cc
+++ b/chrome/browser/chromeos/login/wallpaper_manager.cc
@@ -57,9 +57,6 @@ const int kDefaultEncodingQuality = 90;
// Deprecated. Will remove this const char after done migration.
const char kUserWallpapers[] = "UserWallpapers";
-const int kThumbnailWidth = 128;
-const int kThumbnailHeight = 80;
-
const int kCacheWallpaperDelayMs = 500;
// A dictionary pref that maps usernames to wallpaper properties.
diff --git a/chrome/browser/chromeos/login/wallpaper_manager_unittest.cc b/chrome/browser/chromeos/login/wallpaper_manager_unittest.cc
index 0e3e7a8504..8f3391baa7 100644
--- a/chrome/browser/chromeos/login/wallpaper_manager_unittest.cc
+++ b/chrome/browser/chromeos/login/wallpaper_manager_unittest.cc
@@ -30,16 +30,9 @@
using namespace ash;
-namespace {
-
const char kTestUser1[] = "test-user@example.com";
const char kTestUser1Hash[] = "test-user@example.com-hash";
-const int kLargeWallpaperResourceId = IDR_AURA_WALLPAPER_DEFAULT_LARGE;
-const int kSmallWallpaperResourceId = IDR_AURA_WALLPAPER_DEFAULT_SMALL;
-
-} // namespace
-
namespace chromeos {
class WallpaperManagerTest : public test::AshTestBase {
diff --git a/chrome/browser/chromeos/login/webui_login_view.cc b/chrome/browser/chromeos/login/webui_login_view.cc
index 3e14fff2b5..8bd3004463 100644
--- a/chrome/browser/chromeos/login/webui_login_view.cc
+++ b/chrome/browser/chromeos/login/webui_login_view.cc
@@ -31,7 +31,6 @@
#include "components/web_modal/web_contents_modal_dialog_manager.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/render_view_host_observer.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_view.h"
@@ -61,39 +60,6 @@ const char kAccelNameDeviceRequisition[] = "device_requisition";
const char kAccelNameDeviceRequisitionRemora[] = "device_requisition_remora";
const char kAccelNameAppLaunchBailout[] = "app_launch_bailout";
-// Observes IPC messages from the FrameSniffer and notifies JS if error
-// appears.
-class SnifferObserver : public content::RenderViewHostObserver {
- public:
- SnifferObserver(RenderViewHost* host, content::WebUI* webui)
- : content::RenderViewHostObserver(host), webui_(webui) {
- DCHECK(webui_);
- Send(new ChromeViewMsg_StartFrameSniffer(routing_id(),
- UTF8ToUTF16("gaia-frame")));
- }
-
- virtual ~SnifferObserver() {}
-
- // IPC::Listener implementation.
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(SnifferObserver, message)
- IPC_MESSAGE_HANDLER(ChromeViewHostMsg_FrameLoadingError, OnError)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
- }
-
- private:
- void OnError(int error) {
- base::FundamentalValue error_value(error);
- webui_->CallJavascriptFunction("login.GaiaSigninScreen.onFrameError",
- error_value);
- }
-
- content::WebUI* webui_;
-};
-
// A class to change arrow key traversal behavior when it's alive.
class ScopedArrowKeyTraversal {
public:
@@ -201,13 +167,10 @@ void WebUILoginView::Init() {
SetDelegate(this);
web_contents->SetDelegate(this);
+ WebContentsObserver::Observe(web_contents);
renderer_preferences_util::UpdateFromSystemSettings(
web_contents->GetMutableRendererPrefs(),
signin_profile);
-
- registrar_.Add(this,
- content::NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED,
- content::Source<WebContents>(web_contents));
}
const char* WebUILoginView::GetClassName() const {
@@ -362,12 +325,6 @@ void WebUILoginView::Observe(int type,
registrar_.RemoveAll();
break;
}
- case content::NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED: {
- RenderViewHost* render_view_host =
- content::Details<RenderViewHost>(details).ptr();
- new SnifferObserver(render_view_host, GetWebUI());
- break;
- }
default:
NOTREACHED() << "Unexpected notification " << type;
}
@@ -434,6 +391,22 @@ void WebUILoginView::RequestMediaAccessPermission(
NOTREACHED() << "Media stream not allowed for WebUI";
}
+void WebUILoginView::DidFailProvisionalLoad(
+ int64 frame_id,
+ const string16& frame_unique_name,
+ bool is_main_frame,
+ const GURL& validated_url,
+ int error_code,
+ const string16& error_description,
+ content::RenderViewHost* render_view_host) {
+ if (frame_unique_name != UTF8ToUTF16("gaia-frame"))
+ return;
+
+ base::FundamentalValue error_value(-error_code);
+ GetWebUI()->CallJavascriptFunction("login.GaiaSigninScreen.onFrameError",
+ error_value);
+}
+
void WebUILoginView::OnLoginPromptVisible() {
// If we're hidden than will generate this signal once we're shown.
if (is_hidden_ || webui_visible_) {
diff --git a/chrome/browser/chromeos/login/webui_login_view.h b/chrome/browser/chromeos/login/webui_login_view.h
index 01e378628b..079328020e 100644
--- a/chrome/browser/chromeos/login/webui_login_view.h
+++ b/chrome/browser/chromeos/login/webui_login_view.h
@@ -16,6 +16,7 @@
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/web_contents_delegate.h"
+#include "content/public/browser/web_contents_observer.h"
#include "ui/views/controls/webview/unhandled_keyboard_event_handler.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
@@ -38,6 +39,7 @@ namespace chromeos {
// WebUI based start up and lock screens. It contains a WebView.
class WebUILoginView : public views::View,
public content::WebContentsDelegate,
+ public content::WebContentsObserver,
public content::NotificationObserver,
public ChromeWebModalDialogManagerDelegate,
public web_modal::WebContentsModalDialogHost {
@@ -135,6 +137,16 @@ class WebUILoginView : public views::View,
const content::MediaStreamRequest& request,
const content::MediaResponseCallback& callback) OVERRIDE;
+ // Overridden from content::WebContentsObserver.
+ virtual void DidFailProvisionalLoad(
+ int64 frame_id,
+ const string16& frame_unique_name,
+ bool is_main_frame,
+ const GURL& validated_url,
+ int error_code,
+ const string16& error_description,
+ content::RenderViewHost* render_view_host) OVERRIDE;
+
// Performs series of actions when login prompt is considered
// to be ready and visible.
// 1. Emits LoginPromptVisible signal if needed
diff --git a/chrome/browser/chromeos/login/webui_screen_locker.cc b/chrome/browser/chromeos/login/webui_screen_locker.cc
index a61f54a66e..ee31aab878 100644
--- a/chrome/browser/chromeos/login/webui_screen_locker.cc
+++ b/chrome/browser/chromeos/login/webui_screen_locker.cc
@@ -69,9 +69,6 @@ void WebUIScreenLocker::LockScreen() {
LoadURL(GURL(kLoginURL));
lock_window->Grab();
- // Subscribe to crash events.
- content::WebContentsObserver::Observe(GetWebContents());
-
login_display_.reset(new WebUILoginDisplay(this));
login_display_->set_background_bounds(bounds);
login_display_->set_parent_window(GetNativeWindow());
diff --git a/chrome/browser/chromeos/login/webui_screen_locker.h b/chrome/browser/chromeos/login/webui_screen_locker.h
index ad49795aab..1d97b36c72 100644
--- a/chrome/browser/chromeos/login/webui_screen_locker.h
+++ b/chrome/browser/chromeos/login/webui_screen_locker.h
@@ -19,7 +19,6 @@
#include "chromeos/dbus/power_manager_client.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
-#include "content/public/browser/web_contents_observer.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_observer.h"
@@ -49,8 +48,7 @@ class WebUIScreenLocker : public WebUILoginView,
public LockWindow::Observer,
public ash::LockStateObserver,
public views::WidgetObserver,
- public PowerManagerClient::Observer,
- public content::WebContentsObserver {
+ public PowerManagerClient::Observer {
public:
explicit WebUIScreenLocker(ScreenLocker* screen_locker);
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc
index 5bd9c5f7f1..84c9500938 100644
--- a/chrome/browser/chromeos/login/wizard_controller.cc
+++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -19,7 +19,6 @@
#include "base/prefs/pref_service.h"
#include "base/threading/thread_restrictions.h"
#include "base/values.h"
-#include "chrome/app/breakpad_linux.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
@@ -58,32 +57,19 @@
#include "chromeos/dbus/session_manager_client.h"
#include "chromeos/network/network_state_handler.h"
#include "chromeos/settings/cros_settings_names.h"
+#include "components/breakpad/app/breakpad_linux.h"
#include "content/public/browser/browser_thread.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/l10n/l10n_util.h"
using content::BrowserThread;
-namespace {
-
-// A string pref with initial locale set in VPD or manifest.
-const char kInitialLocale[] = "intl.initial_locale";
-
-// A boolean pref of the OOBE complete flag (first OOBE part before login).
-const char kOobeComplete[] = "OobeComplete";
-
-// A boolean pref of the device registered flag (second part after first login).
-const char kDeviceRegistered[] = "DeviceRegistered";
-
-// Time in seconds that we wait for the device to reboot.
// If reboot didn't happen, ask user to reboot device manually.
const int kWaitForRebootTimeSec = 3;
// Interval in ms which is used for smooth screen showing.
static int kShowDelayMs = 400;
-} // namespace
-
namespace chromeos {
const char WizardController::kNetworkScreenName[] = "network";
@@ -496,7 +482,7 @@ void WizardController::OnEulaAccepted() {
#if defined(GOOGLE_CHROME_BUILD)
// The crash reporter initialization needs IO to complete.
base::ThreadRestrictions::ScopedAllowIO allow_io;
- InitCrashReporter();
+ breakpad::InitCrashReporter();
#endif
}
@@ -634,9 +620,7 @@ void WizardController::PerformPostEulaActions() {
NetworkStateHandler::kDefaultCheckPortalList);
host_->CheckForAutoEnrollment();
host_->PrewarmAuthentication();
- NetworkPortalDetector* detector = NetworkPortalDetector::GetInstance();
- if (NetworkPortalDetector::IsEnabledInCommandLine() && detector)
- detector->Enable(true);
+ NetworkPortalDetector::Get()->Enable(true);
}
void WizardController::PerformPostUpdateActions() {
diff --git a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
index b8a2a958e3..79b278f573 100644
--- a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
+++ b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
@@ -42,8 +42,8 @@
#include "chromeos/chromeos_switches.h"
#include "chromeos/chromeos_test_utils.h"
#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/fake_dbus_thread_manager.h"
#include "chromeos/dbus/fake_session_manager_client.h"
-#include "chromeos/dbus/mock_dbus_thread_manager_without_gmock.h"
#include "chromeos/network/network_state_handler.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_utils.h"
@@ -352,7 +352,7 @@ IN_PROC_BROWSER_TEST_F(WizardControllerFlowTest,
WizardController::default_controller()->GetEnrollmentScreen();
EXPECT_EQ(screen, WizardController::default_controller()->current_screen());
// This is the main expectation: after auto-enrollment, login is resumed.
- EXPECT_CALL(mock_consumer, OnLoginSuccess(_, _, _)).Times(1);
+ EXPECT_CALL(mock_consumer, OnLoginSuccess(_)).Times(1);
OnExit(ScreenObserver::ENTERPRISE_AUTO_MAGIC_ENROLLMENT_COMPLETED);
// Prevent browser launch when the profile is prepared:
browser_shutdown::SetTryingToQuit(true);
@@ -408,11 +408,11 @@ class WizardControllerBrokenLocalStateTest : public WizardControllerTest {
virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
WizardControllerTest::SetUpInProcessBrowserTestFixture();
- MockDBusThreadManagerWithoutGMock* mock_dbus_thread_manager =
- new MockDBusThreadManagerWithoutGMock();
+ FakeDBusThreadManager* fake_dbus_thread_manager =
+ new FakeDBusThreadManager();
fake_session_manager_client_ =
- mock_dbus_thread_manager->fake_session_manager_client();
- DBusThreadManager::InitializeForTesting(mock_dbus_thread_manager);
+ fake_dbus_thread_manager->fake_session_manager_client();
+ DBusThreadManager::InitializeForTesting(fake_dbus_thread_manager);
}
virtual void SetUpOnMainThread() OVERRIDE {
diff --git a/chrome/browser/chromeos/mobile_config.cc b/chrome/browser/chromeos/mobile_config.cc
index a0503ca800..52d4dbb0d5 100644
--- a/chrome/browser/chromeos/mobile_config.cc
+++ b/chrome/browser/chromeos/mobile_config.cc
@@ -22,7 +22,6 @@ using content::BrowserThread;
namespace {
// Config attributes names.
-const char kVersionAttr[] = "version";
const char kAcceptedConfigVersion[] = "1.0";
const char kDefaultAttr[] = "default";
@@ -42,7 +41,6 @@ const char kInfoURLAttr[] = "info_url";
const char kNotificationCountAttr[] = "notification_count";
const char kDealExpireDateAttr[] = "expire_date";
const char kLocalizedContentAttr[] = "localized_content";
-const char kNotificationTextAttr[] = "notification_text";
// Initial locale carrier config attributes.
const char kInitialLocalesAttr[] = "initial_locales";
diff --git a/chrome/browser/chromeos/net/network_portal_detector.cc b/chrome/browser/chromeos/net/network_portal_detector.cc
index 1f7bf5d217..11d4074d06 100644
--- a/chrome/browser/chromeos/net/network_portal_detector.cc
+++ b/chrome/browser/chromeos/net/network_portal_detector.cc
@@ -8,7 +8,7 @@
#include "base/logging.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/net/network_portal_detector_impl.h"
-#include "chrome/browser/chromeos/net/network_portal_detector_stub.h"
+#include "chrome/browser/chromeos/net/network_portal_detector_test_impl.h"
#include "chrome/common/chrome_switches.h"
#include "chromeos/chromeos_switches.h"
@@ -17,47 +17,82 @@ namespace chromeos {
namespace {
NetworkPortalDetector* g_network_portal_detector = NULL;
+bool g_network_portal_detector_set_for_testing = false;
bool IsTestMode() {
return CommandLine::ForCurrentProcess()->HasSwitch(::switches::kTestType);
}
-} // namespace
-
-NetworkPortalDetector::NetworkPortalDetector() {
+bool IsEnabledInCommandLine() {
+ return !CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableChromeCaptivePortalDetector);
}
-NetworkPortalDetector::~NetworkPortalDetector() {
+// Stub implementation of NetworkPortalDetector.
+class NetworkPortalDetectorStubImpl : public NetworkPortalDetector {
+ protected:
+ // NetworkPortalDetector implementation:
+ virtual void AddObserver(Observer* /* observer */) OVERRIDE {}
+ virtual void AddAndFireObserver(Observer* observer) OVERRIDE {
+ if (observer)
+ observer->OnPortalDetectionCompleted(NULL, CaptivePortalState());
+ }
+ virtual void RemoveObserver(Observer* /* observer */) OVERRIDE {}
+ virtual CaptivePortalState GetCaptivePortalState(
+ const NetworkState* /* network */) OVERRIDE {
+ return CaptivePortalState();
+ }
+ virtual bool IsEnabled() OVERRIDE { return false; }
+ virtual void Enable(bool /* start_detection */) OVERRIDE {}
+ virtual bool StartDetectionIfIdle() OVERRIDE { return false; }
+ virtual void EnableLazyDetection() OVERRIDE {}
+ virtual void DisableLazyDetection() OVERRIDE {}
+};
+
+} // namespace
+
+void NetworkPortalDetector::InitializeForTesting(
+ NetworkPortalDetector* network_portal_detector) {
+ CHECK(!g_network_portal_detector)
+ << "NetworkPortalDetector::InitializeForTesting() is called after "
+ << "Initialize()";
+ CHECK(network_portal_detector);
+ g_network_portal_detector = network_portal_detector;
+ g_network_portal_detector_set_for_testing = true;
}
// static
-NetworkPortalDetector* NetworkPortalDetector::CreateInstance() {
- DCHECK(!g_network_portal_detector);
- CHECK(NetworkPortalDetector::IsEnabledInCommandLine());
- if (IsTestMode()) {
- g_network_portal_detector = new NetworkPortalDetectorStub();
+void NetworkPortalDetector::Initialize() {
+ if (g_network_portal_detector_set_for_testing)
+ return;
+ CHECK(!g_network_portal_detector)
+ << "NetworkPortalDetector::Initialize() is called twice";
+ if (!IsEnabledInCommandLine() || IsTestMode()) {
+ g_network_portal_detector = new NetworkPortalDetectorStubImpl();
} else {
CHECK(g_browser_process);
CHECK(g_browser_process->system_request_context());
g_network_portal_detector = new NetworkPortalDetectorImpl(
g_browser_process->system_request_context());
}
- return g_network_portal_detector;
}
// static
-NetworkPortalDetector* NetworkPortalDetector::GetInstance() {
- if (!NetworkPortalDetector::IsEnabledInCommandLine())
- return NULL;
- if (!g_network_portal_detector)
- return CreateInstance();
- return g_network_portal_detector;
+void NetworkPortalDetector::Shutdown() {
+ CHECK(g_network_portal_detector || g_network_portal_detector_set_for_testing)
+ << "NetworkPortalDetectorImpl::Shutdown() is called "
+ << "without previous call to Initialize()";
+ if (g_network_portal_detector) {
+ delete g_network_portal_detector;
+ g_network_portal_detector = NULL;
+ }
}
// static
-bool NetworkPortalDetector::IsEnabledInCommandLine() {
- return !CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableChromeCaptivePortalDetector);
+NetworkPortalDetector* NetworkPortalDetector::Get() {
+ CHECK(g_network_portal_detector)
+ << "NetworkPortalDetector::Get() called before Initialize()";
+ return g_network_portal_detector;
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/net/network_portal_detector.h b/chrome/browser/chromeos/net/network_portal_detector.h
index dd15575ab9..9568b53320 100644
--- a/chrome/browser/chromeos/net/network_portal_detector.h
+++ b/chrome/browser/chromeos/net/network_portal_detector.h
@@ -53,9 +53,6 @@ class NetworkPortalDetector {
virtual ~Observer() {}
};
- virtual void Init() = 0;
- virtual void Shutdown() = 0;
-
// Adds |observer| to the observers list.
virtual void AddObserver(Observer* observer) = 0;
@@ -100,18 +97,24 @@ class NetworkPortalDetector {
// Dizables lazy detection mode.
virtual void DisableLazyDetection() = 0;
+ // Initializes network portal detector for testing. The
+ // |network_portal_detector| will be owned by the internal pointer
+ // and deleted by Shutdown().
+ static void InitializeForTesting(
+ NetworkPortalDetector* network_portal_detector);
+
// Creates an instance of the NetworkPortalDetector.
- static NetworkPortalDetector* CreateInstance();
+ static void Initialize();
- // Gets the instance of the NetworkPortalDetector.
- static NetworkPortalDetector* GetInstance();
+ // Deletes the instance of the NetworkPortalDetector.
+ static void Shutdown();
- // Returns true is NetworkPortalDetector service is enabled in command line.
- static bool IsEnabledInCommandLine();
+ // Gets the instance of the NetworkPortalDetector.
+ static NetworkPortalDetector* Get();
protected:
- NetworkPortalDetector();
- virtual ~NetworkPortalDetector();
+ NetworkPortalDetector() {}
+ virtual ~NetworkPortalDetector() {}
private:
DISALLOW_COPY_AND_ASSIGN(NetworkPortalDetector);
diff --git a/chrome/browser/chromeos/net/network_portal_detector_impl.cc b/chrome/browser/chromeos/net/network_portal_detector_impl.cc
index c8c454ffe0..0088b91162 100644
--- a/chrome/browser/chromeos/net/network_portal_detector_impl.cc
+++ b/chrome/browser/chromeos/net/network_portal_detector_impl.cc
@@ -71,7 +71,8 @@ std::string CaptivePortalStatusString(
NetworkPortalDetectorImpl::NetworkPortalDetectorImpl(
const scoped_refptr<net::URLRequestContextGetter>& request_context)
- : test_url_(CaptivePortalDetector::kDefaultURL),
+ : state_(STATE_IDLE),
+ test_url_(CaptivePortalDetector::kDefaultURL),
enabled_(false),
weak_ptr_factory_(this),
attempt_count_(0),
@@ -91,20 +92,12 @@ NetworkPortalDetectorImpl::NetworkPortalDetectorImpl(
registrar_.Add(this,
chrome::NOTIFICATION_AUTH_CANCELLED,
content::NotificationService::AllSources());
-}
-
-NetworkPortalDetectorImpl::~NetworkPortalDetectorImpl() {
-}
-void NetworkPortalDetectorImpl::Init() {
- DCHECK(CalledOnValidThread());
-
- state_ = STATE_IDLE;
NetworkHandler::Get()->network_state_handler()->AddObserver(
this, FROM_HERE);
}
-void NetworkPortalDetectorImpl::Shutdown() {
+NetworkPortalDetectorImpl::~NetworkPortalDetectorImpl() {
DCHECK(CalledOnValidThread());
detection_task_.Cancel();
diff --git a/chrome/browser/chromeos/net/network_portal_detector_impl.h b/chrome/browser/chromeos/net/network_portal_detector_impl.h
index cf0c4e9537..9c7b68ebaf 100644
--- a/chrome/browser/chromeos/net/network_portal_detector_impl.h
+++ b/chrome/browser/chromeos/net/network_portal_detector_impl.h
@@ -47,8 +47,6 @@ class NetworkPortalDetectorImpl
virtual ~NetworkPortalDetectorImpl();
// NetworkPortalDetector implementation:
- virtual void Init() OVERRIDE;
- virtual void Shutdown() OVERRIDE;
virtual void AddObserver(Observer* observer) OVERRIDE;
virtual void AddAndFireObserver(Observer* observer) OVERRIDE;
virtual void RemoveObserver(Observer* observer) OVERRIDE;
diff --git a/chrome/browser/chromeos/net/network_portal_detector_impl_unittest.cc b/chrome/browser/chromeos/net/network_portal_detector_impl_unittest.cc
index 8f3c18af5b..42e1657e39 100644
--- a/chrome/browser/chromeos/net/network_portal_detector_impl_unittest.cc
+++ b/chrome/browser/chromeos/net/network_portal_detector_impl_unittest.cc
@@ -50,7 +50,6 @@ class NetworkPortalDetectorImplTest
profile_.reset(new TestingProfile());
network_portal_detector_.reset(
new NetworkPortalDetectorImpl(profile_->GetRequestContext()));
- network_portal_detector_->Init();
network_portal_detector_->Enable(false);
set_detector(network_portal_detector_->captive_portal_detector_.get());
@@ -60,7 +59,7 @@ class NetworkPortalDetectorImplTest
}
virtual void TearDown() {
- network_portal_detector_->Shutdown();
+ network_portal_detector_.reset();
profile_.reset();
NetworkHandler::Shutdown();
DBusThreadManager::Shutdown();
diff --git a/chrome/browser/chromeos/net/network_portal_detector_stub.cc b/chrome/browser/chromeos/net/network_portal_detector_test_impl.cc
index 2fd08aa811..473f0d70b1 100644
--- a/chrome/browser/chromeos/net/network_portal_detector_stub.cc
+++ b/chrome/browser/chromeos/net/network_portal_detector_test_impl.cc
@@ -1,19 +1,19 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/chromeos/net/network_portal_detector_stub.h"
+#include "chrome/browser/chromeos/net/network_portal_detector_test_impl.h"
#include "chromeos/network/network_state.h"
namespace chromeos {
-NetworkPortalDetectorStub::NetworkPortalDetectorStub() {}
+NetworkPortalDetectorTestImpl::NetworkPortalDetectorTestImpl() {}
-NetworkPortalDetectorStub::~NetworkPortalDetectorStub() {
+NetworkPortalDetectorTestImpl::~NetworkPortalDetectorTestImpl() {
}
-void NetworkPortalDetectorStub::SetDefaultNetworkPathForTesting(
+void NetworkPortalDetectorTestImpl::SetDefaultNetworkPathForTesting(
const std::string& service_path) {
if (service_path.empty())
default_network_.reset();
@@ -21,14 +21,14 @@ void NetworkPortalDetectorStub::SetDefaultNetworkPathForTesting(
default_network_.reset(new NetworkState(service_path));
}
-void NetworkPortalDetectorStub::SetDetectionResultsForTesting(
+void NetworkPortalDetectorTestImpl::SetDetectionResultsForTesting(
const std::string& service_path,
const CaptivePortalState& state) {
if (!service_path.empty())
portal_state_map_[service_path] = state;
}
-void NetworkPortalDetectorStub::NotifyObserversForTesting() {
+void NetworkPortalDetectorTestImpl::NotifyObserversForTesting() {
CaptivePortalState state;
if (default_network_ &&
portal_state_map_.count(default_network_->path())) {
@@ -38,18 +38,12 @@ void NetworkPortalDetectorStub::NotifyObserversForTesting() {
OnPortalDetectionCompleted(default_network_.get(), state));
}
-void NetworkPortalDetectorStub::Init() {
-}
-
-void NetworkPortalDetectorStub::Shutdown() {
-}
-
-void NetworkPortalDetectorStub::AddObserver(Observer* observer) {
+void NetworkPortalDetectorTestImpl::AddObserver(Observer* observer) {
if (observer && !observers_.HasObserver(observer))
observers_.AddObserver(observer);
}
-void NetworkPortalDetectorStub::AddAndFireObserver(Observer* observer) {
+void NetworkPortalDetectorTestImpl::AddAndFireObserver(Observer* observer) {
AddObserver(observer);
if (!observer)
return;
@@ -64,34 +58,34 @@ void NetworkPortalDetectorStub::AddAndFireObserver(Observer* observer) {
}
}
-void NetworkPortalDetectorStub::RemoveObserver(Observer* observer) {
+void NetworkPortalDetectorTestImpl::RemoveObserver(Observer* observer) {
if (observer)
observers_.RemoveObserver(observer);
}
NetworkPortalDetector::CaptivePortalState
-NetworkPortalDetectorStub::GetCaptivePortalState(
+NetworkPortalDetectorTestImpl::GetCaptivePortalState(
const chromeos::NetworkState* network) {
if (!network || !portal_state_map_.count(network->path()))
return CaptivePortalState();
return portal_state_map_[network->path()];
}
-bool NetworkPortalDetectorStub::IsEnabled() {
+bool NetworkPortalDetectorTestImpl::IsEnabled() {
return true;
}
-void NetworkPortalDetectorStub::Enable(bool start_detection) {
+void NetworkPortalDetectorTestImpl::Enable(bool start_detection) {
}
-bool NetworkPortalDetectorStub::StartDetectionIfIdle() {
+bool NetworkPortalDetectorTestImpl::StartDetectionIfIdle() {
return false;
}
-void NetworkPortalDetectorStub::EnableLazyDetection() {
+void NetworkPortalDetectorTestImpl::EnableLazyDetection() {
}
-void NetworkPortalDetectorStub::DisableLazyDetection() {
+void NetworkPortalDetectorTestImpl::DisableLazyDetection() {
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/net/network_portal_detector_stub.h b/chrome/browser/chromeos/net/network_portal_detector_test_impl.h
index 9494109a70..9d6f9bab6b 100644
--- a/chrome/browser/chromeos/net/network_portal_detector_stub.h
+++ b/chrome/browser/chromeos/net/network_portal_detector_test_impl.h
@@ -1,9 +1,9 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROME_BROWSER_CHROMEOS_NET_NETWORK_PORTAL_DETECTOR_STUB_H_
-#define CHROME_BROWSER_CHROMEOS_NET_NETWORK_PORTAL_DETECTOR_STUB_H_
+#ifndef CHROME_BROWSER_CHROMEOS_NET_NETWORK_PORTAL_DETECTOR_TEST_IMPL_H_
+#define CHROME_BROWSER_CHROMEOS_NET_NETWORK_PORTAL_DETECTOR_TEST_IMPL_H_
#include <string>
@@ -16,10 +16,10 @@
namespace chromeos {
-class NetworkPortalDetectorStub : public NetworkPortalDetector {
+class NetworkPortalDetectorTestImpl : public NetworkPortalDetector {
public:
- NetworkPortalDetectorStub();
- virtual ~NetworkPortalDetectorStub();
+ NetworkPortalDetectorTestImpl();
+ virtual ~NetworkPortalDetectorTestImpl();
void SetDefaultNetworkPathForTesting(const std::string& service_path);
void SetDetectionResultsForTesting(const std::string& service_path,
@@ -27,8 +27,6 @@ class NetworkPortalDetectorStub : public NetworkPortalDetector {
void NotifyObserversForTesting();
// NetworkPortalDetector implementation:
- virtual void Init() OVERRIDE;
- virtual void Shutdown() OVERRIDE;
virtual void AddObserver(Observer* observer) OVERRIDE;
virtual void AddAndFireObserver(Observer* observer) OVERRIDE;
virtual void RemoveObserver(Observer* observer) OVERRIDE;
@@ -49,9 +47,9 @@ class NetworkPortalDetectorStub : public NetworkPortalDetector {
scoped_ptr<NetworkState> default_network_;
CaptivePortalStateMap portal_state_map_;
- DISALLOW_COPY_AND_ASSIGN(NetworkPortalDetectorStub);
+ DISALLOW_COPY_AND_ASSIGN(NetworkPortalDetectorTestImpl);
};
} // namespace chromeos
-#endif // CHROME_BROWSER_CHROMEOS_NET_NETWORK_PORTAL_DETECTOR_STUB_H_
+#endif // CHROME_BROWSER_CHROMEOS_NET_NETWORK_PORTAL_DETECTOR_TEST_IMPL_H_
diff --git a/chrome/browser/chromeos/net/onc_utils.cc b/chrome/browser/chromeos/net/onc_utils.cc
index 4a52464bd7..32d88f464e 100644
--- a/chrome/browser/chromeos/net/onc_utils.cc
+++ b/chrome/browser/chromeos/net/onc_utils.cc
@@ -248,6 +248,33 @@ const base::DictionaryValue* FindPolicyForActiveUser(
FindPolicyByGUID(username_hash, guid, onc_source);
}
+const base::DictionaryValue* GetGlobalConfigFromPolicy(bool for_active_user) {
+ std::string username_hash;
+ if (for_active_user) {
+ const User* user = UserManager::Get()->GetActiveUser();
+ if (!user) {
+ LOG(ERROR) << "No user logged in yet.";
+ return NULL;
+ }
+ username_hash = user->username_hash();
+ }
+ return NetworkHandler::Get()->managed_network_configuration_handler()->
+ GetGlobalConfigFromPolicy(username_hash);
+}
+
+bool PolicyAllowsOnlyPolicyNetworksToAutoconnect(bool for_active_user) {
+ const base::DictionaryValue* global_config =
+ GetGlobalConfigFromPolicy(for_active_user);
+ if (!global_config)
+ return false; // By default, all networks are allowed to autoconnect.
+
+ bool only_policy_autoconnect = false;
+ global_config->GetBooleanWithoutPathExpansion(
+ ::onc::global_network_config::kAllowOnlyPolicyNetworksToAutoconnect,
+ &only_policy_autoconnect);
+ return only_policy_autoconnect;
+}
+
namespace {
const base::DictionaryValue* GetNetworkConfigByGUID(
diff --git a/chrome/browser/chromeos/net/onc_utils.h b/chrome/browser/chromeos/net/onc_utils.h
index 35d076267a..4fa8784abb 100644
--- a/chrome/browser/chromeos/net/onc_utils.h
+++ b/chrome/browser/chromeos/net/onc_utils.h
@@ -47,11 +47,22 @@ void ImportNetworksForUser(const chromeos::User* user,
std::string* error);
// Looks up the policy for |guid| for the current active user and sets
-// |onc_source| accordingly.
+// |global_config| (if not NULL) and |onc_source| (if not NULL) accordingly. If
+// |guid| is empty, returns NULL and sets the |global_config| and |onc_source|
+// if a policy is found.
const base::DictionaryValue* FindPolicyForActiveUser(
const std::string& guid,
::onc::ONCSource* onc_source);
+// Returns the global network configuration section of the active user's network
+// policy (if |for_active_user| is true) or of the device policy.
+const base::DictionaryValue* GetGlobalConfigFromPolicy(bool for_active_user);
+
+// Convenvience function to retrieve the "AllowOnlyPolicyNetworksToAutoconnect"
+// setting from the global network configuration (see
+// GetGlobalConfigFromPolicy).
+bool PolicyAllowsOnlyPolicyNetworksToAutoconnect(bool for_active_user);
+
// Returns the effective (user or device) policy for network |favorite|. Both
// |profile_prefs| and |local_state_prefs| might be NULL. Returns NULL if no
// applicable policy is found. Sets |onc_source| accordingly.
diff --git a/chrome/browser/chromeos/offline/offline_load_page.cc b/chrome/browser/chromeos/offline/offline_load_page.cc
index 952072998a..0219847218 100644
--- a/chrome/browser/chromeos/offline/offline_load_page.cc
+++ b/chrome/browser/chromeos/offline/offline_load_page.cc
@@ -50,9 +50,6 @@ using content::WebContents;
namespace {
-// Maximum time to show a blank page.
-const int kMaxBlankPeriod = 3000;
-
// A utility function to set the dictionary's value given by |resource_id|.
void SetString(DictionaryValue* strings, const char* name, int resource_id) {
strings->SetString(name, l10n_util::GetStringUTF16(resource_id));
diff --git a/chrome/browser/chromeos/options/vpn_config_view.cc b/chrome/browser/chromeos/options/vpn_config_view.cc
index 3bde57995d..ddb6c2d3cf 100644
--- a/chrome/browser/chromeos/options/vpn_config_view.cc
+++ b/chrome/browser/chromeos/options/vpn_config_view.cc
@@ -39,9 +39,6 @@
namespace {
-// Root CA certificates that are built into Chrome use this token name.
-const char* const kRootCertificateTokenName = "Builtin Object Token";
-
enum ProviderTypeIndex {
PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK = 0,
PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT = 1,
@@ -376,6 +373,14 @@ bool VPNConfigView::Login() {
SetConfigProperties(&properties);
bool shared = !LoginState::Get()->IsUserAuthenticated();
+
+ bool only_policy_autoconnect =
+ onc::PolicyAllowsOnlyPolicyNetworksToAutoconnect(!shared);
+ if (only_policy_autoconnect) {
+ properties.SetBooleanWithoutPathExpansion(shill::kAutoConnectProperty,
+ false);
+ }
+
ash::network_connect::CreateConfigurationAndConnect(&properties, shared);
} else {
const NetworkState* vpn = NetworkHandler::Get()->network_state_handler()->
diff --git a/chrome/browser/chromeos/options/wifi_config_view.cc b/chrome/browser/chromeos/options/wifi_config_view.cc
index f5190ae7a4..19cfbbcf86 100644
--- a/chrome/browser/chromeos/options/wifi_config_view.cc
+++ b/chrome/browser/chromeos/options/wifi_config_view.cc
@@ -648,9 +648,19 @@ void WifiConfigView::OnCertificatesLoaded(bool initial_load) {
bool WifiConfigView::Login() {
const bool share_default = true;
+
+ // Set configuration properties.
+ base::DictionaryValue properties;
+ bool share_network = GetShareNetwork(share_default);
+
+ bool only_policy_autoconnect =
+ onc::PolicyAllowsOnlyPolicyNetworksToAutoconnect(!share_network);
+ if (only_policy_autoconnect) {
+ properties.SetBooleanWithoutPathExpansion(shill::kAutoConnectProperty,
+ false);
+ }
+
if (service_path_.empty()) {
- // Set configuration properties.
- base::DictionaryValue properties;
properties.SetStringWithoutPathExpansion(
shill::kTypeProperty, shill::kTypeWifi);
shill_property_util::SetSSID(GetSsid(), &properties);
@@ -686,8 +696,8 @@ bool WifiConfigView::Login() {
shill::kSecurityProperty, security);
// Configure and connect to network.
- bool shared = GetShareNetwork(share_default);
- ash::network_connect::CreateConfigurationAndConnect(&properties, shared);
+ ash::network_connect::CreateConfigurationAndConnect(&properties,
+ share_network);
} else {
const NetworkState* wifi = NetworkHandler::Get()->network_state_handler()->
GetNetworkState(service_path_);
@@ -697,7 +707,6 @@ bool WifiConfigView::Login() {
NET_LOG_ERROR("Network not found", service_path_);
return true; // Close dialog
}
- base::DictionaryValue properties;
if (eap_method_combobox_) {
// Visible 802.1X EAP Wi-Fi connection.
SetEapProperties(&properties);
@@ -711,7 +720,6 @@ bool WifiConfigView::Login() {
shill::kPassphraseProperty, passphrase);
}
}
- bool share_network = GetShareNetwork(share_default);
ash::network_connect::ConfigureNetworkAndConnect(
service_path_, properties, share_network);
}
diff --git a/chrome/browser/chromeos/options/wimax_config_view.cc b/chrome/browser/chromeos/options/wimax_config_view.cc
index b1979351dc..c1b715f738 100644
--- a/chrome/browser/chromeos/options/wimax_config_view.cc
+++ b/chrome/browser/chromeos/options/wimax_config_view.cc
@@ -10,6 +10,7 @@
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/chromeos/enrollment_dialog_view.h"
#include "chrome/browser/chromeos/login/startup_utils.h"
+#include "chrome/browser/chromeos/net/onc_utils.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chromeos/login/login_state.h"
#include "chromeos/network/network_configuration_handler.h"
@@ -158,6 +159,14 @@ bool WimaxConfigView::Login() {
const bool share_default = true;
bool share_network = GetShareNetwork(share_default);
+
+ bool only_policy_autoconnect =
+ onc::PolicyAllowsOnlyPolicyNetworksToAutoconnect(!share_network);
+ if (only_policy_autoconnect) {
+ properties.SetBooleanWithoutPathExpansion(shill::kAutoConnectProperty,
+ false);
+ }
+
ash::network_connect::ConfigureNetworkAndConnect(
service_path_, properties, share_network);
return true; // dialog will be closed
@@ -192,11 +201,11 @@ void WimaxConfigView::Init() {
DCHECK(wimax && wimax->type() == shill::kTypeWimax);
WifiConfigView::ParseWiFiEAPUIProperty(
- &save_credentials_ui_data_, wimax, onc::eap::kSaveCredentials);
+ &save_credentials_ui_data_, wimax, ::onc::eap::kSaveCredentials);
WifiConfigView::ParseWiFiEAPUIProperty(
- &identity_ui_data_, wimax, onc::eap::kIdentity);
+ &identity_ui_data_, wimax, ::onc::eap::kIdentity);
WifiConfigView::ParseWiFiUIProperty(
- &passphrase_ui_data_, wimax, onc::wifi::kPassphrase);
+ &passphrase_ui_data_, wimax, ::onc::wifi::kPassphrase);
views::GridLayout* layout = views::GridLayout::CreatePanel(this);
SetLayoutManager(layout);
diff --git a/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.cc b/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.cc
index 71796220df..58f600c1eb 100644
--- a/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.cc
+++ b/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.cc
@@ -105,9 +105,16 @@ void NetworkConfigurationPolicyHandler::ApplyPolicySettings(
scoped_ptr<base::ListValue> network_configs(new base::ListValue);
base::ListValue certificates;
- chromeos::onc::ParseAndValidateOncForImport(
- onc_blob, onc_source_, "", network_configs.get(), &certificates);
-
+ base::DictionaryValue global_network_config;
+ chromeos::onc::ParseAndValidateOncForImport(onc_blob,
+ onc_source_,
+ "",
+ network_configs.get(),
+ &global_network_config,
+ &certificates);
+
+ // Currently, only the per-network configuration is stored in a pref. Ignore
+ // |global_network_config| and |certificates|.
prefs->SetValue(pref_path_, network_configs.release());
}
diff --git a/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.h b/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.h
index f470b514cc..d1b751d222 100644
--- a/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.h
+++ b/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.h
@@ -5,6 +5,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_POLICY_CONFIGURATION_POLICY_HANDLER_CHROMEOS_H_
#define CHROME_BROWSER_CHROMEOS_POLICY_CONFIGURATION_POLICY_HANDLER_CHROMEOS_H_
+#include "chrome/browser/extensions/policy_handlers.h"
#include "chrome/browser/policy/configuration_policy_handler.h"
#include "chromeos/network/network_ui_data.h"
#include "components/onc/onc_constants.h"
@@ -56,7 +57,8 @@ class NetworkConfigurationPolicyHandler : public TypeCheckingPolicyHandler {
};
// Maps the PinnedLauncherApps policy to the corresponding pref.
-class PinnedLauncherAppsPolicyHandler : public ExtensionListPolicyHandler {
+class PinnedLauncherAppsPolicyHandler
+ : public extensions::ExtensionListPolicyHandler {
public:
PinnedLauncherAppsPolicyHandler();
virtual ~PinnedLauncherAppsPolicyHandler();
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.cc b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.cc
index 987d400c18..beea91d6ec 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.cc
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.cc
@@ -82,6 +82,7 @@ bool GetMachineFlag(const std::string& key, bool default_value) {
DeviceCloudPolicyManagerChromeOS::DeviceCloudPolicyManagerChromeOS(
scoped_ptr<DeviceCloudPolicyStoreChromeOS> store,
const scoped_refptr<base::SequencedTaskRunner>& task_runner,
+ const scoped_refptr<base::SequencedTaskRunner>& background_task_runner,
EnterpriseInstallAttributes* install_attributes)
: CloudPolicyManager(
PolicyNamespaceKey(dm_protocol::kChromeDevicePolicyType,
@@ -89,6 +90,7 @@ DeviceCloudPolicyManagerChromeOS::DeviceCloudPolicyManagerChromeOS(
store.get(),
task_runner),
device_store_(store.Pass()),
+ background_task_runner_(background_task_runner),
install_attributes_(install_attributes),
device_management_service_(NULL),
local_state_(NULL) {}
@@ -120,7 +122,8 @@ void DeviceCloudPolicyManagerChromeOS::StartEnrollment(
enrollment_handler_.reset(
new EnrollmentHandlerChromeOS(
- device_store_.get(), install_attributes_, CreateClient(), auth_token,
+ device_store_.get(), install_attributes_, CreateClient(),
+ background_task_runner_, auth_token,
install_attributes_->GetDeviceId(), is_auto_enrollment,
GetDeviceRequisition(), allowed_device_modes,
base::Bind(&DeviceCloudPolicyManagerChromeOS::EnrollmentCompleted,
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h
index a79dd031d1..120847878c 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h
@@ -46,9 +46,12 @@ class DeviceCloudPolicyManagerChromeOS : public CloudPolicyManager {
typedef base::Callback<void(EnrollmentStatus)> EnrollmentCallback;
// |task_runner| is the runner for policy refresh tasks.
+ // |background_task_runner| is used to execute long-running background tasks
+ // that may involve file I/O.
DeviceCloudPolicyManagerChromeOS(
scoped_ptr<DeviceCloudPolicyStoreChromeOS> store,
const scoped_refptr<base::SequencedTaskRunner>& task_runner,
+ const scoped_refptr<base::SequencedTaskRunner>& background_task_runner,
EnterpriseInstallAttributes* install_attributes);
virtual ~DeviceCloudPolicyManagerChromeOS();
@@ -115,6 +118,7 @@ class DeviceCloudPolicyManagerChromeOS : public CloudPolicyManager {
// Points to the same object as the base CloudPolicyManager::store(), but with
// actual device policy specific type.
scoped_ptr<DeviceCloudPolicyStoreChromeOS> device_store_;
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
EnterpriseInstallAttributes* install_attributes_;
DeviceManagementService* device_management_service_;
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
index 3b58d05f7d..7ee648e6f0 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
@@ -25,7 +25,7 @@
#include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
#include "chrome/browser/prefs/browser_prefs.h"
#include "chrome/test/base/testing_browser_process.h"
-#include "chromeos/cryptohome/cryptohome_library.h"
+#include "chromeos/cryptohome/system_salt_getter.h"
#include "chromeos/dbus/dbus_client_implementation_type.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/system/mock_statistics_provider.h"
@@ -84,10 +84,12 @@ class DeviceCloudPolicyManagerChromeOSTest
install_attributes_.reset(new EnterpriseInstallAttributes(
chromeos::DBusThreadManager::Get()->GetCryptohomeClient()));
store_ = new DeviceCloudPolicyStoreChromeOS(&device_settings_service_,
- install_attributes_.get());
+ install_attributes_.get(),
+ loop_.message_loop_proxy());
manager_.reset(new DeviceCloudPolicyManagerChromeOS(
make_scoped_ptr(store_),
loop_.message_loop_proxy(),
+ loop_.message_loop_proxy(),
install_attributes_.get()));
chrome::RegisterLocalState(local_state_.registry());
@@ -102,9 +104,9 @@ class DeviceCloudPolicyManagerChromeOSTest
request_context_getter_.get());
TestingBrowserProcess::GetGlobal()->SetLocalState(&local_state_);
chromeos::DeviceOAuth2TokenServiceFactory::Initialize();
- // This is needed as CryptohomeLibrary is used for encrypting tokens in
+ // This is needed as SystemSaltGetter is used for encrypting tokens in
// CryptohomeTokenEncryptor.
- chromeos::CryptohomeLibrary::Initialize();
+ chromeos::SystemSaltGetter::Initialize();
url_fetcher_response_code_ = 200;
url_fetcher_response_string_ = "{\"access_token\":\"accessToken4Test\","
"\"expires_in\":1234,"
@@ -116,7 +118,7 @@ class DeviceCloudPolicyManagerChromeOSTest
DeviceSettingsTestBase::TearDown();
chromeos::DeviceOAuth2TokenServiceFactory::Shutdown();
- chromeos::CryptohomeLibrary::Shutdown();
+ chromeos::SystemSaltGetter::Shutdown();
TestingBrowserProcess::GetGlobal()->SetLocalState(NULL);
}
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.cc b/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.cc
index 3b0d634cd8..7f8a547974 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.cc
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h"
#include "base/bind.h"
+#include "base/sequenced_task_runner.h"
#include "chrome/browser/chromeos/policy/device_policy_decoder_chromeos.h"
#include "chrome/browser/chromeos/policy/enterprise_install_attributes.h"
#include "chrome/browser/policy/proto/chromeos/chrome_device_policy.pb.h"
@@ -16,9 +17,11 @@ namespace policy {
DeviceCloudPolicyStoreChromeOS::DeviceCloudPolicyStoreChromeOS(
chromeos::DeviceSettingsService* device_settings_service,
- EnterpriseInstallAttributes* install_attributes)
+ EnterpriseInstallAttributes* install_attributes,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner)
: device_settings_service_(device_settings_service),
install_attributes_(install_attributes),
+ background_task_runner_(background_task_runner),
weak_factory_(this) {
device_settings_service_->AddObserver(this);
}
@@ -92,7 +95,8 @@ scoped_ptr<DeviceCloudPolicyValidator>
scoped_ptr<DeviceCloudPolicyValidator> validator(
DeviceCloudPolicyValidator::Create(
scoped_ptr<em::PolicyFetchResponse>(
- new em::PolicyFetchResponse(policy))));
+ new em::PolicyFetchResponse(policy)),
+ background_task_runner_));
validator->ValidateDomain(install_attributes_->GetDomain());
validator->ValidatePolicyType(dm_protocol::kChromeDevicePolicyType);
validator->ValidatePayload();
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h b/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h
index f468a7598b..6afcd442eb 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h
@@ -7,12 +7,17 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/chromeos/policy/device_cloud_policy_validator.h"
#include "chrome/browser/chromeos/settings/device_settings_service.h"
#include "chrome/browser/policy/cloud/cloud_policy_store.h"
+namespace base {
+class SequencedTaskRunner;
+}
+
namespace enterprise_management {
class PolicyFetchResponse;
}
@@ -29,7 +34,8 @@ class DeviceCloudPolicyStoreChromeOS
public:
DeviceCloudPolicyStoreChromeOS(
chromeos::DeviceSettingsService* device_settings_service,
- EnterpriseInstallAttributes* install_attributes);
+ EnterpriseInstallAttributes* install_attributes,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner);
virtual ~DeviceCloudPolicyStoreChromeOS();
// CloudPolicyStore:
@@ -68,6 +74,8 @@ class DeviceCloudPolicyStoreChromeOS
chromeos::DeviceSettingsService* device_settings_service_;
EnterpriseInstallAttributes* install_attributes_;
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
+
base::WeakPtrFactory<DeviceCloudPolicyStoreChromeOS> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(DeviceCloudPolicyStoreChromeOS);
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos_unittest.cc b/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos_unittest.cc
index b0347dacb4..5ccd535f95 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos_unittest.cc
@@ -39,7 +39,8 @@ class DeviceCloudPolicyStoreChromeOSTest
install_attributes_(new EnterpriseInstallAttributes(
fake_cryptohome_client_.get())),
store_(new DeviceCloudPolicyStoreChromeOS(&device_settings_service_,
- install_attributes_.get())) {
+ install_attributes_.get(),
+ loop_.message_loop_proxy())) {
fake_cryptohome_client_->Init(NULL /* no dbus::Bus */);
}
@@ -99,8 +100,10 @@ class DeviceCloudPolicyStoreChromeOSTest
std::string());
install_attributes_.reset(new EnterpriseInstallAttributes(
fake_cryptohome_client_.get()));
- store_.reset(new DeviceCloudPolicyStoreChromeOS(&device_settings_service_,
- install_attributes_.get()));
+ store_.reset(
+ new DeviceCloudPolicyStoreChromeOS(&device_settings_service_,
+ install_attributes_.get(),
+ loop_.message_loop_proxy()));
}
scoped_ptr<chromeos::FakeCryptohomeClient> fake_cryptohome_client_;
diff --git a/chrome/browser/chromeos/policy/device_local_account.h b/chrome/browser/chromeos/policy/device_local_account.h
index ff83461863..d10b2286a3 100644
--- a/chrome/browser/chromeos/policy/device_local_account.h
+++ b/chrome/browser/chromeos/policy/device_local_account.h
@@ -32,6 +32,22 @@ struct DeviceLocalAccount {
~DeviceLocalAccount();
Type type;
+ // A device-local account has two identifiers:
+ // * The |account_id| is chosen by the entity that defines the device-local
+ // account. The only constraints are that the |account_id| be unique and,
+ // for legacy reasons, it contain an @ symbol.
+ // * The |user_id| is a synthesized identifier that is guaranteed to be
+ // unique, contain an @ symbol, not collide with the |user_id| of any other
+ // user on the device (such as regular users or supervised users) and be
+ // identifiable as belonging to a device-local account by.
+ // The |account_id| is primarily used by policy code: If device policy defines
+ // a device-local account with a certain |account_id|, the user policy for
+ // that account has to be fetched by referencing the same |account_id|.
+ // The |user_id| is passed to the chromeos::UserManager where it becomes part
+ // of the global user list on the device. The |account_id| would not be safe
+ // to use here as it is a free-form identifier that could conflict with
+ // another |user_id| on the device and cannot be easily identified as
+ // belonging to a device-local account.
std::string account_id;
std::string user_id;
std::string kiosk_app_id;
diff --git a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
index aae8978aa6..99346085fd 100644
--- a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
+++ b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
@@ -12,14 +12,17 @@
#include "base/command_line.h"
#include "base/file_util.h"
#include "base/files/file_path.h"
+#include "base/files/scoped_temp_dir.h"
#include "base/json/json_reader.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/path_service.h"
#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_path_override.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_notification_types.h"
@@ -57,6 +60,7 @@
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h"
+#include "chromeos/chromeos_paths.h"
#include "chromeos/chromeos_switches.h"
#include "chromeos/dbus/cryptohome_client.h"
#include "chromeos/dbus/dbus_method_call_status.h"
@@ -113,9 +117,9 @@ const char kUpdateManifestFooter[] =
"</gupdate>\n";
const char kHostedAppID[] = "kbmnembihfiondgfjekmnmcbddelicoi";
const char kHostedAppCRXPath[] = "extensions/hosted_app.crx";
-const char kHostedAppVersion[] = "0.1";
+const char kHostedAppVersion[] = "1.0.0.0";
const char kGoodExtensionID[] = "ldnnhddmnhbkjipkidpdiheffobcpfmf";
-const char kGoodExtensionPath[] = "extensions/good.crx";
+const char kGoodExtensionCRXPath[] = "extensions/good.crx";
const char kGoodExtensionVersion[] = "1.0";
// Helper that serves extension update manifests to Chrome.
@@ -247,6 +251,11 @@ class DeviceLocalAccountTest : public DevicePolicyCrosBrowserTest {
PolicyBuilder::kFakeDeviceId);
ASSERT_TRUE(test_server_.Start());
+ ASSERT_TRUE(extension_cache_root_dir_.CreateUniqueTempDir());
+ extension_cache_root_dir_override_.reset(new base::ScopedPathOverride(
+ chromeos::DIR_DEVICE_LOCAL_ACCOUNT_CACHE,
+ extension_cache_root_dir_.path()));
+
DevicePolicyCrosBrowserTest::SetUp();
}
@@ -336,9 +345,24 @@ class DeviceLocalAccountTest : public DevicePolicyCrosBrowserTest {
EXPECT_EQ(chromeos::User::USER_TYPE_PUBLIC_ACCOUNT, user->GetType());
}
+ base::FilePath GetCacheDirectoryForAccountID(const std::string& account_id) {
+ return extension_cache_root_dir_.path()
+ .Append(base::HexEncode(account_id.c_str(), account_id.size()));
+ }
+
+ base::FilePath GetCacheCRXFile(const std::string& account_id,
+ const std::string& id,
+ const std::string& version) {
+ return GetCacheDirectoryForAccountID(account_id)
+ .Append(base::StringPrintf("%s-%s.crx", id.c_str(), version.c_str()));
+ }
+
const std::string user_id_1_;
const std::string user_id_2_;
+ base::ScopedTempDir extension_cache_root_dir_;
+ scoped_ptr<base::ScopedPathOverride> extension_cache_root_dir_override_;
+
UserPolicyBuilder device_local_account_policy_;
LocalPolicyTestServer test_server_;
};
@@ -554,7 +578,7 @@ IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, FullscreenDisallowed) {
EXPECT_FALSE(browser_window->IsFullscreen());
}
-IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, ExtensionWhitelist) {
+IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, ExtensionsUncached) {
// Make it possible to force-install a hosted app and an extension.
ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
TestingUpdateManifestProvider testing_update_manifest_provider(
@@ -566,7 +590,7 @@ IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, ExtensionWhitelist) {
testing_update_manifest_provider.AddUpdate(
kGoodExtensionID,
kGoodExtensionVersion,
- embedded_test_server()->GetURL(std::string("/") + kGoodExtensionPath));
+ embedded_test_server()->GetURL(std::string("/") + kGoodExtensionCRXPath));
embedded_test_server()->RegisterRequestHandler(
base::Bind(&TestingUpdateManifestProvider::HandleRequest,
base::Unretained(&testing_update_manifest_provider)));
@@ -625,6 +649,105 @@ IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, ExtensionWhitelist) {
controller->LoginAsPublicAccount(user_id_1_);
// Wait for the hosted app installation to succeed and the extension
+ // installation to fail (because hosted apps are whitelisted for use in
+ // device-local accounts and extensions are not).
+ hosted_app_observer.Wait();
+ extension_observer.Wait();
+
+ // Verify that the hosted app was installed.
+ Profile* profile = ProfileManager::GetDefaultProfile();
+ ASSERT_TRUE(profile);
+ ExtensionService* extension_service =
+ extensions::ExtensionSystem::Get(profile)->extension_service();
+ EXPECT_TRUE(extension_service->GetExtensionById(kHostedAppID, true));
+
+ // Verify that the extension was not installed.
+ EXPECT_FALSE(extension_service->GetExtensionById(kGoodExtensionID, true));
+
+ // Verify that the app was copied to the account's extension cache.
+ base::FilePath test_dir;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir));
+ EXPECT_TRUE(ContentsEqual(
+ GetCacheCRXFile(kAccountId1, kHostedAppID, kHostedAppVersion),
+ test_dir.Append(kHostedAppCRXPath)));
+
+ // Verify that the extension was not copied to the account's extension cache.
+ EXPECT_FALSE(PathExists(GetCacheCRXFile(
+ kAccountId1, kGoodExtensionID, kGoodExtensionVersion)));
+}
+
+IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, ExtensionsCached) {
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
+ // Pre-populate the device local account's extension cache with a hosted app
+ // and an extension.
+ EXPECT_TRUE(file_util::CreateDirectory(
+ GetCacheDirectoryForAccountID(kAccountId1)));
+ base::FilePath test_dir;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir));
+ const base::FilePath cached_hosted_app =
+ GetCacheCRXFile(kAccountId1, kHostedAppID, kHostedAppVersion);
+ EXPECT_TRUE(CopyFile(test_dir.Append(kHostedAppCRXPath),
+ cached_hosted_app));
+ const base::FilePath cached_extension =
+ GetCacheCRXFile(kAccountId1, kGoodExtensionID, kGoodExtensionVersion);
+ EXPECT_TRUE(CopyFile(test_dir.Append(kGoodExtensionCRXPath),
+ cached_extension));
+
+ // Specify policy to force-install the hosted app.
+ em::StringList* forcelist = device_local_account_policy_.payload()
+ .mutable_extensioninstallforcelist()->mutable_value();
+ forcelist->add_entries(base::StringPrintf(
+ "%s;%s",
+ kHostedAppID,
+ embedded_test_server()->GetURL(kRelativeUpdateURL).spec().c_str()));
+ forcelist->add_entries(base::StringPrintf(
+ "%s;%s",
+ kGoodExtensionID,
+ embedded_test_server()->GetURL(kRelativeUpdateURL).spec().c_str()));
+
+ UploadAndInstallDeviceLocalAccountPolicy();
+ AddPublicSessionToDevicePolicy(kAccountId1);
+
+ // This observes the display name becoming available as this indicates
+ // device-local account policy is fully loaded, which is a prerequisite for
+ // successful login.
+ content::WindowedNotificationObserver(
+ chrome::NOTIFICATION_USER_LIST_CHANGED,
+ base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
+
+ // Wait for the login UI to be ready.
+ chromeos::LoginDisplayHostImpl* host =
+ reinterpret_cast<chromeos::LoginDisplayHostImpl*>(
+ chromeos::LoginDisplayHostImpl::default_host());
+ ASSERT_TRUE(host);
+ chromeos::OobeUI* oobe_ui = host->GetOobeUI();
+ ASSERT_TRUE(oobe_ui);
+ base::RunLoop run_loop;
+ const bool oobe_ui_ready = oobe_ui->IsJSReady(run_loop.QuitClosure());
+ if (!oobe_ui_ready)
+ run_loop.Run();
+
+ // Ensure that the browser stays alive, even though no windows are opened
+ // during session start.
+ chrome::StartKeepAlive();
+
+ // Start listening for app/extension installation results.
+ content::WindowedNotificationObserver hosted_app_observer(
+ chrome::NOTIFICATION_EXTENSION_INSTALLED,
+ base::Bind(DoesInstallSuccessReferToId, kHostedAppID));
+ content::WindowedNotificationObserver extension_observer(
+ chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
+ base::Bind(DoesInstallFailureReferToId, kGoodExtensionID));
+
+ // Start login into the device-local account.
+ host->StartSignInScreen();
+ chromeos::ExistingUserController* controller =
+ chromeos::ExistingUserController::current_controller();
+ ASSERT_TRUE(controller);
+ controller->LoginAsPublicAccount(user_id_1_);
+
+ // Wait for the hosted app installation to succeed and the extension
// installation to fail.
hosted_app_observer.Wait();
extension_observer.Wait();
@@ -638,6 +761,12 @@ IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, ExtensionWhitelist) {
// Verify that the extension was not installed.
EXPECT_FALSE(extension_service->GetExtensionById(kGoodExtensionID, true));
+
+ // Verify that the app is still in the account's extension cache.
+ EXPECT_TRUE(PathExists(cached_hosted_app));
+
+ // Verify that the extension was removed from the account's extension cache.
+ EXPECT_FALSE(PathExists(cached_extension));
}
class TermsOfServiceTest : public DeviceLocalAccountTest,
@@ -684,7 +813,7 @@ IN_PROC_BROWSER_TEST_P(TermsOfServiceTest, TermsOfServiceScreen) {
// and the first wizard screen, if any, is being shown.
base::RunLoop login_wait_run_loop;
chromeos::MockConsumer login_status_consumer;
- EXPECT_CALL(login_status_consumer, OnLoginSuccess(_, false, false))
+ EXPECT_CALL(login_status_consumer, OnLoginSuccess(_))
.Times(1)
.WillOnce(InvokeWithoutArgs(&login_wait_run_loop, &base::RunLoop::Quit));
diff --git a/chrome/browser/chromeos/policy/device_local_account_policy_provider.cc b/chrome/browser/chromeos/policy/device_local_account_policy_provider.cc
index 6b0535e00d..4381ce43ae 100644
--- a/chrome/browser/chromeos/policy/device_local_account_policy_provider.cc
+++ b/chrome/browser/chromeos/policy/device_local_account_policy_provider.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/chromeos/policy/device_local_account_policy_provider.h"
#include "base/bind.h"
+#include "chrome/browser/policy/cloud/cloud_policy_core.h"
#include "chrome/browser/policy/cloud/cloud_policy_service.h"
#include "chrome/browser/policy/policy_bundle.h"
#include "chrome/browser/policy/policy_service.h"
diff --git a/chrome/browser/chromeos/policy/device_local_account_policy_service.cc b/chrome/browser/chromeos/policy/device_local_account_policy_service.cc
index 5e59294b98..3579bec7a2 100644
--- a/chrome/browser/chromeos/policy/device_local_account_policy_service.cc
+++ b/chrome/browser/chromeos/policy/device_local_account_policy_service.cc
@@ -7,18 +7,24 @@
#include <vector>
#include "base/bind.h"
+#include "base/file_util.h"
+#include "base/files/file_enumerator.h"
+#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "base/message_loop/message_loop_proxy.h"
+#include "base/path_service.h"
+#include "base/sequenced_task_runner.h"
+#include "base/strings/string_number_conversions.h"
#include "chrome/browser/chromeos/policy/device_local_account.h"
#include "chrome/browser/chromeos/policy/device_local_account_policy_store.h"
-#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/chromeos/settings/device_settings_service.h"
#include "chrome/browser/policy/cloud/cloud_policy_client.h"
#include "chrome/browser/policy/cloud/cloud_policy_constants.h"
#include "chrome/browser/policy/cloud/cloud_policy_refresh_scheduler.h"
#include "chrome/browser/policy/cloud/device_management_service.h"
#include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
+#include "chromeos/chromeos_paths.h"
#include "chromeos/dbus/session_manager_client.h"
#include "chromeos/settings/cros_settings_names.h"
#include "chromeos/settings/cros_settings_provider.h"
@@ -53,23 +59,86 @@ scoped_ptr<CloudPolicyClient> CreateClient(
return client.Pass();
}
+// Get the subdirectory of the cache directory in which force-installed
+// extensions are cached for |account_id|.
+std::string GetCacheSubdirectoryForAccountID(const std::string& account_id) {
+ return base::HexEncode(account_id.c_str(), account_id.size());
+}
+
+// Cleans up the cache directory by removing subdirectories that are not found
+// in |subdirectories_to_keep|. Only caches whose cache directory is found in
+// |subdirectories_to_keep| may be running while the clean-up is in progress.
+void DeleteOrphanedExtensionCaches(
+ const std::set<std::string>& subdirectories_to_keep) {
+ base::FilePath cache_root_dir;
+ CHECK(PathService::Get(chromeos::DIR_DEVICE_LOCAL_ACCOUNT_CACHE,
+ &cache_root_dir));
+ base::FileEnumerator enumerator(cache_root_dir,
+ false,
+ base::FileEnumerator::DIRECTORIES);
+ for (base::FilePath path = enumerator.Next(); !path.empty();
+ path = enumerator.Next()) {
+ const std::string subdirectory(path.BaseName().MaybeAsASCII());
+ if (subdirectories_to_keep.find(subdirectory) ==
+ subdirectories_to_keep.end()) {
+ base::DeleteFile(path, true);
+ }
+ }
+}
+
+// Removes the subdirectory belonging to |account_id_to_delete| from the cache
+// directory. No cache belonging to |account_id_to_delete| may be running while
+// the removal is in progress.
+void DeleteObsoleteExtensionCache(const std::string& account_id_to_delete) {
+ base::FilePath cache_root_dir;
+ CHECK(PathService::Get(chromeos::DIR_DEVICE_LOCAL_ACCOUNT_CACHE,
+ &cache_root_dir));
+ const base::FilePath path = cache_root_dir
+ .Append(GetCacheSubdirectoryForAccountID(account_id_to_delete));
+ if (base::DirectoryExists(path))
+ base::DeleteFile(path, true);
+}
+
} // namespace
DeviceLocalAccountPolicyBroker::DeviceLocalAccountPolicyBroker(
- const std::string& user_id,
+ const DeviceLocalAccount& account,
scoped_ptr<DeviceLocalAccountPolicyStore> store,
const scoped_refptr<base::SequencedTaskRunner>& task_runner)
- : user_id_(user_id),
+ : account_id_(account.account_id),
+ user_id_(account.user_id),
store_(store.Pass()),
core_(PolicyNamespaceKey(dm_protocol::kChromePublicAccountPolicyType,
store_->account_id()),
store_.get(),
- task_runner) {}
+ task_runner) {
+ base::FilePath cache_root_dir;
+ CHECK(PathService::Get(chromeos::DIR_DEVICE_LOCAL_ACCOUNT_CACHE,
+ &cache_root_dir));
+ extension_loader_ = new chromeos::DeviceLocalAccountExternalPolicyLoader(
+ store_.get(),
+ cache_root_dir.Append(
+ GetCacheSubdirectoryForAccountID(account.account_id)));
+}
+
+DeviceLocalAccountPolicyBroker::~DeviceLocalAccountPolicyBroker() {
+}
+
+void DeviceLocalAccountPolicyBroker::Initialize() {
+ store_->Load();
+}
+
+void DeviceLocalAccountPolicyBroker::ConnectIfPossible(
+ chromeos::DeviceSettingsService* device_settings_service,
+ DeviceManagementService* device_management_service) {
+ if (core_.client())
+ return;
-DeviceLocalAccountPolicyBroker::~DeviceLocalAccountPolicyBroker() {}
+ scoped_ptr<CloudPolicyClient> client(CreateClient(device_settings_service,
+ device_management_service));
+ if (!client)
+ return;
-void DeviceLocalAccountPolicyBroker::Connect(
- scoped_ptr<CloudPolicyClient> client) {
core_.Connect(client.Pass());
core_.StartRefreshScheduler();
UpdateRefreshDelay();
@@ -98,61 +167,26 @@ std::string DeviceLocalAccountPolicyBroker::GetDisplayName() const {
return display_name;
}
-DeviceLocalAccountPolicyService::PolicyBrokerWrapper::PolicyBrokerWrapper()
- : parent(NULL), broker(NULL) {}
-
-DeviceLocalAccountPolicyBroker*
- DeviceLocalAccountPolicyService::PolicyBrokerWrapper::GetBroker() {
- if (!broker) {
- scoped_ptr<DeviceLocalAccountPolicyStore> store(
- new DeviceLocalAccountPolicyStore(account_id,
- parent->session_manager_client_,
- parent->device_settings_service_));
- broker = new DeviceLocalAccountPolicyBroker(
- user_id, store.Pass(), base::MessageLoopProxy::current());
- broker->core()->store()->AddObserver(parent);
- broker->core()->store()->Load();
- }
- return broker;
-}
-
-void DeviceLocalAccountPolicyService::PolicyBrokerWrapper::ConnectIfPossible() {
- if (broker && broker->core()->client())
- return;
- scoped_ptr<CloudPolicyClient> client(CreateClient(
- parent->device_settings_service_,
- parent->device_management_service_));
- if (client)
- GetBroker()->Connect(client.Pass());
-}
-
-void DeviceLocalAccountPolicyService::PolicyBrokerWrapper::Disconnect() {
- if (broker)
- broker->Disconnect();
-}
-
-void DeviceLocalAccountPolicyService::PolicyBrokerWrapper::DeleteBroker() {
- if (!broker)
- return;
- broker->core()->store()->RemoveObserver(parent);
- delete broker;
- broker = NULL;
-}
-
DeviceLocalAccountPolicyService::DeviceLocalAccountPolicyService(
chromeos::SessionManagerClient* session_manager_client,
chromeos::DeviceSettingsService* device_settings_service,
- chromeos::CrosSettings* cros_settings)
+ chromeos::CrosSettings* cros_settings,
+ scoped_refptr<base::SequencedTaskRunner> store_background_task_runner,
+ scoped_refptr<base::SequencedTaskRunner> extension_cache_task_runner)
: session_manager_client_(session_manager_client),
device_settings_service_(device_settings_service),
cros_settings_(cros_settings),
device_management_service_(NULL),
- cros_settings_callback_factory_(this) {
- local_accounts_subscription_ = cros_settings_->AddSettingsObserver(
- chromeos::kAccountsPrefDeviceLocalAccounts,
- base::Bind(&DeviceLocalAccountPolicyService::
- UpdateAccountListIfNonePending,
- base::Unretained(this)));
+ waiting_for_cros_settings_(false),
+ orphan_cache_deletion_state_(NOT_STARTED),
+ store_background_task_runner_(store_background_task_runner),
+ extension_cache_task_runner_(extension_cache_task_runner),
+ local_accounts_subscription_(cros_settings_->AddSettingsObserver(
+ chromeos::kAccountsPrefDeviceLocalAccounts,
+ base::Bind(&DeviceLocalAccountPolicyService::
+ UpdateAccountListIfNonePending,
+ base::Unretained(this)))),
+ weak_factory_(this) {
UpdateAccountList();
}
@@ -168,7 +202,8 @@ void DeviceLocalAccountPolicyService::Connect(
// Connect the brokers.
for (PolicyBrokerMap::iterator it(policy_brokers_.begin());
it != policy_brokers_.end(); ++it) {
- it->second.ConnectIfPossible();
+ it->second->ConnectIfPossible(device_settings_service_,
+ device_management_service_);
}
}
@@ -179,7 +214,7 @@ void DeviceLocalAccountPolicyService::Disconnect() {
// Disconnect the brokers.
for (PolicyBrokerMap::iterator it(policy_brokers_.begin());
it != policy_brokers_.end(); ++it) {
- it->second.Disconnect();
+ it->second->Disconnect();
}
}
@@ -190,7 +225,7 @@ DeviceLocalAccountPolicyBroker*
if (entry == policy_brokers_.end())
return NULL;
- return entry->second.GetBroker();
+ return entry->second;
}
bool DeviceLocalAccountPolicyService::IsPolicyAvailableForUser(
@@ -224,52 +259,214 @@ void DeviceLocalAccountPolicyService::OnStoreError(CloudPolicyStore* store) {
FOR_EACH_OBSERVER(Observer, observers_, OnPolicyUpdated(broker->user_id()));
}
+bool DeviceLocalAccountPolicyService::IsExtensionCacheDirectoryBusy(
+ const std::string& account_id) {
+ return busy_extension_cache_directories_.find(account_id) !=
+ busy_extension_cache_directories_.end();
+}
+
+void DeviceLocalAccountPolicyService::StartExtensionCachesIfPossible() {
+ for (PolicyBrokerMap::iterator it = policy_brokers_.begin();
+ it != policy_brokers_.end(); ++it) {
+ if (!it->second->extension_loader()->IsCacheRunning() &&
+ !IsExtensionCacheDirectoryBusy(it->second->account_id())) {
+ it->second->extension_loader()->StartCache(extension_cache_task_runner_);
+ }
+ }
+}
+
+bool DeviceLocalAccountPolicyService::StartExtensionCacheForAccountIfPresent(
+ const std::string& account_id) {
+ for (PolicyBrokerMap::iterator it = policy_brokers_.begin();
+ it != policy_brokers_.end(); ++it) {
+ if (it->second->account_id() == account_id) {
+ DCHECK(!it->second->extension_loader()->IsCacheRunning());
+ it->second->extension_loader()->StartCache(extension_cache_task_runner_);
+ return true;
+ }
+ }
+ return false;
+}
+
+void DeviceLocalAccountPolicyService::OnOrphanedExtensionCachesDeleted() {
+ DCHECK_EQ(IN_PROGRESS, orphan_cache_deletion_state_);
+
+ orphan_cache_deletion_state_ = DONE;
+ StartExtensionCachesIfPossible();
+}
+
+void DeviceLocalAccountPolicyService::OnObsoleteExtensionCacheShutdown(
+ const std::string& account_id) {
+ DCHECK_NE(NOT_STARTED, orphan_cache_deletion_state_);
+ DCHECK(IsExtensionCacheDirectoryBusy(account_id));
+
+ // The account with |account_id| was deleted and the broker for it has shut
+ // down completely.
+
+ if (StartExtensionCacheForAccountIfPresent(account_id)) {
+ // If another account with the same ID was created in the meantime, its
+ // extension cache is started, reusing the cache directory. The directory no
+ // longer needs to be marked as busy in this case.
+ busy_extension_cache_directories_.erase(account_id);
+ return;
+ }
+
+ // If no account with |account_id| exists anymore, the cache directory should
+ // be removed. The directory must stay marked as busy while the removal is in
+ // progress.
+ extension_cache_task_runner_->PostTaskAndReply(
+ FROM_HERE,
+ base::Bind(&DeleteObsoleteExtensionCache, account_id),
+ base::Bind(&DeviceLocalAccountPolicyService::
+ OnObsoleteExtensionCacheDeleted,
+ weak_factory_.GetWeakPtr(),
+ account_id));
+}
+
+void DeviceLocalAccountPolicyService::OnObsoleteExtensionCacheDeleted(
+ const std::string& account_id) {
+ DCHECK_EQ(DONE, orphan_cache_deletion_state_);
+ DCHECK(IsExtensionCacheDirectoryBusy(account_id));
+
+ // The cache directory for |account_id| has been deleted. The directory no
+ // longer needs to be marked as busy.
+ busy_extension_cache_directories_.erase(account_id);
+
+ // If another account with the same ID was created in the meantime, start its
+ // extension cache, creating a new cache directory.
+ StartExtensionCacheForAccountIfPresent(account_id);
+}
+
void DeviceLocalAccountPolicyService::UpdateAccountListIfNonePending() {
// Avoid unnecessary calls to UpdateAccountList(): If an earlier call is still
// pending (because the |cros_settings_| are not trusted yet), the updated
// account list will be processed by that call when it eventually runs.
- if (!cros_settings_callback_factory_.HasWeakPtrs())
+ if (!waiting_for_cros_settings_)
UpdateAccountList();
}
void DeviceLocalAccountPolicyService::UpdateAccountList() {
- if (chromeos::CrosSettingsProvider::TRUSTED !=
- cros_settings_->PrepareTrustedValues(
- base::Bind(&DeviceLocalAccountPolicyService::UpdateAccountList,
- cros_settings_callback_factory_.GetWeakPtr()))) {
- return;
+ chromeos::CrosSettingsProvider::TrustedStatus status =
+ cros_settings_->PrepareTrustedValues(
+ base::Bind(&DeviceLocalAccountPolicyService::UpdateAccountList,
+ weak_factory_.GetWeakPtr()));
+ switch (status) {
+ case chromeos::CrosSettingsProvider::TRUSTED:
+ waiting_for_cros_settings_ = false;
+ break;
+ case chromeos::CrosSettingsProvider::TEMPORARILY_UNTRUSTED:
+ waiting_for_cros_settings_ = true;
+ return;
+ case chromeos::CrosSettingsProvider::PERMANENTLY_UNTRUSTED:
+ waiting_for_cros_settings_ = false;
+ return;
}
// Update |policy_brokers_|, keeping existing entries.
PolicyBrokerMap old_policy_brokers;
policy_brokers_.swap(old_policy_brokers);
+ std::set<std::string> subdirectories_to_keep;
const std::vector<DeviceLocalAccount> device_local_accounts =
GetDeviceLocalAccounts(cros_settings_);
for (std::vector<DeviceLocalAccount>::const_iterator it =
device_local_accounts.begin();
it != device_local_accounts.end(); ++it) {
- PolicyBrokerWrapper& wrapper = policy_brokers_[it->user_id];
- wrapper.user_id = it->user_id;
- wrapper.account_id = it->account_id;
- wrapper.parent = this;
-
- // Reuse the existing broker if present.
- PolicyBrokerWrapper& existing_wrapper = old_policy_brokers[it->user_id];
- wrapper.broker = existing_wrapper.broker;
- existing_wrapper.broker = NULL;
+ PolicyBrokerMap::iterator broker_it = old_policy_brokers.find(it->user_id);
+
+ scoped_ptr<DeviceLocalAccountPolicyBroker> broker;
+ bool broker_initialized = false;
+ if (broker_it != old_policy_brokers.end()) {
+ // Reuse the existing broker if present.
+ broker.reset(broker_it->second);
+ old_policy_brokers.erase(broker_it);
+ broker_initialized = true;
+ } else {
+ scoped_ptr<DeviceLocalAccountPolicyStore> store(
+ new DeviceLocalAccountPolicyStore(it->account_id,
+ session_manager_client_,
+ device_settings_service_,
+ store_background_task_runner_));
+ store->AddObserver(this);
+ broker.reset(new DeviceLocalAccountPolicyBroker(
+ *it,
+ store.Pass(),
+ base::MessageLoopProxy::current()));
+ }
// Fire up the cloud connection for fetching policy for the account from
// the cloud if this is an enterprise-managed device.
- wrapper.ConnectIfPossible();
+ broker->ConnectIfPossible(device_settings_service_,
+ device_management_service_);
+
+ policy_brokers_[it->user_id] = broker.release();
+ if (!broker_initialized) {
+ // The broker must be initialized after it has been added to
+ // |policy_brokers_|.
+ policy_brokers_[it->user_id]->Initialize();
+ }
+
+ if (orphan_cache_deletion_state_ == NOT_STARTED) {
+ subdirectories_to_keep.insert(
+ GetCacheSubdirectoryForAccountID(it->account_id));
+ }
+ }
+
+ std::set<std::string> obsolete_account_ids;
+ for (PolicyBrokerMap::const_iterator it = old_policy_brokers.begin();
+ it != old_policy_brokers.end(); ++it) {
+ obsolete_account_ids.insert(it->second->account_id());
+ }
+
+ if (orphan_cache_deletion_state_ == NOT_STARTED) {
+ DCHECK(old_policy_brokers.empty());
+ DCHECK(busy_extension_cache_directories_.empty());
+
+ // If this method is running for the first time, no extension caches have
+ // been started yet. Take this opportunity to do a clean-up by removing
+ // orphaned cache directories not found in |subdirectories_to_keep| from the
+ // cache directory.
+ orphan_cache_deletion_state_ = IN_PROGRESS;
+ extension_cache_task_runner_->PostTaskAndReply(
+ FROM_HERE,
+ base::Bind(&DeleteOrphanedExtensionCaches, subdirectories_to_keep),
+ base::Bind(&DeviceLocalAccountPolicyService::
+ OnOrphanedExtensionCachesDeleted,
+ weak_factory_.GetWeakPtr()));
+
+ // Start the extension caches for all brokers. These belong to accounts in
+ // |account_ids| and are not affected by the clean-up.
+ StartExtensionCachesIfPossible();
+ } else {
+ // If this method has run before, obsolete brokers may exist. Shut down
+ // their extension caches and delete the brokers.
+ DeleteBrokers(&old_policy_brokers);
+
+ if (orphan_cache_deletion_state_ == DONE) {
+ // If the initial clean-up of orphaned cache directories has been
+ // complete, start any extension caches that are not running yet but can
+ // be started now because their cache directories are not busy.
+ StartExtensionCachesIfPossible();
+ }
}
- DeleteBrokers(&old_policy_brokers);
FOR_EACH_OBSERVER(Observer, observers_, OnDeviceLocalAccountsChanged());
}
void DeviceLocalAccountPolicyService::DeleteBrokers(PolicyBrokerMap* map) {
- for (PolicyBrokerMap::iterator it = map->begin(); it != map->end(); ++it)
- it->second.DeleteBroker();
+ for (PolicyBrokerMap::iterator it = map->begin(); it != map->end(); ++it) {
+ it->second->core()->store()->RemoveObserver(this);
+ scoped_refptr<chromeos::DeviceLocalAccountExternalPolicyLoader>
+ extension_loader = it->second->extension_loader();
+ if (extension_loader->IsCacheRunning()) {
+ DCHECK(!IsExtensionCacheDirectoryBusy(it->second->account_id()));
+ busy_extension_cache_directories_.insert(it->second->account_id());
+ extension_loader->StopCache(base::Bind(
+ &DeviceLocalAccountPolicyService::OnObsoleteExtensionCacheShutdown,
+ weak_factory_.GetWeakPtr(),
+ it->second->account_id()));
+ }
+ delete it->second;
+ }
map->clear();
}
@@ -278,8 +475,8 @@ DeviceLocalAccountPolicyBroker*
CloudPolicyStore* store) {
for (PolicyBrokerMap::iterator it(policy_brokers_.begin());
it != policy_brokers_.end(); ++it) {
- if (it->second.broker && it->second.broker->core()->store() == store)
- return it->second.broker;
+ if (it->second->core()->store() == store)
+ return it->second;
}
return NULL;
}
diff --git a/chrome/browser/chromeos/policy/device_local_account_policy_service.h b/chrome/browser/chromeos/policy/device_local_account_policy_service.h
index 02b82f4de2..268f0a70a8 100644
--- a/chrome/browser/chromeos/policy/device_local_account_policy_service.h
+++ b/chrome/browser/chromeos/policy/device_local_account_policy_service.h
@@ -6,6 +6,7 @@
#define CHROME_BROWSER_CHROMEOS_POLICY_DEVICE_LOCAL_ACCOUNT_POLICY_SERVICE_H_
#include <map>
+#include <set>
#include <string>
#include "base/basictypes.h"
@@ -14,6 +15,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
+#include "chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.h"
#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/policy/cloud/cloud_policy_core.h"
#include "chrome/browser/policy/cloud/cloud_policy_store.h"
@@ -23,14 +25,13 @@ class SequencedTaskRunner;
}
namespace chromeos {
-class CrosSettings;
class DeviceSettingsService;
class SessionManagerClient;
}
namespace policy {
-class CloudPolicyClient;
+struct DeviceLocalAccount;
class DeviceLocalAccountPolicyStore;
class DeviceManagementService;
@@ -39,19 +40,31 @@ class DeviceManagementService;
class DeviceLocalAccountPolicyBroker {
public:
// |task_runner| is the runner for policy refresh tasks.
- explicit DeviceLocalAccountPolicyBroker(
- const std::string& user_id,
+ DeviceLocalAccountPolicyBroker(
+ const DeviceLocalAccount& account,
scoped_ptr<DeviceLocalAccountPolicyStore> store,
const scoped_refptr<base::SequencedTaskRunner>& task_runner);
~DeviceLocalAccountPolicyBroker();
+ // Initialize the broker, loading its |store_|.
+ void Initialize();
+
+ // For the difference between |account_id| and |user_id|, see the
+ // documentation of DeviceLocalAccount.
+ const std::string& account_id() const { return account_id_; }
const std::string& user_id() const { return user_id_; }
+ scoped_refptr<chromeos::DeviceLocalAccountExternalPolicyLoader>
+ extension_loader() const { return extension_loader_; }
+
CloudPolicyCore* core() { return &core_; }
const CloudPolicyCore* core() const { return &core_; }
- // Establish a cloud connection for the service.
- void Connect(scoped_ptr<CloudPolicyClient> client);
+ // Fire up the cloud connection for fetching policy for the account from the
+ // cloud if this is an enterprise-managed device.
+ void ConnectIfPossible(
+ chromeos::DeviceSettingsService* device_settings_service,
+ DeviceManagementService* device_management_service);
// Destroy the cloud connection, stopping policy refreshes.
void Disconnect();
@@ -64,8 +77,11 @@ class DeviceLocalAccountPolicyBroker {
std::string GetDisplayName() const;
private:
+ const std::string account_id_;
const std::string user_id_;
- scoped_ptr<DeviceLocalAccountPolicyStore> store_;
+ const scoped_ptr<DeviceLocalAccountPolicyStore> store_;
+ scoped_refptr<chromeos::DeviceLocalAccountExternalPolicyLoader>
+ extension_loader_;
CloudPolicyCore core_;
DISALLOW_COPY_AND_ASSIGN(DeviceLocalAccountPolicyBroker);
@@ -92,7 +108,9 @@ class DeviceLocalAccountPolicyService : public CloudPolicyStore::Observer {
DeviceLocalAccountPolicyService(
chromeos::SessionManagerClient* session_manager_client,
chromeos::DeviceSettingsService* device_settings_service,
- chromeos::CrosSettings* cros_settings);
+ chromeos::CrosSettings* cros_settings,
+ scoped_refptr<base::SequencedTaskRunner> store_background_task_runner,
+ scoped_refptr<base::SequencedTaskRunner> extension_cache_task_runner);
virtual ~DeviceLocalAccountPolicyService();
// Initializes the cloud policy service connection.
@@ -117,29 +135,32 @@ class DeviceLocalAccountPolicyService : public CloudPolicyStore::Observer {
virtual void OnStoreError(CloudPolicyStore* store) OVERRIDE;
private:
- struct PolicyBrokerWrapper {
- PolicyBrokerWrapper();
+ typedef std::map<std::string, DeviceLocalAccountPolicyBroker*>
+ PolicyBrokerMap;
- // Return the |broker|, creating it first if necessary.
- DeviceLocalAccountPolicyBroker* GetBroker();
+ // Returns |true| if the directory in which force-installed extensions are
+ // cached for |account_id| is busy, either because a broker that was using
+ // this directory has not shut down completely yet or because the directory is
+ // being deleted.
+ bool IsExtensionCacheDirectoryBusy(const std::string& account_id);
- // Fire up the cloud connection for fetching policy for the account from the
- // cloud if this is an enterprise-managed device.
- void ConnectIfPossible();
+ // Starts any extension caches that are not running yet but can be started now
+ // because their cache directories are no longer busy.
+ void StartExtensionCachesIfPossible();
- // Destroy the cloud connection.
- void Disconnect();
+ // Checks whether a broker exists for |account_id|. If so, starts the broker's
+ // extension cache and returns |true|. Otherwise, returns |false|.
+ bool StartExtensionCacheForAccountIfPresent(const std::string& account_id);
- // Delete the broker.
- void DeleteBroker();
+ // Called back when any extension caches belonging to device-local accounts
+ // that no longer exist have been removed at start-up.
+ void OnOrphanedExtensionCachesDeleted();
- std::string user_id;
- std::string account_id;
- DeviceLocalAccountPolicyService* parent;
- DeviceLocalAccountPolicyBroker* broker;
- };
+ // Called back when the extension cache for |account_id| has been shut down.
+ void OnObsoleteExtensionCacheShutdown(const std::string& account_id);
- typedef std::map<std::string, PolicyBrokerWrapper> PolicyBrokerMap;
+ // Called back when the extension cache for |account_id| has been removed.
+ void OnObsoleteExtensionCacheDeleted(const std::string& account_id);
// Re-queries the list of defined device-local accounts from device settings
// and updates |policy_brokers_| to match that list.
@@ -163,14 +184,33 @@ class DeviceLocalAccountPolicyService : public CloudPolicyStore::Observer {
// The device-local account policy brokers, keyed by user ID.
PolicyBrokerMap policy_brokers_;
+ // Whether a call to UpdateAccountList() is pending because |cros_settings_|
+ // are not trusted yet.
+ bool waiting_for_cros_settings_;
+
+ // Orphaned extension caches are removed at startup. This tracks the status of
+ // that process.
+ enum OrphanCacheDeletionState {
+ NOT_STARTED,
+ IN_PROGRESS,
+ DONE,
+ };
+ OrphanCacheDeletionState orphan_cache_deletion_state_;
+
+ // Account IDs whose extension cache directories are busy, either because a
+ // broker for the account has not shut down completely yet or because the
+ // directory is being deleted.
+ std::set<std::string> busy_extension_cache_directories_;
+
+ const scoped_refptr<base::SequencedTaskRunner> store_background_task_runner_;
+ const scoped_refptr<base::SequencedTaskRunner> extension_cache_task_runner_;
+
ObserverList<Observer, true> observers_;
- scoped_ptr<chromeos::CrosSettings::ObserverSubscription>
+ const scoped_ptr<chromeos::CrosSettings::ObserverSubscription>
local_accounts_subscription_;
- // Weak pointer factory for cros_settings_->PrepareTrustedValues() callbacks.
- base::WeakPtrFactory<DeviceLocalAccountPolicyService>
- cros_settings_callback_factory_;
+ base::WeakPtrFactory<DeviceLocalAccountPolicyService> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(DeviceLocalAccountPolicyService);
};
diff --git a/chrome/browser/chromeos/policy/device_local_account_policy_service_unittest.cc b/chrome/browser/chromeos/policy/device_local_account_policy_service_unittest.cc
index 8312db92f4..d6c81226d6 100644
--- a/chrome/browser/chromeos/policy/device_local_account_policy_service_unittest.cc
+++ b/chrome/browser/chromeos/policy/device_local_account_policy_service_unittest.cc
@@ -7,6 +7,17 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/file_util.h"
+#include "base/files/file_path.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "base/path_service.h"
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/scoped_path_override.h"
+#include "base/test/test_simple_task_runner.h"
#include "chrome/browser/chromeos/policy/device_local_account.h"
#include "chrome/browser/chromeos/policy/device_local_account_policy_provider.h"
#include "chrome/browser/chromeos/settings/cros_settings.h"
@@ -20,8 +31,11 @@
#include "chrome/browser/policy/external_data_fetcher.h"
#include "chrome/browser/policy/mock_configuration_policy_provider.h"
#include "chrome/browser/policy/proto/chromeos/chrome_device_policy.pb.h"
+#include "chrome/common/chrome_paths.h"
+#include "chromeos/chromeos_paths.h"
#include "chromeos/dbus/power_policy_controller.h"
#include "policy/policy_constants.h"
+#include "policy/proto/cloud_policy.pb.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::AnyNumber;
@@ -34,6 +48,19 @@ namespace em = enterprise_management;
namespace policy {
+namespace {
+
+const char kAccount1[] = "account1@localhost";
+const char kAccount2[] = "account2@localhost";
+const char kAccount3[] = "account3@localhost";
+
+const char kExtensionID[] = "kbmnembihfiondgfjekmnmcbddelicoi";
+const char kExtensionVersion[] = "1.0.0.0";
+const char kExtensionCRXPath[] = "extensions/hosted_app.crx";
+const char kUpdateURL[] = "https://clients2.google.com/service/update2/crx";
+
+} // namespace
+
class MockDeviceLocalAccountPolicyServiceObserver
: public DeviceLocalAccountPolicyService::Observer {
public:
@@ -41,273 +68,342 @@ class MockDeviceLocalAccountPolicyServiceObserver
MOCK_METHOD0(OnDeviceLocalAccountsChanged, void(void));
};
-class DeviceLocalAccountPolicyServiceTest
+class DeviceLocalAccountPolicyServiceTestBase
: public chromeos::DeviceSettingsTestBase {
public:
- DeviceLocalAccountPolicyServiceTest()
- : public_session_user_id_(GenerateDeviceLocalAccountUserId(
- PolicyBuilder::kFakeUsername,
- DeviceLocalAccount::TYPE_PUBLIC_SESSION)),
- cros_settings_(&device_settings_service_),
- service_(&device_settings_test_helper_,
- &device_settings_service_,
- &cros_settings_) {}
-
- virtual void SetUp() OVERRIDE {
- DeviceSettingsTestBase::SetUp();
-
- // Values implicitly enforced for public accounts.
- expected_policy_map_.Set(key::kLidCloseAction,
- POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER,
- base::Value::CreateIntegerValue(
- chromeos::PowerPolicyController::
- ACTION_STOP_SESSION),
- NULL);
- expected_policy_map_.Set(key::kShelfAutoHideBehavior,
- POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER,
- Value::CreateStringValue("Never"),
- NULL);
- expected_policy_map_.Set(key::kShowLogoutButtonInTray,
- POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER,
- Value::CreateBooleanValue(true),
- NULL);
- expected_policy_map_.Set(key::kFullscreenAllowed,
- POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER,
- Value::CreateBooleanValue(false),
- NULL);
-
- // Explicitly set value.
- expected_policy_map_.Set(key::kDisableSpdy,
- POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER,
- Value::CreateBooleanValue(true),
- NULL);
-
- device_local_account_policy_.payload().mutable_disablespdy()->set_value(
- true);
- device_local_account_policy_.policy_data().set_policy_type(
- dm_protocol::kChromePublicAccountPolicyType);
- device_local_account_policy_.policy_data().set_settings_entity_id(
- PolicyBuilder::kFakeUsername);
- device_local_account_policy_.Build();
-
- em::DeviceLocalAccountInfoProto* account =
- device_policy_.payload().mutable_device_local_accounts()->add_account();
- account->set_account_id(PolicyBuilder::kFakeUsername);
- account->set_type(
- em::DeviceLocalAccountInfoProto::ACCOUNT_TYPE_PUBLIC_SESSION);
- device_policy_.Build();
-
- service_.AddObserver(&service_observer_);
- }
-
- virtual void TearDown() OVERRIDE {
- service_.RemoveObserver(&service_observer_);
-
- DeviceSettingsTestBase::TearDown();
- }
-
- void InstallDevicePolicy() {
- EXPECT_CALL(service_observer_, OnDeviceLocalAccountsChanged());
- device_settings_test_helper_.set_policy_blob(device_policy_.GetBlob());
- ReloadDeviceSettings();
- Mock::VerifyAndClearExpectations(&service_observer_);
- }
+ DeviceLocalAccountPolicyServiceTestBase();
- MOCK_METHOD1(OnRefreshDone, void(bool));
+ virtual void SetUp() OVERRIDE;
+ virtual void TearDown() OVERRIDE;
+
+ void CreatePolicyService();
+
+ void InstallDeviceLocalAccountPolicy(const std::string& account_id);
+ void AddDeviceLocalAccountToPolicy(const std::string& account_id);
+ virtual void InstallDevicePolicy();
- const std::string public_session_user_id_;
+ const std::string account_1_user_id_;
+ const std::string account_2_user_id_;
PolicyMap expected_policy_map_;
UserPolicyBuilder device_local_account_policy_;
chromeos::CrosSettings cros_settings_;
- MockDeviceLocalAccountPolicyServiceObserver service_observer_;
+ scoped_refptr<base::TestSimpleTaskRunner> extension_cache_task_runner_;
MockDeviceManagementService mock_device_management_service_;
- DeviceLocalAccountPolicyService service_;
+ scoped_ptr<DeviceLocalAccountPolicyService> service_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DeviceLocalAccountPolicyServiceTestBase);
+};
+
+class DeviceLocalAccountPolicyServiceTest
+ : public DeviceLocalAccountPolicyServiceTestBase {
+ public:
+ MOCK_METHOD1(OnRefreshDone, void(bool));
+
+ protected:
+ DeviceLocalAccountPolicyServiceTest();
+
+ virtual void SetUp() OVERRIDE;
+ virtual void TearDown() OVERRIDE;
+
+ void InstallDevicePolicy() OVERRIDE;
+
+ MockDeviceLocalAccountPolicyServiceObserver service_observer_;
private:
DISALLOW_COPY_AND_ASSIGN(DeviceLocalAccountPolicyServiceTest);
};
+DeviceLocalAccountPolicyServiceTestBase::
+ DeviceLocalAccountPolicyServiceTestBase()
+ : account_1_user_id_(GenerateDeviceLocalAccountUserId(
+ kAccount1,
+ DeviceLocalAccount::TYPE_PUBLIC_SESSION)),
+ account_2_user_id_(GenerateDeviceLocalAccountUserId(
+ kAccount2,
+ DeviceLocalAccount::TYPE_PUBLIC_SESSION)),
+ cros_settings_(&device_settings_service_),
+ extension_cache_task_runner_(new base::TestSimpleTaskRunner) {
+}
+
+void DeviceLocalAccountPolicyServiceTestBase::SetUp() {
+ chromeos::DeviceSettingsTestBase::SetUp();
+
+ // Values implicitly enforced for public accounts.
+ expected_policy_map_.Set(key::kLidCloseAction,
+ POLICY_LEVEL_MANDATORY,
+ POLICY_SCOPE_USER,
+ base::Value::CreateIntegerValue(
+ chromeos::PowerPolicyController::
+ ACTION_STOP_SESSION),
+ NULL);
+ expected_policy_map_.Set(key::kShelfAutoHideBehavior,
+ POLICY_LEVEL_MANDATORY,
+ POLICY_SCOPE_USER,
+ Value::CreateStringValue("Never"),
+ NULL);
+ expected_policy_map_.Set(key::kShowLogoutButtonInTray,
+ POLICY_LEVEL_MANDATORY,
+ POLICY_SCOPE_USER,
+ Value::CreateBooleanValue(true),
+ NULL);
+ expected_policy_map_.Set(key::kFullscreenAllowed,
+ POLICY_LEVEL_MANDATORY,
+ POLICY_SCOPE_USER,
+ Value::CreateBooleanValue(false),
+ NULL);
+
+ // Explicitly set value.
+ expected_policy_map_.Set(key::kDisableSpdy,
+ POLICY_LEVEL_MANDATORY,
+ POLICY_SCOPE_USER,
+ Value::CreateBooleanValue(true),
+ NULL);
+
+ device_local_account_policy_.payload().mutable_disablespdy()->set_value(
+ true);
+ device_local_account_policy_.policy_data().set_policy_type(
+ dm_protocol::kChromePublicAccountPolicyType);
+}
+
+void DeviceLocalAccountPolicyServiceTestBase::TearDown() {
+ service_.reset();
+ extension_cache_task_runner_->RunUntilIdle();
+ chromeos::DeviceSettingsTestBase::TearDown();
+}
+
+void DeviceLocalAccountPolicyServiceTestBase::CreatePolicyService() {
+ service_.reset(new DeviceLocalAccountPolicyService(
+ &device_settings_test_helper_,
+ &device_settings_service_,
+ &cros_settings_,
+ loop_.message_loop_proxy(),
+ extension_cache_task_runner_));
+}
+
+void DeviceLocalAccountPolicyServiceTestBase::
+ InstallDeviceLocalAccountPolicy(const std::string& account_id) {
+ device_local_account_policy_.policy_data().set_settings_entity_id(account_id);
+ device_local_account_policy_.policy_data().set_username(account_id);
+ device_local_account_policy_.Build();
+ device_settings_test_helper_.set_device_local_account_policy_blob(
+ account_id, device_local_account_policy_.GetBlob());
+}
+
+void DeviceLocalAccountPolicyServiceTestBase::AddDeviceLocalAccountToPolicy(
+ const std::string& account_id) {
+ em::DeviceLocalAccountInfoProto* account =
+ device_policy_.payload().mutable_device_local_accounts()->add_account();
+ account->set_account_id(account_id);
+ account->set_type(
+ em::DeviceLocalAccountInfoProto::ACCOUNT_TYPE_PUBLIC_SESSION);
+}
+
+void DeviceLocalAccountPolicyServiceTestBase::InstallDevicePolicy() {
+ device_policy_.Build();
+ device_settings_test_helper_.set_policy_blob(device_policy_.GetBlob());
+ ReloadDeviceSettings();
+}
+
+DeviceLocalAccountPolicyServiceTest::DeviceLocalAccountPolicyServiceTest() {
+ CreatePolicyService();
+}
+
+void DeviceLocalAccountPolicyServiceTest::SetUp() {
+ DeviceLocalAccountPolicyServiceTestBase::SetUp();
+ service_->AddObserver(&service_observer_);
+}
+
+void DeviceLocalAccountPolicyServiceTest::TearDown() {
+ service_->RemoveObserver(&service_observer_);
+ DeviceLocalAccountPolicyServiceTestBase::TearDown();
+}
+
+void DeviceLocalAccountPolicyServiceTest::InstallDevicePolicy() {
+ EXPECT_CALL(service_observer_, OnDeviceLocalAccountsChanged());
+ DeviceLocalAccountPolicyServiceTestBase::InstallDevicePolicy();
+ Mock::VerifyAndClearExpectations(&service_observer_);
+}
+
TEST_F(DeviceLocalAccountPolicyServiceTest, NoAccounts) {
- EXPECT_FALSE(service_.GetBrokerForUser(public_session_user_id_));
+ EXPECT_FALSE(service_->GetBrokerForUser(account_1_user_id_));
}
TEST_F(DeviceLocalAccountPolicyServiceTest, GetBroker) {
+ InstallDeviceLocalAccountPolicy(kAccount1);
+ AddDeviceLocalAccountToPolicy(kAccount1);
+ EXPECT_CALL(service_observer_, OnPolicyUpdated(account_1_user_id_));
InstallDevicePolicy();
DeviceLocalAccountPolicyBroker* broker =
- service_.GetBrokerForUser(public_session_user_id_);
+ service_->GetBrokerForUser(account_1_user_id_);
ASSERT_TRUE(broker);
- EXPECT_EQ(public_session_user_id_, broker->user_id());
+ EXPECT_EQ(account_1_user_id_, broker->user_id());
ASSERT_TRUE(broker->core()->store());
EXPECT_EQ(CloudPolicyStore::STATUS_OK, broker->core()->store()->status());
EXPECT_FALSE(broker->core()->client());
- EXPECT_TRUE(broker->core()->store()->policy_map().empty());
+ EXPECT_FALSE(broker->core()->store()->policy_map().empty());
}
TEST_F(DeviceLocalAccountPolicyServiceTest, LoadNoPolicy) {
+ AddDeviceLocalAccountToPolicy(kAccount1);
+ EXPECT_CALL(service_observer_, OnPolicyUpdated(account_1_user_id_));
InstallDevicePolicy();
- EXPECT_CALL(service_observer_, OnPolicyUpdated(public_session_user_id_));
DeviceLocalAccountPolicyBroker* broker =
- service_.GetBrokerForUser(public_session_user_id_);
+ service_->GetBrokerForUser(account_1_user_id_);
ASSERT_TRUE(broker);
- FlushDeviceSettings();
- Mock::VerifyAndClearExpectations(&service_observer_);
-
+ EXPECT_EQ(account_1_user_id_, broker->user_id());
ASSERT_TRUE(broker->core()->store());
EXPECT_EQ(CloudPolicyStore::STATUS_LOAD_ERROR,
broker->core()->store()->status());
EXPECT_TRUE(broker->core()->store()->policy_map().empty());
- EXPECT_FALSE(service_.IsPolicyAvailableForUser(public_session_user_id_));
+ EXPECT_FALSE(service_->IsPolicyAvailableForUser(account_1_user_id_));
}
TEST_F(DeviceLocalAccountPolicyServiceTest, LoadValidationFailure) {
device_local_account_policy_.policy_data().set_policy_type(
dm_protocol::kChromeUserPolicyType);
- device_local_account_policy_.Build();
- device_settings_test_helper_.set_device_local_account_policy_blob(
- PolicyBuilder::kFakeUsername, device_local_account_policy_.GetBlob());
+ InstallDeviceLocalAccountPolicy(kAccount1);
+ AddDeviceLocalAccountToPolicy(kAccount1);
+ EXPECT_CALL(service_observer_, OnPolicyUpdated(account_1_user_id_));
InstallDevicePolicy();
- EXPECT_CALL(service_observer_, OnPolicyUpdated(public_session_user_id_));
DeviceLocalAccountPolicyBroker* broker =
- service_.GetBrokerForUser(public_session_user_id_);
+ service_->GetBrokerForUser(account_1_user_id_);
ASSERT_TRUE(broker);
- FlushDeviceSettings();
- Mock::VerifyAndClearExpectations(&service_observer_);
-
+ EXPECT_EQ(account_1_user_id_, broker->user_id());
ASSERT_TRUE(broker->core()->store());
EXPECT_EQ(CloudPolicyStore::STATUS_VALIDATION_ERROR,
broker->core()->store()->status());
EXPECT_TRUE(broker->core()->store()->policy_map().empty());
- EXPECT_FALSE(service_.IsPolicyAvailableForUser(public_session_user_id_));
+ EXPECT_FALSE(service_->IsPolicyAvailableForUser(account_1_user_id_));
}
TEST_F(DeviceLocalAccountPolicyServiceTest, LoadPolicy) {
- device_settings_test_helper_.set_device_local_account_policy_blob(
- PolicyBuilder::kFakeUsername, device_local_account_policy_.GetBlob());
+ InstallDeviceLocalAccountPolicy(kAccount1);
+ AddDeviceLocalAccountToPolicy(kAccount1);
+ EXPECT_CALL(service_observer_, OnPolicyUpdated(account_1_user_id_));
InstallDevicePolicy();
- EXPECT_CALL(service_observer_, OnPolicyUpdated(public_session_user_id_));
DeviceLocalAccountPolicyBroker* broker =
- service_.GetBrokerForUser(public_session_user_id_);
+ service_->GetBrokerForUser(account_1_user_id_);
ASSERT_TRUE(broker);
- FlushDeviceSettings();
- Mock::VerifyAndClearExpectations(&service_observer_);
-
+ EXPECT_EQ(account_1_user_id_, broker->user_id());
ASSERT_TRUE(broker->core()->store());
- EXPECT_EQ(CloudPolicyStore::STATUS_OK,
- broker->core()->store()->status());
+ EXPECT_EQ(CloudPolicyStore::STATUS_OK, broker->core()->store()->status());
ASSERT_TRUE(broker->core()->store()->policy());
EXPECT_EQ(device_local_account_policy_.policy_data().SerializeAsString(),
broker->core()->store()->policy()->SerializeAsString());
EXPECT_TRUE(expected_policy_map_.Equals(
broker->core()->store()->policy_map()));
- EXPECT_TRUE(service_.IsPolicyAvailableForUser(public_session_user_id_));
+ EXPECT_TRUE(service_->IsPolicyAvailableForUser(account_1_user_id_));
}
TEST_F(DeviceLocalAccountPolicyServiceTest, StoreValidationFailure) {
- device_local_account_policy_.policy_data().set_policy_type(
- dm_protocol::kChromeUserPolicyType);
- device_local_account_policy_.Build();
+ AddDeviceLocalAccountToPolicy(kAccount1);
+ EXPECT_CALL(service_observer_, OnPolicyUpdated(account_1_user_id_));
InstallDevicePolicy();
+ Mock::VerifyAndClearExpectations(&service_observer_);
- EXPECT_CALL(service_observer_, OnPolicyUpdated(public_session_user_id_));
DeviceLocalAccountPolicyBroker* broker =
- service_.GetBrokerForUser(public_session_user_id_);
+ service_->GetBrokerForUser(account_1_user_id_);
ASSERT_TRUE(broker);
+ EXPECT_EQ(account_1_user_id_, broker->user_id());
ASSERT_TRUE(broker->core()->store());
+
+ device_local_account_policy_.policy_data().set_policy_type(
+ dm_protocol::kChromeUserPolicyType);
+ device_local_account_policy_.Build();
broker->core()->store()->Store(device_local_account_policy_.policy());
+ EXPECT_CALL(service_observer_, OnPolicyUpdated(account_1_user_id_));
FlushDeviceSettings();
- Mock::VerifyAndClearExpectations(&service_observer_);
- ASSERT_TRUE(broker->core()->store());
EXPECT_EQ(CloudPolicyStore::STATUS_VALIDATION_ERROR,
broker->core()->store()->status());
EXPECT_EQ(CloudPolicyValidatorBase::VALIDATION_WRONG_POLICY_TYPE,
broker->core()->store()->validation_status());
- EXPECT_FALSE(service_.IsPolicyAvailableForUser(public_session_user_id_));
+ EXPECT_FALSE(service_->IsPolicyAvailableForUser(account_1_user_id_));
}
TEST_F(DeviceLocalAccountPolicyServiceTest, StorePolicy) {
+ AddDeviceLocalAccountToPolicy(kAccount1);
+ EXPECT_CALL(service_observer_, OnPolicyUpdated(account_1_user_id_));
InstallDevicePolicy();
+ Mock::VerifyAndClearExpectations(&service_observer_);
- EXPECT_CALL(service_observer_, OnPolicyUpdated(public_session_user_id_));
DeviceLocalAccountPolicyBroker* broker =
- service_.GetBrokerForUser(public_session_user_id_);
+ service_->GetBrokerForUser(account_1_user_id_);
ASSERT_TRUE(broker);
+ EXPECT_EQ(account_1_user_id_, broker->user_id());
ASSERT_TRUE(broker->core()->store());
+
+ device_local_account_policy_.policy_data().set_settings_entity_id(kAccount1);
+ device_local_account_policy_.policy_data().set_username(kAccount1);
+ device_local_account_policy_.Build();
broker->core()->store()->Store(device_local_account_policy_.policy());
+ EXPECT_CALL(service_observer_, OnPolicyUpdated(account_1_user_id_));
FlushDeviceSettings();
- Mock::VerifyAndClearExpectations(&service_observer_);
- EXPECT_EQ(device_local_account_policy_.GetBlob(),
- device_settings_test_helper_.device_local_account_policy_blob(
- PolicyBuilder::kFakeUsername));
- EXPECT_TRUE(service_.IsPolicyAvailableForUser(public_session_user_id_));
+ EXPECT_EQ(CloudPolicyStore::STATUS_OK, broker->core()->store()->status());
+ ASSERT_TRUE(broker->core()->store()->policy());
+ EXPECT_EQ(device_local_account_policy_.policy_data().SerializeAsString(),
+ broker->core()->store()->policy()->SerializeAsString());
+ EXPECT_TRUE(expected_policy_map_.Equals(
+ broker->core()->store()->policy_map()));
+ EXPECT_TRUE(service_->IsPolicyAvailableForUser(account_1_user_id_));
}
TEST_F(DeviceLocalAccountPolicyServiceTest, DevicePolicyChange) {
- device_settings_test_helper_.set_device_local_account_policy_blob(
- PolicyBuilder::kFakeUsername, device_local_account_policy_.GetBlob());
+ InstallDeviceLocalAccountPolicy(kAccount1);
+ AddDeviceLocalAccountToPolicy(kAccount1);
+ EXPECT_CALL(service_observer_, OnPolicyUpdated(account_1_user_id_));
InstallDevicePolicy();
- EXPECT_CALL(service_observer_, OnDeviceLocalAccountsChanged());
device_policy_.payload().mutable_device_local_accounts()->clear_account();
- device_policy_.Build();
- device_settings_test_helper_.set_policy_blob(device_policy_.GetBlob());
- device_settings_service_.PropertyChangeComplete(true);
- FlushDeviceSettings();
- EXPECT_FALSE(service_.GetBrokerForUser(public_session_user_id_));
- Mock::VerifyAndClearExpectations(&service_observer_);
+ InstallDevicePolicy();
+
+ EXPECT_FALSE(service_->GetBrokerForUser(account_1_user_id_));
}
TEST_F(DeviceLocalAccountPolicyServiceTest, DuplicateAccounts) {
+ InstallDeviceLocalAccountPolicy(kAccount1);
+ AddDeviceLocalAccountToPolicy(kAccount1);
+ EXPECT_CALL(service_observer_, OnPolicyUpdated(account_1_user_id_));
InstallDevicePolicy();
- DeviceLocalAccountPolicyBroker* broker =
- service_.GetBrokerForUser(public_session_user_id_);
- ASSERT_TRUE(broker);
+ Mock::VerifyAndClearExpectations(&service_observer_);
// Add a second entry with a duplicate account name to device policy.
- em::DeviceLocalAccountInfoProto* account =
- device_policy_.payload().mutable_device_local_accounts()->add_account();
- account->set_account_id(PolicyBuilder::kFakeUsername);
- account->set_type(
- em::DeviceLocalAccountInfoProto::ACCOUNT_TYPE_PUBLIC_SESSION);
- device_policy_.Build();
- device_settings_test_helper_.set_device_local_account_policy_blob(
- PolicyBuilder::kFakeUsername, device_local_account_policy_.GetBlob());
- device_settings_test_helper_.set_policy_blob(device_policy_.GetBlob());
-
- EXPECT_CALL(service_observer_, OnDeviceLocalAccountsChanged());
- EXPECT_CALL(service_observer_, OnPolicyUpdated(public_session_user_id_));
- device_settings_service_.PropertyChangeComplete(true);
- FlushDeviceSettings();
- Mock::VerifyAndClearExpectations(&service_observer_);
+ AddDeviceLocalAccountToPolicy(kAccount1);
+ InstallDevicePolicy();
// Make sure the broker is accessible and policy got loaded.
- broker = service_.GetBrokerForUser(public_session_user_id_);
+ DeviceLocalAccountPolicyBroker* broker =
+ service_->GetBrokerForUser(account_1_user_id_);
ASSERT_TRUE(broker);
- EXPECT_EQ(public_session_user_id_, broker->user_id());
- EXPECT_TRUE(broker->core()->store()->policy());
+ EXPECT_EQ(account_1_user_id_, broker->user_id());
+ ASSERT_TRUE(broker->core()->store());
+ EXPECT_EQ(CloudPolicyStore::STATUS_OK, broker->core()->store()->status());
+ ASSERT_TRUE(broker->core()->store()->policy());
+ EXPECT_EQ(device_local_account_policy_.policy_data().SerializeAsString(),
+ broker->core()->store()->policy()->SerializeAsString());
+ EXPECT_TRUE(expected_policy_map_.Equals(
+ broker->core()->store()->policy_map()));
+ EXPECT_TRUE(service_->IsPolicyAvailableForUser(account_1_user_id_));
}
TEST_F(DeviceLocalAccountPolicyServiceTest, FetchPolicy) {
- device_settings_test_helper_.set_device_local_account_policy_blob(
- PolicyBuilder::kFakeUsername, device_local_account_policy_.GetBlob());
+ InstallDeviceLocalAccountPolicy(kAccount1);
+ AddDeviceLocalAccountToPolicy(kAccount1);
+ EXPECT_CALL(service_observer_, OnPolicyUpdated(account_1_user_id_));
InstallDevicePolicy();
DeviceLocalAccountPolicyBroker* broker =
- service_.GetBrokerForUser(public_session_user_id_);
+ service_->GetBrokerForUser(account_1_user_id_);
ASSERT_TRUE(broker);
- service_.Connect(&mock_device_management_service_);
+ service_->Connect(&mock_device_management_service_);
EXPECT_TRUE(broker->core()->client());
em::DeviceManagementRequest request;
@@ -325,7 +421,7 @@ TEST_F(DeviceLocalAccountPolicyServiceTest, FetchPolicy) {
device_policy_.policy_data().device_id(),
_))
.WillOnce(SaveArg<6>(&request));
- EXPECT_CALL(service_observer_, OnPolicyUpdated(public_session_user_id_));
+ EXPECT_CALL(service_observer_, OnPolicyUpdated(account_1_user_id_));
broker->core()->client()->FetchPolicy();
FlushDeviceSettings();
Mock::VerifyAndClearExpectations(&service_observer_);
@@ -335,7 +431,7 @@ TEST_F(DeviceLocalAccountPolicyServiceTest, FetchPolicy) {
EXPECT_EQ(dm_protocol::kChromePublicAccountPolicyType,
request.policy_request().request(0).policy_type());
EXPECT_FALSE(request.policy_request().request(0).has_machine_id());
- EXPECT_EQ(PolicyBuilder::kFakeUsername,
+ EXPECT_EQ(kAccount1,
request.policy_request().request(0).settings_entity_id());
ASSERT_TRUE(broker->core()->store());
@@ -346,26 +442,27 @@ TEST_F(DeviceLocalAccountPolicyServiceTest, FetchPolicy) {
broker->core()->store()->policy()->SerializeAsString());
EXPECT_TRUE(expected_policy_map_.Equals(
broker->core()->store()->policy_map()));
- EXPECT_TRUE(service_.IsPolicyAvailableForUser(public_session_user_id_));
+ EXPECT_TRUE(service_->IsPolicyAvailableForUser(account_1_user_id_));
- EXPECT_CALL(service_observer_, OnPolicyUpdated(public_session_user_id_))
+ EXPECT_CALL(service_observer_, OnPolicyUpdated(account_1_user_id_))
.Times(0);
- service_.Disconnect();
+ service_->Disconnect();
EXPECT_FALSE(broker->core()->client());
Mock::VerifyAndClearExpectations(&service_observer_);
- EXPECT_TRUE(service_.IsPolicyAvailableForUser(public_session_user_id_));
+ EXPECT_TRUE(service_->IsPolicyAvailableForUser(account_1_user_id_));
}
TEST_F(DeviceLocalAccountPolicyServiceTest, RefreshPolicy) {
- device_settings_test_helper_.set_device_local_account_policy_blob(
- PolicyBuilder::kFakeUsername, device_local_account_policy_.GetBlob());
+ InstallDeviceLocalAccountPolicy(kAccount1);
+ AddDeviceLocalAccountToPolicy(kAccount1);
+ EXPECT_CALL(service_observer_, OnPolicyUpdated(account_1_user_id_));
InstallDevicePolicy();
DeviceLocalAccountPolicyBroker* broker =
- service_.GetBrokerForUser(public_session_user_id_);
+ service_->GetBrokerForUser(account_1_user_id_);
ASSERT_TRUE(broker);
- service_.Connect(&mock_device_management_service_);
+ service_->Connect(&mock_device_management_service_);
ASSERT_TRUE(broker->core()->service());
em::DeviceManagementResponse response;
@@ -375,7 +472,7 @@ TEST_F(DeviceLocalAccountPolicyServiceTest, RefreshPolicy) {
.WillOnce(mock_device_management_service_.SucceedJob(response));
EXPECT_CALL(mock_device_management_service_, StartJob(_, _, _, _, _, _, _));
EXPECT_CALL(*this, OnRefreshDone(true)).Times(1);
- EXPECT_CALL(service_observer_, OnPolicyUpdated(public_session_user_id_));
+ EXPECT_CALL(service_observer_, OnPolicyUpdated(account_1_user_id_));
broker->core()->service()->RefreshPolicy(
base::Bind(&DeviceLocalAccountPolicyServiceTest::OnRefreshDone,
base::Unretained(this)));
@@ -389,90 +486,369 @@ TEST_F(DeviceLocalAccountPolicyServiceTest, RefreshPolicy) {
broker->core()->store()->status());
EXPECT_TRUE(expected_policy_map_.Equals(
broker->core()->store()->policy_map()));
- EXPECT_TRUE(service_.IsPolicyAvailableForUser(public_session_user_id_));
+ EXPECT_TRUE(service_->IsPolicyAvailableForUser(account_1_user_id_));
+}
+
+class DeviceLocalAccountPolicyExtensionCacheTest
+ : public DeviceLocalAccountPolicyServiceTestBase {
+ protected:
+ DeviceLocalAccountPolicyExtensionCacheTest();
+
+ virtual void SetUp() OVERRIDE;
+
+ base::FilePath GetCacheDirectoryForAccountID(const std::string& account_id);
+
+ base::ScopedTempDir cache_root_dir_;
+ scoped_ptr<base::ScopedPathOverride> cache_root_dir_override_;
+
+ base::FilePath cache_dir_1_;
+ base::FilePath cache_dir_2_;
+ base::FilePath cache_dir_3_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DeviceLocalAccountPolicyExtensionCacheTest);
+};
+
+DeviceLocalAccountPolicyExtensionCacheTest::
+ DeviceLocalAccountPolicyExtensionCacheTest() {
+}
+
+void DeviceLocalAccountPolicyExtensionCacheTest::SetUp() {
+ DeviceLocalAccountPolicyServiceTestBase::SetUp();
+ ASSERT_TRUE(cache_root_dir_.CreateUniqueTempDir());
+ cache_root_dir_override_.reset(new base::ScopedPathOverride(
+ chromeos::DIR_DEVICE_LOCAL_ACCOUNT_CACHE,
+ cache_root_dir_.path()));
+
+ cache_dir_1_ = GetCacheDirectoryForAccountID(kAccount1);
+ cache_dir_2_ = GetCacheDirectoryForAccountID(kAccount2);
+ cache_dir_3_ = GetCacheDirectoryForAccountID(kAccount3);
+
+ em::StringList* forcelist = device_local_account_policy_.payload()
+ .mutable_extensioninstallforcelist()->mutable_value();
+ forcelist->add_entries(base::StringPrintf("%s;%s", kExtensionID, kUpdateURL));
+}
+
+base::FilePath DeviceLocalAccountPolicyExtensionCacheTest::
+ GetCacheDirectoryForAccountID(const std::string& account_id) {
+ return cache_root_dir_.path().Append(base::HexEncode(account_id.c_str(),
+ account_id.size()));
+}
+
+// Verifies that during startup, orphaned cache directories are deleted,
+// cache directories belonging to an existing account are preserved and missing
+// cache directories are created. Also verifies that when startup is complete,
+// the caches for all existing accounts are running.
+TEST_F(DeviceLocalAccountPolicyExtensionCacheTest, Startup) {
+ base::FilePath test_data_dir;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir));
+ const base::FilePath source_crx_file =
+ test_data_dir.Append(kExtensionCRXPath);
+ const std::string target_crx_file_name =
+ base::StringPrintf("%s-%s.crx", kExtensionID, kExtensionVersion);
+
+ // Create and pre-populate a cache directory for account 1.
+ EXPECT_TRUE(file_util::CreateDirectory(cache_dir_1_));
+ EXPECT_TRUE(CopyFile(source_crx_file,
+ cache_dir_1_.Append(target_crx_file_name)));
+
+ // Create and pre-populate a cache directory for account 3.
+ EXPECT_TRUE(file_util::CreateDirectory(cache_dir_3_));
+ EXPECT_TRUE(CopyFile(source_crx_file,
+ cache_dir_3_.Append(target_crx_file_name)));
+
+ // Add accounts 1 and 2 to device policy.
+ InstallDeviceLocalAccountPolicy(kAccount1);
+ InstallDeviceLocalAccountPolicy(kAccount2);
+ AddDeviceLocalAccountToPolicy(kAccount1);
+ AddDeviceLocalAccountToPolicy(kAccount2);
+ InstallDevicePolicy();
+
+ // Create the DeviceLocalAccountPolicyService, allowing it to finish the
+ // deletion of orphaned cache directories.
+ CreatePolicyService();
+ FlushDeviceSettings();
+ extension_cache_task_runner_->RunUntilIdle();
+
+ // Verify that the cache directory for account 1 and its contents still exist.
+ EXPECT_TRUE(base::DirectoryExists(cache_dir_1_));
+ EXPECT_TRUE(ContentsEqual(source_crx_file,
+ cache_dir_1_.Append(target_crx_file_name)));
+
+ // Verify that a cache directory for account 2 was created.
+ EXPECT_TRUE(base::DirectoryExists(cache_dir_2_));
+
+ // Verify that the cache directory for account 3 was deleted.
+ EXPECT_FALSE(base::DirectoryExists(cache_dir_3_));
+
+ // Verify that the cache for account 1 has been started.
+ DeviceLocalAccountPolicyBroker* broker =
+ service_->GetBrokerForUser(account_1_user_id_);
+ ASSERT_TRUE(broker);
+ EXPECT_TRUE(broker->extension_loader()->IsCacheRunning());
+
+ // Verify that the cache for account 2 has been started.
+ broker = service_->GetBrokerForUser(account_2_user_id_);
+ ASSERT_TRUE(broker);
+ EXPECT_TRUE(broker->extension_loader()->IsCacheRunning());
+}
+
+// Verifies that while the deletion of orphaned cache directories is in
+// progress, the caches for accounts which existed before the deletion started
+// are running but caches for newly added accounts are not started.
+TEST_F(DeviceLocalAccountPolicyExtensionCacheTest, RaceAgainstOrphanDeletion) {
+ // Add account 1 to device policy.
+ InstallDeviceLocalAccountPolicy(kAccount1);
+ AddDeviceLocalAccountToPolicy(kAccount1);
+ InstallDevicePolicy();
+
+ // Create the DeviceLocalAccountPolicyService, triggering the deletion of
+ // orphaned cache directories.
+ CreatePolicyService();
+ FlushDeviceSettings();
+
+ // Verify that the cache for account 1 has been started as it is unaffected by
+ // the orphan deletion.
+ DeviceLocalAccountPolicyBroker* broker =
+ service_->GetBrokerForUser(account_1_user_id_);
+ ASSERT_TRUE(broker);
+ EXPECT_TRUE(broker->extension_loader()->IsCacheRunning());
+
+ // Add account 2 to device policy.
+ InstallDeviceLocalAccountPolicy(kAccount2);
+ AddDeviceLocalAccountToPolicy(kAccount2);
+ InstallDevicePolicy();
+
+ // Verify that the cache for account 2 has not been started yet as the orphan
+ // deletion is still in progress.
+ broker = service_->GetBrokerForUser(account_2_user_id_);
+ ASSERT_TRUE(broker);
+ EXPECT_FALSE(broker->extension_loader()->IsCacheRunning());
+
+ // Allow the orphan deletion to finish.
+ extension_cache_task_runner_->RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
+
+ // Verify that the cache for account 2 has been started.
+ EXPECT_TRUE(broker->extension_loader()->IsCacheRunning());
+}
+
+// Verifies that while the shutdown of a cache is in progress, no new cache is
+// started if an account with the same ID is re-added.
+TEST_F(DeviceLocalAccountPolicyExtensionCacheTest, RaceAgainstCacheShutdown) {
+ // Add account 1 to device policy.
+ InstallDeviceLocalAccountPolicy(kAccount1);
+ AddDeviceLocalAccountToPolicy(kAccount1);
+ InstallDevicePolicy();
+
+ // Create the DeviceLocalAccountPolicyService, allowing it to finish the
+ // deletion of orphaned cache directories.
+ CreatePolicyService();
+ FlushDeviceSettings();
+ extension_cache_task_runner_->RunUntilIdle();
+
+ // Remove account 1 from device policy, triggering a shutdown of its cache.
+ device_policy_.payload().mutable_device_local_accounts()->clear_account();
+ InstallDevicePolicy();
+
+ // Re-add account 1 to device policy.
+ AddDeviceLocalAccountToPolicy(kAccount1);
+ InstallDevicePolicy();
+
+ // Verify that the cache for account 1 has not been started yet as the
+ // shutdown of a previous cache for this account ID is still in progress.
+ DeviceLocalAccountPolicyBroker* broker =
+ service_->GetBrokerForUser(account_1_user_id_);
+ ASSERT_TRUE(broker);
+ EXPECT_FALSE(broker->extension_loader()->IsCacheRunning());
+
+ // Allow the cache shutdown to finish.
+ extension_cache_task_runner_->RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
+
+ // Verify that the cache directory for account 1 still exists.
+ EXPECT_TRUE(base::DirectoryExists(cache_dir_1_));
+
+ // Verify that the cache for account 1 has been started, reusing the existing
+ // cache directory.
+ EXPECT_TRUE(broker->extension_loader()->IsCacheRunning());
+}
+
+// Verifies that while the deletion of an obsolete cache directory is in
+// progress, no new cache is started if an account with the same ID is re-added.
+TEST_F(DeviceLocalAccountPolicyExtensionCacheTest,
+ RaceAgainstObsoleteDeletion) {
+ // Add account 1 to device policy.
+ InstallDeviceLocalAccountPolicy(kAccount1);
+ AddDeviceLocalAccountToPolicy(kAccount1);
+ InstallDevicePolicy();
+
+ // Create the DeviceLocalAccountPolicyService, allowing it to finish the
+ // deletion of orphaned cache directories.
+ CreatePolicyService();
+ FlushDeviceSettings();
+ extension_cache_task_runner_->RunUntilIdle();
+
+ // Remove account 1 from device policy, allowing the shutdown of its cache to
+ // finish and the deletion of its now obsolete cache directory to begin.
+ device_policy_.payload().mutable_device_local_accounts()->clear_account();
+ InstallDevicePolicy();
+ extension_cache_task_runner_->RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
+
+ // Re-add account 1 to device policy.
+ AddDeviceLocalAccountToPolicy(kAccount1);
+ InstallDevicePolicy();
+
+ // Verify that the cache for account 1 has not been started yet as the
+ // deletion of the cache directory for this account ID is still in progress.
+ DeviceLocalAccountPolicyBroker* broker =
+ service_->GetBrokerForUser(account_1_user_id_);
+ ASSERT_TRUE(broker);
+ EXPECT_FALSE(broker->extension_loader()->IsCacheRunning());
+
+ // Allow the deletion to finish.
+ extension_cache_task_runner_->RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
+
+ // Verify that the cache directory for account 1 was deleted.
+ EXPECT_FALSE(base::DirectoryExists(cache_dir_1_));
+
+ // Verify that the cache for account 1 has been started.
+ EXPECT_TRUE(broker->extension_loader()->IsCacheRunning());
+}
+
+// Verifies that when an account is added and no deletion of cache directories
+// affecting this account is in progress, its cache is started immediately.
+TEST_F(DeviceLocalAccountPolicyExtensionCacheTest, AddAccount) {
+ // Create the DeviceLocalAccountPolicyService, allowing it to finish the
+ // deletion of orphaned cache directories.
+ InstallDevicePolicy();
+ CreatePolicyService();
+ FlushDeviceSettings();
+ extension_cache_task_runner_->RunUntilIdle();
+
+ // Add account 1 to device policy.
+ InstallDeviceLocalAccountPolicy(kAccount1);
+ AddDeviceLocalAccountToPolicy(kAccount1);
+ InstallDevicePolicy();
+
+ // Verify that the cache for account 1 has been started.
+ DeviceLocalAccountPolicyBroker* broker =
+ service_->GetBrokerForUser(account_1_user_id_);
+ ASSERT_TRUE(broker);
+ EXPECT_TRUE(broker->extension_loader()->IsCacheRunning());
+}
+
+// Verifies that when an account is removed, its cache directory is deleted.
+TEST_F(DeviceLocalAccountPolicyExtensionCacheTest, RemoveAccount) {
+ // Add account 1 to device policy.
+ InstallDeviceLocalAccountPolicy(kAccount1);
+ AddDeviceLocalAccountToPolicy(kAccount1);
+ InstallDevicePolicy();
+
+ // Create the DeviceLocalAccountPolicyService, allowing it to finish the
+ // deletion of orphaned cache directories.
+ CreatePolicyService();
+ FlushDeviceSettings();
+ extension_cache_task_runner_->RunUntilIdle();
+
+ // Verify that a cache directory has been created for account 1.
+ EXPECT_TRUE(base::DirectoryExists(cache_dir_1_));
+
+ // Remove account 1 from device policy, allowing the deletion of its now
+ // obsolete cache directory to finish.
+ device_policy_.payload().mutable_device_local_accounts()->clear_account();
+ InstallDevicePolicy();
+ extension_cache_task_runner_->RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
+ extension_cache_task_runner_->RunUntilIdle();
+
+ // Verify that the cache directory for account 1 was deleted.
+ EXPECT_FALSE(base::DirectoryExists(cache_dir_1_));
}
class DeviceLocalAccountPolicyProviderTest
- : public DeviceLocalAccountPolicyServiceTest {
+ : public DeviceLocalAccountPolicyServiceTestBase {
protected:
- DeviceLocalAccountPolicyProviderTest()
- : provider_(
- GenerateDeviceLocalAccountUserId(
- PolicyBuilder::kFakeUsername,
- DeviceLocalAccount::TYPE_PUBLIC_SESSION),
- &service_) {}
-
- virtual void SetUp() OVERRIDE {
- DeviceLocalAccountPolicyServiceTest::SetUp();
- provider_.Init();
- provider_.AddObserver(&provider_observer_);
-
- EXPECT_CALL(service_observer_, OnPolicyUpdated(_)).Times(AnyNumber());
- EXPECT_CALL(service_observer_, OnDeviceLocalAccountsChanged())
- .Times(AnyNumber());
- }
-
- virtual void TearDown() OVERRIDE {
- provider_.RemoveObserver(&provider_observer_);
- provider_.Shutdown();
- DeviceLocalAccountPolicyServiceTest::TearDown();
- }
-
- DeviceLocalAccountPolicyProvider provider_;
+ DeviceLocalAccountPolicyProviderTest();
+
+ virtual void SetUp() OVERRIDE;
+ virtual void TearDown() OVERRIDE;
+
+ scoped_ptr<DeviceLocalAccountPolicyProvider> provider_;
MockConfigurationPolicyObserver provider_observer_;
private:
DISALLOW_COPY_AND_ASSIGN(DeviceLocalAccountPolicyProviderTest);
};
+DeviceLocalAccountPolicyProviderTest::DeviceLocalAccountPolicyProviderTest() {
+ CreatePolicyService();
+ provider_.reset(new DeviceLocalAccountPolicyProvider(
+ GenerateDeviceLocalAccountUserId(kAccount1,
+ DeviceLocalAccount::TYPE_PUBLIC_SESSION),
+ service_.get()));
+}
+
+void DeviceLocalAccountPolicyProviderTest::SetUp() {
+ DeviceLocalAccountPolicyServiceTestBase::SetUp();
+ provider_->Init();
+ provider_->AddObserver(&provider_observer_);
+}
+
+void DeviceLocalAccountPolicyProviderTest::TearDown() {
+ provider_->RemoveObserver(&provider_observer_);
+ provider_->Shutdown();
+ provider_.reset();
+ DeviceLocalAccountPolicyServiceTestBase::TearDown();
+}
+
TEST_F(DeviceLocalAccountPolicyProviderTest, Initialization) {
- EXPECT_FALSE(provider_.IsInitializationComplete(POLICY_DOMAIN_CHROME));
+ EXPECT_FALSE(provider_->IsInitializationComplete(POLICY_DOMAIN_CHROME));
// Policy change should complete initialization.
- EXPECT_CALL(provider_observer_, OnUpdatePolicy(&provider_)).Times(AtLeast(1));
- device_settings_test_helper_.set_device_local_account_policy_blob(
- PolicyBuilder::kFakeUsername, device_local_account_policy_.GetBlob());
- device_settings_test_helper_.set_policy_blob(device_policy_.GetBlob());
- ReloadDeviceSettings();
+ InstallDeviceLocalAccountPolicy(kAccount1);
+ AddDeviceLocalAccountToPolicy(kAccount1);
+ EXPECT_CALL(provider_observer_, OnUpdatePolicy(provider_.get()))
+ .Times(AtLeast(1));
+ InstallDevicePolicy();
Mock::VerifyAndClearExpectations(&provider_observer_);
- EXPECT_TRUE(provider_.IsInitializationComplete(POLICY_DOMAIN_CHROME));
+ EXPECT_TRUE(provider_->IsInitializationComplete(POLICY_DOMAIN_CHROME));
// The account disappearing should *not* flip the initialization flag back.
- EXPECT_CALL(provider_observer_, OnUpdatePolicy(&provider_))
+ EXPECT_CALL(provider_observer_, OnUpdatePolicy(provider_.get()))
.Times(AnyNumber());
device_policy_.payload().mutable_device_local_accounts()->clear_account();
- device_policy_.Build();
- device_settings_test_helper_.set_policy_blob(device_policy_.GetBlob());
- ReloadDeviceSettings();
+ InstallDevicePolicy();
Mock::VerifyAndClearExpectations(&provider_observer_);
- EXPECT_TRUE(provider_.IsInitializationComplete(POLICY_DOMAIN_CHROME));
+ EXPECT_TRUE(provider_->IsInitializationComplete(POLICY_DOMAIN_CHROME));
}
TEST_F(DeviceLocalAccountPolicyProviderTest, Policy) {
// Policy should load successfully.
- EXPECT_CALL(provider_observer_, OnUpdatePolicy(&provider_)).Times(AtLeast(1));
- device_settings_test_helper_.set_policy_blob(device_policy_.GetBlob());
- device_settings_test_helper_.set_device_local_account_policy_blob(
- PolicyBuilder::kFakeUsername, device_local_account_policy_.GetBlob());
- ReloadDeviceSettings();
+ EXPECT_CALL(provider_observer_, OnUpdatePolicy(provider_.get()))
+ .Times(AtLeast(1));
+ InstallDeviceLocalAccountPolicy(kAccount1);
+ AddDeviceLocalAccountToPolicy(kAccount1);
+ InstallDevicePolicy();
Mock::VerifyAndClearExpectations(&provider_observer_);
PolicyBundle expected_policy_bundle;
expected_policy_bundle.Get(PolicyNamespace(
POLICY_DOMAIN_CHROME, std::string())).CopyFrom(expected_policy_map_);
- EXPECT_TRUE(expected_policy_bundle.Equals(provider_.policies()));
+ EXPECT_TRUE(expected_policy_bundle.Equals(provider_->policies()));
// Policy change should be reported.
- EXPECT_CALL(provider_observer_, OnUpdatePolicy(&provider_)).Times(AtLeast(1));
+ EXPECT_CALL(provider_observer_, OnUpdatePolicy(provider_.get()))
+ .Times(AtLeast(1));
device_local_account_policy_.payload().mutable_disablespdy()->set_value(
false);
- device_local_account_policy_.Build();
- device_settings_test_helper_.set_device_local_account_policy_blob(
- PolicyBuilder::kFakeUsername, device_local_account_policy_.GetBlob());
+ InstallDeviceLocalAccountPolicy(kAccount1);
DeviceLocalAccountPolicyBroker* broker =
- service_.GetBrokerForUser(public_session_user_id_);
+ service_->GetBrokerForUser(account_1_user_id_);
ASSERT_TRUE(broker);
broker->core()->store()->Load();
FlushDeviceSettings();
@@ -485,57 +861,55 @@ TEST_F(DeviceLocalAccountPolicyProviderTest, Policy) {
POLICY_SCOPE_USER,
Value::CreateBooleanValue(false),
NULL);
- EXPECT_TRUE(expected_policy_bundle.Equals(provider_.policies()));
+ EXPECT_TRUE(expected_policy_bundle.Equals(provider_->policies()));
// Any values set for the |ShelfAutoHideBehavior|, |ShowLogoutButtonInTray|
// and |ExtensionAllowedTypes| policies should be overridden.
- EXPECT_CALL(provider_observer_, OnUpdatePolicy(&provider_)).Times(AtLeast(1));
+ EXPECT_CALL(provider_observer_, OnUpdatePolicy(provider_.get()))
+ .Times(AtLeast(1));
device_local_account_policy_.payload().mutable_shelfautohidebehavior()->
set_value("Always");
device_local_account_policy_.payload().mutable_showlogoutbuttonintray()->
set_value(false);
- device_local_account_policy_.Build();
- device_settings_test_helper_.set_device_local_account_policy_blob(
- PolicyBuilder::kFakeUsername, device_local_account_policy_.GetBlob());
+ InstallDeviceLocalAccountPolicy(kAccount1);
broker->core()->store()->Load();
FlushDeviceSettings();
Mock::VerifyAndClearExpectations(&provider_observer_);
- EXPECT_TRUE(expected_policy_bundle.Equals(provider_.policies()));
+ EXPECT_TRUE(expected_policy_bundle.Equals(provider_->policies()));
// Account disappears, policy should stay in effect.
- EXPECT_CALL(provider_observer_, OnUpdatePolicy(&provider_))
+ EXPECT_CALL(provider_observer_, OnUpdatePolicy(provider_.get()))
.Times(AnyNumber());
device_policy_.payload().mutable_device_local_accounts()->clear_account();
- device_policy_.Build();
- device_settings_test_helper_.set_policy_blob(device_policy_.GetBlob());
- ReloadDeviceSettings();
+ InstallDevicePolicy();
Mock::VerifyAndClearExpectations(&provider_observer_);
- EXPECT_TRUE(expected_policy_bundle.Equals(provider_.policies()));
+ EXPECT_TRUE(expected_policy_bundle.Equals(provider_->policies()));
}
TEST_F(DeviceLocalAccountPolicyProviderTest, RefreshPolicies) {
// If there's no device policy, the refresh completes immediately.
- EXPECT_FALSE(service_.GetBrokerForUser(public_session_user_id_));
- EXPECT_CALL(provider_observer_, OnUpdatePolicy(&provider_)).Times(AtLeast(1));
- provider_.RefreshPolicies();
+ EXPECT_FALSE(service_->GetBrokerForUser(account_1_user_id_));
+ EXPECT_CALL(provider_observer_, OnUpdatePolicy(provider_.get()))
+ .Times(AtLeast(1));
+ provider_->RefreshPolicies();
Mock::VerifyAndClearExpectations(&provider_observer_);
// Make device settings appear.
- EXPECT_CALL(provider_observer_, OnUpdatePolicy(&provider_))
+ EXPECT_CALL(provider_observer_, OnUpdatePolicy(provider_.get()))
.Times(AnyNumber());
- device_settings_test_helper_.set_policy_blob(device_policy_.GetBlob());
- ReloadDeviceSettings();
- Mock::VerifyAndClearExpectations(&provider_observer_);
- EXPECT_TRUE(service_.GetBrokerForUser(public_session_user_id_));
+ AddDeviceLocalAccountToPolicy(kAccount1);
+ InstallDevicePolicy();
+ EXPECT_TRUE(service_->GetBrokerForUser(account_1_user_id_));
// If there's no cloud connection, refreshes are still immediate.
DeviceLocalAccountPolicyBroker* broker =
- service_.GetBrokerForUser(public_session_user_id_);
+ service_->GetBrokerForUser(account_1_user_id_);
ASSERT_TRUE(broker);
EXPECT_FALSE(broker->core()->client());
- EXPECT_CALL(provider_observer_, OnUpdatePolicy(&provider_)).Times(AtLeast(1));
- provider_.RefreshPolicies();
+ EXPECT_CALL(provider_observer_, OnUpdatePolicy(provider_.get()))
+ .Times(AtLeast(1));
+ provider_->RefreshPolicies();
Mock::VerifyAndClearExpectations(&provider_observer_);
// Bring up the cloud connection. The refresh scheduler may fire refreshes at
@@ -545,7 +919,7 @@ TEST_F(DeviceLocalAccountPolicyProviderTest, RefreshPolicies) {
mock_device_management_service_.FailJob(DM_STATUS_REQUEST_FAILED));
EXPECT_CALL(mock_device_management_service_, StartJob(_, _, _, _, _, _, _))
.Times(AnyNumber());
- service_.Connect(&mock_device_management_service_);
+ service_->Connect(&mock_device_management_service_);
FlushDeviceSettings();
Mock::VerifyAndClearExpectations(&mock_device_management_service_);
@@ -555,16 +929,18 @@ TEST_F(DeviceLocalAccountPolicyProviderTest, RefreshPolicies) {
EXPECT_CALL(mock_device_management_service_, CreateJob(_))
.WillOnce(mock_device_management_service_.CreateAsyncJob(&request_job));
EXPECT_CALL(mock_device_management_service_, StartJob(_, _, _, _, _, _, _));
- provider_.RefreshPolicies();
+ provider_->RefreshPolicies();
ReloadDeviceSettings();
Mock::VerifyAndClearExpectations(&provider_observer_);
Mock::VerifyAndClearExpectations(&mock_device_management_service_);
- EXPECT_TRUE(provider_.IsInitializationComplete(POLICY_DOMAIN_CHROME));
+ EXPECT_TRUE(provider_->IsInitializationComplete(POLICY_DOMAIN_CHROME));
// When the response comes in, it should propagate and fire the notification.
- EXPECT_CALL(provider_observer_, OnUpdatePolicy(&provider_)).Times(AtLeast(1));
+ EXPECT_CALL(provider_observer_, OnUpdatePolicy(provider_.get()))
+ .Times(AtLeast(1));
ASSERT_TRUE(request_job);
em::DeviceManagementResponse response;
+ device_local_account_policy_.Build();
response.mutable_policy_response()->add_response()->CopyFrom(
device_local_account_policy_.policy());
request_job->SendResponse(DM_STATUS_SUCCESS, response);
diff --git a/chrome/browser/chromeos/policy/device_local_account_policy_store.cc b/chrome/browser/chromeos/policy/device_local_account_policy_store.cc
index 898733a134..553d5cf707 100644
--- a/chrome/browser/chromeos/policy/device_local_account_policy_store.cc
+++ b/chrome/browser/chromeos/policy/device_local_account_policy_store.cc
@@ -23,8 +23,10 @@ namespace policy {
DeviceLocalAccountPolicyStore::DeviceLocalAccountPolicyStore(
const std::string& account_id,
chromeos::SessionManagerClient* session_manager_client,
- chromeos::DeviceSettingsService* device_settings_service)
- : account_id_(account_id),
+ chromeos::DeviceSettingsService* device_settings_service,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner)
+ : UserCloudPolicyStoreBase(background_task_runner),
+ account_id_(account_id),
session_manager_client_(session_manager_client),
device_settings_service_(device_settings_service),
weak_factory_(this) {}
@@ -169,7 +171,8 @@ void DeviceLocalAccountPolicyStore::Validate(
}
scoped_ptr<UserCloudPolicyValidator> validator(
- UserCloudPolicyValidator::Create(policy_response.Pass()));
+ UserCloudPolicyValidator::Create(policy_response.Pass(),
+ background_task_runner()));
validator->ValidateUsername(account_id_);
validator->ValidatePolicyType(dm_protocol::kChromePublicAccountPolicyType);
validator->ValidateAgainstCurrentPolicy(
diff --git a/chrome/browser/chromeos/policy/device_local_account_policy_store.h b/chrome/browser/chromeos/policy/device_local_account_policy_store.h
index 9036bb6de7..3af5134e47 100644
--- a/chrome/browser/chromeos/policy/device_local_account_policy_store.h
+++ b/chrome/browser/chromeos/policy/device_local_account_policy_store.h
@@ -9,12 +9,17 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/chromeos/settings/device_settings_service.h"
#include "chrome/browser/policy/cloud/cloud_policy_validator.h"
#include "chrome/browser/policy/cloud/user_cloud_policy_store_base.h"
+namespace base {
+class SequencedTaskRunner;
+}
+
namespace chromeos {
class DeviceSettingsService;
class SessionManagerClient;
@@ -36,7 +41,8 @@ class DeviceLocalAccountPolicyStore
DeviceLocalAccountPolicyStore(
const std::string& account_id,
chromeos::SessionManagerClient* client,
- chromeos::DeviceSettingsService* device_settings_service);
+ chromeos::DeviceSettingsService* device_settings_service,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner);
virtual ~DeviceLocalAccountPolicyStore();
const std::string& account_id() const { return account_id_; }
@@ -76,6 +82,8 @@ class DeviceLocalAccountPolicyStore
chromeos::SessionManagerClient* session_manager_client_;
chromeos::DeviceSettingsService* device_settings_service_;
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
+
base::WeakPtrFactory<DeviceLocalAccountPolicyStore> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(DeviceLocalAccountPolicyStore);
diff --git a/chrome/browser/chromeos/policy/device_policy_cros_browser_test.cc b/chrome/browser/chromeos/policy/device_policy_cros_browser_test.cc
index 93058379ed..26065eb99f 100644
--- a/chrome/browser/chromeos/policy/device_policy_cros_browser_test.cc
+++ b/chrome/browser/chromeos/policy/device_policy_cros_browser_test.cc
@@ -15,8 +15,8 @@
#include "chrome/browser/chromeos/policy/enterprise_install_attributes.h"
#include "chrome/browser/policy/proto/chromeos/install_attributes.pb.h"
#include "chromeos/chromeos_paths.h"
+#include "chromeos/dbus/fake_dbus_thread_manager.h"
#include "chromeos/dbus/fake_session_manager_client.h"
-#include "chromeos/dbus/mock_dbus_thread_manager_without_gmock.h"
#include "crypto/rsa_private_key.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -72,15 +72,15 @@ void DevicePolicyCrosTestHelper::InstallOwnerKey() {
}
DevicePolicyCrosBrowserTest::DevicePolicyCrosBrowserTest()
- : mock_dbus_thread_manager_(
- new chromeos::MockDBusThreadManagerWithoutGMock) {
+ : fake_dbus_thread_manager_(
+ new chromeos::FakeDBusThreadManager) {
}
DevicePolicyCrosBrowserTest::~DevicePolicyCrosBrowserTest() {
}
void DevicePolicyCrosBrowserTest::SetUpInProcessBrowserTestFixture() {
- chromeos::DBusThreadManager::InitializeForTesting(mock_dbus_thread_manager_);
+ chromeos::DBusThreadManager::InitializeForTesting(fake_dbus_thread_manager_);
InProcessBrowserTest::SetUpInProcessBrowserTestFixture();
}
diff --git a/chrome/browser/chromeos/policy/device_policy_cros_browser_test.h b/chrome/browser/chromeos/policy/device_policy_cros_browser_test.h
index 1a0dafc974..afe39ba19f 100644
--- a/chrome/browser/chromeos/policy/device_policy_cros_browser_test.h
+++ b/chrome/browser/chromeos/policy/device_policy_cros_browser_test.h
@@ -10,7 +10,7 @@
#include "base/files/scoped_temp_dir.h"
#include "chrome/browser/chromeos/policy/device_policy_builder.h"
#include "chrome/test/base/in_process_browser_test.h"
-#include "chromeos/dbus/mock_dbus_thread_manager_without_gmock.h"
+#include "chromeos/dbus/fake_dbus_thread_manager.h"
namespace chromeos {
class FakeSessionManagerClient;
@@ -64,12 +64,12 @@ class DevicePolicyCrosBrowserTest : public InProcessBrowserTest {
// recently changed).
void RefreshDevicePolicy();
- chromeos::MockDBusThreadManagerWithoutGMock* mock_dbus_thread_manager() {
- return mock_dbus_thread_manager_;
+ chromeos::FakeDBusThreadManager* fake_dbus_thread_manager() {
+ return fake_dbus_thread_manager_;
}
chromeos::FakeSessionManagerClient* session_manager_client() {
- return mock_dbus_thread_manager_->fake_session_manager_client();
+ return fake_dbus_thread_manager_->fake_session_manager_client();
}
DevicePolicyBuilder* device_policy() { return test_helper_.device_policy(); }
@@ -77,8 +77,8 @@ class DevicePolicyCrosBrowserTest : public InProcessBrowserTest {
private:
DevicePolicyCrosTestHelper test_helper_;
- // MockDBusThreadManagerWithoutGMock uses FakeSessionManagerClient.
- chromeos::MockDBusThreadManagerWithoutGMock* mock_dbus_thread_manager_;
+ // FakeDBusThreadManager uses FakeSessionManagerClient.
+ chromeos::FakeDBusThreadManager* fake_dbus_thread_manager_;
DISALLOW_COPY_AND_ASSIGN(DevicePolicyCrosBrowserTest);
};
diff --git a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc
index c4990df245..182b46a76d 100644
--- a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc
+++ b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc
@@ -33,6 +33,7 @@ EnrollmentHandlerChromeOS::EnrollmentHandlerChromeOS(
DeviceCloudPolicyStoreChromeOS* store,
EnterpriseInstallAttributes* install_attributes,
scoped_ptr<CloudPolicyClient> client,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner,
const std::string& auth_token,
const std::string& client_id,
bool is_auto_enrollment,
@@ -42,6 +43,7 @@ EnrollmentHandlerChromeOS::EnrollmentHandlerChromeOS(
: store_(store),
install_attributes_(install_attributes),
client_(client.Pass()),
+ background_task_runner_(background_task_runner),
auth_token_(auth_token),
client_id_(client_id),
is_auto_enrollment_(is_auto_enrollment),
@@ -94,7 +96,8 @@ void EnrollmentHandlerChromeOS::OnPolicyFetched(CloudPolicyClient* client) {
scoped_ptr<DeviceCloudPolicyValidator> validator(
DeviceCloudPolicyValidator::Create(
scoped_ptr<em::PolicyFetchResponse>(
- new em::PolicyFetchResponse(*policy))));
+ new em::PolicyFetchResponse(*policy)),
+ background_task_runner_));
validator->ValidateTimestamp(base::Time(), base::Time::NowFromSystemTime(),
CloudPolicyValidatorBase::TIMESTAMP_REQUIRED);
diff --git a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.h b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.h
index c470e0881f..74b0fd17bc 100644
--- a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.h
+++ b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.h
@@ -9,6 +9,7 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
@@ -18,6 +19,10 @@
#include "chrome/browser/policy/cloud/cloud_policy_store.h"
#include "google_apis/gaia/gaia_oauth_client.h"
+namespace base {
+class SequencedTaskRunner;
+}
+
namespace enterprise_management {
class PolicyFetchResponse;
}
@@ -49,15 +54,17 @@ class EnrollmentHandlerChromeOS : public CloudPolicyClient::Observer,
// are acceptable. If the mode specified by the server is not acceptable,
// enrollment will fail with an EnrollmentStatus indicating
// STATUS_REGISTRATION_BAD_MODE.
- EnrollmentHandlerChromeOS(DeviceCloudPolicyStoreChromeOS* store,
- EnterpriseInstallAttributes* install_attributes,
- scoped_ptr<CloudPolicyClient> client,
- const std::string& auth_token,
- const std::string& client_id,
- bool is_auto_enrollment,
- const std::string& requisition,
- const AllowedDeviceModes& allowed_device_modes,
- const EnrollmentCallback& completion_callback);
+ EnrollmentHandlerChromeOS(
+ DeviceCloudPolicyStoreChromeOS* store,
+ EnterpriseInstallAttributes* install_attributes,
+ scoped_ptr<CloudPolicyClient> client,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner,
+ const std::string& auth_token,
+ const std::string& client_id,
+ bool is_auto_enrollment,
+ const std::string& requisition,
+ const AllowedDeviceModes& allowed_device_modes,
+ const EnrollmentCallback& completion_callback);
virtual ~EnrollmentHandlerChromeOS();
// Starts the enrollment process and reports the result to
@@ -138,6 +145,7 @@ class EnrollmentHandlerChromeOS : public CloudPolicyClient::Observer,
DeviceCloudPolicyStoreChromeOS* store_;
EnterpriseInstallAttributes* install_attributes_;
scoped_ptr<CloudPolicyClient> client_;
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
scoped_ptr<gaia::GaiaOAuthClient> gaia_oauth_client_;
std::string auth_token_;
diff --git a/chrome/browser/chromeos/policy/network_configuration_updater.cc b/chrome/browser/chromeos/policy/network_configuration_updater.cc
index d4f29c22ed..ae998cd958 100644
--- a/chrome/browser/chromeos/policy/network_configuration_updater.cc
+++ b/chrome/browser/chromeos/policy/network_configuration_updater.cc
@@ -91,9 +91,12 @@ void NetworkConfigurationUpdater::ImportCertificates(
}
void NetworkConfigurationUpdater::ApplyNetworkPolicy(
- base::ListValue* network_configs_onc) {
- network_config_handler_->SetPolicy(
- onc_source_, std::string() /* no username hash */, *network_configs_onc);
+ base::ListValue* network_configs_onc,
+ base::DictionaryValue* global_network_config) {
+ network_config_handler_->SetPolicy(onc_source_,
+ std::string() /* no username hash */,
+ *network_configs_onc,
+ *global_network_config);
}
void NetworkConfigurationUpdater::OnPolicyChanged(
@@ -115,15 +118,17 @@ void NetworkConfigurationUpdater::ApplyPolicy() {
LOG(ERROR) << LogHeader() << " is not a string value.";
base::ListValue network_configs;
+ base::DictionaryValue global_network_config;
base::ListValue certificates;
chromeos::onc::ParseAndValidateOncForImport(onc_blob,
onc_source_,
"" /* no passphrase */,
&network_configs,
+ &global_network_config,
&certificates);
ImportCertificates(certificates);
- ApplyNetworkPolicy(&network_configs);
+ ApplyNetworkPolicy(&network_configs, &global_network_config);
}
std::string NetworkConfigurationUpdater::LogHeader() const {
diff --git a/chrome/browser/chromeos/policy/network_configuration_updater.h b/chrome/browser/chromeos/policy/network_configuration_updater.h
index 3e7fe0d494..4b6556ba95 100644
--- a/chrome/browser/chromeos/policy/network_configuration_updater.h
+++ b/chrome/browser/chromeos/policy/network_configuration_updater.h
@@ -14,6 +14,8 @@
#include "components/onc/onc_constants.h"
namespace base {
+class DictionaryValue;
+class ListValue;
class Value;
}
@@ -69,7 +71,8 @@ class NetworkConfigurationUpdater : public PolicyService::Observer {
// Pushes the network part of the policy to the
// ManagedNetworkConfigurationHandler. This can be overridden by subclasses to
// modify |network_configs_onc| before the actual application.
- virtual void ApplyNetworkPolicy(base::ListValue* network_configs_onc);
+ virtual void ApplyNetworkPolicy(base::ListValue* network_configs_onc,
+ base::DictionaryValue* global_network_config);
onc::ONCSource onc_source_;
diff --git a/chrome/browser/chromeos/policy/network_configuration_updater_unittest.cc b/chrome/browser/chromeos/policy/network_configuration_updater_unittest.cc
index 6b48c5cad2..8f72c50a0a 100644
--- a/chrome/browser/chromeos/policy/network_configuration_updater_unittest.cc
+++ b/chrome/browser/chromeos/policy/network_configuration_updater_unittest.cc
@@ -71,6 +71,9 @@ const char kFakeONC[] =
" \"Security\": \"None\" }"
" }"
" ],"
+ " \"GlobalNetworkConfiguration\": {"
+ " \"AllowOnlyPolicyNetworksToAutoconnect\": true,"
+ " },"
" \"Certificates\": ["
" { \"GUID\": \"{f998f760-272b-6939-4c2beffe428697ac}\","
" \"PKCS12\": \"abc\","
@@ -79,20 +82,31 @@ const char kFakeONC[] =
" \"Type\": \"UnencryptedConfiguration\""
"}";
-std::string ValueToString(const base::Value* value) {
+std::string ValueToString(const base::Value& value) {
std::stringstream str;
- str << *value;
+ str << value;
return str.str();
}
+void AppendAll(const base::ListValue& from, base::ListValue* to) {
+ for (base::ListValue::const_iterator it = from.begin(); it != from.end();
+ ++it) {
+ to->Append((*it)->DeepCopy());
+ }
+}
+
// Matcher to match base::Value.
MATCHER_P(IsEqualTo,
value,
std::string(negation ? "isn't" : "is") + " equal to " +
- ValueToString(value)) {
+ ValueToString(*value)) {
return value->Equals(&arg);
}
+MATCHER(IsEmpty, std::string(negation ? "isn't" : "is") + " empty.") {
+ return arg.empty();
+}
+
ACTION_P(SetCertificateList, list) {
if (arg2)
*arg2 = list;
@@ -114,25 +128,23 @@ class NetworkConfigurationUpdaterTest : public testing::Test {
providers.push_back(&provider_);
policy_service_.reset(new PolicyServiceImpl(providers));
- empty_network_configs_.reset(new base::ListValue);
- empty_certificates_.reset(new base::ListValue);
-
scoped_ptr<base::DictionaryValue> fake_toplevel_onc =
chromeos::onc::ReadDictionaryFromJson(kFakeONC);
- scoped_ptr<base::Value> network_configs_value;
base::ListValue* network_configs = NULL;
- fake_toplevel_onc->RemoveWithoutPathExpansion(
- onc::toplevel_config::kNetworkConfigurations, &network_configs_value);
- network_configs_value.release()->GetAsList(&network_configs);
- fake_network_configs_.reset(network_configs);
+ fake_toplevel_onc->GetListWithoutPathExpansion(
+ onc::toplevel_config::kNetworkConfigurations, &network_configs);
+ AppendAll(*network_configs, &fake_network_configs_);
+
+ base::DictionaryValue* global_config = NULL;
+ fake_toplevel_onc->GetDictionaryWithoutPathExpansion(
+ onc::toplevel_config::kGlobalNetworkConfiguration, &global_config);
+ fake_global_network_config_.MergeDictionary(global_config);
- scoped_ptr<base::Value> certs_value;
base::ListValue* certs = NULL;
- fake_toplevel_onc->RemoveWithoutPathExpansion(
- onc::toplevel_config::kCertificates, &certs_value);
- certs_value.release()->GetAsList(&certs);
- fake_certificates_.reset(certs);
+ fake_toplevel_onc->GetListWithoutPathExpansion(
+ onc::toplevel_config::kCertificates, &certs);
+ AppendAll(*certs, &fake_certificates_);
certificate_importer_ =
new StrictMock<chromeos::onc::MockCertificateImporter>();
@@ -172,10 +184,9 @@ class NetworkConfigurationUpdaterTest : public testing::Test {
&network_config_handler_);
}
- scoped_ptr<base::ListValue> empty_network_configs_;
- scoped_ptr<base::ListValue> empty_certificates_;
- scoped_ptr<base::ListValue> fake_network_configs_;
- scoped_ptr<base::ListValue> fake_certificates_;
+ base::ListValue fake_network_configs_;
+ base::DictionaryValue fake_global_network_config_;
+ base::ListValue fake_certificates_;
StrictMock<chromeos::MockManagedNetworkConfigurationHandler>
network_config_handler_;
@@ -207,6 +218,12 @@ TEST_F(NetworkConfigurationUpdaterTest, PolicyIsValidatedAndRepaired) {
onc::toplevel_config::kNetworkConfigurations, &network_configs_repaired);
ASSERT_TRUE(network_configs_repaired);
+ base::DictionaryValue* global_config_repaired = NULL;
+ onc_repaired->GetDictionaryWithoutPathExpansion(
+ onc::toplevel_config::kGlobalNetworkConfiguration,
+ &global_config_repaired);
+ ASSERT_TRUE(global_config_repaired);
+
PolicyMap policy;
policy.Set(key::kOpenNetworkConfiguration,
POLICY_LEVEL_MANDATORY,
@@ -215,10 +232,11 @@ TEST_F(NetworkConfigurationUpdaterTest, PolicyIsValidatedAndRepaired) {
NULL);
UpdateProviderPolicy(policy);
- EXPECT_CALL(
- network_config_handler_,
- SetPolicy(
- onc::ONC_SOURCE_USER_POLICY, _, IsEqualTo(network_configs_repaired)));
+ EXPECT_CALL(network_config_handler_,
+ SetPolicy(onc::ONC_SOURCE_USER_POLICY,
+ _,
+ IsEqualTo(network_configs_repaired),
+ IsEqualTo(global_config_repaired)));
EXPECT_CALL(*certificate_importer_,
ImportCertificates(_, onc::ONC_SOURCE_USER_POLICY, _));
@@ -236,7 +254,7 @@ TEST_F(NetworkConfigurationUpdaterTest,
ASSERT_EQ(1u, cert_list.size());
EXPECT_CALL(network_config_handler_,
- SetPolicy(onc::ONC_SOURCE_USER_POLICY, _, _));
+ SetPolicy(onc::ONC_SOURCE_USER_POLICY, _, _, _));
EXPECT_CALL(*certificate_importer_, ImportCertificates(_, _, _))
.WillRepeatedly(SetCertificateList(cert_list));
@@ -265,7 +283,7 @@ TEST_F(NetworkConfigurationUpdaterTest, AllowTrustedCertificatesFromPolicy) {
ASSERT_EQ(1u, cert_list.size());
EXPECT_CALL(network_config_handler_,
- SetPolicy(onc::ONC_SOURCE_USER_POLICY, _, _));
+ SetPolicy(onc::ONC_SOURCE_USER_POLICY, _, _, _));
EXPECT_CALL(*certificate_importer_,
ImportCertificates(_, onc::ONC_SOURCE_USER_POLICY, _))
.WillRepeatedly(SetCertificateList(cert_list));
@@ -325,10 +343,11 @@ TEST_P(NetworkConfigurationUpdaterTestWithParam, InitialUpdates) {
EXPECT_CALL(network_config_handler_,
SetPolicy(CurrentONCSource(),
ExpectedUsernameHash(),
- IsEqualTo(fake_network_configs_.get())));
+ IsEqualTo(&fake_network_configs_),
+ IsEqualTo(&fake_global_network_config_)));
EXPECT_CALL(*certificate_importer_,
ImportCertificates(
- IsEqualTo(fake_certificates_.get()), CurrentONCSource(), _));
+ IsEqualTo(&fake_certificates_), CurrentONCSource(), _));
CreateNetworkConfigurationUpdater();
}
@@ -336,7 +355,7 @@ TEST_P(NetworkConfigurationUpdaterTestWithParam, InitialUpdates) {
TEST_P(NetworkConfigurationUpdaterTestWithParam, PolicyChange) {
// Ignore the initial updates.
- EXPECT_CALL(network_config_handler_, SetPolicy(_, _, _)).Times(AtLeast(1));
+ EXPECT_CALL(network_config_handler_, SetPolicy(_, _, _, _)).Times(AtLeast(1));
EXPECT_CALL(*certificate_importer_, ImportCertificates(_, _, _))
.Times(AtLeast(1));
CreateNetworkConfigurationUpdater();
@@ -344,12 +363,14 @@ TEST_P(NetworkConfigurationUpdaterTestWithParam, PolicyChange) {
Mock::VerifyAndClearExpectations(certificate_importer_);
// The Updater should update if policy changes.
- EXPECT_CALL(
- network_config_handler_,
- SetPolicy(CurrentONCSource(), _, IsEqualTo(fake_network_configs_.get())));
+ EXPECT_CALL(network_config_handler_,
+ SetPolicy(CurrentONCSource(),
+ _,
+ IsEqualTo(&fake_network_configs_),
+ IsEqualTo(&fake_global_network_config_)));
EXPECT_CALL(*certificate_importer_,
ImportCertificates(
- IsEqualTo(fake_certificates_.get()), CurrentONCSource(), _));
+ IsEqualTo(&fake_certificates_), CurrentONCSource(), _));
PolicyMap policy;
policy.Set(GetParam(), POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
@@ -359,13 +380,10 @@ TEST_P(NetworkConfigurationUpdaterTestWithParam, PolicyChange) {
Mock::VerifyAndClearExpectations(certificate_importer_);
// Another update is expected if the policy goes away.
- EXPECT_CALL(
- network_config_handler_,
- SetPolicy(
- CurrentONCSource(), _, IsEqualTo(empty_network_configs_.get())));
+ EXPECT_CALL(network_config_handler_,
+ SetPolicy(CurrentONCSource(), _, IsEmpty(), IsEmpty()));
EXPECT_CALL(*certificate_importer_,
- ImportCertificates(
- IsEqualTo(empty_certificates_.get()), CurrentONCSource(), _));
+ ImportCertificates(IsEmpty(), CurrentONCSource(), _));
policy.Erase(GetParam());
UpdateProviderPolicy(policy);
diff --git a/chrome/browser/chromeos/policy/power_policy_browsertest.cc b/chrome/browser/chromeos/policy/power_policy_browsertest.cc
index b00064f82b..28365d35a7 100644
--- a/chrome/browser/chromeos/policy/power_policy_browsertest.cc
+++ b/chrome/browser/chromeos/policy/power_policy_browsertest.cc
@@ -44,9 +44,9 @@
#include "chromeos/chromeos_paths.h"
#include "chromeos/chromeos_switches.h"
#include "chromeos/dbus/cryptohome_client.h"
+#include "chromeos/dbus/fake_dbus_thread_manager.h"
#include "chromeos/dbus/fake_power_manager_client.h"
#include "chromeos/dbus/fake_session_manager_client.h"
-#include "chromeos/dbus/mock_dbus_thread_manager_without_gmock.h"
#include "chromeos/dbus/power_manager/policy.pb.h"
#include "chromeos/dbus/power_policy_controller.h"
#include "content/public/browser/notification_details.h"
@@ -158,7 +158,7 @@ void PowerPolicyBrowserTestBase::SetUpInProcessBrowserTestFixture() {
MarkAsEnterpriseOwned();
power_manager_client_ =
- mock_dbus_thread_manager()->fake_power_manager_client();
+ fake_dbus_thread_manager()->fake_power_manager_client();
}
void PowerPolicyBrowserTestBase::SetUpOnMainThread() {
diff --git a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.cc b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.cc
index c11889b906..9c2f8090ad 100644
--- a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.cc
+++ b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.cc
@@ -20,7 +20,7 @@
#include "chrome/browser/policy/cloud/resource_cache.h"
#include "chrome/browser/policy/policy_bundle.h"
#include "chrome/browser/policy/policy_domain_descriptor.h"
-#include "chrome/common/pref_names.h"
+#include "components/policy/core/common/policy_pref_names.h"
#include "content/public/browser/browser_thread.h"
#include "net/url_request/url_request_context_getter.h"
@@ -351,7 +351,8 @@ void UserCloudPolicyManagerChromeOS::StartRefreshSchedulerIfReady() {
}
core()->StartRefreshScheduler();
- core()->TrackRefreshDelayPref(local_state_, prefs::kUserPolicyRefreshRate);
+ core()->TrackRefreshDelayPref(local_state_,
+ policy_prefs::kUserPolicyRefreshRate);
}
} // namespace policy
diff --git a/chrome/browser/chromeos/policy/user_cloud_policy_manager_factory_chromeos.cc b/chrome/browser/chromeos/policy/user_cloud_policy_manager_factory_chromeos.cc
index 4cb9987be3..a8fdf59e03 100644
--- a/chrome/browser/chromeos/policy/user_cloud_policy_manager_factory_chromeos.cc
+++ b/chrome/browser/chromeos/policy/user_cloud_policy_manager_factory_chromeos.cc
@@ -78,8 +78,10 @@ UserCloudPolicyManagerChromeOS*
scoped_ptr<UserCloudPolicyManagerChromeOS>
UserCloudPolicyManagerFactoryChromeOS::CreateForProfile(
Profile* profile,
- bool force_immediate_load) {
- return GetInstance()->CreateManagerForProfile(profile, force_immediate_load);
+ bool force_immediate_load,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner) {
+ return GetInstance()->CreateManagerForProfile(
+ profile, force_immediate_load, background_task_runner);
}
UserCloudPolicyManagerFactoryChromeOS::UserCloudPolicyManagerFactoryChromeOS()
@@ -102,7 +104,8 @@ UserCloudPolicyManagerChromeOS*
scoped_ptr<UserCloudPolicyManagerChromeOS>
UserCloudPolicyManagerFactoryChromeOS::CreateManagerForProfile(
Profile* profile,
- bool force_immediate_load) {
+ bool force_immediate_load,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner) {
const CommandLine* command_line = CommandLine::ForCurrentProcess();
// Don't initialize cloud policy for the signin profile.
if (chromeos::ProfileHelper::IsSigninProfile(profile))
@@ -156,6 +159,7 @@ scoped_ptr<UserCloudPolicyManagerChromeOS>
new UserCloudPolicyStoreChromeOS(
chromeos::DBusThreadManager::Get()->GetCryptohomeClient(),
chromeos::DBusThreadManager::Get()->GetSessionManagerClient(),
+ background_task_runner,
username, policy_key_dir, token_cache_file, policy_cache_file));
scoped_refptr<base::SequencedTaskRunner> backend_task_runner =
diff --git a/chrome/browser/chromeos/policy/user_cloud_policy_manager_factory_chromeos.h b/chrome/browser/chromeos/policy/user_cloud_policy_manager_factory_chromeos.h
index 471bd61bc8..d746067891 100644
--- a/chrome/browser/chromeos/policy/user_cloud_policy_manager_factory_chromeos.h
+++ b/chrome/browser/chromeos/policy/user_cloud_policy_manager_factory_chromeos.h
@@ -8,11 +8,16 @@
#include <map>
#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
#include "base/memory/singleton.h"
#include "components/browser_context_keyed_service/browser_context_keyed_base_factory.h"
class Profile;
+namespace base {
+class SequencedTaskRunner;
+}
+
namespace content {
class BrowserContext;
}
@@ -53,7 +58,8 @@ class UserCloudPolicyManagerFactoryChromeOS
// UserCloudPolicyStore at startup.
static scoped_ptr<UserCloudPolicyManagerChromeOS> CreateForProfile(
Profile* profile,
- bool force_immediate_load);
+ bool force_immediate_load,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner);
private:
friend struct DefaultSingletonTraits<UserCloudPolicyManagerFactoryChromeOS>;
@@ -65,7 +71,8 @@ class UserCloudPolicyManagerFactoryChromeOS
UserCloudPolicyManagerChromeOS* GetManagerForProfile(Profile* profile);
scoped_ptr<UserCloudPolicyManagerChromeOS> CreateManagerForProfile(
Profile* profile,
- bool force_immediate_load);
+ bool force_immediate_load,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner);
// BrowserContextKeyedBaseFactory:
virtual void BrowserContextShutdown(
diff --git a/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.cc b/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.cc
index cce3d66103..323baecca4 100644
--- a/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.cc
+++ b/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.cc
@@ -8,9 +8,10 @@
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/file_util.h"
+#include "base/location.h"
#include "base/logging.h"
-#include "base/memory/ref_counted.h"
#include "base/metrics/histogram.h"
+#include "base/sequenced_task_runner.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "chrome/browser/chromeos/policy/user_policy_disk_cache.h"
@@ -18,7 +19,6 @@
#include "chrome/browser/policy/proto/cloud/device_management_local.pb.h"
#include "chromeos/dbus/cryptohome_client.h"
#include "chromeos/dbus/session_manager_client.h"
-#include "content/public/browser/browser_thread.h"
#include "google_apis/gaia/gaia_auth_util.h"
#include "policy/proto/cloud_policy.pb.h"
@@ -59,8 +59,10 @@ class LegacyPolicyCacheLoader : public UserPolicyTokenLoader::Delegate,
CloudPolicyStore::Status,
scoped_ptr<em::PolicyFetchResponse>)> Callback;
- LegacyPolicyCacheLoader(const base::FilePath& token_cache_file,
- const base::FilePath& policy_cache_file);
+ LegacyPolicyCacheLoader(
+ const base::FilePath& token_cache_file,
+ const base::FilePath& policy_cache_file,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner);
virtual ~LegacyPolicyCacheLoader();
// Starts loading, and reports the result to |callback| when done.
@@ -102,14 +104,17 @@ class LegacyPolicyCacheLoader : public UserPolicyTokenLoader::Delegate,
LegacyPolicyCacheLoader::LegacyPolicyCacheLoader(
const base::FilePath& token_cache_file,
- const base::FilePath& policy_cache_file)
+ const base::FilePath& policy_cache_file,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner)
: weak_factory_(this),
has_policy_(false),
status_(CloudPolicyStore::STATUS_OK) {
token_loader_ = new UserPolicyTokenLoader(weak_factory_.GetWeakPtr(),
- token_cache_file);
+ token_cache_file,
+ background_task_runner);
policy_cache_ = new UserPolicyDiskCache(weak_factory_.GetWeakPtr(),
- policy_cache_file);
+ policy_cache_file,
+ background_task_runner);
}
LegacyPolicyCacheLoader::~LegacyPolicyCacheLoader() {}
@@ -165,18 +170,21 @@ CloudPolicyStore::Status LegacyPolicyCacheLoader::TranslateLoadResult(
UserCloudPolicyStoreChromeOS::UserCloudPolicyStoreChromeOS(
chromeos::CryptohomeClient* cryptohome_client,
chromeos::SessionManagerClient* session_manager_client,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner,
const std::string& username,
const base::FilePath& user_policy_key_dir,
const base::FilePath& legacy_token_cache_file,
const base::FilePath& legacy_policy_cache_file)
- : cryptohome_client_(cryptohome_client),
+ : UserCloudPolicyStoreBase(background_task_runner),
+ cryptohome_client_(cryptohome_client),
session_manager_client_(session_manager_client),
username_(username),
user_policy_key_dir_(user_policy_key_dir),
weak_factory_(this),
legacy_cache_dir_(legacy_token_cache_file.DirName()),
legacy_loader_(new LegacyPolicyCacheLoader(legacy_token_cache_file,
- legacy_policy_cache_file)),
+ legacy_policy_cache_file,
+ background_task_runner)),
legacy_caches_loaded_(false),
policy_key_loaded_(false) {}
@@ -388,7 +396,7 @@ void UserCloudPolicyStoreChromeOS::OnRetrievedPolicyValidated(
// Policy has been loaded successfully. This indicates that new-style policy
// is working, so the legacy cache directory can be removed.
if (!legacy_cache_dir_.empty()) {
- content::BrowserThread::PostBlockingPoolTask(
+ background_task_runner()->PostTask(
FROM_HERE,
base::Bind(&UserCloudPolicyStoreChromeOS::RemoveLegacyCacheDir,
legacy_cache_dir_));
@@ -468,7 +476,7 @@ void UserCloudPolicyStoreChromeOS::RemoveLegacyCacheDir(
void UserCloudPolicyStoreChromeOS::ReloadPolicyKey(
const base::Closure& callback) {
std::vector<uint8>* key = new std::vector<uint8>();
- content::BrowserThread::PostBlockingPoolTaskAndReply(
+ background_task_runner()->PostTaskAndReply(
FROM_HERE,
base::Bind(&UserCloudPolicyStoreChromeOS::LoadPolicyKey,
policy_key_path_,
diff --git a/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.h b/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.h
index 913235d456..e1939f8799 100644
--- a/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.h
+++ b/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.h
@@ -11,12 +11,17 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/policy/cloud/cloud_policy_validator.h"
#include "chrome/browser/policy/cloud/user_cloud_policy_store_base.h"
#include "chromeos/dbus/dbus_method_call_status.h"
+namespace base {
+class SequencedTaskRunner;
+}
+
namespace chromeos {
class CryptohomeClient;
class SessionManagerClient;
@@ -38,6 +43,7 @@ class UserCloudPolicyStoreChromeOS : public UserCloudPolicyStoreBase {
UserCloudPolicyStoreChromeOS(
chromeos::CryptohomeClient* cryptohome_client,
chromeos::SessionManagerClient* session_manager_client,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner,
const std::string& username,
const base::FilePath& user_policy_key_dir,
const base::FilePath& legacy_token_cache_file,
diff --git a/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos_unittest.cc b/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos_unittest.cc
index 994d52ff16..0f5ab74564 100644
--- a/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos_unittest.cc
@@ -19,7 +19,6 @@
#include "chrome/browser/policy/proto/cloud/device_management_local.pb.h"
#include "chromeos/dbus/mock_cryptohome_client.h"
#include "chromeos/dbus/mock_session_manager_client.h"
-#include "content/public/test/test_browser_thread.h"
#include "policy/policy_constants.h"
#include "policy/proto/cloud_policy.pb.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -53,9 +52,7 @@ ACTION_P2(SendSanitizedUsername, call_status, sanitized_username) {
class UserCloudPolicyStoreChromeOSTest : public testing::Test {
protected:
UserCloudPolicyStoreChromeOSTest()
- : loop_(base::MessageLoop::TYPE_UI),
- ui_thread_(content::BrowserThread::UI, &loop_),
- file_thread_(content::BrowserThread::FILE, &loop_) {}
+ : loop_(base::MessageLoop::TYPE_UI) {}
virtual void SetUp() OVERRIDE {
EXPECT_CALL(cryptohome_client_,
@@ -68,6 +65,7 @@ class UserCloudPolicyStoreChromeOSTest : public testing::Test {
ASSERT_TRUE(tmp_dir_.CreateUniqueTempDir());
store_.reset(new UserCloudPolicyStoreChromeOS(&cryptohome_client_,
&session_manager_client_,
+ loop_.message_loop_proxy(),
PolicyBuilder::kFakeUsername,
user_policy_dir(),
token_file(),
@@ -202,7 +200,6 @@ class UserCloudPolicyStoreChromeOSTest : public testing::Test {
void RunUntilIdle() {
loop_.RunUntilIdle();
- content::BrowserThread::GetBlockingPool()->FlushForTesting();
loop_.RunUntilIdle();
}
@@ -231,8 +228,6 @@ class UserCloudPolicyStoreChromeOSTest : public testing::Test {
scoped_ptr<UserCloudPolicyStoreChromeOS> store_;
private:
- content::TestBrowserThread ui_thread_;
- content::TestBrowserThread file_thread_;
base::ScopedTempDir tmp_dir_;
DISALLOW_COPY_AND_ASSIGN(UserCloudPolicyStoreChromeOSTest);
diff --git a/chrome/browser/chromeos/policy/user_network_configuration_updater.cc b/chrome/browser/chromeos/policy/user_network_configuration_updater.cc
index 990f5bd743..49c2552ded 100644
--- a/chrome/browser/chromeos/policy/user_network_configuration_updater.cc
+++ b/chrome/browser/chromeos/policy/user_network_configuration_updater.cc
@@ -76,12 +76,15 @@ void UserNetworkConfigurationUpdater::ImportCertificates(
}
void UserNetworkConfigurationUpdater::ApplyNetworkPolicy(
- base::ListValue* network_configs_onc) {
+ base::ListValue* network_configs_onc,
+ base::DictionaryValue* global_network_config) {
DCHECK(user_);
chromeos::onc::ExpandStringPlaceholdersInNetworksForUser(user_,
network_configs_onc);
- network_config_handler_->SetPolicy(
- onc_source_, user_->username_hash(), *network_configs_onc);
+ network_config_handler_->SetPolicy(onc_source_,
+ user_->username_hash(),
+ *network_configs_onc,
+ *global_network_config);
}
void UserNetworkConfigurationUpdater::SetTrustAnchors() {
diff --git a/chrome/browser/chromeos/policy/user_network_configuration_updater.h b/chrome/browser/chromeos/policy/user_network_configuration_updater.h
index 78d9ef11e6..aca6b89f29 100644
--- a/chrome/browser/chromeos/policy/user_network_configuration_updater.h
+++ b/chrome/browser/chromeos/policy/user_network_configuration_updater.h
@@ -73,7 +73,8 @@ class UserNetworkConfigurationUpdater : public NetworkConfigurationUpdater {
const base::ListValue& certificates_onc) OVERRIDE;
virtual void ApplyNetworkPolicy(
- base::ListValue* network_configs_onc) OVERRIDE;
+ base::ListValue* network_configs_onc,
+ base::DictionaryValue* global_network_config) OVERRIDE;
// Push |web_trust_certs_| to |cert_verifier_| if necessary.
void SetTrustAnchors();
diff --git a/chrome/browser/chromeos/policy/user_policy_disk_cache.cc b/chrome/browser/chromeos/policy/user_policy_disk_cache.cc
index e9249cd3f3..d22cddf3e2 100644
--- a/chrome/browser/chromeos/policy/user_policy_disk_cache.cc
+++ b/chrome/browser/chromeos/policy/user_policy_disk_cache.cc
@@ -7,63 +7,47 @@
#include "base/bind.h"
#include "base/file_util.h"
#include "base/logging.h"
+#include "base/message_loop/message_loop_proxy.h"
#include "base/metrics/histogram.h"
+#include "base/sequenced_task_runner.h"
#include "chrome/browser/policy/cloud/enterprise_metrics.h"
#include "chrome/browser/policy/proto/cloud/device_management_local.pb.h"
#include "content/public/browser/browser_thread.h"
-using content::BrowserThread;
-
namespace em = enterprise_management;
-namespace {
-
-// Other places can sample on the same UMA counter, so make sure they all do
-// it on the same thread (UI).
-void SampleUMAOnUIThread(policy::MetricPolicy sample) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- UMA_HISTOGRAM_ENUMERATION(policy::kMetricPolicy, sample,
- policy::kMetricPolicySize);
-}
-
-void SampleUMA(policy::MetricPolicy sample) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(&SampleUMAOnUIThread, sample));
-}
-
-} // namespace
-
namespace policy {
UserPolicyDiskCache::Delegate::~Delegate() {}
UserPolicyDiskCache::UserPolicyDiskCache(
const base::WeakPtr<Delegate>& delegate,
- const base::FilePath& backing_file_path)
+ const base::FilePath& backing_file_path,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner)
: delegate_(delegate),
- backing_file_path_(backing_file_path) {}
+ backing_file_path_(backing_file_path),
+ origin_task_runner_(base::MessageLoopProxy::current()),
+ background_task_runner_(background_task_runner) {}
void UserPolicyDiskCache::Load() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- bool ret = BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(&UserPolicyDiskCache::LoadOnFileThread, this));
+ DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
+ bool ret = background_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&UserPolicyDiskCache::LoadOnFileThread, this));
DCHECK(ret);
}
void UserPolicyDiskCache::Store(
const em::CachedCloudPolicyResponse& policy) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
+ DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
+ background_task_runner_->PostTask(
+ FROM_HERE,
base::Bind(&UserPolicyDiskCache::StoreOnFileThread, this, policy));
}
UserPolicyDiskCache::~UserPolicyDiskCache() {}
void UserPolicyDiskCache::LoadOnFileThread() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK(background_task_runner_->RunsTasksOnCurrentThread());
em::CachedCloudPolicyResponse cached_response;
if (!base::PathExists(backing_file_path_)) {
@@ -94,26 +78,31 @@ void UserPolicyDiskCache::LoadOnFileThread() {
void UserPolicyDiskCache::LoadDone(
LoadResult result,
const em::CachedCloudPolicyResponse& policy) {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&UserPolicyDiskCache::ReportResultOnUIThread, this,
- result, policy));
+ origin_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &UserPolicyDiskCache::ReportResultOnUIThread, this, result, policy));
}
void UserPolicyDiskCache::ReportResultOnUIThread(
LoadResult result,
const em::CachedCloudPolicyResponse& policy) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
switch (result) {
case LOAD_RESULT_NOT_FOUND:
break;
case LOAD_RESULT_READ_ERROR:
case LOAD_RESULT_PARSE_ERROR:
- SampleUMAOnUIThread(kMetricPolicyLoadFailed);
+ UMA_HISTOGRAM_ENUMERATION(policy::kMetricPolicy,
+ kMetricPolicyLoadFailed,
+ policy::kMetricPolicySize);
break;
case LOAD_RESULT_SUCCESS:
- SampleUMAOnUIThread(kMetricPolicyLoadSucceeded);
+ UMA_HISTOGRAM_ENUMERATION(policy::kMetricPolicy,
+ kMetricPolicyLoadSucceeded,
+ policy::kMetricPolicySize);
+ break;
}
if (delegate_.get())
@@ -122,28 +111,36 @@ void UserPolicyDiskCache::ReportResultOnUIThread(
void UserPolicyDiskCache::StoreOnFileThread(
const em::CachedCloudPolicyResponse& policy) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK(background_task_runner_->RunsTasksOnCurrentThread());
std::string data;
if (!policy.SerializeToString(&data)) {
LOG(WARNING) << "Failed to serialize policy data";
- SampleUMA(kMetricPolicyStoreFailed);
+ UMA_HISTOGRAM_ENUMERATION(policy::kMetricPolicy,
+ kMetricPolicyStoreFailed,
+ policy::kMetricPolicySize);
return;
}
if (!file_util::CreateDirectory(backing_file_path_.DirName())) {
LOG(WARNING) << "Failed to create directory "
<< backing_file_path_.DirName().value();
- SampleUMA(kMetricPolicyStoreFailed);
+ UMA_HISTOGRAM_ENUMERATION(policy::kMetricPolicy,
+ kMetricPolicyStoreFailed,
+ policy::kMetricPolicySize);
return;
}
int size = data.size();
if (file_util::WriteFile(backing_file_path_, data.c_str(), size) != size) {
LOG(WARNING) << "Failed to write " << backing_file_path_.value();
- SampleUMA(kMetricPolicyStoreFailed);
+ UMA_HISTOGRAM_ENUMERATION(policy::kMetricPolicy,
+ kMetricPolicyStoreFailed,
+ policy::kMetricPolicySize);
return;
}
- SampleUMA(kMetricPolicyStoreSucceeded);
+ UMA_HISTOGRAM_ENUMERATION(policy::kMetricPolicy,
+ kMetricPolicyStoreSucceeded,
+ policy::kMetricPolicySize);
}
} // namespace policy
diff --git a/chrome/browser/chromeos/policy/user_policy_disk_cache.h b/chrome/browser/chromeos/policy/user_policy_disk_cache.h
index 2c41688664..b22ad90a46 100644
--- a/chrome/browser/chromeos/policy/user_policy_disk_cache.h
+++ b/chrome/browser/chromeos/policy/user_policy_disk_cache.h
@@ -10,6 +10,10 @@
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
+namespace base {
+class SequencedTaskRunner;
+}
+
namespace enterprise_management {
class CachedCloudPolicyResponse;
}
@@ -43,8 +47,10 @@ class UserPolicyDiskCache
const enterprise_management::CachedCloudPolicyResponse& policy) = 0;
};
- UserPolicyDiskCache(const base::WeakPtr<Delegate>& delegate,
- const base::FilePath& backing_file_path);
+ UserPolicyDiskCache(
+ const base::WeakPtr<Delegate>& delegate,
+ const base::FilePath& backing_file_path,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner);
// Starts reading the policy cache from disk. Passes the read policy
// information back to the hosting UserPolicyCache after a successful cache
@@ -76,6 +82,8 @@ class UserPolicyDiskCache
base::WeakPtr<Delegate> delegate_;
const base::FilePath backing_file_path_;
+ scoped_refptr<base::SequencedTaskRunner> origin_task_runner_;
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
DISALLOW_COPY_AND_ASSIGN(UserPolicyDiskCache);
};
diff --git a/chrome/browser/chromeos/policy/user_policy_token_loader.cc b/chrome/browser/chromeos/policy/user_policy_token_loader.cc
index 1501e6cb77..0df0966803 100644
--- a/chrome/browser/chromeos/policy/user_policy_token_loader.cc
+++ b/chrome/browser/chromeos/policy/user_policy_token_loader.cc
@@ -6,30 +6,12 @@
#include "base/bind.h"
#include "base/file_util.h"
+#include "base/location.h"
+#include "base/message_loop/message_loop_proxy.h"
#include "base/metrics/histogram.h"
+#include "base/sequenced_task_runner.h"
#include "chrome/browser/policy/cloud/enterprise_metrics.h"
#include "chrome/browser/policy/proto/cloud/device_management_local.pb.h"
-#include "content/public/browser/browser_thread.h"
-
-using content::BrowserThread;
-
-namespace {
-
-// Other places can sample on the same UMA counter, so make sure they all do
-// it on the same thread (UI).
-void SampleUMAOnUIThread(policy::MetricToken sample) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- UMA_HISTOGRAM_ENUMERATION(policy::kMetricToken, sample,
- policy::kMetricTokenSize);
-}
-
-void SampleUMA(policy::MetricToken sample) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(&SampleUMAOnUIThread, sample));
-}
-
-} // namespace
namespace policy {
@@ -39,22 +21,25 @@ UserPolicyTokenLoader::Delegate::~Delegate() {}
UserPolicyTokenLoader::UserPolicyTokenLoader(
const base::WeakPtr<Delegate>& delegate,
- const base::FilePath& cache_file)
+ const base::FilePath& cache_file,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner)
: delegate_(delegate),
- cache_file_(cache_file) {}
+ cache_file_(cache_file),
+ origin_task_runner_(base::MessageLoopProxy::current()),
+ background_task_runner_(background_task_runner) {}
void UserPolicyTokenLoader::Load() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(&UserPolicyTokenLoader::LoadOnFileThread, this));
+ DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
+ background_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&UserPolicyTokenLoader::LoadOnBackgroundThread, this));
}
UserPolicyTokenLoader::~UserPolicyTokenLoader() {
}
-void UserPolicyTokenLoader::LoadOnFileThread() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+void UserPolicyTokenLoader::LoadOnBackgroundThread() {
+ DCHECK(background_task_runner_->RunsTasksOnCurrentThread());
std::string device_token;
std::string device_id;
@@ -65,23 +50,27 @@ void UserPolicyTokenLoader::LoadOnFileThread() {
device_credentials.ParseFromArray(data.c_str(), data.size())) {
device_token = device_credentials.device_token();
device_id = device_credentials.device_id();
- SampleUMA(kMetricTokenLoadSucceeded);
+ UMA_HISTOGRAM_ENUMERATION(policy::kMetricToken,
+ kMetricTokenLoadSucceeded,
+ policy::kMetricTokenSize);
} else {
- SampleUMA(kMetricTokenLoadFailed);
+ UMA_HISTOGRAM_ENUMERATION(policy::kMetricToken,
+ kMetricTokenLoadFailed,
+ policy::kMetricTokenSize);
}
}
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&UserPolicyTokenLoader::NotifyOnUIThread,
+ origin_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&UserPolicyTokenLoader::NotifyOnOriginThread,
this,
device_token,
device_id));
}
-void UserPolicyTokenLoader::NotifyOnUIThread(const std::string& token,
- const std::string& device_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+void UserPolicyTokenLoader::NotifyOnOriginThread(const std::string& token,
+ const std::string& device_id) {
+ DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
if (delegate_.get())
delegate_->OnTokenLoaded(token, device_id);
}
diff --git a/chrome/browser/chromeos/policy/user_policy_token_loader.h b/chrome/browser/chromeos/policy/user_policy_token_loader.h
index f213b00660..919e4aef43 100644
--- a/chrome/browser/chromeos/policy/user_policy_token_loader.h
+++ b/chrome/browser/chromeos/policy/user_policy_token_loader.h
@@ -12,6 +12,10 @@
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
+namespace base {
+class SequencedTaskRunner;
+}
+
namespace policy {
// Handles disk access and threading details for loading and storing tokens.
@@ -29,8 +33,10 @@ class UserPolicyTokenLoader
const std::string& device_id) = 0;
};
- UserPolicyTokenLoader(const base::WeakPtr<Delegate>& delegate,
- const base::FilePath& cache_file);
+ UserPolicyTokenLoader(
+ const base::WeakPtr<Delegate>& delegate,
+ const base::FilePath& cache_file,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner);
// Starts loading the disk cache. After the load is finished, the result is
// reported through the delegate.
@@ -40,12 +46,14 @@ class UserPolicyTokenLoader
friend class base::RefCountedThreadSafe<UserPolicyTokenLoader>;
~UserPolicyTokenLoader();
- void LoadOnFileThread();
- void NotifyOnUIThread(const std::string& token,
+ void LoadOnBackgroundThread();
+ void NotifyOnOriginThread(const std::string& token,
const std::string& device_id);
const base::WeakPtr<Delegate> delegate_;
const base::FilePath cache_file_;
+ scoped_refptr<base::SequencedTaskRunner> origin_task_runner_;
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
DISALLOW_COPY_AND_ASSIGN(UserPolicyTokenLoader);
};
diff --git a/chrome/browser/chromeos/power/peripheral_battery_observer_browsertest.cc b/chrome/browser/chromeos/power/peripheral_battery_observer_browsertest.cc
index 4e8a0a2e44..d29045a313 100644
--- a/chrome/browser/chromeos/power/peripheral_battery_observer_browsertest.cc
+++ b/chrome/browser/chromeos/power/peripheral_battery_observer_browsertest.cc
@@ -9,7 +9,7 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/notifications/notification_ui_manager.h"
#include "chrome/test/base/in_process_browser_test.h"
-#include "chromeos/dbus/mock_dbus_thread_manager_without_gmock.h"
+#include "chromeos/dbus/fake_dbus_thread_manager.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/test/test_browser_thread.h"
#include "content/public/test/test_utils.h"
@@ -37,9 +37,9 @@ class PeripheralBatteryObserverTest : public InProcessBrowserTest {
virtual ~PeripheralBatteryObserverTest () {}
virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
- MockDBusThreadManagerWithoutGMock* mock_dbus_thread_manager =
- new MockDBusThreadManagerWithoutGMock;
- DBusThreadManager::InitializeForTesting(mock_dbus_thread_manager);
+ FakeDBusThreadManager* fake_dbus_thread_manager =
+ new FakeDBusThreadManager;
+ DBusThreadManager::InitializeForTesting(fake_dbus_thread_manager);
InProcessBrowserTest::SetUpInProcessBrowserTestFixture();
}
diff --git a/chrome/browser/chromeos/power/power_prefs_unittest.cc b/chrome/browser/chromeos/power/power_prefs_unittest.cc
index 7a28e040f3..3c040e5183 100644
--- a/chrome/browser/chromeos/power/power_prefs_unittest.cc
+++ b/chrome/browser/chromeos/power/power_prefs_unittest.cc
@@ -23,8 +23,8 @@
#include "chrome/test/base/testing_profile.h"
#include "chrome/test/base/testing_profile_manager.h"
#include "chromeos/chromeos_switches.h"
+#include "chromeos/dbus/fake_dbus_thread_manager.h"
#include "chromeos/dbus/fake_power_manager_client.h"
-#include "chromeos/dbus/mock_dbus_thread_manager_without_gmock.h"
#include "chromeos/dbus/power_manager/policy.pb.h"
#include "chromeos/dbus/power_policy_controller.h"
#include "components/user_prefs/pref_registry_syncable.h"
@@ -51,7 +51,7 @@ class PowerPrefsTest : public testing::Test {
bool GetCurrentAllowScreenWakeLocks() const;
TestingProfileManager profile_manager_;
- MockDBusThreadManagerWithoutGMock mock_dbus_thread_manager_;
+ FakeDBusThreadManager fake_dbus_thread_manager_;
PowerPolicyController* power_policy_controller_; // Not owned.
FakePowerManagerClient* fake_power_manager_client_; // Not owned.
@@ -63,9 +63,9 @@ class PowerPrefsTest : public testing::Test {
PowerPrefsTest::PowerPrefsTest()
: profile_manager_(TestingBrowserProcess::GetGlobal()),
power_policy_controller_(
- mock_dbus_thread_manager_.GetPowerPolicyController()),
+ fake_dbus_thread_manager_.GetPowerPolicyController()),
fake_power_manager_client_(
- mock_dbus_thread_manager_.fake_power_manager_client()) {
+ fake_dbus_thread_manager_.fake_power_manager_client()) {
}
void PowerPrefsTest::SetUp() {
diff --git a/chrome/browser/chromeos/preferences.cc b/chrome/browser/chromeos/preferences.cc
index 5271c72bd3..b3e6262a66 100644
--- a/chrome/browser/chromeos/preferences.cc
+++ b/chrome/browser/chromeos/preferences.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/chromeos/preferences.h"
+#include "ash/autoclick/autoclick_controller.h"
#include "ash/magnifier/magnifier_constants.h"
#include "ash/shell.h"
#include "base/command_line.h"
@@ -162,6 +163,10 @@ void Preferences::RegisterProfilePrefs(
prefs::kAutoclickEnabled,
false,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+ registry->RegisterIntegerPref(
+ prefs::kAutoclickDelayMs,
+ ash::AutoclickController::kDefaultAutoclickDelayMs,
+ user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
registry->RegisterBooleanPref(
prefs::kShouldAlwaysShowAccessibilityMenu,
false,
diff --git a/chrome/browser/chromeos/settings/device_oauth2_token_service.cc b/chrome/browser/chromeos/settings/device_oauth2_token_service.cc
index 6d5d917576..64f2c84000 100644
--- a/chrome/browser/chromeos/settings/device_oauth2_token_service.cc
+++ b/chrome/browser/chromeos/settings/device_oauth2_token_service.cc
@@ -16,7 +16,7 @@
#include "chrome/browser/policy/browser_policy_connector.h"
#include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
#include "chrome/common/pref_names.h"
-#include "chromeos/cryptohome/cryptohome_library.h"
+#include "chromeos/cryptohome/system_salt_getter.h"
#include "content/public/browser/browser_thread.h"
#include "google_apis/gaia/gaia_urls.h"
#include "google_apis/gaia/google_service_auth_error.h"
@@ -238,7 +238,7 @@ void DeviceOAuth2TokenService::SetAndSaveRefreshToken(
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
// TODO(xiyuan): Use async GetSystemSalt after merging to M31.
- const std::string system_salt = CryptohomeLibrary::Get()->GetSystemSaltSync();
+ const std::string system_salt = SystemSaltGetter::Get()->GetSystemSaltSync();
if (system_salt.empty()) {
const int64 kRequestSystemSaltDelayMs = 500;
content::BrowserThread::PostDelayedTask(
@@ -266,7 +266,7 @@ std::string DeviceOAuth2TokenService::GetRefreshToken(
local_state_->GetString(prefs::kDeviceRobotAnyApiRefreshToken);
// TODO(xiyuan): This needs a proper fix after M31.
- LOG_IF(ERROR, CryptohomeLibrary::Get()->GetSystemSaltSync().empty())
+ LOG_IF(ERROR, SystemSaltGetter::Get()->GetSystemSaltSync().empty())
<< "System salt is not available for decryption";
refresh_token_ = token_encryptor_->DecryptWithSystemSalt(
diff --git a/chrome/browser/chromeos/settings/device_oauth2_token_service_unittest.cc b/chrome/browser/chromeos/settings/device_oauth2_token_service_unittest.cc
index 988f6061c2..dd4b246f7a 100644
--- a/chrome/browser/chromeos/settings/device_oauth2_token_service_unittest.cc
+++ b/chrome/browser/chromeos/settings/device_oauth2_token_service_unittest.cc
@@ -11,8 +11,8 @@
#include "chrome/common/pref_names.h"
#include "chrome/test/base/scoped_testing_local_state.h"
#include "chrome/test/base/testing_browser_process.h"
-#include "chromeos/cryptohome/cryptohome_library.h"
-#include "chromeos/dbus/mock_dbus_thread_manager_without_gmock.h"
+#include "chromeos/cryptohome/system_salt_getter.h"
+#include "chromeos/dbus/fake_dbus_thread_manager.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/test/test_browser_thread.h"
#include "google_apis/gaia/gaia_oauth_client.h"
@@ -101,14 +101,14 @@ class DeviceOAuth2TokenServiceTest : public testing::Test {
virtual void SetUp() OVERRIDE {
// TODO(xiyuan): Remove this when cleaning up the system salt load temp fix.
- scoped_ptr<MockDBusThreadManagerWithoutGMock> mock_dbus_thread_manager(
- new MockDBusThreadManagerWithoutGMock);
- DBusThreadManager::InitializeForTesting(mock_dbus_thread_manager.release());
- CryptohomeLibrary::Initialize();
+ scoped_ptr<FakeDBusThreadManager> fake_dbus_thread_manager(
+ new FakeDBusThreadManager);
+ DBusThreadManager::InitializeForTesting(fake_dbus_thread_manager.release());
+ SystemSaltGetter::Initialize();
}
virtual void TearDown() OVERRIDE {
- CryptohomeLibrary::Shutdown();
+ SystemSaltGetter::Shutdown();
DBusThreadManager::Shutdown();
base::RunLoop().RunUntilIdle();
}
diff --git a/chrome/browser/chromeos/settings/device_settings_provider.cc b/chrome/browser/chromeos/settings/device_settings_provider.cc
index a3366ae52a..7c1d3b894e 100644
--- a/chrome/browser/chromeos/settings/device_settings_provider.cc
+++ b/chrome/browser/chromeos/settings/device_settings_provider.cc
@@ -82,9 +82,6 @@ const char* kKnownSettings[] = {
kVariationsRestrictParameter,
};
-// Legacy policy file location. Used to detect migration from pre v12 ChromeOS.
-const char kLegacyPolicyFile[] = "/var/lib/whitelist/preferences";
-
bool HasOldMetricsFile() {
// TODO(pastarmovj): Remove this once migration is not needed anymore.
// If the value is not set we should try to migrate legacy consent file.
diff --git a/chrome/browser/chromeos/settings/device_settings_test_helper.cc b/chrome/browser/chromeos/settings/device_settings_test_helper.cc
index 04a77ea81c..2050364b72 100644
--- a/chrome/browser/chromeos/settings/device_settings_test_helper.cc
+++ b/chrome/browser/chromeos/settings/device_settings_test_helper.cc
@@ -63,6 +63,7 @@ void DeviceSettingsTestHelper::FlushRetrieve() {
for (device_local_account_state = device_local_account_policy_.begin();
device_local_account_state != device_local_account_policy_.end();
++device_local_account_state) {
+ std::vector<RetrievePolicyCallback> callbacks;
callbacks.swap(device_local_account_state->second.retrieve_callbacks_);
for (std::vector<RetrievePolicyCallback>::iterator cb(callbacks.begin());
cb != callbacks.end(); ++cb) {
diff --git a/chrome/browser/chromeos/settings/session_manager_operation.cc b/chrome/browser/chromeos/settings/session_manager_operation.cc
index b31608d501..934c7a2837 100644
--- a/chrome/browser/chromeos/settings/session_manager_operation.cc
+++ b/chrome/browser/chromeos/settings/session_manager_operation.cc
@@ -143,8 +143,16 @@ void SessionManagerOperation::ValidateDeviceSettings(
return;
}
+ base::SequencedWorkerPool* pool =
+ content::BrowserThread::GetBlockingPool();
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner =
+ pool->GetSequencedTaskRunnerWithShutdownBehavior(
+ pool->GetSequenceToken(),
+ base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+
policy::DeviceCloudPolicyValidator* validator =
- policy::DeviceCloudPolicyValidator::Create(policy.Pass());
+ policy::DeviceCloudPolicyValidator::Create(policy.Pass(),
+ background_task_runner);
// Policy auto-generated by session manager doesn't include a timestamp, so we
// need to allow missing timestamps.
diff --git a/chrome/browser/chromeos/settings/session_manager_operation_unittest.cc b/chrome/browser/chromeos/settings/session_manager_operation_unittest.cc
index 98d2f4e6e2..1023aa03d7 100644
--- a/chrome/browser/chromeos/settings/session_manager_operation_unittest.cc
+++ b/chrome/browser/chromeos/settings/session_manager_operation_unittest.cc
@@ -252,7 +252,8 @@ TEST_F(SessionManagerOperationTest, SignAndStoreSettings) {
policy_response->ParseFromString(
device_settings_test_helper_.policy_blob()));
policy::DeviceCloudPolicyValidator* validator =
- policy::DeviceCloudPolicyValidator::Create(policy_response.Pass());
+ policy::DeviceCloudPolicyValidator::Create(
+ policy_response.Pass(), message_loop_.message_loop_proxy());
validator->ValidateUsername(policy_.policy_data().username());
validator->ValidateTimestamp(
before,
diff --git a/chrome/browser/chromeos/settings/token_encryptor.cc b/chrome/browser/chromeos/settings/token_encryptor.cc
index d966091600..269e8cb85a 100644
--- a/chrome/browser/chromeos/settings/token_encryptor.cc
+++ b/chrome/browser/chromeos/settings/token_encryptor.cc
@@ -10,7 +10,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/sys_info.h"
-#include "chromeos/cryptohome/cryptohome_library.h"
+#include "chromeos/cryptohome/system_salt_getter.h"
#include "crypto/encryptor.h"
#include "crypto/nss_util.h"
#include "crypto/sha2.h"
@@ -63,7 +63,7 @@ std::string CryptohomeTokenEncryptor::DecryptWithSystemSalt(
bool CryptohomeTokenEncryptor::LoadSystemSaltKey() {
// Assume the system salt should be obtained beforehand at login time.
if (system_salt_.empty())
- system_salt_ = CryptohomeLibrary::Get()->GetCachedSystemSalt();
+ system_salt_ = SystemSaltGetter::Get()->GetCachedSystemSalt();
if (system_salt_.empty())
return false;
if (!system_salt_key_.get())
diff --git a/chrome/browser/chromeos/status/data_promo_notification.cc b/chrome/browser/chromeos/status/data_promo_notification.cc
index ba79302f42..d9f8ef9785 100644
--- a/chrome/browser/chromeos/status/data_promo_notification.cc
+++ b/chrome/browser/chromeos/status/data_promo_notification.cc
@@ -40,10 +40,6 @@ namespace chromeos {
namespace {
-// Time in milliseconds to delay showing of promo
-// notification when Chrome window is not on screen.
-const int kPromoShowDelayMs = 10000;
-
const int kNotificationCountPrefDefault = -1;
bool GetBooleanPref(const char* pref_name) {
diff --git a/chrome/browser/chromeos/system/ash_system_tray_delegate.cc b/chrome/browser/chromeos/system/ash_system_tray_delegate.cc
index d2ea4b30fa..49b6f1f03c 100644
--- a/chrome/browser/chromeos/system/ash_system_tray_delegate.cc
+++ b/chrome/browser/chromeos/system/ash_system_tray_delegate.cc
@@ -57,6 +57,7 @@
#include "chrome/browser/chromeos/login/login_display_host_impl.h"
#include "chrome/browser/chromeos/login/login_wizard.h"
#include "chrome/browser/chromeos/login/startup_utils.h"
+#include "chrome/browser/chromeos/login/supervised_user_manager.h"
#include "chrome/browser/chromeos/login/user.h"
#include "chrome/browser/chromeos/login/user_adding_screen.h"
#include "chrome/browser/chromeos/login/user_manager.h"
@@ -426,15 +427,17 @@ class SystemTrayDelegate : public ash::SystemTrayDelegate,
virtual const std::string GetLocallyManagedUserManager() const OVERRIDE {
if (GetUserLoginStatus() != ash::user::LOGGED_IN_LOCALLY_MANAGED)
return std::string();
- return UserManager::Get()->GetManagerDisplayEmailForManagedUser(
- chromeos::UserManager::Get()->GetActiveUser()->email());
+ return UserManager::Get()->GetSupervisedUserManager()->
+ GetManagerDisplayEmail(
+ chromeos::UserManager::Get()->GetActiveUser()->email());
}
virtual const string16 GetLocallyManagedUserManagerName() const OVERRIDE {
if (GetUserLoginStatus() != ash::user::LOGGED_IN_LOCALLY_MANAGED)
return string16();
- return UserManager::Get()->GetManagerDisplayNameForManagedUser(
- chromeos::UserManager::Get()->GetActiveUser()->email());
+ return UserManager::Get()->GetSupervisedUserManager()->
+ GetManagerDisplayName(
+ chromeos::UserManager::Get()->GetActiveUser()->email());
}
virtual const string16 GetLocallyManagedUserMessage() const OVERRIDE {
@@ -744,9 +747,8 @@ class SystemTrayDelegate : public ash::SystemTrayDelegate,
virtual void ManageBluetoothDevices() OVERRIDE {
content::RecordAction(
content::UserMetricsAction("ShowBluetoothSettingsPage"));
- std::string sub_page = std::string(chrome::kSearchSubPage) + "#" +
- l10n_util::GetStringUTF8(IDS_OPTIONS_SETTINGS_SECTION_TITLE_BLUETOOTH);
- chrome::ShowSettingsSubPage(GetAppropriateBrowser(), sub_page);
+ chrome::ShowSettingsSubPage(GetAppropriateBrowser(),
+ chrome::kBluetoothAddDeviceSubPage);
}
virtual void ToggleBluetooth() OVERRIDE {
diff --git a/chrome/browser/chromeos/system/automatic_reboot_manager_unittest.cc b/chrome/browser/chromeos/system/automatic_reboot_manager_unittest.cc
index 7aac719cfa..4ea30aadba 100644
--- a/chrome/browser/chromeos/system/automatic_reboot_manager_unittest.cc
+++ b/chrome/browser/chromeos/system/automatic_reboot_manager_unittest.cc
@@ -33,9 +33,9 @@
#include "chrome/test/base/testing_browser_process.h"
#include "chromeos/chromeos_paths.h"
#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/fake_dbus_thread_manager.h"
#include "chromeos/dbus/fake_power_manager_client.h"
#include "chromeos/dbus/fake_update_engine_client.h"
-#include "chromeos/dbus/mock_dbus_thread_manager_without_gmock.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_service.h"
@@ -358,8 +358,7 @@ void AutomaticRebootManagerBasicTest::SetUp() {
TestingBrowserProcess::GetGlobal()->SetLocalState(&local_state_);
AutomaticRebootManager::RegisterPrefs(local_state_.registry());
- MockDBusThreadManagerWithoutGMock* dbus_manager =
- new MockDBusThreadManagerWithoutGMock;
+ FakeDBusThreadManager* dbus_manager = new FakeDBusThreadManager;
DBusThreadManager::InitializeForTesting(dbus_manager);
power_manager_client_ = dbus_manager->fake_power_manager_client();
update_engine_client_ = dbus_manager->fake_update_engine_client();
diff --git a/chrome/browser/component_updater/ppapi_utils.cc b/chrome/browser/component_updater/ppapi_utils.cc
index c59a3a13a1..34893378cb 100644
--- a/chrome/browser/component_updater/ppapi_utils.cc
+++ b/chrome/browser/component_updater/ppapi_utils.cc
@@ -30,6 +30,7 @@
#include "ppapi/c/dev/ppb_truetype_font_dev.h"
#include "ppapi/c/dev/ppb_url_util_dev.h"
#include "ppapi/c/dev/ppb_var_deprecated.h"
+#include "ppapi/c/dev/ppb_var_resource_dev.h"
#include "ppapi/c/dev/ppb_video_capture_dev.h"
#include "ppapi/c/dev/ppb_video_decoder_dev.h"
#include "ppapi/c/dev/ppb_view_dev.h"
diff --git a/chrome/browser/content_settings/tab_specific_content_settings.cc b/chrome/browser/content_settings/tab_specific_content_settings.cc
index 9c019ba621..ee562f3293 100644
--- a/chrome/browser/content_settings/tab_specific_content_settings.cc
+++ b/chrome/browser/content_settings/tab_specific_content_settings.cc
@@ -29,7 +29,6 @@
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/render_view_host_observer.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
#include "net/cookies/canonical_cookie.h"
@@ -43,22 +42,6 @@ using content::WebContents;
DEFINE_WEB_CONTENTS_USER_DATA_KEY(TabSpecificContentSettings);
-namespace {
-
-class InterstitialHostObserver : public content::RenderViewHostObserver {
- public:
- explicit InterstitialHostObserver(RenderViewHost* rvh)
- : content::RenderViewHostObserver(rvh) {}
-
- // content::RenderViewHostObserver overrides.
- virtual void RenderViewHostInitialized() OVERRIDE {
- Send(new ChromeViewMsg_SetAsInterstitial(routing_id()));
- delete this;
- }
-};
-
-} // namespace
-
TabSpecificContentSettings::SiteDataObserver::SiteDataObserver(
TabSpecificContentSettings* tab_specific_content_settings)
: tab_specific_content_settings_(tab_specific_content_settings) {
@@ -664,8 +647,8 @@ void TabSpecificContentSettings::SetPepperBrokerAllowed(bool allowed) {
void TabSpecificContentSettings::RenderViewForInterstitialPageCreated(
RenderViewHost* render_view_host) {
// We want to tell the renderer-side code to ignore content settings for this
- // page but we must wait until the RenderView is created.
- new InterstitialHostObserver(render_view_host);
+ // page.
+ Send(new ChromeViewMsg_SetAsInterstitial(routing_id()));
}
bool TabSpecificContentSettings::OnMessageReceived(
diff --git a/chrome/browser/crash_handler_host_linux.cc b/chrome/browser/crash_handler_host_linux.cc
deleted file mode 100644
index 41b0f55f54..0000000000
--- a/chrome/browser/crash_handler_host_linux.cc
+++ /dev/null
@@ -1,530 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/crash_handler_host_linux.h"
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <sys/socket.h>
-#include <sys/syscall.h>
-#include <unistd.h>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/files/file_path.h"
-#include "base/format_macros.h"
-#include "base/linux_util.h"
-#include "base/logging.h"
-#include "base/memory/singleton.h"
-#include "base/message_loop/message_loop.h"
-#include "base/path_service.h"
-#include "base/posix/eintr_wrapper.h"
-#include "base/rand_util.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/threading/thread.h"
-#include "breakpad/src/client/linux/handler/exception_handler.h"
-#include "breakpad/src/client/linux/minidump_writer/linux_dumper.h"
-#include "breakpad/src/client/linux/minidump_writer/minidump_writer.h"
-#include "chrome/app/breakpad_linux_impl.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/common/env_vars.h"
-#include "content/public/browser/browser_thread.h"
-
-#if defined(OS_ANDROID)
-#include <sys/linux-syscalls.h>
-
-#define SYS_read __NR_read
-#endif
-
-using content::BrowserThread;
-using google_breakpad::ExceptionHandler;
-
-namespace {
-
-// The length of the control message:
-const unsigned kControlMsgSize =
- CMSG_SPACE(2*sizeof(int)) + CMSG_SPACE(sizeof(struct ucred));
-// The length of the regular payload:
-const unsigned kCrashContextSize = sizeof(ExceptionHandler::CrashContext);
-
-// Handles the crash dump and frees the allocated BreakpadInfo struct.
-void CrashDumpTask(CrashHandlerHostLinux* handler, BreakpadInfo* info) {
- if (handler->IsShuttingDown())
- return;
-
- HandleCrashDump(*info);
- delete[] info->filename;
- delete[] info->process_type;
- delete[] info->distro;
- delete info->crash_keys;
- delete info;
-}
-
-} // namespace
-
-// Since classes derived from CrashHandlerHostLinux are singletons, it's only
-// destroyed at the end of the processes lifetime, which is greater in span than
-// the lifetime of the IO message loop. Thus, all calls to base::Bind() use
-// non-refcounted pointers.
-
-CrashHandlerHostLinux::CrashHandlerHostLinux()
- : shutting_down_(false),
- worker_pool_token_(BrowserThread::GetBlockingPool()->GetSequenceToken()) {
- int fds[2];
- // We use SOCK_SEQPACKET rather than SOCK_DGRAM to prevent the process from
- // sending datagrams to other sockets on the system. The sandbox may prevent
- // the process from calling socket() to create new sockets, but it'll still
- // inherit some sockets. With PF_UNIX+SOCK_DGRAM, it can call sendmsg to send
- // a datagram to any (abstract) socket on the same system. With
- // SOCK_SEQPACKET, this is prevented.
- CHECK_EQ(socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds), 0);
- static const int on = 1;
-
- // Enable passcred on the server end of the socket
- CHECK_EQ(setsockopt(fds[1], SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)), 0);
-
- process_socket_ = fds[0];
- browser_socket_ = fds[1];
-
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&CrashHandlerHostLinux::Init, base::Unretained(this)));
-}
-
-CrashHandlerHostLinux::~CrashHandlerHostLinux() {
- (void) HANDLE_EINTR(close(process_socket_));
- (void) HANDLE_EINTR(close(browser_socket_));
-}
-
-void CrashHandlerHostLinux::Init() {
- base::MessageLoopForIO* ml = base::MessageLoopForIO::current();
- CHECK(ml->WatchFileDescriptor(
- browser_socket_, true /* persistent */,
- base::MessageLoopForIO::WATCH_READ,
- &file_descriptor_watcher_, this));
- ml->AddDestructionObserver(this);
-}
-
-void CrashHandlerHostLinux::InitCrashUploaderThread() {
- SetProcessType();
- uploader_thread_.reset(
- new base::Thread(std::string(process_type_ + "_crash_uploader").c_str()));
- uploader_thread_->Start();
-}
-
-void CrashHandlerHostLinux::OnFileCanWriteWithoutBlocking(int fd) {
- NOTREACHED();
-}
-
-void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) {
- DCHECK_EQ(fd, browser_socket_);
-
- // A process has crashed and has signaled us by writing a datagram
- // to the death signal socket. The datagram contains the crash context needed
- // for writing the minidump as well as a file descriptor and a credentials
- // block so that they can't lie about their pid.
- //
- // The message sender is in chrome/app/breakpad_linux.cc.
-
- struct msghdr msg = {0};
- struct iovec iov[kCrashIovSize];
-
- // Freed in WriteDumpFile();
- char* crash_context = new char[kCrashContextSize];
- // Freed in CrashDumpTask();
- char* distro = new char[kDistroSize + 1];
-#if defined(ADDRESS_SANITIZER)
- asan_report_str_ = new char[kMaxAsanReportSize + 1];
-#endif
-
- // Freed in CrashDumpTask().
- CrashKeyStorage* crash_keys = new CrashKeyStorage;
- google_breakpad::SerializedNonAllocatingMap* serialized_crash_keys;
- size_t crash_keys_size = crash_keys->Serialize(
- const_cast<const google_breakpad::SerializedNonAllocatingMap**>(
- &serialized_crash_keys));
-
- char* tid_buf_addr = NULL;
- int tid_fd = -1;
- uint64_t uptime;
- size_t oom_size;
- char control[kControlMsgSize];
- const ssize_t expected_msg_size =
- kCrashContextSize +
- kDistroSize + 1 +
- sizeof(tid_buf_addr) + sizeof(tid_fd) +
- sizeof(uptime) +
-#if defined(ADDRESS_SANITIZER)
- kMaxAsanReportSize + 1 +
-#endif
- sizeof(oom_size) +
- crash_keys_size;
- iov[0].iov_base = crash_context;
- iov[0].iov_len = kCrashContextSize;
- iov[1].iov_base = distro;
- iov[1].iov_len = kDistroSize + 1;
- iov[2].iov_base = &tid_buf_addr;
- iov[2].iov_len = sizeof(tid_buf_addr);
- iov[3].iov_base = &tid_fd;
- iov[3].iov_len = sizeof(tid_fd);
- iov[4].iov_base = &uptime;
- iov[4].iov_len = sizeof(uptime);
- iov[5].iov_base = &oom_size;
- iov[5].iov_len = sizeof(oom_size);
- iov[6].iov_base = serialized_crash_keys;
- iov[6].iov_len = crash_keys_size;
-#if defined(ADDRESS_SANITIZER)
- iov[7].iov_base = asan_report_str_;
- iov[7].iov_len = kMaxAsanReportSize + 1;
-#endif
- msg.msg_iov = iov;
- msg.msg_iovlen = kCrashIovSize;
- msg.msg_control = control;
- msg.msg_controllen = kControlMsgSize;
-
- const ssize_t msg_size = HANDLE_EINTR(recvmsg(browser_socket_, &msg, 0));
- if (msg_size != expected_msg_size) {
- LOG(ERROR) << "Error reading from death signal socket. Crash dumping"
- << " is disabled."
- << " msg_size:" << msg_size
- << " errno:" << errno;
- file_descriptor_watcher_.StopWatchingFileDescriptor();
- return;
- }
-
- if (msg.msg_controllen != kControlMsgSize ||
- msg.msg_flags & ~MSG_TRUNC) {
- LOG(ERROR) << "Received death signal message with the wrong size;"
- << " msg.msg_controllen:" << msg.msg_controllen
- << " msg.msg_flags:" << msg.msg_flags
- << " kCrashContextSize:" << kCrashContextSize
- << " kControlMsgSize:" << kControlMsgSize;
- return;
- }
-
- // Walk the control payload an extract the file descriptor and validated pid.
- pid_t crashing_pid = -1;
- int partner_fd = -1;
- int signal_fd = -1;
- for (struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); hdr;
- hdr = CMSG_NXTHDR(&msg, hdr)) {
- if (hdr->cmsg_level != SOL_SOCKET)
- continue;
- if (hdr->cmsg_type == SCM_RIGHTS) {
- const unsigned len = hdr->cmsg_len -
- (((uint8_t*)CMSG_DATA(hdr)) - (uint8_t*)hdr);
- DCHECK_EQ(len % sizeof(int), 0u);
- const unsigned num_fds = len / sizeof(int);
- if (num_fds != 2) {
- // A nasty process could try and send us too many descriptors and
- // force a leak.
- LOG(ERROR) << "Death signal contained wrong number of descriptors;"
- << " num_fds:" << num_fds;
- for (unsigned i = 0; i < num_fds; ++i)
- (void) HANDLE_EINTR(close(reinterpret_cast<int*>(CMSG_DATA(hdr))[i]));
- return;
- } else {
- partner_fd = reinterpret_cast<int*>(CMSG_DATA(hdr))[0];
- signal_fd = reinterpret_cast<int*>(CMSG_DATA(hdr))[1];
- }
- } else if (hdr->cmsg_type == SCM_CREDENTIALS) {
- const struct ucred *cred =
- reinterpret_cast<struct ucred*>(CMSG_DATA(hdr));
- crashing_pid = cred->pid;
- }
- }
-
- if (crashing_pid == -1 || partner_fd == -1 || signal_fd == -1) {
- LOG(ERROR) << "Death signal message didn't contain all expected control"
- << " messages";
- if (partner_fd >= 0)
- (void) HANDLE_EINTR(close(partner_fd));
- if (signal_fd >= 0)
- (void) HANDLE_EINTR(close(signal_fd));
- return;
- }
-
- // Kernel bug workaround (broken in 2.6.30 and 2.6.32, working in 2.6.38).
- // The kernel doesn't translate PIDs in SCM_CREDENTIALS across PID
- // namespaces. Thus |crashing_pid| might be garbage from our point of view.
- // In the future we can remove this workaround, but we have to wait a couple
- // of years to be sure that it's worked its way out into the world.
- // TODO(thestig) Remove the workaround when Ubuntu Lucid is deprecated.
-
- // The crashing process closes its copy of the signal_fd immediately after
- // calling sendmsg(). We can thus not reliably look for with with
- // FindProcessHoldingSocket(). But by necessity, it has to keep the
- // partner_fd open until the crashdump is complete.
- ino_t inode_number;
- if (!base::FileDescriptorGetInode(&inode_number, partner_fd)) {
- LOG(WARNING) << "Failed to get inode number for passed socket";
- (void) HANDLE_EINTR(close(partner_fd));
- (void) HANDLE_EINTR(close(signal_fd));
- return;
- }
- (void) HANDLE_EINTR(close(partner_fd));
-
- pid_t actual_crashing_pid = -1;
- if (!base::FindProcessHoldingSocket(&actual_crashing_pid, inode_number)) {
- LOG(WARNING) << "Failed to find process holding other end of crash reply "
- "socket";
- (void) HANDLE_EINTR(close(signal_fd));
- return;
- }
-
- crashing_pid = actual_crashing_pid;
-
- // The crashing TID set inside the compromised context via
- // sys_gettid() in ExceptionHandler::HandleSignal might be wrong (if
- // the kernel supports PID namespacing) and may need to be
- // translated.
- //
- // We expect the crashing thread to be in sys_read(), waiting for us to
- // write to |signal_fd|. Most newer kernels where we have the different pid
- // namespaces also have /proc/[pid]/syscall, so we can look through
- // |actual_crashing_pid|'s thread group and find the thread that's in the
- // read syscall with the right arguments.
-
- std::string expected_syscall_data;
- // /proc/[pid]/syscall is formatted as follows:
- // syscall_number arg1 ... arg6 sp pc
- // but we just check syscall_number through arg3.
- base::StringAppendF(&expected_syscall_data, "%d 0x%x %p 0x1 ",
- SYS_read, tid_fd, tid_buf_addr);
- bool syscall_supported = false;
- pid_t crashing_tid =
- base::FindThreadIDWithSyscall(crashing_pid,
- expected_syscall_data,
- &syscall_supported);
- if (crashing_tid == -1) {
- // We didn't find the thread we want. Maybe it didn't reach
- // sys_read() yet or the thread went away. We'll just take a
- // guess here and assume the crashing thread is the thread group
- // leader. If procfs syscall is not supported by the kernel, then
- // we assume the kernel also does not support TID namespacing and
- // trust the TID passed by the crashing process.
- LOG(WARNING) << "Could not translate tid - assuming crashing thread is "
- "thread group leader; syscall_supported=" << syscall_supported;
- crashing_tid = crashing_pid;
- }
-
- ExceptionHandler::CrashContext* bad_context =
- reinterpret_cast<ExceptionHandler::CrashContext*>(crash_context);
- bad_context->tid = crashing_tid;
-
- // Freed in CrashDumpTask();
- BreakpadInfo* info = new BreakpadInfo;
-
- info->fd = -1;
- info->process_type_length = process_type_.length();
- char* process_type_str = new char[info->process_type_length + 1];
- process_type_.copy(process_type_str, info->process_type_length);
- process_type_str[info->process_type_length] = '\0';
- info->process_type = process_type_str;
-
- info->distro_length = strlen(distro);
- info->distro = distro;
-#if defined(OS_ANDROID)
- // Nothing gets uploaded in android.
- info->upload = false;
-#else
- info->upload = (getenv(env_vars::kHeadless) == NULL);
-#endif
-
- info->crash_keys = crash_keys;
-
-#if defined(ADDRESS_SANITIZER)
- info->asan_report_str = asan_report_str_;
- info->asan_report_length = strlen(asan_report_str_);
-#endif
- info->process_start_time = uptime;
- info->oom_size = oom_size;
-
- BrowserThread::GetBlockingPool()->PostSequencedWorkerTask(
- worker_pool_token_,
- FROM_HERE,
- base::Bind(&CrashHandlerHostLinux::WriteDumpFile,
- base::Unretained(this),
- info,
- crashing_pid,
- crash_context,
- signal_fd));
-}
-
-void CrashHandlerHostLinux::WriteDumpFile(BreakpadInfo* info,
- pid_t crashing_pid,
- char* crash_context,
- int signal_fd) {
- DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
- worker_pool_token_));
-
- base::FilePath dumps_path("/tmp");
- PathService::Get(base::DIR_TEMP, &dumps_path);
- if (!info->upload)
- PathService::Get(chrome::DIR_CRASH_DUMPS, &dumps_path);
- const uint64 rand = base::RandUint64();
- const std::string minidump_filename =
- base::StringPrintf("%s/chromium-%s-minidump-%016" PRIx64 ".dmp",
- dumps_path.value().c_str(),
- process_type_.c_str(),
- rand);
-
- if (!google_breakpad::WriteMinidump(minidump_filename.c_str(),
- kMaxMinidumpFileSize,
- crashing_pid, crash_context,
- kCrashContextSize,
- google_breakpad::MappingList(),
- google_breakpad::AppMemoryList())) {
- LOG(ERROR) << "Failed to write crash dump for pid " << crashing_pid;
- }
-#if defined(ADDRESS_SANITIZER)
- // Create a temporary file holding the AddressSanitizer report.
- const std::string log_filename =
- base::StringPrintf("%s/chromium-%s-minidump-%016" PRIx64 ".log",
- dumps_path.value().c_str(),
- process_type_.c_str(),
- rand);
- FILE* logfile = fopen(log_filename.c_str(), "w");
- CHECK(logfile);
- fprintf(logfile, "%s", asan_report_str_);
- fclose(logfile);
-#endif
-
- delete[] crash_context;
-
- // Freed in CrashDumpTask();
- char* minidump_filename_str = new char[minidump_filename.length() + 1];
- minidump_filename.copy(minidump_filename_str, minidump_filename.length());
- minidump_filename_str[minidump_filename.length()] = '\0';
- info->filename = minidump_filename_str;
-#if defined(ADDRESS_SANITIZER)
- char* minidump_log_filename_str = new char[minidump_filename.length() + 1];
- minidump_filename.copy(minidump_log_filename_str, minidump_filename.length());
- memcpy(minidump_log_filename_str + minidump_filename.length() - 3, "log", 3);
- minidump_log_filename_str[minidump_filename.length()] = '\0';
- info->log_filename = minidump_log_filename_str;
-#endif
- info->pid = crashing_pid;
-
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&CrashHandlerHostLinux::QueueCrashDumpTask,
- base::Unretained(this),
- info,
- signal_fd));
-}
-
-void CrashHandlerHostLinux::QueueCrashDumpTask(BreakpadInfo* info,
- int signal_fd) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
- // Send the done signal to the process: it can exit now.
- struct msghdr msg = {0};
- struct iovec done_iov;
- done_iov.iov_base = const_cast<char*>("\x42");
- done_iov.iov_len = 1;
- msg.msg_iov = &done_iov;
- msg.msg_iovlen = 1;
-
- (void) HANDLE_EINTR(sendmsg(signal_fd, &msg, MSG_DONTWAIT | MSG_NOSIGNAL));
- (void) HANDLE_EINTR(close(signal_fd));
-
- uploader_thread_->message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&CrashDumpTask, base::Unretained(this), info));
-}
-
-void CrashHandlerHostLinux::WillDestroyCurrentMessageLoop() {
- file_descriptor_watcher_.StopWatchingFileDescriptor();
-
- // If we are quitting and there are crash dumps in the queue, turn them into
- // no-ops.
- shutting_down_ = true;
- uploader_thread_->Stop();
-}
-
-bool CrashHandlerHostLinux::IsShuttingDown() const {
- return shutting_down_;
-}
-
-ExtensionCrashHandlerHostLinux::ExtensionCrashHandlerHostLinux() {
- InitCrashUploaderThread();
-}
-
-ExtensionCrashHandlerHostLinux::~ExtensionCrashHandlerHostLinux() {
-}
-
-void ExtensionCrashHandlerHostLinux::SetProcessType() {
- process_type_ = "extension";
-}
-
-// static
-ExtensionCrashHandlerHostLinux* ExtensionCrashHandlerHostLinux::GetInstance() {
- return Singleton<ExtensionCrashHandlerHostLinux>::get();
-}
-
-GpuCrashHandlerHostLinux::GpuCrashHandlerHostLinux() {
- InitCrashUploaderThread();
-}
-
-GpuCrashHandlerHostLinux::~GpuCrashHandlerHostLinux() {
-}
-
-void GpuCrashHandlerHostLinux::SetProcessType() {
- process_type_ = "gpu-process";
-}
-
-// static
-GpuCrashHandlerHostLinux* GpuCrashHandlerHostLinux::GetInstance() {
- return Singleton<GpuCrashHandlerHostLinux>::get();
-}
-
-PluginCrashHandlerHostLinux::PluginCrashHandlerHostLinux() {
- InitCrashUploaderThread();
-}
-
-PluginCrashHandlerHostLinux::~PluginCrashHandlerHostLinux() {
-}
-
-void PluginCrashHandlerHostLinux::SetProcessType() {
- process_type_ = "plugin";
-}
-
-// static
-PluginCrashHandlerHostLinux* PluginCrashHandlerHostLinux::GetInstance() {
- return Singleton<PluginCrashHandlerHostLinux>::get();
-}
-
-PpapiCrashHandlerHostLinux::PpapiCrashHandlerHostLinux() {
- InitCrashUploaderThread();
-}
-
-PpapiCrashHandlerHostLinux::~PpapiCrashHandlerHostLinux() {
-}
-
-void PpapiCrashHandlerHostLinux::SetProcessType() {
- process_type_ = "ppapi";
-}
-
-// static
-PpapiCrashHandlerHostLinux* PpapiCrashHandlerHostLinux::GetInstance() {
- return Singleton<PpapiCrashHandlerHostLinux>::get();
-}
-
-RendererCrashHandlerHostLinux::RendererCrashHandlerHostLinux() {
- InitCrashUploaderThread();
-}
-
-RendererCrashHandlerHostLinux::~RendererCrashHandlerHostLinux() {
-}
-
-void RendererCrashHandlerHostLinux::SetProcessType() {
- process_type_ = "renderer";
-}
-
-// static
-RendererCrashHandlerHostLinux* RendererCrashHandlerHostLinux::GetInstance() {
- return Singleton<RendererCrashHandlerHostLinux>::get();
-}
diff --git a/chrome/browser/crash_handler_host_linux.h b/chrome/browser/crash_handler_host_linux.h
deleted file mode 100644
index 6b2703729d..0000000000
--- a/chrome/browser/crash_handler_host_linux.h
+++ /dev/null
@@ -1,171 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_CRASH_HANDLER_HOST_LINUX_H_
-#define CHROME_BROWSER_CRASH_HANDLER_HOST_LINUX_H_
-
-#include <sys/types.h>
-
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/threading/sequenced_worker_pool.h"
-
-struct BreakpadInfo;
-
-namespace base {
-class Thread;
-}
-
-template <typename T> struct DefaultSingletonTraits;
-
-// This is the base class for singleton objects which crash dump renderers and
-// plugins on Linux or Android. We perform the crash dump from the browser
-// because it allows us to be outside the sandbox.
-//
-// PluginCrashHandlerHostLinux and RendererCrashHandlerHostLinux are
-// singletons that handle plugin and renderer crashes, respectively.
-//
-// Processes signal that they need to be dumped by sending a datagram over a
-// UNIX domain socket. All processes of the same type share the client end of
-// this socket which is installed in their descriptor table before exec.
-class CrashHandlerHostLinux : public base::MessageLoopForIO::Watcher,
- public base::MessageLoop::DestructionObserver {
- public:
- // Get the file descriptor which processes should be given in order to signal
- // crashes to the browser.
- int GetDeathSignalSocket() const {
- return process_socket_;
- }
-
- // MessagePumbLibevent::Watcher impl:
- virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE;
- virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE;
-
- // MessageLoop::DestructionObserver impl:
- virtual void WillDestroyCurrentMessageLoop() OVERRIDE;
-
- // Whether we are shutting down or not.
- bool IsShuttingDown() const;
-
- protected:
- CrashHandlerHostLinux();
- virtual ~CrashHandlerHostLinux();
-
- // Only called in concrete subclasses.
- void InitCrashUploaderThread();
-
- std::string process_type_;
-
- private:
- void Init();
-
- // This is here on purpose to make CrashHandlerHostLinux abstract.
- virtual void SetProcessType() = 0;
-
- // Do work on the FILE thread for OnFileCanReadWithoutBlocking().
- void WriteDumpFile(BreakpadInfo* info,
- pid_t crashing_pid,
- char* crash_context,
- int signal_fd);
-
- // Continue OnFileCanReadWithoutBlocking()'s work on the IO thread.
- void QueueCrashDumpTask(BreakpadInfo* info, int signal_fd);
-
- int process_socket_;
- int browser_socket_;
-
- base::MessageLoopForIO::FileDescriptorWatcher file_descriptor_watcher_;
- scoped_ptr<base::Thread> uploader_thread_;
- bool shutting_down_;
-
- // Unique sequence token so that writing crash dump won't be blocked
- // by other tasks.
- base::SequencedWorkerPool::SequenceToken worker_pool_token_;
-
-#if defined(ADDRESS_SANITIZER)
- char* asan_report_str_;
-#endif
-
- DISALLOW_COPY_AND_ASSIGN(CrashHandlerHostLinux);
-};
-
-class ExtensionCrashHandlerHostLinux : public CrashHandlerHostLinux {
- public:
- // Returns the singleton instance.
- static ExtensionCrashHandlerHostLinux* GetInstance();
-
- private:
- friend struct DefaultSingletonTraits<ExtensionCrashHandlerHostLinux>;
- ExtensionCrashHandlerHostLinux();
- virtual ~ExtensionCrashHandlerHostLinux();
-
- virtual void SetProcessType() OVERRIDE;
-
- DISALLOW_COPY_AND_ASSIGN(ExtensionCrashHandlerHostLinux);
-};
-
-class GpuCrashHandlerHostLinux : public CrashHandlerHostLinux {
- public:
- // Returns the singleton instance.
- static GpuCrashHandlerHostLinux* GetInstance();
-
- private:
- friend struct DefaultSingletonTraits<GpuCrashHandlerHostLinux>;
- GpuCrashHandlerHostLinux();
- virtual ~GpuCrashHandlerHostLinux();
-
- virtual void SetProcessType() OVERRIDE;
-
- DISALLOW_COPY_AND_ASSIGN(GpuCrashHandlerHostLinux);
-};
-
-class PluginCrashHandlerHostLinux : public CrashHandlerHostLinux {
- public:
- // Returns the singleton instance.
- static PluginCrashHandlerHostLinux* GetInstance();
-
- private:
- friend struct DefaultSingletonTraits<PluginCrashHandlerHostLinux>;
- PluginCrashHandlerHostLinux();
- virtual ~PluginCrashHandlerHostLinux();
-
- virtual void SetProcessType() OVERRIDE;
-
- DISALLOW_COPY_AND_ASSIGN(PluginCrashHandlerHostLinux);
-};
-
-class PpapiCrashHandlerHostLinux : public CrashHandlerHostLinux {
- public:
- // Returns the singleton instance.
- static PpapiCrashHandlerHostLinux* GetInstance();
-
- private:
- friend struct DefaultSingletonTraits<PpapiCrashHandlerHostLinux>;
- PpapiCrashHandlerHostLinux();
- virtual ~PpapiCrashHandlerHostLinux();
-
- virtual void SetProcessType() OVERRIDE;
-
- DISALLOW_COPY_AND_ASSIGN(PpapiCrashHandlerHostLinux);
-};
-
-class RendererCrashHandlerHostLinux : public CrashHandlerHostLinux {
- public:
- // Returns the singleton instance.
- static RendererCrashHandlerHostLinux* GetInstance();
-
- private:
- friend struct DefaultSingletonTraits<RendererCrashHandlerHostLinux>;
- RendererCrashHandlerHostLinux();
- virtual ~RendererCrashHandlerHostLinux();
-
- virtual void SetProcessType() OVERRIDE;
-
- DISALLOW_COPY_AND_ASSIGN(RendererCrashHandlerHostLinux);
-};
-
-#endif // CHROME_BROWSER_CRASH_HANDLER_HOST_LINUX_H_
diff --git a/chrome/browser/devtools/OWNERS b/chrome/browser/devtools/OWNERS
index 9793bcc9f5..030f974441 100644
--- a/chrome/browser/devtools/OWNERS
+++ b/chrome/browser/devtools/OWNERS
@@ -1,4 +1,6 @@
+kaznacheev@chromium.org
pfeldman@chromium.org
+vsevik@chromium.org
yurys@chromium.org
# Changes to embedder messages require a security review.
diff --git a/chrome/browser/devtools/devtools_adb_bridge.cc b/chrome/browser/devtools/devtools_adb_bridge.cc
index 40989f4f81..156bcf4a21 100644
--- a/chrome/browser/devtools/devtools_adb_bridge.cc
+++ b/chrome/browser/devtools/devtools_adb_bridge.cc
@@ -79,19 +79,17 @@ typedef base::Callback<void(const AndroidDevices&)> AndroidDevicesCallback;
class AdbDeviceImpl : public DevToolsAdbBridge::AndroidDevice {
public:
- explicit AdbDeviceImpl(const std::string& serial);
+ AdbDeviceImpl(const std::string& serial, bool is_connected);
virtual void RunCommand(const std::string& command,
const CommandCallback& callback) OVERRIDE;
virtual void OpenSocket(const std::string& name,
const SocketCallback& callback) OVERRIDE;
- virtual bool IsConnected() OVERRIDE;
-
private:
virtual ~AdbDeviceImpl() {}
};
-AdbDeviceImpl::AdbDeviceImpl(const std::string& serial)
- : AndroidDevice(serial) {
+AdbDeviceImpl::AdbDeviceImpl(const std::string& serial, bool is_connected)
+ : AndroidDevice(serial, is_connected) {
}
void AdbDeviceImpl::RunCommand(const std::string& command,
@@ -108,11 +106,6 @@ void AdbDeviceImpl::OpenSocket(const std::string& name,
AdbClientSocket::TransportQuery(kAdbPort, serial(), socket_name, callback);
}
-bool AdbDeviceImpl::IsConnected() {
- return true;
-}
-
-
// UsbDeviceImpl --------------------------------------------------------------
class UsbDeviceImpl : public DevToolsAdbBridge::AndroidDevice {
@@ -122,7 +115,6 @@ class UsbDeviceImpl : public DevToolsAdbBridge::AndroidDevice {
const CommandCallback& callback) OVERRIDE;
virtual void OpenSocket(const std::string& name,
const SocketCallback& callback) OVERRIDE;
- virtual bool IsConnected() OVERRIDE;
private:
void OnOpenSocket(const SocketCallback& callback,
@@ -143,7 +135,7 @@ class UsbDeviceImpl : public DevToolsAdbBridge::AndroidDevice {
UsbDeviceImpl::UsbDeviceImpl(AndroidUsbDevice* device)
- : AndroidDevice(device->serial()),
+ : AndroidDevice(device->serial(), device->is_connected()),
device_(device) {
device_->InitOnCallerThread();
}
@@ -208,10 +200,6 @@ void UsbDeviceImpl::OnRead(net::StreamSocket* socket,
OnRead(socket, buffer, new_data, callback, result);
}
-bool UsbDeviceImpl::IsConnected() {
- return device_->is_connected();
-}
-
// AdbCountDevicesCommand -----------------------------------------------------
@@ -351,7 +339,7 @@ void AdbPagesCommand::WrapUsbDevices(const AndroidUsbDevices& usb_devices) {
DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current());
#if defined(DEBUG_DEVTOOLS)
- devices_.push_back(new AdbDeviceImpl("")); // For desktop remote debugging.
+ devices_.push_back(new AdbDeviceImpl("", true)); // For desktop debugging.
#endif // defined(DEBUG_DEVTOOLS)
for (AndroidUsbDevices::const_iterator it = usb_devices.begin();
@@ -373,7 +361,8 @@ void AdbPagesCommand::ReceivedAdbDevices(
for (size_t i = 0; i < serials.size(); ++i) {
std::vector<std::string> tokens;
Tokenize(serials[i], "\t ", &tokens);
- devices_.push_back(new AdbDeviceImpl(tokens[0]));
+ bool offline = tokens.size() > 1 && tokens[1] == "offline";
+ devices_.push_back(new AdbDeviceImpl(tokens[0], !offline));
}
ProcessSerials();
}
@@ -409,7 +398,7 @@ void AdbPagesCommand::ProcessSerials() {
#endif // defined(DEBUG_DEVTOOLS)
scoped_refptr<DevToolsAdbBridge::AndroidDevice> device = devices_.back();
- if (device->IsConnected()) {
+ if (device->is_connected()) {
device->RunCommand(kDeviceModelCommand,
base::Bind(&AdbPagesCommand::ReceivedModel, this));
} else {
@@ -763,8 +752,10 @@ DevToolsAdbBridge::Factory::BuildServiceInstanceFor(
// DevToolsAdbBridge::AndroidDevice -------------------------------------------
-DevToolsAdbBridge::AndroidDevice::AndroidDevice(const std::string& serial)
- : serial_(serial) {
+DevToolsAdbBridge::AndroidDevice::AndroidDevice(const std::string& serial,
+ bool is_connected)
+ : serial_(serial),
+ is_connected_(is_connected) {
}
void DevToolsAdbBridge::AndroidDevice::HttpQuery(
@@ -1062,7 +1053,7 @@ std::string DevToolsAdbBridge::RemoteDevice::GetModel() {
}
bool DevToolsAdbBridge::RemoteDevice::IsConnected() {
- return device_->IsConnected();
+ return device_->is_connected();
}
void DevToolsAdbBridge::RemoteDevice::AddBrowser(
diff --git a/chrome/browser/devtools/devtools_adb_bridge.h b/chrome/browser/devtools/devtools_adb_bridge.h
index 0273e081d7..ccc34042cb 100644
--- a/chrome/browser/devtools/devtools_adb_bridge.h
+++ b/chrome/browser/devtools/devtools_adb_bridge.h
@@ -211,13 +211,12 @@ class DevToolsAdbBridge
class AndroidDevice : public base::RefCounted<AndroidDevice> {
public:
- explicit AndroidDevice(const std::string& serial);
+ AndroidDevice(const std::string& serial, bool is_connected);
virtual void RunCommand(const std::string& command,
const CommandCallback& callback) = 0;
virtual void OpenSocket(const std::string& socket_name,
const SocketCallback& callback) = 0;
- virtual bool IsConnected() = 0;
void HttpQuery(const std::string& la_name,
const std::string& request,
const CommandCallback& callback);
@@ -226,6 +225,7 @@ class DevToolsAdbBridge
const SocketCallback& callback);
std::string serial() { return serial_; }
+ bool is_connected() { return is_connected_; }
std::string model() { return model_; }
void set_model(const std::string& model) { model_ = model; }
@@ -245,6 +245,7 @@ class DevToolsAdbBridge
net::StreamSocket* socket);
std::string serial_;
+ bool is_connected_;
std::string model_;
DISALLOW_COPY_AND_ASSIGN(AndroidDevice);
diff --git a/chrome/browser/devtools/devtools_file_helper.cc b/chrome/browser/devtools/devtools_file_helper.cc
index 38e49bcaa7..d8372a40eb 100644
--- a/chrome/browser/devtools/devtools_file_helper.cc
+++ b/chrome/browser/devtools/devtools_file_helper.cc
@@ -152,6 +152,7 @@ std::string RegisterFileSystem(WebContents* web_contents,
policy->GrantReadFileSystem(renderer_id, file_system_id);
policy->GrantWriteFileSystem(renderer_id, file_system_id);
policy->GrantCreateFileForFileSystem(renderer_id, file_system_id);
+ policy->GrantDeleteFromFileSystem(renderer_id, file_system_id);
// We only need file level access for reading FileEntries. Saving FileEntries
// just needs the file system to have read/write access, which is granted
diff --git a/chrome/browser/devtools/devtools_sanity_browsertest.cc b/chrome/browser/devtools/devtools_sanity_browsertest.cc
index 57472a6ab8..c0129ffe83 100644
--- a/chrome/browser/devtools/devtools_sanity_browsertest.cc
+++ b/chrome/browser/devtools/devtools_sanity_browsertest.cc
@@ -444,16 +444,18 @@ IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestBeforeUnloadEvents) {
}
// Tests scripts panel showing.
-IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestShowScriptsTab) {
+// Disabled: http://crbug.com/309822
+IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, DISABLED_TestShowScriptsTab) {
RunTest("testShowScriptsTab", kDebuggerTestPage);
}
// Tests that scripts tab is populated with inspected scripts even if it
// hadn't been shown by the moment inspected paged refreshed.
// @see http://crbug.com/26312
+// Disabled: http://crbug.com/309822
IN_PROC_BROWSER_TEST_F(
DevToolsSanityTest,
- TestScriptsTabIsPopulatedOnInspectedPageRefresh) {
+ DISABLED_TestScriptsTabIsPopulatedOnInspectedPageRefresh) {
// Clear inspector settings to ensure that Elements will be
// current panel when DevTools window is open.
content::BrowserContext* browser_context =
@@ -497,22 +499,25 @@ IN_PROC_BROWSER_TEST_F(DevToolsExperimentalExtensionTest,
// Tests that a content script is in the scripts list.
// http://crbug.com/114104
+// Disabled: http://crbug.com/309822
IN_PROC_BROWSER_TEST_F(DevToolsExtensionTest,
- TestContentScriptIsPresent) {
+ DISABLED_TestContentScriptIsPresent) {
LoadExtension("simple_content_script");
RunTest("testContentScriptIsPresent", kPageWithContentScript);
}
// Tests that scripts are not duplicated after Scripts Panel switch.
+// Disabled: http://crbug.com/309822
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest,
- TestNoScriptDuplicatesOnPanelSwitch) {
+ DISABLED_TestNoScriptDuplicatesOnPanelSwitch) {
RunTest("testNoScriptDuplicatesOnPanelSwitch", kDebuggerTestPage);
}
// Tests that debugger works correctly if pause event occurs when DevTools
// frontend is being loaded.
+// Disabled: http://crbug.com/309822
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest,
- TestPauseWhenLoadingDevTools) {
+ DISABLED_TestPauseWhenLoadingDevTools) {
RunTest("testPauseWhenLoadingDevTools", kPauseWhenLoadingDevTools);
}
@@ -527,7 +532,9 @@ IN_PROC_BROWSER_TEST_F(DevToolsSanityTest,
#else
#define MAYBE_TestPauseWhenScriptIsRunning TestPauseWhenScriptIsRunning
#endif
-IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, MAYBE_TestPauseWhenScriptIsRunning) {
+// Disabled: http://crbug.com/309822
+IN_PROC_BROWSER_TEST_F(DevToolsSanityTest,
+ DISABLED_TestPauseWhenScriptIsRunning) {
RunTest("testPauseWhenScriptIsRunning", kPauseWhenScriptIsRunning);
}
diff --git a/chrome/browser/devtools/devtools_window.cc b/chrome/browser/devtools/devtools_window.cc
index 40ccdcb3cd..a3fa06396b 100644
--- a/chrome/browser/devtools/devtools_window.cc
+++ b/chrome/browser/devtools/devtools_window.cc
@@ -17,6 +17,7 @@
#include "chrome/browser/extensions/api/debugger/debugger_api.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/extension_web_contents_observer.h"
#include "chrome/browser/file_select_helper.h"
#include "chrome/browser/infobars/confirm_infobar_delegate.h"
#include "chrome/browser/prefs/pref_service_syncable.h"
@@ -572,6 +573,7 @@ DevToolsWindow::DevToolsWindow(Profile* profile,
web_contents_, this));
file_helper_.reset(new DevToolsFileHelper(web_contents_, profile));
file_system_indexer_ = new DevToolsFileSystemIndexer();
+ extensions::ExtensionWebContentsObserver::CreateForWebContents(web_contents_);
g_instances.Get().push_back(this);
@@ -621,6 +623,9 @@ GURL DevToolsWindow::GetDevToolsURL(Profile* profile,
DevToolsDockSide dock_side,
bool shared_worker_frontend,
bool external_frontend) {
+ if (base_url.SchemeIs("data"))
+ return base_url;
+
std::string frontend_url(
base_url.is_empty() ? chrome::kChromeUIDevToolsURL : base_url.spec());
ThemeService* tp = ThemeServiceFactory::GetForProfile(profile);
diff --git a/chrome/browser/download/OWNERS b/chrome/browser/download/OWNERS
index bd9d0d4fb3..93ed63f383 100644
--- a/chrome/browser/download/OWNERS
+++ b/chrome/browser/download/OWNERS
@@ -5,3 +5,6 @@ phajdan.jr@chromium.org
rdsmith@chromium.org
per-file *_file_picker_chromeos.*=achuith@chromium.org
+
+per-file download_dir_policy_handler*=dconnelly@chromium.org
+per-file download_dir_policy_handler*=joaodasilva@chromium.org
diff --git a/chrome/browser/download/download_browsertest.cc b/chrome/browser/download/download_browsertest.cc
index 31d8abe656..e99192fdb8 100644
--- a/chrome/browser/download/download_browsertest.cc
+++ b/chrome/browser/download/download_browsertest.cc
@@ -703,6 +703,7 @@ class DownloadTest : public InProcessBrowserTest {
GURL slow_download_url(URLRequestSlowDownloadJob::kUnknownSizeUrl);
DownloadManager* manager = DownloadManagerForBrowser(browser());
+ EXPECT_EQ(0, manager->NonMaliciousInProgressCount());
EXPECT_EQ(0, manager->InProgressCount());
if (manager->InProgressCount() != 0)
return NULL;
diff --git a/chrome/browser/download/download_danger_prompt.cc b/chrome/browser/download/download_danger_prompt.cc
index a22eab1cf4..9c62965959 100644
--- a/chrome/browser/download/download_danger_prompt.cc
+++ b/chrome/browser/download/download_danger_prompt.cc
@@ -8,7 +8,6 @@
#include "base/metrics/field_trial.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/download/chrome_download_manager_delegate.h"
-#include "chrome/browser/download/download_field_trial.h"
#include "chrome/browser/ui/tab_modal_confirm_dialog.h"
#include "chrome/browser/ui/tab_modal_confirm_dialog_delegate.h"
#include "content/public/browser/download_danger_type.h"
@@ -41,6 +40,7 @@ class DownloadDangerPromptImpl : public DownloadDangerPrompt,
virtual string16 GetTitle() OVERRIDE;
virtual string16 GetMessage() OVERRIDE;
virtual string16 GetAcceptButtonTitle() OVERRIDE;
+ virtual string16 GetCancelButtonTitle() OVERRIDE;
virtual void OnAccepted() OVERRIDE;
virtual void OnCanceled() OVERRIDE;
virtual void OnClosed() OVERRIDE;
@@ -96,48 +96,56 @@ void DownloadDangerPromptImpl::OnDownloadUpdated(
}
string16 DownloadDangerPromptImpl::GetTitle() {
- return l10n_util::GetStringUTF16(IDS_CONFIRM_KEEP_DANGEROUS_DOWNLOAD_TITLE);
+ if (show_context_)
+ return l10n_util::GetStringUTF16(IDS_CONFIRM_KEEP_DANGEROUS_DOWNLOAD_TITLE);
+ else
+ return l10n_util::GetStringUTF16(IDS_RESTORE_KEEP_DANGEROUS_DOWNLOAD_TITLE);
}
string16 DownloadDangerPromptImpl::GetMessage() {
- if (!show_context_)
- return l10n_util::GetStringUTF16(
- IDS_PROMPT_CONFIRM_KEEP_DANGEROUS_DOWNLOAD);
- switch (download_->GetDangerType()) {
- case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE: {
- return l10n_util::GetStringFUTF16(
- IDS_PROMPT_DANGEROUS_DOWNLOAD,
- download_->GetFileNameToReportUser().LossyDisplayName());
- }
- case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: // Fall through
- case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
- case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: {
- std::string trial_condition =
- base::FieldTrialList::FindFullName(kMalwareWarningFinchTrialName);
- if (trial_condition.empty()) {
+ if (show_context_) {
+ switch (download_->GetDangerType()) {
+ case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE: {
+ return l10n_util::GetStringFUTF16(
+ IDS_PROMPT_DANGEROUS_DOWNLOAD,
+ download_->GetFileNameToReportUser().LossyDisplayName());
+ }
+ case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: // Fall through
+ case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
+ case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: {
return l10n_util::GetStringFUTF16(
IDS_PROMPT_MALICIOUS_DOWNLOAD_CONTENT,
download_->GetFileNameToReportUser().LossyDisplayName());
}
- return AssembleMalwareFinchString(
- trial_condition,
- download_->GetFileNameToReportUser().LossyDisplayName());
- }
- case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: {
- return l10n_util::GetStringFUTF16(
- IDS_PROMPT_UNCOMMON_DOWNLOAD_CONTENT,
- download_->GetFileNameToReportUser().LossyDisplayName());
- }
- case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: {
- return l10n_util::GetStringFUTF16(
- IDS_PROMPT_DOWNLOAD_CHANGES_SEARCH_SETTINGS,
- download_->GetFileNameToReportUser().LossyDisplayName());
+ case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: {
+ return l10n_util::GetStringFUTF16(
+ IDS_PROMPT_UNCOMMON_DOWNLOAD_CONTENT,
+ download_->GetFileNameToReportUser().LossyDisplayName());
+ }
+ case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: {
+ return l10n_util::GetStringFUTF16(
+ IDS_PROMPT_DOWNLOAD_CHANGES_SEARCH_SETTINGS,
+ download_->GetFileNameToReportUser().LossyDisplayName());
+ }
+ case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS:
+ case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT:
+ case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED:
+ case content::DOWNLOAD_DANGER_TYPE_MAX: {
+ break;
+ }
}
- case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS:
- case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT:
- case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED:
- case content::DOWNLOAD_DANGER_TYPE_MAX: {
- break;
+ } else {
+ switch (download_->GetDangerType()) {
+ case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
+ case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
+ case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: {
+ return l10n_util::GetStringUTF16(
+ IDS_PROMPT_CONFIRM_KEEP_MALICIOUS_DOWNLOAD);
+ }
+ default: {
+ return l10n_util::GetStringUTF16(
+ IDS_PROMPT_CONFIRM_KEEP_DANGEROUS_DOWNLOAD);
+ }
}
}
NOTREACHED();
@@ -145,8 +153,31 @@ string16 DownloadDangerPromptImpl::GetMessage() {
}
string16 DownloadDangerPromptImpl::GetAcceptButtonTitle() {
- return l10n_util::GetStringUTF16(
- show_context_ ? IDS_CONFIRM_DOWNLOAD : IDS_CONFIRM_DOWNLOAD_AGAIN);
+ if (show_context_)
+ return l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD);
+ switch (download_->GetDangerType()) {
+ case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
+ case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
+ case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: {
+ return l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD_AGAIN_MALICIOUS);
+ }
+ default:
+ return l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD_AGAIN);
+ }
+}
+
+string16 DownloadDangerPromptImpl::GetCancelButtonTitle() {
+ if (show_context_)
+ return l10n_util::GetStringUTF16(IDS_CANCEL);
+ switch (download_->GetDangerType()) {
+ case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
+ case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
+ case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: {
+ return l10n_util::GetStringUTF16(IDS_CONFIRM_CANCEL_AGAIN_MALICIOUS);
+ }
+ default:
+ return l10n_util::GetStringUTF16(IDS_CANCEL);
+ }
}
void DownloadDangerPromptImpl::OnAccepted() {
diff --git a/chrome/browser/download/download_danger_prompt_browsertest.cc b/chrome/browser/download/download_danger_prompt_browsertest.cc
index 02627adf92..cdd17d02dc 100644
--- a/chrome/browser/download/download_danger_prompt_browsertest.cc
+++ b/chrome/browser/download/download_danger_prompt_browsertest.cc
@@ -77,8 +77,10 @@ class DownloadDangerPromptTest : public InProcessBrowserTest {
EXPECT_CALL(download_, GetFileNameToReportUser()).WillRepeatedly(Return(
base::FilePath(FILE_PATH_LITERAL("evil.exe"))));
EXPECT_CALL(download_, AddObserver(_))
- .WillOnce(SaveArg<0>(&download_observer_));
+ .WillOnce(SaveArg<0>(&download_observer_));
EXPECT_CALL(download_, RemoveObserver(Eq(ByRef(download_observer_))));
+ EXPECT_CALL(download_, GetDangerType())
+ .WillRepeatedly(Return(content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL));
}
void CreatePrompt() {
diff --git a/chrome/browser/download/download_dir_policy_handler.cc b/chrome/browser/download/download_dir_policy_handler.cc
new file mode 100644
index 0000000000..f1d4932ac8
--- /dev/null
+++ b/chrome/browser/download/download_dir_policy_handler.cc
@@ -0,0 +1,42 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/download/download_dir_policy_handler.h"
+
+#include "base/files/file_path.h"
+#include "base/prefs/pref_value_map.h"
+#include "base/values.h"
+#include "chrome/browser/download/download_prefs.h"
+#include "chrome/browser/policy/policy_map.h"
+#include "chrome/browser/policy/policy_path_parser.h"
+#include "chrome/common/pref_names.h"
+#include "policy/policy_constants.h"
+
+DownloadDirPolicyHandler::DownloadDirPolicyHandler()
+ : TypeCheckingPolicyHandler(policy::key::kDownloadDirectory,
+ base::Value::TYPE_STRING) {}
+
+DownloadDirPolicyHandler::~DownloadDirPolicyHandler() {}
+
+void DownloadDirPolicyHandler::ApplyPolicySettings(
+ const policy::PolicyMap& policies,
+ PrefValueMap* prefs) {
+ const base::Value* value = policies.GetValue(policy_name());
+ base::FilePath::StringType string_value;
+ if (!value || !value->GetAsString(&string_value))
+ return;
+
+ base::FilePath::StringType expanded_value =
+ policy::path_parser::ExpandPathVariables(string_value);
+ // Make sure the path isn't empty, since that will point to an undefined
+ // location; the default location is used instead in that case.
+ // This is checked after path expansion because a non-empty policy value can
+ // lead to an empty path value after expansion (e.g. "\"\"").
+ if (expanded_value.empty())
+ expanded_value = DownloadPrefs::GetDefaultDownloadDirectory().value();
+ prefs->SetValue(prefs::kDownloadDefaultDirectory,
+ Value::CreateStringValue(expanded_value));
+ prefs->SetValue(prefs::kPromptForDownload,
+ Value::CreateBooleanValue(false));
+}
diff --git a/chrome/browser/download/download_dir_policy_handler.h b/chrome/browser/download/download_dir_policy_handler.h
new file mode 100644
index 0000000000..3620ef6fed
--- /dev/null
+++ b/chrome/browser/download/download_dir_policy_handler.h
@@ -0,0 +1,30 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_DIR_POLICY_HANDLER_H_
+#define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_DIR_POLICY_HANDLER_H_
+
+#include "chrome/browser/policy/configuration_policy_handler.h"
+
+class PrefValueMap;
+
+namespace policy {
+class PolicyMap;
+} // namespace policy
+
+// ConfigurationPolicyHandler for the DownloadDirectory policy.
+class DownloadDirPolicyHandler : public policy::TypeCheckingPolicyHandler {
+ public:
+ DownloadDirPolicyHandler();
+ virtual ~DownloadDirPolicyHandler();
+
+ // ConfigurationPolicyHandler methods:
+ virtual void ApplyPolicySettings(const policy::PolicyMap& policies,
+ PrefValueMap* prefs) OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DownloadDirPolicyHandler);
+};
+
+#endif // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_DIR_POLICY_HANDLER_H_
diff --git a/chrome/browser/download/download_dir_policy_handler_unittest.cc b/chrome/browser/download/download_dir_policy_handler_unittest.cc
new file mode 100644
index 0000000000..c4ff387750
--- /dev/null
+++ b/chrome/browser/download/download_dir_policy_handler_unittest.cc
@@ -0,0 +1,35 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/values.h"
+#include "chrome/browser/download/download_dir_policy_handler.h"
+#include "chrome/browser/download/download_prefs.h"
+#include "chrome/browser/policy/configuration_policy_pref_store.h"
+#include "chrome/browser/policy/configuration_policy_pref_store_unittest.h"
+#include "chrome/browser/policy/policy_map.h"
+#include "chrome/common/pref_names.h"
+#include "policy/policy_constants.h"
+
+class DownloadDirPolicyHandlerTest
+ : public policy::ConfigurationPolicyPrefStoreTest {};
+
+TEST_F(DownloadDirPolicyHandlerTest, SetDownloadDirectory) {
+ policy::PolicyMap policy;
+ EXPECT_FALSE(store_->GetValue(prefs::kPromptForDownload, NULL));
+ policy.Set(policy::key::kDownloadDirectory,
+ policy::POLICY_LEVEL_MANDATORY,
+ policy::POLICY_SCOPE_USER,
+ base::Value::CreateStringValue(std::string()),
+ NULL);
+ UpdateProviderPolicy(policy);
+
+ // Setting a DownloadDirectory should disable the PromptForDownload pref.
+ const base::Value* value = NULL;
+ EXPECT_TRUE(store_->GetValue(prefs::kPromptForDownload, &value));
+ ASSERT_TRUE(value);
+ bool prompt_for_download = true;
+ bool result = value->GetAsBoolean(&prompt_for_download);
+ ASSERT_TRUE(result);
+ EXPECT_FALSE(prompt_for_download);
+}
diff --git a/chrome/browser/download/download_field_trial.cc b/chrome/browser/download/download_field_trial.cc
deleted file mode 100644
index 58d76da584..0000000000
--- a/chrome/browser/download/download_field_trial.cc
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/download/download_field_trial.h"
-
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-
-namespace {
-
-const char kCondition1Control[] = "Condition1Control";
-const char kCondition2Control[] = "Condition2Control";
-const char kCondition3Malicious[] = "Condition3Malicious";
-const char kCondition4Unsafe[] = "Condition4Unsafe";
-const char kCondition5Dangerous[] = "Condition5Dangerous";
-const char kCondition6Harmful[] = "Condition6Harmful";
-const char kCondition7DiscardSecond[] = "Condition7DiscardSecond";
-const char kCondition8DiscardFirst[] = "Condition8DiscardFirst";
-const char kCondition9SafeDiscard[] = "Condition9SafeDiscard";
-const char kCondition10SafeDontRun[] = "Condition10SafeDontRun";
-
-} // namespace
-
-const char kMalwareWarningFinchTrialName[] = "MalwareDownloadWarning";
-
-base::string16 AssembleMalwareFinchString(
- const std::string& trial_condition,
- const base::string16& elided_filename) {
- // Sanity check to make sure we have a filename.
- base::string16 filename;
- if (elided_filename.empty()) {
- filename = ASCIIToUTF16("This file");
- } else {
- filename = ReplaceStringPlaceholders(
- ASCIIToUTF16("File '$1'"), elided_filename, NULL);
- }
-
- // Set the message text according to the condition.
- if (trial_condition == kCondition1Control) {
- return ASCIIToUTF16("This file appears malicious.");
- }
- base::string16 message_text;
- if (trial_condition == kCondition2Control) {
- message_text = ASCIIToUTF16("$1 appears malicious.");
- } else if (trial_condition == kCondition3Malicious) {
- message_text = ASCIIToUTF16("$1 is malicious.");
- } else if (trial_condition == kCondition4Unsafe) {
- message_text = ASCIIToUTF16("$1 is unsafe.");
- } else if (trial_condition == kCondition5Dangerous) {
- message_text = ASCIIToUTF16("$1 is dangerous.");
- } else if (trial_condition == kCondition6Harmful) {
- message_text = ASCIIToUTF16("$1 is harmful.");
- } else if (trial_condition == kCondition7DiscardSecond) {
- message_text = ASCIIToUTF16(
- "$1 is malicious. Discard this file to stay safe.");
- } else if (trial_condition == kCondition8DiscardFirst) {
- message_text = ASCIIToUTF16(
- "Discard this file to stay safe. $1 is malicious.");
- } else if (trial_condition == kCondition9SafeDiscard) {
- message_text = ASCIIToUTF16("$1 is malicious. To stay safe, discard it.");
- } else if (trial_condition == kCondition10SafeDontRun) {
- message_text = ASCIIToUTF16("$1 is malicious. To stay safe, don't run it.");
- } else {
- // We use the second control as a default for other conditions that don't
- // change the warning string.
- message_text = ASCIIToUTF16("$1 appears malicious.");
- }
-
- return ReplaceStringPlaceholders(message_text, filename, NULL);
-}
diff --git a/chrome/browser/download/download_field_trial.h b/chrome/browser/download/download_field_trial.h
deleted file mode 100644
index 8f5d721b2f..0000000000
--- a/chrome/browser/download/download_field_trial.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_FIELD_TRIAL_H_
-#define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_FIELD_TRIAL_H_
-
-#include <string>
-
-#include "base/strings/string16.h"
-
-// Summer/Fall 2013 Finch experiment strings ---------------------------------
-// Only deployed to English speakers, don't need translation.
-
-extern const char kMalwareWarningFinchTrialName[];
-
-// Helper for getting the appropriate message for a Finch trial.
-// You should only invoke this if you believe you're in the kFinchTrialName
-// finch trial; if you aren't, use the default string and don't invoke this.
-base::string16 AssembleMalwareFinchString(
- const std::string& trial_condition,
- const base::string16& elided_filename);
-
-#endif // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_FIELD_TRIAL_H_
diff --git a/chrome/browser/download/download_field_trial_unittest.cc b/chrome/browser/download/download_field_trial_unittest.cc
deleted file mode 100644
index 314497b6e4..0000000000
--- a/chrome/browser/download/download_field_trial_unittest.cc
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/download/download_field_trial.h"
-
-#include "base/strings/utf_string_conversions.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-TEST(DownloadFieldTrialTest, FinchStrings) {
- const std::string malicious_condition("Condition3Malicious");
- EXPECT_EQ(ASCIIToUTF16("This file is malicious."),
- AssembleMalwareFinchString(malicious_condition, base::string16()));
- EXPECT_EQ(ASCIIToUTF16("File 'malware.exe' is malicious."),
- AssembleMalwareFinchString(malicious_condition,
- ASCIIToUTF16("malware.exe")));
-}
diff --git a/chrome/browser/download/download_item_model.cc b/chrome/browser/download/download_item_model.cc
index d7983808ac..0823a40df3 100644
--- a/chrome/browser/download/download_item_model.cc
+++ b/chrome/browser/download/download_item_model.cc
@@ -13,7 +13,6 @@
#include "base/supports_user_data.h"
#include "base/time/time.h"
#include "chrome/browser/download/download_crx_util.h"
-#include "chrome/browser/download/download_field_trial.h"
#include "chrome/browser/safe_browsing/download_feedback_service.h"
#include "content/public/browser/download_danger_type.h"
#include "content/public/browser/download_interrupt_reasons.h"
@@ -346,11 +345,7 @@ string16 DownloadItemModel::GetWarningText(const gfx::FontList& font_list,
base_width);
switch (download_->GetDangerType()) {
case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: {
- std::string trial_condition =
- base::FieldTrialList::FindFullName(kMalwareWarningFinchTrialName);
- if (trial_condition.empty())
- return l10n_util::GetStringUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_URL);
- return AssembleMalwareFinchString(trial_condition, elided_filename);
+ return l10n_util::GetStringUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_URL);
}
case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE: {
if (download_crx_util::IsExtensionDownload(*download_)) {
@@ -363,13 +358,8 @@ string16 DownloadItemModel::GetWarningText(const gfx::FontList& font_list,
}
case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: {
- std::string trial_condition =
- base::FieldTrialList::FindFullName(kMalwareWarningFinchTrialName);
- if (trial_condition.empty()) {
- return l10n_util::GetStringFUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_CONTENT,
- elided_filename);
- }
- return AssembleMalwareFinchString(trial_condition, elided_filename);
+ return l10n_util::GetStringFUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_CONTENT,
+ elided_filename);
}
case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: {
return l10n_util::GetStringFUTF16(IDS_PROMPT_UNCOMMON_DOWNLOAD_CONTENT,
@@ -422,7 +412,7 @@ bool DownloadItemModel::IsDangerous() const {
return download_->IsDangerous();
}
-bool DownloadItemModel::IsMalicious() const {
+bool DownloadItemModel::MightBeMalicious() const {
if (!IsDangerous())
return false;
switch (download_->GetDangerType()) {
@@ -447,6 +437,33 @@ bool DownloadItemModel::IsMalicious() const {
return false;
}
+// If you change this definition of malicious, also update
+// DownloadManagerImpl::NonMaliciousInProgressCount.
+bool DownloadItemModel::IsMalicious() const {
+ if (!MightBeMalicious())
+ return false;
+ switch (download_->GetDangerType()) {
+ case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
+ case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
+ case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST:
+ return true;
+
+ case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS:
+ case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT:
+ case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED:
+ case content::DOWNLOAD_DANGER_TYPE_MAX:
+ case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE:
+ // We shouldn't get any of these due to the MightBeMalicious() test above.
+ NOTREACHED();
+ // Fallthrough.
+ case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT:
+ case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED:
+ return false;
+ }
+ NOTREACHED();
+ return false;
+}
+
bool DownloadItemModel::ShouldAllowDownloadFeedback() const {
if (!IsDangerous())
return false;
diff --git a/chrome/browser/download/download_item_model.h b/chrome/browser/download/download_item_model.h
index 62e937cab3..5a2c141ac5 100644
--- a/chrome/browser/download/download_item_model.h
+++ b/chrome/browser/download/download_item_model.h
@@ -81,6 +81,10 @@ class DownloadItemModel {
bool IsDangerous() const;
// Is this considered a malicious download? Implies IsDangerous().
+ bool MightBeMalicious() const;
+
+ // Is this considered a malicious download with very high confidence?
+ // Implies IsDangerous() and MightBeMalicious().
bool IsMalicious() const;
// Is safe browsing download feedback feature available for this download?
diff --git a/chrome/browser/download/download_service.cc b/chrome/browser/download/download_service.cc
index bb75459fb5..d5f1f420e0 100644
--- a/chrome/browser/download/download_service.cc
+++ b/chrome/browser/download/download_service.cc
@@ -88,24 +88,26 @@ bool DownloadService::HasCreatedDownloadManager() {
return download_manager_created_;
}
-int DownloadService::DownloadCount() const {
+int DownloadService::NonMaliciousDownloadCount() const {
if (!download_manager_created_)
return 0;
- return BrowserContext::GetDownloadManager(profile_)->InProgressCount();
+ return BrowserContext::GetDownloadManager(profile_)->
+ NonMaliciousInProgressCount();
}
// static
-int DownloadService::DownloadCountAllProfiles() {
+int DownloadService::NonMaliciousDownloadCountAllProfiles() {
std::vector<Profile*> profiles(
g_browser_process->profile_manager()->GetLoadedProfiles());
int count = 0;
for (std::vector<Profile*>::iterator it = profiles.begin();
it < profiles.end(); ++it) {
- count += DownloadServiceFactory::GetForBrowserContext(*it)->DownloadCount();
+ count += DownloadServiceFactory::GetForBrowserContext(*it)->
+ NonMaliciousDownloadCount();
if ((*it)->HasOffTheRecordProfile())
count += DownloadServiceFactory::GetForBrowserContext(
- (*it)->GetOffTheRecordProfile())->DownloadCount();
+ (*it)->GetOffTheRecordProfile())->NonMaliciousDownloadCount();
}
return count;
diff --git a/chrome/browser/download/download_service.h b/chrome/browser/download/download_service.h
index 3c3f6b6675..80cce15467 100644
--- a/chrome/browser/download/download_service.h
+++ b/chrome/browser/download/download_service.h
@@ -44,11 +44,12 @@ class DownloadService : public BrowserContextKeyedService {
// Has a download manager been created?
bool HasCreatedDownloadManager();
- // Number of downloads associated with this instance of the service.
- int DownloadCount() const;
+ // Number of non-malicious downloads associated with this instance of the
+ // service.
+ int NonMaliciousDownloadCount() const;
- // Number of downloads associated with all profiles.
- static int DownloadCountAllProfiles();
+ // Number of non-malicious downloads associated with all profiles.
+ static int NonMaliciousDownloadCountAllProfiles();
// Sets the DownloadManagerDelegate associated with this object and
// its DownloadManager. Takes ownership of |delegate|, and destroys
diff --git a/chrome/browser/download/download_shelf_context_menu.cc b/chrome/browser/download/download_shelf_context_menu.cc
index 76de09f827..9bd9d6ba8f 100644
--- a/chrome/browser/download/download_shelf_context_menu.cc
+++ b/chrome/browser/download/download_shelf_context_menu.cc
@@ -55,10 +55,12 @@ ui::SimpleMenuModel* DownloadShelfContextMenu::GetMenuModel() {
DownloadItemModel download_model(download_item_);
// We shouldn't be opening a context menu for a dangerous download, unless it
// is a malicious download.
- DCHECK(!download_model.IsDangerous() || download_model.IsMalicious());
+ DCHECK(!download_model.IsDangerous() || download_model.MightBeMalicious());
if (download_model.IsMalicious())
model = GetMaliciousMenuModel();
+ else if (download_model.MightBeMalicious())
+ model = GetMaybeMaliciousMenuModel();
else if (download_item_->GetState() == DownloadItem::COMPLETE)
model = GetFinishedMenuModel();
else if (download_item_->GetState() == DownloadItem::INTERRUPTED)
@@ -307,17 +309,39 @@ ui::SimpleMenuModel* DownloadShelfContextMenu::GetInterruptedMenuModel() {
return interrupted_download_menu_model_.get();
}
-ui::SimpleMenuModel* DownloadShelfContextMenu::GetMaliciousMenuModel() {
+ui::SimpleMenuModel* DownloadShelfContextMenu::GetMaybeMaliciousMenuModel() {
+ if (maybe_malicious_download_menu_model_)
+ return maybe_malicious_download_menu_model_.get();
+
+ maybe_malicious_download_menu_model_.reset(new ui::SimpleMenuModel(this));
+
+ maybe_malicious_download_menu_model_->AddItemWithStringId(
+ DISCARD, IDS_DOWNLOAD_MENU_DISCARD);
+ maybe_malicious_download_menu_model_->AddItemWithStringId(
+ KEEP, IDS_DOWNLOAD_MENU_KEEP);
+ maybe_malicious_download_menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
+ maybe_malicious_download_menu_model_->AddItemWithStringId(
+ LEARN_MORE_SCANNING, IDS_DOWNLOAD_MENU_LEARN_MORE_SCANNING);
+ LOG(INFO) << "GetMaybeMaliciousMenuModel";
+ return maybe_malicious_download_menu_model_.get();
+}
+
+ui::SimpleMenuModel*
+DownloadShelfContextMenu::GetMaliciousMenuModel() {
if (malicious_download_menu_model_)
return malicious_download_menu_model_.get();
malicious_download_menu_model_.reset(new ui::SimpleMenuModel(this));
- malicious_download_menu_model_->AddItemWithStringId(
- DISCARD, IDS_DOWNLOAD_MENU_DISCARD);
- malicious_download_menu_model_->AddItemWithStringId(
- KEEP, IDS_DOWNLOAD_MENU_KEEP);
- malicious_download_menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
+ // If the primary action is "record & discard", this also puts a plain
+ // "discard" option in the dropdown. Otherwise this dropdown doesn't need it
+ // because there is no alternative besides "learn more".
+ DownloadItemModel download_model(download_item_);
+ if (download_model.ShouldAllowDownloadFeedback()) {
+ maybe_malicious_download_menu_model_->AddItemWithStringId(
+ DISCARD, IDS_DOWNLOAD_MENU_DISCARD);
+ }
+ LOG(INFO) << "GetMaliciousMenuModel";
malicious_download_menu_model_->AddItemWithStringId(
LEARN_MORE_SCANNING, IDS_DOWNLOAD_MENU_LEARN_MORE_SCANNING);
diff --git a/chrome/browser/download/download_shelf_context_menu.h b/chrome/browser/download/download_shelf_context_menu.h
index b495c25e8e..345aaaf20b 100644
--- a/chrome/browser/download/download_shelf_context_menu.h
+++ b/chrome/browser/download/download_shelf_context_menu.h
@@ -69,6 +69,7 @@ class DownloadShelfContextMenu : public ui::SimpleMenuModel::Delegate,
ui::SimpleMenuModel* GetInProgressMenuModel();
ui::SimpleMenuModel* GetFinishedMenuModel();
ui::SimpleMenuModel* GetInterruptedMenuModel();
+ ui::SimpleMenuModel* GetMaybeMaliciousMenuModel();
ui::SimpleMenuModel* GetMaliciousMenuModel();
// We show slightly different menus if the download is in progress vs. if the
@@ -76,6 +77,7 @@ class DownloadShelfContextMenu : public ui::SimpleMenuModel::Delegate,
scoped_ptr<ui::SimpleMenuModel> in_progress_download_menu_model_;
scoped_ptr<ui::SimpleMenuModel> finished_download_menu_model_;
scoped_ptr<ui::SimpleMenuModel> interrupted_download_menu_model_;
+ scoped_ptr<ui::SimpleMenuModel> maybe_malicious_download_menu_model_;
scoped_ptr<ui::SimpleMenuModel> malicious_download_menu_model_;
// Information source.
diff --git a/chrome/browser/drive/drive_api_service.cc b/chrome/browser/drive/drive_api_service.cc
index 31a873ec02..ccd60f5b9a 100644
--- a/chrome/browser/drive/drive_api_service.cc
+++ b/chrome/browser/drive/drive_api_service.cc
@@ -84,11 +84,16 @@ const char kDriveAppsReadonlyScope[] =
// Mime type to create a directory.
const char kFolderMimeType[] = "application/vnd.google-apps.folder";
-// Expected max number of files resources in a http request.
-// Be careful not to use something too small because it might overload the
-// server. Be careful not to use something too large because it takes longer
-// time to fetch the result without UI response.
-const int kMaxNumFilesResourcePerRequest = 500;
+// Max number of file entries to be fetched in a single http request.
+//
+// The larger the number is,
+// - The total running time to fetch the whole file list will become shorter.
+// - The running time for a single request tends to become longer.
+// Since the file list fetching is a completely background task, for our side,
+// only the total time matters. However, the server seems to have a time limit
+// per single request, which disables us to set the largest value (1000).
+// TODO(kinaba): make it larger when the server gets faster.
+const int kMaxNumFilesResourcePerRequest = 250;
const int kMaxNumFilesResourcePerRequestForSearch = 50;
// For performance, we declare all fields we use.
diff --git a/chrome/browser/drive/drive_api_util.cc b/chrome/browser/drive/drive_api_util.cc
index bde7103ff9..c892aa05fb 100644
--- a/chrome/browser/drive/drive_api_util.cc
+++ b/chrome/browser/drive/drive_api_util.cc
@@ -33,6 +33,8 @@ const char kGooglePresentationMimeType[] =
const char kGoogleSpreadsheetMimeType[] =
"application/vnd.google-apps.spreadsheet";
const char kGoogleTableMimeType[] = "application/vnd.google-apps.table";
+const char kGoogleFormMimeType[] = "application/vnd.google-apps.form";
+const char kDriveFolderMimeType[] = "application/vnd.google-apps.folder";
ScopedVector<std::string> CopyScopedVectorString(
const ScopedVector<std::string>& source) {
@@ -120,6 +122,9 @@ ConvertInstalledAppToAppResource(
return resource.Pass();
}
+// Returns the argument string.
+std::string Identity(const std::string& resource_id) { return resource_id; }
+
} // namespace
@@ -231,6 +236,10 @@ std::string CanonicalizeResourceId(const std::string& resource_id) {
return resource_id;
}
+ResourceIdCanonicalizer GetIdentityResourceIdCanonicalizer() {
+ return base::Bind(&Identity);
+}
+
const char kDocsListScope[] = "https://docs.google.com/feeds/";
const char kDriveAppsScope[] = "https://www.googleapis.com/auth/drive.apps";
@@ -307,7 +316,10 @@ scoped_ptr<google_apis::FileResource> ConvertResourceEntryToFileResource(
}
file->set_download_url(entry.download_url());
- file->set_mime_type(entry.content_mime_type());
+ if (entry.is_folder())
+ file->set_mime_type(kDriveFolderMimeType);
+ else
+ file->set_mime_type(entry.content_mime_type());
file->set_md5_checksum(entry.file_md5());
file->set_file_size(entry.file_size());
@@ -378,6 +390,8 @@ google_apis::DriveEntryKind GetKind(
return google_apis::ENTRY_KIND_DRAWING;
if (mime_type == kGoogleTableMimeType)
return google_apis::ENTRY_KIND_TABLE;
+ if (mime_type == kGoogleFormMimeType)
+ return google_apis::ENTRY_KIND_FORM;
if (mime_type == "application/pdf")
return google_apis::ENTRY_KIND_PDF;
return google_apis::ENTRY_KIND_FILE;
diff --git a/chrome/browser/drive/drive_api_util.h b/chrome/browser/drive/drive_api_util.h
index 3bef862a73..fe741ee980 100644
--- a/chrome/browser/drive/drive_api_util.h
+++ b/chrome/browser/drive/drive_api_util.h
@@ -8,6 +8,7 @@
#include <string>
#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/drive/drive_service_interface.h"
#include "chrome/browser/google_apis/drive_common_callbacks.h"
#include "chrome/browser/google_apis/drive_entry_kinds.h"
#include "chrome/browser/google_apis/gdata_errorcode.h"
@@ -61,6 +62,9 @@ std::string ExtractResourceIdFromUrl(const GURL& url);
// into the new format.
std::string CanonicalizeResourceId(const std::string& resource_id);
+// Returns a ResourceIdCanonicalizer which returns the argument.
+ResourceIdCanonicalizer GetIdentityResourceIdCanonicalizer();
+
// Note: Following constants and a function are used to support GetShareUrl on
// Drive API v2. Unfortunately, there is no support on Drive API v2, so we need
// to fall back to GData WAPI for the GetShareUrl. Thus, these are shared by
diff --git a/chrome/browser/drive/drive_uploader.cc b/chrome/browser/drive/drive_uploader.cc
index 43d434f948..30ab0b9c1b 100644
--- a/chrome/browser/drive/drive_uploader.cc
+++ b/chrome/browser/drive/drive_uploader.cc
@@ -287,12 +287,8 @@ void DriveUploader::OnUploadLocationReceived(
<< "] for [" << upload_file_info->file_path.value() << "]";
if (code != HTTP_SUCCESS) {
- // TODO(achuith): Handle error codes from Google Docs server.
- if (code == HTTP_PRECONDITION) {
- // ETag mismatch.
- UploadFailed(upload_file_info.Pass(), HTTP_CONFLICT);
- return;
- }
+ if (code == HTTP_PRECONDITION)
+ code = HTTP_CONFLICT; // ETag mismatch.
UploadFailed(upload_file_info.Pass(), code);
return;
}
diff --git a/chrome/browser/drive/dummy_drive_service.cc b/chrome/browser/drive/dummy_drive_service.cc
index de84f86202..14afaecd02 100644
--- a/chrome/browser/drive/dummy_drive_service.cc
+++ b/chrome/browser/drive/dummy_drive_service.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/drive/dummy_drive_service.h"
#include "base/bind.h"
+#include "chrome/browser/drive/drive_api_util.h"
using google_apis::AboutResourceCallback;
using google_apis::AppListCallback;
@@ -23,13 +24,6 @@ using google_apis::UploadRangeCallback;
namespace drive {
-namespace {
-
-// Returns the argument string.
-std::string Identity(const std::string& resource_id) { return resource_id; }
-
-} // namespace
-
DummyDriveService::DummyDriveService() {}
DummyDriveService::~DummyDriveService() {}
@@ -43,7 +37,7 @@ void DummyDriveService::RemoveObserver(DriveServiceObserver* observer) {}
bool DummyDriveService::CanSendRequest() const { return true; }
ResourceIdCanonicalizer DummyDriveService::GetResourceIdCanonicalizer() const {
- return base::Bind(&Identity);
+ return util::GetIdentityResourceIdCanonicalizer();
}
bool DummyDriveService::HasAccessToken() const { return true; }
diff --git a/chrome/browser/drive/fake_drive_service.cc b/chrome/browser/drive/fake_drive_service.cc
index e6611efed9..352e517b2f 100644
--- a/chrome/browser/drive/fake_drive_service.cc
+++ b/chrome/browser/drive/fake_drive_service.cc
@@ -132,9 +132,6 @@ void EntryActionCallbackAdapter(
callback.Run(error);
}
-// Returns the argument string.
-std::string Identity(const std::string& resource_id) { return resource_id; }
-
} // namespace
struct FakeDriveService::UploadSession {
@@ -296,7 +293,7 @@ bool FakeDriveService::CanSendRequest() const {
}
ResourceIdCanonicalizer FakeDriveService::GetResourceIdCanonicalizer() const {
- return base::Bind(&Identity);
+ return util::GetIdentityResourceIdCanonicalizer();
}
bool FakeDriveService::HasAccessToken() const {
diff --git a/chrome/browser/drive/fake_drive_service_unittest.cc b/chrome/browser/drive/fake_drive_service_unittest.cc
index 453a914501..128fdf7f8b 100644
--- a/chrome/browser/drive/fake_drive_service_unittest.cc
+++ b/chrome/browser/drive/fake_drive_service_unittest.cc
@@ -104,10 +104,6 @@ class FakeDriveServiceTest : public testing::Test {
FakeDriveService fake_service_;
};
-void AppendProgressCallbackResult(std::vector<int64>* values, int64 progress) {
- values->push_back(progress);
-}
-
TEST_F(FakeDriveServiceTest, GetAllResourceList) {
ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
"gdata/root_feed.json"));
diff --git a/chrome/browser/drive/gdata_wapi_service.cc b/chrome/browser/drive/gdata_wapi_service.cc
index efe3bea999..963c6ae569 100644
--- a/chrome/browser/drive/gdata_wapi_service.cc
+++ b/chrome/browser/drive/gdata_wapi_service.cc
@@ -123,9 +123,6 @@ void ConvertAppListAndRun(
callback.Run(error, app_list.Pass());
}
-// Returns the argument string.
-std::string Identity(const std::string& resource_id) { return resource_id; }
-
} // namespace
GDataWapiService::GDataWapiService(
@@ -185,7 +182,7 @@ bool GDataWapiService::CanSendRequest() const {
}
ResourceIdCanonicalizer GDataWapiService::GetResourceIdCanonicalizer() const {
- return base::Bind(&Identity);
+ return util::GetIdentityResourceIdCanonicalizer();
}
std::string GDataWapiService::GetRootResourceId() const {
diff --git a/chrome/browser/errorpage_browsertest.cc b/chrome/browser/errorpage_browsertest.cc
index 020a0f1d43..15a1590863 100644
--- a/chrome/browser/errorpage_browsertest.cc
+++ b/chrome/browser/errorpage_browsertest.cc
@@ -129,6 +129,7 @@ class TestFailProvisionalLoadObserver : public content::WebContentsObserver {
// This method is invoked when the provisional load failed.
virtual void DidFailProvisionalLoad(
int64 frame_id,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& validated_url,
int error_code,
diff --git a/chrome/browser/extensions/active_tab_apitest.cc b/chrome/browser/extensions/active_tab_apitest.cc
index d6a6d1daa2..1ec7e32c05 100644
--- a/chrome/browser/extensions/active_tab_apitest.cc
+++ b/chrome/browser/extensions/active_tab_apitest.cc
@@ -43,7 +43,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_ActiveTab) {
// Granting to the extension should give it access to page.html.
{
ResultCatcher catcher;
- service->toolbar_model()->ExecuteBrowserAction(extension, browser(), NULL);
+ service->toolbar_model()->ExecuteBrowserAction(
+ extension, browser(), NULL, true);
EXPECT_TRUE(catcher.GetNextResult()) << message_;
}
diff --git a/chrome/browser/extensions/activity_log/activity_log.cc b/chrome/browser/extensions/activity_log/activity_log.cc
index c0fb023a83..1e8b34aeda 100644
--- a/chrome/browser/extensions/activity_log/activity_log.cc
+++ b/chrome/browser/extensions/activity_log/activity_log.cc
@@ -47,6 +47,10 @@ namespace {
using extensions::Action;
using constants::kArgUrlPlaceholder;
+// If DOM API methods start with this string, we flag them as being of type
+// DomActionType::XHR.
+const char kDomXhrPrefix[] = "XMLHttpRequest.";
+
// Specifies a possible action to take to get an extracted URL in the ApiInfo
// structure below.
enum Transformation {
@@ -532,6 +536,18 @@ void ActivityLog::LogAction(scoped_refptr<Action> action) {
// mask out incognito URLs if appropriate.
ExtractUrls(action, profile_);
+ // Mark DOM XHR requests as such, for easier processing later.
+ if (action->action_type() == Action::ACTION_DOM_ACCESS &&
+ StartsWithASCII(action->api_name(), kDomXhrPrefix, true) &&
+ action->other()) {
+ DictionaryValue* other = action->mutable_other();
+ int dom_verb = -1;
+ if (other->GetInteger(constants::kActionDomVerb, &dom_verb) &&
+ dom_verb == DomActionType::METHOD) {
+ other->SetInteger(constants::kActionDomVerb, DomActionType::XHR);
+ }
+ }
+
if (uma_policy_)
uma_policy_->ProcessAction(action);
if (IsDatabaseEnabled() && database_policy_)
diff --git a/chrome/browser/extensions/activity_log/activity_log_unittest.cc b/chrome/browser/extensions/activity_log/activity_log_unittest.cc
index 664c679939..bfb7748386 100644
--- a/chrome/browser/extensions/activity_log/activity_log_unittest.cc
+++ b/chrome/browser/extensions/activity_log/activity_log_unittest.cc
@@ -7,6 +7,7 @@
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/synchronization/waitable_event.h"
+#include "chrome/browser/extensions/activity_log/activity_action_constants.h"
#include "chrome/browser/extensions/activity_log/activity_log.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/test_extension_system.h"
@@ -110,12 +111,23 @@ class ActivityLogTest : public ChromeRenderViewHostTestHarness {
static void RetrieveActions_ArgUrlExtraction(
scoped_ptr<std::vector<scoped_refptr<Action> > > i) {
+ const DictionaryValue* other = NULL;
+ int dom_verb = -1;
+
ASSERT_EQ(4U, i->size());
scoped_refptr<Action> action = i->at(0);
ASSERT_EQ("XMLHttpRequest.open", action->api_name());
ASSERT_EQ("[\"POST\",\"\\u003Carg_url\\u003E\"]",
ActivityLogPolicy::Util::Serialize(action->args()));
ASSERT_EQ("http://api.google.com/", action->arg_url().spec());
+ // Test that the dom_verb field was changed to XHR (from METHOD). This
+ // could be tested on all retrieved XHR actions but it would be redundant,
+ // so just test once.
+ other = action->other();
+ ASSERT_TRUE(other);
+ ASSERT_TRUE(other->GetInteger(activity_log_constants::kActionDomVerb,
+ &dom_verb));
+ ASSERT_EQ(DomActionType::XHR, dom_verb);
action = i->at(1);
ASSERT_EQ("XMLHttpRequest.open", action->api_name());
@@ -241,6 +253,8 @@ TEST_F(ActivityLogTest, ArgUrlExtraction) {
action->set_page_url(GURL("http://www.google.com/"));
action->mutable_args()->AppendString("POST");
action->mutable_args()->AppendString("http://api.google.com/");
+ action->mutable_other()->SetInteger(activity_log_constants::kActionDomVerb,
+ DomActionType::METHOD);
activity_log->LogAction(action);
// Submit a DOM API call with a relative URL in the argument, which should be
@@ -252,6 +266,8 @@ TEST_F(ActivityLogTest, ArgUrlExtraction) {
action->set_page_url(GURL("http://www.google.com/"));
action->mutable_args()->AppendString("POST");
action->mutable_args()->AppendString("/api/");
+ action->mutable_other()->SetInteger(activity_log_constants::kActionDomVerb,
+ DomActionType::METHOD);
activity_log->LogAction(action);
// Submit a DOM API call with a relative URL but no base page URL against
@@ -262,6 +278,8 @@ TEST_F(ActivityLogTest, ArgUrlExtraction) {
"XMLHttpRequest.open");
action->mutable_args()->AppendString("POST");
action->mutable_args()->AppendString("/api/");
+ action->mutable_other()->SetInteger(activity_log_constants::kActionDomVerb,
+ DomActionType::METHOD);
activity_log->LogAction(action);
// Submit an API call with an embedded URL.
diff --git a/chrome/browser/extensions/api/api_resource.cc b/chrome/browser/extensions/api/api_resource.cc
index ccbdd77e7f..c8ddd4025a 100644
--- a/chrome/browser/extensions/api/api_resource.cc
+++ b/chrome/browser/extensions/api/api_resource.cc
@@ -15,7 +15,7 @@ ApiResource::ApiResource(const std::string& owner_extension_id)
ApiResource::~ApiResource() {
}
-bool ApiResource::persistent() const {
+bool ApiResource::IsPersistent() const {
return true; // backward-compatible behavior.
}
diff --git a/chrome/browser/extensions/api/api_resource.h b/chrome/browser/extensions/api/api_resource.h
index cc4e3ff626..2911cf3e12 100644
--- a/chrome/browser/extensions/api/api_resource.h
+++ b/chrome/browser/extensions/api/api_resource.h
@@ -23,7 +23,9 @@ class ApiResource {
return owner_extension_id_;
}
- virtual bool persistent() const;
+ // If this method returns |true|, the resource remains open when the
+ // owning extension is suspended due to inactivity.
+ virtual bool IsPersistent() const;
static const content::BrowserThread::ID kThreadId =
content::BrowserThread::IO;
diff --git a/chrome/browser/extensions/api/api_resource_manager.h b/chrome/browser/extensions/api/api_resource_manager.h
index d39c41b35a..fab663af64 100644
--- a/chrome/browser/extensions/api/api_resource_manager.h
+++ b/chrome/browser/extensions/api/api_resource_manager.h
@@ -24,6 +24,7 @@
namespace extensions {
namespace api {
+class TCPServerSocketEventDispatcher;
class TCPSocketEventDispatcher;
class UDPSocketEventDispatcher;
}
@@ -153,6 +154,7 @@ class ApiResourceManager : public ProfileKeyedAPI,
}
private:
+ friend class api::TCPServerSocketEventDispatcher;
friend class api::TCPSocketEventDispatcher;
friend class api::UDPSocketEventDispatcher;
friend class ProfileKeyedAPIFactory<ApiResourceManager<T> >;
@@ -286,7 +288,7 @@ class ApiResourceManager : public ProfileKeyedAPI,
} else {
linked_ptr<T> ptr = api_resource_map_[*it];
T* resource = ptr.get();
- erase = (resource && !resource->persistent());
+ erase = (resource && !resource->IsPersistent());
}
if (erase) {
diff --git a/chrome/browser/extensions/api/cast_channel/cast_channel_api.cc b/chrome/browser/extensions/api/cast_channel/cast_channel_api.cc
index 4f216c9dfe..8a5db589a2 100644
--- a/chrome/browser/extensions/api/cast_channel/cast_channel_api.cc
+++ b/chrome/browser/extensions/api/cast_channel/cast_channel_api.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/extensions/api/cast_channel/cast_channel_api.h"
+#include "base/json/json_writer.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/api/cast_channel/cast_socket.h"
@@ -30,11 +31,20 @@ using cast_channel::ReadyState;
using content::BrowserThread;
namespace {
-const long kUnknownChannelId = -1;
+
+// T is an extension dictionary (MessageInfo or ChannelInfo)
+template <class T>
+std::string ParamToString(const T& info) {
+ scoped_ptr<base::DictionaryValue> dict = info.ToValue();
+ std::string out;
+ base::JSONWriter::Write(dict.get(), &out);
+ return out;
+}
+
} // namespace
CastChannelAPI::CastChannelAPI(Profile* profile)
- : profile_(profile) {
+ : profile_(profile) {
DCHECK(profile_);
}
@@ -75,6 +85,8 @@ void CastChannelAPI::OnMessage(const CastSocket* socket,
socket->FillChannelInfo(&channel_info);
scoped_ptr<base::ListValue> results =
OnMessage::Create(channel_info, message_info);
+ DVLOG(1) << "Sending message " << ParamToString(message_info)
+ << " to channel " << ParamToString(channel_info);
scoped_ptr<Event> event(new Event(OnMessage::kEventName, results.Pass()));
extensions::ExtensionSystem::Get(profile_)->event_router()->
DispatchEventToExtension(socket->owner_extension_id(), event.Pass());
@@ -83,8 +95,7 @@ void CastChannelAPI::OnMessage(const CastSocket* socket,
CastChannelAPI::~CastChannelAPI() {}
CastChannelAsyncApiFunction::CastChannelAsyncApiFunction()
- : socket_(NULL), channel_id_(kUnknownChannelId), manager_(NULL),
- error_(cast_channel::CHANNEL_ERROR_NONE) { }
+ : manager_(NULL), error_(cast_channel::CHANNEL_ERROR_NONE) { }
CastChannelAsyncApiFunction::~CastChannelAsyncApiFunction() { }
@@ -97,64 +108,62 @@ bool CastChannelAsyncApiFunction::Respond() {
return error_ != cast_channel::CHANNEL_ERROR_NONE;
}
-ApiResourceManager<api::cast_channel::CastSocket>*
-CastChannelAsyncApiFunction::GetSocketManager() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- return manager_;
-}
-
-CastSocket* CastChannelAsyncApiFunction::GetSocket(long channel_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DCHECK(!socket_);
- DCHECK_EQ(channel_id_, kUnknownChannelId);
- CastSocket* socket = GetSocketManager()->Get(extension_->id(), channel_id);
- if (socket) {
- socket_ = socket;
- channel_id_ = channel_id;
+CastSocket* CastChannelAsyncApiFunction::GetSocketOrCompleteWithError(
+ int channel_id) {
+ CastSocket* socket = GetSocket(channel_id);
+ if (!socket) {
+ SetResultFromError(cast_channel::CHANNEL_ERROR_INVALID_CHANNEL_ID);
+ AsyncWorkCompleted();
}
return socket;
}
-void CastChannelAsyncApiFunction::RemoveSocketIfError() {
- if (error_ != cast_channel::CHANNEL_ERROR_NONE)
- RemoveSocket();
-}
-
-void CastChannelAsyncApiFunction::RemoveSocket() {
+int CastChannelAsyncApiFunction::AddSocket(CastSocket* socket) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DCHECK(socket_);
- DCHECK(channel_id_ != kUnknownChannelId);
- GetSocketManager()->Remove(extension_->id(), channel_id_);
- channel_id_ = kUnknownChannelId;
- socket_ = NULL;
+ DCHECK(socket);
+ DCHECK(manager_);
+ return manager_->Add(socket);
}
-void CastChannelAsyncApiFunction::SetResultFromChannelInfo(
- const ChannelInfo& channel_info) {
+void CastChannelAsyncApiFunction::RemoveSocket(int channel_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- SetResult(channel_info.ToValue().release());
+ DCHECK(manager_);
+ manager_->Remove(extension_->id(), channel_id);
}
-void CastChannelAsyncApiFunction::SetResultFromSocket() {
- DCHECK(socket_);
+void CastChannelAsyncApiFunction::SetResultFromSocket(int channel_id) {
+ CastSocket* socket = GetSocket(channel_id);
+ DCHECK(socket);
ChannelInfo channel_info;
- socket_->FillChannelInfo(&channel_info);
- error_ = socket_->error_state();
+ socket->FillChannelInfo(&channel_info);
+ error_ = socket->error_state();
SetResultFromChannelInfo(channel_info);
}
-void CastChannelAsyncApiFunction::SetResultFromError(
- const std::string& url, ChannelError error) {
+void CastChannelAsyncApiFunction::SetResultFromError(ChannelError error) {
ChannelInfo channel_info;
- channel_info.channel_id = channel_id_;
- channel_info.url = url;
+ channel_info.channel_id = -1;
+ channel_info.url = "";
channel_info.ready_state = cast_channel::READY_STATE_CLOSED;
channel_info.error_state = error;
SetResultFromChannelInfo(channel_info);
error_ = error;
}
-CastChannelOpenFunction::CastChannelOpenFunction() { }
+CastSocket* CastChannelAsyncApiFunction::GetSocket(int channel_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK(manager_);
+ return manager_->Get(extension_->id(), channel_id);
+}
+
+void CastChannelAsyncApiFunction::SetResultFromChannelInfo(
+ const ChannelInfo& channel_info) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ SetResult(channel_info.ToValue().release());
+}
+
+CastChannelOpenFunction::CastChannelOpenFunction()
+ : new_channel_id_(0) { }
CastChannelOpenFunction::~CastChannelOpenFunction() { }
@@ -171,21 +180,16 @@ bool CastChannelOpenFunction::Prepare() {
void CastChannelOpenFunction::AsyncWorkStart() {
DCHECK(api_);
- socket_ = new CastSocket(extension_->id(), GURL(params_->url),
- api_, g_browser_process->net_log());
- socket_->Connect(base::Bind(&CastChannelOpenFunction::OnOpen, this));
+ CastSocket* socket = new CastSocket(extension_->id(), GURL(params_->url),
+ api_, g_browser_process->net_log());
+ int new_channel_id = AddSocket(socket);
+ socket->set_id(new_channel_id);
+ socket->Connect(base::Bind(&CastChannelOpenFunction::OnOpen, this));
}
void CastChannelOpenFunction::OnOpen(int result) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- if (result == net::OK) {
- socket_->set_id(GetSocketManager()->Add(socket_));
- SetResultFromSocket();
- } else {
- SetResultFromError(params_->url,
- cast_channel::CHANNEL_ERROR_CONNECT_ERROR);
- }
- RemoveSocketIfError();
+ SetResultFromSocket(new_channel_id_);
AsyncWorkCompleted();
}
@@ -200,25 +204,20 @@ bool CastChannelSendFunction::Prepare() {
}
void CastChannelSendFunction::AsyncWorkStart() {
- if (!GetSocket(params_->channel.channel_id)) {
- SetResultFromError("",
- cast_channel::CHANNEL_ERROR_INVALID_CHANNEL_ID);
- AsyncWorkCompleted();
- return;
- }
- socket_->SendMessage(params_->message,
- base::Bind(&CastChannelSendFunction::OnSend, this));
+ CastSocket* socket = GetSocketOrCompleteWithError(
+ params_->channel.channel_id);
+ if (socket)
+ socket->SendMessage(params_->message,
+ base::Bind(&CastChannelSendFunction::OnSend, this));
}
void CastChannelSendFunction::OnSend(int result) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (result < 0) {
- SetResultFromError("",
- cast_channel::CHANNEL_ERROR_SOCKET_ERROR);
+ SetResultFromError(cast_channel::CHANNEL_ERROR_SOCKET_ERROR);
} else {
- SetResultFromSocket();
+ SetResultFromSocket(params_->channel.channel_id);
}
- RemoveSocketIfError();
AsyncWorkCompleted();
}
@@ -233,23 +232,21 @@ bool CastChannelCloseFunction::Prepare() {
}
void CastChannelCloseFunction::AsyncWorkStart() {
- if (!GetSocket(params_->channel.channel_id)) {
- SetResultFromError("", cast_channel::CHANNEL_ERROR_INVALID_CHANNEL_ID);
- AsyncWorkCompleted();
- return;
- }
- socket_->Close(base::Bind(&CastChannelCloseFunction::OnClose, this));
+ CastSocket* socket = GetSocketOrCompleteWithError(
+ params_->channel.channel_id);
+ if (socket)
+ socket->Close(base::Bind(&CastChannelCloseFunction::OnClose, this));
}
void CastChannelCloseFunction::OnClose(int result) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
DVLOG(1) << "CastChannelCloseFunction::OnClose result = " << result;
if (result < 0) {
- SetResultFromError("", cast_channel::CHANNEL_ERROR_SOCKET_ERROR);
- RemoveSocketIfError();
+ SetResultFromError(cast_channel::CHANNEL_ERROR_SOCKET_ERROR);
} else {
- SetResultFromSocket();
- RemoveSocket();
+ int channel_id = params_->channel.channel_id;
+ SetResultFromSocket(channel_id);
+ RemoveSocket(channel_id);
}
AsyncWorkCompleted();
}
diff --git a/chrome/browser/extensions/api/cast_channel/cast_channel_api.h b/chrome/browser/extensions/api/cast_channel/cast_channel_api.h
index fe0b8878d6..5aea438d41 100644
--- a/chrome/browser/extensions/api/cast_channel/cast_channel_api.h
+++ b/chrome/browser/extensions/api/cast_channel/cast_channel_api.h
@@ -63,40 +63,38 @@ class CastChannelAsyncApiFunction : public AsyncApiFunction {
virtual bool PrePrepare() OVERRIDE;
virtual bool Respond() OVERRIDE;
- ApiResourceManager<cast_channel::CastSocket>*
- GetSocketManager();
+ // Returns the socket corresponding to |channel_id| if one exists. Otherwise,
+ // sets the function result with CHANNEL_ERROR_INVALID_CHANNEL_ID, completes
+ // the function, and returns null.
+ cast_channel::CastSocket* GetSocketOrCompleteWithError(int channel_id);
- // Returns the socket corresponding to |channel_id| if one exists. If found,
- // sets |socket_| and |channel_id_|.
- cast_channel::CastSocket* GetSocket(long channel_id);
+ // Adds |socket| to |manager_| and returns the new channel_id. |manager_|
+ // assumes ownership of |socket|.
+ int AddSocket(cast_channel::CastSocket* socket);
- // Sets the ChannelInfo result from the state of the CastSocket used by the
- // function.
- void SetResultFromSocket();
+ // Removes the CastSocket corresponding to |channel_id| from the resource
+ // manager.
+ void RemoveSocket(int channel_id);
- // Sets the ChannelInfo result from |url| and |error|, when there is no
- // CastSocket associated with the function.
- void SetResultFromError(const std::string& url,
- cast_channel::ChannelError error);
+ // Sets the function result to a ChannelInfo obtained from the state of the
+ // CastSocket corresponding to |channel_id|.
+ void SetResultFromSocket(int channel_id);
- // Destroys the CastSocket used by the function.
- void RemoveSocket();
-
- // Destroys the CastSocket used by the function, but only when an error
- // has occurred..
- void RemoveSocketIfError();
-
- // The socket being used by the function. Set lazily.
- cast_channel::CastSocket* socket_;
-
- // The id of the socket being used by the function. Set lazily.
- long channel_id_;
+ // Sets the function result to a ChannelInfo with |error|.
+ void SetResultFromError(cast_channel::ChannelError error);
private:
+ // Returns the socket corresponding to |channel_id| if one exists, or null
+ // otherwise.
+ cast_channel::CastSocket* GetSocket(int channel_id);
+
+ // Sets the function result from |channel_info|.
void SetResultFromChannelInfo(
const cast_channel::ChannelInfo& channel_info);
+ // The API resource manager for CastSockets.
ApiResourceManager<cast_channel::CastSocket>* manager_;
+
// The result of the function.
cast_channel::ChannelError error_;
};
@@ -119,7 +117,8 @@ class CastChannelOpenFunction : public CastChannelAsyncApiFunction {
void OnOpen(int result);
scoped_ptr<cast_channel::Open::Params> params_;
- // Ptr to the API object.
+ // The id of the newly opened socket.
+ int new_channel_id_;
CastChannelAPI* api_;
DISALLOW_COPY_AND_ASSIGN(CastChannelOpenFunction);
diff --git a/chrome/browser/extensions/api/cast_channel/cast_socket.cc b/chrome/browser/extensions/api/cast_channel/cast_socket.cc
index a4e7b18fb7..e384587d4f 100644
--- a/chrome/browser/extensions/api/cast_channel/cast_socket.cc
+++ b/chrome/browser/extensions/api/cast_channel/cast_socket.cc
@@ -7,15 +7,26 @@
#include <string.h>
#include "base/bind.h"
+#include "base/callback_helpers.h"
#include "base/lazy_instance.h"
#include "base/strings/string_number_conversions.h"
#include "base/sys_byteorder.h"
#include "chrome/browser/extensions/api/cast_channel/cast_channel.pb.h"
#include "chrome/browser/extensions/api/cast_channel/cast_message_util.h"
#include "net/base/address_list.h"
+#include "net/base/host_port_pair.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
+#include "net/cert/cert_verifier.h"
+#include "net/cert/x509_certificate.h"
+#include "net/http/transport_security_state.h"
+#include "net/socket/client_socket_factory.h"
+#include "net/socket/client_socket_handle.h"
+#include "net/socket/ssl_client_socket.h"
+#include "net/socket/stream_socket.h"
#include "net/socket/tcp_client_socket.h"
+#include "net/ssl/ssl_config_service.h"
+#include "net/ssl/ssl_info.h"
namespace {
@@ -56,10 +67,18 @@ const uint32 kMaxMessageSize = 65536;
CastSocket::CastSocket(const std::string& owner_extension_id,
const GURL& url, CastSocket::Delegate* delegate,
net::NetLog* net_log) :
- ApiResource(owner_extension_id), channel_id_(0), url_(url),
- delegate_(delegate), error_state_(CHANNEL_ERROR_NONE),
- ready_state_(READY_STATE_NONE), write_callback_pending_(false),
- read_callback_pending_(false), current_message_size_(0), net_log_(net_log) {
+ ApiResource(owner_extension_id),
+ channel_id_(0),
+ url_(url),
+ delegate_(delegate),
+ is_secure_(false),
+ error_state_(CHANNEL_ERROR_NONE),
+ ready_state_(READY_STATE_NONE),
+ write_callback_pending_(false),
+ read_callback_pending_(false),
+ current_message_size_(0),
+ net_log_(net_log),
+ next_state_(CONN_STATE_NONE) {
DCHECK(net_log_);
net_log_source_.type = net::NetLog::SOURCE_SOCKET;
net_log_source_.id = net_log_->NextID();
@@ -78,12 +97,59 @@ const GURL& CastSocket::url() const {
return url_;
}
-net::TCPClientSocket* CastSocket::CreateSocket(
- const net::AddressList& addresses,
- net::NetLog* net_log,
- const net::NetLog::Source& source) {
- // TODO(mfoltz,munjal): Create a TLS socket.
- return new net::TCPClientSocket(addresses, net_log, source);
+bool CastSocket::ExtractPeerCert(std::string* cert) {
+ CHECK(peer_cert_.empty());
+ net::SSLInfo ssl_info;
+ if (!socket_->GetSSLInfo(&ssl_info) || !ssl_info.cert.get())
+ return false;
+ bool result = net::X509Certificate::GetDEREncoded(
+ ssl_info.cert->os_cert_handle(), cert);
+ if (result)
+ DVLOG(1) << "Successfully extracted peer certificate: " << *cert;
+ return result;
+}
+
+scoped_ptr<net::TCPClientSocket> CastSocket::CreateTcpSocket() {
+ net::AddressList addresses(ip_endpoint_);
+ scoped_ptr<net::TCPClientSocket> tcp_socket(
+ new net::TCPClientSocket(addresses, net_log_, net_log_source_));
+ // Enable keepalive
+ tcp_socket->SetKeepAlive(true, kTcpKeepAliveDelaySecs);
+ return tcp_socket.Pass();
+}
+
+scoped_ptr<net::SSLClientSocket> CastSocket::CreateSslSocket() {
+ net::SSLConfig ssl_config;
+ // If a peer cert was extracted in a previous attempt to connect, then
+ // whitelist that cert.
+ if (!peer_cert_.empty()) {
+ net::SSLConfig::CertAndStatus cert_and_status;
+ cert_and_status.cert_status = net::CERT_STATUS_AUTHORITY_INVALID;
+ cert_and_status.der_cert = peer_cert_;
+ ssl_config.allowed_bad_certs.push_back(cert_and_status);
+ }
+
+ cert_verifier_.reset(net::CertVerifier::CreateDefault());
+ transport_security_state_.reset(new net::TransportSecurityState);
+ net::SSLClientSocketContext context;
+ // CertVerifier and TransportSecurityState are owned by us, not the
+ // context object.
+ context.cert_verifier = cert_verifier_.get();
+ context.transport_security_state = transport_security_state_.get();
+
+ scoped_ptr<net::ClientSocketHandle> connection(new net::ClientSocketHandle);
+ connection->SetSocket(tcp_socket_.PassAs<net::StreamSocket>());
+ net::HostPortPair host_and_port = net::HostPortPair::FromIPEndPoint(
+ ip_endpoint_);
+
+ return net::ClientSocketFactory::GetDefaultFactory()->CreateSSLClientSocket(
+ connection.Pass(), host_and_port, ssl_config, context);
+}
+
+void CastSocket::OnConnectComplete(int result) {
+ int rv = DoConnectLoop(result);
+ if (rv != net::ERR_IO_PENDING)
+ DoConnectCallback(rv);
}
void CastSocket::Connect(const net::CompletionCallback& callback) {
@@ -100,34 +166,103 @@ void CastSocket::Connect(const net::CompletionCallback& callback) {
callback.Run(result);
return;
}
- ready_state_ = READY_STATE_CONNECTING;
- net::AddressList address_list(ip_endpoint_);
- socket_.reset(CreateSocket(address_list, net_log_, net_log_source_));
-
- // Enable TCP_NODELAY, as we want to minimize message latency.
- socket_->SetNoDelay(true);
- // Enable keepalive
- socket_->SetKeepAlive(true, kTcpKeepAliveDelaySecs);
connect_callback_ = callback;
- socket_->Connect(base::Bind(&CastSocket::OnConnectComplete,
- AsWeakPtr()));
+ next_state_ = CONN_STATE_TCP_CONNECT;
+ int rv = DoConnectLoop(net::OK);
+ if (rv != net::ERR_IO_PENDING)
+ DoConnectCallback(rv);
}
-void CastSocket::OnConnectComplete(int result) {
- DCHECK(CalledOnValidThread());
- DVLOG(1) << "OnConnectComplete result = " << result;
- ready_state_ = (result == net::OK) ?
- READY_STATE_OPEN : READY_STATE_CLOSED;
- connect_callback_.Run(result);
- connect_callback_.Reset();
+// This method performs the state machine transitions for connection flow.
+// There are two entry points to this method:
+// 1. public Connect method: this starts the flow
+// 2. OnConnectComplete: callback method called when an async operation
+// is done. OnConnectComplete calls this method to continue the state
+// machine transitions.
+int CastSocket::DoConnectLoop(int result) {
+ // Network operations can either finish sycnronously or asynchronously.
+ // This method executes the state machine transitions in a loop so that
+ // correct state transitions happen even when network operations finish
+ // synchronously.
+ int rv = result;
+ do {
+ ConnectionState state = next_state_;
+ // All the Do* methods do not set next_state_ in case of an
+ // error. So set next_state_ to NONE to figure out if the Do*
+ // method changed state or not.
+ next_state_ = CONN_STATE_NONE;
+ switch (state) {
+ case CONN_STATE_TCP_CONNECT:
+ rv = DoTcpConnect();
+ break;
+ case CONN_STATE_TCP_CONNECT_COMPLETE:
+ rv = DoTcpConnectComplete(rv);
+ break;
+ case CONN_STATE_SSL_CONNECT:
+ DCHECK_EQ(net::OK, rv);
+ rv = DoSslConnect();
+ break;
+ case CONN_STATE_SSL_CONNECT_COMPLETE:
+ rv = DoSslConnectComplete(rv);
+ break;
+ default:
+ NOTREACHED() << "BUG in CastSocket state machine code";
+ break;
+ }
+ } while (rv != net::ERR_IO_PENDING && next_state_ != CONN_STATE_NONE);
+ // Get out of the loop either when:
+ // a. A network operation is pending, OR
+ // b. The Do* method called did not change state
+
+ return rv;
+}
+
+int CastSocket::DoTcpConnect() {
+ next_state_ = CONN_STATE_TCP_CONNECT_COMPLETE;
+ tcp_socket_ = CreateTcpSocket();
+ return tcp_socket_->Connect(
+ base::Bind(&CastSocket::OnConnectComplete, AsWeakPtr()));
+}
+
+int CastSocket::DoTcpConnectComplete(int result) {
+ if (result == net::OK)
+ next_state_ = CONN_STATE_SSL_CONNECT;
+ return result;
+}
+
+int CastSocket::DoSslConnect() {
+ next_state_ = CONN_STATE_SSL_CONNECT_COMPLETE;
+ socket_ = CreateSslSocket();
+ return socket_->Connect(
+ base::Bind(&CastSocket::OnConnectComplete, AsWeakPtr()));
+}
+
+int CastSocket::DoSslConnectComplete(int result) {
// TODO(mfoltz,munjal): Authenticate the channel if is_secure_ == true.
- ReadData();
+ if (result == net::ERR_CERT_AUTHORITY_INVALID &&
+ peer_cert_.empty() &&
+ ExtractPeerCert(&peer_cert_)) {
+ next_state_ = CONN_STATE_TCP_CONNECT;
+ }
+ return result;
+}
+
+void CastSocket::DoConnectCallback(int result) {
+ ready_state_ = (result == net::OK) ? READY_STATE_OPEN : READY_STATE_CLOSED;
+ error_state_ = (result == net::OK) ?
+ CHANNEL_ERROR_NONE : CHANNEL_ERROR_CONNECT_ERROR;
+ base::ResetAndReturn(&connect_callback_).Run(result);
+ if (result == net::OK)
+ ReadData();
}
void CastSocket::Close(const net::CompletionCallback& callback) {
DCHECK(CalledOnValidThread());
DVLOG(1) << "Close ReadyState = " << ready_state_;
+ tcp_socket_.reset(NULL);
socket_.reset(NULL);
+ cert_verifier_.reset(NULL);
+ transport_security_state_.reset(NULL);
ready_state_ = READY_STATE_CLOSED;
callback.Run(net::OK);
}
@@ -135,7 +270,7 @@ void CastSocket::Close(const net::CompletionCallback& callback) {
void CastSocket::SendMessage(const MessageInfo& message,
const net::CompletionCallback& callback) {
DCHECK(CalledOnValidThread());
- DVLOG(1) << "Send::ReadyState " << ready_state_;
+ DVLOG(1) << "Send ReadyState " << ready_state_;
int result = net::ERR_FAILED;
if (ready_state_ != READY_STATE_OPEN) {
callback.Run(result);
diff --git a/chrome/browser/extensions/api/cast_channel/cast_socket.h b/chrome/browser/extensions/api/cast_channel/cast_socket.h
index c542fb9055..e9c5a82ccf 100644
--- a/chrome/browser/extensions/api/cast_channel/cast_socket.h
+++ b/chrome/browser/extensions/api/cast_channel/cast_socket.h
@@ -25,7 +25,10 @@
namespace net {
class AddressList;
+class CertVerifier;
+class SSLClientSocket;
class TCPClientSocket;
+class TransportSecurityState;
}
namespace extensions {
@@ -64,7 +67,8 @@ class CastSocket : public ApiResource,
// Creates a new CastSocket to |url|. |owner_extension_id| is the id of the
// extension that opened the socket.
CastSocket(const std::string& owner_extension_id,
- const GURL& url, CastSocket::Delegate* delegate,
+ const GURL& url,
+ CastSocket::Delegate* delegate,
net::NetLog* net_log);
virtual ~CastSocket();
@@ -104,10 +108,14 @@ class CastSocket : public ApiResource,
void FillChannelInfo(ChannelInfo* channel_info) const;
protected:
- // Factory method for sockets.
- virtual net::TCPClientSocket* CreateSocket(const net::AddressList& addresses,
- net::NetLog* net_log,
- const net::NetLog::Source& source);
+ // Creates an instance of TCPClientSocket.
+ virtual scoped_ptr<net::TCPClientSocket> CreateTcpSocket();
+ // Creates an instance of SSLClientSocket.
+ virtual scoped_ptr<net::SSLClientSocket> CreateSslSocket();
+ // Extracts peer certificate from SSLClientSocket instance when the socket
+ // is in cert error state.
+ // Returns whether certificate is successfully extracted.
+ virtual bool ExtractPeerCert(std::string* cert);
private:
friend class ApiResourceManager<CastSocket>;
@@ -115,13 +123,45 @@ class CastSocket : public ApiResource,
return "CastSocketManager";
}
+ // Internal connection states.
+ enum ConnectionState {
+ CONN_STATE_NONE,
+ CONN_STATE_TCP_CONNECT,
+ CONN_STATE_TCP_CONNECT_COMPLETE,
+ CONN_STATE_SSL_CONNECT,
+ CONN_STATE_SSL_CONNECT_COMPLETE,
+ };
+
+ /////////////////////////////////////////////////////////////////////////////
+ // Following methods work together to implement the following flow:
+ // 1. Create a new TCP socket and connect to it
+ // 2. Create a new SSL socket and try connecting to it
+ // 3. If connection fails due to invalid cert authority, then extract the
+ // peer certificate from the error.
+ // 4. Whitelist the peer certificate and try #1 and #2 again.
+
+ // Main method that performs connection state transitions.
+ int DoConnectLoop(int result);
+ // Each of the below Do* method is executed in the corresponding
+ // connection state. For e.g. when connection state is TCP_CONNECT
+ // DoTcpConnect is called, and so on.
+ int DoTcpConnect();
+ int DoTcpConnectComplete(int result);
+ int DoSslConnect();
+ int DoSslConnectComplete(int result);
+ int DoSslConnectRetry();
+ /////////////////////////////////////////////////////////////////////////////
+
+ // Callback method for callbacks from underlying sockets.
+ void OnConnectComplete(int result);
+
+ // Runs the external connection callback and resets it.
+ void DoConnectCallback(int result);
+
// Verifies that the URL is a valid cast:// or casts:// URL and sets url_ to
// the result.
bool ParseChannelUrl(const GURL& url);
- // Called when the socket is connected.
- void OnConnectComplete(int result);
-
// Writes data to the socket from the WriteRequest at the head of the queue.
// Calls OnWriteData() on completion.
void WriteData();
@@ -183,11 +223,17 @@ class CastSocket : public ApiResource,
// The NetLog source for this service.
net::NetLog::Source net_log_source_;
- // Owned ptr to the underlying socket.
- //
- // NOTE(mfoltz): We'll have to refactor this to allow substitution of an
- // SSLClientSocket, since the APIs are different.
- scoped_ptr<net::TCPClientSocket> socket_;
+ // Next connection state to transition to.
+ ConnectionState next_state_;
+ // Owned ptr to the underlying TCP socket.
+ scoped_ptr<net::TCPClientSocket> tcp_socket_;
+ // Owned ptr to the underlying SSL socket.
+ scoped_ptr<net::SSLClientSocket> socket_;
+ // Certificate of the peer. This field may be empty if the peer
+ // certificate is not yet fetched.
+ std::string peer_cert_;
+ scoped_ptr<net::CertVerifier> cert_verifier_;
+ scoped_ptr<net::TransportSecurityState> transport_security_state_;
// Callback invoked when the socket is connected.
net::CompletionCallback connect_callback_;
diff --git a/chrome/browser/extensions/api/cast_channel/cast_socket_unittest.cc b/chrome/browser/extensions/api/cast_channel/cast_socket_unittest.cc
index 45cf51c3b5..fdb94f0cc5 100644
--- a/chrome/browser/extensions/api/cast_channel/cast_socket_unittest.cc
+++ b/chrome/browser/extensions/api/cast_channel/cast_socket_unittest.cc
@@ -10,7 +10,11 @@
#include "net/base/capturing_net_log.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
+#include "net/base/net_log.h"
+#include "net/socket/socket_test_util.h"
+#include "net/socket/ssl_client_socket.h"
#include "net/socket/tcp_client_socket.h"
+#include "net/ssl/ssl_info.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -33,8 +37,8 @@ class MockCastSocketDelegate : public CastSocket::Delegate {
class MockTCPClientSocket : public net::TCPClientSocket {
public:
- explicit MockTCPClientSocket(const net::AddressList& addresses) :
- TCPClientSocket(addresses, NULL, net::NetLog::Source()) { }
+ explicit MockTCPClientSocket() :
+ TCPClientSocket(net::AddressList(), NULL, net::NetLog::Source()) { }
virtual ~MockTCPClientSocket() { }
MOCK_METHOD1(Connect, int(const net::CompletionCallback& callback));
@@ -47,6 +51,23 @@ class MockTCPClientSocket : public net::TCPClientSocket {
MOCK_METHOD0(Disconnect, void());
};
+class MockSSLClientSocket : public net::MockClientSocket {
+ public:
+ MockSSLClientSocket() : MockClientSocket(net::BoundNetLog()) { }
+ virtual ~MockSSLClientSocket() { }
+
+ MOCK_METHOD1(Connect, int(const net::CompletionCallback& callback));
+ MOCK_METHOD3(Read, int(net::IOBuffer* buf, int buf_len,
+ const net::CompletionCallback& callback));
+ MOCK_METHOD3(Write, int(net::IOBuffer* buf, int buf_len,
+ const net::CompletionCallback& callback));
+ MOCK_METHOD0(Disconnect, void());
+ MOCK_CONST_METHOD0(WasEverUsed, bool());
+ MOCK_CONST_METHOD0(UsingTCPFastOpen, bool());
+ MOCK_CONST_METHOD0(WasNpnNegotiated, bool());
+ MOCK_METHOD1(GetSSLInfo, bool(net::SSLInfo*));
+};
+
class CompleteHandler {
public:
CompleteHandler() {}
@@ -61,43 +82,72 @@ class TestCastSocket : public CastSocket {
public:
explicit TestCastSocket(MockCastSocketDelegate* delegate) :
CastSocket("abcdefg", GURL("cast://192.0.0.1:8009"), delegate,
- &capturing_net_log_), owns_socket_(true) {
- net::AddressList addresses;
- mock_tcp_socket_ = new MockTCPClientSocket(addresses);
+ &capturing_net_log_),
+ mock_tcp_socket_(new MockTCPClientSocket()),
+ mock_ssl_socket_(new MockSSLClientSocket()),
+ owns_tcp_socket_(true),
+ owns_ssl_socket_(true),
+ extract_cert_result_(true) {
}
virtual ~TestCastSocket() {
- if (owns_socket_) {
+ if (owns_tcp_socket_) {
DCHECK(mock_tcp_socket_);
delete mock_tcp_socket_;
}
+ if (owns_ssl_socket_) {
+ DCHECK(mock_ssl_socket_);
+ delete mock_ssl_socket_;
+ }
}
virtual void Close(const net::CompletionCallback& callback) OVERRIDE {
- if (!owns_socket_)
+ if (!owns_tcp_socket_)
mock_tcp_socket_ = NULL;
+ if (!owns_ssl_socket_)
+ mock_ssl_socket_ = NULL;
CastSocket::Close(callback);
}
- // Ptr to the mock socket. Ownership is transferred to CastSocket when it is
- // returned from CreateSocket(). CastSocket will destroy it on Close(),
- // so don't refer to |mock_tcp_socket_| afterwards.
+ void CreateNewSockets() {
+ owns_tcp_socket_ = true;
+ mock_tcp_socket_ = new MockTCPClientSocket();
+ owns_ssl_socket_ = true;
+ mock_ssl_socket_ = new MockSSLClientSocket();
+ }
+
+ void SetExtractCertResult(bool value) {
+ extract_cert_result_ = value;
+ }
+
MockTCPClientSocket* mock_tcp_socket_;
+ MockSSLClientSocket* mock_ssl_socket_;
protected:
- // Transfers ownership of |mock_tcp_socket_| to CastSocket.
- virtual net::TCPClientSocket* CreateSocket(
- const net::AddressList& addresses,
- net::NetLog* net_log,
- const net::NetLog::Source& source) OVERRIDE {
- owns_socket_ = false;
- return mock_tcp_socket_;
+ virtual scoped_ptr<net::TCPClientSocket> CreateTcpSocket() OVERRIDE {
+ owns_tcp_socket_ = false;
+ return scoped_ptr<net::TCPClientSocket>(mock_tcp_socket_);
+ }
+
+ virtual scoped_ptr<net::SSLClientSocket> CreateSslSocket() OVERRIDE {
+ owns_ssl_socket_ = false;
+ return scoped_ptr<net::SSLClientSocket>(mock_ssl_socket_);
+ }
+
+ virtual bool ExtractPeerCert(std::string* cert) OVERRIDE {
+ if (extract_cert_result_)
+ cert->assign("dummy_test_cert");
+ return extract_cert_result_;
}
private:
net::CapturingNetLog capturing_net_log_;
// Whether this object or the parent owns |mock_tcp_socket_|.
- bool owns_socket_;
+ bool owns_tcp_socket_;
+ // Whether this object or the parent owns |mock_ssl_socket_|.
+ bool owns_ssl_socket_;
+ // Simulated result of peer cert extraction.
+ bool extract_cert_result_;
};
class CastSocketTest : public testing::Test {
@@ -120,30 +170,51 @@ class CastSocketTest : public testing::Test {
base::Unretained(&handler_)));
}
- // Sets expectations when the socket is connected. Connecting the socket also
+ // Sets an expectation on the TCP socket Connect method. Connect method is
+ // setup to return net::ERR_IO_PENDING and store the callback passed to it
+ // in |callback|.
+ void ExpectTCPConnect(net::CompletionCallback* callback) {
+ EXPECT_CALL(mock_tcp_socket(), Connect(A<const net::CompletionCallback&>()))
+ .Times(1)
+ .WillOnce(DoAll(SaveArg<0>(callback), Return(net::ERR_IO_PENDING)));
+ }
+
+ // Sets an expectation on the SSL socket Connect method. Connect method is
+ // setup to return net::ERR_IO_PENDING and store the callback passed to it
+ // in |callback|.
+ void ExpectSSLConnect(net::CompletionCallback* callback) {
+ EXPECT_CALL(mock_ssl_socket(), Connect(A<const net::CompletionCallback&>()))
+ .Times(1)
+ .WillOnce(DoAll(SaveArg<0>(callback), Return(net::ERR_IO_PENDING)));
+ }
+
+ // Sets an expectation on the SSL socket Read method. Read method is setup
+ // to return net::ERR_IO_PENDING and to be called |times| number of times.
+ void ExpectSSLRead(int times) {
+ EXPECT_CALL(mock_ssl_socket(), Read(A<net::IOBuffer*>(),
+ A<int>(),
+ A<const net::CompletionCallback&>()))
+ .Times(times)
+ .WillOnce(Return(net::ERR_IO_PENDING));
+ }
+
+ // Sets expectations when the socket is connected. Connecting the socket also
// starts the read loop; we expect the call to Read(), but never fire the read
// callback.
void ConnectHelper() {
- net::CompletionCallback connect_callback;
- EXPECT_CALL(mock_tcp_socket(), SetNoDelay(true))
- .Times(1)
- .WillOnce(Return(true));
- EXPECT_CALL(mock_tcp_socket(), SetKeepAlive(true, A<int>()))
- .Times(1)
- .WillOnce(Return(true));
- EXPECT_CALL(mock_tcp_socket(), Connect(A<const net::CompletionCallback&>()))
- .Times(1)
- .WillOnce(DoAll(SaveArg<0>(&connect_callback), Return(net::OK)));
+ net::CompletionCallback connect_callback1;
+ net::CompletionCallback connect_callback2;
+
+ ExpectTCPConnect(&connect_callback1);
+ ExpectSSLConnect(&connect_callback2);
EXPECT_CALL(handler_, OnConnectComplete(net::OK));
- EXPECT_CALL(mock_tcp_socket(), Read(A<net::IOBuffer*>(),
- A<int>(),
- A<const net::CompletionCallback&>()))
- .Times(1)
- .WillOnce(Return(net::ERR_IO_PENDING));
+ ExpectSSLRead(1);
socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
base::Unretained(&handler_)));
- connect_callback.Run(net::OK);
+ connect_callback1.Run(net::OK);
+ connect_callback2.Run(net::OK);
+
EXPECT_EQ(cast_channel::READY_STATE_OPEN, socket_->ready_state());
EXPECT_EQ(cast_channel::CHANNEL_ERROR_NONE, socket_->error_state());
}
@@ -155,6 +226,12 @@ class CastSocketTest : public testing::Test {
return *mock_socket;
}
+ MockSSLClientSocket& mock_ssl_socket() {
+ MockSSLClientSocket* mock_socket = socket_->mock_ssl_socket_;
+ DCHECK(mock_socket);
+ return *mock_socket;
+ }
+
MockCastSocketDelegate mock_delegate_;
scoped_ptr<TestCastSocket> socket_;
CompleteHandler handler_;
@@ -198,12 +275,106 @@ TEST_F(CastSocketTest, TestConnectAndClose) {
EXPECT_EQ(cast_channel::CHANNEL_ERROR_NONE, socket_->error_state());
}
-// Tests writing a single message where the completion is signaled via callback.
+// Test that when first connection attempt fails with certificate authority
+// invalid error, a second connection attempt is made with peer cert
+// whitelisted.
+TEST_F(CastSocketTest, TestTwoStepConnect) {
+ // Expectations for the initial connect call
+ net::CompletionCallback tcp_connect_callback1;
+ net::CompletionCallback ssl_connect_callback1;
+
+ ExpectTCPConnect(&tcp_connect_callback1);
+ ExpectSSLConnect(&ssl_connect_callback1);
+
+ // Start connect flow
+ socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
+ base::Unretained(&handler_)));
+ tcp_connect_callback1.Run(net::OK);
+
+ // Expectations for the second connect call
+ socket_->CreateNewSockets();
+ net::CompletionCallback tcp_connect_callback2;
+ net::CompletionCallback ssl_connect_callback2;
+ ExpectTCPConnect(&tcp_connect_callback2);
+ ExpectSSLConnect(&ssl_connect_callback2);
+ EXPECT_CALL(handler_, OnConnectComplete(net::OK));
+ ExpectSSLRead(1);
+
+ // Trigger callbacks for the first connect
+ ssl_connect_callback1.Run(net::ERR_CERT_AUTHORITY_INVALID);
+
+ // Trigger callbacks for the second connect
+ tcp_connect_callback2.Run(net::OK);
+ ssl_connect_callback2.Run(net::OK);
+
+ EXPECT_EQ(cast_channel::READY_STATE_OPEN, socket_->ready_state());
+ EXPECT_EQ(cast_channel::CHANNEL_ERROR_NONE, socket_->error_state());
+}
+
+// Test that connection will be attempted a maximum of 2 times even if the
+// second attempt also returns certificate authority invalid error.
+TEST_F(CastSocketTest, TestMaxTwoConnectAttempts) {
+ net::CompletionCallback tcp_connect_callback1;
+ net::CompletionCallback ssl_connect_callback1;
+
+ // Expectations for the initial connect call
+ ExpectTCPConnect(&tcp_connect_callback1);
+ ExpectSSLConnect(&ssl_connect_callback1);
+
+ // Start connect flow
+ socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
+ base::Unretained(&handler_)));
+ tcp_connect_callback1.Run(net::OK);
+
+ socket_->CreateNewSockets();
+ net::CompletionCallback tcp_connect_callback2;
+ net::CompletionCallback ssl_connect_callback2;
+
+ // Expectations for the second connect call
+ ExpectTCPConnect(&tcp_connect_callback2);
+ ExpectSSLConnect(&ssl_connect_callback2);
+ EXPECT_CALL(handler_, OnConnectComplete(net::ERR_CERT_AUTHORITY_INVALID));
+
+ // Trigger callbacks for the first connect
+ ssl_connect_callback1.Run(net::ERR_CERT_AUTHORITY_INVALID);
+
+ // Trigger callbacks for the second connect
+ tcp_connect_callback2.Run(net::OK);
+ ssl_connect_callback2.Run(net::ERR_CERT_AUTHORITY_INVALID);
+
+ EXPECT_EQ(cast_channel::READY_STATE_CLOSED, socket_->ready_state());
+ EXPECT_EQ(cast_channel::CHANNEL_ERROR_CONNECT_ERROR, socket_->error_state());
+}
+
+TEST_F(CastSocketTest, TestCertExtractionFailure) {
+ net::CompletionCallback connect_callback1;
+ net::CompletionCallback connect_callback2;
+
+ ExpectTCPConnect(&connect_callback1);
+ ExpectSSLConnect(&connect_callback2);
+
+ socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
+ base::Unretained(&handler_)));
+ connect_callback1.Run(net::OK);
+
+ EXPECT_CALL(handler_, OnConnectComplete(net::ERR_CERT_AUTHORITY_INVALID));
+
+ // Set cert extraction to fail
+ socket_->SetExtractCertResult(false);
+ // Attempt to connect results in ERR_CERT_AUTHORTY_INVALID
+ connect_callback2.Run(net::ERR_CERT_AUTHORITY_INVALID);
+
+ EXPECT_EQ(cast_channel::READY_STATE_CLOSED, socket_->ready_state());
+ EXPECT_EQ(cast_channel::CHANNEL_ERROR_CONNECT_ERROR, socket_->error_state());
+}
+
+// Tests writing a single message where the completion is signaled via
+// callback.
TEST_F(CastSocketTest, TestWriteViaCallback) {
ConnectHelper();
net::CompletionCallback write_callback;
- EXPECT_CALL(mock_tcp_socket(),
+ EXPECT_CALL(mock_ssl_socket(),
Write(A<net::IOBuffer*>(),
39,
A<const net::CompletionCallback&>()))
@@ -223,7 +394,7 @@ TEST_F(CastSocketTest, TestWriteViaCallback) {
TEST_F(CastSocketTest, TestWrite) {
ConnectHelper();
- EXPECT_CALL(mock_tcp_socket(),
+ EXPECT_CALL(mock_ssl_socket(),
Write(A<net::IOBuffer*>(),
39,
A<const net::CompletionCallback&>()))
@@ -250,7 +421,7 @@ TEST_F(CastSocketTest, TestWriteMany) {
net::CompletionCallback write_callback;
for (int i = 0; i < 4; i++) {
- EXPECT_CALL(mock_tcp_socket(),
+ EXPECT_CALL(mock_ssl_socket(),
Write(A<net::IOBuffer*>(),
sizes[i],
A<const net::CompletionCallback&>()))
@@ -280,7 +451,7 @@ TEST_F(CastSocketTest, TestWriteError) {
ConnectHelper();
net::CompletionCallback write_callback;
- EXPECT_CALL(mock_tcp_socket(),
+ EXPECT_CALL(mock_ssl_socket(),
Write(A<net::IOBuffer*>(),
39,
A<const net::CompletionCallback&>()))
@@ -299,28 +470,28 @@ TEST_F(CastSocketTest, TestWriteError) {
// Tests reading a single message.
TEST_F(CastSocketTest, TestRead) {
- net::CompletionCallback connect_callback;
+ net::CompletionCallback connect_callback1;
+ net::CompletionCallback connect_callback2;
net::CompletionCallback read_callback;
std::string message_data;
ASSERT_TRUE(CastSocket::Serialize(test_proto_, &message_data));
- EXPECT_CALL(mock_tcp_socket(), SetNoDelay(true))
- .Times(1)
- .WillOnce(Return(true));
- EXPECT_CALL(mock_tcp_socket(), SetKeepAlive(true, A<int>()))
- .Times(1)
- .WillOnce(Return(true));
EXPECT_CALL(mock_tcp_socket(), Connect(A<const net::CompletionCallback&>()))
- .Times(1)
- .WillOnce(DoAll(SaveArg<0>(&connect_callback), Return(net::OK)));
+ .Times(1)
+ .WillOnce(DoAll(SaveArg<0>(&connect_callback1),
+ Return(net::ERR_IO_PENDING)));
+ EXPECT_CALL(mock_ssl_socket(), Connect(A<const net::CompletionCallback&>()))
+ .Times(1)
+ .WillOnce(DoAll(SaveArg<0>(&connect_callback2),
+ Return(net::ERR_IO_PENDING)));
EXPECT_CALL(handler_, OnConnectComplete(net::OK));
- EXPECT_CALL(mock_tcp_socket(), Read(A<net::IOBuffer*>(),
+ EXPECT_CALL(mock_ssl_socket(), Read(A<net::IOBuffer*>(),
A<int>(),
A<const net::CompletionCallback&>()))
- .Times(3)
- .WillRepeatedly(DoAll(SaveArg<2>(&read_callback),
- Return(net::ERR_IO_PENDING)));
+ .Times(3)
+ .WillRepeatedly(DoAll(SaveArg<2>(&read_callback),
+ Return(net::ERR_IO_PENDING)));
// Expect the test message to be read and invoke the delegate.
EXPECT_CALL(mock_delegate_,
@@ -329,7 +500,8 @@ TEST_F(CastSocketTest, TestRead) {
// Connect the socket.
socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
base::Unretained(&handler_)));
- connect_callback.Run(net::OK);
+ connect_callback1.Run(net::OK);
+ connect_callback2.Run(net::OK);
// Put the test header and message into the io_buffers and invoke the read
// callbacks.
@@ -346,8 +518,10 @@ TEST_F(CastSocketTest, TestRead) {
// Tests reading multiple messages.
TEST_F(CastSocketTest, TestReadMany) {
- net::CompletionCallback connect_callback;
+ net::CompletionCallback connect_callback1;
+ net::CompletionCallback connect_callback2;
net::CompletionCallback read_callback;
+
std::string messages[4];
messages[0] = "Hello, World!";
messages[1] = "Goodbye, World!";
@@ -362,17 +536,16 @@ TEST_F(CastSocketTest, TestReadMany) {
ASSERT_TRUE(CastSocket::Serialize(test_proto_, &message_data[i]));
}
- EXPECT_CALL(mock_tcp_socket(), SetNoDelay(true))
- .Times(1)
- .WillOnce(Return(true));
- EXPECT_CALL(mock_tcp_socket(), SetKeepAlive(true, A<int>()))
- .Times(1)
- .WillOnce(Return(true));
EXPECT_CALL(mock_tcp_socket(), Connect(A<const net::CompletionCallback&>()))
- .Times(1)
- .WillOnce(DoAll(SaveArg<0>(&connect_callback), Return(net::OK)));
+ .Times(1)
+ .WillOnce(DoAll(SaveArg<0>(&connect_callback1),
+ Return(net::ERR_IO_PENDING)));
+ EXPECT_CALL(mock_ssl_socket(), Connect(A<const net::CompletionCallback&>()))
+ .Times(1)
+ .WillOnce(DoAll(SaveArg<0>(&connect_callback2),
+ Return(net::ERR_IO_PENDING)));
EXPECT_CALL(handler_, OnConnectComplete(net::OK));
- EXPECT_CALL(mock_tcp_socket(), Read(A<net::IOBuffer*>(),
+ EXPECT_CALL(mock_ssl_socket(), Read(A<net::IOBuffer*>(),
A<int>(),
A<const net::CompletionCallback&>()))
.Times(9)
@@ -387,7 +560,8 @@ TEST_F(CastSocketTest, TestReadMany) {
// Connect the socket.
socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
base::Unretained(&handler_)));
- connect_callback.Run(net::OK);
+ connect_callback1.Run(net::OK);
+ connect_callback2.Run(net::OK);
// Put the test headers and messages into the io_buffer and invoke the read
// callbacks.
@@ -406,20 +580,20 @@ TEST_F(CastSocketTest, TestReadMany) {
// Tests error on reading.
TEST_F(CastSocketTest, TestReadError) {
- net::CompletionCallback connect_callback;
+ net::CompletionCallback connect_callback1;
+ net::CompletionCallback connect_callback2;
net::CompletionCallback read_callback;
- EXPECT_CALL(mock_tcp_socket(), SetNoDelay(true))
- .Times(1)
- .WillOnce(Return(true));
- EXPECT_CALL(mock_tcp_socket(), SetKeepAlive(true, A<int>()))
- .Times(1)
- .WillOnce(Return(true));
EXPECT_CALL(mock_tcp_socket(), Connect(A<const net::CompletionCallback&>()))
- .Times(1)
- .WillOnce(DoAll(SaveArg<0>(&connect_callback), Return(net::OK)));
+ .Times(1)
+ .WillOnce(DoAll(SaveArg<0>(&connect_callback1),
+ Return(net::ERR_IO_PENDING)));
+ EXPECT_CALL(mock_ssl_socket(), Connect(A<const net::CompletionCallback&>()))
+ .Times(1)
+ .WillOnce(DoAll(SaveArg<0>(&connect_callback2),
+ Return(net::ERR_IO_PENDING)));
EXPECT_CALL(handler_, OnConnectComplete(net::OK));
- EXPECT_CALL(mock_tcp_socket(), Read(A<net::IOBuffer*>(),
+ EXPECT_CALL(mock_ssl_socket(), Read(A<net::IOBuffer*>(),
A<int>(),
A<const net::CompletionCallback&>()))
.WillOnce(DoAll(SaveArg<2>(&read_callback),
@@ -430,7 +604,8 @@ TEST_F(CastSocketTest, TestReadError) {
// Connect the socket.
socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
base::Unretained(&handler_)));
- connect_callback.Run(net::OK);
+ connect_callback1.Run(net::OK);
+ connect_callback2.Run(net::OK);
// Cause an error.
read_callback.Run(net::ERR_SOCKET_NOT_CONNECTED);
diff --git a/chrome/browser/extensions/api/commands/command_service.cc b/chrome/browser/extensions/api/commands/command_service.cc
index 4b3ef78758..5282cf0a1d 100644
--- a/chrome/browser/extensions/api/commands/command_service.cc
+++ b/chrome/browser/extensions/api/commands/command_service.cc
@@ -18,6 +18,7 @@
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/accelerator_utils.h"
#include "chrome/common/extensions/api/commands/commands_handler.h"
+#include "chrome/common/extensions/feature_switch.h"
#include "chrome/common/pref_names.h"
#include "components/user_prefs/pref_registry_syncable.h"
#include "content/public/browser/notification_details.h"
@@ -30,6 +31,7 @@ namespace {
const char kExtension[] = "extension";
const char kCommandName[] = "command_name";
+const char kGlobal[] = "global";
// A preference that indicates that the initial keybindings for the given
// extension have been set.
@@ -155,18 +157,21 @@ bool CommandService::GetNamedCommands(const std::string& extension_id,
extensions::CommandMap::const_iterator iter = commands->begin();
for (; iter != commands->end(); ++iter) {
- ui::Accelerator shortcut_assigned =
- FindShortcutForCommand(extension_id, iter->second.command_name());
+ // Look up to see if the user has overridden how the command should work.
+ extensions::Command saved_command =
+ FindCommandByName(extension_id, iter->second.command_name());
+ ui::Accelerator shortcut_assigned = saved_command.accelerator();
if (type == ACTIVE_ONLY && shortcut_assigned.key_code() == ui::VKEY_UNKNOWN)
continue;
extensions::Command command = iter->second;
- if (scope != ANY_SCOPE && ((scope == GLOBAL) != command.global()))
+ if (scope != ANY_SCOPE && ((scope == GLOBAL) != saved_command.global()))
continue;
if (shortcut_assigned.key_code() != ui::VKEY_UNKNOWN)
command.set_accelerator(shortcut_assigned);
+ command.set_global(saved_command.global());
(*command_map)[iter->second.command_name()] = command;
}
@@ -178,7 +183,8 @@ bool CommandService::AddKeybindingPref(
const ui::Accelerator& accelerator,
std::string extension_id,
std::string command_name,
- bool allow_overrides) {
+ bool allow_overrides,
+ bool global) {
if (accelerator.key_code() == ui::VKEY_UNKNOWN)
return false;
@@ -194,6 +200,7 @@ bool CommandService::AddKeybindingPref(
base::DictionaryValue* keybinding = new base::DictionaryValue();
keybinding->SetString(kExtension, extension_id);
keybinding->SetString(kCommandName, command_name);
+ keybinding->SetBoolean(kGlobal, global);
bindings->Set(key, keybinding);
@@ -231,16 +238,30 @@ void CommandService::Observe(
void CommandService::UpdateKeybindingPrefs(const std::string& extension_id,
const std::string& command_name,
const std::string& keystroke) {
+ extensions::Command command = FindCommandByName(extension_id, command_name);
+
// The extension command might be assigned another shortcut. Remove that
// shortcut before proceeding.
RemoveKeybindingPrefs(extension_id, command_name);
ui::Accelerator accelerator =
Command::StringToAccelerator(keystroke, command_name);
- AddKeybindingPref(accelerator, extension_id, command_name, true);
+ AddKeybindingPref(accelerator, extension_id, command_name,
+ true, command.global());
+}
+
+void CommandService::ToggleScope(const std::string& extension_id,
+ const std::string& command_name) {
+ extensions::Command command = FindCommandByName(extension_id, command_name);
+
+ // Pre-existing shortcuts must be removed before proceeding because the
+ // handlers for global and non-global extensions are not one and the same.
+ RemoveKeybindingPrefs(extension_id, command_name);
+ AddKeybindingPref(command.accelerator(), extension_id,
+ command_name, true, !command.global());
}
-ui::Accelerator CommandService::FindShortcutForCommand(
+Command CommandService::FindCommandByName(
const std::string& extension_id, const std::string& command) {
const base::DictionaryValue* bindings =
profile_->GetPrefs()->GetDictionary(prefs::kExtensionCommands);
@@ -257,15 +278,18 @@ ui::Accelerator CommandService::FindShortcutForCommand(
item->GetString(kCommandName, &command_name);
if (command != command_name)
continue;
+ bool global = false;
+ if (FeatureSwitch::global_commands()->IsEnabled())
+ item->GetBoolean(kGlobal, &global);
std::string shortcut = it.key();
if (StartsWithASCII(shortcut, Command::CommandPlatform() + ":", true))
shortcut = shortcut.substr(Command::CommandPlatform().length() + 1);
- return Command::StringToAccelerator(shortcut, command_name);
+ return Command(command_name, string16(), shortcut, global);
}
- return ui::Accelerator();
+ return Command();
}
void CommandService::AssignInitialKeybindings(const Extension* extension) {
@@ -289,7 +313,8 @@ void CommandService::AssignInitialKeybindings(const Extension* extension) {
AddKeybindingPref(iter->second.accelerator(),
extension->id(),
iter->second.command_name(),
- false); // Overwriting not allowed.
+ false, // Overwriting not allowed.
+ iter->second.global());
}
}
@@ -301,7 +326,8 @@ void CommandService::AssignInitialKeybindings(const Extension* extension) {
AddKeybindingPref(browser_action_command->accelerator(),
extension->id(),
browser_action_command->command_name(),
- false); // Overwriting not allowed.
+ false, // Overwriting not allowed.
+ false); // Browser actions can't be global.
}
}
@@ -313,7 +339,8 @@ void CommandService::AssignInitialKeybindings(const Extension* extension) {
AddKeybindingPref(page_action_command->accelerator(),
extension->id(),
page_action_command->command_name(),
- false); // Overwriting not allowed.
+ false, // Overwriting not allowed.
+ false); // Page actions can't be global.
}
}
@@ -325,7 +352,8 @@ void CommandService::AssignInitialKeybindings(const Extension* extension) {
AddKeybindingPref(script_badge_command->accelerator(),
extension->id(),
script_badge_command->command_name(),
- false); // Overwriting not allowed.
+ false, // Overwriting not allowed.
+ false); // Script badges can't be global.
}
}
}
@@ -407,8 +435,10 @@ bool CommandService::GetExtensionActionCommand(
if (!requested_command)
return false;
- ui::Accelerator shortcut_assigned =
- FindShortcutForCommand(extension_id, requested_command->command_name());
+ // Look up to see if the user has overridden how the command should work.
+ extensions::Command saved_command =
+ FindCommandByName(extension_id, requested_command->command_name());
+ ui::Accelerator shortcut_assigned = saved_command.accelerator();
if (active)
*active = (shortcut_assigned.key_code() != ui::VKEY_UNKNOWN);
diff --git a/chrome/browser/extensions/api/commands/command_service.h b/chrome/browser/extensions/api/commands/command_service.h
index ac553aa318..cedacd770f 100644
--- a/chrome/browser/extensions/api/commands/command_service.h
+++ b/chrome/browser/extensions/api/commands/command_service.h
@@ -115,12 +115,14 @@ class CommandService : public ProfileKeyedAPI,
// |allow_overrides| is false, the keybinding must be free for the change to
// be recorded (as determined by the master list in |user_prefs|). If
// |allow_overwrites| is true, any previously recorded keybinding for this
- // |accelerator| will be overwritten. Returns true if the change was
- // successfully recorded.
+ // |accelerator| will be overwritten. If |global| is true, the command will
+ // be registered as a global command (be active even when Chrome does not have
+ // focus. Returns true if the change was successfully recorded.
bool AddKeybindingPref(const ui::Accelerator& accelerator,
std::string extension_id,
std::string command_name,
- bool allow_overrides);
+ bool allow_overrides,
+ bool global);
// Removes all keybindings for a given extension by its |extension_id|.
// |command_name| is optional and if specified, causes only the command with
@@ -135,12 +137,15 @@ class CommandService : public ProfileKeyedAPI,
const std::string& command_name,
const std::string& keystroke);
- // Finds the shortcut assigned to a command with the name |command_name|
- // within an extension with id |extension_id|. Returns an empty Accelerator
- // object (with keycode VKEY_UNKNOWN) if no shortcut is assigned or the
- // command is not found.
- ui::Accelerator FindShortcutForCommand(const std::string& extension_id,
- const std::string& command);
+ // Toggles the scope of the keybinding.
+ void ToggleScope(const std::string& extension_id,
+ const std::string& command_name);
+
+ // Finds the command with the name |command_name| within an extension with id
+ // |extension_id| . Returns an empty Command object (with keycode
+ // VKEY_UNKNOWN) if the command is not found.
+ Command FindCommandByName(const std::string& extension_id,
+ const std::string& command);
// Overridden from content::NotificationObserver.
virtual void Observe(int type,
diff --git a/chrome/browser/extensions/api/commands/command_service_browsertest.cc b/chrome/browser/extensions/api/commands/command_service_browsertest.cc
index 2ed81c2db2..1a1a6c1adf 100644
--- a/chrome/browser/extensions/api/commands/command_service_browsertest.cc
+++ b/chrome/browser/extensions/api/commands/command_service_browsertest.cc
@@ -42,9 +42,8 @@ IN_PROC_BROWSER_TEST_F(CommandServiceTest, RemoveShortcutSurvivesUpdate) {
EXPECT_TRUE(service->GetExtensionById(kId, false) != NULL);
// Verify it has a command of Alt+Shift+F.
- ui::Accelerator accelerator =
- command_service->FindShortcutForCommand(
- kId, manifest_values::kBrowserActionCommandEvent);
+ ui::Accelerator accelerator = command_service->FindCommandByName(
+ kId, manifest_values::kBrowserActionCommandEvent).accelerator();
EXPECT_EQ(ui::VKEY_F, accelerator.key_code());
EXPECT_FALSE(accelerator.IsCtrlDown());
EXPECT_TRUE(accelerator.IsShiftDown());
@@ -55,8 +54,8 @@ IN_PROC_BROWSER_TEST_F(CommandServiceTest, RemoveShortcutSurvivesUpdate) {
kId, manifest_values::kBrowserActionCommandEvent);
// Verify it got removed.
- accelerator = command_service->FindShortcutForCommand(
- kId, manifest_values::kBrowserActionCommandEvent);
+ accelerator = command_service->FindCommandByName(
+ kId, manifest_values::kBrowserActionCommandEvent).accelerator();
EXPECT_EQ(ui::VKEY_UNKNOWN, accelerator.key_code());
// Update to version 2.
@@ -64,8 +63,8 @@ IN_PROC_BROWSER_TEST_F(CommandServiceTest, RemoveShortcutSurvivesUpdate) {
EXPECT_TRUE(service->GetExtensionById(kId, false) != NULL);
// Verify it is still set to nothing.
- accelerator = command_service->FindShortcutForCommand(
- kId, manifest_values::kBrowserActionCommandEvent);
+ accelerator = command_service->FindCommandByName(
+ kId, manifest_values::kBrowserActionCommandEvent).accelerator();
EXPECT_EQ(ui::VKEY_UNKNOWN, accelerator.key_code());
}
diff --git a/chrome/browser/extensions/api/commands/commands.cc b/chrome/browser/extensions/api/commands/commands.cc
index 7e2a10bae4..0b6f0e54c6 100644
--- a/chrome/browser/extensions/api/commands/commands.cc
+++ b/chrome/browser/extensions/api/commands/commands.cc
@@ -60,9 +60,9 @@ bool GetAllCommandsFunction::RunImpl() {
for (extensions::CommandMap::const_iterator iter = named_commands.begin();
iter != named_commands.end(); ++iter) {
- ui::Accelerator shortcut_assigned =
- command_service->FindShortcutForCommand(
- extension_->id(), iter->second.command_name());
+ extensions::Command command = command_service->FindCommandByName(
+ extension_->id(), iter->second.command_name());
+ ui::Accelerator shortcut_assigned = command.accelerator();
active = (shortcut_assigned.key_code() != ui::VKEY_UNKNOWN);
command_list->Append(CreateCommandValue(iter->second, active));
diff --git a/chrome/browser/extensions/api/content_settings/content_settings_apitest.cc b/chrome/browser/extensions/api/content_settings/content_settings_apitest.cc
index dbc714aea8..e17de512bf 100644
--- a/chrome/browser/extensions/api/content_settings/content_settings_apitest.cc
+++ b/chrome/browser/extensions/api/content_settings/content_settings_apitest.cc
@@ -191,7 +191,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionContentSettingsApiTest, MAYBE_Standard) {
CheckContentSettingsSet();
// The settings should not be reset when the extension is reloaded.
- ReloadExtension(last_loaded_extension_id_);
+ ReloadExtension(last_loaded_extension_id());
CheckContentSettingsSet();
// Uninstalling and installing the extension (without running the test that
@@ -199,7 +199,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionContentSettingsApiTest, MAYBE_Standard) {
content::WindowedNotificationObserver observer(
chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
content::NotificationService::AllSources());
- UninstallExtension(last_loaded_extension_id_);
+ UninstallExtension(last_loaded_extension_id());
observer.Wait();
CheckContentSettingsDefault();
diff --git a/chrome/browser/extensions/api/declarative/declarative_rule.h b/chrome/browser/extensions/api/declarative/declarative_rule.h
index d1dab32782..84dffc21a8 100644
--- a/chrome/browser/extensions/api/declarative/declarative_rule.h
+++ b/chrome/browser/extensions/api/declarative/declarative_rule.h
@@ -21,6 +21,7 @@
#include "base/stl_util.h"
#include "base/time/time.h"
#include "chrome/common/extensions/api/events.h"
+#include "chrome/common/extensions/extension.h"
#include "extensions/common/matcher/url_matcher.h"
namespace base {
@@ -39,6 +40,7 @@ namespace extensions {
//
// // Arguments passed through from DeclarativeConditionSet::Create.
// static scoped_ptr<ConditionT> Create(
+// const Extension* extension,
// URLMatcherConditionFactory* url_matcher_condition_factory,
// // Except this argument gets elements of the AnyVector.
// const base::Value& definition,
@@ -57,10 +59,11 @@ class DeclarativeConditionSet {
typedef std::vector<linked_ptr<const ConditionT> > Conditions;
typedef typename Conditions::const_iterator const_iterator;
- // Factory method that creates a DeclarativeConditionSet according to the JSON
- // array |conditions| passed by the extension API. Sets |error| and returns
- // NULL in case of an error.
+ // Factory method that creates a DeclarativeConditionSet for |extension|
+ // according to the JSON array |conditions| passed by the extension API. Sets
+ // |error| and returns NULL in case of an error.
static scoped_ptr<DeclarativeConditionSet> Create(
+ const Extension* extension,
URLMatcherConditionFactory* url_matcher_condition_factory,
const AnyVector& conditions,
std::string* error);
@@ -112,6 +115,7 @@ class DeclarativeConditionSet {
//
// // Arguments passed through from ActionSet::Create.
// static scoped_ptr<ActionT> Create(
+// const Extension* extension,
// // Except this argument gets elements of the AnyVector.
// const base::Value& definition,
// std::string* error, bool* bad_message);
@@ -139,10 +143,11 @@ class DeclarativeActionSet {
explicit DeclarativeActionSet(const Actions& actions);
- // Factory method that instantiates a DeclarativeActionSet according to
- // |actions| which represents the array of actions received from the
- // extension API.
- static scoped_ptr<DeclarativeActionSet> Create(const AnyVector& actions,
+ // Factory method that instantiates a DeclarativeActionSet for |extension|
+ // according to |actions| which represents the array of actions received from
+ // the extension API.
+ static scoped_ptr<DeclarativeActionSet> Create(const Extension* extension,
+ const AnyVector& actions,
std::string* error,
bool* bad_message);
@@ -202,9 +207,9 @@ class DeclarativeRule {
scoped_ptr<ActionSet> actions,
Priority priority);
- // Creates a DeclarativeRule for an extension given a json definition. The
+ // Creates a DeclarativeRule for |extension| given a json definition. The
// format of each condition and action's json is up to the specific ConditionT
- // and ActionT.
+ // and ActionT. |extension| may be NULL in tests.
//
// Before constructing the final rule, calls check_consistency(conditions,
// actions, error) and returns NULL if it fails. Pass NULL if no consistency
@@ -212,7 +217,7 @@ class DeclarativeRule {
// the returned rule is internally consistent.
static scoped_ptr<DeclarativeRule> Create(
URLMatcherConditionFactory* url_matcher_condition_factory,
- const std::string& extension_id,
+ const Extension* extension,
base::Time extension_installation_time,
linked_ptr<JsonRule> rule,
ConsistencyChecker check_consistency,
@@ -288,6 +293,7 @@ void DeclarativeConditionSet<ConditionT>::GetURLMatcherConditionSets(
template<typename ConditionT>
scoped_ptr<DeclarativeConditionSet<ConditionT> >
DeclarativeConditionSet<ConditionT>::Create(
+ const Extension* extension,
URLMatcherConditionFactory* url_matcher_condition_factory,
const AnyVector& conditions,
std::string* error) {
@@ -296,8 +302,8 @@ DeclarativeConditionSet<ConditionT>::Create(
for (AnyVector::const_iterator i = conditions.begin();
i != conditions.end(); ++i) {
CHECK(i->get());
- scoped_ptr<ConditionT> condition =
- ConditionT::Create(url_matcher_condition_factory, **i, error);
+ scoped_ptr<ConditionT> condition = ConditionT::Create(
+ extension, url_matcher_condition_factory, **i, error);
if (!error->empty())
return scoped_ptr<DeclarativeConditionSet>();
result.push_back(make_linked_ptr(condition.release()));
@@ -346,6 +352,7 @@ DeclarativeActionSet<ActionT>::DeclarativeActionSet(const Actions& actions)
template<typename ActionT>
scoped_ptr<DeclarativeActionSet<ActionT> >
DeclarativeActionSet<ActionT>::Create(
+ const Extension* extension,
const AnyVector& actions,
std::string* error,
bool* bad_message) {
@@ -357,7 +364,7 @@ DeclarativeActionSet<ActionT>::Create(
i != actions.end(); ++i) {
CHECK(i->get());
scoped_refptr<const ActionT> action =
- ActionT::Create(**i, error, bad_message);
+ ActionT::Create(extension, **i, error, bad_message);
if (!error->empty() || *bad_message)
return scoped_ptr<DeclarativeActionSet>();
result.push_back(action);
@@ -423,7 +430,7 @@ template<typename ConditionT, typename ActionT>
scoped_ptr<DeclarativeRule<ConditionT, ActionT> >
DeclarativeRule<ConditionT, ActionT>::Create(
URLMatcherConditionFactory* url_matcher_condition_factory,
- const std::string& extension_id,
+ const Extension* extension,
base::Time extension_installation_time,
linked_ptr<JsonRule> rule,
ConsistencyChecker check_consistency,
@@ -431,14 +438,14 @@ DeclarativeRule<ConditionT, ActionT>::Create(
scoped_ptr<DeclarativeRule> error_result;
scoped_ptr<ConditionSet> conditions = ConditionSet::Create(
- url_matcher_condition_factory, rule->conditions, error);
+ extension, url_matcher_condition_factory, rule->conditions, error);
if (!error->empty())
return error_result.Pass();
CHECK(conditions.get());
bool bad_message = false;
scoped_ptr<ActionSet> actions =
- ActionSet::Create(rule->actions, error, &bad_message);
+ ActionSet::Create(extension, rule->actions, error, &bad_message);
if (bad_message) {
// TODO(battre) Export concept of bad_message to caller, the extension
// should be killed in case it is true.
@@ -459,7 +466,7 @@ DeclarativeRule<ConditionT, ActionT>::Create(
CHECK(rule->priority.get());
int priority = *(rule->priority);
- GlobalRuleId rule_id(extension_id, *(rule->id));
+ GlobalRuleId rule_id(extension->id(), *(rule->id));
Tags tags = rule->tags ? *rule->tags : Tags();
return scoped_ptr<DeclarativeRule>(
new DeclarativeRule(rule_id, tags, extension_installation_time,
diff --git a/chrome/browser/extensions/api/declarative/declarative_rule_unittest.cc b/chrome/browser/extensions/api/declarative/declarative_rule_unittest.cc
index 3808188e15..fee8401b5d 100644
--- a/chrome/browser/extensions/api/declarative/declarative_rule_unittest.cc
+++ b/chrome/browser/extensions/api/declarative/declarative_rule_unittest.cc
@@ -8,6 +8,7 @@
#include "base/message_loop/message_loop.h"
#include "base/test/values_test_util.h"
#include "base/values.h"
+#include "chrome/common/extensions/extension_builder.h"
#include "extensions/common/matcher/url_matcher_constants.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -23,6 +24,14 @@ linked_ptr<T> ScopedToLinkedPtr(scoped_ptr<T> ptr) {
return linked_ptr<T>(ptr.release());
}
+scoped_ptr<DictionaryValue> SimpleManifest() {
+ return DictionaryBuilder()
+ .Set("name", "extension")
+ .Set("manifest_version", 2)
+ .Set("version", "1.0")
+ .Build();
+}
+
} // namespace
struct RecordingCondition {
@@ -37,6 +46,7 @@ struct RecordingCondition {
}
static scoped_ptr<RecordingCondition> Create(
+ const Extension* extension,
URLMatcherConditionFactory* url_matcher_condition_factory,
const base::Value& condition,
std::string* error) {
@@ -61,9 +71,8 @@ TEST(DeclarativeConditionTest, ErrorConditionSet) {
conditions.push_back(ScopedToLinkedPtr(ParseJson("{\"bad_key\": 2}")));
std::string error;
- scoped_ptr<RecordingConditionSet> result =
- RecordingConditionSet::Create(matcher.condition_factory(),
- conditions, &error);
+ scoped_ptr<RecordingConditionSet> result = RecordingConditionSet::Create(
+ NULL, matcher.condition_factory(), conditions, &error);
EXPECT_EQ("Found error key", error);
ASSERT_FALSE(result);
}
@@ -76,9 +85,8 @@ TEST(DeclarativeConditionTest, CreateConditionSet) {
// Test insertion
std::string error;
- scoped_ptr<RecordingConditionSet> result =
- RecordingConditionSet::Create(matcher.condition_factory(),
- conditions, &error);
+ scoped_ptr<RecordingConditionSet> result = RecordingConditionSet::Create(
+ NULL, matcher.condition_factory(), conditions, &error);
EXPECT_EQ("", error);
ASSERT_TRUE(result);
EXPECT_EQ(2u, result->conditions().size());
@@ -120,7 +128,8 @@ struct FulfillableCondition {
}
static scoped_ptr<FulfillableCondition> Create(
- URLMatcherConditionFactory* /*url_matcher_condition_factory*/,
+ const Extension* extension,
+ URLMatcherConditionFactory* url_matcher_condition_factory,
const base::Value& condition,
std::string* error) {
scoped_ptr<FulfillableCondition> result(new FulfillableCondition());
@@ -157,7 +166,7 @@ TEST(DeclarativeConditionTest, FulfillConditionSet) {
// Test insertion
std::string error;
scoped_ptr<FulfillableConditionSet> result =
- FulfillableConditionSet::Create(NULL, conditions, &error);
+ FulfillableConditionSet::Create(NULL, NULL, conditions, &error);
ASSERT_EQ("", error);
ASSERT_TRUE(result);
EXPECT_EQ(4u, result->conditions().size());
@@ -205,7 +214,8 @@ class SummingAction : public base::RefCounted<SummingAction> {
SummingAction(int increment, int min_priority)
: increment_(increment), min_priority_(min_priority) {}
- static scoped_refptr<const SummingAction> Create(const base::Value& action,
+ static scoped_refptr<const SummingAction> Create(const Extension* extension,
+ const base::Value& action,
std::string* error,
bool* bad_message) {
int increment = 0;
@@ -255,7 +265,7 @@ TEST(DeclarativeActionTest, ErrorActionSet) {
std::string error;
bool bad = false;
scoped_ptr<SummingActionSet> result =
- SummingActionSet::Create(actions, &error, &bad);
+ SummingActionSet::Create(NULL, actions, &error, &bad);
EXPECT_EQ("the error", error);
EXPECT_FALSE(bad);
EXPECT_FALSE(result);
@@ -263,7 +273,7 @@ TEST(DeclarativeActionTest, ErrorActionSet) {
actions.clear();
actions.push_back(ScopedToLinkedPtr(ParseJson("{\"value\": 1}")));
actions.push_back(ScopedToLinkedPtr(ParseJson("{\"bad\": 3}")));
- result = SummingActionSet::Create(actions, &error, &bad);
+ result = SummingActionSet::Create(NULL, actions, &error, &bad);
EXPECT_EQ("", error);
EXPECT_TRUE(bad);
EXPECT_FALSE(result);
@@ -280,7 +290,7 @@ TEST(DeclarativeActionTest, ApplyActionSet) {
std::string error;
bool bad = false;
scoped_ptr<SummingActionSet> result =
- SummingActionSet::Create(actions, &error, &bad);
+ SummingActionSet::Create(NULL, actions, &error, &bad);
EXPECT_EQ("", error);
EXPECT_FALSE(bad);
ASSERT_TRUE(result);
@@ -312,13 +322,17 @@ TEST(DeclarativeRuleTest, Create) {
json_rule.get()));
const char kExtensionId[] = "ext1";
+ scoped_refptr<Extension> extension = ExtensionBuilder()
+ .SetManifest(SimpleManifest())
+ .SetID(kExtensionId)
+ .Build();
base::Time install_time = base::Time::Now();
URLMatcher matcher;
std::string error;
scoped_ptr<Rule> rule(Rule::Create(matcher.condition_factory(),
- kExtensionId,
+ extension.get(),
install_time,
json_rule,
Rule::ConsistencyChecker(),
@@ -365,6 +379,10 @@ TEST(DeclarativeRuleTest, CheckConsistency) {
std::string error;
linked_ptr<Rule::JsonRule> json_rule(new Rule::JsonRule);
const char kExtensionId[] = "ext1";
+ scoped_refptr<Extension> extension = ExtensionBuilder()
+ .SetManifest(SimpleManifest())
+ .SetID(kExtensionId)
+ .Build();
ASSERT_TRUE(Rule::JsonRule::Populate(
*ParseJson("{ \n"
@@ -381,9 +399,12 @@ TEST(DeclarativeRuleTest, CheckConsistency) {
" \"priority\": 200 \n"
"}"),
json_rule.get()));
- scoped_ptr<Rule> rule(
- Rule::Create(matcher.condition_factory(), kExtensionId, base::Time(),
- json_rule, base::Bind(AtLeastOneCondition), &error));
+ scoped_ptr<Rule> rule(Rule::Create(matcher.condition_factory(),
+ extension.get(),
+ base::Time(),
+ json_rule,
+ base::Bind(AtLeastOneCondition),
+ &error));
EXPECT_TRUE(rule);
EXPECT_EQ("", error);
@@ -400,8 +421,12 @@ TEST(DeclarativeRuleTest, CheckConsistency) {
" \"priority\": 200 \n"
"}"),
json_rule.get()));
- rule = Rule::Create(matcher.condition_factory(), kExtensionId, base::Time(),
- json_rule, base::Bind(AtLeastOneCondition), &error);
+ rule = Rule::Create(matcher.condition_factory(),
+ extension.get(),
+ base::Time(),
+ json_rule,
+ base::Bind(AtLeastOneCondition),
+ &error);
EXPECT_FALSE(rule);
EXPECT_EQ("No conditions", error);
}
diff --git a/chrome/browser/extensions/api/declarative/rules_registry_with_cache.cc b/chrome/browser/extensions/api/declarative/rules_registry_with_cache.cc
index e285eb761e..a452130fb0 100644
--- a/chrome/browser/extensions/api/declarative/rules_registry_with_cache.cc
+++ b/chrome/browser/extensions/api/declarative/rules_registry_with_cache.cc
@@ -16,6 +16,7 @@
#include "chrome/browser/extensions/extension_prefs.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/extensions/state_store.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/extension.h"
@@ -402,7 +403,7 @@ RulesRegistryWithCache::RuleStorageOnUI::ReadRulesForInstalledExtensions() {
(*i)->HasAPIPermission(APIPermission::kDeclarativeWebRequest);
bool respects_off_the_record =
!(profile_->IsOffTheRecord()) ||
- extension_service->IsIncognitoEnabled((*i)->id());
+ extension_util::IsIncognitoEnabled((*i)->id(), extension_service);
if (needs_apis_storing_rules && respects_off_the_record)
ReadFromStorage((*i)->id());
}
diff --git a/chrome/browser/extensions/api/declarative_content/content_action.cc b/chrome/browser/extensions/api/declarative_content/content_action.cc
index a0531e0413..97ad637ef8 100644
--- a/chrome/browser/extensions/api/declarative_content/content_action.cc
+++ b/chrome/browser/extensions/api/declarative_content/content_action.cc
@@ -27,6 +27,8 @@ namespace {
// Error messages.
const char kInvalidInstanceTypeError[] =
"An action has an invalid instanceType: %s";
+const char kNoPageAction[] =
+ "Can't use declarativeContent.ShowPageAction without a page action";
#define INPUT_FORMAT_VALIDATE(test) do { \
if (!(test)) { \
@@ -44,6 +46,18 @@ class ShowPageAction : public ContentAction {
public:
ShowPageAction() {}
+ static scoped_refptr<ContentAction> Create(const Extension* extension,
+ const base::DictionaryValue* dict,
+ std::string* error,
+ bool* bad_message) {
+ // We can't show a page action if the extension doesn't have one.
+ if (ActionInfo::GetPageActionInfo(extension) == NULL) {
+ *error = kNoPageAction;
+ return scoped_refptr<ContentAction>();
+ }
+ return scoped_refptr<ContentAction>(new ShowPageAction);
+ }
+
// Implementation of ContentAction:
virtual Type GetType() const OVERRIDE { return ACTION_SHOW_PAGE_ACTION; }
virtual void Apply(const std::string& extension_id,
@@ -80,33 +94,25 @@ class ShowPageAction : public ContentAction {
DISALLOW_COPY_AND_ASSIGN(ShowPageAction);
};
-// Helper function for ContentActions that can be instantiated by just
-// calling the constructor.
-template <class T>
-scoped_refptr<ContentAction> CallConstructorFactoryMethod(
- const base::DictionaryValue* dict,
- std::string* error,
- bool* bad_message) {
- return scoped_refptr<ContentAction>(new T);
-}
-
struct ContentActionFactory {
- // Factory methods for ContentAction instances. |dict| contains the json
- // dictionary that describes the action. |error| is used to return error
- // messages in case the extension passed an action that was syntactically
- // correct but semantically incorrect. |bad_message| is set to true in case
- // |dict| does not confirm to the validated JSON specification.
- typedef scoped_refptr<ContentAction>
- (* FactoryMethod)(const base::DictionaryValue* /* dict */,
- std::string* /* error */,
- bool* /* bad_message */);
+ // Factory methods for ContentAction instances. |extension| is the extension
+ // for which the action is being created. |dict| contains the json dictionary
+ // that describes the action. |error| is used to return error messages in case
+ // the extension passed an action that was syntactically correct but
+ // semantically incorrect. |bad_message| is set to true in case |dict| does
+ // not confirm to the validated JSON specification.
+ typedef scoped_refptr<ContentAction>(*FactoryMethod)(
+ const Extension* /* extension */,
+ const base::DictionaryValue* /* dict */,
+ std::string* /* error */,
+ bool* /* bad_message */);
// Maps the name of a declarativeContent action type to the factory
// function creating it.
std::map<std::string, FactoryMethod> factory_methods;
ContentActionFactory() {
factory_methods[keys::kShowPageAction] =
- &CallConstructorFactoryMethod<ShowPageAction>;
+ &ShowPageAction::Create;
}
};
@@ -125,6 +131,7 @@ ContentAction::~ContentAction() {}
// static
scoped_refptr<ContentAction> ContentAction::Create(
+ const Extension* extension,
const base::Value& json_action,
std::string* error,
bool* bad_message) {
@@ -142,7 +149,8 @@ scoped_refptr<ContentAction> ContentAction::Create(
std::map<std::string, ContentActionFactory::FactoryMethod>::iterator
factory_method_iter = factory.factory_methods.find(instance_type);
if (factory_method_iter != factory.factory_methods.end())
- return (*factory_method_iter->second)(action_dict, error, bad_message);
+ return (*factory_method_iter->second)(
+ extension, action_dict, error, bad_message);
*error = base::StringPrintf(kInvalidInstanceTypeError, instance_type.c_str());
return scoped_refptr<ContentAction>();
diff --git a/chrome/browser/extensions/api/declarative_content/content_action.h b/chrome/browser/extensions/api/declarative_content/content_action.h
index 799f5c1b90..404719feda 100644
--- a/chrome/browser/extensions/api/declarative_content/content_action.h
+++ b/chrome/browser/extensions/api/declarative_content/content_action.h
@@ -23,6 +23,7 @@ class WebContents;
}
namespace extensions {
+class Extension;
// Base class for all ContentActions of the declarative content API.
class ContentAction : public base::RefCounted<ContentAction> {
@@ -57,9 +58,10 @@ class ContentAction : public base::RefCounted<ContentAction> {
// Sets |error| and returns NULL in case of a semantic error that cannot
// be caught by schema validation. Sets |bad_message| and returns NULL
// in case the input is syntactically unexpected.
- static scoped_refptr<ContentAction> Create(const base::Value& json_action,
- std::string* error,
- bool* bad_message);
+ static scoped_refptr<ContentAction> Create(const Extension* extension,
+ const base::Value& json_action,
+ std::string* error,
+ bool* bad_message);
protected:
friend class base::RefCounted<ContentAction>;
diff --git a/chrome/browser/extensions/api/declarative_content/content_action_unittest.cc b/chrome/browser/extensions/api/declarative_content/content_action_unittest.cc
index 049cc6c530..47d2a70511 100644
--- a/chrome/browser/extensions/api/declarative_content/content_action_unittest.cc
+++ b/chrome/browser/extensions/api/declarative_content/content_action_unittest.cc
@@ -9,6 +9,7 @@
#include "chrome/browser/extensions/extension_action_manager.h"
#include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/extensions/test_extension_environment.h"
+#include "chrome/common/extensions/extension_builder.h"
#include "chrome/test/base/testing_profile.h"
#include "content/public/browser/web_contents.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -28,21 +29,21 @@ TEST(DeclarativeContentActionTest, InvalidCreation) {
// Test wrong data type passed.
error.clear();
- result = ContentAction::Create(*ParseJson("[]"), &error, &bad_message);
+ result = ContentAction::Create(NULL, *ParseJson("[]"), &error, &bad_message);
EXPECT_TRUE(bad_message);
EXPECT_EQ("", error);
EXPECT_FALSE(result.get());
// Test missing instanceType element.
error.clear();
- result = ContentAction::Create(*ParseJson("{}"), &error, &bad_message);
+ result = ContentAction::Create(NULL, *ParseJson("{}"), &error, &bad_message);
EXPECT_TRUE(bad_message);
EXPECT_EQ("", error);
EXPECT_FALSE(result.get());
// Test wrong instanceType element.
error.clear();
- result = ContentAction::Create(*ParseJson(
+ result = ContentAction::Create(NULL, *ParseJson(
"{\n"
" \"instanceType\": \"declarativeContent.UnknownType\",\n"
"}"),
@@ -51,23 +52,45 @@ TEST(DeclarativeContentActionTest, InvalidCreation) {
EXPECT_FALSE(result.get());
}
+TEST(DeclarativeContentActionTest, ShowPageActionWithoutPageAction) {
+ TestExtensionEnvironment env;
+
+ const Extension* extension = env.MakeExtension(base::DictionaryValue());
+ std::string error;
+ bool bad_message = false;
+ scoped_refptr<const ContentAction> result = ContentAction::Create(
+ extension,
+ *ParseJson(
+ "{\n"
+ " \"instanceType\": \"declarativeContent.ShowPageAction\",\n"
+ "}"),
+ &error,
+ &bad_message);
+ EXPECT_THAT(error, testing::HasSubstr("without a page action"));
+ EXPECT_FALSE(bad_message);
+ ASSERT_FALSE(result.get());
+}
+
TEST(DeclarativeContentActionTest, ShowPageAction) {
TestExtensionEnvironment env;
+ const Extension* extension = env.MakeExtension(
+ *ParseJson("{\"page_action\": { \"default_title\": \"Extension\" } }"));
std::string error;
bool bad_message = false;
scoped_refptr<const ContentAction> result = ContentAction::Create(
- *ParseJson("{\n"
- " \"instanceType\": \"declarativeContent.ShowPageAction\",\n"
- "}"),
- &error, &bad_message);
+ extension,
+ *ParseJson(
+ "{\n"
+ " \"instanceType\": \"declarativeContent.ShowPageAction\",\n"
+ "}"),
+ &error,
+ &bad_message);
EXPECT_EQ("", error);
EXPECT_FALSE(bad_message);
ASSERT_TRUE(result.get());
EXPECT_EQ(ContentAction::ACTION_SHOW_PAGE_ACTION, result->GetType());
- const Extension* extension = env.MakeExtension(
- *ParseJson("{\"page_action\": { \"default_title\": \"Extension\" } }"));
ExtensionAction* page_action =
ExtensionActionManager::Get(env.profile())->GetPageAction(*extension);
scoped_ptr<content::WebContents> contents = env.MakeTab();
diff --git a/chrome/browser/extensions/api/declarative_content/content_condition.cc b/chrome/browser/extensions/api/declarative_content/content_condition.cc
index 1d83093e10..74319f8337 100644
--- a/chrome/browser/extensions/api/declarative_content/content_condition.cc
+++ b/chrome/browser/extensions/api/declarative_content/content_condition.cc
@@ -63,6 +63,7 @@ bool ContentCondition::IsFulfilled(
// static
scoped_ptr<ContentCondition> ContentCondition::Create(
+ const Extension* extension,
URLMatcherConditionFactory* url_matcher_condition_factory,
const base::Value& condition,
std::string* error) {
diff --git a/chrome/browser/extensions/api/declarative_content/content_condition.h b/chrome/browser/extensions/api/declarative_content/content_condition.h
index abb86d60bd..389f301e78 100644
--- a/chrome/browser/extensions/api/declarative_content/content_condition.h
+++ b/chrome/browser/extensions/api/declarative_content/content_condition.h
@@ -62,6 +62,7 @@ class ContentCondition {
// description |condition| passed by the extension API. |condition| should be
// an instance of declarativeContent.PageStateMatcher.
static scoped_ptr<ContentCondition> Create(
+ const Extension* extension,
URLMatcherConditionFactory* url_matcher_condition_factory,
const base::Value& condition,
std::string* error);
diff --git a/chrome/browser/extensions/api/declarative_content/content_condition_unittest.cc b/chrome/browser/extensions/api/declarative_content/content_condition_unittest.cc
index 557fbff8f5..f4cdb8ef6e 100644
--- a/chrome/browser/extensions/api/declarative_content/content_condition_unittest.cc
+++ b/chrome/browser/extensions/api/declarative_content/content_condition_unittest.cc
@@ -24,12 +24,13 @@ TEST(DeclarativeContentConditionTest, UnknownConditionName) {
URLMatcher matcher;
std::string error;
scoped_ptr<ContentCondition> result = ContentCondition::Create(
+ NULL,
matcher.condition_factory(),
*base::test::ParseJson(
- "{\n"
- " \"invalid\": \"foobar\",\n"
- " \"instanceType\": \"declarativeContent.PageStateMatcher\",\n"
- "}"),
+ "{\n"
+ " \"invalid\": \"foobar\",\n"
+ " \"instanceType\": \"declarativeContent.PageStateMatcher\",\n"
+ "}"),
&error);
EXPECT_THAT(error, HasSubstr("Unknown condition attribute"));
EXPECT_FALSE(result);
@@ -41,6 +42,7 @@ TEST(DeclarativeContentConditionTest, WrongPageUrlDatatype) {
URLMatcher matcher;
std::string error;
scoped_ptr<ContentCondition> result = ContentCondition::Create(
+ NULL,
matcher.condition_factory(),
*base::test::ParseJson(
"{\n"
@@ -58,6 +60,7 @@ TEST(DeclarativeContentConditionTest, WrongCssDatatype) {
URLMatcher matcher;
std::string error;
scoped_ptr<ContentCondition> result = ContentCondition::Create(
+ NULL,
matcher.condition_factory(),
*base::test::ParseJson(
"{\n"
@@ -76,6 +79,7 @@ TEST(DeclarativeContentConditionTest, ConditionWithUrlAndCss) {
std::string error;
scoped_ptr<ContentCondition> result = ContentCondition::Create(
+ NULL,
matcher.condition_factory(),
*base::test::ParseJson(
"{\n"
diff --git a/chrome/browser/extensions/api/declarative_content/content_rules_registry.cc b/chrome/browser/extensions/api/declarative_content/content_rules_registry.cc
index 63b8947b70..99f1490824 100644
--- a/chrome/browser/extensions/api/declarative_content/content_rules_registry.cc
+++ b/chrome/browser/extensions/api/declarative_content/content_rules_registry.cc
@@ -8,6 +8,7 @@
#include "chrome/browser/extensions/api/declarative_content/content_action.h"
#include "chrome/browser/extensions/api/declarative_content/content_condition.h"
#include "chrome/browser/extensions/api/declarative_content/content_constants.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/profiles/profile.h"
@@ -137,6 +138,11 @@ ContentRulesRegistry::GetMatches(
std::string ContentRulesRegistry::AddRulesImpl(
const std::string& extension_id,
const std::vector<linked_ptr<RulesRegistry::Rule> >& rules) {
+ ExtensionService* service =
+ ExtensionSystem::Get(profile_)->extension_service();
+ const Extension* extension = service->GetInstalledExtension(extension_id);
+ DCHECK(extension) << "Must have extension with id " << extension_id;
+
base::Time extension_installation_time =
GetExtensionInstallationTime(extension_id);
@@ -150,7 +156,7 @@ std::string ContentRulesRegistry::AddRulesImpl(
scoped_ptr<ContentRule> content_rule(
ContentRule::Create(url_matcher_.condition_factory(),
- extension_id,
+ extension,
extension_installation_time,
*rule,
ContentRule::ConsistencyChecker(),
diff --git a/chrome/browser/extensions/api/declarative_content/declarative_content_apitest.cc b/chrome/browser/extensions/api/declarative_content/declarative_content_apitest.cc
index 33c179d37f..395012cf20 100644
--- a/chrome/browser/extensions/api/declarative_content/declarative_content_apitest.cc
+++ b/chrome/browser/extensions/api/declarative_content/declarative_content_apitest.cc
@@ -28,21 +28,27 @@ const char kDeclarativeContentManifest[] =
" \"background\": {\n"
" \"scripts\": [\"background.js\"]\n"
" },\n"
+ " \"page_action\": {},\n"
" \"permissions\": [\n"
" \"declarativeContent\"\n"
- " ],\n"
- " \"page_action\": {}\n"
+ " ]\n"
"}\n";
const char kBackgroundHelpers[] =
"var PageStateMatcher = chrome.declarativeContent.PageStateMatcher;\n"
"var ShowPageAction = chrome.declarativeContent.ShowPageAction;\n"
"var onPageChanged = chrome.declarativeContent.onPageChanged;\n"
+ "var Reply = window.domAutomationController.send.bind(\n"
+ " window.domAutomationController);\n"
"\n"
"function setRules(rules, responseString) {\n"
" onPageChanged.removeRules(undefined, function() {\n"
" onPageChanged.addRules(rules, function() {\n"
- " window.domAutomationController.send(responseString);\n"
+ " if (chrome.runtime.lastError) {\n"
+ " Reply(chrome.runtime.lastError.message);\n"
+ " return;\n"
+ " }\n"
+ " Reply(responseString);\n"
" });\n"
" });\n"
"};\n";
@@ -233,6 +239,37 @@ IN_PROC_BROWSER_TEST_F(DeclarativeContentApiTest,
}
IN_PROC_BROWSER_TEST_F(DeclarativeContentApiTest,
+ ShowPageActionWithoutPageAction) {
+ std::string manifest_without_page_action = kDeclarativeContentManifest;
+ ReplaceSubstringsAfterOffset(
+ &manifest_without_page_action, 0, "\"page_action\": {},", "");
+ ext_dir_.WriteManifest(manifest_without_page_action);
+ ext_dir_.WriteFile(FILE_PATH_LITERAL("background.js"), kBackgroundHelpers);
+ const Extension* extension = LoadExtension(ext_dir_.unpacked_path());
+ ASSERT_TRUE(extension);
+
+ EXPECT_THAT(ExecuteScriptInBackgroundPage(
+ extension->id(),
+ "setRules([{\n"
+ " conditions: [new PageStateMatcher({\n"
+ " pageUrl: {hostPrefix: \"test\"}})],\n"
+ " actions: [new ShowPageAction()]\n"
+ "}], 'test_rule');\n"),
+ testing::HasSubstr("without a page action"));
+
+ content::WebContents* const tab =
+ browser()->tab_strip_model()->GetWebContentsAt(0);
+ NavigateInRenderer(tab, GURL("http://test/"));
+
+ EXPECT_EQ(NULL,
+ ExtensionActionManager::Get(browser()->profile())->
+ GetPageAction(*extension));
+ EXPECT_EQ(0,
+ browser()->window()->GetLocationBar()->GetLocationBarForTesting()->
+ PageActionCount());
+}
+
+IN_PROC_BROWSER_TEST_F(DeclarativeContentApiTest,
CanonicalizesPageStateMatcherCss) {
ext_dir_.WriteManifest(kDeclarativeContentManifest);
ext_dir_.WriteFile(
diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.cc
index fb38c55156..4da726e9fb 100644
--- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.cc
+++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.cc
@@ -467,6 +467,7 @@ bool WebRequestAction::HasPermission(const ExtensionInfoMap* extension_info_map,
// static
scoped_refptr<const WebRequestAction> WebRequestAction::Create(
+ const Extension* extension,
const base::Value& json_action,
std::string* error,
bool* bad_message) {
diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.h b/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.h
index faa70cfa5d..07fa95c869 100644
--- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.h
+++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.h
@@ -134,6 +134,7 @@ class WebRequestAction : public base::RefCounted<WebRequestAction> {
// be caught by schema validation. Sets |bad_message| and returns NULL
// in case the input is syntactically unexpected.
static scoped_refptr<const WebRequestAction> Create(
+ const Extension* extension,
const base::Value& json_action,
std::string* error,
bool* bad_message);
diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_action_unittest.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_action_unittest.cc
index 41d3d9194b..0c4925fdb6 100644
--- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_action_unittest.cc
+++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_action_unittest.cc
@@ -57,7 +57,7 @@ scoped_ptr<WebRequestActionSet> CreateSetOfActions(const char* json) {
bool bad_message = false;
scoped_ptr<WebRequestActionSet> action_set(
- WebRequestActionSet::Create(actions, &error, &bad_message));
+ WebRequestActionSet::Create(NULL, actions, &error, &bad_message));
EXPECT_EQ("", error);
EXPECT_FALSE(bad_message);
CHECK(action_set);
@@ -180,28 +180,28 @@ TEST(WebRequestActionTest, CreateAction) {
// Test wrong data type passed.
error.clear();
base::ListValue empty_list;
- result = WebRequestAction::Create(empty_list, &error, &bad_message);
+ result = WebRequestAction::Create(NULL, empty_list, &error, &bad_message);
EXPECT_TRUE(bad_message);
EXPECT_FALSE(result.get());
// Test missing instanceType element.
base::DictionaryValue input;
error.clear();
- result = WebRequestAction::Create(input, &error, &bad_message);
+ result = WebRequestAction::Create(NULL, input, &error, &bad_message);
EXPECT_TRUE(bad_message);
EXPECT_FALSE(result.get());
// Test wrong instanceType element.
input.SetString(keys::kInstanceTypeKey, kUnknownActionType);
error.clear();
- result = WebRequestAction::Create(input, &error, &bad_message);
+ result = WebRequestAction::Create(NULL, input, &error, &bad_message);
EXPECT_NE("", error);
EXPECT_FALSE(result.get());
// Test success
input.SetString(keys::kInstanceTypeKey, keys::kCancelRequestType);
error.clear();
- result = WebRequestAction::Create(input, &error, &bad_message);
+ result = WebRequestAction::Create(NULL, input, &error, &bad_message);
EXPECT_EQ("", error);
EXPECT_FALSE(bad_message);
ASSERT_TRUE(result.get());
@@ -217,7 +217,7 @@ TEST(WebRequestActionTest, CreateActionSet) {
// Test empty input.
error.clear();
- result = WebRequestActionSet::Create(input, &error, &bad_message);
+ result = WebRequestActionSet::Create(NULL, input, &error, &bad_message);
EXPECT_TRUE(error.empty()) << error;
EXPECT_FALSE(bad_message);
ASSERT_TRUE(result.get());
@@ -233,7 +233,7 @@ TEST(WebRequestActionTest, CreateActionSet) {
// Test success.
input.push_back(linked_ptr<base::Value>(correct_action.DeepCopy()));
error.clear();
- result = WebRequestActionSet::Create(input, &error, &bad_message);
+ result = WebRequestActionSet::Create(NULL, input, &error, &bad_message);
EXPECT_TRUE(error.empty()) << error;
EXPECT_FALSE(bad_message);
ASSERT_TRUE(result.get());
@@ -245,7 +245,7 @@ TEST(WebRequestActionTest, CreateActionSet) {
// Test failure.
input.push_back(linked_ptr<base::Value>(incorrect_action.DeepCopy()));
error.clear();
- result = WebRequestActionSet::Create(input, &error, &bad_message);
+ result = WebRequestActionSet::Create(NULL, input, &error, &bad_message);
EXPECT_NE("", error);
EXPECT_FALSE(result.get());
}
diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.cc
index 3ac29d6ce4..1e1ddec101 100644
--- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.cc
+++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.cc
@@ -122,6 +122,7 @@ void WebRequestCondition::GetURLMatcherConditionSets(
// static
scoped_ptr<WebRequestCondition> WebRequestCondition::Create(
+ const Extension* extension,
URLMatcherConditionFactory* url_matcher_condition_factory,
const base::Value& condition,
std::string* error) {
diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.h b/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.h
index e017a6ab6b..a9c9355482 100644
--- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.h
+++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.h
@@ -78,6 +78,7 @@ class WebRequestCondition {
// Factory method that instantiates a WebRequestCondition according to
// the description |condition| passed by the extension API.
static scoped_ptr<WebRequestCondition> Create(
+ const Extension* extension,
URLMatcherConditionFactory* url_matcher_condition_factory,
const base::Value& condition,
std::string* error);
diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_unittest.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_unittest.cc
index 9fcacc56cb..d30d1a6b3b 100644
--- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_unittest.cc
+++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_unittest.cc
@@ -31,11 +31,12 @@ TEST(WebRequestConditionTest, CreateCondition) {
// Test wrong condition name passed.
error.clear();
result = WebRequestCondition::Create(
+ NULL,
matcher.condition_factory(),
*base::test::ParseJson(
- "{ \"invalid\": \"foobar\", \n"
- " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
- "}"),
+ "{ \"invalid\": \"foobar\", \n"
+ " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
+ "}"),
&error);
EXPECT_FALSE(error.empty());
EXPECT_FALSE(result.get());
@@ -43,12 +44,13 @@ TEST(WebRequestConditionTest, CreateCondition) {
// Test wrong datatype in host_suffix.
error.clear();
result = WebRequestCondition::Create(
+ NULL,
matcher.condition_factory(),
*base::test::ParseJson(
- "{ \n"
- " \"url\": [], \n"
- " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
- "}"),
+ "{ \n"
+ " \"url\": [], \n"
+ " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
+ "}"),
&error);
EXPECT_FALSE(error.empty());
EXPECT_FALSE(result.get());
@@ -56,13 +58,14 @@ TEST(WebRequestConditionTest, CreateCondition) {
// Test success (can we support multiple criteria?)
error.clear();
result = WebRequestCondition::Create(
+ NULL,
matcher.condition_factory(),
*base::test::ParseJson(
- "{ \n"
- " \"resourceType\": [\"main_frame\"], \n"
- " \"url\": { \"hostSuffix\": \"example.com\" }, \n"
- " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
- "}"),
+ "{ \n"
+ " \"resourceType\": [\"main_frame\"], \n"
+ " \"url\": { \"hostSuffix\": \"example.com\" }, \n"
+ " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
+ "}"),
&error);
EXPECT_EQ("", error);
ASSERT_TRUE(result.get());
@@ -102,12 +105,13 @@ TEST(WebRequestConditionTest, CreateConditionFirstPartyForCookies) {
scoped_ptr<WebRequestCondition> result;
result = WebRequestCondition::Create(
+ NULL,
matcher.condition_factory(),
*base::test::ParseJson(
- "{ \n"
- " \"firstPartyForCookiesUrl\": { \"hostPrefix\": \"fpfc\"}, \n"
- " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
- "}"),
+ "{ \n"
+ " \"firstPartyForCookiesUrl\": { \"hostPrefix\": \"fpfc\"}, \n"
+ " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
+ "}"),
&error);
EXPECT_EQ("", error);
ASSERT_TRUE(result.get());
@@ -146,11 +150,12 @@ TEST(WebRequestConditionTest, NoUrlAttributes) {
// The empty condition.
error.clear();
scoped_ptr<WebRequestCondition> condition_empty = WebRequestCondition::Create(
+ NULL,
matcher.condition_factory(),
*base::test::ParseJson(
- "{ \n"
- " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
- "}"),
+ "{ \n"
+ " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
+ "}"),
&error);
EXPECT_EQ("", error);
ASSERT_TRUE(condition_empty.get());
@@ -159,14 +164,16 @@ TEST(WebRequestConditionTest, NoUrlAttributes) {
error.clear();
scoped_ptr<WebRequestCondition> condition_no_url_true =
WebRequestCondition::Create(
+ NULL,
matcher.condition_factory(),
*base::test::ParseJson(
- "{ \n"
- " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
- // There is no "1st party for cookies" URL in the requests below,
- // therefore all requests are considered first party for cookies.
- " \"thirdPartyForCookies\": false, \n"
- "}"),
+ "{ \n"
+ " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", "
+ "\n"
+ // There is no "1st party for cookies" URL in the requests below,
+ // therefore all requests are considered first party for cookies.
+ " \"thirdPartyForCookies\": false, \n"
+ "}"),
&error);
EXPECT_EQ("", error);
ASSERT_TRUE(condition_no_url_true.get());
@@ -175,12 +182,14 @@ TEST(WebRequestConditionTest, NoUrlAttributes) {
error.clear();
scoped_ptr<WebRequestCondition> condition_no_url_false =
WebRequestCondition::Create(
+ NULL,
matcher.condition_factory(),
*base::test::ParseJson(
- "{ \n"
- " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
- " \"thirdPartyForCookies\": true, \n"
- "}"),
+ "{ \n"
+ " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", "
+ "\n"
+ " \"thirdPartyForCookies\": true, \n"
+ "}"),
&error);
EXPECT_EQ("", error);
ASSERT_TRUE(condition_no_url_false.get());
@@ -231,9 +240,8 @@ TEST(WebRequestConditionTest, CreateConditionSet) {
// Test insertion
std::string error;
- scoped_ptr<WebRequestConditionSet> result =
- WebRequestConditionSet::Create(matcher.condition_factory(),
- conditions, &error);
+ scoped_ptr<WebRequestConditionSet> result = WebRequestConditionSet::Create(
+ NULL, matcher.condition_factory(), conditions, &error);
EXPECT_EQ("", error);
ASSERT_TRUE(result.get());
EXPECT_EQ(2u, result->conditions().size());
@@ -289,9 +297,8 @@ TEST(WebRequestConditionTest, TestPortFilter) {
// Test insertion
std::string error;
- scoped_ptr<WebRequestConditionSet> result =
- WebRequestConditionSet::Create(matcher.condition_factory(),
- conditions, &error);
+ scoped_ptr<WebRequestConditionSet> result = WebRequestConditionSet::Create(
+ NULL, matcher.condition_factory(), conditions, &error);
EXPECT_EQ("", error);
ASSERT_TRUE(result.get());
EXPECT_EQ(1u, result->conditions().size());
@@ -340,15 +347,16 @@ TEST(WebRequestConditionTest, ConditionsWithConflictingStages) {
// Test error on incompatible application stages for involved attributes.
error.clear();
result = WebRequestCondition::Create(
+ NULL,
matcher.condition_factory(),
*base::test::ParseJson(
- "{ \n"
- " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
- // Pass a JS array with one empty object to each of the header
- // filters.
- " \"requestHeaders\": [{}], \n"
- " \"responseHeaders\": [{}], \n"
- "}"),
+ "{ \n"
+ " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
+ // Pass a JS array with one empty object to each of the header
+ // filters.
+ " \"requestHeaders\": [{}], \n"
+ " \"responseHeaders\": [{}], \n"
+ "}"),
&error);
EXPECT_FALSE(error.empty());
EXPECT_FALSE(result.get());
diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.cc
index a72edc5d6c..7dc19f7ade 100644
--- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.cc
+++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.cc
@@ -178,7 +178,7 @@ std::string WebRequestRulesRegistry::AddRulesImpl(
scoped_ptr<WebRequestRule> webrequest_rule(WebRequestRule::Create(
url_matcher_.condition_factory(),
- extension_id, extension_installation_time, *rule,
+ extension, extension_installation_time, *rule,
base::Bind(&Checker, base::Unretained(extension)),
&error));
if (!error.empty()) {
diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc
index 2b345147fd..29f7791d5c 100644
--- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc
+++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc
@@ -690,13 +690,13 @@ TEST(WebRequestRulesRegistrySimpleTest, StageChecker) {
URLMatcher matcher;
scoped_ptr<WebRequestConditionSet> conditions =
WebRequestConditionSet::Create(
- matcher.condition_factory(), rule.conditions, &error);
+ NULL, matcher.condition_factory(), rule.conditions, &error);
ASSERT_TRUE(error.empty()) << error;
ASSERT_TRUE(conditions);
bool bad_message = false;
scoped_ptr<WebRequestActionSet> actions =
- WebRequestActionSet::Create(rule.actions, &error, &bad_message);
+ WebRequestActionSet::Create(NULL, rule.actions, &error, &bad_message);
ASSERT_TRUE(error.empty()) << error;
ASSERT_FALSE(bad_message);
ASSERT_TRUE(actions);
@@ -723,7 +723,7 @@ TEST(WebRequestRulesRegistrySimpleTest, HostPermissionsChecker) {
std::string error;
bool bad_message = false;
scoped_ptr<WebRequestActionSet> action_set(
- WebRequestActionSet::Create(actions, &error, &bad_message));
+ WebRequestActionSet::Create(NULL, actions, &error, &bad_message));
ASSERT_TRUE(error.empty()) << error;
ASSERT_FALSE(bad_message);
ASSERT_TRUE(action_set);
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api.cc b/chrome/browser/extensions/api/developer_private/developer_private_api.cc
index bd92c260a2..eb81a66e71 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_api.cc
+++ b/chrome/browser/extensions/api/developer_private/developer_private_api.cc
@@ -27,6 +27,7 @@
#include "chrome/browser/extensions/extension_error_reporter.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/extensions/management_policy.h"
#include "chrome/browser/extensions/unpacked_installer.h"
#include "chrome/browser/extensions/updater/extension_updater.h"
@@ -341,9 +342,10 @@ scoped_ptr<developer::ItemInfo>
}
}
- info->incognito_enabled = service->IsIncognitoEnabled(item.id());
+ info->incognito_enabled =
+ extension_util::IsIncognitoEnabled(item.id(),service);
info->wants_file_access = item.wants_file_access();
- info->allow_file_access = service->AllowFileAccess(&item);
+ info->allow_file_access = extension_util::AllowFileAccess(&item, service);
info->allow_reload = Manifest::IsUnpackedLocation(item.location());
info->is_unpacked = Manifest::IsUnpackedLocation(item.location());
info->terminated = service->terminated_extensions()->Contains(item.id());
@@ -608,7 +610,7 @@ bool DeveloperPrivateAllowFileAccessFunction::RunImpl() {
<< extension->id();
result = false;
} else {
- service->SetAllowFileAccess(extension, params->allow);
+ extension_util::SetAllowFileAccess(extension, service, params->allow);
result = true;
}
@@ -630,7 +632,8 @@ bool DeveloperPrivateAllowIncognitoFunction::RunImpl() {
if (!extension)
result = false;
else
- service->SetIsIncognitoEnabled(extension->id(), params->allow);
+ extension_util::SetIsIncognitoEnabled(
+ extension->id(),service, params->allow);
return result;
}
diff --git a/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc b/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
index 6c819b0583..a26c662a26 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
+++ b/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
@@ -473,6 +473,7 @@ class DownloadExtensionTest : public ExtensionApiTest {
GURL slow_download_url(URLRequestSlowDownloadJob::kUnknownSizeUrl);
DownloadManager* manager = GetCurrentManager();
+ EXPECT_EQ(0, manager->NonMaliciousInProgressCount());
EXPECT_EQ(0, manager->InProgressCount());
if (manager->InProgressCount() != 0)
return NULL;
@@ -3345,6 +3346,7 @@ IN_PROC_BROWSER_TEST_F(
scoped_ptr<content::DownloadTestObserver> observer(
new JustInProgressDownloadObserver(manager, 1));
ASSERT_EQ(0, manager->InProgressCount());
+ ASSERT_EQ(0, manager->NonMaliciousInProgressCount());
// Tabs created just for a download are automatically closed, invalidating
// the download's WebContents. Downloads without WebContents cannot be
// resumed. http://crbug.com/225901
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys_private/OWNERS b/chrome/browser/extensions/api/enterprise_platform_keys_private/OWNERS
index 14072cbf8d..a48744dcca 100644
--- a/chrome/browser/extensions/api/enterprise_platform_keys_private/OWNERS
+++ b/chrome/browser/extensions/api/enterprise_platform_keys_private/OWNERS
@@ -1,2 +1,3 @@
mnissler@chromium.org
-
+pastarmovj@chromium.org
+bartfab@chromium.org
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.cc b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.cc
index a5a70a7393..b1078c6b94 100644
--- a/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.cc
+++ b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.cc
@@ -146,18 +146,20 @@ std::string EPKPChallengeKeyBase::GetDeviceId() const {
void EPKPChallengeKeyBase::PrepareKey(
chromeos::attestation::AttestationKeyType key_type,
+ const std::string& user_id,
const std::string& key_name,
chromeos::attestation::AttestationCertificateProfile certificate_profile,
bool require_user_consent,
const base::Callback<void(PrepareKeyResult)>& callback) {
cryptohome_client_->TpmAttestationDoesKeyExist(
- key_type, key_name, base::Bind(
+ key_type, user_id, key_name, base::Bind(
&EPKPChallengeKeyBase::DoesKeyExistCallback, this,
- certificate_profile, require_user_consent, callback));
+ certificate_profile, user_id, require_user_consent, callback));
}
void EPKPChallengeKeyBase::DoesKeyExistCallback(
chromeos::attestation::AttestationCertificateProfile certificate_profile,
+ const std::string& user_id,
bool require_user_consent,
const base::Callback<void(PrepareKeyResult)>& callback,
chromeos::DBusMethodCallStatus status,
@@ -177,10 +179,11 @@ void EPKPChallengeKeyBase::DoesKeyExistCallback(
// information to PCA.
AskForUserConsent(
base::Bind(&EPKPChallengeKeyBase::AskForUserConsentCallback, this,
- certificate_profile, callback));
+ certificate_profile, user_id, callback));
} else {
// User consent is not required. Skip to the next step.
- AskForUserConsentCallback(certificate_profile, callback, true);
+ AskForUserConsentCallback(certificate_profile, user_id, callback,
+ true);
}
}
}
@@ -194,6 +197,7 @@ void EPKPChallengeKeyBase::AskForUserConsent(
void EPKPChallengeKeyBase::AskForUserConsentCallback(
chromeos::attestation::AttestationCertificateProfile certificate_profile,
+ const std::string& user_id,
const base::Callback<void(PrepareKeyResult)>& callback,
bool result) {
if (!result) {
@@ -205,7 +209,7 @@ void EPKPChallengeKeyBase::AskForUserConsentCallback(
// Generate a new key and have it signed by PCA.
attestation_flow_->GetCertificate(
certificate_profile,
- std::string(), // Not used.
+ user_id,
std::string(), // Not used.
true, // Force a new key to be generated.
base::Bind(&EPKPChallengeKeyBase::GetCertificateCallback, this,
@@ -296,6 +300,7 @@ void EPKPChallengeMachineKey::GetDeviceAttestationEnabledCallback(
}
PrepareKey(chromeos::attestation::KEY_DEVICE,
+ std::string(), // Not used.
kKeyName,
chromeos::attestation::PROFILE_ENTERPRISE_MACHINE_CERTIFICATE,
false, // user consent is not required.
@@ -314,6 +319,7 @@ void EPKPChallengeMachineKey::PrepareKeyCallback(
// Everything is checked. Sign the challenge.
async_caller_->TpmAttestationSignEnterpriseChallenge(
chromeos::attestation::KEY_DEVICE,
+ std::string(), // Not used.
kKeyName,
GetEnterpriseDomain(),
GetDeviceId(),
@@ -441,6 +447,7 @@ void EPKPChallengeUserKey::GetDeviceAttestationEnabledCallback(
}
PrepareKey(chromeos::attestation::KEY_USER,
+ GetUserEmail(),
kKeyName,
chromeos::attestation::PROFILE_ENTERPRISE_USER_CERTIFICATE,
require_user_consent,
@@ -460,6 +467,7 @@ void EPKPChallengeUserKey::PrepareKeyCallback(const std::string& challenge,
// Everything is checked. Sign the challenge.
async_caller_->TpmAttestationSignEnterpriseChallenge(
chromeos::attestation::KEY_USER,
+ GetUserEmail(),
kKeyName,
GetUserEmail(),
GetDeviceId(),
@@ -483,6 +491,7 @@ void EPKPChallengeUserKey::SignChallengeCallback(bool register_key,
if (register_key) {
async_caller_->TpmAttestationRegisterKey(
chromeos::attestation::KEY_USER,
+ GetUserEmail(),
kKeyName,
base::Bind(&EPKPChallengeUserKey::RegisterKeyCallback, this, response));
} else {
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.h b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.h
index 2619f6035a..80e6b9fb6b 100644
--- a/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.h
+++ b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.h
@@ -92,6 +92,7 @@ class EPKPChallengeKeyBase : public AsyncExtensionFunction {
// user consent before calling GetCertificate().
void PrepareKey(
chromeos::attestation::AttestationKeyType key_type,
+ const std::string& user_id,
const std::string& key_name,
chromeos::attestation::AttestationCertificateProfile certificate_profile,
bool require_user_consent,
@@ -105,6 +106,7 @@ class EPKPChallengeKeyBase : public AsyncExtensionFunction {
private:
void DoesKeyExistCallback(
chromeos::attestation::AttestationCertificateProfile certificate_profile,
+ const std::string& user_id,
bool require_user_consent,
const base::Callback<void(PrepareKeyResult)>& callback,
chromeos::DBusMethodCallStatus status,
@@ -112,6 +114,7 @@ class EPKPChallengeKeyBase : public AsyncExtensionFunction {
void AskForUserConsent(const base::Callback<void(bool)>& callback) const;
void AskForUserConsentCallback(
chromeos::attestation::AttestationCertificateProfile certificate_profile,
+ const std::string& user_id,
const base::Callback<void(PrepareKeyResult)>& callback,
bool result);
void GetCertificateCallback(
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc
index f592549db3..c4698745e4 100644
--- a/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc
+++ b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc
@@ -38,6 +38,7 @@ namespace {
void DoesKeyExistCallbackTrue(
chromeos::attestation::AttestationKeyType key_type,
+ const std::string& user_id,
const std::string& key_name,
const chromeos::BoolDBusMethodCallback& callback) {
callback.Run(chromeos::DBUS_METHOD_CALL_SUCCESS, true);
@@ -45,6 +46,7 @@ void DoesKeyExistCallbackTrue(
void DoesKeyExistCallbackFalse(
chromeos::attestation::AttestationKeyType key_type,
+ const std::string& user_id,
const std::string& key_name,
const chromeos::BoolDBusMethodCallback& callback) {
callback.Run(chromeos::DBUS_METHOD_CALL_SUCCESS, false);
@@ -52,6 +54,7 @@ void DoesKeyExistCallbackFalse(
void DoesKeyExistCallbackFailed(
chromeos::attestation::AttestationKeyType key_type,
+ const std::string& user_id,
const std::string& key_name,
const chromeos::BoolDBusMethodCallback& callback) {
callback.Run(chromeos::DBUS_METHOD_CALL_FAILURE, false);
@@ -59,6 +62,7 @@ void DoesKeyExistCallbackFailed(
void RegisterKeyCallbackTrue(
chromeos::attestation::AttestationKeyType key_type,
+ const std::string& user_id,
const std::string& key_name,
const cryptohome::AsyncMethodCaller::Callback& callback) {
callback.Run(true, cryptohome::MOUNT_ERROR_NONE);
@@ -66,6 +70,7 @@ void RegisterKeyCallbackTrue(
void RegisterKeyCallbackFalse(
chromeos::attestation::AttestationKeyType key_type,
+ const std::string& user_id,
const std::string& key_name,
const cryptohome::AsyncMethodCaller::Callback& callback) {
callback.Run(false, cryptohome::MOUNT_ERROR_NONE);
@@ -73,6 +78,7 @@ void RegisterKeyCallbackFalse(
void SignChallengeCallbackTrue(
chromeos::attestation::AttestationKeyType key_type,
+ const std::string& user_id,
const std::string& key_name,
const std::string& domain,
const std::string& device_id,
@@ -84,6 +90,7 @@ void SignChallengeCallbackTrue(
void SignChallengeCallbackFalse(
chromeos::attestation::AttestationKeyType key_type,
+ const std::string& user_id,
const std::string& key_name,
const std::string& domain,
const std::string& device_id,
@@ -95,7 +102,7 @@ void SignChallengeCallbackFalse(
void GetCertificateCallbackTrue(
chromeos::attestation::AttestationCertificateProfile certificate_profile,
- const std::string& user_email,
+ const std::string& user_id,
const std::string& request_origin,
bool force_new_key,
const chromeos::attestation::AttestationFlow::CertificateCallback&
@@ -105,7 +112,7 @@ void GetCertificateCallbackTrue(
void GetCertificateCallbackFalse(
chromeos::attestation::AttestationCertificateProfile certificate_profile,
- const std::string& user_email,
+ const std::string& user_id,
const std::string& request_origin,
bool force_new_key,
const chromeos::attestation::AttestationFlow::CertificateCallback&
@@ -118,12 +125,12 @@ class EPKPChallengeKeyTestBase : public BrowserWithTestWindowTest {
EPKPChallengeKeyTestBase()
: extension_(utils::CreateEmptyExtension("")) {
// Set up the default behavior of mocks.
- ON_CALL(mock_cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _))
+ ON_CALL(mock_cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _, _))
.WillByDefault(Invoke(DoesKeyExistCallbackFalse));
- ON_CALL(mock_async_method_caller_, TpmAttestationRegisterKey(_, _, _))
+ ON_CALL(mock_async_method_caller_, TpmAttestationRegisterKey(_, _, _, _))
.WillByDefault(Invoke(RegisterKeyCallbackTrue));
ON_CALL(mock_async_method_caller_,
- TpmAttestationSignEnterpriseChallenge(_, _, _, _, _, _, _))
+ TpmAttestationSignEnterpriseChallenge(_, _, _, _, _, _, _, _))
.WillByDefault(Invoke(SignChallengeCallbackTrue));
ON_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _))
.WillByDefault(Invoke(GetCertificateCallbackTrue));
@@ -231,7 +238,7 @@ TEST_F(EPKPChallengeMachineKeyTest, DevicePolicyDisabled) {
}
TEST_F(EPKPChallengeMachineKeyTest, DoesKeyExistDbusFailed) {
- EXPECT_CALL(mock_cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _))
+ EXPECT_CALL(mock_cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _, _))
.WillRepeatedly(Invoke(DoesKeyExistCallbackFailed));
EXPECT_EQ(base::StringPrintf(
@@ -250,7 +257,7 @@ TEST_F(EPKPChallengeMachineKeyTest, GetCertificateFailed) {
TEST_F(EPKPChallengeMachineKeyTest, SignChallengeFailed) {
EXPECT_CALL(mock_async_method_caller_,
- TpmAttestationSignEnterpriseChallenge(_, _, _, _, _, _, _))
+ TpmAttestationSignEnterpriseChallenge(_, _, _, _, _, _, _, _))
.WillRepeatedly(Invoke(SignChallengeCallbackFalse));
EXPECT_EQ(EPKPChallengeKeyBase::kSignChallengeFailedError,
@@ -258,7 +265,7 @@ TEST_F(EPKPChallengeMachineKeyTest, SignChallengeFailed) {
}
TEST_F(EPKPChallengeMachineKeyTest, KeyExists) {
- EXPECT_CALL(mock_cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _))
+ EXPECT_CALL(mock_cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _, _))
.WillRepeatedly(Invoke(DoesKeyExistCallbackTrue));
// GetCertificate must not be called if the key exists.
EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _))
@@ -277,7 +284,7 @@ TEST_F(EPKPChallengeMachineKeyTest, Success) {
// SignEnterpriseChallenge must be called exactly once.
EXPECT_CALL(mock_async_method_caller_,
TpmAttestationSignEnterpriseChallenge(
- chromeos::attestation::KEY_DEVICE, "attest-ent-machine",
+ chromeos::attestation::KEY_DEVICE, "", "attest-ent-machine",
"google.com", "device_id", _, "challenge", _))
.Times(1);
@@ -351,7 +358,7 @@ TEST_F(EPKPChallengeUserKeyTest, DevicePolicyDisabled) {
}
TEST_F(EPKPChallengeUserKeyTest, DoesKeyExistDbusFailed) {
- EXPECT_CALL(mock_cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _))
+ EXPECT_CALL(mock_cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _, _))
.WillRepeatedly(Invoke(DoesKeyExistCallbackFailed));
EXPECT_EQ(base::StringPrintf(
@@ -370,7 +377,7 @@ TEST_F(EPKPChallengeUserKeyTest, GetCertificateFailed) {
TEST_F(EPKPChallengeUserKeyTest, SignChallengeFailed) {
EXPECT_CALL(mock_async_method_caller_,
- TpmAttestationSignEnterpriseChallenge(_, _, _, _, _, _, _))
+ TpmAttestationSignEnterpriseChallenge(_, _, _, _, _, _, _, _))
.WillRepeatedly(Invoke(SignChallengeCallbackFalse));
EXPECT_EQ(EPKPChallengeKeyBase::kSignChallengeFailedError,
@@ -378,7 +385,7 @@ TEST_F(EPKPChallengeUserKeyTest, SignChallengeFailed) {
}
TEST_F(EPKPChallengeUserKeyTest, KeyRegistrationFailed) {
- EXPECT_CALL(mock_async_method_caller_, TpmAttestationRegisterKey(_, _, _))
+ EXPECT_CALL(mock_async_method_caller_, TpmAttestationRegisterKey(_, _, _, _))
.WillRepeatedly(Invoke(RegisterKeyCallbackFalse));
EXPECT_EQ(EPKPChallengeUserKey::kKeyRegistrationFailedError,
@@ -386,7 +393,7 @@ TEST_F(EPKPChallengeUserKeyTest, KeyRegistrationFailed) {
}
TEST_F(EPKPChallengeUserKeyTest, KeyExists) {
- EXPECT_CALL(mock_cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _))
+ EXPECT_CALL(mock_cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _, _))
.WillRepeatedly(Invoke(DoesKeyExistCallbackTrue));
// GetCertificate must not be called if the key exists.
EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _))
@@ -396,7 +403,7 @@ TEST_F(EPKPChallengeUserKeyTest, KeyExists) {
}
TEST_F(EPKPChallengeUserKeyTest, KeyNotRegistered) {
- EXPECT_CALL(mock_async_method_caller_, TpmAttestationRegisterKey(_, _, _))
+ EXPECT_CALL(mock_async_method_caller_, TpmAttestationRegisterKey(_, _, _, _))
.Times(0);
EXPECT_TRUE(utils::RunFunction(
@@ -421,12 +428,14 @@ TEST_F(EPKPChallengeUserKeyTest, Success) {
// SignEnterpriseChallenge must be called exactly once.
EXPECT_CALL(mock_async_method_caller_,
TpmAttestationSignEnterpriseChallenge(
- chromeos::attestation::KEY_USER, "attest-ent-user",
- "test@google.com", "device_id", _, "challenge", _))
+ chromeos::attestation::KEY_USER, "test@google.com",
+ "attest-ent-user", "test@google.com", "device_id", _,
+ "challenge", _))
.Times(1);
// RegisterKey must be called exactly once.
EXPECT_CALL(mock_async_method_caller_,
TpmAttestationRegisterKey(chromeos::attestation::KEY_USER,
+ "test@google.com",
"attest-ent-user", _))
.Times(1);
diff --git a/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc b/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc
index 06017801b9..dc680e3017 100644
--- a/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc
+++ b/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc
@@ -120,7 +120,8 @@ IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, Basic) {
ExtensionService* service = extensions::ExtensionSystem::Get(
browser()->profile())->extension_service();
- service->toolbar_model()->ExecuteBrowserAction(extension, browser(), NULL);
+ service->toolbar_model()->ExecuteBrowserAction(
+ extension, browser(), NULL, true);
ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
}
@@ -590,7 +591,7 @@ IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, DISABLED_CloseBackgroundPage) {
// Click the browser action.
extensions::ExtensionSystem::Get(browser()->profile())->extension_service()->
- toolbar_model()->ExecuteBrowserAction(extension, browser(), NULL);
+ toolbar_model()->ExecuteBrowserAction(extension, browser(), NULL, true);
// It can take a moment for the background page to actually get destroyed
// so we wait for the notification before checking that it's really gone
diff --git a/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc b/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc
new file mode 100644
index 0000000000..0236ca69d7
--- /dev/null
+++ b/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc
@@ -0,0 +1,193 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/browser_action_test_util.h"
+#include "chrome/browser/extensions/extension_action.h"
+#include "chrome/browser/extensions/extension_action_manager.h"
+#include "chrome/browser/extensions/extension_apitest.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/extension_tab_util.h"
+#include "chrome/browser/extensions/extension_test_message_listener.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/extensions/permissions/permissions_data.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/web_contents.h"
+
+namespace extensions {
+namespace {
+
+// chrome.browserAction API tests that interact with the UI in such a way that
+// they cannot be run concurrently (i.e. openPopup API tests that require the
+// window be focused/active).
+class BrowserActionInteractiveTest : public ExtensionApiTest {
+ public:
+ BrowserActionInteractiveTest() {}
+ virtual ~BrowserActionInteractiveTest() {}
+
+ protected:
+ // Function to control whether to run popup tests for the current platform.
+ // These tests require RunExtensionSubtest to work as expected and the browser
+ // window to able to be made active automatically. Returns false for platforms
+ // where these conditions are not met.
+ bool ShouldRunPopupTest() {
+ // TODO(justinlin): http://crbug.com/177163
+#if defined(OS_WIN) && !defined(NDEBUG)
+ return false;
+#elif defined(OS_MACOSX)
+ // TODO(justinlin): Browser window do not become active on Mac even when
+ // Activate() is called on them. Enable when/if it's possible to fix.
+ return false;
+#else
+ return true;
+#endif
+ }
+};
+
+// Tests opening a popup using the chrome.browserAction.openPopup API. This test
+// opens a popup in the starting window, closes the popup, creates a new window
+// and opens a popup in the new window. Both popups should succeed in opening.
+IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, TestOpenPopup) {
+ if (!ShouldRunPopupTest())
+ return;
+
+ BrowserActionTestUtil browserActionBar = BrowserActionTestUtil(browser());
+ // Setup extension message listener to wait for javascript to finish running.
+ ExtensionTestMessageListener listener("ready", true);
+ {
+ // Setup the notification observer to wait for the popup to finish loading.
+ content::WindowedNotificationObserver frame_observer(
+ content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
+ content::NotificationService::AllSources());
+ // Show first popup in first window and expect it to have loaded.
+ ASSERT_TRUE(RunExtensionSubtest("browser_action/open_popup",
+ "open_popup_succeeds.html")) << message_;
+ frame_observer.Wait();
+ EXPECT_TRUE(browserActionBar.HasPopup());
+ browserActionBar.HidePopup();
+ }
+
+ EXPECT_TRUE(listener.WaitUntilSatisfied());
+ Browser* new_browser = NULL;
+ {
+ content::WindowedNotificationObserver frame_observer(
+ content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
+ content::NotificationService::AllSources());
+ // Open a new window.
+ new_browser = chrome::FindBrowserWithWebContents(
+ browser()->OpenURL(content::OpenURLParams(
+ GURL("about:"), content::Referrer(), NEW_WINDOW,
+ content::PAGE_TRANSITION_TYPED, false)));
+#if defined(OS_WIN)
+ // Hide all the buttons to test that it opens even when browser action is
+ // in the overflow bucket.
+ // TODO(justinlin): Implement for other platforms.
+ browserActionBar.SetIconVisibilityCount(0);
+#endif
+ frame_observer.Wait();
+ }
+
+ ResultCatcher catcher;
+ {
+ content::WindowedNotificationObserver frame_observer(
+ content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
+ content::NotificationService::AllSources());
+ // Show second popup in new window.
+ listener.Reply("");
+ frame_observer.Wait();
+ EXPECT_TRUE(BrowserActionTestUtil(new_browser).HasPopup());
+ }
+ ASSERT_TRUE(catcher.GetNextResult()) << message_;
+}
+
+// Tests opening a popup in an incognito window.
+IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, TestOpenPopupIncognito) {
+ if (!ShouldRunPopupTest())
+ return;
+
+ content::WindowedNotificationObserver frame_observer(
+ content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
+ content::NotificationService::AllSources());
+ ASSERT_TRUE(RunExtensionSubtest("browser_action/open_popup",
+ "open_popup_succeeds.html",
+ kFlagEnableIncognito | kFlagUseIncognito))
+ << message_;
+ frame_observer.Wait();
+ // Non-Aura Linux uses a singleton for the popup, so it looks like all windows
+ // have popups if there is any popup open.
+#if !(defined(OS_LINUX) && !defined(USE_AURA))
+ // Starting window does not have a popup.
+ EXPECT_FALSE(BrowserActionTestUtil(browser()).HasPopup());
+#endif
+ // Incognito window should have a popup.
+ EXPECT_TRUE(BrowserActionTestUtil(BrowserList::GetInstance(
+ chrome::GetActiveDesktop())->GetLastActive()).HasPopup());
+}
+
+#if defined(OS_LINUX)
+#define MAYBE_TestOpenPopupDoesNotCloseOtherPopups DISABLED_TestOpenPopupDoesNotCloseOtherPopups
+#else
+#define MAYBE_TestOpenPopupDoesNotCloseOtherPopups TestOpenPopupDoesNotCloseOtherPopups
+#endif
+// Tests if there is already a popup open (by a user click or otherwise), that
+// the openPopup API does not override it.
+IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest,
+ MAYBE_TestOpenPopupDoesNotCloseOtherPopups) {
+ if (!ShouldRunPopupTest())
+ return;
+
+ // Load a first extension that can open a popup.
+ ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII(
+ "browser_action/popup")));
+ const Extension* extension = GetSingleLoadedExtension();
+ ASSERT_TRUE(extension) << message_;
+
+ ExtensionTestMessageListener listener("ready", true);
+ // Load the test extension which will do nothing except notifyPass() to
+ // return control here.
+ ASSERT_TRUE(RunExtensionSubtest("browser_action/open_popup",
+ "open_popup_fails.html")) << message_;
+ EXPECT_TRUE(listener.WaitUntilSatisfied());
+
+ content::WindowedNotificationObserver frame_observer(
+ content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
+ content::NotificationService::AllSources());
+ // Open popup in the first extension.
+ BrowserActionTestUtil(browser()).Press(0);
+ frame_observer.Wait();
+ EXPECT_TRUE(BrowserActionTestUtil(browser()).HasPopup());
+
+ ResultCatcher catcher;
+ // Return control to javascript to validate that opening a popup fails now.
+ listener.Reply("");
+ ASSERT_TRUE(catcher.GetNextResult()) << message_;
+}
+
+// Test that openPopup does not grant tab permissions like for browser action
+// clicks if the activeTab permission is set.
+IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest,
+ TestOpenPopupDoesNotGrantTabPermissions) {
+ if (!ShouldRunPopupTest())
+ return;
+
+ content::WindowedNotificationObserver frame_observer(
+ content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
+ content::NotificationService::AllSources());
+ ASSERT_TRUE(RunExtensionSubtest("browser_action/open_popup",
+ "open_popup_succeeds.html")) << message_;
+ frame_observer.Wait();
+
+ ExtensionService* service = extensions::ExtensionSystem::Get(
+ browser()->profile())->extension_service();
+ ASSERT_FALSE(PermissionsData::HasAPIPermissionForTab(
+ service->GetExtensionById(last_loaded_extension_id(), false),
+ SessionID::IdForTab(browser()->tab_strip_model()->GetActiveWebContents()),
+ APIPermission::kTab));
+}
+
+} // namespace
+} // namespace extensions
diff --git a/chrome/browser/extensions/api/extension_action/extension_action_api.cc b/chrome/browser/extensions/api/extension_action/extension_action_api.cc
index 98e73ee428..1024b83571 100644
--- a/chrome/browser/extensions/api/extension_action/extension_action_api.cc
+++ b/chrome/browser/extensions/api/extension_action/extension_action_api.cc
@@ -4,8 +4,6 @@
#include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
-#include <string>
-
#include "base/base64.h"
#include "base/lazy_instance.h"
#include "base/strings/string_number_conversions.h"
@@ -17,6 +15,7 @@
#include "chrome/browser/extensions/extension_action.h"
#include "chrome/browser/extensions/extension_action_manager.h"
#include "chrome/browser/extensions/extension_function_registry.h"
+#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/extensions/extension_tab_util.h"
@@ -59,6 +58,10 @@ const char kNoTabError[] = "No tab with id: *.";
const char kNoPageActionError[] =
"This extension has no page action specified.";
const char kUrlNotActiveError[] = "This url is no longer active: *.";
+const char kOpenPopupError[] =
+ "Failed to show popup either because there is an existing popup or another "
+ "error occurred.";
+const char kInternalError[] = "Internal error.";
struct IconRepresentationInfo {
// Size as a string that will be used to retrieve representation value from
@@ -209,6 +212,7 @@ ExtensionActionAPI::ExtensionActionAPI(Profile* profile) {
registry->RegisterFunction<BrowserActionGetPopupFunction>();
registry->RegisterFunction<BrowserActionEnableFunction>();
registry->RegisterFunction<BrowserActionDisableFunction>();
+ registry->RegisterFunction<BrowserActionOpenPopupFunction>();
// Page Actions
registry->RegisterFunction<EnablePageActionsFunction>();
@@ -805,6 +809,65 @@ bool ExtensionActionGetBadgeBackgroundColorFunction::RunExtensionAction() {
return true;
}
+BrowserActionOpenPopupFunction::BrowserActionOpenPopupFunction()
+ : response_sent_(false) {
+}
+
+bool BrowserActionOpenPopupFunction::RunImpl() {
+ ExtensionToolbarModel* model = extensions::ExtensionSystem::Get(profile_)->
+ extension_service()->toolbar_model();
+ if (!model) {
+ error_ = kInternalError;
+ return false;
+ }
+
+ if (!model->ShowBrowserActionPopup(extension_)) {
+ error_ = kOpenPopupError;
+ return false;
+ }
+
+ registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING,
+ content::Source<Profile>(profile_));
+
+ // Set a timeout for waiting for the notification that the popup is loaded.
+ // Waiting is required so that the popup view can be retrieved by the custom
+ // bindings for the response callback. It's also needed to keep this function
+ // instance around until a notification is observed.
+ base::MessageLoopForUI::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&BrowserActionOpenPopupFunction::OpenPopupTimedOut, this),
+ base::TimeDelta::FromSeconds(10));
+ return true;
+}
+
+void BrowserActionOpenPopupFunction::OpenPopupTimedOut() {
+ if (response_sent_)
+ return;
+
+ DVLOG(1) << "chrome.browserAction.openPopup did not show a popup.";
+ error_ = kOpenPopupError;
+ SendResponse(false);
+ response_sent_ = true;
+}
+
+void BrowserActionOpenPopupFunction::Observe(
+ int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) {
+ DCHECK_EQ(chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING, type);
+ if (response_sent_)
+ return;
+
+ ExtensionHost* host = content::Details<ExtensionHost>(details).ptr();
+ if (host->extension_host_type() != VIEW_TYPE_EXTENSION_POPUP ||
+ host->extension()->id() != extension_->id())
+ return;
+
+ SendResponse(true);
+ response_sent_ = true;
+ registrar_.RemoveAll();
+}
+
//
// ScriptBadgeGetAttentionFunction
//
diff --git a/chrome/browser/extensions/api/extension_action/extension_action_api.h b/chrome/browser/extensions/api/extension_action/extension_action_api.h
index 692576c088..8471ae3332 100644
--- a/chrome/browser/extensions/api/extension_action/extension_action_api.h
+++ b/chrome/browser/extensions/api/extension_action/extension_action_api.h
@@ -5,6 +5,8 @@
#ifndef CHROME_BROWSER_EXTENSIONS_API_EXTENSION_ACTION_EXTENSION_ACTION_API_H_
#define CHROME_BROWSER_EXTENSIONS_API_EXTENSION_ACTION_EXTENSION_ACTION_API_H_
+#include <string>
+
#include "base/memory/weak_ptr.h"
#include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
#include "chrome/browser/extensions/extension_action.h"
@@ -341,6 +343,30 @@ class BrowserActionDisableFunction : public ExtensionActionHideFunction {
virtual ~BrowserActionDisableFunction() {}
};
+class BrowserActionOpenPopupFunction : public UIThreadExtensionFunction,
+ public content::NotificationObserver {
+ public:
+ DECLARE_EXTENSION_FUNCTION("browserAction.openPopup",
+ BROWSERACTION_OPEN_POPUP)
+ BrowserActionOpenPopupFunction();
+
+ private:
+ virtual ~BrowserActionOpenPopupFunction() {}
+
+ // ExtensionFunction:
+ virtual bool RunImpl() OVERRIDE;
+
+ virtual void Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) OVERRIDE;
+ void OpenPopupTimedOut();
+
+ content::NotificationRegistrar registrar_;
+ bool response_sent_;
+
+ DISALLOW_COPY_AND_ASSIGN(BrowserActionOpenPopupFunction);
+};
+
//
// scriptBadge.* aliases for supported scriptBadge APIs.
//
diff --git a/chrome/browser/extensions/api/extension_action/page_as_browser_action_apitest.cc b/chrome/browser/extensions/api/extension_action/page_as_browser_action_apitest.cc
index 196ecc1d7c..34eb519d7e 100644
--- a/chrome/browser/extensions/api/extension_action/page_as_browser_action_apitest.cc
+++ b/chrome/browser/extensions/api/extension_action/page_as_browser_action_apitest.cc
@@ -91,7 +91,8 @@ IN_PROC_BROWSER_TEST_F(PageAsBrowserActionApiTest, Basic) {
ResultCatcher catcher;
ExtensionService* service = extensions::ExtensionSystem::Get(
browser()->profile())->extension_service();
- service->toolbar_model()->ExecuteBrowserAction(extension, browser(), NULL);
+ service->toolbar_model()->ExecuteBrowserAction(
+ extension, browser(), NULL, true);
EXPECT_TRUE(catcher.GetNextResult());
}
@@ -135,7 +136,8 @@ IN_PROC_BROWSER_TEST_F(PageAsBrowserActionApiTest, AddPopup) {
ResultCatcher catcher;
ExtensionService* service = extensions::ExtensionSystem::Get(
browser()->profile())->extension_service();
- service->toolbar_model()->ExecuteBrowserAction(extension, browser(), NULL);
+ service->toolbar_model()->ExecuteBrowserAction(
+ extension, browser(), NULL, true);
ASSERT_TRUE(catcher.GetNextResult());
}
@@ -202,5 +204,5 @@ IN_PROC_BROWSER_TEST_F(PageAsBrowserActionApiTest, Getters) {
ASSERT_TRUE(catcher.GetNextResult());
}
-}
+} // namespace
} // namespace extensions
diff --git a/chrome/browser/extensions/api/feedback_private/feedback_browsertest.cc b/chrome/browser/extensions/api/feedback_private/feedback_browsertest.cc
new file mode 100644
index 0000000000..82c2137774
--- /dev/null
+++ b/chrome/browser/extensions/api/feedback_private/feedback_browsertest.cc
@@ -0,0 +1,92 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "apps/shell_window.h"
+#include "apps/shell_window_registry.h"
+#include "base/bind.h"
+#include "chrome/browser/apps/app_browsertest_util.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/extensions/api/feedback_private/feedback_private_api.h"
+#include "chrome/browser/extensions/component_loader.h"
+#include "chrome/browser/extensions/event_router.h"
+#include "chrome/browser/extensions/extension_browsertest.h"
+#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/common/extensions/api/feedback_private.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "content/public/common/content_switches.h"
+
+using apps::ShellWindow;
+using apps::ShellWindowRegistry;
+using extensions::Extension;
+
+namespace {
+
+void StopMessageLoopCallback() {
+ base::MessageLoopForUI::current()->Quit();
+}
+
+} // namespace
+
+namespace extensions {
+
+class FeedbackTest : public ExtensionBrowserTest {
+ public:
+ virtual void SetUp() OVERRIDE {
+ extensions::ComponentLoader::EnableBackgroundExtensionsForTesting();
+ InProcessBrowserTest::SetUp();
+ }
+
+ virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+ command_line->AppendSwitch(::switches::kEnableUserMediaScreenCapturing);
+ InProcessBrowserTest::SetUpCommandLine(command_line);
+ }
+
+ protected:
+ bool IsFeedbackAppAvailable() {
+ return extensions::ExtensionSystem::Get(
+ browser()->profile())->event_router()->ExtensionHasEventListener(
+ kFeedbackExtensionId,
+ extensions::api::feedback_private::OnFeedbackRequested::kEventName);
+ }
+
+ void StartFeedbackUI() {
+ base::Closure callback = base::Bind(&StopMessageLoopCallback);
+ extensions::FeedbackPrivateGetStringsFunction::set_test_callback(&callback);
+ InvokeFeedbackUI();
+ content::RunMessageLoop();
+ extensions::FeedbackPrivateGetStringsFunction::set_test_callback(NULL);
+ }
+
+ void VerifyFeedbackAppLaunch() {
+ ShellWindow* window =
+ PlatformAppBrowserTest::GetFirstShellWindowForBrowser(browser());
+ ASSERT_TRUE(window);
+ const Extension* feedback_app = window->extension();
+ ASSERT_TRUE(feedback_app);
+ EXPECT_EQ(feedback_app->id(), std::string(kFeedbackExtensionId));
+ }
+
+ private:
+ void InvokeFeedbackUI() {
+ extensions::FeedbackPrivateAPI* api =
+ extensions::FeedbackPrivateAPI::GetFactoryInstance()->GetForProfile(
+ browser()->profile());
+ api->RequestFeedback("Test description",
+ "Test tag",
+ GURL("http://www.test.com"));
+ }
+};
+
+IN_PROC_BROWSER_TEST_F(FeedbackTest, ShowFeedback) {
+ WaitForExtensionViewsToLoad();
+
+ ASSERT_TRUE(IsFeedbackAppAvailable());
+ StartFeedbackUI();
+ VerifyFeedbackAppLaunch();
+}
+
+} // namespace extensions
diff --git a/chrome/browser/extensions/api/feedback_private/feedback_private_api.cc b/chrome/browser/extensions/api/feedback_private/feedback_private_api.cc
index b4c67e73a1..8e7ecbab3a 100644
--- a/chrome/browser/extensions/api/feedback_private/feedback_private_api.cc
+++ b/chrome/browser/extensions/api/feedback_private/feedback_private_api.cc
@@ -18,12 +18,6 @@
#include "ui/base/webui/web_ui_util.h"
#include "url/url_util.h"
-namespace {
-
-char kFeedbackExtensionId[] = "gfdkimpbcpahaombhbimeihdjnejgicl";
-
-}
-
namespace extensions {
namespace feedback_private = api::feedback_private;
@@ -31,6 +25,8 @@ namespace feedback_private = api::feedback_private;
using feedback_private::SystemInformation;
using feedback_private::FeedbackInfo;
+char kFeedbackExtensionId[] = "gfdkimpbcpahaombhbimeihdjnejgicl";
+
static base::LazyInstance<ProfileKeyedAPIFactory<FeedbackPrivateAPI> >
g_factory = LAZY_INSTANCE_INITIALIZER;
@@ -84,6 +80,9 @@ void FeedbackPrivateAPI::RequestFeedback(
}
}
+// static
+base::Closure* FeedbackPrivateGetStringsFunction::test_callback_ = NULL;
+
bool FeedbackPrivateGetStringsFunction::RunImpl() {
DictionaryValue* dict = new DictionaryValue();
SetResult(dict);
@@ -108,6 +107,10 @@ bool FeedbackPrivateGetStringsFunction::RunImpl() {
#undef SET_STRING
webui::SetFontAndTextDirection(dict);
+
+ if (test_callback_ && !test_callback_->is_null())
+ test_callback_->Run();
+
return true;
}
diff --git a/chrome/browser/extensions/api/feedback_private/feedback_private_api.h b/chrome/browser/extensions/api/feedback_private/feedback_private_api.h
index bfdc000bcc..a4ac0459b8 100644
--- a/chrome/browser/extensions/api/feedback_private/feedback_private_api.h
+++ b/chrome/browser/extensions/api/feedback_private/feedback_private_api.h
@@ -12,6 +12,8 @@
namespace extensions {
+extern char kFeedbackExtensionId[];
+
class FeedbackService;
using extensions::api::feedback_private::SystemInformation;
@@ -49,11 +51,19 @@ class FeedbackPrivateGetStringsFunction : public SyncExtensionFunction {
DECLARE_EXTENSION_FUNCTION("feedbackPrivate.getStrings",
FEEDBACKPRIVATE_GETSTRINGS)
+ // Invoke this callback when this function is called - used for testing.
+ static void set_test_callback(base::Closure* const callback) {
+ test_callback_ = callback;
+ }
+
protected:
virtual ~FeedbackPrivateGetStringsFunction() {}
// SyncExtensionFunction overrides.
virtual bool RunImpl() OVERRIDE;
+
+ private:
+ static base::Closure* test_callback_;
};
class FeedbackPrivateGetUserEmailFunction : public SyncExtensionFunction {
diff --git a/chrome/browser/extensions/api/file_handlers/app_file_handler_util.cc b/chrome/browser/extensions/api/file_handlers/app_file_handler_util.cc
index 81648f0adb..ca64e69053 100644
--- a/chrome/browser/extensions/api/file_handlers/app_file_handler_util.cc
+++ b/chrome/browser/extensions/api/file_handlers/app_file_handler_util.cc
@@ -313,6 +313,7 @@ GrantedFileEntry CreateFileEntry(
policy->GrantReadFileSystem(renderer_id, result.filesystem_id);
if (HasFileSystemWritePermission(extension)) {
policy->GrantWriteFileSystem(renderer_id, result.filesystem_id);
+ policy->GrantDeleteFromFileSystem(renderer_id, result.filesystem_id);
if (is_directory)
policy->GrantCreateFileForFileSystem(renderer_id, result.filesystem_id);
}
diff --git a/chrome/browser/extensions/api/identity/account_tracker.cc b/chrome/browser/extensions/api/identity/account_tracker.cc
new file mode 100644
index 0000000000..03db40a97d
--- /dev/null
+++ b/chrome/browser/extensions/api/identity/account_tracker.cc
@@ -0,0 +1,244 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/api/identity/account_tracker.h"
+
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/profile_oauth2_token_service.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
+#include "chrome/browser/signin/signin_manager_base.h"
+#include "content/public/browser/notification_details.h"
+
+namespace extensions {
+
+AccountTracker::AccountTracker(Profile* profile) : profile_(profile) {
+ registrar_.Add(this,
+ chrome::NOTIFICATION_GOOGLE_SIGNED_OUT,
+ content::Source<Profile>(profile_));
+
+ ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)->AddObserver(this);
+ SigninGlobalError::GetForProfile(profile_)->AddProvider(this);
+}
+
+AccountTracker::~AccountTracker() {}
+
+void AccountTracker::ReportAuthError(const std::string& account_id,
+ const GoogleServiceAuthError& error) {
+ account_errors_.insert(make_pair(account_id, error));
+ SigninGlobalError::GetForProfile(profile_)->AuthStatusChanged();
+ UpdateSignInState(account_id, false);
+}
+
+void AccountTracker::Shutdown() {
+ STLDeleteValues(&user_info_requests_);
+ SigninGlobalError::GetForProfile(profile_)->RemoveProvider(this);
+ ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)->
+ RemoveObserver(this);
+}
+
+void AccountTracker::AddObserver(Observer* observer) {
+ observer_list_.AddObserver(observer);
+}
+
+void AccountTracker::RemoveObserver(Observer* observer) {
+ observer_list_.RemoveObserver(observer);
+}
+
+void AccountTracker::OnRefreshTokenAvailable(const std::string& account_id) {
+ DVLOG(1) << "AVAILABLE " << account_id;
+ account_errors_.erase(account_id);
+ UpdateSignInState(account_id, true);
+}
+
+void AccountTracker::OnRefreshTokenRevoked(const std::string& account_id) {
+ DVLOG(1) << "REVOKED " << account_id;
+ UpdateSignInState(account_id, false);
+}
+
+void AccountTracker::Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) {
+ switch (type) {
+ case chrome::NOTIFICATION_GOOGLE_SIGNED_OUT:
+ StopTrackingAccount(content::Details<GoogleServiceSignoutDetails>(
+ details)->username);
+ break;
+ default:
+ NOTREACHED();
+ }
+}
+
+void AccountTracker::NotifyAccountAdded(const AccountState& account) {
+ DCHECK(!account.ids.gaia.empty());
+ FOR_EACH_OBSERVER(
+ Observer, observer_list_, OnAccountAdded(account.ids));
+}
+
+void AccountTracker::NotifyAccountRemoved(const AccountState& account) {
+ DCHECK(!account.ids.gaia.empty());
+ FOR_EACH_OBSERVER(
+ Observer, observer_list_, OnAccountRemoved(account.ids));
+}
+
+void AccountTracker::NotifySignInChanged(const AccountState& account) {
+ DCHECK(!account.ids.gaia.empty());
+ FOR_EACH_OBSERVER(Observer,
+ observer_list_,
+ OnAccountSignInChanged(account.ids, account.is_signed_in));
+}
+
+void AccountTracker::UpdateSignInState(const std::string& account_key,
+ bool is_signed_in) {
+ StartTrackingAccount(account_key);
+ AccountState& account = accounts_[account_key];
+ bool needs_gaia_id = account.ids.gaia.empty();
+ bool was_signed_in = account.is_signed_in;
+ account.is_signed_in = is_signed_in;
+
+ if (needs_gaia_id && is_signed_in)
+ StartFetchingUserInfo(account_key);
+
+ if (!needs_gaia_id && (was_signed_in != is_signed_in))
+ NotifySignInChanged(account);
+}
+
+void AccountTracker::StartTrackingAccount(const std::string& account_key) {
+ if (!ContainsKey(accounts_, account_key)) {
+ DVLOG(1) << "StartTracking " << account_key;
+ AccountState account_state;
+ account_state.ids.account_key = account_key;
+ account_state.ids.email = account_key;
+ account_state.is_signed_in = false;
+ accounts_.insert(make_pair(account_key, account_state));
+ }
+}
+
+void AccountTracker::StopTrackingAccount(const std::string& account_key) {
+ if (ContainsKey(accounts_, account_key)) {
+ AccountState& account = accounts_[account_key];
+ if (!account.ids.gaia.empty()) {
+ UpdateSignInState(account_key, false);
+ NotifyAccountRemoved(account);
+ }
+ accounts_.erase(account_key);
+ }
+
+ account_errors_.erase(account_key);
+
+ if (ContainsKey(user_info_requests_, account_key))
+ DeleteFetcher(user_info_requests_[account_key]);
+}
+
+void AccountTracker::StartFetchingUserInfo(const std::string& account_key) {
+ if (ContainsKey(user_info_requests_, account_key))
+ DeleteFetcher(user_info_requests_[account_key]);
+
+ DVLOG(1) << "StartFetching " << account_key;
+ AccountIdFetcher* fetcher =
+ new AccountIdFetcher(profile_, this, account_key);
+ user_info_requests_[account_key] = fetcher;
+ fetcher->Start();
+}
+
+void AccountTracker::OnUserInfoFetchSuccess(AccountIdFetcher* fetcher,
+ const std::string& gaia_id) {
+ const std::string& account_key = fetcher->account_key();
+ DCHECK(ContainsKey(accounts_, account_key));
+ AccountState& account = accounts_[account_key];
+
+ account.ids.gaia = gaia_id;
+ NotifyAccountAdded(account);
+
+ if (account.is_signed_in)
+ NotifySignInChanged(account);
+
+ DeleteFetcher(fetcher);
+}
+
+void AccountTracker::OnUserInfoFetchFailure(AccountIdFetcher* fetcher) {
+ LOG(WARNING) << "Failed to get UserInfo for " << fetcher->account_key();
+ std::string key = fetcher->account_key();
+ DeleteFetcher(fetcher);
+ StopTrackingAccount(key);
+}
+
+std::string AccountTracker::GetAccountId() const {
+ if (account_errors_.size() == 0)
+ return std::string();
+ else
+ return account_errors_.begin()->first;
+}
+
+GoogleServiceAuthError AccountTracker::GetAuthStatus() const {
+ if (account_errors_.size() == 0)
+ return GoogleServiceAuthError::AuthErrorNone();
+ else
+ return account_errors_.begin()->second;
+}
+
+void AccountTracker::DeleteFetcher(AccountIdFetcher* fetcher) {
+ const std::string& account_key = fetcher->account_key();
+ DCHECK(ContainsKey(user_info_requests_, account_key));
+ DCHECK_EQ(fetcher, user_info_requests_[account_key]);
+ user_info_requests_.erase(account_key);
+ delete fetcher;
+}
+
+AccountIdFetcher::AccountIdFetcher(Profile* profile,
+ AccountTracker* tracker,
+ const std::string& account_key)
+ : profile_(profile),
+ tracker_(tracker),
+ account_key_(account_key) {}
+
+AccountIdFetcher::~AccountIdFetcher() {}
+
+void AccountIdFetcher::Start() {
+ ProfileOAuth2TokenService* service =
+ ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
+ login_token_request_ = service->StartRequest(
+ account_key_, OAuth2TokenService::ScopeSet(), this);
+}
+
+void AccountIdFetcher::OnGetTokenSuccess(
+ const OAuth2TokenService::Request* request,
+ const std::string& access_token,
+ const base::Time& expiration_time) {
+ DCHECK_EQ(request, login_token_request_.get());
+
+ gaia_oauth_client_.reset(new gaia::GaiaOAuthClient(
+ g_browser_process->system_request_context()));
+
+ const int kMaxGetUserIdRetries = 3;
+ gaia_oauth_client_->GetUserId(access_token, kMaxGetUserIdRetries, this);
+}
+
+void AccountIdFetcher::OnGetTokenFailure(
+ const OAuth2TokenService::Request* request,
+ const GoogleServiceAuthError& error) {
+ LOG(ERROR) << "OnGetTokenFailure: " << error.error_message();
+ DCHECK_EQ(request, login_token_request_.get());
+ tracker_->OnUserInfoFetchFailure(this);
+}
+
+void AccountIdFetcher::OnGetUserIdResponse(const std::string& gaia_id) {
+ tracker_->OnUserInfoFetchSuccess(this, gaia_id);
+}
+
+void AccountIdFetcher::OnOAuthError() {
+ LOG(ERROR) << "OnOAuthError";
+ tracker_->OnUserInfoFetchFailure(this);
+}
+
+void AccountIdFetcher::OnNetworkError(int response_code) {
+ LOG(ERROR) << "OnNetworkError " << response_code;
+ tracker_->OnUserInfoFetchFailure(this);
+}
+
+} // namespace extensions
diff --git a/chrome/browser/extensions/api/identity/account_tracker.h b/chrome/browser/extensions/api/identity/account_tracker.h
new file mode 100644
index 0000000000..de9b6d8851
--- /dev/null
+++ b/chrome/browser/extensions/api/identity/account_tracker.h
@@ -0,0 +1,140 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_API_IDENTITY_ACCOUNT_TRACKER_H_
+#define CHROME_BROWSER_EXTENSIONS_API_IDENTITY_ACCOUNT_TRACKER_H_
+
+#include <map>
+#include <string>
+
+#include "base/observer_list.h"
+#include "chrome/browser/signin/signin_global_error.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/notification_source.h"
+#include "google_apis/gaia/gaia_oauth_client.h"
+#include "google_apis/gaia/oauth2_token_service.h"
+
+class GoogleServiceAuthError;
+class Profile;
+
+namespace extensions {
+
+struct AccountIds {
+ std::string account_key; // The account ID used by OAuth2TokenService.
+ std::string gaia;
+ std::string email;
+};
+
+class AccountIdFetcher;
+
+// The AccountTracker keeps track of what accounts exist on the
+// profile and the state of their credentials. The tracker fetches the
+// gaia ID of each account it knows about.
+//
+// The AccountTracker maintains these invariants:
+// 1. Events are only fired after the gaia ID has been fetched.
+// 2. Add/Remove and SignIn/SignOut pairs are always generated in order.
+// 3. SignIn follows Add, and there will be a SignOut between SignIn & Remove.
+class AccountTracker : public OAuth2TokenService::Observer,
+ public content::NotificationObserver,
+ public SigninGlobalError::AuthStatusProvider {
+ public:
+ explicit AccountTracker(Profile* profile);
+ virtual ~AccountTracker();
+
+ class Observer {
+ public:
+ virtual void OnAccountAdded(const AccountIds& ids) = 0;
+ virtual void OnAccountRemoved(const AccountIds& ids) = 0;
+ virtual void OnAccountSignInChanged(const AccountIds& ids,
+ bool is_signed_in) = 0;
+ };
+
+ void Shutdown();
+
+ void ReportAuthError(const std::string& account_key,
+ const GoogleServiceAuthError& error);
+
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+
+ // OAuth2TokenService::Observer implementation.
+ virtual void OnRefreshTokenAvailable(const std::string& account_key) OVERRIDE;
+ virtual void OnRefreshTokenRevoked(const std::string& account_key) OVERRIDE;
+
+ // content::NotificationObserver implementation.
+ virtual void Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) OVERRIDE;
+
+ void OnUserInfoFetchSuccess(AccountIdFetcher* fetcher,
+ const std::string& gaia_id);
+ void OnUserInfoFetchFailure(AccountIdFetcher* fetcher);
+
+ // AuthStatusProvider implementation.
+ virtual std::string GetAccountId() const OVERRIDE;
+ virtual GoogleServiceAuthError GetAuthStatus() const OVERRIDE;
+
+ private:
+ struct AccountState {
+ AccountIds ids;
+ bool is_signed_in;
+ };
+
+ void NotifyAccountAdded(const AccountState& account);
+ void NotifyAccountRemoved(const AccountState& account);
+ void NotifySignInChanged(const AccountState& account);
+
+ void UpdateSignInState(const std::string& account_key, bool is_signed_in);
+
+ void StartTrackingAccount(const std::string& account_key);
+ void StopTrackingAccount(const std::string& account_key);
+ void StartFetchingUserInfo(const std::string& account_key);
+ void DeleteFetcher(AccountIdFetcher* fetcher);
+
+ Profile* profile_;
+ std::map<std::string, AccountIdFetcher*> user_info_requests_;
+ std::map<std::string, AccountState> accounts_;
+ std::map<std::string, GoogleServiceAuthError> account_errors_;
+ ObserverList<Observer> observer_list_;
+ content::NotificationRegistrar registrar_;
+};
+
+class AccountIdFetcher : public OAuth2TokenService::Consumer,
+ public gaia::GaiaOAuthClient::Delegate {
+ public:
+ AccountIdFetcher(Profile* profile,
+ AccountTracker* tracker,
+ const std::string& account_key);
+ virtual ~AccountIdFetcher();
+
+ const std::string& account_key() { return account_key_; }
+
+ void Start();
+
+ // OAuth2TokenService::Consumer implementation.
+ virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
+ const std::string& access_token,
+ const base::Time& expiration_time) OVERRIDE;
+ virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request,
+ const GoogleServiceAuthError& error) OVERRIDE;
+
+ // gaia::GaiaOAuthClient::Delegate implementation.
+ virtual void OnGetUserIdResponse(const std::string& gaia_id) OVERRIDE;
+ virtual void OnOAuthError() OVERRIDE;
+ virtual void OnNetworkError(int response_code) OVERRIDE;
+
+ private:
+ Profile* profile_;
+ AccountTracker* tracker_;
+ const std::string account_key_;
+
+ scoped_ptr<OAuth2TokenService::Request> login_token_request_;
+ scoped_ptr<gaia::GaiaOAuthClient> gaia_oauth_client_;
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_API_IDENTITY_ACCOUNT_TRACKER_H_
diff --git a/chrome/browser/extensions/api/identity/account_tracker_unittest.cc b/chrome/browser/extensions/api/identity/account_tracker_unittest.cc
new file mode 100644
index 0000000000..2ac55aded6
--- /dev/null
+++ b/chrome/browser/extensions/api/identity/account_tracker_unittest.cc
@@ -0,0 +1,504 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/api/identity/account_tracker.h"
+
+#include <vector>
+
+#include "base/strings/stringprintf.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/signin/fake_profile_oauth2_token_service.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
+#include "chrome/browser/signin/signin_manager_base.h"
+#include "chrome/test/base/testing_profile.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "google_apis/gaia/gaia_oauth_client.h"
+#include "net/http/http_status_code.h"
+#include "net/url_request/test_url_fetcher_factory.h"
+#include "net/url_request/url_fetcher_delegate.h"
+#include "net/url_request/url_request_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const char kFakeGaiaId[] = "8675309";
+
+enum TrackingEventType {
+ ADDED,
+ REMOVED,
+ SIGN_IN,
+ SIGN_OUT
+};
+
+class TrackingEvent {
+ public:
+ TrackingEvent(TrackingEventType type,
+ const std::string& account_key,
+ const std::string& gaia_id)
+ : type_(type),
+ account_key_(account_key),
+ gaia_id_(gaia_id) {}
+
+ TrackingEvent(TrackingEventType type,
+ const std::string& account_key)
+ : type_(type),
+ account_key_(account_key),
+ gaia_id_(kFakeGaiaId) {}
+
+ bool operator==(const TrackingEvent& event) const {
+ return type_ == event.type_ && account_key_ == event.account_key_ &&
+ gaia_id_ == event.gaia_id_;
+ }
+
+ std::string ToString() const {
+ const char * typestr = "INVALID";
+ switch (type_) {
+ case ADDED:
+ typestr = "ADD";
+ break;
+ case REMOVED:
+ typestr = "REM";
+ break;
+ case SIGN_IN:
+ typestr = " IN";
+ break;
+ case SIGN_OUT:
+ typestr = "OUT";
+ break;
+ }
+ return base::StringPrintf("{ type: %s, email: %s, gaia: %s }",
+ typestr,
+ account_key_.c_str(),
+ gaia_id_.c_str());
+ }
+
+ private:
+ TrackingEventType type_;
+ std::string account_key_;
+ std::string gaia_id_;
+};
+
+std::string Str(const std::vector<TrackingEvent>& events) {
+ std::string str = "[";
+ bool needs_comma = false;
+ for (std::vector<TrackingEvent>::const_iterator it =
+ events.begin(); it != events.end(); ++it) {
+ if (needs_comma)
+ str += ",\n ";
+ needs_comma = true;
+ str += it->ToString();
+ }
+ str += "]";
+ return str;
+}
+
+} // namespace
+
+namespace extensions {
+
+class AccountTrackerObserver : public AccountTracker::Observer {
+ public:
+ AccountTrackerObserver() {}
+ virtual ~AccountTrackerObserver() {}
+
+ testing::AssertionResult CheckEvents();
+ testing::AssertionResult CheckEvents(const TrackingEvent& e1);
+ testing::AssertionResult CheckEvents(const TrackingEvent& e1,
+ const TrackingEvent& e2);
+ testing::AssertionResult CheckEvents(const TrackingEvent& e1,
+ const TrackingEvent& e2,
+ const TrackingEvent& e3);
+ testing::AssertionResult CheckEvents(const TrackingEvent& e1,
+ const TrackingEvent& e2,
+ const TrackingEvent& e3,
+ const TrackingEvent& e4);
+
+ // AccountTracker::Observer implementation
+ virtual void OnAccountAdded(const AccountIds& ids) OVERRIDE;
+ virtual void OnAccountRemoved(const AccountIds& ids) OVERRIDE;
+ virtual void OnAccountSignInChanged(const AccountIds& ids, bool is_signed_in)
+ OVERRIDE;
+
+ private:
+ testing::AssertionResult CheckEvents(
+ const std::vector<TrackingEvent>& events);
+
+ std::vector<TrackingEvent> events_;
+};
+
+void AccountTrackerObserver::OnAccountAdded(const AccountIds& ids) {
+ events_.push_back(TrackingEvent(ADDED, ids.email, ids.gaia));
+}
+
+void AccountTrackerObserver::OnAccountRemoved(const AccountIds& ids) {
+ events_.push_back(TrackingEvent(REMOVED, ids.email, ids.gaia));
+}
+
+void AccountTrackerObserver::OnAccountSignInChanged(const AccountIds& ids,
+ bool is_signed_in) {
+ events_.push_back(
+ TrackingEvent(is_signed_in ? SIGN_IN : SIGN_OUT, ids.email, ids.gaia));
+}
+
+testing::AssertionResult AccountTrackerObserver::CheckEvents() {
+ std::vector<TrackingEvent> events;
+ return CheckEvents(events);
+}
+
+testing::AssertionResult AccountTrackerObserver::CheckEvents(
+ const TrackingEvent& e1) {
+ std::vector<TrackingEvent> events;
+ events.push_back(e1);
+ return CheckEvents(events);
+}
+
+testing::AssertionResult AccountTrackerObserver::CheckEvents(
+ const TrackingEvent& e1,
+ const TrackingEvent& e2) {
+ std::vector<TrackingEvent> events;
+ events.push_back(e1);
+ events.push_back(e2);
+ return CheckEvents(events);
+}
+
+testing::AssertionResult AccountTrackerObserver::CheckEvents(
+ const TrackingEvent& e1,
+ const TrackingEvent& e2,
+ const TrackingEvent& e3) {
+ std::vector<TrackingEvent> events;
+ events.push_back(e1);
+ events.push_back(e2);
+ events.push_back(e3);
+ return CheckEvents(events);
+}
+
+testing::AssertionResult AccountTrackerObserver::CheckEvents(
+ const TrackingEvent& e1,
+ const TrackingEvent& e2,
+ const TrackingEvent& e3,
+ const TrackingEvent& e4) {
+ std::vector<TrackingEvent> events;
+ events.push_back(e1);
+ events.push_back(e2);
+ events.push_back(e3);
+ events.push_back(e4);
+ return CheckEvents(events);
+}
+
+testing::AssertionResult AccountTrackerObserver::CheckEvents(
+ const std::vector<TrackingEvent>& events) {
+ std::string maybe_newline = (events.size() + events_.size()) > 2 ? "\n" : "";
+ testing::AssertionResult result(
+ (events_ == events)
+ ? testing::AssertionSuccess()
+ : (testing::AssertionFailure()
+ << "Expected " << maybe_newline << Str(events) << ", "
+ << maybe_newline << "Got " << maybe_newline << Str(events_)));
+ events_.clear();
+ return result;
+}
+
+class IdentityAccountTrackerTest : public testing::Test {
+ public:
+ IdentityAccountTrackerTest() {}
+
+ virtual ~IdentityAccountTrackerTest() {}
+
+ virtual void SetUp() OVERRIDE {
+ TestingProfile::Builder builder;
+ builder.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(),
+ FakeProfileOAuth2TokenService::Build);
+
+ test_profile_ = builder.Build();
+
+ fake_oauth2_token_service_ = static_cast<FakeProfileOAuth2TokenService*>(
+ ProfileOAuth2TokenServiceFactory::GetForProfile(test_profile_.get()));
+
+ account_tracker_.reset(new AccountTracker(test_profile_.get()));
+ account_tracker_->AddObserver(&observer_);
+ }
+
+ virtual void TearDown() OVERRIDE {
+ account_tracker_->RemoveObserver(&observer_);
+ account_tracker_->Shutdown();
+ }
+
+ Profile* profile() {
+ return test_profile_.get();
+ }
+
+ AccountTrackerObserver* observer() {
+ return &observer_;
+ }
+
+ AccountTracker* account_tracker() {
+ return account_tracker_.get();
+ }
+
+ // Helpers to pass fake events to the tracker.
+
+ void NotifyRemoveAccount(const std::string& username) {
+ GoogleServiceSigninSuccessDetails details(username, std::string());
+ content::NotificationService::current()->Notify(
+ chrome::NOTIFICATION_GOOGLE_SIGNED_OUT,
+ content::Source<Profile>(profile()),
+ content::Details<const GoogleServiceSigninSuccessDetails>(&details));
+ }
+
+ void NotifyTokenAvailable(const std::string& username) {
+ fake_oauth2_token_service_->IssueRefreshTokenForUser(username,
+ "refresh_token");
+ }
+
+ void NotifyTokenRevoked(const std::string& username) {
+ fake_oauth2_token_service_->IssueRefreshTokenForUser(username,
+ std::string());
+ }
+
+ // Helpers to fake access token and user info fetching
+ void IssueAccessToken() {
+ fake_oauth2_token_service_->IssueTokenForAllPendingRequests(
+ "access_token", base::Time::Max());
+ }
+
+ std::string GetValidTokenInfoResponse(const std::string email) {
+ return std::string("{ \"id\": \"") + kFakeGaiaId + "\" }";
+ }
+
+ void ReturnOAuthUrlFetchResults(int fetcher_id,
+ net::HttpStatusCode response_code,
+ const std::string& response_string);
+
+ void ReturnOAuthUrlFetchSuccess(const std::string& account_key);
+ void ReturnOAuthUrlFetchFailure(const std::string& account_key);
+
+ private:
+ scoped_ptr<TestingProfile> test_profile_;
+ net::TestURLFetcherFactory test_fetcher_factory_;
+ FakeProfileOAuth2TokenService* fake_oauth2_token_service_;
+ content::TestBrowserThreadBundle thread_bundle_;
+
+ scoped_ptr<AccountTracker> account_tracker_;
+ AccountTrackerObserver observer_;
+};
+
+void IdentityAccountTrackerTest::ReturnOAuthUrlFetchResults(
+ int fetcher_id,
+ net::HttpStatusCode response_code,
+ const std::string& response_string) {
+
+ net::TestURLFetcher* fetcher =
+ test_fetcher_factory_.GetFetcherByID(fetcher_id);
+ ASSERT_TRUE(fetcher);
+ fetcher->set_response_code(response_code);
+ fetcher->SetResponseString(response_string);
+ fetcher->delegate()->OnURLFetchComplete(fetcher);
+}
+
+void IdentityAccountTrackerTest::ReturnOAuthUrlFetchSuccess(
+ const std::string& account_key) {
+ IssueAccessToken();
+ ReturnOAuthUrlFetchResults(gaia::GaiaOAuthClient::kUrlFetcherId,
+ net::HTTP_OK,
+ GetValidTokenInfoResponse(account_key));
+}
+
+void IdentityAccountTrackerTest::ReturnOAuthUrlFetchFailure(
+ const std::string& account_key) {
+ IssueAccessToken();
+ ReturnOAuthUrlFetchResults(
+ gaia::GaiaOAuthClient::kUrlFetcherId, net::HTTP_BAD_REQUEST, "");
+}
+
+TEST_F(IdentityAccountTrackerTest, Available) {
+ NotifyTokenAvailable("user@example.com");
+ EXPECT_TRUE(observer()->CheckEvents());
+
+ ReturnOAuthUrlFetchSuccess("user@example.com");
+ EXPECT_TRUE(observer()->CheckEvents(
+ TrackingEvent(ADDED, "user@example.com", kFakeGaiaId),
+ TrackingEvent(SIGN_IN, "user@example.com", kFakeGaiaId)));
+}
+
+TEST_F(IdentityAccountTrackerTest, Revoke) {
+ account_tracker()->OnRefreshTokenRevoked("user@example.com");
+ EXPECT_TRUE(observer()->CheckEvents());
+}
+
+TEST_F(IdentityAccountTrackerTest, Remove) {
+ NotifyRemoveAccount("user@example.com");
+ EXPECT_TRUE(observer()->CheckEvents());
+}
+
+TEST_F(IdentityAccountTrackerTest, AvailableRemoveFetchCancelAvailable) {
+ NotifyTokenAvailable("user@example.com");
+ NotifyRemoveAccount("user@example.com");
+ EXPECT_TRUE(observer()->CheckEvents());
+
+ NotifyTokenAvailable("user@example.com");
+ ReturnOAuthUrlFetchSuccess("user@example.com");
+ EXPECT_TRUE(observer()->CheckEvents(
+ TrackingEvent(ADDED, "user@example.com", kFakeGaiaId),
+ TrackingEvent(SIGN_IN, "user@example.com", kFakeGaiaId)));
+}
+
+TEST_F(IdentityAccountTrackerTest, AvailableRemoveAvailable) {
+ NotifyTokenAvailable("user@example.com");
+ ReturnOAuthUrlFetchSuccess("user@example.com");
+ NotifyRemoveAccount("user@example.com");
+ EXPECT_TRUE(observer()->CheckEvents(
+ TrackingEvent(ADDED, "user@example.com", kFakeGaiaId),
+ TrackingEvent(SIGN_IN, "user@example.com", kFakeGaiaId),
+ TrackingEvent(SIGN_OUT, "user@example.com", kFakeGaiaId),
+ TrackingEvent(REMOVED, "user@example.com", kFakeGaiaId)));
+
+ NotifyTokenAvailable("user@example.com");
+ ReturnOAuthUrlFetchSuccess("user@example.com");
+ EXPECT_TRUE(observer()->CheckEvents(
+ TrackingEvent(ADDED, "user@example.com", kFakeGaiaId),
+ TrackingEvent(SIGN_IN, "user@example.com", kFakeGaiaId)));
+}
+
+TEST_F(IdentityAccountTrackerTest, AvailableRevokeAvailable) {
+ NotifyTokenAvailable("user@example.com");
+ ReturnOAuthUrlFetchSuccess("user@example.com");
+ NotifyTokenRevoked("user@example.com");
+ EXPECT_TRUE(observer()->CheckEvents(
+ TrackingEvent(ADDED, "user@example.com", kFakeGaiaId),
+ TrackingEvent(SIGN_IN, "user@example.com", kFakeGaiaId),
+ TrackingEvent(SIGN_OUT, "user@example.com", kFakeGaiaId)));
+
+ NotifyTokenAvailable("user@example.com");
+ EXPECT_TRUE(observer()->CheckEvents(
+ TrackingEvent(SIGN_IN, "user@example.com", kFakeGaiaId)));
+}
+
+TEST_F(IdentityAccountTrackerTest, AvailableRevokeAvailableWithPendingFetch) {
+ NotifyTokenAvailable("user@example.com");
+ NotifyTokenRevoked("user@example.com");
+ EXPECT_TRUE(observer()->CheckEvents());
+
+ NotifyTokenAvailable("user@example.com");
+ ReturnOAuthUrlFetchSuccess("user@example.com");
+ EXPECT_TRUE(observer()->CheckEvents(
+ TrackingEvent(ADDED, "user@example.com", kFakeGaiaId),
+ TrackingEvent(SIGN_IN, "user@example.com", kFakeGaiaId)));
+}
+
+TEST_F(IdentityAccountTrackerTest, AvailableRevokeRemove) {
+ NotifyTokenAvailable("user@example.com");
+ ReturnOAuthUrlFetchSuccess("user@example.com");
+ NotifyTokenRevoked("user@example.com");
+ EXPECT_TRUE(observer()->CheckEvents(
+ TrackingEvent(ADDED, "user@example.com", kFakeGaiaId),
+ TrackingEvent(SIGN_IN, "user@example.com", kFakeGaiaId),
+ TrackingEvent(SIGN_OUT, "user@example.com", kFakeGaiaId)));
+
+ NotifyRemoveAccount("user@example.com");
+ EXPECT_TRUE(observer()->CheckEvents(
+ TrackingEvent(REMOVED, "user@example.com", kFakeGaiaId)));
+}
+
+TEST_F(IdentityAccountTrackerTest, AvailableRevokeRevoke) {
+ NotifyTokenAvailable("user@example.com");
+ ReturnOAuthUrlFetchSuccess("user@example.com");
+ NotifyTokenRevoked("user@example.com");
+ EXPECT_TRUE(observer()->CheckEvents(
+ TrackingEvent(ADDED, "user@example.com", kFakeGaiaId),
+ TrackingEvent(SIGN_IN, "user@example.com", kFakeGaiaId),
+ TrackingEvent(SIGN_OUT, "user@example.com", kFakeGaiaId)));
+
+ NotifyTokenRevoked("user@example.com");
+ EXPECT_TRUE(observer()->CheckEvents());
+}
+
+TEST_F(IdentityAccountTrackerTest, AvailableAvailable) {
+ NotifyTokenAvailable("user@example.com");
+ ReturnOAuthUrlFetchSuccess("user@example.com");
+ EXPECT_TRUE(observer()->CheckEvents(
+ TrackingEvent(ADDED, "user@example.com", kFakeGaiaId),
+ TrackingEvent(SIGN_IN, "user@example.com", kFakeGaiaId)));
+
+ NotifyTokenAvailable("user@example.com");
+ EXPECT_TRUE(observer()->CheckEvents());
+}
+
+TEST_F(IdentityAccountTrackerTest, TwoAccounts) {
+ NotifyTokenAvailable("alpha@example.com");
+ ReturnOAuthUrlFetchSuccess("alpha@example.com");
+ EXPECT_TRUE(observer()->CheckEvents(
+ TrackingEvent(ADDED, "alpha@example.com", kFakeGaiaId),
+ TrackingEvent(SIGN_IN, "alpha@example.com", kFakeGaiaId)));
+
+ NotifyTokenAvailable("beta@example.com");
+ ReturnOAuthUrlFetchSuccess("beta@example.com");
+ EXPECT_TRUE(observer()->CheckEvents(
+ TrackingEvent(ADDED, "beta@example.com", kFakeGaiaId),
+ TrackingEvent(SIGN_IN, "beta@example.com", kFakeGaiaId)));
+
+ NotifyRemoveAccount("alpha@example.com");
+ EXPECT_TRUE(observer()->CheckEvents(
+ TrackingEvent(SIGN_OUT, "alpha@example.com", kFakeGaiaId),
+ TrackingEvent(REMOVED, "alpha@example.com", kFakeGaiaId)));
+
+ NotifyRemoveAccount("beta@example.com");
+ EXPECT_TRUE(observer()->CheckEvents(
+ TrackingEvent(SIGN_OUT, "beta@example.com", kFakeGaiaId),
+ TrackingEvent(REMOVED, "beta@example.com", kFakeGaiaId)));
+}
+
+TEST_F(IdentityAccountTrackerTest, GlobalErrors) {
+ NotifyTokenAvailable("alpha@example.com");
+ ReturnOAuthUrlFetchSuccess("alpha@example.com");
+ EXPECT_TRUE(observer()->CheckEvents(
+ TrackingEvent(ADDED, "alpha@example.com", kFakeGaiaId),
+ TrackingEvent(SIGN_IN, "alpha@example.com", kFakeGaiaId)));
+ NotifyTokenAvailable("beta@example.com");
+ ReturnOAuthUrlFetchSuccess("beta@example.com");
+ EXPECT_TRUE(observer()->CheckEvents(
+ TrackingEvent(ADDED, "beta@example.com", kFakeGaiaId),
+ TrackingEvent(SIGN_IN, "beta@example.com", kFakeGaiaId)));
+
+ EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(),
+ account_tracker()->GetAuthStatus());
+
+ account_tracker()->ReportAuthError(
+ "beta@example.com",
+ GoogleServiceAuthError(GoogleServiceAuthError::CONNECTION_FAILED));
+ EXPECT_TRUE(observer()->CheckEvents(
+ TrackingEvent(SIGN_OUT, "beta@example.com", kFakeGaiaId)));
+ EXPECT_EQ(GoogleServiceAuthError(GoogleServiceAuthError::CONNECTION_FAILED),
+ account_tracker()->GetAuthStatus());
+
+ account_tracker()->ReportAuthError(
+ "alpha@example.com",
+ GoogleServiceAuthError(GoogleServiceAuthError::CONNECTION_FAILED));
+ EXPECT_TRUE(observer()->CheckEvents(
+ TrackingEvent(SIGN_OUT, "alpha@example.com", kFakeGaiaId)));
+ EXPECT_EQ(GoogleServiceAuthError(GoogleServiceAuthError::CONNECTION_FAILED),
+ account_tracker()->GetAuthStatus());
+
+ NotifyRemoveAccount("alpha@example.com");
+ EXPECT_EQ(GoogleServiceAuthError(GoogleServiceAuthError::CONNECTION_FAILED),
+ account_tracker()->GetAuthStatus());
+
+ NotifyTokenAvailable("beta@example.com");
+ EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(),
+ account_tracker()->GetAuthStatus());
+}
+
+TEST_F(IdentityAccountTrackerTest, AvailableTokenFetchFailAvailable) {
+ NotifyTokenAvailable("alpha@example.com");
+ ReturnOAuthUrlFetchFailure("alpha@example.com");
+ EXPECT_TRUE(observer()->CheckEvents());
+
+ NotifyTokenAvailable("user@example.com");
+ ReturnOAuthUrlFetchSuccess("user@example.com");
+ EXPECT_TRUE(observer()->CheckEvents(
+ TrackingEvent(ADDED, "user@example.com", kFakeGaiaId),
+ TrackingEvent(SIGN_IN, "user@example.com", kFakeGaiaId)));
+}
+
+} // namespace extensions
diff --git a/chrome/browser/extensions/api/identity/identity_api.cc b/chrome/browser/extensions/api/identity/identity_api.cc
index 890f99443d..485711e8be 100644
--- a/chrome/browser/extensions/api/identity/identity_api.cc
+++ b/chrome/browser/extensions/api/identity/identity_api.cc
@@ -36,6 +36,7 @@
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"
#include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
+#include "google_apis/gaia/gaia_constants.h"
#endif
namespace extensions {
@@ -215,18 +216,11 @@ void IdentityGetAuthTokenFunction::StartMintToken(
#if defined(OS_CHROMEOS)
// Always force minting token for ChromeOS kiosk app.
if (chromeos::UserManager::Get()->IsLoggedInAsKioskApp()) {
+ gaia_mint_token_mode_ = OAuth2MintTokenFlow::MODE_MINT_TOKEN_FORCE;
if (g_browser_process->browser_policy_connector()->
IsEnterpriseManaged()) {
- OAuth2TokenService::ScopeSet scope_set(oauth2_info.scopes.begin(),
- oauth2_info.scopes.end());
- chromeos::DeviceOAuth2TokenService* token_service =
- chromeos::DeviceOAuth2TokenServiceFactory::Get();
- device_token_request_ =
- token_service->StartRequest(token_service->GetRobotAccountId(),
- scope_set,
- this);
+ StartDeviceLoginAccessTokenRequest();
} else {
- gaia_mint_token_mode_ = OAuth2MintTokenFlow::MODE_MINT_TOKEN_FORCE;
StartLoginAccessTokenRequest();
}
return;
@@ -386,37 +380,32 @@ void IdentityGetAuthTokenFunction::OnGetTokenSuccess(
const OAuth2TokenService::Request* request,
const std::string& access_token,
const base::Time& expiration_time) {
- if (login_token_request_.get() == request) {
- login_token_request_.reset();
- StartGaiaRequest(access_token);
- } else {
- DCHECK_EQ(device_token_request_.get(), request);
- device_token_request_.reset();
-
- const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(GetExtension());
- IdentityTokenCacheValue token(access_token,
- expiration_time - base::Time::Now());
- IdentityAPI::GetFactoryInstance()->GetForProfile(profile())->SetCachedToken(
- GetExtension()->id(), oauth2_info.scopes, token);
-
- CompleteMintTokenFlow();
- CompleteFunctionWithResult(access_token);
- }
+ login_token_request_.reset();
+ StartGaiaRequest(access_token);
}
void IdentityGetAuthTokenFunction::OnGetTokenFailure(
const OAuth2TokenService::Request* request,
const GoogleServiceAuthError& error) {
- if (login_token_request_.get() == request) {
- login_token_request_.reset();
- } else {
- DCHECK_EQ(device_token_request_.get(), request);
- device_token_request_.reset();
- }
-
+ login_token_request_.reset();
OnGaiaFlowFailure(GaiaWebAuthFlow::SERVICE_AUTH_ERROR, error, std::string());
}
+#if defined(OS_CHROMEOS)
+void IdentityGetAuthTokenFunction::StartDeviceLoginAccessTokenRequest() {
+ chromeos::DeviceOAuth2TokenService* service =
+ chromeos::DeviceOAuth2TokenServiceFactory::Get();
+ // Since robot account refresh tokens are scoped down to [any-api] only,
+ // request access token for [any-api] instead of login.
+ OAuth2TokenService::ScopeSet scopes;
+ scopes.insert(GaiaConstants::kAnyApiOAuth2Scope);
+ login_token_request_ =
+ service->StartRequest(service->GetRobotAccountId(),
+ scopes,
+ this);
+}
+#endif
+
void IdentityGetAuthTokenFunction::StartLoginAccessTokenRequest() {
ProfileOAuth2TokenService* service =
ProfileOAuth2TokenServiceFactory::GetForProfile(profile());
@@ -666,13 +655,12 @@ const base::Time& IdentityTokenCacheValue::expiration_time() const {
IdentityAPI::IdentityAPI(Profile* profile)
: profile_(profile),
- error_(GoogleServiceAuthError::NONE) {
- SigninGlobalError::GetForProfile(profile_)->AddProvider(this);
- ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)->AddObserver(this);
+ account_tracker_(profile),
+ identity_event_router_(profile) {
+ account_tracker_.AddObserver(this);
}
-IdentityAPI::~IdentityAPI() {
-}
+IdentityAPI::~IdentityAPI() {}
IdentityMintRequestQueue* IdentityAPI::mint_queue() {
return &mint_queue_;
@@ -720,14 +708,14 @@ const IdentityAPI::CachedTokens& IdentityAPI::GetAllCachedTokens() {
}
void IdentityAPI::ReportAuthError(const GoogleServiceAuthError& error) {
- error_ = error;
- SigninGlobalError::GetForProfile(profile_)->AuthStatusChanged();
+ ProfileOAuth2TokenService* token_service =
+ ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
+ account_tracker_.ReportAuthError(token_service->GetPrimaryAccountId(), error);
}
void IdentityAPI::Shutdown() {
- SigninGlobalError::GetForProfile(profile_)->RemoveProvider(this);
- ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)->
- RemoveObserver(this);
+ account_tracker_.RemoveObserver(this);
+ account_tracker_.Shutdown();
}
static base::LazyInstance<ProfileKeyedAPIFactory<IdentityAPI> >
@@ -738,24 +726,18 @@ ProfileKeyedAPIFactory<IdentityAPI>* IdentityAPI::GetFactoryInstance() {
return &g_factory.Get();
}
-std::string IdentityAPI::GetAccountId() const {
- return ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)->
- GetPrimaryAccountId();
-}
+void IdentityAPI::OnAccountAdded(const AccountIds& ids) {}
-GoogleServiceAuthError IdentityAPI::GetAuthStatus() const {
- return error_;
-}
+void IdentityAPI::OnAccountRemoved(const AccountIds& ids) {}
-void IdentityAPI::OnRefreshTokenAvailable(const std::string& account_id) {
- error_ = GoogleServiceAuthError::AuthErrorNone();
+void IdentityAPI::OnAccountSignInChanged(const AccountIds& ids,
+ bool is_signed_in) {
+ identity_event_router_.DispatchSignInEvent(ids.gaia, ids.email, is_signed_in);
}
template <>
void ProfileKeyedAPIFactory<IdentityAPI>::DeclareFactoryDependencies() {
DependsOn(ExtensionSystemFactory::GetInstance());
- // Need dependency on ProfileOAuth2TokenServiceFactory because it owns
- // the SigninGlobalError instance.
DependsOn(ProfileOAuth2TokenServiceFactory::GetInstance());
}
diff --git a/chrome/browser/extensions/api/identity/identity_api.h b/chrome/browser/extensions/api/identity/identity_api.h
index 6918a786bd..a9a77468e1 100644
--- a/chrome/browser/extensions/api/identity/identity_api.h
+++ b/chrome/browser/extensions/api/identity/identity_api.h
@@ -13,7 +13,9 @@
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
+#include "chrome/browser/extensions/api/identity/account_tracker.h"
#include "chrome/browser/extensions/api/identity/gaia_web_auth_flow.h"
+#include "chrome/browser/extensions/api/identity/identity_event_router.h"
#include "chrome/browser/extensions/api/identity/identity_mint_queue.h"
#include "chrome/browser/extensions/api/identity/identity_signin_flow.h"
#include "chrome/browser/extensions/api/identity/web_auth_flow.h"
@@ -128,6 +130,12 @@ class IdentityGetAuthTokenFunction : public AsyncExtensionFunction,
// Starts a login access token request.
virtual void StartLoginAccessTokenRequest();
+#if defined(OS_CHROMEOS)
+ // Starts a login access token request for device robot account. This method
+ // will be called only in enterprise kiosk mode in ChromeOS.
+ virtual void StartDeviceLoginAccessTokenRequest();
+#endif
+
// Starts a mint token request to GAIA.
void StartGaiaRequest(const std::string& login_access_token);
@@ -159,7 +167,6 @@ class IdentityGetAuthTokenFunction : public AsyncExtensionFunction,
IssueAdviceInfo issue_advice_;
scoped_ptr<GaiaWebAuthFlow> gaia_web_auth_flow_;
scoped_ptr<IdentitySigninFlow> signin_flow_;
- scoped_ptr<OAuth2TokenService::Request> device_token_request_;
scoped_ptr<OAuth2TokenService::Request> login_token_request_;
};
@@ -234,8 +241,7 @@ class IdentityTokenCacheValue {
};
class IdentityAPI : public ProfileKeyedAPI,
- public SigninGlobalError::AuthStatusProvider,
- public OAuth2TokenService::Observer {
+ public AccountTracker::Observer {
public:
struct TokenCacheKey {
TokenCacheKey(const std::string& extension_id,
@@ -272,12 +278,11 @@ class IdentityAPI : public ProfileKeyedAPI,
virtual void Shutdown() OVERRIDE;
static ProfileKeyedAPIFactory<IdentityAPI>* GetFactoryInstance();
- // AuthStatusProvider implementation.
- virtual std::string GetAccountId() const OVERRIDE;
- virtual GoogleServiceAuthError GetAuthStatus() const OVERRIDE;
-
- // OAuth2TokenService::Observer implementation:
- virtual void OnRefreshTokenAvailable(const std::string& account_id) OVERRIDE;
+ // AccountTracker::Observer implementation:
+ virtual void OnAccountAdded(const AccountIds& ids) OVERRIDE;
+ virtual void OnAccountRemoved(const AccountIds& ids) OVERRIDE;
+ virtual void OnAccountSignInChanged(const AccountIds& ids, bool is_signed_in)
+ OVERRIDE;
private:
friend class ProfileKeyedAPIFactory<IdentityAPI>;
@@ -289,9 +294,10 @@ class IdentityAPI : public ProfileKeyedAPI,
static const bool kServiceIsNULLWhileTesting = true;
Profile* profile_;
- GoogleServiceAuthError error_;
IdentityMintRequestQueue mint_queue_;
CachedTokens token_cache_;
+ AccountTracker account_tracker_;
+ IdentityEventRouter identity_event_router_;
};
template <>
diff --git a/chrome/browser/extensions/api/identity/identity_event_router.cc b/chrome/browser/extensions/api/identity/identity_event_router.cc
new file mode 100644
index 0000000000..06a9ac8d53
--- /dev/null
+++ b/chrome/browser/extensions/api/identity/identity_event_router.cc
@@ -0,0 +1,73 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/api/identity/identity_event_router.h"
+
+#include <set>
+
+#include "base/stl_util.h"
+#include "base/values.h"
+#include "chrome/browser/extensions/event_router.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/common/extensions/api/identity.h"
+
+namespace extensions {
+
+IdentityEventRouter::IdentityEventRouter(Profile* profile)
+ : profile_(profile) {}
+
+IdentityEventRouter::~IdentityEventRouter() {}
+
+void IdentityEventRouter::DispatchSignInEvent(const std::string& id,
+ const std::string& email,
+ bool is_signed_in) {
+ const EventListenerMap::ListenerList& listeners =
+ extensions::ExtensionSystem::Get(profile_)->event_router()->listeners()
+ .GetEventListenersByName(api::identity::OnSignInChanged::kEventName);
+
+ ExtensionService* service =
+ ExtensionSystem::Get(profile_)->extension_service();
+ EventRouter* event_router = ExtensionSystem::Get(profile_)->event_router();
+
+ api::identity::AccountInfo account_info;
+ account_info.id = id;
+
+ api::identity::AccountInfo account_info_email;
+ account_info_email.id = id;
+ account_info_email.email = scoped_ptr<std::string>(new std::string(email));
+
+ std::set<std::string> already_dispatched;
+
+ for (EventListenerMap::ListenerList::const_iterator it = listeners.begin();
+ it != listeners.end();
+ ++it) {
+
+ const std::string extension_id = (*it)->extension_id;
+ const Extension* extension = service->extensions()->GetByID(extension_id);
+
+ if (ContainsKey(already_dispatched, extension_id))
+ continue;
+
+ already_dispatched.insert(extension_id);
+
+ // Add the email address to AccountInfo only for extensions that
+ // have APIPermission::kIdentityEmail.
+ scoped_ptr<base::ListValue> args;
+ if (extension->HasAPIPermission(APIPermission::kIdentityEmail)) {
+ args = api::identity::OnSignInChanged::Create(account_info_email,
+ is_signed_in);
+ } else {
+ args = api::identity::OnSignInChanged::Create(account_info,
+ is_signed_in);
+ }
+
+ scoped_ptr<Event> event(
+ new Event(api::identity::OnSignInChanged::kEventName, args.Pass()));
+ event->restrict_to_profile = profile_;
+ event_router->DispatchEventToExtension(extension_id, event.Pass());
+ }
+}
+
+} // namespace extensions
diff --git a/chrome/browser/extensions/api/identity/identity_event_router.h b/chrome/browser/extensions/api/identity/identity_event_router.h
new file mode 100644
index 0000000000..21bf2eb734
--- /dev/null
+++ b/chrome/browser/extensions/api/identity/identity_event_router.h
@@ -0,0 +1,35 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_API_IDENTITY_IDENTITY_EVENT_ROUTER_H_
+#define CHROME_BROWSER_EXTENSIONS_API_IDENTITY_IDENTITY_EVENT_ROUTER_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+
+class Profile;
+
+namespace extensions {
+
+class IdentityEventRouter {
+ public:
+ explicit IdentityEventRouter(Profile* profile);
+ ~IdentityEventRouter();
+
+ // Dispatch identity.onSignInChanged event, including email address
+ // for extensions with the identity.email permission.
+ void DispatchSignInEvent(const std::string& id,
+ const std::string& email,
+ bool is_signed_in);
+
+ private:
+ Profile* profile_;
+
+ DISALLOW_COPY_AND_ASSIGN(IdentityEventRouter);
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_API_IDENTITY_IDENTITY_EVENT_ROUTER_H_
diff --git a/chrome/browser/extensions/api/identity/identity_event_router_unittest.cc b/chrome/browser/extensions/api/identity/identity_event_router_unittest.cc
new file mode 100644
index 0000000000..8b65c5cec8
--- /dev/null
+++ b/chrome/browser/extensions/api/identity/identity_event_router_unittest.cc
@@ -0,0 +1,291 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/api/identity/identity_event_router.h"
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "base/stl_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/values.h"
+#include "chrome/browser/extensions/event_router.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/extension_system_factory.h"
+#include "chrome/browser/extensions/test_extension_service.h"
+#include "chrome/browser/extensions/test_extension_system.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/extensions/api/identity.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_builder.h"
+#include "chrome/common/extensions/extension_set.h"
+#include "chrome/common/extensions/permissions/permissions_data.h"
+#include "chrome/common/extensions/value_builder.h"
+#include "chrome/test/base/testing_profile.h"
+#include "content/public/test/mock_render_process_host.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "extensions/common/permissions/api_permission.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+struct EventInfo {
+ std::string user_id;
+ std::string email;
+ bool is_signed_in;
+};
+
+class FakeEventRouter : public extensions::EventRouter {
+ public:
+ explicit FakeEventRouter(Profile* profile) : EventRouter(profile, NULL) {}
+
+ virtual void DispatchEventToExtension(
+ const std::string& extension_id,
+ scoped_ptr<extensions::Event> event) OVERRIDE {
+ EventInfo event_info;
+ base::DictionaryValue* event_object = NULL;
+ EXPECT_TRUE(event->event_args->GetDictionary(0, &event_object));
+ EXPECT_TRUE(event_object->GetString("id", &event_info.user_id));
+ event_object->GetString("email", &event_info.email);
+
+ EXPECT_TRUE(event->event_args->GetBoolean(1, &event_info.is_signed_in));
+
+ EXPECT_FALSE(ContainsKey(extension_id_to_event_, extension_id));
+ extension_id_to_event_[extension_id] = event_info;
+ }
+
+ size_t GetEventCount() {
+ return extension_id_to_event_.size();
+ }
+
+ bool ContainsExtensionId(const std::string extension_id) {
+ return ContainsKey(extension_id_to_event_, extension_id);
+ }
+
+ const EventInfo& GetEventInfo(const std::string extension_id) {
+ return extension_id_to_event_[extension_id];
+ }
+
+ private:
+ std::map<std::string, EventInfo> extension_id_to_event_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeEventRouter);
+};
+
+class FakeExtensionService : public TestExtensionService {
+ public:
+ FakeExtensionService() {}
+ virtual ~FakeExtensionService() {}
+
+ virtual const ExtensionSet* extensions() const OVERRIDE {
+ return &extensions_;
+ }
+
+ virtual void AddExtension(const extensions::Extension* extension) OVERRIDE {
+ extensions_.Insert(extension);
+ }
+
+ private:
+ ExtensionSet extensions_;
+};
+
+class FakeExtensionSystem : public extensions::TestExtensionSystem {
+ public:
+ explicit FakeExtensionSystem(Profile* profile)
+ : extensions::TestExtensionSystem(profile) {}
+
+ virtual extensions::EventRouter* event_router() OVERRIDE {
+ return fake_event_router();
+ }
+
+ virtual ExtensionService* extension_service() OVERRIDE {
+ ExtensionServiceInterface* as_interface =
+ static_cast<ExtensionServiceInterface*>(&fake_extension_service_);
+ return static_cast<ExtensionService*>(as_interface);
+ }
+
+ FakeEventRouter* fake_event_router() {
+ if (!fake_event_router_)
+ fake_event_router_.reset(new FakeEventRouter(profile_));
+ return fake_event_router_.get();
+ }
+
+ private:
+ FakeExtensionService fake_extension_service_;
+ scoped_ptr<FakeEventRouter> fake_event_router_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeExtensionSystem);
+};
+
+BrowserContextKeyedService* BuildFakeExtensionSystem(
+ content::BrowserContext* profile) {
+ return new FakeExtensionSystem(static_cast<Profile*>(profile));
+}
+
+} // namespace
+
+namespace extensions {
+
+class IdentityEventRouterTest : public testing::Test {
+ public:
+ IdentityEventRouterTest()
+ : test_profile_(new TestingProfile()),
+ identity_event_router_(test_profile_.get()),
+ extension_counter_(0) {}
+
+ virtual void SetUp() OVERRIDE {
+ fake_extension_system_ = static_cast<FakeExtensionSystem*>(
+ ExtensionSystemFactory::GetInstance()->SetTestingFactoryAndUse(
+ test_profile_.get(), &BuildFakeExtensionSystem));
+ }
+
+ FakeEventRouter* fake_event_router() {
+ return fake_extension_system_->fake_event_router();
+ }
+
+ Profile* profile() {
+ return test_profile_.get();
+ }
+
+ protected:
+ scoped_refptr<const Extension> CreateExtension(bool has_email_permission) {
+ ListBuilder permissions;
+ if (has_email_permission)
+ permissions.Append("identity.email");
+
+ std::string id = base::StringPrintf("id.%d", extension_counter_++);
+ scoped_refptr<const Extension> extension = ExtensionBuilder()
+ .SetID(id)
+ .SetManifest(DictionaryBuilder()
+ .Set("name", "Extension with ID " + id)
+ .Set("version", "1.0")
+ .Set("manifest_version", 2)
+ .Set("permissions", permissions))
+ .Build();
+ fake_extension_system_->extension_service()->AddExtension(extension.get());
+ fake_event_router()->AddEventListener(
+ api::identity::OnSignInChanged::kEventName, NULL, extension->id());
+ return extension;
+ }
+
+ scoped_ptr<TestingProfile> test_profile_;
+ IdentityEventRouter identity_event_router_;
+ FakeExtensionSystem* fake_extension_system_;
+ content::TestBrowserThreadBundle thread_bundle_;
+ int extension_counter_;
+};
+
+TEST_F(IdentityEventRouterTest, SignInNoListeners) {
+ identity_event_router_.DispatchSignInEvent(
+ "test_user_id", "test_email", true);
+ EXPECT_EQ(0ul, fake_event_router()->GetEventCount());
+}
+
+TEST_F(IdentityEventRouterTest, SignInNoEmailListener) {
+ scoped_refptr<const Extension> ext = CreateExtension(false);
+ identity_event_router_.DispatchSignInEvent(
+ "test_user_id", "test_email", true);
+ EXPECT_EQ(1ul, fake_event_router()->GetEventCount());
+ EXPECT_TRUE(fake_event_router()->ContainsExtensionId(ext->id()));
+ EXPECT_EQ("test_user_id",
+ fake_event_router()->GetEventInfo(ext->id()).user_id);
+ EXPECT_TRUE(fake_event_router()->GetEventInfo(ext->id()).email.empty());
+ EXPECT_TRUE(fake_event_router()->GetEventInfo(ext->id()).is_signed_in);
+}
+
+TEST_F(IdentityEventRouterTest, SignInWithEmailListener) {
+ scoped_refptr<const Extension> ext = CreateExtension(true);
+ identity_event_router_.DispatchSignInEvent(
+ "test_user_id", "test_email", true);
+ EXPECT_EQ(1ul, fake_event_router()->GetEventCount());
+ EXPECT_TRUE(fake_event_router()->ContainsExtensionId(ext->id()));
+ EXPECT_EQ("test_user_id",
+ fake_event_router()->GetEventInfo(ext->id()).user_id);
+ EXPECT_EQ("test_email", fake_event_router()->GetEventInfo(ext->id()).email);
+ EXPECT_TRUE(fake_event_router()->GetEventInfo(ext->id()).is_signed_in);
+}
+
+TEST_F(IdentityEventRouterTest, SignInMultipleListeners) {
+ typedef std::vector<scoped_refptr<const Extension> > ExtensionVector;
+ ExtensionVector with_email;
+ ExtensionVector no_email;
+
+ for (int i = 0; i < 3; i++)
+ with_email.push_back(CreateExtension(true));
+
+ for (int i = 0; i < 2; i++)
+ no_email.push_back(CreateExtension(false));
+
+ identity_event_router_.DispatchSignInEvent(
+ "test_user_id", "test_email", true);
+
+ EXPECT_EQ(with_email.size() + no_email.size(),
+ fake_event_router()->GetEventCount());
+
+ for (ExtensionVector::const_iterator it = with_email.begin();
+ it != with_email.end();
+ ++it) {
+ EXPECT_TRUE(fake_event_router()->ContainsExtensionId((*it)->id()));
+ EXPECT_EQ("test_user_id",
+ fake_event_router()->GetEventInfo((*it)->id()).user_id);
+ EXPECT_EQ("test_email",
+ fake_event_router()->GetEventInfo((*it)->id()).email);
+ EXPECT_TRUE(fake_event_router()->GetEventInfo((*it)->id()).is_signed_in);
+ }
+
+ for (ExtensionVector::const_iterator it = no_email.begin();
+ it != no_email.end();
+ ++it) {
+ EXPECT_TRUE(fake_event_router()->ContainsExtensionId((*it)->id()));
+ EXPECT_EQ("test_user_id",
+ fake_event_router()->GetEventInfo((*it)->id()).user_id);
+ EXPECT_TRUE(fake_event_router()->GetEventInfo((*it)->id()).email.empty());
+ EXPECT_TRUE(fake_event_router()->GetEventInfo((*it)->id()).is_signed_in);
+ }
+}
+
+TEST_F(IdentityEventRouterTest, SignInWithTwoListenersOnOneExtension) {
+ scoped_refptr<const Extension> ext = CreateExtension(true);
+
+ scoped_ptr<content::MockRenderProcessHost> fake_render_process(
+ new content::MockRenderProcessHost(profile()));
+ fake_event_router()->AddEventListener(
+ api::identity::OnSignInChanged::kEventName,
+ fake_render_process.get(),
+ ext->id());
+
+ identity_event_router_.DispatchSignInEvent(
+ "test_user_id", "test_email", true);
+ EXPECT_EQ(1ul, fake_event_router()->GetEventCount());
+ EXPECT_TRUE(fake_event_router()->ContainsExtensionId(ext->id()));
+ EXPECT_EQ("test_user_id",
+ fake_event_router()->GetEventInfo(ext->id()).user_id);
+ EXPECT_EQ("test_email", fake_event_router()->GetEventInfo(ext->id()).email);
+ EXPECT_TRUE(fake_event_router()->GetEventInfo(ext->id()).is_signed_in);
+
+ fake_event_router()->RemoveEventListener(
+ api::identity::OnSignInChanged::kEventName,
+ fake_render_process.get(),
+ ext->id());
+}
+
+TEST_F(IdentityEventRouterTest, SignOut) {
+ scoped_refptr<const Extension> ext = CreateExtension(false);
+ identity_event_router_.DispatchSignInEvent(
+ "test_user_id", "test_email", false);
+ EXPECT_EQ(1ul, fake_event_router()->GetEventCount());
+ EXPECT_TRUE(fake_event_router()->ContainsExtensionId(ext->id()));
+ EXPECT_EQ("test_user_id",
+ fake_event_router()->GetEventInfo(ext->id()).user_id);
+ EXPECT_TRUE(fake_event_router()->GetEventInfo(ext->id()).email.empty());
+ EXPECT_FALSE(fake_event_router()->GetEventInfo(ext->id()).is_signed_in);
+}
+
+} // namespace extensions
diff --git a/chrome/browser/extensions/api/identity/web_auth_flow.cc b/chrome/browser/extensions/api/identity/web_auth_flow.cc
index 2c50724531..f59a6b7938 100644
--- a/chrome/browser/extensions/api/identity/web_auth_flow.cc
+++ b/chrome/browser/extensions/api/identity/web_auth_flow.cc
@@ -223,6 +223,7 @@ void WebAuthFlow::DidStartProvisionalLoadForFrame(
}
void WebAuthFlow::DidFailProvisionalLoad(int64 frame_id,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& validated_url,
int error_code,
diff --git a/chrome/browser/extensions/api/identity/web_auth_flow.h b/chrome/browser/extensions/api/identity/web_auth_flow.h
index e1a98523fb..d9a4336a3d 100644
--- a/chrome/browser/extensions/api/identity/web_auth_flow.h
+++ b/chrome/browser/extensions/api/identity/web_auth_flow.h
@@ -118,6 +118,7 @@ class WebAuthFlow : public content::NotificationObserver,
bool is_iframe_srcdoc,
content::RenderViewHost* render_view_host) OVERRIDE;
virtual void DidFailProvisionalLoad(int64 frame_id,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& validated_url,
int error_code,
diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api.cc b/chrome/browser/extensions/api/input_ime/input_ime_api.cc
index 54ca0d40e2..bd8048e327 100644
--- a/chrome/browser/extensions/api/input_ime/input_ime_api.cc
+++ b/chrome/browser/extensions/api/input_ime/input_ime_api.cc
@@ -34,7 +34,6 @@ namespace SetComposition = extensions::api::input_ime::SetComposition;
namespace {
const char kErrorEngineNotAvailable[] = "Engine is not available";
-const char kErrorBadCandidateList[] = "Invalid candidate list provided";
const char kErrorSetMenuItemsFail[] = "Could not create menu Items";
const char kErrorUpdateMenuItemsFail[] = "Could not update menu Items";
diff --git a/chrome/browser/extensions/api/management/management_apitest.cc b/chrome/browser/extensions/api/management/management_apitest.cc
index 0dc25451a3..3a0fccbff9 100644
--- a/chrome/browser/extensions/api/management/management_apitest.cc
+++ b/chrome/browser/extensions/api/management/management_apitest.cc
@@ -70,7 +70,7 @@ class ExtensionManagementApiTest : public ExtensionApiTest {
ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII(app_path)));
if (out_app_id)
- *out_app_id = last_loaded_extension_id_;
+ *out_app_id = last_loaded_extension_id();
ASSERT_TRUE(launched_app.WaitUntilSatisfied());
}
diff --git a/chrome/browser/extensions/api/mdns/dns_sd_delegate.h b/chrome/browser/extensions/api/mdns/dns_sd_delegate.h
index cca02c62e1..d1c2df48c1 100644
--- a/chrome/browser/extensions/api/mdns/dns_sd_delegate.h
+++ b/chrome/browser/extensions/api/mdns/dns_sd_delegate.h
@@ -36,6 +36,7 @@ class DnsSdDelegate {
const DnsSdService& service) = 0;
virtual void ServiceRemoved(const std::string& service_type,
const std::string& service_name) = 0;
+ virtual void ServicesFlushed(const std::string& service_type) = 0;
};
} // namespace extensions
diff --git a/chrome/browser/extensions/api/mdns/dns_sd_device_lister.cc b/chrome/browser/extensions/api/mdns/dns_sd_device_lister.cc
index fdb7fe4231..2deea48325 100644
--- a/chrome/browser/extensions/api/mdns/dns_sd_device_lister.cc
+++ b/chrome/browser/extensions/api/mdns/dns_sd_device_lister.cc
@@ -4,17 +4,9 @@
#include "chrome/browser/extensions/api/mdns/dns_sd_device_lister.h"
-#include <utility>
-
-#include "base/bind.h"
-#include "chrome/browser/local_discovery/service_discovery_shared_client.h"
#include "chrome/common/extensions/api/mdns.h"
-#include "net/base/net_util.h"
using local_discovery::ServiceDescription;
-using local_discovery::ServiceDiscoverySharedClient;
-using local_discovery::ServiceResolver;
-using local_discovery::ServiceWatcher;
namespace extensions {
@@ -38,74 +30,40 @@ void FillServiceInfo(const ServiceDescription& service_description,
} // namespace
DnsSdDeviceLister::DnsSdDeviceLister(
+ local_discovery::ServiceDiscoveryClient* service_discovery_client,
DnsSdDelegate* delegate,
- const std::string& service_type,
- ServiceDiscoverySharedClient* service_discovery_client)
+ const std::string& service_type)
: delegate_(delegate),
- service_type_(service_type),
- service_discovery_client_(service_discovery_client) {
+ device_lister_(this, service_discovery_client, service_type),
+ started_(false) {
}
-DnsSdDeviceLister::~DnsSdDeviceLister() {}
-
-void DnsSdDeviceLister::Discover(bool force_update) {
- if (!service_discovery_client_)
- return;
-
- if (!service_watcher_.get()) {
- service_watcher_ = service_discovery_client_->CreateServiceWatcher(
- service_type_,
- base::Bind(&DnsSdDeviceLister::OnServiceUpdated,
- base::Unretained(this)));
- service_watcher_->Start();
- }
- service_watcher_->DiscoverNewServices(force_update);
+DnsSdDeviceLister::~DnsSdDeviceLister() {
}
-void DnsSdDeviceLister::OnServiceUpdated(
- ServiceWatcher::UpdateType update,
- const std::string& service_name) {
- // TODO(justinlin): Consolidate with PrivetDeviceListerImpl.
- if (update != ServiceWatcher::UPDATE_REMOVED) {
- bool added = (update == ServiceWatcher::UPDATE_ADDED);
- std::pair<ServiceResolverMap::iterator, bool> insert_result =
- resolvers_.insert(make_pair(service_name,
- linked_ptr<ServiceResolver>(NULL)));
-
- // If there is already a resolver working on this service, don't add one.
- if (insert_result.second) {
- scoped_ptr<ServiceResolver> resolver =
- service_discovery_client_->CreateServiceResolver(
- service_name, base::Bind(
- &DnsSdDeviceLister::OnResolveComplete,
- base::Unretained(this),
- added));
-
- insert_result.first->second.reset(resolver.release());
- insert_result.first->second->StartResolving();
- }
- } else {
- delegate_->ServiceRemoved(service_type_, service_name);
+void DnsSdDeviceLister::Discover(bool force_update) {
+ if (!started_) {
+ device_lister_.Start();
+ started_ = true;
}
+ device_lister_.DiscoverNewDevices(force_update);
}
-void DnsSdDeviceLister::OnResolveComplete(
+void DnsSdDeviceLister::OnDeviceChanged(
bool added,
- ServiceResolver::RequestStatus status,
const ServiceDescription& service_description) {
- // TODO(justinlin): Consolidate with PrivetDeviceListerImpl.
- if (status != ServiceResolver::STATUS_SUCCESS) {
- resolvers_.erase(service_description.service_name);
-
- // TODO(noamsml): Add retry logic.
- return;
- }
-
DnsSdService service;
FillServiceInfo(service_description, &service);
+ delegate_->ServiceChanged(device_lister_.service_type(), added, service);
+}
+
+void DnsSdDeviceLister::OnDeviceRemoved(const std::string& service_name) {
+ delegate_->ServiceRemoved(device_lister_.service_type(), service_name);
+}
- resolvers_.erase(service_description.service_name);
- delegate_->ServiceChanged(service_type_, added, service);
+void DnsSdDeviceLister::OnDeviceCacheFlushed() {
+ delegate_->ServicesFlushed(device_lister_.service_type());
+ device_lister_.DiscoverNewDevices(false);
}
} // namespace extensions
diff --git a/chrome/browser/extensions/api/mdns/dns_sd_device_lister.h b/chrome/browser/extensions/api/mdns/dns_sd_device_lister.h
index 4c6f49c2ce..060af2fafc 100644
--- a/chrome/browser/extensions/api/mdns/dns_sd_device_lister.h
+++ b/chrome/browser/extensions/api/mdns/dns_sd_device_lister.h
@@ -5,65 +5,42 @@
#ifndef CHROME_BROWSER_EXTENSIONS_API_MDNS_DNS_SD_DEVICE_LISTER_H_
#define CHROME_BROWSER_EXTENSIONS_API_MDNS_DNS_SD_DEVICE_LISTER_H_
-#include <map>
#include <string>
-#include "base/basictypes.h"
-#include "base/memory/linked_ptr.h"
-#include "base/memory/scoped_ptr.h"
#include "chrome/browser/extensions/api/mdns/dns_sd_delegate.h"
-#include "chrome/common/local_discovery/service_discovery_client.h"
+#include "chrome/browser/local_discovery/service_discovery_device_lister.h"
namespace local_discovery {
-class ServiceDiscoverySharedClient;
+class ServiceDiscoveryClient;
} // local_discovery
namespace extensions {
// Manages a watcher for a specific MDNS/DNS-SD service type and notifies
// a delegate of changes to watched services.
-class DnsSdDeviceLister {
+class DnsSdDeviceLister
+ : public local_discovery::ServiceDiscoveryDeviceLister::Delegate {
public:
DnsSdDeviceLister(
+ local_discovery::ServiceDiscoveryClient* service_discovery_client,
DnsSdDelegate* delegate,
- const std::string& service_type,
- local_discovery::ServiceDiscoverySharedClient* service_discovery_client);
+ const std::string& service_type);
virtual ~DnsSdDeviceLister();
- // Requests that the service watcher issue an immediate query for services.
- // force_update will first clear the service cache. This must be called
- // to instantiate the service watcher and start discovery.
virtual void Discover(bool force_update);
protected:
- // Invoked when the watcher notifies us of a service change.
- void OnServiceUpdated(
- local_discovery::ServiceWatcher::UpdateType update,
- const std::string& service_name);
-
- void OnResolveComplete(
- bool added,
- local_discovery::ServiceResolver::RequestStatus status,
- const local_discovery::ServiceDescription& description);
+ virtual void OnDeviceChanged(
+ bool added,
+ const local_discovery::ServiceDescription& service_description) OVERRIDE;
+ virtual void OnDeviceRemoved(const std::string& service_name) OVERRIDE;
+ virtual void OnDeviceCacheFlushed() OVERRIDE;
private:
- typedef std::map<std::string, linked_ptr<local_discovery::ServiceResolver> >
- ServiceResolverMap;
-
// The delegate to notify of changes to services.
DnsSdDelegate* const delegate_;
-
- // The service type for this watcher.
- const std::string service_type_;
-
- // The instance of the service discovery client.
- scoped_refptr<local_discovery::ServiceDiscoverySharedClient>
- service_discovery_client_;
-
- // The instance of the service watcher.
- scoped_ptr<local_discovery::ServiceWatcher> service_watcher_;
-
- ServiceResolverMap resolvers_;
+ local_discovery::ServiceDiscoveryDeviceLister device_lister_;
+ bool started_;
DISALLOW_COPY_AND_ASSIGN(DnsSdDeviceLister);
};
diff --git a/chrome/browser/extensions/api/mdns/dns_sd_registry.cc b/chrome/browser/extensions/api/mdns/dns_sd_registry.cc
index 6a72fc52ff..e4e92dd4c5 100644
--- a/chrome/browser/extensions/api/mdns/dns_sd_registry.cc
+++ b/chrome/browser/extensions/api/mdns/dns_sd_registry.cc
@@ -73,6 +73,14 @@ bool DnsSdRegistry::ServiceTypeData::RemoveService(
return false;
};
+bool DnsSdRegistry::ServiceTypeData::ClearServices() {
+ if (service_list_.empty())
+ return false;
+
+ service_list_.clear();
+ return true;
+}
+
const DnsSdRegistry::DnsSdServiceList&
DnsSdRegistry::ServiceTypeData::GetServiceList() {
return service_list_;
@@ -102,14 +110,14 @@ DnsSdDeviceLister* DnsSdRegistry::CreateDnsSdDeviceLister(
DnsSdDelegate* delegate,
const std::string& service_type,
local_discovery::ServiceDiscoverySharedClient* discovery_client) {
- return new DnsSdDeviceLister(delegate, service_type, discovery_client);
+ return new DnsSdDeviceLister(discovery_client, delegate, service_type);
}
void DnsSdRegistry::RegisterDnsSdListener(std::string service_type) {
if (service_type.empty())
return;
- if (service_data_map_.find(service_type) != service_data_map_.end()) {
+ if (IsRegistered(service_type)) {
service_data_map_[service_type]->ListenerAdded();
DispatchApiEvent(service_type);
return;
@@ -137,7 +145,7 @@ void DnsSdRegistry::UnregisterDnsSdListener(std::string service_type) {
void DnsSdRegistry::ServiceChanged(const std::string& service_type,
bool added,
const DnsSdService& service) {
- if (service_data_map_.find(service_type) == service_data_map_.end())
+ if (!IsRegistered(service_type))
return;
if (service_data_map_[service_type]->UpdateService(added, service)) {
@@ -150,7 +158,7 @@ void DnsSdRegistry::ServiceChanged(const std::string& service_type,
void DnsSdRegistry::ServiceRemoved(const std::string& service_type,
const std::string& service_name) {
- if (service_data_map_.find(service_type) == service_data_map_.end())
+ if (!IsRegistered(service_type))
return;
if (service_data_map_[service_type]->RemoveService(service_name)) {
@@ -160,9 +168,23 @@ void DnsSdRegistry::ServiceRemoved(const std::string& service_type,
}
}
+void DnsSdRegistry::ServicesFlushed(const std::string& service_type) {
+ if (!IsRegistered(service_type))
+ return;
+
+ if (service_data_map_[service_type]->ClearServices())
+ DispatchApiEvent(service_type);
+}
+
void DnsSdRegistry::DispatchApiEvent(const std::string& service_type) {
+ // TODO(justinlin): Make this MaybeDispatchApiEvent instead and dispatch if a
+ // dirty bit is set.
FOR_EACH_OBSERVER(DnsSdObserver, observers_, OnDnsSdEvent(
service_type, service_data_map_[service_type]->GetServiceList()));
}
+bool DnsSdRegistry::IsRegistered(const std::string& service_type) {
+ return service_data_map_.find(service_type) != service_data_map_.end();
+}
+
} // namespace extensions
diff --git a/chrome/browser/extensions/api/mdns/dns_sd_registry.h b/chrome/browser/extensions/api/mdns/dns_sd_registry.h
index 79d898809f..e3d59d8461 100644
--- a/chrome/browser/extensions/api/mdns/dns_sd_registry.h
+++ b/chrome/browser/extensions/api/mdns/dns_sd_registry.h
@@ -68,6 +68,7 @@ class DnsSdRegistry : public DnsSdDelegate {
// Methods for adding, updating or removing services for this service type.
bool UpdateService(bool added, const DnsSdService& service);
bool RemoveService(const std::string& service_name);
+ bool ClearServices();
const DnsSdRegistry::DnsSdServiceList& GetServiceList();
@@ -93,11 +94,13 @@ class DnsSdRegistry : public DnsSdDelegate {
const DnsSdService& service) OVERRIDE;
virtual void ServiceRemoved(const std::string& service_type,
const std::string& service_name) OVERRIDE;
+ virtual void ServicesFlushed(const std::string& service_type) OVERRIDE;
DnsSdServiceTypeDataMap service_data_map_;
private:
void DispatchApiEvent(const std::string& service_type);
+ bool IsRegistered(const std::string& service_type);
scoped_refptr<local_discovery::ServiceDiscoverySharedClient>
service_discovery_client_;
diff --git a/chrome/browser/extensions/api/mdns/dns_sd_registry_unittest.cc b/chrome/browser/extensions/api/mdns/dns_sd_registry_unittest.cc
index 451dc6ad3b..ee9bbe58a8 100644
--- a/chrome/browser/extensions/api/mdns/dns_sd_registry_unittest.cc
+++ b/chrome/browser/extensions/api/mdns/dns_sd_registry_unittest.cc
@@ -13,10 +13,10 @@ namespace extensions {
class MockDnsSdDeviceLister : public DnsSdDeviceLister {
public:
- MockDnsSdDeviceLister() : DnsSdDeviceLister(NULL, "", NULL) {}
+ MockDnsSdDeviceLister() : DnsSdDeviceLister(NULL, NULL, "") {}
virtual ~MockDnsSdDeviceLister() {}
- virtual void Discover(bool forced) OVERRIDE {}
+ virtual void Discover(bool force_update) OVERRIDE {}
};
class TestDnsSdRegistry : public DnsSdRegistry {
@@ -43,8 +43,8 @@ class TestDnsSdRegistry : public DnsSdRegistry {
virtual DnsSdDeviceLister* CreateDnsSdDeviceLister(
DnsSdDelegate* delegate,
const std::string& service_type,
- local_discovery::ServiceDiscoverySharedClient*
- discovery_client) OVERRIDE {
+ local_discovery::ServiceDiscoverySharedClient* discovery_client)
+ OVERRIDE {
delegate_ = delegate;
MockDnsSdDeviceLister* lister = new MockDnsSdDeviceLister();
listers_[service_type] = lister;
@@ -173,4 +173,33 @@ TEST_F(DnsSdRegistryTest, AddMultipleServices) {
registry_->GetDelegate()->ServiceChanged(service_type, true, service2);
}
+// Tests adding multiple services and handling a flush event.
+TEST_F(DnsSdRegistryTest, FlushCache) {
+ testing::InSequence s;
+ const std::string service_type = "_testing._tcp.local";
+
+ DnsSdService service;
+ service.service_name = "_myDevice." + service_type;
+ service.ip_address = "192.168.0.100";
+
+ DnsSdService service2;
+ service.service_name = "_myDevice2." + service_type;
+ service.ip_address = "192.168.0.101";
+
+ DnsSdRegistry::DnsSdServiceList service_list;
+ EXPECT_CALL(observer_, OnDnsSdEvent(service_type, service_list));
+ service_list.push_back(service);
+ EXPECT_CALL(observer_, OnDnsSdEvent(service_type, service_list));
+ service_list.push_back(service2);
+ EXPECT_CALL(observer_, OnDnsSdEvent(service_type, service_list));
+ service_list.clear();
+ EXPECT_CALL(observer_, OnDnsSdEvent(service_type, service_list));
+
+ registry_->RegisterDnsSdListener(service_type);
+ registry_->GetDelegate()->ServiceChanged(service_type, true, service);
+ registry_->GetDelegate()->ServiceChanged(service_type, true, service2);
+ registry_->GetDelegate()->ServicesFlushed(service_type);
+}
+
+
} // namespace extensions
diff --git a/chrome/browser/extensions/api/media_galleries/media_galleries_api.cc b/chrome/browser/extensions/api/media_galleries/media_galleries_api.cc
index c07e229b65..0358fa31fd 100644
--- a/chrome/browser/extensions/api/media_galleries/media_galleries_api.cc
+++ b/chrome/browser/extensions/api/media_galleries/media_galleries_api.cc
@@ -196,11 +196,10 @@ void MediaGalleriesGetMediaFileSystemsFunction::ReturnGalleries(
if (filesystems[i].path.empty())
continue;
- if (has_read_permission || has_copy_to_permission) {
+ if (has_read_permission) {
content::ChildProcessSecurityPolicy* policy =
ChildProcessSecurityPolicy::GetInstance();
- if (has_read_permission)
- policy->GrantReadFileSystem(child_id, filesystems[i].fsid);
+ policy->GrantReadFileSystem(child_id, filesystems[i].fsid);
if (has_copy_to_permission)
policy->GrantCopyIntoFileSystem(child_id, filesystems[i].fsid);
}
diff --git a/chrome/browser/extensions/api/media_galleries_private/media_galleries_private_api.cc b/chrome/browser/extensions/api/media_galleries_private/media_galleries_private_api.cc
index 34801a4461..2fb85d7de3 100644
--- a/chrome/browser/extensions/api/media_galleries_private/media_galleries_private_api.cc
+++ b/chrome/browser/extensions/api/media_galleries_private/media_galleries_private_api.cc
@@ -19,6 +19,7 @@
#include "chrome/browser/extensions/extension_function.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/media_galleries/media_file_system_registry.h"
#include "chrome/browser/media_galleries/media_galleries_preferences.h"
#include "chrome/browser/profiles/profile.h"
@@ -381,7 +382,7 @@ bool MediaGalleriesPrivateGetHandlersFunction::RunImpl() {
++iter) {
const Extension* extension = iter->get();
if (profile_->IsOffTheRecord() &&
- !service->IsIncognitoEnabled(extension->id()))
+ !extension_util::IsIncognitoEnabled(extension->id(), service))
continue;
MediaGalleriesHandler::List* handler_list =
diff --git a/chrome/browser/extensions/api/media_galleries_private/media_galleries_watch_apitest.cc b/chrome/browser/extensions/api/media_galleries_private/media_galleries_watch_apitest.cc
index bc98bb11a5..1447203859 100644
--- a/chrome/browser/extensions/api/media_galleries_private/media_galleries_watch_apitest.cc
+++ b/chrome/browser/extensions/api/media_galleries_private/media_galleries_watch_apitest.cc
@@ -26,6 +26,7 @@ namespace {
const char kTestExtensionId[] = "gceegfkgibmgpfopknlcgleimclbknie";
const char kTestExtensionPath[] = "media_galleries_private/gallerywatch";
+#if !defined(OS_CHROMEOS)
// JS commands.
const char kGetAllWatchedGalleryIdsCmd[] = "getAllWatchedGalleryIds()";
const char kGetMediaFileSystemsCmd[] = "getMediaFileSystems()";
@@ -62,6 +63,7 @@ const char kGalleryChangedEventReceived[] = "gallery_changed_event_received";
const char kGetAllGalleryWatchResultB[] =
"watchers_for_galleries_{1, 2, 3}_found";
#endif // defined(OS_WIN)
+#endif // !defined(OS_CHROMEOS)
} // namespace
diff --git a/chrome/browser/extensions/api/messaging/incognito_connectability.cc b/chrome/browser/extensions/api/messaging/incognito_connectability.cc
new file mode 100644
index 0000000000..eca7bd22a9
--- /dev/null
+++ b/chrome/browser/extensions/api/messaging/incognito_connectability.cc
@@ -0,0 +1,124 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/api/messaging/incognito_connectability.h"
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/ui/simple_message_box.h"
+#include "chrome/common/extensions/extension.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_view.h"
+#include "grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace extensions {
+
+namespace {
+IncognitoConnectability::ScopedAlertTracker::Mode g_alert_mode =
+ IncognitoConnectability::ScopedAlertTracker::INTERACTIVE;
+int g_alert_count = 0;
+}
+
+IncognitoConnectability::ScopedAlertTracker::ScopedAlertTracker(Mode mode)
+ : last_checked_invocation_count_(g_alert_count) {
+ DCHECK_EQ(INTERACTIVE, g_alert_mode);
+ DCHECK_NE(INTERACTIVE, mode);
+ g_alert_mode = mode;
+}
+
+IncognitoConnectability::ScopedAlertTracker::~ScopedAlertTracker() {
+ DCHECK_NE(INTERACTIVE, g_alert_mode);
+ g_alert_mode = INTERACTIVE;
+}
+
+int IncognitoConnectability::ScopedAlertTracker::GetAndResetAlertCount() {
+ int result = g_alert_count - last_checked_invocation_count_;
+ last_checked_invocation_count_ = g_alert_count;
+ return result;
+}
+
+IncognitoConnectability::IncognitoConnectability(Profile* profile) {
+ CHECK(profile->IsOffTheRecord());
+}
+
+IncognitoConnectability::~IncognitoConnectability() {
+}
+
+// static
+IncognitoConnectability* IncognitoConnectability::Get(Profile* profile) {
+ return ProfileKeyedAPIFactory<IncognitoConnectability>::GetForProfile(
+ profile);
+}
+
+bool IncognitoConnectability::Query(const Extension* extension,
+ content::WebContents* web_contents,
+ const GURL& url) {
+ GURL origin = url.GetOrigin();
+ if (origin.is_empty())
+ return false;
+
+ if (IsInMap(extension, origin, allowed_origins_))
+ return true;
+ if (IsInMap(extension, origin, disallowed_origins_))
+ return false;
+
+ // We need to ask the user.
+ ++g_alert_count;
+ chrome::MessageBoxResult result = chrome::MESSAGE_BOX_RESULT_NO;
+
+ switch (g_alert_mode) {
+ // Production code should always be using INTERACTIVE.
+ case ScopedAlertTracker::INTERACTIVE: {
+ int template_id = extension->is_app() ?
+ IDS_EXTENSION_PROMPT_APP_CONNECT_FROM_INCOGNITO :
+ IDS_EXTENSION_PROMPT_EXTENSION_CONNECT_FROM_INCOGNITO;
+ result = chrome::ShowMessageBox(
+ web_contents ? web_contents->GetView()->GetTopLevelNativeWindow()
+ : NULL,
+ string16(), // no title
+ l10n_util::GetStringFUTF16(template_id,
+ UTF8ToUTF16(origin.spec()),
+ UTF8ToUTF16(extension->name())),
+ chrome::MESSAGE_BOX_TYPE_QUESTION);
+ break;
+ }
+
+ // Testing code can override to always allow or deny.
+ case ScopedAlertTracker::ALWAYS_ALLOW:
+ result = chrome::MESSAGE_BOX_RESULT_YES;
+ break;
+ case ScopedAlertTracker::ALWAYS_DENY:
+ result = chrome::MESSAGE_BOX_RESULT_NO;
+ break;
+ }
+
+ if (result == chrome::MESSAGE_BOX_RESULT_NO) {
+ disallowed_origins_[extension->id()].insert(origin);
+ return false;
+ }
+ allowed_origins_[extension->id()].insert(origin);
+ return true;
+}
+
+bool IncognitoConnectability::IsInMap(const Extension* extension,
+ const GURL& origin,
+ const ExtensionToOriginsMap& map) {
+ DCHECK_EQ(origin, origin.GetOrigin());
+ ExtensionToOriginsMap::const_iterator it = map.find(extension->id());
+ return it != map.end() && it->second.count(origin) > 0;
+}
+
+static base::LazyInstance<ProfileKeyedAPIFactory<IncognitoConnectability> >
+ g_factory = LAZY_INSTANCE_INITIALIZER;
+
+// static
+ProfileKeyedAPIFactory<IncognitoConnectability>*
+IncognitoConnectability::GetFactoryInstance() {
+ return &g_factory.Get();
+}
+
+} // namespace extensions
diff --git a/chrome/browser/extensions/api/messaging/incognito_connectability.h b/chrome/browser/extensions/api/messaging/incognito_connectability.h
new file mode 100644
index 0000000000..6b680ab115
--- /dev/null
+++ b/chrome/browser/extensions/api/messaging/incognito_connectability.h
@@ -0,0 +1,93 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_API_MESSAGING_INCOGNITO_CONNECTABILITY_H_
+#define CHROME_BROWSER_EXTENSIONS_API_MESSAGING_INCOGNITO_CONNECTABILITY_H_
+
+#include <set>
+
+#include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
+#include "url/gurl.h"
+
+class Profile;
+namespace content {
+class WebContents;
+}
+
+namespace extensions {
+class Extension;
+
+// Tracks the web connectability of domains to extensions in incognito mode.
+//
+// The most important functionality is prompting the user to allow or disallow
+// connections from incognito tabs to extensions or apps. Even if an extension
+// hasn't been enabled in incognito mode, it's still useful for web sites to be
+// able to send messages to them, with user constent. For apps, it's essential
+// we have this functionality because there is no way for them to be enabled in
+// incognito.
+class IncognitoConnectability : public ProfileKeyedAPI {
+ public:
+ // While in scope, immediately either accepts or denies the alerts that show
+ // up, and counts the number of times it was invoked.
+ class ScopedAlertTracker {
+ public:
+ enum Mode {
+ INTERACTIVE,
+ ALWAYS_ALLOW,
+ ALWAYS_DENY,
+ };
+
+ explicit ScopedAlertTracker(Mode mode);
+
+ ~ScopedAlertTracker();
+
+ // Returns the number of times the alert has been shown since
+ // GetAndResetAlertCount was last called.
+ int GetAndResetAlertCount();
+
+ private:
+ int last_checked_invocation_count_;
+ };
+
+ // Returns the IncognitoConnectability object for |profile|. |profile| must
+ // be off-the-record.
+ static IncognitoConnectability* Get(Profile* profile);
+
+ // Returns true if |url| is allowed to connect from this profile, false
+ // otherwise. If unknown, this call will block and prompt the user.
+ bool Query(const Extension* extension,
+ content::WebContents* web_contents,
+ const GURL& url);
+
+ private:
+ friend class ProfileKeyedAPIFactory<IncognitoConnectability>;
+
+ explicit IncognitoConnectability(Profile* profile);
+ virtual ~IncognitoConnectability();
+
+ typedef std::map<std::string, std::set<GURL> > ExtensionToOriginsMap;
+
+ // Returns true if the (|extension|, |origin|) pair appears in the map.
+ bool IsInMap(const Extension* extension,
+ const GURL& origin,
+ const ExtensionToOriginsMap& map);
+
+ // ProfileKeyedAPI implementation.
+ static ProfileKeyedAPIFactory<IncognitoConnectability>* GetFactoryInstance();
+ static const char* service_name() {
+ return "Messaging.IncognitoConnectability";
+ }
+ static const bool kServiceHasOwnInstanceInIncognito = true;
+ static const bool kServiceIsCreatedWithBrowserContext = false;
+
+ // The origins that have been prompted for and either allowed or disallowed.
+ // These are deliberately stored in-memory so that they're reset when the
+ // profile is destroyed (i.e. when the last incognito window is closed).
+ ExtensionToOriginsMap allowed_origins_;
+ ExtensionToOriginsMap disallowed_origins_;
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_API_MESSAGING_INCOGNITO_CONNECTABILITY_H_
diff --git a/chrome/browser/extensions/api/messaging/message_service.cc b/chrome/browser/extensions/api/messaging/message_service.cc
index db57a4e2aa..754bc101b4 100644
--- a/chrome/browser/extensions/api/messaging/message_service.cc
+++ b/chrome/browser/extensions/api/messaging/message_service.cc
@@ -14,12 +14,14 @@
#include "base/values.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/extensions/api/messaging/extension_message_port.h"
+#include "chrome/browser/extensions/api/messaging/incognito_connectability.h"
#include "chrome/browser/extensions/api/messaging/native_message_port.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_process_manager.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/extensions/extension_tab_util.h"
+#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/extensions/lazy_background_task_queue.h"
#include "chrome/browser/extensions/process_map.h"
#include "chrome/browser/profiles/profile.h"
@@ -27,7 +29,6 @@
#include "chrome/common/extensions/background_info.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_messages.h"
-#include "chrome/common/extensions/features/simple_feature.h"
#include "chrome/common/extensions/incognito_handler.h"
#include "chrome/common/extensions/manifest_handlers/externally_connectable.h"
#include "content/public/browser/notification_service.h"
@@ -60,8 +61,10 @@ namespace extensions {
const char kReceivingEndDoesntExistError[] =
"Could not establish connection. Receiving end does not exist.";
+#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
const char kMissingPermissionError[] =
"Access to native messaging requires nativeMessaging permission.";
+#endif
struct MessageService::MessageChannel {
scoped_ptr<MessagePort> opener;
@@ -207,23 +210,7 @@ void MessageService::OpenChannelToExtension(
return;
}
- ExtensionService* extension_service =
- ExtensionSystem::Get(profile)->extension_service();
-
- if (profile->IsOffTheRecord() &&
- !extension_service->IsIncognitoEnabled(target_extension_id)) {
- // Allow the security token apps (normal, dev) to be connectable from
- // incognito profiles. See http://crbug.com/295845.
- std::set<std::string> incognito_whitelist;
- incognito_whitelist.insert("E4FCC42F7C7776C0985996DAED74F630C4F0A785");
- incognito_whitelist.insert("D3D12919F7F00FE553E8A573AAA7147C51DD65C9");
- if (!extensions::SimpleFeature::IsIdInWhitelist(target_extension_id,
- incognito_whitelist)) {
- DispatchOnDisconnect(
- source, receiver_port_id, kReceivingEndDoesntExistError);
- return;
- }
- }
+ bool is_web_connection = false;
if (source_extension_id != target_extension_id) {
// It's an external connection. Check the externally_connectable manifest
@@ -239,6 +226,7 @@ void MessageService::OpenChannelToExtension(
if (source_extension_id.empty()) {
// No source extension ID so the source was a web page. Check that the
// URL matches.
+ is_web_connection = true;
is_externally_connectable =
externally_connectable->matches.MatchesURL(source_url);
// Only include the TLS channel ID for externally connected web pages.
@@ -266,14 +254,35 @@ void MessageService::OpenChannelToExtension(
}
}
+ ExtensionService* extension_service =
+ ExtensionSystem::Get(profile)->extension_service();
+ WebContents* source_contents = tab_util::GetWebContentsByID(
+ source_process_id, source_routing_id);
+
+ if (profile->IsOffTheRecord() &&
+ !extension_util::IsIncognitoEnabled(target_extension_id,
+ extension_service)) {
+ // Give the user a chance to accept an incognito connection if they haven't
+ // already - but only for spanning-mode incognito. We don't want the
+ // complication of spinning up an additional process here which might need
+ // to do some setup that we're not expecting.
+ if (!is_web_connection ||
+ IncognitoInfo::IsSplitMode(target_extension) ||
+ !IncognitoConnectability::Get(profile)->Query(target_extension,
+ source_contents,
+ source_url)) {
+ DispatchOnDisconnect(
+ source, receiver_port_id, kReceivingEndDoesntExistError);
+ return;
+ }
+ }
+
// Note: we use the source's profile here. If the source is an incognito
// process, we will use the incognito EPM to find the right extension process,
// which depends on whether the extension uses spanning or split mode.
MessagePort* receiver = new ExtensionMessagePort(
GetExtensionProcess(profile, target_extension_id), MSG_ROUTING_CONTROL,
target_extension_id);
- WebContents* source_contents = tab_util::GetWebContentsByID(
- source_process_id, source_routing_id);
// Include info about the opener's tab (if it was a tab).
scoped_ptr<base::DictionaryValue> source_tab;
diff --git a/chrome/browser/extensions/api/module/module.cc b/chrome/browser/extensions/api/module/module.cc
index b1295d1650..31e849c1d5 100644
--- a/chrome/browser/extensions/api/module/module.cc
+++ b/chrome/browser/extensions/api/module/module.cc
@@ -10,6 +10,7 @@
#include "chrome/browser/extensions/extension_prefs.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/profiles/profile.h"
namespace extensions {
@@ -51,7 +52,7 @@ bool ExtensionIsAllowedIncognitoAccessFunction::RunImpl() {
const Extension* extension = GetExtension();
SetResult(new base::FundamentalValue(
- ext_service->IsIncognitoEnabled(extension->id())));
+ extension_util::IsIncognitoEnabled(extension->id(), ext_service)));
return true;
}
@@ -61,7 +62,7 @@ bool ExtensionIsAllowedFileSchemeAccessFunction::RunImpl() {
const Extension* extension = GetExtension();
SetResult(new base::FundamentalValue(
- ext_service->AllowFileAccess(extension)));
+ extension_util::AllowFileAccess(extension, ext_service)));
return true;
}
diff --git a/chrome/browser/extensions/api/music_manager_private/device_id_chromeos.cc b/chrome/browser/extensions/api/music_manager_private/device_id_chromeos.cc
index 2e79c62925..5d392b4c3c 100644
--- a/chrome/browser/extensions/api/music_manager_private/device_id_chromeos.cc
+++ b/chrome/browser/extensions/api/music_manager_private/device_id_chromeos.cc
@@ -5,7 +5,7 @@
#include "chrome/browser/extensions/api/music_manager_private/device_id.h"
#include "base/message_loop/message_loop.h"
-#include "chromeos/cryptohome/cryptohome_library.h"
+#include "chromeos/cryptohome/system_salt_getter.h"
namespace extensions {
namespace api {
@@ -13,7 +13,7 @@ namespace api {
// ChromeOS: Use the System Salt.
/* static */
void DeviceId::GetMachineId(const IdCallback& callback) {
- chromeos::CryptohomeLibrary* c_home = chromeos::CryptohomeLibrary::Get();
+ chromeos::SystemSaltGetter* c_home = chromeos::SystemSaltGetter::Get();
std::string result = c_home->GetSystemSaltSync();
if (result.empty()) {
// cryptohome must not be running; re-request after a delay.
diff --git a/chrome/browser/extensions/api/networking_private/networking_private_api.h b/chrome/browser/extensions/api/networking_private/networking_private_api.h
index 754219a592..08b2708936 100644
--- a/chrome/browser/extensions/api/networking_private/networking_private_api.h
+++ b/chrome/browser/extensions/api/networking_private/networking_private_api.h
@@ -136,6 +136,60 @@ class NetworkingPrivateGetVisibleNetworksFunction
DISALLOW_COPY_AND_ASSIGN(NetworkingPrivateGetVisibleNetworksFunction);
};
+// Implements the chrome.networkingPrivate.getEnabledNetworkTypes method.
+class NetworkingPrivateGetEnabledNetworkTypesFunction
+ : public SyncExtensionFunction {
+ public:
+ NetworkingPrivateGetEnabledNetworkTypesFunction() {}
+ DECLARE_EXTENSION_FUNCTION("networkingPrivate.getEnabledNetworkTypes",
+ NETWORKINGPRIVATE_GETENABLEDNETWORKTYPES);
+
+ protected:
+ virtual ~NetworkingPrivateGetEnabledNetworkTypesFunction();
+
+ // SyncExtensionFunction overrides.
+ virtual bool RunImpl() OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NetworkingPrivateGetEnabledNetworkTypesFunction);
+};
+
+// Implements the chrome.networkingPrivate.enableNetworkType method.
+class NetworkingPrivateEnableNetworkTypeFunction
+ : public SyncExtensionFunction {
+ public:
+ NetworkingPrivateEnableNetworkTypeFunction() {}
+ DECLARE_EXTENSION_FUNCTION("networkingPrivate.enableNetworkType",
+ NETWORKINGPRIVATE_ENABLENETWORKTYPE);
+
+ protected:
+ virtual ~NetworkingPrivateEnableNetworkTypeFunction();
+
+ // SyncExtensionFunction overrides.
+ virtual bool RunImpl() OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NetworkingPrivateEnableNetworkTypeFunction);
+};
+
+// Implements the chrome.networkingPrivate.disableNetworkType method.
+class NetworkingPrivateDisableNetworkTypeFunction
+ : public SyncExtensionFunction {
+ public:
+ NetworkingPrivateDisableNetworkTypeFunction() {}
+ DECLARE_EXTENSION_FUNCTION("networkingPrivate.disableNetworkType",
+ NETWORKINGPRIVATE_DISABLENETWORKTYPE);
+
+ protected:
+ virtual ~NetworkingPrivateDisableNetworkTypeFunction();
+
+ // SyncExtensionFunction overrides.
+ virtual bool RunImpl() OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NetworkingPrivateDisableNetworkTypeFunction);
+};
+
// Implements the chrome.networkingPrivate.requestNetworkScan method.
class NetworkingPrivateRequestNetworkScanFunction
: public SyncExtensionFunction {
diff --git a/chrome/browser/extensions/api/networking_private/networking_private_api_chromeos.cc b/chrome/browser/extensions/api/networking_private/networking_private_api_chromeos.cc
index 96aa57a11e..a2f6e797fe 100644
--- a/chrome/browser/extensions/api/networking_private/networking_private_api_chromeos.cc
+++ b/chrome/browser/extensions/api/networking_private/networking_private_api_chromeos.cc
@@ -22,6 +22,7 @@
#include "chromeos/network/network_state_handler.h"
#include "chromeos/network/onc/onc_signature.h"
#include "chromeos/network/onc/onc_translator.h"
+#include "chromeos/network/shill_property_util.h"
#include "components/onc/onc_constants.h"
namespace api = extensions::api::networking_private;
@@ -31,6 +32,7 @@ using chromeos::ManagedNetworkConfigurationHandler;
using chromeos::NetworkHandler;
using chromeos::NetworkState;
using chromeos::NetworkStateHandler;
+using chromeos::NetworkTypePattern;
using chromeos::ShillManagerClient;
namespace {
@@ -305,6 +307,108 @@ bool NetworkingPrivateGetVisibleNetworksFunction::RunImpl() {
}
////////////////////////////////////////////////////////////////////////////////
+// NetworkingPrivateGetEnabledNetworkTypesFunction
+
+NetworkingPrivateGetEnabledNetworkTypesFunction::
+~NetworkingPrivateGetEnabledNetworkTypesFunction() {
+}
+
+bool NetworkingPrivateGetEnabledNetworkTypesFunction::RunImpl() {
+ NetworkStateHandler* state_handler =
+ NetworkHandler::Get()->network_state_handler();
+
+ base::ListValue* network_list = new base::ListValue;
+
+ if (state_handler->IsTechnologyEnabled(NetworkTypePattern::Ethernet()))
+ network_list->AppendString("Ethernet");
+ if (state_handler->IsTechnologyEnabled(NetworkTypePattern::WiFi()))
+ network_list->AppendString("WiFi");
+ if (state_handler->IsTechnologyEnabled(NetworkTypePattern::Cellular()))
+ network_list->AppendString("Cellular");
+
+ SetResult(network_list);
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NetworkingPrivateEnableNetworkTypeFunction
+
+NetworkingPrivateEnableNetworkTypeFunction::
+~NetworkingPrivateEnableNetworkTypeFunction() {
+}
+
+bool NetworkingPrivateEnableNetworkTypeFunction::RunImpl() {
+ scoped_ptr<api::EnableNetworkType::Params> params =
+ api::EnableNetworkType::Params::Create(*args_);
+ EXTENSION_FUNCTION_VALIDATE(params);
+ NetworkStateHandler* state_handler =
+ NetworkHandler::Get()->network_state_handler();
+
+ switch (params->network_type) {
+ case api::NETWORK_TYPE_ETHERNET:
+ state_handler->SetTechnologyEnabled(
+ NetworkTypePattern::Ethernet(), true,
+ chromeos::network_handler::ErrorCallback());
+ break;
+
+ case api::NETWORK_TYPE_WIFI:
+ state_handler->SetTechnologyEnabled(
+ NetworkTypePattern::WiFi(), true,
+ chromeos::network_handler::ErrorCallback());
+ break;
+
+ case api::NETWORK_TYPE_CELLULAR:
+ state_handler->SetTechnologyEnabled(
+ NetworkTypePattern::Cellular(), true,
+ chromeos::network_handler::ErrorCallback());
+ break;
+
+ default:
+ break;
+ }
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NetworkingPrivateDisableNetworkTypeFunction
+
+NetworkingPrivateDisableNetworkTypeFunction::
+~NetworkingPrivateDisableNetworkTypeFunction() {
+}
+
+bool NetworkingPrivateDisableNetworkTypeFunction::RunImpl() {
+ scoped_ptr<api::DisableNetworkType::Params> params =
+ api::DisableNetworkType::Params::Create(*args_);
+ NetworkStateHandler* state_handler =
+ NetworkHandler::Get()->network_state_handler();
+
+ switch (params->network_type) {
+ case api::NETWORK_TYPE_ETHERNET:
+ state_handler->SetTechnologyEnabled(
+ NetworkTypePattern::Ethernet(), false,
+ chromeos::network_handler::ErrorCallback());
+ break;
+
+ case api::NETWORK_TYPE_WIFI:
+ state_handler->SetTechnologyEnabled(
+ NetworkTypePattern::WiFi(), false,
+ chromeos::network_handler::ErrorCallback());
+ break;
+
+ case api::NETWORK_TYPE_CELLULAR:
+ state_handler->SetTechnologyEnabled(
+ NetworkTypePattern::Cellular(), false,
+ chromeos::network_handler::ErrorCallback());
+ break;
+
+ default:
+ break;
+ }
+
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
// NetworkingPrivateRequestNetworkScanFunction
NetworkingPrivateRequestNetworkScanFunction::
diff --git a/chrome/browser/extensions/api/networking_private/networking_private_api_nonchromeos.cc b/chrome/browser/extensions/api/networking_private/networking_private_api_nonchromeos.cc
index 167d853cbf..467b9b746b 100644
--- a/chrome/browser/extensions/api/networking_private/networking_private_api_nonchromeos.cc
+++ b/chrome/browser/extensions/api/networking_private/networking_private_api_nonchromeos.cc
@@ -290,6 +290,52 @@ bool NetworkingPrivateGetVisibleNetworksFunction::RunImpl() {
}
////////////////////////////////////////////////////////////////////////////////
+// NetworkingPrivateGetEnabledNetworkTypesFunction
+
+NetworkingPrivateGetEnabledNetworkTypesFunction::
+~NetworkingPrivateGetEnabledNetworkTypesFunction() {
+}
+
+bool NetworkingPrivateGetEnabledNetworkTypesFunction::RunImpl() {
+ base::ListValue* network_list = new base::ListValue;
+
+ network_list->Append(new base::StringValue("Ethernet"));
+ network_list->Append(new base::StringValue("WiFi"));
+ network_list->Append(new base::StringValue("Cellular"));
+
+ SetResult(network_list);
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NetworkingPrivateEnableNetworkTypeFunction
+
+NetworkingPrivateEnableNetworkTypeFunction::
+~NetworkingPrivateEnableNetworkTypeFunction() {
+}
+
+bool NetworkingPrivateEnableNetworkTypeFunction::RunImpl() {
+ scoped_ptr<api::EnableNetworkType::Params> params =
+ api::EnableNetworkType::Params::Create(*args_);
+ EXTENSION_FUNCTION_VALIDATE(params);
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NetworkingPrivateDisableNetworkTypeFunction
+
+NetworkingPrivateDisableNetworkTypeFunction::
+~NetworkingPrivateDisableNetworkTypeFunction() {
+}
+
+bool NetworkingPrivateDisableNetworkTypeFunction::RunImpl() {
+ scoped_ptr<api::DisableNetworkType::Params> params =
+ api::DisableNetworkType::Params::Create(*args_);
+ EXTENSION_FUNCTION_VALIDATE(params);
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
// NetworkingPrivateRequestNetworkScanFunction
NetworkingPrivateRequestNetworkScanFunction::
diff --git a/chrome/browser/extensions/api/notifications/notifications_api.cc b/chrome/browser/extensions/api/notifications/notifications_api.cc
index 3fa8c76927..16254322b2 100644
--- a/chrome/browser/extensions/api/notifications/notifications_api.cc
+++ b/chrome/browser/extensions/api/notifications/notifications_api.cc
@@ -323,6 +323,9 @@ bool NotificationsApiFunction::CreateNotification(
}
}
+ if (options->is_clickable.get())
+ optional_fields.clickable = *options->is_clickable;
+
NotificationsApiDelegate* api_delegate(new NotificationsApiDelegate(
this,
profile(),
@@ -435,6 +438,10 @@ bool NotificationsApiFunction::UpdateNotification(
}
}
+ // Then override if it's already set.
+ if (options->is_clickable.get())
+ notification->set_clickable(*options->is_clickable);
+
g_browser_process->notification_ui_manager()->Update(
*notification, profile());
return true;
@@ -531,11 +538,13 @@ bool NotificationsUpdateFunction::RunNotificationsApi() {
return true;
}
+ // Copy the existing notification to get a writable version of it.
+ Notification notification = *matched_notification;
+
// If we have trouble updating the notification (could be improper use of API
// or some other reason), mark the function as failed, calling the callback
// with false.
// TODO(dewittj): Add more human-readable error strings if this fails.
- Notification notification = *matched_notification;
bool could_update_notification = UpdateNotification(
params_->notification_id, &params_->options, &notification);
SetResult(new base::FundamentalValue(could_update_notification));
diff --git a/chrome/browser/extensions/api/permissions/permissions_api.cc b/chrome/browser/extensions/api/permissions/permissions_api.cc
index 9fc653685c..cf23aa049b 100644
--- a/chrome/browser/extensions/api/permissions/permissions_api.cc
+++ b/chrome/browser/extensions/api/permissions/permissions_api.cc
@@ -14,6 +14,7 @@
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/permissions/permissions_data.h"
#include "extensions/common/error_utils.h"
+#include "extensions/common/permissions/permission_message_provider.h"
#include "extensions/common/permissions/permissions_info.h"
#include "extensions/common/url_pattern_set.h"
#include "url/gurl.h"
@@ -205,8 +206,9 @@ bool PermissionsRequestFunction::RunImpl() {
// We don't need to show the prompt if there are no new warnings, or if
// we're skipping the confirmation UI. All extension types but INTERNAL
// are allowed to silently increase their permission level.
- bool has_no_warnings = requested_permissions_->GetWarningMessages(
- GetExtension()->GetType()).empty();
+ bool has_no_warnings =
+ PermissionMessageProvider::Get()->GetWarningMessages(
+ requested_permissions_, GetExtension()->GetType()).empty();
if (auto_confirm_for_tests == PROCEED || has_no_warnings ||
extension_->location() == Manifest::COMPONENT) {
InstallUIProceed();
diff --git a/chrome/browser/extensions/api/preference/preference_apitest.cc b/chrome/browser/extensions/api/preference/preference_apitest.cc
index bbb4cab5d8..6e0bcb3880 100644
--- a/chrome/browser/extensions/api/preference/preference_apitest.cc
+++ b/chrome/browser/extensions/api/preference/preference_apitest.cc
@@ -111,7 +111,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionPreferenceApiTest, MAYBE_Standard) {
CheckPreferencesSet();
// The settings should not be reset when the extension is reloaded.
- ReloadExtension(last_loaded_extension_id_);
+ ReloadExtension(last_loaded_extension_id());
CheckPreferencesSet();
// Uninstalling and installing the extension (without running the test that
@@ -119,7 +119,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionPreferenceApiTest, MAYBE_Standard) {
content::WindowedNotificationObserver observer(
chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
content::NotificationService::AllSources());
- UninstallExtension(last_loaded_extension_id_);
+ UninstallExtension(last_loaded_extension_id());
observer.Wait();
CheckPreferencesCleared();
diff --git a/chrome/browser/extensions/api/preference/preference_helpers.cc b/chrome/browser/extensions/api/preference/preference_helpers.cc
index 8649f8eb04..162e2ae862 100644
--- a/chrome/browser/extensions/api/preference/preference_helpers.cc
+++ b/chrome/browser/extensions/api/preference/preference_helpers.cc
@@ -12,6 +12,7 @@
#include "chrome/browser/extensions/extension_prefs.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/incognito_handler.h"
@@ -102,7 +103,7 @@ void DispatchEventToExtensions(
if (router->ExtensionHasEventListener(extension_id, event_name) &&
(*it)->HasAPIPermission(permission) &&
(!incognito || IncognitoInfo::IsSplitMode(it->get()) ||
- extension_service->CanCrossIncognito(it->get()))) {
+ extension_util::CanCrossIncognito(it->get(), extension_service))) {
// Inject level of control key-value.
base::DictionaryValue* dict;
bool rv = args->GetDictionary(0, &dict);
@@ -118,7 +119,9 @@ void DispatchEventToExtensions(
Profile* restrict_to_profile = NULL;
bool from_incognito = false;
if (IncognitoInfo::IsSplitMode(it->get())) {
- if (incognito && extension_service->IsIncognitoEnabled(extension_id)) {
+ if (incognito &&
+ extension_util::IsIncognitoEnabled(extension_id,
+ extension_service)) {
restrict_to_profile = profile->GetOffTheRecordProfile();
} else if (!incognito &&
PreferenceAPI::Get(profile)->DoesExtensionControlPref(
diff --git a/chrome/browser/extensions/api/processes/processes_apitest.cc b/chrome/browser/extensions/api/processes/processes_apitest.cc
index f6e1f0a2d7..db840e1346 100644
--- a/chrome/browser/extensions/api/processes/processes_apitest.cc
+++ b/chrome/browser/extensions/api/processes/processes_apitest.cc
@@ -50,7 +50,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ProcessesVsTaskManager) {
EXPECT_EQ(TaskManagerModel::TASK_PENDING, model->update_state_);
// Unload the extension and check that listener count decreases
- UnloadExtension(last_loaded_extension_id_);
+ UnloadExtension(last_loaded_extension_id());
EXPECT_EQ(1, model->update_requests_);
}
diff --git a/chrome/browser/extensions/api/socket/tcp_socket.cc b/chrome/browser/extensions/api/socket/tcp_socket.cc
index 8401dc2674..4f9273468a 100644
--- a/chrome/browser/extensions/api/socket/tcp_socket.cc
+++ b/chrome/browser/extensions/api/socket/tcp_socket.cc
@@ -28,6 +28,17 @@ ApiResourceManager<ResumableTCPSocket>::GetFactoryInstance() {
return &g_factory.Get();
}
+static base::LazyInstance<ProfileKeyedAPIFactory<
+ ApiResourceManager<ResumableTCPServerSocket> > >
+ g_server_factory = LAZY_INSTANCE_INITIALIZER;
+
+// static
+template <>
+ProfileKeyedAPIFactory<ApiResourceManager<ResumableTCPServerSocket> >*
+ApiResourceManager<ResumableTCPServerSocket>::GetFactoryInstance() {
+ return &g_server_factory.Get();
+}
+
TCPSocket::TCPSocket(const std::string& owner_extension_id)
: Socket(owner_extension_id),
socket_mode_(UNKNOWN) {
@@ -109,6 +120,10 @@ void TCPSocket::Disconnect() {
if (socket_.get())
socket_->Disconnect();
server_socket_.reset(NULL);
+ connect_callback_.Reset();
+ read_callback_.Reset();
+ accept_callback_.Reset();
+ accept_socket_.reset(NULL);
}
int TCPSocket::Bind(const std::string& address, int port) {
@@ -127,28 +142,23 @@ void TCPSocket::Read(int count,
if (!read_callback_.is_null()) {
callback.Run(net::ERR_IO_PENDING, NULL);
return;
- } else {
- read_callback_ = callback;
}
- int result = net::ERR_FAILED;
- scoped_refptr<net::IOBuffer> io_buffer;
- do {
- if (count < 0) {
- result = net::ERR_INVALID_ARGUMENT;
- break;
- }
+ if (count < 0) {
+ callback.Run(net::ERR_INVALID_ARGUMENT, NULL);
+ return;
+ }
- if (!socket_.get() || !IsConnected()) {
- result = net::ERR_SOCKET_NOT_CONNECTED;
- break;
- }
+ if (!socket_.get() || !IsConnected()) {
+ callback.Run(net::ERR_SOCKET_NOT_CONNECTED, NULL);
+ return;
+ }
- io_buffer = new net::IOBuffer(count);
- result = socket_->Read(io_buffer.get(), count,
- base::Bind(&TCPSocket::OnReadComplete, base::Unretained(this),
- io_buffer));
- } while (false);
+ read_callback_ = callback;
+ scoped_refptr<net::IOBuffer> io_buffer = new net::IOBuffer(count);
+ int result = socket_->Read(io_buffer.get(), count,
+ base::Bind(&TCPSocket::OnReadComplete, base::Unretained(this),
+ io_buffer));
if (result != net::ERR_IO_PENDING)
OnReadComplete(io_buffer, result);
@@ -266,8 +276,7 @@ void TCPSocket::RefreshConnectionStatus() {
if (!is_connected_) return;
if (server_socket_) return;
if (!socket_->IsConnected()) {
- is_connected_ = false;
- socket_->Disconnect();
+ Disconnect();
}
}
@@ -304,8 +313,28 @@ ResumableTCPSocket::ResumableTCPSocket(const std::string& owner_extension_id)
paused_(false) {
}
-bool ResumableTCPSocket::persistent() const {
- return persistent_;
+ResumableTCPSocket::ResumableTCPSocket(net::TCPClientSocket* tcp_client_socket,
+ const std::string& owner_extension_id,
+ bool is_connected)
+ : TCPSocket(tcp_client_socket, owner_extension_id, is_connected),
+ persistent_(false),
+ buffer_size_(0),
+ paused_(false) {
+}
+
+bool ResumableTCPSocket::IsPersistent() const {
+ return persistent();
+}
+
+ResumableTCPServerSocket::ResumableTCPServerSocket(
+ const std::string& owner_extension_id)
+ : TCPSocket(owner_extension_id),
+ persistent_(false),
+ paused_(false) {
+}
+
+bool ResumableTCPServerSocket::IsPersistent() const {
+ return persistent();
}
} // namespace extensions
diff --git a/chrome/browser/extensions/api/socket/tcp_socket.h b/chrome/browser/extensions/api/socket/tcp_socket.h
index c6848243af..6cda66c0ad 100644
--- a/chrome/browser/extensions/api/socket/tcp_socket.h
+++ b/chrome/browser/extensions/api/socket/tcp_socket.h
@@ -102,11 +102,17 @@ class TCPSocket : public Socket {
class ResumableTCPSocket : public TCPSocket {
public:
explicit ResumableTCPSocket(const std::string& owner_extension_id);
+ explicit ResumableTCPSocket(net::TCPClientSocket* tcp_client_socket,
+ const std::string& owner_extension_id,
+ bool is_connected);
+
+ // Overriden from ApiResource
+ virtual bool IsPersistent() const OVERRIDE;
const std::string& name() const { return name_; }
void set_name(const std::string& name) { name_ = name; }
- virtual bool persistent() const OVERRIDE;
+ bool persistent() const { return persistent_; }
void set_persistent(bool persistent) { persistent_ = persistent; }
int buffer_size() const { return buffer_size_; }
@@ -124,7 +130,7 @@ class ResumableTCPSocket : public TCPSocket {
// Application-defined string - see sockets_tcp.idl.
std::string name_;
// Flag indicating whether the socket is left open when the application is
- // suspended - see sockets_tcp.idl..
+ // suspended - see sockets_tcp.idl.
bool persistent_;
// The size of the buffer used to receive data - see sockets_tcp.idl.
int buffer_size_;
@@ -133,6 +139,41 @@ class ResumableTCPSocket : public TCPSocket {
bool paused_;
};
+// TCP Socket instances from the "sockets.tcpServer" namespace. These are
+// regular socket objects with additional properties related to the behavior
+// defined in the "sockets.tcpServer" namespace.
+class ResumableTCPServerSocket : public TCPSocket {
+ public:
+ explicit ResumableTCPServerSocket(const std::string& owner_extension_id);
+
+ // Overriden from ApiResource
+ virtual bool IsPersistent() const OVERRIDE;
+
+ const std::string& name() const { return name_; }
+ void set_name(const std::string& name) { name_ = name; }
+
+ bool persistent() const { return persistent_; }
+ void set_persistent(bool persistent) { persistent_ = persistent; }
+
+ bool paused() const { return paused_; }
+ void set_paused(bool paused) { paused_ = paused; }
+
+ private:
+ friend class ApiResourceManager<ResumableTCPServerSocket>;
+ static const char* service_name() {
+ return "ResumableTCPServerSocketManager";
+ }
+
+ // Application-defined string - see sockets_tcp_server.idl.
+ std::string name_;
+ // Flag indicating whether the socket is left open when the application is
+ // suspended - see sockets_tcp_server.idl.
+ bool persistent_;
+ // Flag indicating whether a connected socket blocks its peer from sending
+ // more data - see sockets_tcp_server.idl.
+ bool paused_;
+};
+
} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_API_SOCKET_TCP_SOCKET_H_
diff --git a/chrome/browser/extensions/api/socket/udp_socket.cc b/chrome/browser/extensions/api/socket/udp_socket.cc
index 7d36ffcece..b6be256a74 100644
--- a/chrome/browser/extensions/api/socket/udp_socket.cc
+++ b/chrome/browser/extensions/api/socket/udp_socket.cc
@@ -71,6 +71,10 @@ int UDPSocket::Bind(const std::string& address, int port) {
void UDPSocket::Disconnect() {
is_connected_ = false;
socket_.Close();
+ read_callback_.Reset();
+ recv_from_callback_.Reset();
+ send_to_callback_.Reset();
+ multicast_groups_.clear();
}
void UDPSocket::Read(int count,
@@ -295,28 +299,8 @@ ResumableUDPSocket::ResumableUDPSocket(const std::string& owner_extension_id)
buffer_size_(0) {
}
-const std::string& ResumableUDPSocket::name() const {
- return name_;
-}
-
-void ResumableUDPSocket::set_name(const std::string& name) {
- name_ = name;
-}
-
-bool ResumableUDPSocket::persistent() const {
- return persistent_;
-}
-
-void ResumableUDPSocket::set_persistent(bool persistent) {
- persistent_ = persistent;
-}
-
-int ResumableUDPSocket::buffer_size() const {
- return buffer_size_;
-}
-
-void ResumableUDPSocket::set_buffer_size(int buffer_size) {
- buffer_size_ = buffer_size;
+bool ResumableUDPSocket::IsPersistent() const {
+ return persistent();
}
} // namespace extensions
diff --git a/chrome/browser/extensions/api/socket/udp_socket.h b/chrome/browser/extensions/api/socket/udp_socket.h
index 4989e27092..e3dab20a18 100644
--- a/chrome/browser/extensions/api/socket/udp_socket.h
+++ b/chrome/browser/extensions/api/socket/udp_socket.h
@@ -81,14 +81,17 @@ class ResumableUDPSocket : public UDPSocket {
public:
explicit ResumableUDPSocket(const std::string& owner_extension_id);
- const std::string& name() const;
- void set_name(const std::string& name);
+ // Overriden from ApiResource
+ virtual bool IsPersistent() const OVERRIDE;
- virtual bool persistent() const OVERRIDE;
- void set_persistent(bool persistent);
+ const std::string& name() const { return name_; }
+ void set_name(const std::string& name) { name_ = name; }
- int buffer_size() const;
- void set_buffer_size(int buffer_size);
+ bool persistent() const { return persistent_; }
+ void set_persistent(bool persistent) { persistent_ = persistent; }
+
+ int buffer_size() const { return buffer_size_; }
+ void set_buffer_size(int buffer_size) { buffer_size_ = buffer_size; }
private:
friend class ApiResourceManager<ResumableUDPSocket>;
@@ -96,8 +99,12 @@ class ResumableUDPSocket : public UDPSocket {
return "ResumableUDPSocketManager";
}
+ // Application-defined string - see sockets_udp.idl.
std::string name_;
+ // Flag indicating whether the socket is left open when the application is
+ // suspended - see sockets_udp.idl.
bool persistent_;
+ // The size of the buffer used to receive data - see sockets_udp.idl.
int buffer_size_;
};
diff --git a/chrome/browser/extensions/api/sockets_tcp/tcp_socket_event_dispatcher.cc b/chrome/browser/extensions/api/sockets_tcp/tcp_socket_event_dispatcher.cc
index fe674ae497..40d8c22782 100644
--- a/chrome/browser/extensions/api/sockets_tcp/tcp_socket_event_dispatcher.cc
+++ b/chrome/browser/extensions/api/sockets_tcp/tcp_socket_event_dispatcher.cc
@@ -116,10 +116,15 @@ void TCPSocketEventDispatcher::ReadCallback(
scoped_refptr<net::IOBuffer> io_buffer) {
DCHECK(BrowserThread::CurrentlyOn(params.thread_id));
- // Note: if "bytes_read" < 0, there was a network error, and "bytes_read" is
- // a value from "net::ERR_".
+ // If |bytes_read| == 0, the connection has been closed by the peer.
+ // If |bytes_read| < 0, there was a network error, and |bytes_read| is a value
+ // from "net::ERR_".
- if (bytes_read >= 0) {
+ if (bytes_read == 0) {
+ bytes_read = net::ERR_CONNECTION_CLOSED;
+ }
+
+ if (bytes_read > 0) {
// Dispatch "onReceive" event.
sockets_tcp::ReceiveInfo receive_info;
receive_info.socket_id = params.socket_id;
diff --git a/chrome/browser/extensions/api/sockets_tcp_server/sockets_tcp_server_api.cc b/chrome/browser/extensions/api/sockets_tcp_server/sockets_tcp_server_api.cc
new file mode 100644
index 0000000000..0827e29bed
--- /dev/null
+++ b/chrome/browser/extensions/api/sockets_tcp_server/sockets_tcp_server_api.cc
@@ -0,0 +1,298 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/api/sockets_tcp_server/sockets_tcp_server_api.h"
+
+#include "chrome/browser/extensions/api/socket/tcp_socket.h"
+#include "chrome/browser/extensions/api/sockets_tcp_server/tcp_server_socket_event_dispatcher.h"
+#include "chrome/common/extensions/api/sockets/sockets_handler.h"
+#include "chrome/common/extensions/permissions/permissions_data.h"
+#include "chrome/common/extensions/permissions/socket_permission.h"
+#include "content/public/common/socket_permission_request.h"
+#include "net/base/net_errors.h"
+
+using content::SocketPermissionRequest;
+using extensions::ResumableTCPServerSocket;
+using extensions::api::sockets_tcp_server::SocketInfo;
+using extensions::api::sockets_tcp_server::SocketProperties;
+
+namespace {
+
+const char kSocketNotFoundError[] = "Socket not found";
+const char kPermissionError[] = "Does not have permission";
+const int kDefaultListenBacklog = SOMAXCONN;
+
+linked_ptr<SocketInfo> CreateSocketInfo(int socket_id,
+ ResumableTCPServerSocket* socket) {
+ linked_ptr<SocketInfo> socket_info(new SocketInfo());
+ // This represents what we know about the socket, and does not call through
+ // to the system.
+ socket_info->socket_id = socket_id;
+ if (!socket->name().empty()) {
+ socket_info->name.reset(new std::string(socket->name()));
+ }
+ socket_info->persistent = socket->persistent();
+ socket_info->paused = socket->paused();
+
+ // Grab the local address as known by the OS.
+ net::IPEndPoint localAddress;
+ if (socket->GetLocalAddress(&localAddress)) {
+ socket_info->local_address.reset(
+ new std::string(localAddress.ToStringWithoutPort()));
+ socket_info->local_port.reset(new int(localAddress.port()));
+ }
+
+ return socket_info;
+}
+
+void SetSocketProperties(ResumableTCPServerSocket* socket,
+ SocketProperties* properties) {
+ if (properties->name.get()) {
+ socket->set_name(*properties->name.get());
+ }
+ if (properties->persistent.get()) {
+ socket->set_persistent(*properties->persistent.get());
+ }
+}
+
+} // namespace
+
+namespace extensions {
+namespace api {
+
+TCPServerSocketAsyncApiFunction::~TCPServerSocketAsyncApiFunction() {}
+
+scoped_ptr<SocketResourceManagerInterface>
+ TCPServerSocketAsyncApiFunction::CreateSocketResourceManager() {
+ return scoped_ptr<SocketResourceManagerInterface>(
+ new SocketResourceManager<ResumableTCPServerSocket>()).Pass();
+}
+
+ResumableTCPServerSocket* TCPServerSocketAsyncApiFunction::GetTcpSocket(
+ int socket_id) {
+ return static_cast<ResumableTCPServerSocket*>(GetSocket(socket_id));
+}
+
+SocketsTcpServerCreateFunction::SocketsTcpServerCreateFunction() {}
+
+SocketsTcpServerCreateFunction::~SocketsTcpServerCreateFunction() {}
+
+bool SocketsTcpServerCreateFunction::Prepare() {
+ params_ = sockets_tcp_server::Create::Params::Create(*args_);
+ EXTENSION_FUNCTION_VALIDATE(params_.get());
+ return true;
+}
+
+void SocketsTcpServerCreateFunction::Work() {
+ ResumableTCPServerSocket* socket =
+ new ResumableTCPServerSocket(extension_->id());
+
+ sockets_tcp_server::SocketProperties* properties =
+ params_.get()->properties.get();
+ if (properties) {
+ SetSocketProperties(socket, properties);
+ }
+
+ sockets_tcp_server::CreateInfo create_info;
+ create_info.socket_id = AddSocket(socket);
+ results_ = sockets_tcp_server::Create::Results::Create(create_info);
+}
+
+SocketsTcpServerUpdateFunction::SocketsTcpServerUpdateFunction() {}
+
+SocketsTcpServerUpdateFunction::~SocketsTcpServerUpdateFunction() {}
+
+bool SocketsTcpServerUpdateFunction::Prepare() {
+ params_ = sockets_tcp_server::Update::Params::Create(*args_);
+ EXTENSION_FUNCTION_VALIDATE(params_.get());
+ return true;
+}
+
+void SocketsTcpServerUpdateFunction::Work() {
+ ResumableTCPServerSocket* socket = GetTcpSocket(params_->socket_id);
+ if (!socket) {
+ error_ = kSocketNotFoundError;
+ return;
+ }
+
+ SetSocketProperties(socket, &params_.get()->properties);
+ results_ = sockets_tcp_server::Update::Results::Create();
+}
+
+SocketsTcpServerSetPausedFunction::SocketsTcpServerSetPausedFunction()
+ : socket_event_dispatcher_(NULL) {}
+
+SocketsTcpServerSetPausedFunction::~SocketsTcpServerSetPausedFunction() {}
+
+bool SocketsTcpServerSetPausedFunction::Prepare() {
+ params_ = api::sockets_tcp_server::SetPaused::Params::Create(*args_);
+ EXTENSION_FUNCTION_VALIDATE(params_.get());
+
+ socket_event_dispatcher_ = TCPServerSocketEventDispatcher::Get(profile());
+ DCHECK(socket_event_dispatcher_) << "There is no socket event dispatcher. "
+ "If this assertion is failing during a test, then it is likely that "
+ "TestExtensionSystem is failing to provide an instance of "
+ "TCPServerSocketEventDispatcher.";
+ return socket_event_dispatcher_ != NULL;
+}
+
+void SocketsTcpServerSetPausedFunction::Work() {
+ ResumableTCPServerSocket* socket = GetTcpSocket(params_->socket_id);
+ if (!socket) {
+ error_ = kSocketNotFoundError;
+ return;
+ }
+
+ if (socket->paused() != params_->paused) {
+ socket->set_paused(params_->paused);
+ if (socket->IsConnected() && !params_->paused) {
+ socket_event_dispatcher_->OnServerSocketResume(extension_->id(),
+ params_->socket_id);
+ }
+ }
+
+ results_ = sockets_tcp_server::SetPaused::Results::Create();
+}
+
+SocketsTcpServerListenFunction::SocketsTcpServerListenFunction()
+ : socket_event_dispatcher_(NULL) {}
+
+SocketsTcpServerListenFunction::~SocketsTcpServerListenFunction() {}
+
+bool SocketsTcpServerListenFunction::Prepare() {
+ params_ = api::sockets_tcp_server::Listen::Params::Create(*args_);
+ EXTENSION_FUNCTION_VALIDATE(params_.get());
+
+ socket_event_dispatcher_ = TCPServerSocketEventDispatcher::Get(profile());
+ DCHECK(socket_event_dispatcher_) << "There is no socket event dispatcher. "
+ "If this assertion is failing during a test, then it is likely that "
+ "TestExtensionSystem is failing to provide an instance of "
+ "TCPServerSocketEventDispatcher.";
+ return socket_event_dispatcher_ != NULL;
+}
+
+void SocketsTcpServerListenFunction::Work() {
+ ResumableTCPServerSocket* socket = GetTcpSocket(params_->socket_id);
+ if (!socket) {
+ error_ = kSocketNotFoundError;
+ return;
+ }
+
+ SocketPermissionRequest param(
+ SocketPermissionRequest::TCP_LISTEN,
+ params_->address,
+ params_->port);
+ if (!SocketsManifestData::CheckRequest(GetExtension(), param)) {
+ error_ = kPermissionError;
+ return;
+ }
+
+ int net_result = socket->Listen(
+ params_->address,
+ params_->port,
+ params_->backlog.get() ? *params_->backlog.get() : kDefaultListenBacklog,
+ &error_);
+
+ if (net_result != net::OK)
+ error_ = net::ErrorToString(net_result);
+
+
+ if (net_result == net::OK) {
+ socket_event_dispatcher_->OnServerSocketListen(extension_->id(),
+ params_->socket_id);
+ }
+
+ results_ = sockets_tcp_server::Listen::Results::Create(net_result);
+}
+
+SocketsTcpServerDisconnectFunction::SocketsTcpServerDisconnectFunction() {}
+
+SocketsTcpServerDisconnectFunction::~SocketsTcpServerDisconnectFunction() {}
+
+bool SocketsTcpServerDisconnectFunction::Prepare() {
+ params_ = sockets_tcp_server::Disconnect::Params::Create(*args_);
+ EXTENSION_FUNCTION_VALIDATE(params_.get());
+ return true;
+}
+
+void SocketsTcpServerDisconnectFunction::Work() {
+ ResumableTCPServerSocket* socket = GetTcpSocket(params_->socket_id);
+ if (!socket) {
+ error_ = kSocketNotFoundError;
+ return;
+ }
+
+ socket->Disconnect();
+ results_ = sockets_tcp_server::Disconnect::Results::Create();
+}
+
+SocketsTcpServerCloseFunction::SocketsTcpServerCloseFunction() {}
+
+SocketsTcpServerCloseFunction::~SocketsTcpServerCloseFunction() {}
+
+bool SocketsTcpServerCloseFunction::Prepare() {
+ params_ = sockets_tcp_server::Close::Params::Create(*args_);
+ EXTENSION_FUNCTION_VALIDATE(params_.get());
+ return true;
+}
+
+void SocketsTcpServerCloseFunction::Work() {
+ ResumableTCPServerSocket* socket = GetTcpSocket(params_->socket_id);
+ if (!socket) {
+ error_ = kSocketNotFoundError;
+ return;
+ }
+
+ RemoveSocket(params_->socket_id);
+ results_ = sockets_tcp_server::Close::Results::Create();
+}
+
+SocketsTcpServerGetInfoFunction::SocketsTcpServerGetInfoFunction() {}
+
+SocketsTcpServerGetInfoFunction::~SocketsTcpServerGetInfoFunction() {}
+
+bool SocketsTcpServerGetInfoFunction::Prepare() {
+ params_ = sockets_tcp_server::GetInfo::Params::Create(*args_);
+ EXTENSION_FUNCTION_VALIDATE(params_.get());
+ return true;
+}
+
+void SocketsTcpServerGetInfoFunction::Work() {
+ ResumableTCPServerSocket* socket = GetTcpSocket(params_->socket_id);
+ if (!socket) {
+ error_ = kSocketNotFoundError;
+ return;
+ }
+
+ linked_ptr<sockets_tcp_server::SocketInfo> socket_info =
+ CreateSocketInfo(params_->socket_id, socket);
+ results_ = sockets_tcp_server::GetInfo::Results::Create(*socket_info);
+}
+
+SocketsTcpServerGetSocketsFunction::SocketsTcpServerGetSocketsFunction() {}
+
+SocketsTcpServerGetSocketsFunction::~SocketsTcpServerGetSocketsFunction() {}
+
+bool SocketsTcpServerGetSocketsFunction::Prepare() {
+ return true;
+}
+
+void SocketsTcpServerGetSocketsFunction::Work() {
+ std::vector<linked_ptr<sockets_tcp_server::SocketInfo> > socket_infos;
+ base::hash_set<int>* resource_ids = GetSocketIds();
+ if (resource_ids != NULL) {
+ for (base::hash_set<int>::iterator it = resource_ids->begin();
+ it != resource_ids->end(); ++it) {
+ int socket_id = *it;
+ ResumableTCPServerSocket* socket = GetTcpSocket(socket_id);
+ if (socket) {
+ socket_infos.push_back(CreateSocketInfo(socket_id, socket));
+ }
+ }
+ }
+ results_ = sockets_tcp_server::GetSockets::Results::Create(socket_infos);
+}
+
+} // namespace api
+} // namespace extensions
diff --git a/chrome/browser/extensions/api/sockets_tcp_server/sockets_tcp_server_api.h b/chrome/browser/extensions/api/sockets_tcp_server/sockets_tcp_server_api.h
new file mode 100644
index 0000000000..439b85714c
--- /dev/null
+++ b/chrome/browser/extensions/api/sockets_tcp_server/sockets_tcp_server_api.h
@@ -0,0 +1,179 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_API_SOCKETS_TCP_SERVER_SOCKETS_TCP_SERVER_API_H_
+#define CHROME_BROWSER_EXTENSIONS_API_SOCKETS_TCP_SERVER_SOCKETS_TCP_SERVER_API_H_
+
+#include "chrome/browser/extensions/api/socket/socket_api.h"
+#include "chrome/common/extensions/api/sockets_tcp_server.h"
+
+namespace extensions {
+class ResumableTCPServerSocket;
+}
+
+namespace extensions {
+namespace api {
+
+class TCPServerSocketAsyncApiFunction : public SocketAsyncApiFunction {
+ protected:
+ virtual ~TCPServerSocketAsyncApiFunction();
+
+ virtual scoped_ptr<SocketResourceManagerInterface>
+ CreateSocketResourceManager() OVERRIDE;
+
+ ResumableTCPServerSocket* GetTcpSocket(int socket_id);
+};
+
+class SocketsTcpServerCreateFunction : public TCPServerSocketAsyncApiFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION("sockets.tcpServer.create",
+ SOCKETS_TCP_SERVER_CREATE)
+
+ SocketsTcpServerCreateFunction();
+
+ protected:
+ virtual ~SocketsTcpServerCreateFunction();
+
+ // AsyncApiFunction:
+ virtual bool Prepare() OVERRIDE;
+ virtual void Work() OVERRIDE;
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(SocketsTcpServerUnitTest, Create);
+ scoped_ptr<sockets_tcp_server::Create::Params> params_;
+};
+
+class SocketsTcpServerUpdateFunction : public TCPServerSocketAsyncApiFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION("sockets.tcpServer.update",
+ SOCKETS_TCP_SERVER_UPDATE)
+
+ SocketsTcpServerUpdateFunction();
+
+ protected:
+ virtual ~SocketsTcpServerUpdateFunction();
+
+ // AsyncApiFunction:
+ virtual bool Prepare() OVERRIDE;
+ virtual void Work() OVERRIDE;
+
+ private:
+ scoped_ptr<sockets_tcp_server::Update::Params> params_;
+};
+
+class SocketsTcpServerSetPausedFunction
+ : public TCPServerSocketAsyncApiFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION("sockets.tcpServer.setPaused",
+ SOCKETS_TCP_SERVER_SETPAUSED)
+
+ SocketsTcpServerSetPausedFunction();
+
+ protected:
+ virtual ~SocketsTcpServerSetPausedFunction();
+
+ // AsyncApiFunction
+ virtual bool Prepare() OVERRIDE;
+ virtual void Work() OVERRIDE;
+
+ private:
+ scoped_ptr<sockets_tcp_server::SetPaused::Params> params_;
+ TCPServerSocketEventDispatcher* socket_event_dispatcher_;
+};
+
+class SocketsTcpServerListenFunction
+ : public TCPServerSocketAsyncApiFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION("sockets.tcpServer.listen",
+ SOCKETS_TCP_SERVER_LISTEN)
+
+ SocketsTcpServerListenFunction();
+
+ protected:
+ virtual ~SocketsTcpServerListenFunction();
+
+ // AsyncApiFunction:
+ virtual bool Prepare() OVERRIDE;
+ virtual void Work() OVERRIDE;
+
+ private:
+ scoped_ptr<sockets_tcp_server::Listen::Params> params_;
+ TCPServerSocketEventDispatcher* socket_event_dispatcher_;
+};
+
+class SocketsTcpServerDisconnectFunction
+ : public TCPServerSocketAsyncApiFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION("sockets.tcpServer.disconnect",
+ SOCKETS_TCP_SERVER_DISCONNECT)
+
+ SocketsTcpServerDisconnectFunction();
+
+ protected:
+ virtual ~SocketsTcpServerDisconnectFunction();
+
+ // AsyncApiFunction:
+ virtual bool Prepare() OVERRIDE;
+ virtual void Work() OVERRIDE;
+
+ private:
+ scoped_ptr<sockets_tcp_server::Disconnect::Params> params_;
+};
+
+class SocketsTcpServerCloseFunction : public TCPServerSocketAsyncApiFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION("sockets.tcpServer.close",
+ SOCKETS_TCP_SERVER_CLOSE)
+
+ SocketsTcpServerCloseFunction();
+
+ protected:
+ virtual ~SocketsTcpServerCloseFunction();
+
+ // AsyncApiFunction:
+ virtual bool Prepare() OVERRIDE;
+ virtual void Work() OVERRIDE;
+
+ private:
+ scoped_ptr<sockets_tcp_server::Close::Params> params_;
+};
+
+class SocketsTcpServerGetInfoFunction : public TCPServerSocketAsyncApiFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION("sockets.tcpServer.getInfo",
+ SOCKETS_TCP_SERVER_GETINFO)
+
+ SocketsTcpServerGetInfoFunction();
+
+ protected:
+ virtual ~SocketsTcpServerGetInfoFunction();
+
+ // AsyncApiFunction:
+ virtual bool Prepare() OVERRIDE;
+ virtual void Work() OVERRIDE;
+
+ private:
+ scoped_ptr<sockets_tcp_server::GetInfo::Params> params_;
+};
+
+class SocketsTcpServerGetSocketsFunction
+ : public TCPServerSocketAsyncApiFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION("sockets.tcpServer.getSockets",
+ SOCKETS_TCP_SERVER_GETSOCKETS)
+
+ SocketsTcpServerGetSocketsFunction();
+
+ protected:
+ virtual ~SocketsTcpServerGetSocketsFunction();
+
+ // AsyncApiFunction:
+ virtual bool Prepare() OVERRIDE;
+ virtual void Work() OVERRIDE;
+};
+
+} // namespace api
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_API_SOCKETS_TCP_SERVER_SOCKETS_TCP_SERVER_API_H_
diff --git a/chrome/browser/extensions/api/sockets_tcp_server/sockets_tcp_server_api_unittest.cc b/chrome/browser/extensions/api/sockets_tcp_server/sockets_tcp_server_api_unittest.cc
new file mode 100644
index 0000000000..6ed0f9e08e
--- /dev/null
+++ b/chrome/browser/extensions/api/sockets_tcp_server/sockets_tcp_server_api_unittest.cc
@@ -0,0 +1,94 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/values.h"
+#include "chrome/browser/browser_process_impl.h"
+#include "chrome/browser/extensions/api/api_function.h"
+#include "chrome/browser/extensions/api/api_resource_manager.h"
+#include "chrome/browser/extensions/api/socket/socket.h"
+#include "chrome/browser/extensions/api/socket/tcp_socket.h"
+#include "chrome/browser/extensions/api/sockets_tcp_server/sockets_tcp_server_api.h"
+#include "chrome/browser/extensions/extension_function_test_utils.h"
+#include "chrome/browser/extensions/test_extension_system.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/test/base/browser_with_test_window_test.h"
+#include "chrome/test/base/testing_browser_process.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace utils = extension_function_test_utils;
+
+namespace extensions {
+namespace api {
+
+static
+BrowserContextKeyedService* ApiResourceManagerTestFactory(
+ content::BrowserContext* profile) {
+ content::BrowserThread::ID id;
+ CHECK(content::BrowserThread::GetCurrentThreadIdentifier(&id));
+ return ApiResourceManager<ResumableTCPSocket>::
+ CreateApiResourceManagerForTest(static_cast<Profile*>(profile), id);
+}
+
+static
+BrowserContextKeyedService* ApiResourceManagerTestServerFactory(
+ content::BrowserContext* profile) {
+ content::BrowserThread::ID id;
+ CHECK(content::BrowserThread::GetCurrentThreadIdentifier(&id));
+ return ApiResourceManager<ResumableTCPServerSocket>::
+ CreateApiResourceManagerForTest(static_cast<Profile*>(profile), id);
+}
+
+class SocketsTcpServerUnitTest : public BrowserWithTestWindowTest {
+ public:
+ virtual void SetUp() {
+ BrowserWithTestWindowTest::SetUp();
+
+ ApiResourceManager<ResumableTCPSocket>::GetFactoryInstance()->
+ SetTestingFactoryAndUse(browser()->profile(),
+ ApiResourceManagerTestFactory);
+
+ ApiResourceManager<ResumableTCPServerSocket>::GetFactoryInstance()->
+ SetTestingFactoryAndUse(browser()->profile(),
+ ApiResourceManagerTestServerFactory);
+
+ extension_ = utils::CreateEmptyExtensionWithLocation(
+ extensions::Manifest::UNPACKED);
+ }
+
+ base::Value* RunFunctionWithExtension(
+ UIThreadExtensionFunction* function, const std::string& args) {
+ scoped_refptr<UIThreadExtensionFunction> delete_function(function);
+ function->set_extension(extension_.get());
+ return utils::RunFunctionAndReturnSingleResult(function, args, browser());
+ }
+
+ base::DictionaryValue* RunFunctionAndReturnDict(
+ UIThreadExtensionFunction* function, const std::string& args) {
+ base::Value* result = RunFunctionWithExtension(function, args);
+ return result ? utils::ToDictionary(result) : NULL;
+ }
+
+ protected:
+ scoped_refptr<extensions::Extension> extension_;
+};
+
+TEST_F(SocketsTcpServerUnitTest, Create) {
+ // Get BrowserThread
+ content::BrowserThread::ID id;
+ CHECK(content::BrowserThread::GetCurrentThreadIdentifier(&id));
+
+ // Create SocketCreateFunction and put it on BrowserThread
+ SocketsTcpServerCreateFunction *function =
+ new SocketsTcpServerCreateFunction();
+ function->set_work_thread_id(id);
+
+ // Run tests
+ scoped_ptr<base::DictionaryValue> result(RunFunctionAndReturnDict(
+ function, "[{\"persistent\": true, \"name\": \"foo\"}]"));
+ ASSERT_TRUE(result.get());
+}
+
+} // namespace api
+} // namespace extensions
diff --git a/chrome/browser/extensions/api/sockets_tcp_server/sockets_tcp_server_apitest.cc b/chrome/browser/extensions/api/sockets_tcp_server/sockets_tcp_server_apitest.cc
new file mode 100644
index 0000000000..6e36a8cacf
--- /dev/null
+++ b/chrome/browser/extensions/api/sockets_tcp_server/sockets_tcp_server_apitest.cc
@@ -0,0 +1,111 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/ref_counted.h"
+#include "base/path_service.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/browser/extensions/api/dns/host_resolver_wrapper.h"
+#include "chrome/browser/extensions/api/dns/mock_host_resolver_creator.h"
+#include "chrome/browser/extensions/api/sockets_tcp_server/sockets_tcp_server_api.h"
+#include "chrome/browser/extensions/extension_apitest.h"
+#include "chrome/browser/extensions/extension_function_test_utils.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_test_message_listener.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/extensions/application_launch.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/test/spawned_test_server/spawned_test_server.h"
+
+using extensions::Extension;
+using extensions::api::SocketsTcpServerCreateFunction;
+
+namespace utils = extension_function_test_utils;
+
+namespace {
+
+// TODO(jschuh): Hanging plugin tests. crbug.com/244653
+#if defined(OS_WIN) && defined(ARCH_CPU_X86_64)
+#define MAYBE(x) DISABLED_##x
+#else
+#define MAYBE(x) x
+#endif
+
+const std::string kHostname = "127.0.0.1";
+const int kPort = 8888;
+
+class SocketsTcpServerApiTest : public ExtensionApiTest {
+ public:
+ SocketsTcpServerApiTest() : resolver_event_(true, false),
+ resolver_creator_(
+ new extensions::MockHostResolverCreator()) {
+ }
+
+ virtual void SetUpOnMainThread() OVERRIDE {
+ extensions::HostResolverWrapper::GetInstance()->SetHostResolverForTesting(
+ resolver_creator_->CreateMockHostResolver());
+ }
+
+ virtual void CleanUpOnMainThread() OVERRIDE {
+ extensions::HostResolverWrapper::GetInstance()->
+ SetHostResolverForTesting(NULL);
+ resolver_creator_->DeleteMockHostResolver();
+ }
+
+ private:
+ base::WaitableEvent resolver_event_;
+
+ // The MockHostResolver asserts that it's used on the same thread on which
+ // it's created, which is actually a stronger rule than its real counterpart.
+ // But that's fine; it's good practice.
+ scoped_refptr<extensions::MockHostResolverCreator> resolver_creator_;
+};
+
+} // namespace
+
+IN_PROC_BROWSER_TEST_F(SocketsTcpServerApiTest, SocketTCPCreateGood) {
+ scoped_refptr<SocketsTcpServerCreateFunction>
+ socket_create_function(new SocketsTcpServerCreateFunction());
+ scoped_refptr<Extension> empty_extension(utils::CreateEmptyExtension());
+
+ socket_create_function->set_extension(empty_extension.get());
+ socket_create_function->set_has_callback(true);
+
+ scoped_ptr<base::Value> result(utils::RunFunctionAndReturnSingleResult(
+ socket_create_function.get(), "[]", browser(), utils::NONE));
+ ASSERT_EQ(base::Value::TYPE_DICTIONARY, result->GetType());
+ base::DictionaryValue *value =
+ static_cast<base::DictionaryValue*>(result.get());
+ int socketId = -1;
+ EXPECT_TRUE(value->GetInteger("socketId", &socketId));
+ ASSERT_TRUE(socketId > 0);
+}
+
+IN_PROC_BROWSER_TEST_F(SocketsTcpServerApiTest, SocketTCPServerExtension) {
+ base::FilePath path = test_data_dir_.AppendASCII("sockets_tcp_server/api");
+ ResultCatcher catcher;
+ catcher.RestrictToProfile(browser()->profile());
+ ExtensionTestMessageListener listener("info_please", true);
+ ASSERT_TRUE(LoadExtension(path));
+ EXPECT_TRUE(listener.WaitUntilSatisfied());
+ listener.Reply(
+ base::StringPrintf("tcp_server:%s:%d", kHostname.c_str(), kPort));
+
+ EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
+}
+
+IN_PROC_BROWSER_TEST_F(SocketsTcpServerApiTest, SocketTCPServerUnbindOnUnload) {
+ base::FilePath path = test_data_dir_.AppendASCII("sockets_tcp_server/unload");
+ ResultCatcher catcher;
+ const Extension* extension = LoadExtension(path);
+ ASSERT_TRUE(extension);
+ EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
+
+ UnloadExtension(extension->id());
+
+ ASSERT_TRUE(LoadExtension(path)) << message_;
+ EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
+}
diff --git a/chrome/browser/extensions/api/sockets_tcp_server/tcp_server_socket_event_dispatcher.cc b/chrome/browser/extensions/api/sockets_tcp_server/tcp_server_socket_event_dispatcher.cc
new file mode 100644
index 0000000000..d849e8c0e2
--- /dev/null
+++ b/chrome/browser/extensions/api/sockets_tcp_server/tcp_server_socket_event_dispatcher.cc
@@ -0,0 +1,198 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/api/sockets_tcp_server/tcp_server_socket_event_dispatcher.h"
+
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/extensions/api/socket/tcp_socket.h"
+#include "chrome/browser/extensions/event_router.h"
+#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "net/base/net_errors.h"
+
+namespace extensions {
+namespace api {
+
+using content::BrowserThread;
+
+static
+ base::LazyInstance<ProfileKeyedAPIFactory<TCPServerSocketEventDispatcher> >
+ g_factory = LAZY_INSTANCE_INITIALIZER;
+
+// static
+ProfileKeyedAPIFactory<TCPServerSocketEventDispatcher>*
+ TCPServerSocketEventDispatcher::GetFactoryInstance() {
+ return &g_factory.Get();
+}
+
+// static
+TCPServerSocketEventDispatcher* TCPServerSocketEventDispatcher::Get(
+ Profile* profile) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ return ProfileKeyedAPIFactory<TCPServerSocketEventDispatcher>::GetForProfile(
+ profile);
+}
+
+TCPServerSocketEventDispatcher::TCPServerSocketEventDispatcher(Profile* profile)
+ : thread_id_(Socket::kThreadId),
+ profile_(profile) {
+ ApiResourceManager<ResumableTCPServerSocket>* server_manager =
+ ApiResourceManager<ResumableTCPServerSocket>::Get(profile);
+ DCHECK(server_manager) << "There is no server socket manager. "
+ "If this assertion is failing during a test, then it is likely that "
+ "TestExtensionSystem is failing to provide an instance of "
+ "ApiResourceManager<ResumableTCPServerSocket>.";
+ server_sockets_ = server_manager->data_;
+
+ ApiResourceManager<ResumableTCPSocket>* client_manager =
+ ApiResourceManager<ResumableTCPSocket>::Get(profile);
+ DCHECK(client_manager) << "There is no client socket manager. "
+ "If this assertion is failing during a test, then it is likely that "
+ "TestExtensionSystem is failing to provide an instance of "
+ "ApiResourceManager<ResumableTCPSocket>.";
+ client_sockets_ = client_manager->data_;
+}
+
+TCPServerSocketEventDispatcher::~TCPServerSocketEventDispatcher() {}
+
+TCPServerSocketEventDispatcher::AcceptParams::AcceptParams() {}
+
+TCPServerSocketEventDispatcher::AcceptParams::~AcceptParams() {}
+
+void TCPServerSocketEventDispatcher::OnServerSocketListen(
+ const std::string& extension_id,
+ int socket_id) {
+ DCHECK(BrowserThread::CurrentlyOn(thread_id_));
+
+ StartSocketAccept(extension_id, socket_id);
+}
+
+void TCPServerSocketEventDispatcher::OnServerSocketResume(
+ const std::string& extension_id,
+ int socket_id) {
+ DCHECK(BrowserThread::CurrentlyOn(thread_id_));
+
+ StartSocketAccept(extension_id, socket_id);
+}
+
+void TCPServerSocketEventDispatcher::StartSocketAccept(
+ const std::string& extension_id,
+ int socket_id) {
+ DCHECK(BrowserThread::CurrentlyOn(thread_id_));
+
+ AcceptParams params;
+ params.thread_id = thread_id_;
+ params.profile_id = profile_;
+ params.extension_id = extension_id;
+ params.server_sockets = server_sockets_;
+ params.client_sockets = client_sockets_;
+ params.socket_id = socket_id;
+
+ StartAccept(params);
+}
+
+// static
+void TCPServerSocketEventDispatcher::StartAccept(const AcceptParams& params) {
+ DCHECK(BrowserThread::CurrentlyOn(params.thread_id));
+
+ ResumableTCPServerSocket* socket =
+ params.server_sockets->Get(params.extension_id, params.socket_id);
+ if (!socket) {
+ // This can happen if the socket is closed while our callback is active.
+ return;
+ }
+ DCHECK(params.extension_id == socket->owner_extension_id())
+ << "Socket has wrong owner.";
+
+ // Don't start another accept if the socket has been paused.
+ if (socket->paused())
+ return;
+
+ socket->Accept(base::Bind(&TCPServerSocketEventDispatcher::AcceptCallback,
+ params));
+}
+
+// static
+void TCPServerSocketEventDispatcher::AcceptCallback(
+ const AcceptParams& params,
+ int result_code,
+ net::TCPClientSocket *socket) {
+ DCHECK(BrowserThread::CurrentlyOn(params.thread_id));
+
+ if (result_code >= 0) {
+ ResumableTCPSocket *client_socket =
+ new ResumableTCPSocket(socket, params.extension_id, true);
+ client_socket->set_paused(true);
+ int client_socket_id = params.client_sockets->Add(client_socket);
+
+ // Dispatch "onAccept" event.
+ sockets_tcp_server::AcceptInfo accept_info;
+ accept_info.socket_id = params.socket_id;
+ accept_info.client_socket_id = client_socket_id;
+ scoped_ptr<base::ListValue> args =
+ sockets_tcp_server::OnAccept::Create(accept_info);
+ scoped_ptr<Event> event(
+ new Event(sockets_tcp_server::OnAccept::kEventName, args.Pass()));
+ PostEvent(params, event.Pass());
+
+ // Post a task to delay the "accept" until the socket is available, as
+ // calling StartAccept at this point would error with ERR_IO_PENDING.
+ BrowserThread::PostTask(
+ params.thread_id, FROM_HERE,
+ base::Bind(&TCPServerSocketEventDispatcher::StartAccept, params));
+ } else {
+ // Dispatch "onAcceptError" event but don't start another accept to avoid
+ // potential infinite "accepts" if we have a persistent network error.
+ sockets_tcp_server::AcceptErrorInfo accept_error_info;
+ accept_error_info.socket_id = params.socket_id;
+ accept_error_info.result_code = result_code;
+ scoped_ptr<base::ListValue> args =
+ sockets_tcp_server::OnAcceptError::Create(accept_error_info);
+ scoped_ptr<Event> event(
+ new Event(sockets_tcp_server::OnAcceptError::kEventName, args.Pass()));
+ PostEvent(params, event.Pass());
+
+ // Since we got an error, the socket is now "paused" until the application
+ // "resumes" it.
+ ResumableTCPServerSocket* socket =
+ params.server_sockets->Get(params.extension_id, params.socket_id);
+ if (socket) {
+ socket->set_paused(true);
+ }
+ }
+}
+
+// static
+void TCPServerSocketEventDispatcher::PostEvent(const AcceptParams& params,
+ scoped_ptr<Event> event) {
+ DCHECK(BrowserThread::CurrentlyOn(params.thread_id));
+
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&DispatchEvent,
+ params.profile_id,
+ params.extension_id,
+ base::Passed(event.Pass())));
+}
+
+// static
+void TCPServerSocketEventDispatcher::DispatchEvent(
+ void* profile_id,
+ const std::string& extension_id,
+ scoped_ptr<Event> event) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ Profile* profile = reinterpret_cast<Profile*>(profile_id);
+ if (!g_browser_process->profile_manager()->IsValidProfile(profile))
+ return;
+
+ EventRouter* router = ExtensionSystem::Get(profile)->event_router();
+ if (router)
+ router->DispatchEventToExtension(extension_id, event.Pass());
+}
+
+} // namespace api
+} // namespace extensions
diff --git a/chrome/browser/extensions/api/sockets_tcp_server/tcp_server_socket_event_dispatcher.h b/chrome/browser/extensions/api/sockets_tcp_server/tcp_server_socket_event_dispatcher.h
new file mode 100644
index 0000000000..4d15bc351b
--- /dev/null
+++ b/chrome/browser/extensions/api/sockets_tcp_server/tcp_server_socket_event_dispatcher.h
@@ -0,0 +1,99 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_API_SOCKETS_TCP_SERVER_TCP_SERVER_SOCKET_EVENT_DISPATCHER_H_
+#define CHROME_BROWSER_EXTENSIONS_API_SOCKETS_TCP_SERVER_TCP_SERVER_SOCKET_EVENT_DISPATCHER_H_
+
+#include "chrome/browser/extensions/api/api_resource_manager.h"
+#include "chrome/browser/extensions/api/sockets_tcp/sockets_tcp_api.h"
+#include "chrome/browser/extensions/api/sockets_tcp_server/sockets_tcp_server_api.h"
+
+namespace extensions {
+struct Event;
+class ResumableTCPSocket;
+}
+
+namespace extensions {
+namespace api {
+
+// Dispatch events related to "sockets.tcp" sockets from callback on native
+// socket instances. There is one instance per profile.
+class TCPServerSocketEventDispatcher
+ : public ProfileKeyedAPI,
+ public base::SupportsWeakPtr<TCPServerSocketEventDispatcher> {
+ public:
+ explicit TCPServerSocketEventDispatcher(Profile* profile);
+ virtual ~TCPServerSocketEventDispatcher();
+
+ // Server socket is active, start accepting connections from it.
+ void OnServerSocketListen(const std::string& extension_id, int socket_id);
+
+ // Server socket is active again, start accepting connections from it.
+ void OnServerSocketResume(const std::string& extension_id, int socket_id);
+
+ // ProfileKeyedAPI implementation.
+ static ProfileKeyedAPIFactory<TCPServerSocketEventDispatcher>*
+ GetFactoryInstance();
+
+ // Convenience method to get the SocketEventDispatcher for a profile.
+ static TCPServerSocketEventDispatcher* Get(Profile* profile);
+
+ private:
+ typedef ApiResourceManager<ResumableTCPServerSocket>::ApiResourceData
+ ServerSocketData;
+ typedef ApiResourceManager<ResumableTCPSocket>::ApiResourceData
+ ClientSocketData;
+ friend class ProfileKeyedAPIFactory<TCPServerSocketEventDispatcher>;
+ // ProfileKeyedAPI implementation.
+ static const char* service_name() {
+ return "TCPServerSocketEventDispatcher";
+ }
+ static const bool kServiceHasOwnInstanceInIncognito = true;
+ static const bool kServiceIsNULLWhileTesting = true;
+
+ // base::Bind supports methods with up to 6 parameters. AcceptParams is used
+ // as a workaround that limitation for invoking StartAccept.
+ struct AcceptParams {
+ AcceptParams();
+ ~AcceptParams();
+
+ content::BrowserThread::ID thread_id;
+ void* profile_id;
+ std::string extension_id;
+ scoped_refptr<ServerSocketData> server_sockets;
+ scoped_refptr<ClientSocketData> client_sockets;
+ int socket_id;
+ };
+
+ // Start an accept and register a callback.
+ void StartSocketAccept(const std::string& extension_id, int socket_id);
+
+ // Start an accept and register a callback.
+ static void StartAccept(const AcceptParams& params);
+
+ // Called when socket accepts a new connection.
+ static void AcceptCallback(const AcceptParams& params,
+ int result_code,
+ net::TCPClientSocket *socket);
+
+ // Post an extension event from |thread_id| to UI thread
+ static void PostEvent(const AcceptParams& params,
+ scoped_ptr<Event> event);
+
+ // Dispatch an extension event on to EventRouter instance on UI thread.
+ static void DispatchEvent(void* profile_id,
+ const std::string& extension_id,
+ scoped_ptr<Event> event);
+
+ // Usually IO thread (except for unit testing).
+ content::BrowserThread::ID thread_id_;
+ Profile* const profile_;
+ scoped_refptr<ServerSocketData> server_sockets_;
+ scoped_refptr<ClientSocketData> client_sockets_;
+};
+
+} // namespace api
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_API_SOCKETS_TCP_SERVER_TCP_SERVER_SOCKET_EVENT_DISPATCHER_H_
diff --git a/chrome/browser/extensions/api/system_display/display_info_provider_chromeos.cc b/chrome/browser/extensions/api/system_display/display_info_provider_chromeos.cc
index 3bb69835e7..151b9bb0b6 100644
--- a/chrome/browser/extensions/api/system_display/display_info_provider_chromeos.cc
+++ b/chrome/browser/extensions/api/system_display/display_info_provider_chromeos.cc
@@ -167,9 +167,8 @@ void UpdateDisplayLayout(const gfx::Rect& primary_display_bounds,
int target_display_id) {
ash::DisplayLayout layout = GetLayoutForRectangles(primary_display_bounds,
target_display_bounds);
- ash::DisplayController* display_controller =
- ash::Shell::GetInstance()->display_controller();
- display_controller->SetLayoutForCurrentDisplays(layout);
+ ash::Shell::GetInstance()->display_manager()->
+ SetLayoutForCurrentDisplays(layout);
}
// Validates that parameters passed to the SetInfo function are valid for the
diff --git a/chrome/browser/extensions/api/system_display/display_info_provider_chromeos_unittest.cc b/chrome/browser/extensions/api/system_display/display_info_provider_chromeos_unittest.cc
index c5d9a0f482..c91e725251 100644
--- a/chrome/browser/extensions/api/system_display/display_info_provider_chromeos_unittest.cc
+++ b/chrome/browser/extensions/api/system_display/display_info_provider_chromeos_unittest.cc
@@ -279,7 +279,7 @@ TEST_F(DisplayInfoProviderChromeosTest, GetMirroring) {
TEST_F(DisplayInfoProviderChromeosTest, GetBounds) {
UpdateDisplay("600x600, 400x520");
- GetDisplayController()->SetLayoutForCurrentDisplays(
+ GetDisplayManager()->SetLayoutForCurrentDisplays(
ash::DisplayLayout::FromInts(ash::DisplayLayout::LEFT, -40));
DisplayInfo result = DisplayInfoProvider::Get()->GetAllDisplaysInfo();
@@ -289,7 +289,7 @@ TEST_F(DisplayInfoProviderChromeosTest, GetBounds) {
EXPECT_EQ("-400,-40 400x520",
SystemInfoDisplayBoundsToString(result[1]->bounds));
- GetDisplayController()->SetLayoutForCurrentDisplays(
+ GetDisplayManager()->SetLayoutForCurrentDisplays(
ash::DisplayLayout::FromInts(ash::DisplayLayout::TOP, 40));
result = DisplayInfoProvider::Get()->GetAllDisplaysInfo();
@@ -299,7 +299,7 @@ TEST_F(DisplayInfoProviderChromeosTest, GetBounds) {
EXPECT_EQ("40,-520 400x520",
SystemInfoDisplayBoundsToString(result[1]->bounds));
- GetDisplayController()->SetLayoutForCurrentDisplays(
+ GetDisplayManager()->SetLayoutForCurrentDisplays(
ash::DisplayLayout::FromInts(ash::DisplayLayout::BOTTOM, 80));
result = DisplayInfoProvider::Get()->GetAllDisplaysInfo();
diff --git a/chrome/browser/extensions/api/system_indicator/system_indicator_apitest.cc b/chrome/browser/extensions/api/system_indicator/system_indicator_apitest.cc
index 616fad4138..5b923cab8f 100644
--- a/chrome/browser/extensions/api/system_indicator/system_indicator_apitest.cc
+++ b/chrome/browser/extensions/api/system_indicator/system_indicator_apitest.cc
@@ -60,7 +60,7 @@ IN_PROC_BROWSER_TEST_F(SystemIndicatorApiTest, SystemIndicator) {
// Lazy Background Page has been shut down.
ExtensionProcessManager* pm =
extensions::ExtensionSystem::Get(profile())->process_manager();
- EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_));
+ EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id()));
EXPECT_TRUE(manager->SendClickEventToExtensionForTest(extension->id()));
EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
diff --git a/chrome/browser/extensions/api/system_private/system_private_apitest.cc b/chrome/browser/extensions/api/system_private/system_private_apitest.cc
index 6e3d3419bc..74f9266989 100644
--- a/chrome/browser/extensions/api/system_private/system_private_apitest.cc
+++ b/chrome/browser/extensions/api/system_private/system_private_apitest.cc
@@ -9,8 +9,8 @@
#include "chrome/common/pref_names.h"
#if defined(OS_CHROMEOS)
+#include "chromeos/dbus/fake_dbus_thread_manager.h"
#include "chromeos/dbus/fake_update_engine_client.h"
-#include "chromeos/dbus/mock_dbus_thread_manager_without_gmock.h"
using chromeos::UpdateEngineClient;
#endif
@@ -31,11 +31,11 @@ class GetUpdateStatusApiTest : public ExtensionApiTest {
virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
ExtensionApiTest::SetUpInProcessBrowserTestFixture();
- chromeos::MockDBusThreadManagerWithoutGMock* mock_dbus_thread_manager =
- new chromeos::MockDBusThreadManagerWithoutGMock;
- chromeos::DBusThreadManager::InitializeForTesting(mock_dbus_thread_manager);
+ chromeos::FakeDBusThreadManager* fake_dbus_thread_manager =
+ new chromeos::FakeDBusThreadManager;
+ chromeos::DBusThreadManager::InitializeForTesting(fake_dbus_thread_manager);
fake_update_engine_client_ =
- mock_dbus_thread_manager->fake_update_engine_client();
+ fake_dbus_thread_manager->fake_update_engine_client();
}
virtual void TearDownInProcessBrowserTestFixture() OVERRIDE {
diff --git a/chrome/browser/extensions/api/system_storage/storage_info_provider.cc b/chrome/browser/extensions/api/system_storage/storage_info_provider.cc
index 0c1abf1965..5cdc4692aa 100644
--- a/chrome/browser/extensions/api/system_storage/storage_info_provider.cc
+++ b/chrome/browser/extensions/api/system_storage/storage_info_provider.cc
@@ -87,6 +87,28 @@ void StorageInfoProvider::GetAllStoragesIntoInfoList() {
}
}
+double StorageInfoProvider::GetStorageFreeSpaceFromTransientIdOnFileThread(
+ const std::string& transient_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ std::vector<StorageInfo> storage_list =
+ StorageMonitor::GetInstance()->GetAllAvailableStorages();
+
+ std::string device_id =
+ StorageMonitor::GetInstance()->GetDeviceIdForTransientId(
+ transient_id);
+
+ // Lookup the matched storage info by |device_id|.
+ for (std::vector<StorageInfo>::const_iterator it =
+ storage_list.begin();
+ it != storage_list.end(); ++it) {
+ if (device_id == it->device_id())
+ return static_cast<double>(base::SysInfo::AmountOfFreeDiskSpace(
+ base::FilePath(it->location())));
+ }
+
+ return -1;
+}
+
// static
StorageInfoProvider* StorageInfoProvider::Get() {
if (provider_.Get().get() == NULL)
diff --git a/chrome/browser/extensions/api/system_storage/storage_info_provider.h b/chrome/browser/extensions/api/system_storage/storage_info_provider.h
index 5bcf4a13cc..e94246a12d 100644
--- a/chrome/browser/extensions/api/system_storage/storage_info_provider.h
+++ b/chrome/browser/extensions/api/system_storage/storage_info_provider.h
@@ -35,6 +35,9 @@ typedef std::vector<linked_ptr<
class StorageInfoProvider : public SystemInfoProvider {
public:
+ typedef base::Callback<void(const std::string&, double)>
+ GetStorageFreeSpaceCallback;
+
// Get the single shared instance of StorageInfoProvider.
static StorageInfoProvider* Get();
@@ -43,6 +46,9 @@ class StorageInfoProvider : public SystemInfoProvider {
virtual void InitializeProvider(const base::Closure& do_query_info_callback)
OVERRIDE;
+ virtual double GetStorageFreeSpaceFromTransientIdOnFileThread(
+ const std::string& transient_id);
+
const StorageUnitInfoList& storage_unit_info_list() const;
static void InitializeForTesting(scoped_refptr<StorageInfoProvider> provider);
diff --git a/chrome/browser/extensions/api/system_storage/system_storage_api.cc b/chrome/browser/extensions/api/system_storage/system_storage_api.cc
index 2157badefd..e374f63288 100644
--- a/chrome/browser/extensions/api/system_storage/system_storage_api.cc
+++ b/chrome/browser/extensions/api/system_storage/system_storage_api.cc
@@ -8,6 +8,7 @@ namespace extensions {
using api::system_storage::StorageUnitInfo;
namespace EjectDevice = api::system_storage::EjectDevice;
+namespace GetAvailableCapacity = api::system_storage::GetAvailableCapacity;
SystemStorageGetInfoFunction::SystemStorageGetInfoFunction() {
}
@@ -92,4 +93,53 @@ void SystemStorageEjectDeviceFunction::HandleResponse(
SendResponse(true);
}
+SystemStorageGetAvailableCapacityFunction::
+ SystemStorageGetAvailableCapacityFunction() {
+}
+
+SystemStorageGetAvailableCapacityFunction::
+ ~SystemStorageGetAvailableCapacityFunction() {
+}
+
+bool SystemStorageGetAvailableCapacityFunction::RunImpl() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+
+ scoped_ptr<GetAvailableCapacity::Params> params(
+ GetAvailableCapacity::Params::Create(*args_));
+ EXTENSION_FUNCTION_VALIDATE(params.get());
+
+ StorageMonitor::GetInstance()->EnsureInitialized(base::Bind(
+ &SystemStorageGetAvailableCapacityFunction::OnStorageMonitorInit,
+ this,
+ params->id));
+ return true;
+}
+
+void SystemStorageGetAvailableCapacityFunction::OnStorageMonitorInit(
+ const std::string& transient_id) {
+ content::BrowserThread::PostTaskAndReplyWithResult(
+ content::BrowserThread::FILE,
+ FROM_HERE,
+ base::Bind(
+ &StorageInfoProvider::GetStorageFreeSpaceFromTransientIdOnFileThread,
+ StorageInfoProvider::Get(), transient_id),
+ base::Bind(
+ &SystemStorageGetAvailableCapacityFunction::OnQueryCompleted,
+ this, transient_id));
+}
+
+void SystemStorageGetAvailableCapacityFunction::OnQueryCompleted(
+ const std::string& transient_id, double available_capacity) {
+ bool success = available_capacity >= 0;
+ if (success) {
+ api::system_storage::StorageAvailableCapacityInfo result;
+ result.id = transient_id;
+ result.available_capacity = available_capacity;
+ SetResult(result.ToValue().release());
+ } else {
+ SetError("Error occurred when querying available capacity.");
+ }
+ SendResponse(success);
+}
+
} // namespace extensions
diff --git a/chrome/browser/extensions/api/system_storage/system_storage_api.h b/chrome/browser/extensions/api/system_storage/system_storage_api.h
index 07e29a664c..f31793c8b0 100644
--- a/chrome/browser/extensions/api/system_storage/system_storage_api.h
+++ b/chrome/browser/extensions/api/system_storage/system_storage_api.h
@@ -44,6 +44,21 @@ class SystemStorageEjectDeviceFunction
void HandleResponse(StorageMonitor::EjectStatus status);
};
+class SystemStorageGetAvailableCapacityFunction
+ : public AsyncExtensionFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION("system.storage.getAvailableCapacity",
+ SYSTEM_STORAGE_GETAVAILABLECAPACITY);
+ SystemStorageGetAvailableCapacityFunction();
+
+ private:
+ void OnStorageMonitorInit(const std::string& transient_id);
+ void OnQueryCompleted(const std::string& transient_id,
+ double available_capacity);
+ virtual ~SystemStorageGetAvailableCapacityFunction();
+ virtual bool RunImpl() OVERRIDE;
+};
+
} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_API_SYSTEM_STORAGE_SYSTEM_STORAGE_API_H_
diff --git a/chrome/browser/extensions/api/system_storage/system_storage_apitest.cc b/chrome/browser/extensions/api/system_storage/system_storage_apitest.cc
index 5bd4fe9ac7..4ce92d38ef 100644
--- a/chrome/browser/extensions/api/system_storage/system_storage_apitest.cc
+++ b/chrome/browser/extensions/api/system_storage/system_storage_apitest.cc
@@ -21,13 +21,49 @@ using extensions::test::TestStorageUnitInfo;
using extensions::test::kRemovableStorageData;
const struct TestStorageUnitInfo kTestingData[] = {
- {"dcim:device:001", "0xbeaf", 4098, 1000},
- {"path:device:002", "/home", 4098, 1000},
- {"path:device:003", "/data", 10000, 1000}
+ {"dcim:device:001", "0xbeaf", 4098, 1},
+ {"path:device:002", "/home", 4098, 2},
+ {"path:device:003", "/data", 10000, 3}
};
} // namespace
+class TestStorageInfoProvider : public extensions::StorageInfoProvider {
+ public:
+ TestStorageInfoProvider(const struct TestStorageUnitInfo* testing_data,
+ size_t n);
+
+ private:
+ virtual ~TestStorageInfoProvider();
+
+ // StorageInfoProvider implementations.
+ virtual double GetStorageFreeSpaceFromTransientIdOnFileThread(
+ const std::string& transient_id) OVERRIDE;
+
+ std::vector<struct TestStorageUnitInfo> testing_data_;
+};
+
+TestStorageInfoProvider::TestStorageInfoProvider(
+ const struct TestStorageUnitInfo* testing_data, size_t n)
+ : testing_data_(testing_data, testing_data + n) {
+}
+
+TestStorageInfoProvider::~TestStorageInfoProvider() {
+}
+
+double TestStorageInfoProvider::GetStorageFreeSpaceFromTransientIdOnFileThread(
+ const std::string& transient_id) {
+ std::string device_id =
+ StorageMonitor::GetInstance()->GetDeviceIdForTransientId(
+ transient_id);
+ for (size_t i = 0; i < testing_data_.size(); ++i) {
+ if (testing_data_[i].device_id == device_id) {
+ return static_cast<double>(testing_data_[i].available_capacity);
+ }
+ }
+ return -1;
+}
+
class SystemStorageApiTest : public ExtensionApiTest {
public:
SystemStorageApiTest() {}
@@ -65,6 +101,10 @@ class SystemStorageApiTest : public ExtensionApiTest {
IN_PROC_BROWSER_TEST_F(SystemStorageApiTest, Storage) {
SetUpAllMockStorageDevices();
+ TestStorageInfoProvider* provider =
+ new TestStorageInfoProvider(kTestingData,
+ arraysize(kTestingData));
+ extensions::StorageInfoProvider::InitializeForTesting(provider);
std::vector<linked_ptr<ExtensionTestMessageListener> > device_ids_listeners;
for (size_t i = 0; i < arraysize(kTestingData); ++i) {
linked_ptr<ExtensionTestMessageListener> listener(
diff --git a/chrome/browser/extensions/api/tab_capture/tab_capture_performancetest.cc b/chrome/browser/extensions/api/tab_capture/tab_capture_performancetest.cc
index b7b6978f0c..5bd518763f 100644
--- a/chrome/browser/extensions/api/tab_capture/tab_capture_performancetest.cc
+++ b/chrome/browser/extensions/api/tab_capture/tab_capture_performancetest.cc
@@ -231,7 +231,15 @@ class TabCapturePerformanceTest
} // namespace
-IN_PROC_BROWSER_TEST_P(TabCapturePerformanceTest, Performance) {
+// This does not work on Aura and Mac GPU bots yet
+// http://crbug.com/308236
+#if defined(USE_AURA) || defined(OS_MACOSX)
+#define MAYBE_Performance DISABLED_Performance
+#else
+#define MAYBE_Performance Performance
+#endif
+
+IN_PROC_BROWSER_TEST_P(TabCapturePerformanceTest, MAYBE_Performance) {
RunTest("TabCapturePerformance");
}
@@ -250,7 +258,7 @@ INSTANTIATE_TEST_CASE_P(
kTestThroughWebRTC | kDisableVsync,
kTestThroughWebRTC | kDisableVsync | kUseGpu | kForceGpuComposited));
-#ifdef USE_AURA
+#if defined(USE_AURA)
// TODO(hubbe):
// These are temporary tests for the purpose of determining what the
// appropriate scaling quality is. Once that has been determined,
diff --git a/chrome/browser/extensions/api/tabs/windows_event_router.cc b/chrome/browser/extensions/api/tabs/windows_event_router.cc
index 1f90f45e56..adc9a07889 100644
--- a/chrome/browser/extensions/api/tabs/windows_event_router.cc
+++ b/chrome/browser/extensions/api/tabs/windows_event_router.cc
@@ -9,6 +9,7 @@
#include "chrome/browser/extensions/event_router.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/extensions/window_controller.h"
#include "chrome/browser/extensions/window_controller_list.h"
#include "chrome/browser/profiles/profile.h"
@@ -115,8 +116,9 @@ static void WillDispatchWindowFocusedEvent(Profile* new_active_profile,
// can't see the new focused window across the incognito boundary.
// See crbug.com/46610.
if (new_active_profile && new_active_profile != profile &&
- !extensions::ExtensionSystem::Get(profile)->extension_service()->
- CanCrossIncognito(extension)) {
+ !extension_util::CanCrossIncognito(
+ extension,
+ extensions::ExtensionSystem::Get(profile)->extension_service())) {
event_args->Clear();
event_args->Append(new base::FundamentalValue(
extension_misc::kUnknownWindowId));
diff --git a/chrome/browser/extensions/api/usb/usb_api.cc b/chrome/browser/extensions/api/usb/usb_api.cc
index 1898fcb571..48a6840b67 100644
--- a/chrome/browser/extensions/api/usb/usb_api.cc
+++ b/chrome/browser/extensions/api/usb/usb_api.cc
@@ -65,7 +65,9 @@ const char kErrorOpen[] = "Failed to open device.";
const char kErrorCancelled[] = "Transfer was cancelled.";
const char kErrorDisconnect[] = "Device disconnected.";
const char kErrorGeneric[] = "Transfer failed.";
+#if !defined(OS_CHROMEOS)
const char kErrorNotSupported[] = "Not supported on this platform.";
+#endif
const char kErrorOverflow[] = "Inbound transfer overflow.";
const char kErrorStalled[] = "Transfer stalled.";
const char kErrorTimeout[] = "Transfer timed out.";
diff --git a/chrome/browser/extensions/api/web_navigation/web_navigation_api.cc b/chrome/browser/extensions/api/web_navigation/web_navigation_api.cc
index cdf05541e0..7616dcc370 100644
--- a/chrome/browser/extensions/api/web_navigation/web_navigation_api.cc
+++ b/chrome/browser/extensions/api/web_navigation/web_navigation_api.cc
@@ -406,6 +406,7 @@ void WebNavigationTabObserver::DidStartProvisionalLoadForFrame(
void WebNavigationTabObserver::DidCommitProvisionalLoadForFrame(
int64 frame_num,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& url,
content::PageTransition transition_type,
@@ -483,6 +484,7 @@ void WebNavigationTabObserver::DidCommitProvisionalLoadForFrame(
void WebNavigationTabObserver::DidFailProvisionalLoad(
int64 frame_num,
+ const string16& frame_unique_id,
bool is_main_frame,
const GURL& validated_url,
int error_code,
diff --git a/chrome/browser/extensions/api/web_navigation/web_navigation_api.h b/chrome/browser/extensions/api/web_navigation/web_navigation_api.h
index d0a6a6996c..eeb25ec72f 100644
--- a/chrome/browser/extensions/api/web_navigation/web_navigation_api.h
+++ b/chrome/browser/extensions/api/web_navigation/web_navigation_api.h
@@ -66,12 +66,14 @@ class WebNavigationTabObserver
content::RenderViewHost* render_view_host) OVERRIDE;
virtual void DidCommitProvisionalLoadForFrame(
int64 frame_num,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& url,
content::PageTransition transition_type,
content::RenderViewHost* render_view_host) OVERRIDE;
virtual void DidFailProvisionalLoad(
int64 frame_num,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& validated_url,
int error_code,
diff --git a/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc b/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc
index df18d25096..bb0a7d0906 100644
--- a/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc
+++ b/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc
@@ -202,6 +202,7 @@ class DelayLoadStartAndExecuteJavascript
virtual void DidCommitProvisionalLoadForFrame(
int64 frame_id,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& url,
content::PageTransition transition_type,
@@ -533,7 +534,7 @@ IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, MAYBE_UserAction) {
ExtensionService* service = extensions::ExtensionSystem::Get(
browser()->profile())->extension_service();
const extensions::Extension* extension =
- service->GetExtensionById(last_loaded_extension_id_, false);
+ service->GetExtensionById(last_loaded_extension_id(), false);
GURL url = extension->GetResourceURL("userAction/a.html");
ui_test_utils::NavigateToURL(browser(), url);
@@ -575,7 +576,7 @@ IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, MAYBE_RequestOpenTab) {
ExtensionService* service = extensions::ExtensionSystem::Get(
browser()->profile())->extension_service();
const extensions::Extension* extension =
- service->GetExtensionById(last_loaded_extension_id_, false);
+ service->GetExtensionById(last_loaded_extension_id(), false);
GURL url = extension->GetResourceURL("requestOpenTab/a.html");
ui_test_utils::NavigateToURL(browser(), url);
@@ -687,7 +688,7 @@ IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, CrossProcess) {
ExtensionService* service = extensions::ExtensionSystem::Get(
browser()->profile())->extension_service();
const extensions::Extension* extension =
- service->GetExtensionById(last_loaded_extension_id_, false);
+ service->GetExtensionById(last_loaded_extension_id(), false);
// See crossProcess/d.html.
DelayLoadStartAndExecuteJavascript call_script(
@@ -709,7 +710,7 @@ IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, CrossProcessFragment) {
ExtensionService* service = extensions::ExtensionSystem::Get(
browser()->profile())->extension_service();
const extensions::Extension* extension =
- service->GetExtensionById(last_loaded_extension_id_, false);
+ service->GetExtensionById(last_loaded_extension_id(), false);
// See crossProcess/f.html.
DelayLoadStartAndExecuteJavascript call_script3(
@@ -742,7 +743,7 @@ IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, CrossProcessHistory) {
ExtensionService* service = extensions::ExtensionSystem::Get(
browser()->profile())->extension_service();
const extensions::Extension* extension =
- service->GetExtensionById(last_loaded_extension_id_, false);
+ service->GetExtensionById(last_loaded_extension_id(), false);
// See crossProcess/e.html.
DelayLoadStartAndExecuteJavascript call_script2(
diff --git a/chrome/browser/extensions/api/web_request/web_request_apitest.cc b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
index 05de8d862b..67d8623c31 100644
--- a/chrome/browser/extensions/api/web_request/web_request_apitest.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
@@ -135,7 +135,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, MAYBE_WebRequestNewTab) {
ExtensionService* service = extensions::ExtensionSystem::Get(
browser()->profile())->extension_service();
const extensions::Extension* extension =
- service->GetExtensionById(last_loaded_extension_id_, false);
+ service->GetExtensionById(last_loaded_extension_id(), false);
GURL url = extension->GetResourceURL("newTab/a.html");
ui_test_utils::NavigateToURL(browser(), url);
diff --git a/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc b/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
index ad40866543..f01005f81e 100644
--- a/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
+++ b/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
@@ -468,6 +468,7 @@ void WebstorePrivateBeginInstallWithManifest3Function::InstallUIProceed() {
// If we are enabling the launcher, we should not show the app list in order
// to train the user to open it themselves at least once.
approval->skip_post_install_ui = params_->details.enable_launcher;
+ approval->dummy_extension = dummy_extension_;
approval->installing_icon = gfx::ImageSkia::CreateFrom1xBitmap(icon_);
g_pending_approvals.Get().PushApproval(approval.Pass());
diff --git a/chrome/browser/extensions/app_background_page_apitest.cc b/chrome/browser/extensions/app_background_page_apitest.cc
index f07952c868..8687af80d2 100644
--- a/chrome/browser/extensions/app_background_page_apitest.cc
+++ b/chrome/browser/extensions/app_background_page_apitest.cc
@@ -13,6 +13,7 @@
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_dialogs.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h"
@@ -69,7 +70,7 @@ class AppBackgroundPageApiTest : public ExtensionApiTest {
DLOG(WARNING) << "Skipping check - background mode disabled";
return true;
}
- if (manager->IsBackgroundModeActiveForTest() == expected_background_mode)
+ if (manager->IsBackgroundModeActive() == expected_background_mode)
return true;
// We are not currently in the expected state - wait for the state to
@@ -78,7 +79,7 @@ class AppBackgroundPageApiTest : public ExtensionApiTest {
chrome::NOTIFICATION_BACKGROUND_MODE_CHANGED,
content::NotificationService::AllSources());
watcher.Wait();
- return manager->IsBackgroundModeActiveForTest() == expected_background_mode;
+ return manager->IsBackgroundModeActive() == expected_background_mode;
#endif
}
@@ -216,6 +217,11 @@ IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, ManifestBackgroundPage) {
}
IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, NoJsBackgroundPage) {
+ // Keep the task manager up through this test to verify that a crash doesn't
+ // happen when window.open creates a background page that switches
+ // RenderViewHosts. See http://crbug.com/165138.
+ chrome::ShowTaskManager(browser());
+
// Make sure that no BackgroundContentses get deleted (a signal that repeated
// window.open calls recreate instances, instead of being no-ops).
content::TestNotificationTracker background_deleted_tracker;
diff --git a/chrome/browser/extensions/component_loader.cc b/chrome/browser/extensions/component_loader.cc
index 81aa454db3..1f802b5164 100644
--- a/chrome/browser/extensions/component_loader.cc
+++ b/chrome/browser/extensions/component_loader.cc
@@ -435,12 +435,18 @@ void ComponentLoader::AddDefaultComponentExtensionsWithBackgroundPages(
#endif
}
+ // If (!enable_background_extensions_during_testing || this isn't a test)
+ // install_feedback = false;
+ bool install_feedback = enable_background_extensions_during_testing;
#if defined(GOOGLE_CHROME_BUILD)
- Add(IDR_FEEDBACK_MANIFEST, base::FilePath(FILE_PATH_LITERAL("feedback")));
+ install_feedback = true;
#endif // defined(GOOGLE_CHROME_BUILD)
+ if (install_feedback)
+ Add(IDR_FEEDBACK_MANIFEST, base::FilePath(FILE_PATH_LITERAL("feedback")));
#if defined(OS_CHROMEOS)
- if (!skip_session_components) {
+ if (!skip_session_components &&
+ !command_line->HasSwitch(chromeos::switches::kGuestSession)) {
Add(IDR_WALLPAPERMANAGER_MANIFEST,
base::FilePath(FILE_PATH_LITERAL("chromeos/wallpaper_manager")));
@@ -500,11 +506,13 @@ void ComponentLoader::AddDefaultComponentExtensionsWithBackgroundPages(
std::string enable_prefix(kEnablePrefix);
std::string field_trial_result =
base::FieldTrialList::FindFullName(kFieldTrialName);
- if ((field_trial_result.compare(
+ if (((field_trial_result.compare(
0,
enable_prefix.length(),
- enable_prefix) == 0) ||
- CommandLine::ForCurrentProcess()->HasSwitch(
+ enable_prefix) == 0) &&
+ !CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableGoogleNowIntegration)) ||
+ CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableGoogleNowIntegration)) {
Add(IDR_GOOGLE_NOW_MANIFEST,
base::FilePath(FILE_PATH_LITERAL("google_now")));
diff --git a/chrome/browser/extensions/context_menu_matcher.cc b/chrome/browser/extensions/context_menu_matcher.cc
index 950461d4d0..c125660b09 100644
--- a/chrome/browser/extensions/context_menu_matcher.cc
+++ b/chrome/browser/extensions/context_menu_matcher.cc
@@ -7,6 +7,7 @@
#include "chrome/browser/extensions/context_menu_matcher.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/profiles/profile.h"
#include "content/public/common/context_menu_params.h"
#include "ui/gfx/favicon_size.h"
@@ -161,7 +162,7 @@ bool ContextMenuMatcher::GetRelevantExtensionTopLevelItems(
if (!all_items || all_items->empty())
return false;
- *can_cross_incognito = service->CanCrossIncognito(*extension);
+ *can_cross_incognito = extension_util::CanCrossIncognito(*extension, service);
items = GetRelevantExtensionItems(*all_items,
*can_cross_incognito);
diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc
index 2205608e8c..5b45c476cb 100644
--- a/chrome/browser/extensions/crx_installer.cc
+++ b/chrome/browser/extensions/crx_installer.cc
@@ -48,6 +48,7 @@
#include "content/public/browser/resource_dispatcher_host.h"
#include "content/public/browser/user_metrics.h"
#include "extensions/common/manifest.h"
+#include "extensions/common/permissions/permission_message_provider.h"
#include "extensions/common/user_script.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
@@ -108,7 +109,9 @@ CrxInstaller::CrxInstaller(
: install_directory_(service_weak->install_directory()),
install_source_(Manifest::INTERNAL),
approved_(false),
- expected_manifest_strict_checking_(true),
+ expected_manifest_check_level_(
+ WebstoreInstaller::MANIFEST_CHECK_LEVEL_STRICT),
+ expected_version_strict_checking_(false),
extensions_enabled_(service_weak->extensions_enabled()),
delete_source_(false),
create_app_shortcut_(false),
@@ -143,10 +146,16 @@ CrxInstaller::CrxInstaller(
// Mark the extension as approved, but save the expected manifest and ID
// so we can check that they match the CRX's.
approved_ = true;
- expected_manifest_.reset(approval->manifest->DeepCopy());
- expected_manifest_strict_checking_ = approval->strict_manifest_check;
+ expected_manifest_check_level_ = approval->manifest_check_level;
+ if (expected_manifest_check_level_ !=
+ WebstoreInstaller::MANIFEST_CHECK_LEVEL_NONE)
+ expected_manifest_.reset(approval->manifest->DeepCopy());
expected_id_ = approval->extension_id;
}
+ if (approval->minimum_version.get()) {
+ expected_version_.reset(new Version(*approval->minimum_version));
+ expected_version_strict_checking_ = false;
+ }
show_dialog_callback_ = approval->show_dialog_callback;
}
@@ -247,21 +256,41 @@ CrxInstallerError CrxInstaller::AllowInstall(const Extension* extension) {
ASCIIToUTF16(extension->id())));
}
- if (expected_version_.get() &&
- !expected_version_->Equals(*extension->version())) {
- return CrxInstallerError(
- l10n_util::GetStringFUTF16(
- IDS_EXTENSION_INSTALL_UNEXPECTED_VERSION,
- ASCIIToUTF16(expected_version_->GetString()),
- ASCIIToUTF16(extension->version()->GetString())));
+ if (expected_version_.get()) {
+ if (expected_version_strict_checking_) {
+ if (!expected_version_->Equals(*extension->version())) {
+ return CrxInstallerError(
+ l10n_util::GetStringFUTF16(
+ IDS_EXTENSION_INSTALL_UNEXPECTED_VERSION,
+ ASCIIToUTF16(expected_version_->GetString()),
+ ASCIIToUTF16(extension->version()->GetString())));
+ }
+ } else {
+ if (extension->version()->CompareTo(*expected_version_) < 0) {
+ return CrxInstallerError(
+ l10n_util::GetStringFUTF16(
+ IDS_EXTENSION_INSTALL_UNEXPECTED_VERSION,
+ ASCIIToUTF16(expected_version_->GetString() + "+"),
+ ASCIIToUTF16(extension->version()->GetString())));
+ }
+ }
}
// Make sure the manifests match if we want to bypass the prompt.
if (approved_) {
bool valid = false;
- if (expected_manifest_.get()) {
+ if (expected_manifest_check_level_ ==
+ WebstoreInstaller::MANIFEST_CHECK_LEVEL_NONE) {
+ // To skip manifest checking, the extension must be a shared module
+ // and not request any permissions.
+ if (SharedModuleInfo::IsSharedModule(extension) &&
+ PermissionsData::GetActivePermissions(extension)->IsEmpty()) {
+ valid = true;
+ }
+ } else {
valid = expected_manifest_->Equals(original_manifest_.get());
- if (!valid && !expected_manifest_strict_checking_) {
+ if (!valid && expected_manifest_check_level_ ==
+ WebstoreInstaller::MANIFEST_CHECK_LEVEL_LOOSE) {
std::string error;
scoped_refptr<Extension> dummy_extension =
Extension::Create(base::FilePath(),
@@ -272,12 +301,14 @@ CrxInstallerError CrxInstaller::AllowInstall(const Extension* extension) {
if (error.empty()) {
scoped_refptr<const PermissionSet> expected_permissions =
PermissionsData::GetActivePermissions(dummy_extension.get());
- valid = !(expected_permissions->HasLessPrivilegesThan(
- PermissionsData::GetActivePermissions(extension),
- extension->GetType()));
+ valid = !(PermissionMessageProvider::Get()->IsPrivilegeIncrease(
+ expected_permissions,
+ PermissionsData::GetActivePermissions(extension),
+ extension->GetType()));
}
}
}
+
if (!valid)
return CrxInstallerError(
l10n_util::GetStringUTF16(IDS_EXTENSION_MANIFEST_INVALID));
diff --git a/chrome/browser/extensions/crx_installer.h b/chrome/browser/extensions/crx_installer.h
index fde15b69d9..6d55481e8a 100644
--- a/chrome/browser/extensions/crx_installer.h
+++ b/chrome/browser/extensions/crx_installer.h
@@ -127,6 +127,7 @@ class CrxInstaller
void set_expected_version(const Version& val) {
expected_version_.reset(new Version(val));
+ expected_version_strict_checking_ = true;
}
bool delete_source() const { return delete_source_; }
@@ -288,10 +289,9 @@ class CrxInstaller
// extension's manifest must match this for the install to proceed.
scoped_ptr<Manifest> expected_manifest_;
- // Set to true if we want a strict, exact match check between the actual and
- // expected manifest, rather than just a check that the effective permissions
- // are the same.
- bool expected_manifest_strict_checking_;
+ // The level of checking when comparing the actual manifest against
+ // the |expected_manifest_|.
+ WebstoreInstaller::ManifestCheckLevel expected_manifest_check_level_;
// If non-NULL, contains the expected version of the extension we're
// installing. Important for external sources, where claiming the wrong
@@ -299,6 +299,11 @@ class CrxInstaller
// restart.
scoped_ptr<Version> expected_version_;
+ // If true, the actual version should be same with the |expected_version_|,
+ // Otherwise the actual version should be equal to or newer than
+ // the |expected_version_|.
+ bool expected_version_strict_checking_;
+
// Whether manual extension installation is enabled. We can't just check this
// before trying to install because themes are special-cased to always be
// allowed.
diff --git a/chrome/browser/extensions/crx_installer_browsertest.cc b/chrome/browser/extensions/crx_installer_browsertest.cc
index a91684215e..d9c7114c7b 100644
--- a/chrome/browser/extensions/crx_installer_browsertest.cc
+++ b/chrome/browser/extensions/crx_installer_browsertest.cc
@@ -365,7 +365,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, DISABLED_AllowOffStore) {
}
crx_installer->InstallCrx(test_data_dir_.AppendASCII("good.crx"));
- EXPECT_EQ(kTestData[i], WaitForExtensionInstall()) << kTestData[i];
+ EXPECT_EQ(kTestData[i],
+ WaitForExtensionInstall()) << kTestData[i];
EXPECT_EQ(kTestData[i], mock_prompt->did_succeed());
EXPECT_EQ(kTestData[i], mock_prompt->confirmation_requested()) <<
kTestData[i];
diff --git a/chrome/browser/extensions/error_console/error_console_browsertest.cc b/chrome/browser/extensions/error_console/error_console_browsertest.cc
index 3e2ab2fc3c..952ff52263 100644
--- a/chrome/browser/extensions/error_console/error_console_browsertest.cc
+++ b/chrome/browser/extensions/error_console/error_console_browsertest.cc
@@ -247,7 +247,7 @@ class ErrorConsoleBrowserTest : public ExtensionBrowserTest {
ExtensionService* service =
extensions::ExtensionSystem::Get(profile())->extension_service();
service->toolbar_model()->ExecuteBrowserAction(
- *extension, browser(), NULL);
+ *extension, browser(), NULL, true);
break;
}
case ACTION_NONE:
diff --git a/chrome/browser/extensions/event_router.cc b/chrome/browser/extensions/event_router.cc
index b547a33b77..b5e88bf4e1 100644
--- a/chrome/browser/extensions/event_router.cc
+++ b/chrome/browser/extensions/event_router.cc
@@ -22,6 +22,7 @@
#include "chrome/browser/extensions/extension_process_manager.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/extensions/lazy_background_task_queue.h"
#include "chrome/browser/extensions/process_map.h"
#include "chrome/browser/profiles/profile.h"
@@ -631,9 +632,9 @@ bool EventRouter::CanDispatchEventToProfile(Profile* profile,
// incognito tab event sent to a normal process, or vice versa).
bool cross_incognito =
event->restrict_to_profile && profile != event->restrict_to_profile;
- if (cross_incognito &&
- !ExtensionSystem::Get(profile)->extension_service()->
- CanCrossIncognito(extension)) {
+ if (cross_incognito && !extension_util::CanCrossIncognito(
+ extension,
+ ExtensionSystem::Get(profile)->extension_service())) {
return false;
}
diff --git a/chrome/browser/extensions/extension_browsertest.cc b/chrome/browser/extensions/extension_browsertest.cc
index f5da8f6d0e..0d6fd91e81 100644
--- a/chrome/browser/extensions/extension_browsertest.cc
+++ b/chrome/browser/extensions/extension_browsertest.cc
@@ -24,12 +24,12 @@
#include "chrome/browser/extensions/extension_install_prompt.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/extensions/unpacked_installer.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/ui/omnibox/location_bar.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
@@ -54,38 +54,19 @@ using extensions::ExtensionCreator;
using extensions::FeatureSwitch;
using extensions::Manifest;
-namespace {
-
-bool HasExtensionPageActionCountReachedTarget(LocationBarTesting* location_bar,
- int target_page_action_count) {
- VLOG(1) << "Number of page actions: " << location_bar->PageActionCount();
- return location_bar->PageActionCount() == target_page_action_count;
-}
-
-bool HasExtensionPageActionVisibilityReachedTarget(
- LocationBarTesting* location_bar,
- int target_visible_page_action_count) {
- VLOG(1) << "Number of visible page actions: "
- << location_bar->PageActionVisibleCount();
- return location_bar->PageActionVisibleCount() ==
- target_visible_page_action_count;
-}
-
-} // namespace
-
ExtensionBrowserTest::ExtensionBrowserTest()
: loaded_(false),
installed_(false),
- extension_installs_observed_(0),
- extension_load_errors_observed_(0),
current_channel_(chrome::VersionInfo::CHANNEL_DEV),
override_prompt_for_external_extensions_(
- FeatureSwitch::prompt_for_external_extensions(), false),
+ FeatureSwitch::prompt_for_external_extensions(),
+ false),
profile_(NULL) {
EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
}
-ExtensionBrowserTest::~ExtensionBrowserTest() {}
+ExtensionBrowserTest::~ExtensionBrowserTest() {
+}
Profile* ExtensionBrowserTest::profile() {
if (!profile_) {
@@ -114,6 +95,7 @@ const Extension* ExtensionBrowserTest::GetExtensionByPath(
void ExtensionBrowserTest::SetUpCommandLine(CommandLine* command_line) {
PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir_);
test_data_dir_ = test_data_dir_.AppendASCII("extensions");
+ observer_.reset(new ExtensionTestNotificationObserver(browser()));
#if defined(OS_CHROMEOS)
// This makes sure that we create the Default profile first, with no
@@ -127,6 +109,7 @@ void ExtensionBrowserTest::SetUpCommandLine(CommandLine* command_line) {
void ExtensionBrowserTest::SetUpOnMainThread() {
InProcessBrowserTest::SetUpOnMainThread();
+ observer_.reset(new ExtensionTestNotificationObserver(browser()));
}
const Extension* ExtensionBrowserTest::LoadExtensionWithFlags(
@@ -134,23 +117,21 @@ const Extension* ExtensionBrowserTest::LoadExtensionWithFlags(
ExtensionService* service = extensions::ExtensionSystem::Get(
profile())->extension_service();
{
- content::WindowedNotificationObserver observer(
- chrome::NOTIFICATION_EXTENSION_LOADED,
- content::NotificationService::AllSources());
- content::NotificationRegistrar registrar;
- registrar.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
- content::NotificationService::AllSources());
+ observer_->Watch(chrome::NOTIFICATION_EXTENSION_LOADED,
+ content::NotificationService::AllSources());
+
scoped_refptr<extensions::UnpackedInstaller> installer(
extensions::UnpackedInstaller::Create(service));
installer->set_prompt_for_plugins(false);
installer->set_require_modern_manifest_version(
(flags & kFlagAllowOldManifestVersions) == 0);
installer->Load(path);
- observer.Wait();
+
+ observer_->Wait();
}
// Find the loaded extension by its path. See crbug.com/59531 for why
- // we cannot just use last_loaded_extension_id_.
+ // we cannot just use last_loaded_extension_id().
const Extension* extension = GetExtensionByPath(service->extensions(), path);
if (!extension)
return NULL;
@@ -192,11 +173,11 @@ const Extension* ExtensionBrowserTest::LoadExtensionWithFlags(
content::WindowedNotificationObserver load_signal(
chrome::NOTIFICATION_EXTENSION_LOADED,
content::Source<Profile>(profile()));
- CHECK(!service->IsIncognitoEnabled(extension_id) ||
+ CHECK(!extension_util::IsIncognitoEnabled(extension_id, service) ||
extension->force_incognito_enabled());
if (flags & kFlagEnableIncognito) {
- service->SetIsIncognitoEnabled(extension_id, true);
+ extension_util::SetIsIncognitoEnabled(extension_id, service, true);
load_signal.Wait();
extension = service->GetExtensionById(extension_id, false);
CHECK(extension) << extension_id << " not found after reloading.";
@@ -207,16 +188,16 @@ const Extension* ExtensionBrowserTest::LoadExtensionWithFlags(
content::WindowedNotificationObserver load_signal(
chrome::NOTIFICATION_EXTENSION_LOADED,
content::Source<Profile>(profile()));
- CHECK(service->AllowFileAccess(extension));
+ CHECK(extension_util::AllowFileAccess(extension, service));
if (!(flags & kFlagEnableFileAccess)) {
- service->SetAllowFileAccess(extension, false);
+ extension_util::SetAllowFileAccess(extension, service, false);
load_signal.Wait();
extension = service->GetExtensionById(extension_id, false);
CHECK(extension) << extension_id << " not found after reloading.";
}
}
- if (!WaitForExtensionViewsToLoad())
+ if (!observer_->WaitForExtensionViewsToLoad())
return NULL;
return extension;
@@ -248,7 +229,7 @@ const Extension* ExtensionBrowserTest::LoadExtensionAsComponentWithManifest(
const Extension* extension = service->extensions()->GetByID(extension_id);
if (!extension)
return NULL;
- last_loaded_extension_id_ = extension->id();
+ observer_->set_last_loaded_extension_id(extension->id());
return extension;
}
@@ -456,16 +437,13 @@ const Extension* ExtensionBrowserTest::InstallOrUpdateExtension(
extensions::CrxInstaller::OffStoreInstallAllowedInTest);
}
- content::WindowedNotificationObserver observer(
+ observer_->Watch(
chrome::NOTIFICATION_CRX_INSTALLER_DONE,
content::Source<extensions::CrxInstaller>(installer.get()));
- content::NotificationRegistrar registrar;
- registrar.Add(this, chrome::NOTIFICATION_CRX_INSTALLER_DONE,
- content::Source<extensions::CrxInstaller>(installer.get()));
installer->InstallCrx(crx_path);
- observer.Wait();
+ observer_->Wait();
}
size_t num_after = service->extensions()->size();
@@ -489,24 +467,21 @@ const Extension* ExtensionBrowserTest::InstallOrUpdateExtension(
return NULL;
}
- if (!WaitForExtensionViewsToLoad())
+ if (!observer_->WaitForExtensionViewsToLoad())
return NULL;
- return service->GetExtensionById(last_loaded_extension_id_, false);
+ return service->GetExtensionById(last_loaded_extension_id(), false);
}
void ExtensionBrowserTest::ReloadExtension(const std::string extension_id) {
- content::WindowedNotificationObserver observer(
- chrome::NOTIFICATION_EXTENSION_LOADED,
- content::NotificationService::AllSources());
- content::NotificationRegistrar registrar;
- registrar.Add(this,
- chrome::NOTIFICATION_EXTENSION_LOADED,
+ observer_->Watch(chrome::NOTIFICATION_EXTENSION_LOADED,
content::NotificationService::AllSources());
+
ExtensionService* service =
extensions::ExtensionSystem::Get(profile())->extension_service();
service->ReloadExtension(extension_id);
- observer.Wait();
- WaitForExtensionViewsToLoad();
+
+ observer_->Wait();
+ observer_->WaitForExtensionViewsToLoad();
}
void ExtensionBrowserTest::UnloadExtension(const std::string& extension_id) {
@@ -533,126 +508,11 @@ void ExtensionBrowserTest::EnableExtension(const std::string& extension_id) {
service->EnableExtension(extension_id);
}
-bool ExtensionBrowserTest::WaitForPageActionCountChangeTo(int count) {
- LocationBarTesting* location_bar =
- browser()->window()->GetLocationBar()->GetLocationBarForTesting();
- if (!HasExtensionPageActionCountReachedTarget(location_bar, count)) {
- content::WindowedNotificationObserver(
- chrome::NOTIFICATION_EXTENSION_PAGE_ACTION_COUNT_CHANGED,
- base::Bind(
- &HasExtensionPageActionCountReachedTarget, location_bar, count))
- .Wait();
- }
- return HasExtensionPageActionCountReachedTarget(location_bar, count);
-}
-
-bool ExtensionBrowserTest::WaitForPageActionVisibilityChangeTo(int count) {
- LocationBarTesting* location_bar =
- browser()->window()->GetLocationBar()->GetLocationBarForTesting();
- if (!HasExtensionPageActionVisibilityReachedTarget(location_bar, count)) {
- content::WindowedNotificationObserver(
- chrome::NOTIFICATION_EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED,
- base::Bind(&HasExtensionPageActionVisibilityReachedTarget,
- location_bar,
- count))
- .Wait();
- }
- return HasExtensionPageActionVisibilityReachedTarget(location_bar, count);
-}
-
-void ExtensionBrowserTest::WaitForNotification(int notification_type) {
- // TODO(bauerb): Using a WindowedNotificationObserver like this can break
- // easily, if the notification we're waiting for is sent before this method.
- // Change it so that the WindowedNotificationObserver is constructed earlier.
- content::NotificationRegistrar registrar;
- registrar.Add(this, notification_type,
- content::NotificationService::AllSources());
- content::WindowedNotificationObserver(
- notification_type, content::NotificationService::AllSources()).Wait();
-}
-
-bool ExtensionBrowserTest::WaitForExtensionViewsToLoad() {
-
- ExtensionProcessManager* manager =
- extensions::ExtensionSystem::Get(profile())->process_manager();
- ExtensionProcessManager::ViewSet all_views = manager->GetAllViews();
- for (ExtensionProcessManager::ViewSet::const_iterator iter =
- all_views.begin();
- iter != all_views.end();) {
- if (!(*iter)->IsLoading()) {
- ++iter;
- } else {
- // Wait for all the extension render view hosts that exist to finish
- // loading.
- content::WindowedNotificationObserver observer(
- content::NOTIFICATION_LOAD_STOP,
- content::NotificationService::AllSources());
- observer.AddNotificationType(
- content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
- content::NotificationService::AllSources());
- observer.Wait();
-
- // Test activity may have modified the set of extension processes during
- // message processing, so re-start the iteration to catch added/removed
- // processes.
- all_views = manager->GetAllViews();
- iter = all_views.begin();
- }
- }
- return true;
-}
-
-bool ExtensionBrowserTest::WaitForExtensionInstall() {
- int before = extension_installs_observed_;
- WaitForNotification(chrome::NOTIFICATION_EXTENSION_INSTALLED);
- return extension_installs_observed_ == (before + 1);
-}
-
-bool ExtensionBrowserTest::WaitForExtensionInstallError() {
- int before = extension_installs_observed_;
- content::WindowedNotificationObserver(
- chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
- content::NotificationService::AllSources()).Wait();
- return extension_installs_observed_ == before;
-}
-
-void ExtensionBrowserTest::WaitForExtensionLoad() {
- WaitForNotification(chrome::NOTIFICATION_EXTENSION_LOADED);
- WaitForExtensionViewsToLoad();
-}
-
-bool ExtensionBrowserTest::WaitForExtensionLoadError() {
- int before = extension_load_errors_observed_;
- WaitForNotification(chrome::NOTIFICATION_EXTENSION_LOAD_ERROR);
- return extension_load_errors_observed_ != before;
-}
-
-bool ExtensionBrowserTest::WaitForExtensionCrash(
- const std::string& extension_id) {
- ExtensionService* service =
- extensions::ExtensionSystem::Get(profile())->extension_service();
-
- if (!service->GetExtensionById(extension_id, true)) {
- // The extension is already unloaded, presumably due to a crash.
- return true;
- }
- content::WindowedNotificationObserver(
- chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED,
- content::NotificationService::AllSources()).Wait();
- return (service->GetExtensionById(extension_id, true) == NULL);
-}
-
-bool ExtensionBrowserTest::WaitForCrxInstallerDone() {
- int before = crx_installers_done_observed_;
- WaitForNotification(chrome::NOTIFICATION_CRX_INSTALLER_DONE);
- return crx_installers_done_observed_ == (before + 1);
-}
-
void ExtensionBrowserTest::OpenWindow(content::WebContents* contents,
const GURL& url,
bool newtab_process_should_equal_opener,
content::WebContents** newtab_result) {
- content::WindowedNotificationObserver observer(
+ content::WindowedNotificationObserver windowed_observer(
content::NOTIFICATION_LOAD_STOP,
content::NotificationService::AllSources());
ASSERT_TRUE(content::ExecuteScript(contents,
@@ -661,9 +521,10 @@ void ExtensionBrowserTest::OpenWindow(content::WebContents* contents,
// The above window.open call is not user-initiated, so it will create
// a popup window instead of a new tab in current window.
// The stop notification will come from the new tab.
- observer.Wait();
+ windowed_observer.Wait();
content::NavigationController* controller =
- content::Source<content::NavigationController>(observer.source()).ptr();
+ content::Source<content::NavigationController>(
+ windowed_observer.source()).ptr();
content::WebContents* newtab = controller->GetWebContents();
ASSERT_TRUE(newtab);
EXPECT_EQ(url, controller->GetLastCommittedEntry()->GetURL());
@@ -679,7 +540,7 @@ void ExtensionBrowserTest::OpenWindow(content::WebContents* contents,
void ExtensionBrowserTest::NavigateInRenderer(content::WebContents* contents,
const GURL& url) {
bool result = false;
- content::WindowedNotificationObserver observer(
+ content::WindowedNotificationObserver windowed_observer(
content::NOTIFICATION_LOAD_STOP,
content::NotificationService::AllSources());
ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
@@ -690,7 +551,7 @@ void ExtensionBrowserTest::NavigateInRenderer(content::WebContents* contents,
"window.location = '" + url.spec() + "';",
&result));
ASSERT_TRUE(result);
- observer.Wait();
+ windowed_observer.Wait();
EXPECT_EQ(url, contents->GetController().GetLastCommittedEntry()->GetURL());
}
@@ -720,43 +581,3 @@ std::string ExtensionBrowserTest::ExecuteScriptInBackgroundPage(
return extensions::browsertest_util::ExecuteScriptInBackgroundPage(
profile(), extension_id, script);
}
-
-void ExtensionBrowserTest::Observe(
- int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) {
- switch (type) {
- case chrome::NOTIFICATION_EXTENSION_LOADED:
- last_loaded_extension_id_ =
- content::Details<const Extension>(details).ptr()->id();
- VLOG(1) << "Got EXTENSION_LOADED notification.";
- break;
-
- case chrome::NOTIFICATION_CRX_INSTALLER_DONE:
- VLOG(1) << "Got CRX_INSTALLER_DONE notification.";
- {
- const Extension* extension =
- content::Details<const Extension>(details).ptr();
- if (extension)
- last_loaded_extension_id_ = extension->id();
- else
- last_loaded_extension_id_.clear();
- }
- ++crx_installers_done_observed_;
- break;
-
- case chrome::NOTIFICATION_EXTENSION_INSTALLED:
- VLOG(1) << "Got EXTENSION_INSTALLED notification.";
- ++extension_installs_observed_;
- break;
-
- case chrome::NOTIFICATION_EXTENSION_LOAD_ERROR:
- VLOG(1) << "Got EXTENSION_LOAD_ERROR notification.";
- ++extension_load_errors_observed_;
- break;
-
- default:
- NOTREACHED();
- break;
- }
-}
diff --git a/chrome/browser/extensions/extension_browsertest.h b/chrome/browser/extensions/extension_browsertest.h
index ad127c3932..ff930ea28f 100644
--- a/chrome/browser/extensions/extension_browsertest.h
+++ b/chrome/browser/extensions/extension_browsertest.h
@@ -8,19 +8,17 @@
#include <string>
#include "base/command_line.h"
-#include "base/compiler_specific.h"
+
#include "base/files/file_path.h"
#include "base/files/scoped_temp_dir.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/extension_test_notification_observer.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/feature_switch.h"
#include "chrome/common/extensions/features/feature_channel.h"
#include "chrome/test/base/in_process_browser_test.h"
-#include "content/public/browser/notification_details.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_types.h"
#include "content/public/browser/web_contents.h"
#include "extensions/common/manifest.h"
@@ -31,8 +29,7 @@ class Profile;
// Base class for extension browser tests. Provides utilities for loading,
// unloading, and installing extensions.
-class ExtensionBrowserTest : virtual public InProcessBrowserTest,
- public content::NotificationObserver {
+class ExtensionBrowserTest : virtual public InProcessBrowserTest {
protected:
// Flags used to configure how the tests are run.
enum Flags {
@@ -61,6 +58,10 @@ class ExtensionBrowserTest : virtual public InProcessBrowserTest,
return extensions::ExtensionSystem::Get(profile())->extension_service();
}
+ const std::string& last_loaded_extension_id() {
+ return observer_->last_loaded_extension_id();
+ }
+
// Get the profile to use.
Profile* profile();
@@ -194,32 +195,58 @@ class ExtensionBrowserTest : virtual public InProcessBrowserTest,
void EnableExtension(const std::string& extension_id);
// Wait for the total number of page actions to change to |count|.
- bool WaitForPageActionCountChangeTo(int count);
+ bool WaitForPageActionCountChangeTo(int count) {
+ return observer_->WaitForPageActionCountChangeTo(count);
+ }
// Wait for the number of visible page actions to change to |count|.
- bool WaitForPageActionVisibilityChangeTo(int count);
+ bool WaitForPageActionVisibilityChangeTo(int count) {
+ return observer_->WaitForPageActionVisibilityChangeTo(count);
+ }
// Waits until an extension is installed and loaded. Returns true if an
// install happened before timeout.
- bool WaitForExtensionInstall();
+ bool WaitForExtensionInstall() {
+ return observer_->WaitForExtensionInstall();
+ }
// Wait for an extension install error to be raised. Returns true if an
// error was raised.
- bool WaitForExtensionInstallError();
+ bool WaitForExtensionInstallError() {
+ return observer_->WaitForExtensionInstallError();
+ }
+
+ // Waits until an extension is loaded and all view have loaded.
+ void WaitForExtensionAndViewLoad() {
+ return observer_->WaitForExtensionAndViewLoad();
+ }
// Waits until an extension is loaded.
- void WaitForExtensionLoad();
+ void WaitForExtensionLoad() {
+ return observer_->WaitForExtensionLoad();
+ }
// Waits for an extension load error. Returns true if the error really
// happened.
- bool WaitForExtensionLoadError();
+ bool WaitForExtensionLoadError() {
+ return observer_->WaitForExtensionLoadError();
+ }
// Wait for the specified extension to crash. Returns true if it really
// crashed.
- bool WaitForExtensionCrash(const std::string& extension_id);
+ bool WaitForExtensionCrash(const std::string& extension_id) {
+ return observer_->WaitForExtensionCrash(extension_id);
+ }
// Wait for the crx installer to be done. Returns true if it really is done.
- bool WaitForCrxInstallerDone();
+ bool WaitForCrxInstallerDone() {
+ return observer_->WaitForCrxInstallerDone();
+ }
+
+ // Wait for all extension views to load.
+ bool WaitForExtensionViewsToLoad() {
+ return observer_->WaitForExtensionViewsToLoad();
+ }
// Simulates a page calling window.open on an URL and waits for the
// navigation.
@@ -238,27 +265,19 @@ class ExtensionBrowserTest : virtual public InProcessBrowserTest,
extensions::ExtensionHost* FindHostWithPath(ExtensionProcessManager* manager,
const std::string& path,
int expected_hosts);
-
// Returns
// extensions::browsertest_util::ExecuteScriptInBackgroundPage(profile(),
// extension_id, script).
std::string ExecuteScriptInBackgroundPage(const std::string& extension_id,
const std::string& script);
- // content::NotificationObserver
- virtual void Observe(int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) OVERRIDE;
-
bool loaded_;
bool installed_;
// test_data/extensions.
base::FilePath test_data_dir_;
- std::string last_loaded_extension_id_;
- int extension_installs_observed_;
- int extension_load_errors_observed_;
- int crx_installers_done_observed_;
+
+ scoped_ptr<ExtensionTestNotificationObserver> observer_;
private:
// Temporary directory for testing.
@@ -301,12 +320,6 @@ class ExtensionBrowserTest : virtual public InProcessBrowserTest,
extensions::Extension::InitFromValueFlags creation_flags,
bool wait_for_idle);
- // Wait for a notification of the specified type to be sent.
- // |notification_type| must be a type that this class handles in Observe().
- void WaitForNotification(int notification_type);
-
- bool WaitForExtensionViewsToLoad();
-
// Make the current channel "dev" for the duration of the test.
extensions::ScopedCurrentChannel current_channel_;
diff --git a/chrome/browser/extensions/extension_commands_global_registry_apitest.cc b/chrome/browser/extensions/extension_commands_global_registry_apitest.cc
new file mode 100644
index 0000000000..85f3ac40c6
--- /dev/null
+++ b/chrome/browser/extensions/extension_commands_global_registry_apitest.cc
@@ -0,0 +1,128 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/extension_apitest.h"
+#include "chrome/browser/extensions/window_controller.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/test/base/interactive_test_utils.h"
+#include "content/public/test/browser_test_utils.h"
+#include "ui/base/base_window.h"
+
+#if defined(TOOLKIT_GTK)
+#include <X11/Xlib.h>
+#include <X11/extensions/XTest.h>
+#include <X11/keysym.h>
+
+#include "ui/events/keycodes/keyboard_code_conversion_x.h"
+#include "ui/gfx/x/x11_types.h"
+#endif
+
+namespace extensions {
+
+typedef ExtensionApiTest GlobalCommandsApiTest;
+
+#if defined(TOOLKIT_GTK)
+// Send a simulated key press and release event, where |control|, |shift| or
+// |alt| indicates whether the key is struck with corresponding modifier.
+void SendNativeKeyEventToXDisplay(ui::KeyboardCode key,
+ bool control,
+ bool shift,
+ bool alt) {
+ Display* display = gfx::GetXDisplay();
+ KeyCode ctrl_key_code = XKeysymToKeycode(display, XK_Control_L);
+ KeyCode shift_key_code = XKeysymToKeycode(display, XK_Shift_L);
+ KeyCode alt_key_code = XKeysymToKeycode(display, XK_Alt_L);
+
+ // Release modifiers first of all to make sure this function can work as
+ // expected. For example, when |control| is false, but the status of Ctrl key
+ // is down, we will generate a keyboard event with unwanted Ctrl key.
+ XTestFakeKeyEvent(display, ctrl_key_code, False, CurrentTime);
+ XTestFakeKeyEvent(display, shift_key_code, False, CurrentTime);
+ XTestFakeKeyEvent(display, alt_key_code, False, CurrentTime);
+
+ typedef std::vector<KeyCode> KeyCodes;
+ KeyCodes key_codes;
+ if (control)
+ key_codes.push_back(ctrl_key_code);
+ if (shift)
+ key_codes.push_back(shift_key_code);
+ if (alt)
+ key_codes.push_back(alt_key_code);
+
+ key_codes.push_back(XKeysymToKeycode(display,
+ XKeysymForWindowsKeyCode(key, false)));
+
+ // Simulate the keys being pressed.
+ for (KeyCodes::iterator it = key_codes.begin(); it != key_codes.end(); it++)
+ XTestFakeKeyEvent(display, *it, True, CurrentTime);
+
+ // Simulate the keys being released.
+ for (KeyCodes::iterator it = key_codes.begin(); it != key_codes.end(); it++)
+ XTestFakeKeyEvent(display, *it, False, CurrentTime);
+
+ XFlush(display);
+}
+#endif // TOOLKIT_GTK
+
+#if defined(OS_WIN) || defined(TOOLKIT_GTK)
+// The feature is only fully implemented on Windows and Linux GTK+, other
+// platforms coming.
+#define MAYBE_GlobalCommand GlobalCommand
+#else
+#define MAYBE_GlobalCommand DISABLED_GlobalCommand
+#endif
+
+// Test the basics of global commands and make sure they work when Chrome
+// doesn't have focus. Also test that non-global commands are not treated as
+// global and that keys beyond Ctrl+Shift+[0..9] cannot be auto-assigned by an
+// extension.
+IN_PROC_BROWSER_TEST_F(GlobalCommandsApiTest, MAYBE_GlobalCommand) {
+ FeatureSwitch::ScopedOverride enable_global_commands(
+ FeatureSwitch::global_commands(), true);
+
+ // Load the extension in the non-incognito browser.
+ ResultCatcher catcher;
+ ASSERT_TRUE(RunExtensionTest("keybinding/global")) << message_;
+ ASSERT_TRUE(catcher.GetNextResult());
+
+#if !defined(TOOLKIT_GTK)
+ // Our infrastructure for sending keys expects a browser to send them to, but
+ // to properly test global shortcuts you need to send them to another target.
+ // So, create an incognito browser to use as a target to send the shortcuts
+ // to. It will ignore all of them and allow us test whether the global
+ // shortcut really is global in nature and also that the non-global shortcut
+ // is non-global.
+ Browser* incognito_browser = CreateIncognitoBrowser();
+
+ // Try to activate the non-global shortcut (Ctrl+Shift+1) and the
+ // non-assignable shortcut (Ctrl+Shift+A) by sending the keystrokes to the
+ // incognito browser. Both shortcuts should have no effect (extension is not
+ // loaded there).
+ ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
+ incognito_browser, ui::VKEY_1, true, true, false, false));
+ ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
+ incognito_browser, ui::VKEY_A, true, true, false, false));
+
+ // Activate the shortcut (Ctrl+Shift+9). This should have an effect.
+ ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
+ incognito_browser, ui::VKEY_9, true, true, false, false));
+#else
+ // On Linux GTK+, our infrastructure for sending keys just synthesize keyboard
+ // event and send them directly to the specified window, without notifying the
+ // X root window. It didn't work while testing global shortcut because the
+ // stuff of global shortcut on Linux need to be notified when KeyPress event
+ // is happening on X root window. So we simulate the keyboard input here.
+ SendNativeKeyEventToXDisplay(ui::VKEY_1, true, true, false);
+ SendNativeKeyEventToXDisplay(ui::VKEY_A, true, true, false);
+ SendNativeKeyEventToXDisplay(ui::VKEY_9, true, true, false);
+#endif
+
+ // If this fails, it might be because the global shortcut failed to work,
+ // but it might also be because the non-global shortcuts unexpectedly
+ // worked.
+ ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
+}
+
+} // namespace extensions
diff --git a/chrome/browser/extensions/extension_disabled_ui.cc b/chrome/browser/extensions/extension_disabled_ui.cc
index 42767a1bf1..0192142a32 100644
--- a/chrome/browser/extensions/extension_disabled_ui.cc
+++ b/chrome/browser/extensions/extension_disabled_ui.cc
@@ -34,6 +34,7 @@
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/notification_source.h"
+#include "extensions/common/permissions/permission_message_provider.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
@@ -265,8 +266,8 @@ std::vector<string16> ExtensionDisabledGlobalError::GetBubbleViewMessages() {
messages.push_back(l10n_util::GetStringUTF16(
IDS_EXTENSION_PROMPT_WILL_NOW_HAVE_ACCESS_TO));
std::vector<string16> permission_warnings =
- extension_->GetActivePermissions()->GetWarningMessages(
- extension_->GetType());
+ extensions::PermissionMessageProvider::Get()->GetWarningMessages(
+ extension_->GetActivePermissions(), extension_->GetType());
for (size_t i = 0; i < permission_warnings.size(); ++i) {
messages.push_back(l10n_util::GetStringFUTF16(
IDS_EXTENSION_PERMISSION_LINE, permission_warnings[i]));
diff --git a/chrome/browser/extensions/extension_function.cc b/chrome/browser/extensions/extension_function.cc
index 766a10687d..5b5ea2a365 100644
--- a/chrome/browser/extensions/extension_function.cc
+++ b/chrome/browser/extensions/extension_function.cc
@@ -21,9 +21,12 @@
#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
using content::BrowserThread;
using content::RenderViewHost;
+using content::WebContents;
using extensions::ExtensionAPI;
using extensions::Feature;
@@ -32,25 +35,36 @@ void ExtensionFunctionDeleteTraits::Destruct(const ExtensionFunction* x) {
x->Destruct();
}
-UIThreadExtensionFunction::RenderViewHostTracker::RenderViewHostTracker(
- UIThreadExtensionFunction* function)
- : content::RenderViewHostObserver(function->render_view_host()),
- function_(function) {
-}
+// Helper class to track the lifetime of ExtensionFunction's RenderViewHost
+// pointer and NULL it out when it dies. It also allows us to filter IPC
+// messages coming from the RenderViewHost.
+class UIThreadExtensionFunction::RenderViewHostTracker
+ : public content::WebContentsObserver {
+ public:
+ explicit RenderViewHostTracker(UIThreadExtensionFunction* function)
+ : content::WebContentsObserver(
+ WebContents::FromRenderViewHost(function->render_view_host())),
+ function_(function) {
+ }
-void UIThreadExtensionFunction::RenderViewHostTracker::RenderViewHostDestroyed(
- RenderViewHost* render_view_host) {
- // Overidding the default behavior of RenderViewHostObserver which is to
- // delete this. In our case, we'll be deleted when the
- // UIThreadExtensionFunction that contains us goes away.
+ private:
+ // content::WebContentsObserver:
+ virtual void RenderViewDeleted(
+ content::RenderViewHost* render_view_host) OVERRIDE {
+ if (render_view_host != function_->render_view_host())
+ return;
- function_->SetRenderViewHost(NULL);
-}
+ function_->SetRenderViewHost(NULL);
+ }
-bool UIThreadExtensionFunction::RenderViewHostTracker::OnMessageReceived(
- const IPC::Message& message) {
- return function_->OnMessageReceivedFromRenderView(message);
-}
+ virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
+ return function_->OnMessageReceivedFromRenderView(message);
+ }
+
+ UIThreadExtensionFunction* function_;
+
+ DISALLOW_COPY_AND_ASSIGN(RenderViewHostTracker);
+};
ExtensionFunction::ExtensionFunction()
: request_id_(-1),
diff --git a/chrome/browser/extensions/extension_function.h b/chrome/browser/extensions/extension_function.h
index 8ffee2e63f..d26ae1e6e7 100644
--- a/chrome/browser/extensions/extension_function.h
+++ b/chrome/browser/extensions/extension_function.h
@@ -19,7 +19,6 @@
#include "chrome/browser/extensions/extension_info_map.h"
#include "chrome/common/extensions/extension.h"
#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/render_view_host_observer.h"
#include "content/public/common/console_message_level.h"
#include "ipc/ipc_message.h"
@@ -368,23 +367,7 @@ class UIThreadExtensionFunction : public ExtensionFunction {
Profile* profile_;
private:
- // Helper class to track the lifetime of ExtensionFunction's RenderViewHost
- // pointer and NULL it out when it dies. It also allows us to filter IPC
- // messages coming from the RenderViewHost.
- class RenderViewHostTracker : public content::RenderViewHostObserver {
- public:
- explicit RenderViewHostTracker(UIThreadExtensionFunction* function);
-
- private:
- // content::RenderViewHostObserver:
- virtual void RenderViewHostDestroyed(
- content::RenderViewHost* render_view_host) OVERRIDE;
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
-
- UIThreadExtensionFunction* function_;
-
- DISALLOW_COPY_AND_ASSIGN(RenderViewHostTracker);
- };
+ class RenderViewHostTracker;
virtual void Destruct() const OVERRIDE;
diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc
index 056dda4b8f..85961e3012 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.cc
+++ b/chrome/browser/extensions/extension_function_dispatcher.cc
@@ -18,6 +18,7 @@
#include "chrome/browser/extensions/extension_function_registry.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/extensions/extension_web_ui.h"
#include "chrome/browser/extensions/extensions_quota_service.h"
#include "chrome/browser/extensions/process_map.h"
@@ -31,7 +32,8 @@
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/render_view_host_observer.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/user_metrics.h"
#include "content/public/common/result_codes.h"
#include "ipc/ipc_message.h"
@@ -144,30 +146,34 @@ void IOThreadResponseCallback(
} // namespace
class ExtensionFunctionDispatcher::UIThreadResponseCallbackWrapper
- : public content::RenderViewHostObserver {
+ : public content::WebContentsObserver {
public:
UIThreadResponseCallbackWrapper(
const base::WeakPtr<ExtensionFunctionDispatcher>& dispatcher,
RenderViewHost* render_view_host)
- : content::RenderViewHostObserver(render_view_host),
+ : content::WebContentsObserver(
+ content::WebContents::FromRenderViewHost(render_view_host)),
dispatcher_(dispatcher),
+ render_view_host_(render_view_host),
weak_ptr_factory_(this) {
}
virtual ~UIThreadResponseCallbackWrapper() {
}
- // content::RenderViewHostObserver overrides.
- virtual void RenderViewHostDestroyed(
+ // content::WebContentsObserver overrides.
+ virtual void RenderViewDeleted(
RenderViewHost* render_view_host) OVERRIDE {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (render_view_host != render_view_host_)
+ return;
+
if (dispatcher_.get()) {
dispatcher_->ui_thread_response_callback_wrappers_
.erase(render_view_host);
}
- // This call will delete |this|.
- content::RenderViewHostObserver::RenderViewHostDestroyed(render_view_host);
+ delete this;
}
ExtensionFunction::ResponseCallback CreateCallback(int request_id) {
@@ -183,12 +189,13 @@ class ExtensionFunctionDispatcher::UIThreadResponseCallbackWrapper
const base::ListValue& results,
const std::string& error) {
CommonResponseCallback(
- render_view_host(), render_view_host()->GetRoutingID(),
- render_view_host()->GetProcess()->GetHandle(), request_id, type,
+ render_view_host_, render_view_host_->GetRoutingID(),
+ render_view_host_->GetProcess()->GetHandle(), request_id, type,
results, error);
}
base::WeakPtr<ExtensionFunctionDispatcher> dispatcher_;
+ content::RenderViewHost* render_view_host_;
base::WeakPtrFactory<UIThreadResponseCallbackWrapper> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(UIThreadResponseCallbackWrapper);
@@ -346,7 +353,8 @@ void ExtensionFunctionDispatcher::DispatchWithCallback(
function_ui->SetRenderViewHost(render_view_host);
function_ui->set_dispatcher(AsWeakPtr());
function_ui->set_profile(profile_);
- function->set_include_incognito(service->CanCrossIncognito(extension));
+ function->set_include_incognito(extension_util::CanCrossIncognito(extension,
+ service));
if (!CheckPermissions(function.get(), extension, params, callback))
return;
diff --git a/chrome/browser/extensions/extension_function_histogram_value.h b/chrome/browser/extensions/extension_function_histogram_value.h
index a62b014712..59f7aae3af 100644
--- a/chrome/browser/extensions/extension_function_histogram_value.h
+++ b/chrome/browser/extensions/extension_function_histogram_value.h
@@ -660,6 +660,19 @@ enum HistogramValue {
SOCKETS_TCP_CLOSE,
SOCKETS_TCP_GETINFO,
SOCKETS_TCP_GETSOCKETS,
+ NETWORKINGPRIVATE_GETENABLEDNETWORKTYPES,
+ NETWORKINGPRIVATE_ENABLENETWORKTYPE,
+ NETWORKINGPRIVATE_DISABLENETWORKTYPE,
+ SOCKETS_TCP_SERVER_CREATE,
+ SOCKETS_TCP_SERVER_UPDATE,
+ SOCKETS_TCP_SERVER_SETPAUSED,
+ SOCKETS_TCP_SERVER_LISTEN,
+ SOCKETS_TCP_SERVER_DISCONNECT,
+ SOCKETS_TCP_SERVER_CLOSE,
+ SOCKETS_TCP_SERVER_GETINFO,
+ SOCKETS_TCP_SERVER_GETSOCKETS,
+ SYSTEM_STORAGE_GETAVAILABLECAPACITY,
+ BROWSERACTION_OPEN_POPUP,
ENUM_BOUNDARY // Last entry: Add new entries above.
};
diff --git a/chrome/browser/extensions/extension_functional_browsertest.cc b/chrome/browser/extensions/extension_functional_browsertest.cc
index 19c7e0ad14..cf43c565a3 100644
--- a/chrome/browser/extensions/extension_functional_browsertest.cc
+++ b/chrome/browser/extensions/extension_functional_browsertest.cc
@@ -6,6 +6,7 @@
#include "chrome/browser/extensions/crx_installer.h"
#include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/test/base/ui_test_utils.h"
@@ -34,22 +35,19 @@ public:
installer->set_off_store_install_allow_reason(
extensions::CrxInstaller::OffStoreInstallAllowedInTest);
- content::WindowedNotificationObserver observer(
+ observer_->Watch(
chrome::NOTIFICATION_CRX_INSTALLER_DONE,
content::Source<extensions::CrxInstaller>(installer.get()));
- content::NotificationRegistrar registrar;
- registrar.Add(this, chrome::NOTIFICATION_CRX_INSTALLER_DONE,
- content::Source<extensions::CrxInstaller>(installer.get()));
installer->InstallCrx(path);
- observer.Wait();
+ observer_->Wait();
size_t num_after = service->extensions()->size();
EXPECT_EQ(num_before + 1, num_after);
extension_loaded_observer.Wait();
const Extension* extension = service->GetExtensionById(
- last_loaded_extension_id_, false);
+ last_loaded_extension_id(), false);
EXPECT_TRUE(extension != NULL);
}
};
@@ -64,8 +62,9 @@ IN_PROC_BROWSER_TEST_F(ExtensionFunctionalTest, TestAdblockExtensionCrash) {
ExtensionService* service = profile()->GetExtensionService();
// Verify that the extension is enabled and allowed in incognito
// is disabled.
- EXPECT_TRUE(service->IsExtensionEnabled(last_loaded_extension_id_));
- EXPECT_FALSE(service->IsIncognitoEnabled(last_loaded_extension_id_));
+ EXPECT_TRUE(service->IsExtensionEnabled(last_loaded_extension_id()));
+ EXPECT_FALSE(
+ extension_util::IsIncognitoEnabled(last_loaded_extension_id(), service));
}
IN_PROC_BROWSER_TEST_F(ExtensionFunctionalTest, TestSetExtensionsState) {
@@ -73,24 +72,30 @@ IN_PROC_BROWSER_TEST_F(ExtensionFunctionalTest, TestSetExtensionsState) {
InstallExtensionSilently(service, "google_talk.crx");
// Disable the extension and verify.
- service->SetIsIncognitoEnabled(last_loaded_extension_id_, false);
- service->DisableExtension(last_loaded_extension_id_,
+ extension_util::SetIsIncognitoEnabled(
+ last_loaded_extension_id(), service, false);
+ service->DisableExtension(last_loaded_extension_id(),
Extension::DISABLE_USER_ACTION);
- EXPECT_FALSE(service->IsExtensionEnabled(last_loaded_extension_id_));
+ EXPECT_FALSE(service->IsExtensionEnabled(last_loaded_extension_id()));
// Enable the extension and verify.
- service->SetIsIncognitoEnabled(last_loaded_extension_id_, false);
- service->EnableExtension(last_loaded_extension_id_);
- EXPECT_TRUE(service->IsExtensionEnabled(last_loaded_extension_id_));
+ extension_util::SetIsIncognitoEnabled(
+ last_loaded_extension_id(), service, false);
+ service->EnableExtension(last_loaded_extension_id());
+ EXPECT_TRUE(service->IsExtensionEnabled(last_loaded_extension_id()));
// Allow extension in incognito mode and verify.
- service->EnableExtension(last_loaded_extension_id_);
- service->SetIsIncognitoEnabled(last_loaded_extension_id_, true);
- EXPECT_TRUE(service->IsIncognitoEnabled(last_loaded_extension_id_));
+ service->EnableExtension(last_loaded_extension_id());
+ extension_util::SetIsIncognitoEnabled(
+ last_loaded_extension_id(), service, true);
+ EXPECT_TRUE(
+ extension_util::IsIncognitoEnabled(last_loaded_extension_id(), service));
// Disallow extension in incognito mode and verify.
- service->EnableExtension(last_loaded_extension_id_);
- service->SetIsIncognitoEnabled(last_loaded_extension_id_, false);
- EXPECT_FALSE(service->IsIncognitoEnabled(last_loaded_extension_id_));
+ service->EnableExtension(last_loaded_extension_id());
+ extension_util::SetIsIncognitoEnabled(
+ last_loaded_extension_id(), service, false);
+ EXPECT_FALSE(
+ extension_util::IsIncognitoEnabled(last_loaded_extension_id(), service));
}
} // namespace extensions
diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc
index 59dd814429..b859c41797 100644
--- a/chrome/browser/extensions/extension_host.cc
+++ b/chrome/browser/extensions/extension_host.cc
@@ -22,6 +22,7 @@
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/extensions/extension_tab_util.h"
+#include "chrome/browser/extensions/extension_web_contents_observer.h"
#include "chrome/browser/extensions/window_controller.h"
#include "chrome/browser/file_select_helper.h"
#include "chrome/browser/media/media_capture_devices_dispatcher.h"
@@ -155,6 +156,7 @@ ExtensionHost::ExtensionHost(const Extension* extension,
host_contents_->SetDelegate(this);
SetViewType(host_contents_.get(), host_type);
+ ExtensionWebContentsObserver::CreateForWebContents(host_contents());
PrefsTabHelper::CreateForWebContents(host_contents());
render_view_host_ = host_contents_->GetRenderViewHost();
diff --git a/chrome/browser/extensions/extension_install_prompt.cc b/chrome/browser/extensions/extension_install_prompt.cc
index ae201f1034..66c7ab9f98 100644
--- a/chrome/browser/extensions/extension_install_prompt.cc
+++ b/chrome/browser/extensions/extension_install_prompt.cc
@@ -36,6 +36,7 @@
#include "extensions/common/extension_resource.h"
#include "extensions/common/manifest.h"
#include "extensions/common/manifest_constants.h"
+#include "extensions/common/permissions/permission_message_provider.h"
#include "extensions/common/url_pattern.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
@@ -801,9 +802,11 @@ void ExtensionInstallPrompt::ShowConfirmation() {
Manifest::Type extension_type = extension_ ?
extension_->GetType() : Manifest::TYPE_UNKNOWN;
prompt_.SetPermissions(
- permissions_->GetWarningMessages(extension_type));
+ extensions::PermissionMessageProvider::Get()->
+ GetWarningMessages(permissions_, extension_type));
prompt_.SetPermissionsDetails(
- permissions_->GetWarningMessagesDetails(extension_type));
+ extensions::PermissionMessageProvider::Get()->
+ GetWarningMessagesDetails(permissions_, extension_type));
}
switch (prompt_.type()) {
diff --git a/chrome/browser/extensions/extension_install_ui_browsertest.cc b/chrome/browser/extensions/extension_install_ui_browsertest.cc
index 6a1aac8728..615584e654 100644
--- a/chrome/browser/extensions/extension_install_ui_browsertest.cc
+++ b/chrome/browser/extensions/extension_install_ui_browsertest.cc
@@ -186,7 +186,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionInstallUIBrowserTest,
}
}
-class NewTabUISortingBrowserTest : public ExtensionInstallUIBrowserTest {
+class NewTabUISortingBrowserTest : public ExtensionInstallUIBrowserTest,
+ public content::NotificationObserver {
public:
NewTabUISortingBrowserTest() {}
@@ -194,7 +195,7 @@ class NewTabUISortingBrowserTest : public ExtensionInstallUIBrowserTest {
const content::NotificationSource& source,
const content::NotificationDetails& details) OVERRIDE {
if (type != chrome::NOTIFICATION_EXTENSION_LAUNCHER_REORDERED) {
- ExtensionInstallUIBrowserTest::Observe(type, source, details);
+ observer_->Observe(type, source, details);
return;
}
const std::string* id = content::Details<const std::string>(details).ptr();
diff --git a/chrome/browser/extensions/extension_keybinding_apitest_new.cc b/chrome/browser/extensions/extension_keybinding_apitest_new.cc
deleted file mode 100644
index 848a799b49..0000000000
--- a/chrome/browser/extensions/extension_keybinding_apitest_new.cc
+++ /dev/null
@@ -1,202 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/extensions/active_tab_permission_granter.h"
-#include "chrome/browser/extensions/browser_action_test_util.h"
-#include "chrome/browser/extensions/extension_action.h"
-#include "chrome/browser/extensions/extension_action_manager.h"
-#include "chrome/browser/extensions/extension_apitest.h"
-#include "chrome/browser/extensions/tab_helper.h"
-#include "chrome/browser/sessions/session_tab_helper.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/test/base/interactive_test_utils.h"
-#include "chrome/test/base/ui_test_utils.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/test/browser_test_utils.h"
-
-using content::WebContents;
-
-namespace extensions {
-
-class CommandsApiTest : public ExtensionApiTest {
- public:
- CommandsApiTest() {}
- virtual ~CommandsApiTest() {}
-
- protected:
- BrowserActionTestUtil GetBrowserActionsBar() {
- return BrowserActionTestUtil(browser());
- }
-};
-
-class ScriptBadgesCommandsApiTest : public ExtensionApiTest {
- public:
- ScriptBadgesCommandsApiTest() {
- // We cannot add this to CommandsApiTest because then PageActions get
- // treated like BrowserActions and the PageAction test starts failing.
- CommandLine::ForCurrentProcess()->AppendSwitchASCII(
- switches::kScriptBadges, "1");
- }
- virtual ~ScriptBadgesCommandsApiTest() {}
-
- bool IsGrantedForTab(const Extension* extension,
- const content::WebContents* web_contents) {
- return PermissionsData::HasAPIPermissionForTab(
- extension,
- SessionID::IdForTab(web_contents),
- APIPermission::kTab);
- }
-};
-
-// Test the basic functionality of the Keybinding API:
-// - That pressing the shortcut keys should perform actions (activate the
-// browser action or send an event).
-// - Note: Page action keybindings are tested in PageAction test below.
-// - The shortcut keys taken by one extension are not overwritten by the last
-// installed extension.
-IN_PROC_BROWSER_TEST_F(CommandsApiTest, Basic) {
- ASSERT_TRUE(test_server()->Start());
- ASSERT_TRUE(RunExtensionTest("keybinding/basics")) << message_;
- const Extension* extension = GetSingleLoadedExtension();
- ASSERT_TRUE(extension) << message_;
-
- // Load this extension, which uses the same keybindings but sets the page
- // to different colors. This is so we can see that it doesn't interfere. We
- // don't test this extension in any other way (it should otherwise be
- // immaterial to this test).
- ASSERT_TRUE(RunExtensionTest("keybinding/conflicting")) << message_;
-
- // Test that there are two browser actions in the toolbar.
- ASSERT_EQ(2, GetBrowserActionsBar().NumberOfBrowserActions());
-
- ui_test_utils::NavigateToURL(browser(),
- test_server()->GetURL("files/extensions/test_file.txt"));
-
- // activeTab shouldn't have been granted yet.
- WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
- ASSERT_TRUE(tab);
-
- EXPECT_FALSE(IsGrantedForTab(extension, tab));
-
- // Activate the shortcut (Ctrl+Shift+F).
- ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
- browser(), ui::VKEY_F, true, true, false, false));
-
- // activeTab should now be granted.
- EXPECT_TRUE(IsGrantedForTab(extension, tab));
-
- // Verify the command worked.
- bool result = false;
- ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
- tab,
- "setInterval(function(){"
- " if(document.body.bgColor == 'red'){"
- " window.domAutomationController.send(true)}}, 100)",
- &result));
- ASSERT_TRUE(result);
-
- // Activate the shortcut (Ctrl+Shift+Y).
- ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
- browser(), ui::VKEY_Y, true, true, false, false));
-
- result = false;
- ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
- tab,
- "setInterval(function(){"
- " if(document.body.bgColor == 'blue'){"
- " window.domAutomationController.send(true)}}, 100)",
- &result));
- ASSERT_TRUE(result);
-}
-
-// Flaky on linux and chromeos, http://crbug.com/165825
-#if defined(OS_MACOSX) || defined(OS_WIN)
-#define MAYBE_PageAction PageAction
-#else
-#define MAYBE_PageAction DISABLED_PageAction
-#endif
-IN_PROC_BROWSER_TEST_F(CommandsApiTest, MAYBE_PageAction) {
- ASSERT_TRUE(test_server()->Start());
- ASSERT_TRUE(RunExtensionTest("keybinding/page_action")) << message_;
- const Extension* extension = GetSingleLoadedExtension();
- ASSERT_TRUE(extension) << message_;
-
- {
- // Load a page, the extension will detect the navigation and request to show
- // the page action icon.
- ResultCatcher catcher;
- ui_test_utils::NavigateToURL(browser(),
- test_server()->GetURL("files/extensions/test_file.txt"));
- ASSERT_TRUE(catcher.GetNextResult());
- }
-
- // Make sure it appears and is the right one.
- ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(1));
- int tab_id = SessionTabHelper::FromWebContents(
- browser()->tab_strip_model()->GetActiveWebContents())->session_id().id();
- ExtensionAction* action =
- ExtensionActionManager::Get(browser()->profile())->
- GetPageAction(*extension);
- ASSERT_TRUE(action);
- EXPECT_EQ("Make this page red", action->GetTitle(tab_id));
-
- // Activate the shortcut (Alt+Shift+F).
- ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
- browser(), ui::VKEY_F, false, true, true, false));
-
- // Verify the command worked (the page action turns the page red).
- WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
- bool result = false;
- ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
- tab,
- "setInterval(function(){"
- " if(document.body.bgColor == 'red'){"
- " window.domAutomationController.send(true)}}, 100)",
- &result));
- ASSERT_TRUE(result);
-}
-
-// Checked-in in a disabled state, because the necessary functionality to
-// automatically verify that the test works hasn't been implemented for the
-// script badges yet (see http://crbug.com/140016). The test results, can be
-// verified manually by running the test and verifying that the synthesized
-// popup for script badges appear. When bug 140016 has been fixed, the popup
-// code can signal to the test that the test passed.
-// TODO(finnur): Enable this test once the bug is fixed.
-IN_PROC_BROWSER_TEST_F(ScriptBadgesCommandsApiTest, DISABLED_ScriptBadge) {
- ASSERT_TRUE(test_server()->Start());
- ASSERT_TRUE(RunExtensionTest("keybinding/script_badge")) << message_;
- const Extension* extension = GetSingleLoadedExtension();
- ASSERT_TRUE(extension) << message_;
-
- {
- ResultCatcher catcher;
- // Tell the extension to update the script badge state.
- ui_test_utils::NavigateToURL(
- browser(), GURL(extension->GetResourceURL("show.html")));
- ASSERT_TRUE(catcher.GetNextResult());
- }
-
- {
- ResultCatcher catcher;
- // Activate the shortcut (Ctrl+Shift+F).
- ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
- browser(), ui::VKEY_F, true, true, false, false));
- ASSERT_TRUE(catcher.GetNextResult());
- }
-}
-
-// This test validates that the getAll query API function returns registered
-// commands as well as synthesized ones and that inactive commands (like the
-// synthesized ones are in nature) have no shortcuts.
-IN_PROC_BROWSER_TEST_F(CommandsApiTest, SynthesizedCommand) {
- ASSERT_TRUE(test_server()->Start());
- ASSERT_TRUE(RunExtensionTest("keybinding/synthesized")) << message_;
-}
-
-} // namespace extensions
diff --git a/chrome/browser/extensions/extension_messages_apitest.cc b/chrome/browser/extensions/extension_messages_apitest.cc
index 712b5ed606..131a743dcb 100644
--- a/chrome/browser/extensions/extension_messages_apitest.cc
+++ b/chrome/browser/extensions/extension_messages_apitest.cc
@@ -13,6 +13,7 @@
#include "base/synchronization/waitable_event.h"
#include "base/values.h"
#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/extensions/api/messaging/incognito_connectability.h"
#include "chrome/browser/extensions/event_router.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_prefs.h"
@@ -586,26 +587,74 @@ IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
CanConnectAndSendMessages(not_connectable->id()));
}
-// Tests connection from incognito tabs. Spanning mode only.
+// Tests connection from incognito tabs when the user denies the connection
+// request. Spanning mode only.
//
// TODO(kalman): ensure that we exercise split vs spanning incognito logic
// somewhere. This is a test that should be shared with the content script logic
// so it's not really our specific concern for web connectable.
-IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest, FromIncognito) {
+//
+// TODO(kalman): test messages from incognito extensions too.
+IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest, FromIncognitoDeny) {
InitializeTestServer();
const Extension* chromium_connectable = LoadChromiumConnectableExtension();
+ const std::string& id = chromium_connectable->id();
Browser* incognito_browser = ui_test_utils::OpenURLOffTheRecord(
profile()->GetOffTheRecordProfile(),
chromium_org_url());
- // No connection because incognito enabled hasn't been set.
+ // No connection because incognito-enabled hasn't been set for the extension,
+ // and the user denied our interactive request.
+ {
+ IncognitoConnectability::ScopedAlertTracker alert_tracker(
+ IncognitoConnectability::ScopedAlertTracker::ALWAYS_DENY);
+
+ EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR,
+ CanConnectAndSendMessages(incognito_browser, id));
+ EXPECT_EQ(1, alert_tracker.GetAndResetAlertCount());
+
+ // Try again. User has already denied.
+ EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR,
+ CanConnectAndSendMessages(incognito_browser, id));
+ EXPECT_EQ(0, alert_tracker.GetAndResetAlertCount());
+ }
+
+ // Allowing the extension in incognito mode will bypass the deny.
+ ExtensionPrefs::Get(profile())->SetIsIncognitoEnabled(id, true);
+ EXPECT_EQ(OK, CanConnectAndSendMessages(incognito_browser, id));
+}
+
+// Tests connection from incognito tabs when the user accepts the connection
+// request. Spanning mode only.
+//
+// TODO(kalman): see comment above about split mode.
+IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest, FromIncognitoAllow) {
+ InitializeTestServer();
+
+ const Extension* chromium_connectable = LoadChromiumConnectableExtension();
const std::string& id = chromium_connectable->id();
- EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR,
- CanConnectAndSendMessages(incognito_browser, id));
- // Then yes.
+ Browser* incognito_browser = ui_test_utils::OpenURLOffTheRecord(
+ profile()->GetOffTheRecordProfile(),
+ chromium_org_url());
+
+ // Connection allowed even with incognito disabled, because the user accepted
+ // the interactive request.
+ {
+ IncognitoConnectability::ScopedAlertTracker alert_tracker(
+ IncognitoConnectability::ScopedAlertTracker::ALWAYS_ALLOW);
+
+ EXPECT_EQ(OK, CanConnectAndSendMessages(incognito_browser, id));
+ EXPECT_EQ(1, alert_tracker.GetAndResetAlertCount());
+
+ // Try again. User has already allowed.
+ EXPECT_EQ(OK, CanConnectAndSendMessages(incognito_browser, id));
+ EXPECT_EQ(0, alert_tracker.GetAndResetAlertCount());
+ }
+
+ // Allowing the extension in incognito mode will continue to allow.
ExtensionPrefs::Get(profile())->SetIsIncognitoEnabled(id, true);
EXPECT_EQ(OK, CanConnectAndSendMessages(incognito_browser, id));
}
diff --git a/chrome/browser/extensions/extension_nacl_browsertest.cc b/chrome/browser/extensions/extension_nacl_browsertest.cc
index df151de798..ba724d55e9 100644
--- a/chrome/browser/extensions/extension_nacl_browsertest.cc
+++ b/chrome/browser/extensions/extension_nacl_browsertest.cc
@@ -77,7 +77,7 @@ class NaClExtensionTest : public ExtensionBrowserTest {
case INSTALL_TYPE_FROM_WEBSTORE:
// Install native_client.crx from the webstore.
if (InstallExtensionFromWebstore(file_path, 1)) {
- extension = service->GetExtensionById(last_loaded_extension_id_,
+ extension = service->GetExtensionById(last_loaded_extension_id(),
false);
}
break;
@@ -85,7 +85,7 @@ class NaClExtensionTest : public ExtensionBrowserTest {
case INSTALL_TYPE_NON_WEBSTORE:
// Install native_client.crx but not from the webstore.
if (ExtensionBrowserTest::InstallExtension(file_path, 1)) {
- extension = service->GetExtensionById(last_loaded_extension_id_,
+ extension = service->GetExtensionById(last_loaded_extension_id(),
false);
}
break;
diff --git a/chrome/browser/extensions/extension_prefs.cc b/chrome/browser/extensions/extension_prefs.cc
index 751d5361b5..cc04550b05 100644
--- a/chrome/browser/extensions/extension_prefs.cc
+++ b/chrome/browser/extensions/extension_prefs.cc
@@ -1001,7 +1001,7 @@ bool ExtensionPrefs::IsActive(const std::string& extension_id) {
return is_active;
}
-bool ExtensionPrefs::IsIncognitoEnabled(const std::string& extension_id) {
+bool ExtensionPrefs::IsIncognitoEnabled(const std::string& extension_id) const {
return ReadPrefAsBooleanAndReturn(extension_id, kPrefIncognitoEnabled);
}
@@ -1011,7 +1011,7 @@ void ExtensionPrefs::SetIsIncognitoEnabled(const std::string& extension_id,
new base::FundamentalValue(enabled));
}
-bool ExtensionPrefs::AllowFileAccess(const std::string& extension_id) {
+bool ExtensionPrefs::AllowFileAccess(const std::string& extension_id) const {
return ReadPrefAsBooleanAndReturn(extension_id, kPrefAllowFileAccess);
}
diff --git a/chrome/browser/extensions/extension_prefs.h b/chrome/browser/extensions/extension_prefs.h
index 22a00b154a..a079c0eadf 100644
--- a/chrome/browser/extensions/extension_prefs.h
+++ b/chrome/browser/extensions/extension_prefs.h
@@ -369,14 +369,17 @@ class ExtensionPrefs : public ExtensionScopedPrefs,
// Returns true if the user enabled this extension to be loaded in incognito
// mode.
//
- // IMPORTANT: you probably want to use ExtensionService::IsIncognitoEnabled
+ // IMPORTANT: you probably want to use extension_utils::IsIncognitoEnabled
// instead of this method.
- bool IsIncognitoEnabled(const std::string& extension_id);
+ bool IsIncognitoEnabled(const std::string& extension_id) const;
void SetIsIncognitoEnabled(const std::string& extension_id, bool enabled);
// Returns true if the user has chosen to allow this extension to inject
// scripts into pages with file URLs.
- bool AllowFileAccess(const std::string& extension_id);
+ //
+ // IMPORTANT: you probably want to use extension_utils::AllowFileAccess
+ // instead of this method.
+ bool AllowFileAccess(const std::string& extension_id) const;
void SetAllowFileAccess(const std::string& extension_id, bool allow);
bool HasAllowFileAccessSetting(const std::string& extension_id) const;
diff --git a/chrome/browser/extensions/extension_process_manager.cc b/chrome/browser/extensions/extension_process_manager.cc
index b86df25e4b..a4b2374301 100644
--- a/chrome/browser/extensions/extension_process_manager.cc
+++ b/chrome/browser/extensions/extension_process_manager.cc
@@ -20,6 +20,7 @@
#include "chrome/browser/extensions/extension_info_map.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/browser.h"
@@ -40,6 +41,8 @@
#include "content/public/browser/site_instance.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/browser/web_contents_user_data.h"
#include "content/public/common/renderer_preferences.h"
#include "extensions/browser/view_type_utils.h"
@@ -55,6 +58,9 @@ using extensions::BackgroundManifestHandler;
using extensions::Extension;
using extensions::ExtensionHost;
+class RenderViewHostDestructionObserver;
+DEFINE_WEB_CONTENTS_USER_DATA_KEY(RenderViewHostDestructionObserver);
+
namespace {
std::string GetExtensionID(RenderViewHost* render_view_host) {
@@ -111,6 +117,33 @@ static void CreateBackgroundHostForExtensionLoad(
} // namespace
+class RenderViewHostDestructionObserver
+ : public content::WebContentsObserver,
+ public content::WebContentsUserData<RenderViewHostDestructionObserver> {
+ public:
+ virtual ~RenderViewHostDestructionObserver() {}
+
+ private:
+ explicit RenderViewHostDestructionObserver(WebContents* web_contents)
+ : WebContentsObserver(web_contents) {
+ Profile* profile =
+ Profile::FromBrowserContext(web_contents->GetBrowserContext());
+ process_manager_ =
+ extensions::ExtensionSystem::Get(profile)->process_manager();
+ }
+
+ friend class content::WebContentsUserData<RenderViewHostDestructionObserver>;
+
+ // content::WebContentsObserver overrides.
+ virtual void RenderViewDeleted(RenderViewHost* render_view_host) OVERRIDE {
+ process_manager_->UnregisterRenderViewHost(render_view_host);
+ }
+
+ ExtensionProcessManager* process_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(RenderViewHostDestructionObserver);
+};
+
struct ExtensionProcessManager::BackgroundPageData {
// The count of things keeping the lazy background page alive.
int lazy_keepalive_count;
@@ -654,6 +687,11 @@ void ExtensionProcessManager::Observe(
RVHPair* switched_details = content::Details<RVHPair>(details).ptr();
if (switched_details->first)
UnregisterRenderViewHost(switched_details->first);
+
+ // The above will unregister a RVH when it gets swapped out with a new
+ // one. However we need to watch the WebContents to know when a RVH is
+ // deleted because the WebContents has gone away.
+ RenderViewHostDestructionObserver::CreateForWebContents(contents);
RegisterRenderViewHost(switched_details->second);
break;
}
@@ -916,7 +954,7 @@ bool IncognitoExtensionProcessManager::IsIncognitoEnabled(
const Extension* extension) {
// Keep in sync with duplicate in extension_info_map.cc.
ExtensionService* service = GetProfile()->GetExtensionService();
- return service && service->IsIncognitoEnabled(extension->id());
+ return extension_util::IsIncognitoEnabled(extension->id(), service);
}
void IncognitoExtensionProcessManager::Observe(
diff --git a/chrome/browser/extensions/extension_renderer_state.cc b/chrome/browser/extensions/extension_renderer_state.cc
index 2075d30773..34c998134e 100644
--- a/chrome/browser/extensions/extension_renderer_state.cc
+++ b/chrome/browser/extensions/extension_renderer_state.cc
@@ -17,8 +17,8 @@
#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/render_view_host_observer.h"
#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
using content::BrowserThread;
using content::RenderProcessHost;
@@ -30,13 +30,16 @@ using content::WebContents;
//
class ExtensionRendererState::RenderViewHostObserver
- : public content::RenderViewHostObserver {
+ : public content::WebContentsObserver {
public:
- explicit RenderViewHostObserver(content::RenderViewHost* host)
- : content::RenderViewHostObserver(host) {
+ RenderViewHostObserver(RenderViewHost* host, WebContents* web_contents)
+ : content::WebContentsObserver(web_contents),
+ render_view_host_(host) {
}
- virtual void RenderViewHostDestroyed(content::RenderViewHost* host) OVERRIDE {
+ virtual void RenderViewDeleted(content::RenderViewHost* host) OVERRIDE {
+ if (host != render_view_host_)
+ return;
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(
@@ -48,6 +51,8 @@ class ExtensionRendererState::RenderViewHostObserver
}
private:
+ RenderViewHost* render_view_host_;
+
DISALLOW_COPY_AND_ASSIGN(RenderViewHostObserver);
};
@@ -111,7 +116,7 @@ void ExtensionRendererState::TabObserver::Observe(
session_tab_helper->window_id().id()));
// The observer deletes itself.
- new ExtensionRendererState::RenderViewHostObserver(host);
+ new ExtensionRendererState::RenderViewHostObserver(host, web_contents);
break;
}
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index 18bcbeb7fc..c560220f40 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -50,6 +50,7 @@
#include "chrome/browser/extensions/extension_special_storage_policy.h"
#include "chrome/browser/extensions/extension_sync_data.h"
#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/extensions/external_install_ui.h"
#include "chrome/browser/extensions/external_provider_impl.h"
#include "chrome/browser/extensions/external_provider_interface.h"
@@ -98,6 +99,7 @@
#include "extensions/common/error_utils.h"
#include "extensions/common/manifest.h"
#include "extensions/common/manifest_constants.h"
+#include "extensions/common/permissions/permission_message_provider.h"
#include "grit/generated_resources.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "sync/api/sync_change.h"
@@ -284,28 +286,6 @@ bool ExtensionService::IsInstalledApp(const GURL& url) const {
return !!GetInstalledApp(url);
}
-const Extension* ExtensionService::GetIsolatedAppForRenderer(
- int renderer_child_id) const {
- std::set<std::string> extension_ids =
- process_map_.GetExtensionsInProcess(renderer_child_id);
- // All apps in one process share the same partition.
- // It is only possible for the app to have isolated storage
- // if there is only 1 app in the process.
- if (extension_ids.size() != 1)
- return NULL;
-
- const extensions::Extension* extension =
- extensions_.GetByID(*(extension_ids.begin()));
- // We still need to check if the extension has isolated storage,
- // because it's common for there to be one extension in a process
- // without isolated storage.
- if (extension &&
- extensions::AppIsolationInfo::HasIsolatedStorage(extension))
- return extension;
-
- return NULL;
-}
-
// static
// This function is used to implement the command-line switch
// --uninstall-extension, and to uninstall an extension via sync. The LOG
@@ -1250,6 +1230,10 @@ extensions::ExtensionPrefs* ExtensionService::extension_prefs() {
return extension_prefs_;
}
+const extensions::ExtensionPrefs* ExtensionService::extension_prefs() const {
+ return extension_prefs_;
+}
+
extensions::SettingsFrontend* ExtensionService::settings_frontend() {
return settings_frontend_.get();
}
@@ -1415,9 +1399,10 @@ syncer::SyncError ExtensionService::ProcessSyncChanges(
extensions::ExtensionSyncData ExtensionService::GetExtensionSyncData(
const Extension& extension) const {
- return extensions::ExtensionSyncData(extension,
- IsExtensionEnabled(extension.id()),
- IsIncognitoEnabled(extension.id()));
+ return extensions::ExtensionSyncData(
+ extension,
+ IsExtensionEnabled(extension.id()),
+ extension_util::IsIncognitoEnabled(extension.id(), this));
}
extensions::AppSyncData ExtensionService::GetAppSyncData(
@@ -1425,7 +1410,7 @@ extensions::AppSyncData ExtensionService::GetAppSyncData(
return extensions::AppSyncData(
extension,
IsExtensionEnabled(extension.id()),
- IsIncognitoEnabled(extension.id()),
+ extension_util::IsIncognitoEnabled(extension.id(), this),
extension_prefs_->extension_sorting()->GetAppLaunchOrdinal(
extension.id()),
extension_prefs_->extension_sorting()->GetPageOrdinal(extension.id()));
@@ -1570,7 +1555,8 @@ bool ExtensionService::ProcessExtensionSyncDataHelper(
bool extension_installed = (extension != NULL);
int result = extension ?
extension->version()->CompareTo(extension_sync_data.version()) : 0;
- SetIsIncognitoEnabled(id, extension_sync_data.incognito_enabled());
+ extension_util::SetIsIncognitoEnabled(
+ id, this, extension_sync_data.incognito_enabled());
extension = NULL; // No longer safe to use.
if (extension_installed) {
@@ -1607,79 +1593,6 @@ bool ExtensionService::ProcessExtensionSyncDataHelper(
return true;
}
-bool ExtensionService::IsIncognitoEnabled(
- const std::string& extension_id) const {
- const Extension* extension = GetInstalledExtension(extension_id);
- if (extension && !extension->can_be_incognito_enabled())
- return false;
- // If this is an existing component extension we always allow it to
- // work in incognito mode.
- if (extension && extension->location() == Manifest::COMPONENT)
- return true;
- if (extension && extension->force_incognito_enabled())
- return true;
-
- // Check the prefs.
- return extension_prefs_->IsIncognitoEnabled(extension_id);
-}
-
-void ExtensionService::SetIsIncognitoEnabled(
- const std::string& extension_id, bool enabled) {
- const Extension* extension = GetInstalledExtension(extension_id);
- if (extension && !extension->can_be_incognito_enabled())
- return;
- if (extension && extension->location() == Manifest::COMPONENT) {
- // This shouldn't be called for component extensions unless they are
- // syncable.
- DCHECK(extensions::sync_helper::IsSyncable(extension));
-
- // If we are here, make sure the we aren't trying to change the value.
- DCHECK_EQ(enabled, IsIncognitoEnabled(extension_id));
-
- return;
- }
-
- // Broadcast unloaded and loaded events to update browser state. Only bother
- // if the value changed and the extension is actually enabled, since there is
- // no UI otherwise.
- bool old_enabled = extension_prefs_->IsIncognitoEnabled(extension_id);
- if (enabled == old_enabled)
- return;
-
- extension_prefs_->SetIsIncognitoEnabled(extension_id, enabled);
-
- bool extension_is_enabled = extensions_.Contains(extension_id);
-
- // When we reload the extension the ID may be invalidated if we've passed it
- // by const ref everywhere. Make a copy to be safe.
- std::string id = extension_id;
- if (extension_is_enabled)
- ReloadExtension(id);
-
- // Reloading the extension invalidates the |extension| pointer.
- extension = GetInstalledExtension(id);
- if (extension)
- SyncExtensionChangeIfNeeded(*extension);
-}
-
-bool ExtensionService::CanCrossIncognito(const Extension* extension) const {
- // We allow the extension to see events and data from another profile iff it
- // uses "spanning" behavior and it has incognito access. "split" mode
- // extensions only see events for a matching profile.
- CHECK(extension);
- return IsIncognitoEnabled(extension->id()) &&
- !extensions::IncognitoInfo::IsSplitMode(extension);
-}
-
-bool ExtensionService::CanLoadInIncognito(const Extension* extension) const {
- if (extension->is_hosted_app())
- return true;
- // Packaged apps and regular extensions need to be enabled specifically for
- // incognito (and split mode should be set).
- return extensions::IncognitoInfo::IsSplitMode(extension) &&
- IsIncognitoEnabled(extension->id());
-}
-
void ExtensionService::OnExtensionMoved(
const std::string& moved_extension_id,
const std::string& predecessor_extension_id,
@@ -1694,27 +1607,6 @@ void ExtensionService::OnExtensionMoved(
SyncExtensionChangeIfNeeded(*extension);
}
-bool ExtensionService::AllowFileAccess(const Extension* extension) const {
- return (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableExtensionsFileAccessCheck) ||
- extension_prefs_->AllowFileAccess(extension->id()));
-}
-
-void ExtensionService::SetAllowFileAccess(const Extension* extension,
- bool allow) {
- // Reload to update browser state. Only bother if the value changed and the
- // extension is actually enabled, since there is no UI otherwise.
- bool old_allow = AllowFileAccess(extension);
- if (allow == old_allow)
- return;
-
- extension_prefs_->SetAllowFileAccess(extension->id(), allow);
-
- bool extension_is_enabled = extensions_.Contains(extension->id());
- if (extension_is_enabled)
- ReloadExtension(extension->id());
-}
-
// Some extensions will autoupdate themselves externally from Chrome. These
// are typically part of some larger client application package. To support
// these, the extension will register its location in the the preferences file
@@ -2323,8 +2215,11 @@ void ExtensionService::CheckPermissionsIncrease(const Extension* extension,
// that requires the user's approval. This could occur because the browser
// upgraded and recognized additional privileges, or an extension upgrades
// to a version that requires additional privileges.
- is_privilege_increase = granted_permissions->HasLessPrivilegesThan(
- extension->GetActivePermissions().get(), extension->GetType());
+ is_privilege_increase =
+ extensions::PermissionMessageProvider::Get()->IsPrivilegeIncrease(
+ granted_permissions,
+ extension->GetActivePermissions().get(),
+ extension->GetType());
}
if (is_extension_installed) {
@@ -2384,12 +2279,14 @@ void ExtensionService::UpdateActiveExtensionsInCrashReporter() {
crash_keys::SetActiveExtensions(extension_ids);
}
-ExtensionService::ImportStatus ExtensionService::SatisfyImports(
- const Extension* extension) {
+ExtensionService::ImportStatus ExtensionService::CheckImports(
+ const extensions::Extension* extension,
+ std::list<SharedModuleInfo::ImportInfo>* missing_modules,
+ std::list<SharedModuleInfo::ImportInfo>* outdated_modules) {
+ DCHECK(extension);
+ DCHECK(missing_modules && missing_modules->empty());
+ DCHECK(outdated_modules && outdated_modules->empty());
ImportStatus status = IMPORT_STATUS_OK;
- std::vector<std::string> pending;
- // TODO(elijahtaylor): Message the user if there is a failure that is
- // unrecoverable.
if (SharedModuleInfo::ImportsModules(extension)) {
const std::vector<SharedModuleInfo::ImportInfo>& imports =
SharedModuleInfo::GetImports(extension);
@@ -2401,7 +2298,7 @@ ExtensionService::ImportStatus ExtensionService::SatisfyImports(
if (!imported_module) {
if (extension->from_webstore()) {
status = IMPORT_STATUS_UNSATISFIED;
- pending.push_back(i->extension_id);
+ missing_modules->push_back(*i);
} else {
return IMPORT_STATUS_UNRECOVERABLE;
}
@@ -2410,6 +2307,7 @@ ExtensionService::ImportStatus ExtensionService::SatisfyImports(
} else if (version_required.IsValid() &&
imported_module->version()->CompareTo(version_required) < 0) {
if (imported_module->from_webstore()) {
+ outdated_modules->push_back(*i);
status = IMPORT_STATUS_UNSATISFIED;
} else {
return IMPORT_STATUS_UNRECOVERABLE;
@@ -2417,12 +2315,21 @@ ExtensionService::ImportStatus ExtensionService::SatisfyImports(
}
}
}
+ return status;
+}
+
+ExtensionService::ImportStatus ExtensionService::SatisfyImports(
+ const Extension* extension) {
+ std::list<SharedModuleInfo::ImportInfo> noinstalled;
+ std::list<SharedModuleInfo::ImportInfo> outdated;
+ ImportStatus status = CheckImports(extension, &noinstalled, &outdated);
+ if (status == IMPORT_STATUS_UNRECOVERABLE)
+ return status;
if (status == IMPORT_STATUS_UNSATISFIED) {
- for (std::vector<std::string>::const_iterator iter = pending.begin();
- iter != pending.end();
- ++iter) {
+ std::list<SharedModuleInfo::ImportInfo>::const_iterator iter;
+ for (iter = noinstalled.begin(); iter != noinstalled.end(); ++iter) {
pending_extension_manager()->AddFromExtensionImport(
- *iter,
+ iter->extension_id,
extension_urls::GetWebstoreUpdateUrl(),
IsSharedModule);
}
diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h
index ee26e92028..e9e7cba230 100644
--- a/chrome/browser/extensions/extension_service.h
+++ b/chrome/browser/extensions/extension_service.h
@@ -5,6 +5,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_SERVICE_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_SERVICE_H_
+#include <list>
#include <map>
#include <set>
#include <string>
@@ -36,6 +37,7 @@
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/extensions/extension_set.h"
+#include "chrome/common/extensions/manifest_handlers/shared_module_info.h"
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
@@ -144,11 +146,6 @@ class ExtensionService
// Returns whether the URL is from either a hosted or packaged app.
bool IsInstalledApp(const GURL& url) const;
- // If the renderer is hosting an installed app with isolated storage,
- // returns it, otherwise returns NULL.
- const extensions::Extension* GetIsolatedAppForRenderer(
- int renderer_child_id) const;
-
// Attempts to uninstall an extension from a given ExtensionService. Returns
// true iff the target extension exists.
static bool UninstallExtensionHelper(ExtensionService* extensions_service,
@@ -186,11 +183,6 @@ class ExtensionService
extensions::ProcessMap* process_map() { return &process_map_; }
- // Whether this extension can run in an incognito window.
- virtual bool IsIncognitoEnabled(const std::string& extension_id) const;
- virtual void SetIsIncognitoEnabled(const std::string& extension_id,
- bool enabled);
-
// Updates the app launcher value for the moved extension so that it is now
// located after the given predecessor and before the successor. This will
// trigger a sync if needed. Empty strings are used to indicate no successor
@@ -199,19 +191,6 @@ class ExtensionService
const std::string& predecessor_extension_id,
const std::string& successor_extension_id);
- // Returns true if the given extension can see events and data from another
- // sub-profile (incognito to original profile, or vice versa).
- bool CanCrossIncognito(const extensions::Extension* extension) const;
-
- // Returns true if the given extension can be loaded in incognito.
- bool CanLoadInIncognito(const extensions::Extension* extension) const;
-
- // Whether this extension can inject scripts into pages with file URLs.
- bool AllowFileAccess(const extensions::Extension* extension) const;
- // Will reload the extension since this permission is applied at loading time
- // only.
- void SetAllowFileAccess(const extensions::Extension* extension, bool allow);
-
// Whether the persistent background page, if any, is ready. We don't load
// other components until then. If there is no background page, or if it is
// non-persistent (lazy), we consider it to be ready.
@@ -397,6 +376,13 @@ class ExtensionService
IMPORT_STATUS_UNRECOVERABLE
};
+ // Checks an extension's imports. No installed and outdated imports will be
+ // stored in |missing_modules| and |outdated_modules|.
+ ImportStatus CheckImports(
+ const extensions::Extension* extension,
+ std::list<extensions::SharedModuleInfo::ImportInfo>* missing_modules,
+ std::list<extensions::SharedModuleInfo::ImportInfo>* outdated_modules);
+
// Checks an extension's shared module imports to see if they are satisfied.
// If they are not, this function adds the dependencies to the pending install
// list if |extension| came from the webstore.
@@ -503,6 +489,7 @@ class ExtensionService
// TODO(skerner): Change to const ExtensionPrefs& extension_prefs() const,
// ExtensionPrefs* mutable_extension_prefs().
extensions::ExtensionPrefs* extension_prefs();
+ const extensions::ExtensionPrefs* extension_prefs() const;
extensions::SettingsFrontend* settings_frontend();
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc
index 38c51b0762..b9e4dcec90 100644
--- a/chrome/browser/extensions/extension_service_unittest.cc
+++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -44,6 +44,7 @@
#include "chrome/browser/extensions/extension_special_storage_policy.h"
#include "chrome/browser/extensions/extension_sync_data.h"
#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/extensions/external_install_ui.h"
#include "chrome/browser/extensions/external_policy_loader.h"
#include "chrome/browser/extensions/external_pref_loader.h"
@@ -449,7 +450,7 @@ class MockProviderVisitor
ExtensionServiceTestBase::ExtensionServiceInitParams::
ExtensionServiceInitParams()
- : autoupdate_enabled(false), is_first_run(true) {
+ : autoupdate_enabled(false), is_first_run(true), profile_is_managed(false) {
}
// Our message loop may be used in tests which require it to be an IO loop.
@@ -487,6 +488,10 @@ void ExtensionServiceTestBase::InitializeExtensionService(
chrome::RegisterUserProfilePrefs(registry.get());
profile_builder.SetPrefService(prefs.Pass());
}
+
+ if (params.profile_is_managed)
+ profile_builder.SetManagedUserId("asdf");
+
profile_builder.SetPath(params.profile_path);
profile_ = profile_builder.Build();
@@ -512,6 +517,8 @@ void ExtensionServiceTestBase::InitializeExtensionService(
management_policy_ =
ExtensionSystem::Get(profile_.get())->management_policy();
+ extensions_install_dir_ = params.extensions_install_dir;
+
// When we start up, we want to make sure there is no external provider,
// since the ExtensionService on Windows will use the Registry as a default
// provider and if there is something already registered there then it will
@@ -529,22 +536,25 @@ void ExtensionServiceTestBase::InitializeExtensionService(
void ExtensionServiceTestBase::InitializeInstalledExtensionService(
const base::FilePath& prefs_file,
const base::FilePath& source_install_dir) {
- ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
base::FilePath path = temp_dir_.path();
path = path.Append(FILE_PATH_LITERAL("TestingExtensionsPath"));
- base::DeleteFile(path, true);
- file_util::CreateDirectory(path);
+ EXPECT_TRUE(base::DeleteFile(path, true));
+ base::PlatformFileError error = base::PLATFORM_FILE_OK;
+ EXPECT_TRUE(file_util::CreateDirectoryAndGetError(path, &error)) << error;
base::FilePath temp_prefs = path.Append(FILE_PATH_LITERAL("Preferences"));
- base::CopyFile(prefs_file, temp_prefs);
+ EXPECT_TRUE(base::CopyFile(prefs_file, temp_prefs));
- extensions_install_dir_ = path.Append(FILE_PATH_LITERAL("Extensions"));
- base::DeleteFile(extensions_install_dir_, true);
- base::CopyDirectory(source_install_dir, extensions_install_dir_, true);
+ base::FilePath extensions_install_dir =
+ path.Append(FILE_PATH_LITERAL("Extensions"));
+ EXPECT_TRUE(base::DeleteFile(extensions_install_dir, true));
+ EXPECT_TRUE(
+ base::CopyDirectory(source_install_dir, extensions_install_dir, true));
ExtensionServiceInitParams params;
params.profile_path = path;
params.pref_file = temp_prefs;
- params.extensions_install_dir = extensions_install_dir_;
+ params.extensions_install_dir = extensions_install_dir;
InitializeExtensionService(params);
}
@@ -559,7 +569,7 @@ void ExtensionServiceTestBase::InitializeGoodInstalledExtensionService() {
}
void ExtensionServiceTestBase::InitializeEmptyExtensionService() {
- InitializeExtensionServiceHelper(false, true);
+ InitializeExtensionService(CreateDefaultInitParams());
}
void ExtensionServiceTestBase::InitializeExtensionProcessManager() {
@@ -569,30 +579,33 @@ void ExtensionServiceTestBase::InitializeExtensionProcessManager() {
}
void ExtensionServiceTestBase::InitializeExtensionServiceWithUpdater() {
- InitializeExtensionServiceHelper(true, true);
+ ExtensionServiceInitParams params = CreateDefaultInitParams();
+ params.autoupdate_enabled = true;
+ InitializeExtensionService(params);
service_->updater()->Start();
}
-void ExtensionServiceTestBase::InitializeExtensionServiceHelper(
- bool autoupdate_enabled, bool is_first_run) {
- ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ExtensionServiceTestBase::ExtensionServiceInitParams
+ExtensionServiceTestBase::CreateDefaultInitParams() {
+ ExtensionServiceInitParams params;
+ EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
base::FilePath path = temp_dir_.path();
path = path.Append(FILE_PATH_LITERAL("TestingExtensionsPath"));
- base::DeleteFile(path, true);
- file_util::CreateDirectory(path);
+ EXPECT_TRUE(base::DeleteFile(path, true));
+ base::PlatformFileError error = base::PLATFORM_FILE_OK;
+ EXPECT_TRUE(file_util::CreateDirectoryAndGetError(path, &error)) << error;
base::FilePath prefs_filename =
path.Append(FILE_PATH_LITERAL("TestPreferences"));
- extensions_install_dir_ = path.Append(FILE_PATH_LITERAL("Extensions"));
- base::DeleteFile(extensions_install_dir_, true);
- file_util::CreateDirectory(extensions_install_dir_);
+ base::FilePath extensions_install_dir =
+ path.Append(FILE_PATH_LITERAL("Extensions"));
+ EXPECT_TRUE(base::DeleteFile(extensions_install_dir, true));
+ EXPECT_TRUE(file_util::CreateDirectoryAndGetError(extensions_install_dir,
+ &error)) << error;
- ExtensionServiceInitParams params;
params.profile_path = path;
params.pref_file = prefs_filename;
- params.extensions_install_dir = extensions_install_dir_;
- params.autoupdate_enabled = autoupdate_enabled;
- params.is_first_run = is_first_run;
- InitializeExtensionService(params);
+ params.extensions_install_dir = extensions_install_dir;
+ return params;
}
// static
@@ -2925,7 +2938,7 @@ TEST_F(ExtensionServiceTest, UpdateExtensionPreservesState) {
// Disable it and allow it to run in incognito. These settings should carry
// over to the updated version.
service_->DisableExtension(good->id(), Extension::DISABLE_USER_ACTION);
- service_->SetIsIncognitoEnabled(good->id(), true);
+ extension_util::SetIsIncognitoEnabled(good->id(), service_, true);
service_->extension_prefs()->SetDidExtensionEscalatePermissions(good, true);
path = data_dir_.AppendASCII("good2.crx");
@@ -2933,7 +2946,7 @@ TEST_F(ExtensionServiceTest, UpdateExtensionPreservesState) {
ASSERT_EQ(1u, service_->disabled_extensions()->size());\
const Extension* good2 = service_->GetExtensionById(good_crx, true);
ASSERT_EQ("1.0.0.1", good2->version()->GetString());
- EXPECT_TRUE(service_->IsIncognitoEnabled(good2->id()));
+ EXPECT_TRUE(extension_util::IsIncognitoEnabled(good2->id(), service_));
EXPECT_TRUE(service_->extension_prefs()->DidExtensionEscalatePermissions(
good2->id()));
}
@@ -3187,7 +3200,7 @@ TEST_F(ExtensionServiceTest, MAYBE_UpdatePendingExternalCrx) {
EXPECT_FALSE(
service_->extension_prefs()->IsExtensionDisabled(extension->id()));
EXPECT_TRUE(service_->IsExtensionEnabled(extension->id()));
- EXPECT_FALSE(service_->IsIncognitoEnabled(extension->id()));
+ EXPECT_FALSE(extension_util::IsIncognitoEnabled(extension->id(), service_));
}
// Test updating a pending CRX as if the source is an external extension
@@ -3769,6 +3782,12 @@ TEST_F(ExtensionServiceTest, ManagementPolicyRequiresEnable) {
EXPECT_EQ(0u, service_->disabled_extensions()->size());
}
+// Flaky on windows; http://crbug.com/309833
+#if defined(OS_WIN)
+#define MAYBE_ExternalExtensionAutoAcknowledgement DISABLED_ExternalExtensionAutoAcknowledgement
+#else
+#define MAYBE_ExternalExtensionAutoAcknowledgement ExternalExtensionAutoAcknowledgement
+#endif
TEST_F(ExtensionServiceTest, ExternalExtensionAutoAcknowledgement) {
InitializeEmptyExtensionService();
set_extensions_enabled(true);
@@ -5366,7 +5385,8 @@ TEST_F(ExtensionServiceTest, GetSyncData) {
EXPECT_EQ(extension->id(), data.id());
EXPECT_FALSE(data.uninstalled());
EXPECT_EQ(service_->IsExtensionEnabled(good_crx), data.enabled());
- EXPECT_EQ(service_->IsIncognitoEnabled(good_crx), data.incognito_enabled());
+ EXPECT_EQ(extension_util::IsIncognitoEnabled(good_crx, service_),
+ data.incognito_enabled());
EXPECT_TRUE(data.version().Equals(*extension->version()));
EXPECT_EQ(extensions::ManifestURL::GetUpdateURL(extension),
data.update_url());
@@ -5392,7 +5412,8 @@ TEST_F(ExtensionServiceTest, GetSyncDataTerminated) {
EXPECT_EQ(extension->id(), data.id());
EXPECT_FALSE(data.uninstalled());
EXPECT_EQ(service_->IsExtensionEnabled(good_crx), data.enabled());
- EXPECT_EQ(service_->IsIncognitoEnabled(good_crx), data.incognito_enabled());
+ EXPECT_EQ(extension_util::IsIncognitoEnabled(good_crx, service_),
+ data.incognito_enabled());
EXPECT_TRUE(data.version().Equals(*extension->version()));
EXPECT_EQ(extensions::ManifestURL::GetUpdateURL(extension),
data.update_url());
@@ -5443,7 +5464,7 @@ TEST_F(ExtensionServiceTest, GetSyncExtensionDataUserSettings) {
EXPECT_FALSE(data.incognito_enabled());
}
- service_->SetIsIncognitoEnabled(good_crx, true);
+ extension_util::SetIsIncognitoEnabled(good_crx, service_, true);
{
syncer::SyncDataList list = service_->GetAllSyncData(syncer::EXTENSIONS);
ASSERT_EQ(list.size(), 1U);
@@ -5705,7 +5726,7 @@ TEST_F(ExtensionServiceTest, ProcessSyncDataSettings) {
InstallCRX(data_dir_.AppendASCII("good.crx"), INSTALL_NEW);
EXPECT_TRUE(service_->IsExtensionEnabled(good_crx));
- EXPECT_FALSE(service_->IsIncognitoEnabled(good_crx));
+ EXPECT_FALSE(extension_util::IsIncognitoEnabled(good_crx, service_));
sync_pb::EntitySpecifics specifics;
sync_pb::ExtensionSpecifics* ext_specifics = specifics.mutable_extension();
@@ -5724,7 +5745,7 @@ TEST_F(ExtensionServiceTest, ProcessSyncDataSettings) {
list[0] = sync_change;
service_->ProcessSyncChanges(FROM_HERE, list);
EXPECT_FALSE(service_->IsExtensionEnabled(good_crx));
- EXPECT_FALSE(service_->IsIncognitoEnabled(good_crx));
+ EXPECT_FALSE(extension_util::IsIncognitoEnabled(good_crx, service_));
}
{
@@ -5739,7 +5760,7 @@ TEST_F(ExtensionServiceTest, ProcessSyncDataSettings) {
list[0] = sync_change;
service_->ProcessSyncChanges(FROM_HERE, list);
EXPECT_TRUE(service_->IsExtensionEnabled(good_crx));
- EXPECT_TRUE(service_->IsIncognitoEnabled(good_crx));
+ EXPECT_TRUE(extension_util::IsIncognitoEnabled(good_crx, service_));
}
{
@@ -5754,7 +5775,7 @@ TEST_F(ExtensionServiceTest, ProcessSyncDataSettings) {
list[0] = sync_change;
service_->ProcessSyncChanges(FROM_HERE, list);
EXPECT_FALSE(service_->IsExtensionEnabled(good_crx));
- EXPECT_TRUE(service_->IsIncognitoEnabled(good_crx));
+ EXPECT_TRUE(extension_util::IsIncognitoEnabled(good_crx, service_));
}
EXPECT_FALSE(service_->pending_extension_manager()->IsIdPending(good_crx));
@@ -5771,7 +5792,7 @@ TEST_F(ExtensionServiceTest, ProcessSyncDataTerminatedExtension) {
InstallCRX(data_dir_.AppendASCII("good.crx"), INSTALL_NEW);
TerminateExtension(good_crx);
EXPECT_TRUE(service_->IsExtensionEnabled(good_crx));
- EXPECT_FALSE(service_->IsIncognitoEnabled(good_crx));
+ EXPECT_FALSE(extension_util::IsIncognitoEnabled(good_crx, service_));
sync_pb::EntitySpecifics specifics;
sync_pb::ExtensionSpecifics* ext_specifics = specifics.mutable_extension();
@@ -5790,7 +5811,7 @@ TEST_F(ExtensionServiceTest, ProcessSyncDataTerminatedExtension) {
service_->ProcessSyncChanges(FROM_HERE, list);
EXPECT_FALSE(service_->IsExtensionEnabled(good_crx));
- EXPECT_TRUE(service_->IsIncognitoEnabled(good_crx));
+ EXPECT_TRUE(extension_util::IsIncognitoEnabled(good_crx, service_));
EXPECT_FALSE(service_->pending_extension_manager()->IsIdPending(good_crx));
}
@@ -5805,7 +5826,7 @@ TEST_F(ExtensionServiceTest, ProcessSyncDataVersionCheck) {
InstallCRX(data_dir_.AppendASCII("good.crx"), INSTALL_NEW);
EXPECT_TRUE(service_->IsExtensionEnabled(good_crx));
- EXPECT_FALSE(service_->IsIncognitoEnabled(good_crx));
+ EXPECT_FALSE(extension_util::IsIncognitoEnabled(good_crx, service_));
sync_pb::EntitySpecifics specifics;
sync_pb::ExtensionSpecifics* ext_specifics = specifics.mutable_extension();
@@ -5887,11 +5908,11 @@ TEST_F(ExtensionServiceTest, ProcessSyncDataNotInstalled) {
EXPECT_TRUE(service_->IsExtensionEnabled(good_crx));
- EXPECT_FALSE(service_->IsIncognitoEnabled(good_crx));
+ EXPECT_FALSE(extension_util::IsIncognitoEnabled(good_crx, service_));
service_->ProcessSyncChanges(FROM_HERE, list);
EXPECT_TRUE(service_->updater()->WillCheckSoon());
EXPECT_FALSE(service_->IsExtensionEnabled(good_crx));
- EXPECT_TRUE(service_->IsIncognitoEnabled(good_crx));
+ EXPECT_TRUE(extension_util::IsIncognitoEnabled(good_crx, service_));
const extensions::PendingExtensionInfo* info;
EXPECT_TRUE((info = service_->pending_extension_manager()->
@@ -6475,7 +6496,9 @@ TEST_F(ExtensionServiceTest, ExternalInstallUpdatesFromWebstoreOldProfile) {
// This sets up the ExtensionPrefs used by our ExtensionService to be
// post-first run.
- InitializeExtensionServiceHelper(false, false);
+ ExtensionServiceInitParams params = CreateDefaultInitParams();
+ params.is_first_run = false;
+ InitializeExtensionService(params);
base::FilePath crx_path = temp_dir_.path().AppendASCII("webstore.crx");
PackCRX(data_dir_.AppendASCII("update_from_webstore"),
diff --git a/chrome/browser/extensions/extension_service_unittest.h b/chrome/browser/extensions/extension_service_unittest.h
index 05b71a0877..2972c6db16 100644
--- a/chrome/browser/extensions/extension_service_unittest.h
+++ b/chrome/browser/extensions/extension_service_unittest.h
@@ -36,6 +36,7 @@ class ExtensionServiceTestBase : public testing::Test {
base::FilePath extensions_install_dir;
bool autoupdate_enabled;
bool is_first_run;
+ bool profile_is_managed;
ExtensionServiceInitParams();
};
@@ -67,8 +68,7 @@ class ExtensionServiceTestBase : public testing::Test {
}
protected:
- void InitializeExtensionServiceHelper(bool autoupdate_enabled,
- bool is_first_run);
+ ExtensionServiceInitParams CreateDefaultInitParams();
// Destroying at_exit_manager_ will delete all LazyInstances, so it must come
// after thread_bundle_ in the destruction order.
diff --git a/chrome/browser/extensions/extension_startup_browsertest.cc b/chrome/browser/extensions/extension_startup_browsertest.cc
index 300f0230b2..b0250545b9 100644
--- a/chrome/browser/extensions/extension_startup_browsertest.cc
+++ b/chrome/browser/extensions/extension_startup_browsertest.cc
@@ -12,6 +12,7 @@
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/extensions/user_script_master.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
@@ -188,7 +189,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionsStartupTest, MAYBE_NoFileAccess) {
it != service->extensions()->end(); ++it) {
if ((*it)->location() == extensions::Manifest::COMPONENT)
continue;
- if (service->AllowFileAccess(it->get()))
+ if (extension_util::AllowFileAccess(it->get(), service))
extension_list.push_back(it->get());
}
@@ -196,7 +197,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionsStartupTest, MAYBE_NoFileAccess) {
content::WindowedNotificationObserver user_scripts_observer(
chrome::NOTIFICATION_USER_SCRIPTS_UPDATED,
content::NotificationService::AllSources());
- service->SetAllowFileAccess(extension_list[i], false);
+ extension_util::SetAllowFileAccess(extension_list[i], service, false);
user_scripts_observer.Wait();
}
diff --git a/chrome/browser/extensions/extension_system.cc b/chrome/browser/extensions/extension_system.cc
index 348c5ee08a..ddb687dfb1 100644
--- a/chrome/browser/extensions/extension_system.cc
+++ b/chrome/browser/extensions/extension_system.cc
@@ -24,6 +24,7 @@
#include "chrome/browser/extensions/extension_process_manager.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system_factory.h"
+#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/extensions/extension_warning_badge_service.h"
#include "chrome/browser/extensions/extension_warning_set.h"
#include "chrome/browser/extensions/lazy_background_task_queue.h"
@@ -395,7 +396,7 @@ void ExtensionSystemImpl::RegisterExtensionWithRequestContexts(
GetInstallTime(extension->id());
}
bool incognito_enabled =
- extension_service()->IsIncognitoEnabled(extension->id());
+ extension_util::IsIncognitoEnabled(extension->id(), extension_service());
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&ExtensionInfoMap::AddExtension, info_map(),
diff --git a/chrome/browser/extensions/extension_test_notification_observer.cc b/chrome/browser/extensions/extension_test_notification_observer.cc
new file mode 100644
index 0000000000..f8b7a6d4ec
--- /dev/null
+++ b/chrome/browser/extensions/extension_test_notification_observer.cc
@@ -0,0 +1,234 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/extension_test_notification_observer.h"
+
+#include "chrome/browser/extensions/extension_process_manager.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/common/extensions/extension.h"
+#include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/test/test_utils.h"
+
+using extensions::Extension;
+
+namespace {
+
+bool HasExtensionPageActionCountReachedTarget(LocationBarTesting* location_bar,
+ int target_page_action_count) {
+ VLOG(1) << "Number of page actions: " << location_bar->PageActionCount();
+ return location_bar->PageActionCount() == target_page_action_count;
+}
+
+bool HasExtensionPageActionVisibilityReachedTarget(
+ LocationBarTesting* location_bar,
+ int target_visible_page_action_count) {
+ VLOG(1) << "Number of visible page actions: "
+ << location_bar->PageActionVisibleCount();
+ return location_bar->PageActionVisibleCount() ==
+ target_visible_page_action_count;
+}
+
+} // namespace
+
+ExtensionTestNotificationObserver::ExtensionTestNotificationObserver(
+ Browser* browser)
+ : browser_(browser),
+ profile_(NULL),
+ extension_installs_observed_(0),
+ extension_load_errors_observed_(0),
+ crx_installers_done_observed_(0) {
+}
+
+ExtensionTestNotificationObserver::~ExtensionTestNotificationObserver() {}
+
+Profile* ExtensionTestNotificationObserver::GetProfile() {
+ if (!profile_) {
+ if (browser_)
+ profile_ = browser_->profile();
+ else
+ profile_ = ProfileManager::GetDefaultProfile();
+ }
+ return profile_;
+}
+
+void ExtensionTestNotificationObserver::WaitForNotification(
+ int notification_type) {
+ // TODO(bauerb): Using a WindowedNotificationObserver like this can break
+ // easily, if the notification we're waiting for is sent before this method.
+ // Change it so that the WindowedNotificationObserver is constructed earlier.
+ content::NotificationRegistrar registrar;
+ registrar.Add(
+ this, notification_type, content::NotificationService::AllSources());
+ content::WindowedNotificationObserver(
+ notification_type, content::NotificationService::AllSources()).Wait();
+}
+
+bool ExtensionTestNotificationObserver::WaitForPageActionCountChangeTo(
+ int count) {
+ LocationBarTesting* location_bar =
+ browser_->window()->GetLocationBar()->GetLocationBarForTesting();
+ if (!HasExtensionPageActionCountReachedTarget(location_bar, count)) {
+ content::WindowedNotificationObserver(
+ chrome::NOTIFICATION_EXTENSION_PAGE_ACTION_COUNT_CHANGED,
+ base::Bind(
+ &HasExtensionPageActionCountReachedTarget, location_bar, count))
+ .Wait();
+ }
+ return HasExtensionPageActionCountReachedTarget(location_bar, count);
+}
+
+bool ExtensionTestNotificationObserver::WaitForPageActionVisibilityChangeTo(
+ int count) {
+ LocationBarTesting* location_bar =
+ browser_->window()->GetLocationBar()->GetLocationBarForTesting();
+ if (!HasExtensionPageActionVisibilityReachedTarget(location_bar, count)) {
+ content::WindowedNotificationObserver(
+ chrome::NOTIFICATION_EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED,
+ base::Bind(&HasExtensionPageActionVisibilityReachedTarget,
+ location_bar,
+ count)).Wait();
+ }
+ return HasExtensionPageActionVisibilityReachedTarget(location_bar, count);
+}
+
+bool ExtensionTestNotificationObserver::WaitForExtensionViewsToLoad() {
+ ExtensionProcessManager* manager =
+ extensions::ExtensionSystem::Get(GetProfile())->process_manager();
+ ExtensionProcessManager::ViewSet all_views = manager->GetAllViews();
+ for (ExtensionProcessManager::ViewSet::const_iterator iter =
+ all_views.begin();
+ iter != all_views.end();) {
+ if (!(*iter)->IsLoading()) {
+ ++iter;
+ } else {
+ // Wait for all the extension render view hosts that exist to finish
+ // loading.
+ content::WindowedNotificationObserver observer(
+ content::NOTIFICATION_LOAD_STOP,
+ content::NotificationService::AllSources());
+ observer.AddNotificationType(
+ content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
+ content::NotificationService::AllSources());
+ observer.Wait();
+
+ // Test activity may have modified the set of extension processes during
+ // message processing, so re-start the iteration to catch added/removed
+ // processes.
+ all_views = manager->GetAllViews();
+ iter = all_views.begin();
+ }
+ }
+ return true;
+}
+
+bool ExtensionTestNotificationObserver::WaitForExtensionInstall() {
+ int before = extension_installs_observed_;
+ WaitForNotification(chrome::NOTIFICATION_EXTENSION_INSTALLED);
+ return extension_installs_observed_ == (before + 1);
+}
+
+bool ExtensionTestNotificationObserver::WaitForExtensionInstallError() {
+ int before = extension_installs_observed_;
+ content::WindowedNotificationObserver(
+ chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
+ content::NotificationService::AllSources()).Wait();
+ return extension_installs_observed_ == before;
+}
+
+void ExtensionTestNotificationObserver::WaitForExtensionLoad() {
+ WaitForNotification(chrome::NOTIFICATION_EXTENSION_LOADED);
+}
+
+void ExtensionTestNotificationObserver::WaitForExtensionAndViewLoad() {
+ this->WaitForExtensionLoad();
+ WaitForExtensionViewsToLoad();
+}
+
+bool ExtensionTestNotificationObserver::WaitForExtensionLoadError() {
+ int before = extension_load_errors_observed_;
+ WaitForNotification(chrome::NOTIFICATION_EXTENSION_LOAD_ERROR);
+ return extension_load_errors_observed_ != before;
+}
+
+bool ExtensionTestNotificationObserver::WaitForExtensionCrash(
+ const std::string& extension_id) {
+ ExtensionService* service = extensions::ExtensionSystem::Get(
+ GetProfile())->extension_service();
+
+ if (!service->GetExtensionById(extension_id, true)) {
+ // The extension is already unloaded, presumably due to a crash.
+ return true;
+ }
+ content::WindowedNotificationObserver(
+ chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED,
+ content::NotificationService::AllSources()).Wait();
+ return (service->GetExtensionById(extension_id, true) == NULL);
+}
+
+bool ExtensionTestNotificationObserver::WaitForCrxInstallerDone() {
+ int before = crx_installers_done_observed_;
+ WaitForNotification(chrome::NOTIFICATION_CRX_INSTALLER_DONE);
+ return crx_installers_done_observed_ == (before + 1);
+}
+
+void ExtensionTestNotificationObserver::Watch(
+ int type,
+ const content::NotificationSource& source) {
+ CHECK(!observer_);
+ observer_.reset(new content::WindowedNotificationObserver(type, source));
+ registrar_.Add(this, type, source);
+}
+
+void ExtensionTestNotificationObserver::Wait() {
+ observer_->Wait();
+
+ registrar_.RemoveAll();
+ observer_.reset();
+}
+
+void ExtensionTestNotificationObserver::Observe(
+ int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) {
+ switch (type) {
+ case chrome::NOTIFICATION_EXTENSION_LOADED:
+ last_loaded_extension_id_ =
+ content::Details<const Extension>(details).ptr()->id();
+ VLOG(1) << "Got EXTENSION_LOADED notification.";
+ break;
+
+ case chrome::NOTIFICATION_CRX_INSTALLER_DONE:
+ VLOG(1) << "Got CRX_INSTALLER_DONE notification.";
+ {
+ const Extension* extension =
+ content::Details<const Extension>(details).ptr();
+ if (extension)
+ last_loaded_extension_id_ = extension->id();
+ else
+ last_loaded_extension_id_.clear();
+ }
+ ++crx_installers_done_observed_;
+ break;
+
+ case chrome::NOTIFICATION_EXTENSION_INSTALLED:
+ VLOG(1) << "Got EXTENSION_INSTALLED notification.";
+ ++extension_installs_observed_;
+ break;
+
+ case chrome::NOTIFICATION_EXTENSION_LOAD_ERROR:
+ VLOG(1) << "Got EXTENSION_LOAD_ERROR notification.";
+ ++extension_load_errors_observed_;
+ break;
+
+ default:
+ NOTREACHED();
+ break;
+ }
+}
diff --git a/chrome/browser/extensions/extension_test_notification_observer.h b/chrome/browser/extensions/extension_test_notification_observer.h
new file mode 100644
index 0000000000..14636b6675
--- /dev/null
+++ b/chrome/browser/extensions/extension_test_notification_observer.h
@@ -0,0 +1,100 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_TEST_NOTIFICATION_OBSERVER_H_
+#define CHROME_BROWSER_EXTENSIONS_EXTENSION_TEST_NOTIFICATION_OBSERVER_H_
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/omnibox/location_bar.h"
+#include "content/public/browser/notification_details.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_types.h"
+
+namespace content {
+class WindowedNotificationObserver;
+}
+
+// Test helper class for observing extension-related events.
+class ExtensionTestNotificationObserver : public content::NotificationObserver {
+ public:
+ explicit ExtensionTestNotificationObserver(Browser* browser);
+ virtual ~ExtensionTestNotificationObserver();
+
+ // Wait for the total number of page actions to change to |count|.
+ bool WaitForPageActionCountChangeTo(int count);
+
+ // Wait for the number of visible page actions to change to |count|.
+ bool WaitForPageActionVisibilityChangeTo(int count);
+
+ // Waits until an extension is installed and loaded. Returns true if an
+ // install happened before timeout.
+ bool WaitForExtensionInstall();
+
+ // Wait for an extension install error to be raised. Returns true if an
+ // error was raised.
+ bool WaitForExtensionInstallError();
+
+ // Waits until an extension is loaded and all view have loaded.
+ void WaitForExtensionAndViewLoad();
+
+ // Waits until an extension is loaded.
+ void WaitForExtensionLoad();
+
+ // Waits for an extension load error. Returns true if the error really
+ // happened.
+ bool WaitForExtensionLoadError();
+
+ // Wait for the specified extension to crash. Returns true if it really
+ // crashed.
+ bool WaitForExtensionCrash(const std::string& extension_id);
+
+ // Wait for the crx installer to be done. Returns true if it really is done.
+ bool WaitForCrxInstallerDone();
+
+ // Wait for all extension views to load.
+ bool WaitForExtensionViewsToLoad();
+
+ // Watch for the given event type from the given source.
+ // After calling this method, call Wait() to ensure that RunMessageLoop() is
+ // called appropriately and cleanup is performed.
+ void Watch(int type, const content::NotificationSource& source);
+
+ // After registering one or more event types with Watch(), call
+ // this method to run the message loop and perform cleanup.
+ void Wait();
+
+ const std::string& last_loaded_extension_id() {
+ return last_loaded_extension_id_;
+ }
+ void set_last_loaded_extension_id(std::string last_loaded_extension_id) {
+ last_loaded_extension_id_ = last_loaded_extension_id;
+ }
+
+ // content::NotificationObserver
+ virtual void Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) OVERRIDE;
+
+ private:
+ Profile* GetProfile();
+
+ void WaitForNotification(int notification_type);
+
+ Browser* browser_;
+ Profile* profile_;
+
+ content::NotificationRegistrar registrar_;
+ scoped_ptr<content::WindowedNotificationObserver> observer_;
+
+ std::string last_loaded_extension_id_;
+ int extension_installs_observed_;
+ int extension_load_errors_observed_;
+ int crx_installers_done_observed_;
+};
+
+#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_TEST_NOTIFICATION_OBSERVER_H_
diff --git a/chrome/browser/extensions/extension_toolbar_model.cc b/chrome/browser/extensions/extension_toolbar_model.cc
index c869fd91d1..a3a61e6d0f 100644
--- a/chrome/browser/extensions/extension_toolbar_model.cc
+++ b/chrome/browser/extensions/extension_toolbar_model.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/extensions/extension_toolbar_model.h"
+#include <string>
+
#include "base/prefs/pref_service.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
@@ -12,6 +14,7 @@
#include "chrome/browser/extensions/extension_prefs.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_tab_util.h"
+#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/extensions/tab_helper.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
@@ -41,6 +44,11 @@ bool IsInExtensionList(const Extension* extension,
} // namespace
+bool ExtensionToolbarModel::Observer::BrowserActionShowPopup(
+ const extensions::Extension* extension) {
+ return false;
+}
+
ExtensionToolbarModel::ExtensionToolbarModel(ExtensionService* service)
: service_(service),
prefs_(service->profile()->GetPrefs()),
@@ -128,7 +136,8 @@ void ExtensionToolbarModel::MoveBrowserAction(const Extension* extension,
ExtensionToolbarModel::Action ExtensionToolbarModel::ExecuteBrowserAction(
const Extension* extension,
Browser* browser,
- GURL* popup_url_out) {
+ GURL* popup_url_out,
+ bool should_grant) {
content::WebContents* web_contents = NULL;
int tab_id = 0;
if (!ExtensionTabUtil::GetDefaultTab(browser, &web_contents, &tab_id))
@@ -142,8 +151,10 @@ ExtensionToolbarModel::Action ExtensionToolbarModel::ExecuteBrowserAction(
if (!browser_action->GetIsVisible(tab_id))
return ACTION_NONE;
- extensions::TabHelper::FromWebContents(web_contents)->
- active_tab_permission_granter()->GrantIfRequested(extension);
+ if (should_grant) {
+ extensions::TabHelper::FromWebContents(web_contents)->
+ active_tab_permission_granter()->GrantIfRequested(extension);
+ }
if (browser_action->HasPopup(tab_id)) {
if (popup_url_out)
@@ -402,7 +413,7 @@ int ExtensionToolbarModel::IncognitoIndexToOriginal(int incognito_index) {
for (ExtensionList::iterator iter = toolbar_items_.begin();
iter != toolbar_items_.end();
++iter, ++original_index) {
- if (service_->IsIncognitoEnabled((*iter)->id())) {
+ if (extension_util::IsIncognitoEnabled((*iter)->id(), service_)) {
if (incognito_index == i)
break;
++i;
@@ -418,7 +429,7 @@ int ExtensionToolbarModel::OriginalIndexToIncognito(int original_index) {
++iter, ++i) {
if (original_index == i)
break;
- if (service_->IsIncognitoEnabled((*iter)->id()))
+ if (extension_util::IsIncognitoEnabled((*iter)->id(), service_))
++incognito_index;
}
return incognito_index;
@@ -454,3 +465,15 @@ void ExtensionToolbarModel::OnExtensionToolbarPrefChange() {
weak_ptr_factory_.GetWeakPtr()));
}
}
+
+bool ExtensionToolbarModel::ShowBrowserActionPopup(
+ const extensions::Extension* extension) {
+ ObserverListBase<Observer>::Iterator it(observers_);
+ Observer* obs = NULL;
+ while ((obs = it.GetNext()) != NULL) {
+ // Stop after first popup since it should only show in the active window.
+ if (obs->BrowserActionShowPopup(extension))
+ return true;
+ }
+ return false;
+}
diff --git a/chrome/browser/extensions/extension_toolbar_model.h b/chrome/browser/extensions/extension_toolbar_model.h
index df01de5d17..1d77d4ee81 100644
--- a/chrome/browser/extensions/extension_toolbar_model.h
+++ b/chrome/browser/extensions/extension_toolbar_model.h
@@ -33,7 +33,7 @@ class ExtensionToolbarModel : public content::NotificationObserver {
};
// A class which is informed of changes to the model; represents the view of
- // MVC.
+ // MVC. Also used for signaling view changes such as showing extension popups.
class Observer {
public:
// An extension with a browser action button has been added, and should go
@@ -48,6 +48,10 @@ class ExtensionToolbarModel : public content::NotificationObserver {
virtual void BrowserActionMoved(const extensions::Extension* extension,
int index) {}
+ // Signal the |extension| to show the popup now in the active window.
+ // Returns true if a popup was slated to be shown.
+ virtual bool BrowserActionShowPopup(const extensions::Extension* extension);
+
// Called when the model has finished loading.
virtual void ModelLoaded() {}
@@ -62,10 +66,14 @@ class ExtensionToolbarModel : public content::NotificationObserver {
// Executes the browser action for an extension and returns the action that
// the UI should perform in response.
// |popup_url_out| will be set if the extension should show a popup, with
- // the URL that should be shown, if non-NULL.
+ // the URL that should be shown, if non-NULL. |should_grant| controls whether
+ // the extension should be granted page tab permissions, which is what happens
+ // when the user clicks the browser action, but not, for example, when the
+ // showPopup API is called.
Action ExecuteBrowserAction(const extensions::Extension* extension,
Browser* browser,
- GURL* popup_url_out);
+ GURL* popup_url_out,
+ bool should_grant);
// If count == size(), this will set the visible icon count to -1, meaning
// "show all actions".
void SetVisibleIconCount(int count);
@@ -85,6 +93,10 @@ class ExtensionToolbarModel : public content::NotificationObserver {
void OnExtensionToolbarPrefChange();
+ // Tells observers to display a popup without granting tab permissions and
+ // returns whether the popup was slated to be shown.
+ bool ShowBrowserActionPopup(const extensions::Extension* extension);
+
private:
// content::NotificationObserver implementation.
virtual void Observe(int type,
diff --git a/chrome/browser/extensions/extension_url_rewrite_browsertest.cc b/chrome/browser/extensions/extension_url_rewrite_browsertest.cc
index 0db2dcbf8d..6dc93f0ed7 100644
--- a/chrome/browser/extensions/extension_url_rewrite_browsertest.cc
+++ b/chrome/browser/extensions/extension_url_rewrite_browsertest.cc
@@ -111,14 +111,6 @@ IN_PROC_BROWSER_TEST_F(ExtensionURLRewriteBrowserTest, MAYBE_BookmarksURL) {
EXPECT_TRUE(navigation->GetURL().SchemeIs(extensions::kExtensionScheme));
}
-#if defined(FILE_MANAGER_EXTENSION)
-IN_PROC_BROWSER_TEST_F(ExtensionURLRewriteBrowserTest, FileManagerURL) {
- // Navigate to chrome://files and check that the location bar URL is
- // what was entered and the internal URL uses the chrome-extension:// scheme.
- TestExtensionURLOverride(GURL(chrome::kChromeUIFileManagerURL));
-}
-#endif
-
IN_PROC_BROWSER_TEST_F(ExtensionURLRewriteBrowserTest, BookmarksURLWithRef) {
// Navigate to chrome://bookmarks/#1 and check that the location bar URL is
// what was entered and the internal URL uses the chrome-extension:// scheme.
diff --git a/chrome/browser/extensions/extension_util.cc b/chrome/browser/extensions/extension_util.cc
new file mode 100644
index 0000000000..71375ddcfc
--- /dev/null
+++ b/chrome/browser/extensions/extension_util.cc
@@ -0,0 +1,124 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/extension_util.h"
+
+#include "base/command_line.h"
+#include "chrome/browser/extensions/extension_prefs.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/incognito_handler.h"
+#include "chrome/common/extensions/sync_helper.h"
+#include "extensions/common/manifest.h"
+
+using extensions::Extension;
+using extensions::ExtensionPrefs;
+
+namespace extension_util {
+
+bool IsIncognitoEnabled(const std::string& extension_id,
+ const ExtensionService* service) {
+ if (!service)
+ return false;
+
+ const Extension* extension = service->GetInstalledExtension(extension_id);
+ if (extension && !extension->can_be_incognito_enabled())
+ return false;
+ // If this is an existing component extension we always allow it to
+ // work in incognito mode.
+ if (extension && extension->location() == extensions::Manifest::COMPONENT)
+ return true;
+ if (extension && extension->force_incognito_enabled())
+ return true;
+
+ // Check the prefs.
+ return service->extension_prefs()->IsIncognitoEnabled(extension_id);
+}
+
+void SetIsIncognitoEnabled(const std::string& extension_id,
+ ExtensionService* service,
+ bool enabled) {
+ const Extension* extension = service->GetInstalledExtension(extension_id);
+ if (extension && !extension->can_be_incognito_enabled())
+ return;
+ if (extension && extension->location() == extensions::Manifest::COMPONENT) {
+ // This shouldn't be called for component extensions unless it is called
+ // by sync, for syncable component extensions.
+ // See http://crbug.com/112290 and associated CLs for the sordid history.
+ DCHECK(extensions::sync_helper::IsSyncable(extension));
+
+ // If we are here, make sure the we aren't trying to change the value.
+ DCHECK_EQ(enabled, IsIncognitoEnabled(extension_id, service));
+ return;
+ }
+
+ ExtensionPrefs* extension_prefs = service->extension_prefs();
+ // Broadcast unloaded and loaded events to update browser state. Only bother
+ // if the value changed and the extension is actually enabled, since there is
+ // no UI otherwise.
+ bool old_enabled = extension_prefs->IsIncognitoEnabled(extension_id);
+ if (enabled == old_enabled)
+ return;
+
+ extension_prefs->SetIsIncognitoEnabled(extension_id, enabled);
+
+ bool extension_is_enabled = service->extensions()->Contains(extension_id);
+
+ // When we reload the extension the ID may be invalidated if we've passed it
+ // by const ref everywhere. Make a copy to be safe.
+ std::string id = extension_id;
+ if (extension_is_enabled)
+ service->ReloadExtension(id);
+
+ // Reloading the extension invalidates the |extension| pointer.
+ extension = service->GetInstalledExtension(id);
+ if (extension)
+ service->SyncExtensionChangeIfNeeded(*extension);
+}
+
+bool CanCrossIncognito(const Extension* extension,
+ const ExtensionService* service) {
+ // We allow the extension to see events and data from another profile iff it
+ // uses "spanning" behavior and it has incognito access. "split" mode
+ // extensions only see events for a matching profile.
+ CHECK(extension);
+ return extension_util::IsIncognitoEnabled(extension->id(), service) &&
+ !extensions::IncognitoInfo::IsSplitMode(extension);
+}
+
+bool CanLoadInIncognito(const Extension* extension,
+ const ExtensionService* service) {
+ if (extension->is_hosted_app())
+ return true;
+ // Packaged apps and regular extensions need to be enabled specifically for
+ // incognito (and split mode should be set).
+ return extensions::IncognitoInfo::IsSplitMode(extension) &&
+ extension_util::IsIncognitoEnabled(extension->id(), service);
+}
+
+bool AllowFileAccess(const Extension* extension,
+ const ExtensionService* service) {
+ return (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableExtensionsFileAccessCheck) ||
+ service->extension_prefs()->AllowFileAccess(extension->id()));
+}
+
+void SetAllowFileAccess(const Extension* extension,
+ ExtensionService* service,
+ bool allow) {
+ // Reload to update browser state. Only bother if the value changed and the
+ // extension is actually enabled, since there is no UI otherwise.
+ bool old_allow = AllowFileAccess(extension, service);
+ if (allow == old_allow)
+ return;
+
+ service->extension_prefs()->SetAllowFileAccess(extension->id(), allow);
+
+ bool extension_is_enabled = service->extensions()->Contains(extension->id());
+ if (extension_is_enabled)
+ service->ReloadExtension(extension->id());
+}
+
+} // namespace extension_util
diff --git a/chrome/browser/extensions/extension_util.h b/chrome/browser/extensions/extension_util.h
new file mode 100644
index 0000000000..fb9d74e4cd
--- /dev/null
+++ b/chrome/browser/extensions/extension_util.h
@@ -0,0 +1,49 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_UTIL_H_
+#define CHROME_BROWSER_EXTENSIONS_EXTENSION_UTIL_H_
+
+#include <string>
+
+namespace extensions {
+class Extension;
+}
+
+class ExtensionService;
+
+namespace extension_util {
+
+// Whether this extension can run in an incognito window.
+bool IsIncognitoEnabled(const std::string& extension_id,
+ const ExtensionService* service);
+
+// Will reload the extension since this permission is applied at loading time
+// only.
+void SetIsIncognitoEnabled(const std::string& extension_id,
+ ExtensionService* service,
+ bool enabled);
+
+// Returns true if the given extension can see events and data from another
+// sub-profile (incognito to original profile, or vice versa).
+bool CanCrossIncognito(const extensions::Extension* extension,
+ const ExtensionService* service);
+
+// Returns true if the given extension can be loaded in incognito.
+bool CanLoadInIncognito(const extensions::Extension* extension,
+ const ExtensionService* service);
+
+// Whether this extension can inject scripts into pages with file URLs.
+bool AllowFileAccess(const extensions::Extension* extension,
+ const ExtensionService* service);
+
+// Will reload the extension since this permission is applied at loading time
+// only.
+void SetAllowFileAccess(const extensions::Extension* extension,
+ ExtensionService* service,
+ bool allow);
+
+} // namespace extension_util
+
+#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_UTIL_H_
diff --git a/chrome/browser/extensions/extension_web_contents_observer.cc b/chrome/browser/extensions/extension_web_contents_observer.cc
new file mode 100644
index 0000000000..8f648b6066
--- /dev/null
+++ b/chrome/browser/extensions/extension_web_contents_observer.cc
@@ -0,0 +1,137 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/extension_web_contents_observer.h"
+
+#include "chrome/browser/extensions/api/messaging/message_service.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/extensions/extension_messages.h"
+#include "chrome/common/url_constants.h"
+#include "content/public/browser/child_process_security_policy.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/site_instance.h"
+#include "content/public/browser/web_contents.h"
+#include "extensions/browser/view_type_utils.h"
+#include "extensions/common/constants.h"
+
+DEFINE_WEB_CONTENTS_USER_DATA_KEY(extensions::ExtensionWebContentsObserver);
+
+namespace extensions {
+
+ExtensionWebContentsObserver::ExtensionWebContentsObserver(
+ content::WebContents* web_contents)
+ : content::WebContentsObserver(web_contents),
+ profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())) {
+}
+
+ExtensionWebContentsObserver::~ExtensionWebContentsObserver() {
+}
+
+void ExtensionWebContentsObserver::RenderViewCreated(
+ content::RenderViewHost* render_view_host) {
+ render_view_host->Send(new ExtensionMsg_NotifyRenderViewType(
+ render_view_host->GetRoutingID(),
+ extensions::GetViewType(web_contents())));
+
+ const Extension* extension = GetExtension(render_view_host);
+ if (!extension)
+ return;
+
+ content::RenderProcessHost* process = render_view_host->GetProcess();
+
+ // Some extensions use chrome:// URLs.
+ // This is a temporary solution. Replace it with access to chrome-static://
+ // once it is implemented. See: crbug.com/226927.
+ Manifest::Type type = extension->GetType();
+ if (type == Manifest::TYPE_EXTENSION ||
+ type == Manifest::TYPE_LEGACY_PACKAGED_APP ||
+ (type == Manifest::TYPE_PLATFORM_APP &&
+ extension->location() == Manifest::COMPONENT)) {
+ content::ChildProcessSecurityPolicy::GetInstance()->GrantScheme(
+ process->GetID(), chrome::kChromeUIScheme);
+ }
+
+ // Some extensions use file:// URLs.
+ if (type == Manifest::TYPE_EXTENSION ||
+ type == Manifest::TYPE_LEGACY_PACKAGED_APP) {
+ if (ExtensionSystem::Get(profile_)->extension_service()->
+ extension_prefs()->AllowFileAccess(extension->id())) {
+ content::ChildProcessSecurityPolicy::GetInstance()->GrantScheme(
+ process->GetID(), chrome::kFileScheme);
+ }
+ }
+
+ switch (type) {
+ case Manifest::TYPE_EXTENSION:
+ case Manifest::TYPE_USER_SCRIPT:
+ case Manifest::TYPE_HOSTED_APP:
+ case Manifest::TYPE_LEGACY_PACKAGED_APP:
+ case Manifest::TYPE_PLATFORM_APP:
+ // Always send a Loaded message before ActivateExtension so that
+ // ExtensionDispatcher knows what Extension is active, not just its ID.
+ // This is important for classifying the Extension's JavaScript context
+ // correctly (see ExtensionDispatcher::ClassifyJavaScriptContext).
+ render_view_host->Send(new ExtensionMsg_Loaded(
+ std::vector<ExtensionMsg_Loaded_Params>(
+ 1, ExtensionMsg_Loaded_Params(extension))));
+ render_view_host->Send(
+ new ExtensionMsg_ActivateExtension(extension->id()));
+ break;
+
+ case Manifest::TYPE_UNKNOWN:
+ case Manifest::TYPE_THEME:
+ case Manifest::TYPE_SHARED_MODULE:
+ break;
+ }
+}
+
+bool ExtensionWebContentsObserver::OnMessageReceived(
+ const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(ExtensionWebContentsObserver, message)
+ IPC_MESSAGE_HANDLER(ExtensionHostMsg_PostMessage, OnPostMessage)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void ExtensionWebContentsObserver::OnPostMessage(int port_id,
+ const std::string& message) {
+ MessageService* message_service = MessageService::Get(profile_);
+ if (message_service) {
+ message_service->PostMessage(port_id, message);
+ }
+}
+
+const Extension* ExtensionWebContentsObserver::GetExtension(
+ content::RenderViewHost* render_view_host) {
+ // Note that due to ChromeContentBrowserClient::GetEffectiveURL(), hosted apps
+ // (excluding bookmark apps) will have a chrome-extension:// URL for their
+ // site, so we can ignore that wrinkle here.
+ content::SiteInstance* site_instance = render_view_host->GetSiteInstance();
+ const GURL& site = site_instance->GetSiteURL();
+
+ if (!site.SchemeIs(kExtensionScheme))
+ return NULL;
+
+ ExtensionService* service = profile_->GetExtensionService();
+ if (!service)
+ return NULL;
+
+ // Reload the extension if it has crashed.
+ // TODO(yoz): This reload doesn't happen synchronously for unpacked
+ // extensions. It seems to be fast enough, but there is a race.
+ // We should delay loading until the extension has reloaded.
+ if (service->GetTerminatedExtension(site.host()))
+ service->ReloadExtension(site.host());
+
+ // May be null if the extension doesn't exist, for example if somebody typos
+ // a chrome-extension:// URL.
+ return service->extensions()->GetByID(site.host());
+}
+
+} // namespace extensions
diff --git a/chrome/browser/extensions/extension_web_contents_observer.h b/chrome/browser/extensions/extension_web_contents_observer.h
new file mode 100644
index 0000000000..dbac7f9b6e
--- /dev/null
+++ b/chrome/browser/extensions/extension_web_contents_observer.h
@@ -0,0 +1,45 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_WEB_CONTENTS_OBSERVER_H_
+#define CHROME_BROWSER_EXTENSIONS_EXTENSION_WEB_CONTENTS_OBSERVER_H_
+
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/browser/web_contents_user_data.h"
+
+class Profile;
+
+namespace extensions {
+class Extension;
+
+// A web contents observer that's used for WebContents in renderer and extension
+// processes.
+class ExtensionWebContentsObserver
+ : public content::WebContentsObserver,
+ public content::WebContentsUserData<ExtensionWebContentsObserver> {
+ public:
+ virtual ~ExtensionWebContentsObserver();
+
+ private:
+ explicit ExtensionWebContentsObserver(content::WebContents* web_contents);
+ friend class content::WebContentsUserData<ExtensionWebContentsObserver>;
+
+ // content::WebContentsObserver overrides.
+ virtual void RenderViewCreated(
+ content::RenderViewHost* render_view_host) OVERRIDE;
+ virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+
+ void OnPostMessage(int port_id, const std::string& message);
+
+ // Gets the extension or app (if any) that is associated with a RVH.
+ const Extension* GetExtension(content::RenderViewHost* render_view_host);
+
+ Profile* profile_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExtensionWebContentsObserver);
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_WEB_CONTENTS_OBSERVER_H_
diff --git a/chrome/browser/extensions/extension_web_ui.cc b/chrome/browser/extensions/extension_web_ui.cc
index 631ba560a7..b2002c2644 100644
--- a/chrome/browser/extensions/extension_web_ui.cc
+++ b/chrome/browser/extensions/extension_web_ui.cc
@@ -14,6 +14,7 @@
#include "chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_tab_util.h"
+#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/extensions/image_loader.h"
#include "chrome/browser/favicon/favicon_util.h"
#include "chrome/browser/prefs/scoped_user_pref_update.h"
@@ -228,7 +229,7 @@ bool ExtensionWebUI::HandleChromeURLOverride(
// extension uses split mode.
bool incognito_override_allowed =
extensions::IncognitoInfo::IsSplitMode(extension) &&
- service->IsIncognitoEnabled(extension->id());
+ extension_util::IsIncognitoEnabled(extension->id(), service);
if (profile->IsOffTheRecord() && !incognito_override_allowed) {
++i;
continue;
diff --git a/chrome/browser/extensions/external_provider_impl.cc b/chrome/browser/extensions/external_provider_impl.cc
index 20a72b8817..df29f6ac93 100644
--- a/chrome/browser/extensions/external_provider_impl.cc
+++ b/chrome/browser/extensions/external_provider_impl.cc
@@ -34,9 +34,13 @@
#include "ui/base/l10n/l10n_util.h"
#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.h"
#include "chrome/browser/chromeos/extensions/external_pref_cache_loader.h"
+#include "chrome/browser/chromeos/login/user.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/chromeos/policy/app_pack_updater.h"
+#include "chrome/browser/chromeos/policy/device_local_account.h"
+#include "chrome/browser/chromeos/policy/device_local_account_policy_service.h"
#include "chrome/browser/policy/browser_policy_connector.h"
#else
#include "chrome/browser/extensions/default_apps.h"
@@ -61,12 +65,13 @@ const char ExternalProviderImpl::kKeepIfPresent[] = "keep_if_present";
const char ExternalProviderImpl::kRequirePermissionsConsent[] =
"require_permissions_consent";
-ExternalProviderImpl::ExternalProviderImpl(VisitorInterface* service,
- ExternalLoader* loader,
- Profile* profile,
- Manifest::Location crx_location,
- Manifest::Location download_location,
- int creation_flags)
+ExternalProviderImpl::ExternalProviderImpl(
+ VisitorInterface* service,
+ const scoped_refptr<ExternalLoader>& loader,
+ Profile* profile,
+ Manifest::Location crx_location,
+ Manifest::Location download_location,
+ int creation_flags)
: crx_location_(crx_location),
download_location_(download_location),
service_(service),
@@ -346,16 +351,41 @@ void ExternalProviderImpl::CreateExternalProviders(
VisitorInterface* service,
Profile* profile,
ProviderCollection* provider_list) {
+ scoped_refptr<ExternalLoader> external_loader;
+ extensions::Manifest::Location crx_location = Manifest::INVALID_LOCATION;
+#if defined(OS_CHROMEOS)
+ const chromeos::User* user =
+ chromeos::UserManager::Get()->GetUserByProfile(profile);
+ if (user && policy::IsDeviceLocalAccountUser(user->email(), NULL)) {
+ policy::DeviceLocalAccountPolicyBroker* broker =
+ g_browser_process->browser_policy_connector()->
+ GetDeviceLocalAccountPolicyService()->
+ GetBrokerForUser(user->email());
+ if (broker) {
+ external_loader = broker->extension_loader();
+ crx_location = Manifest::EXTERNAL_POLICY;
+ } else {
+ NOTREACHED();
+ }
+ } else {
+ external_loader = new ExternalPolicyLoader(profile);
+ }
+#else
+ external_loader = new ExternalPolicyLoader(profile);
+#endif
+
// Policies are mandatory so they can't be skipped with command line flag.
- provider_list->push_back(
- linked_ptr<ExternalProviderInterface>(
- new ExternalProviderImpl(
- service,
- new ExternalPolicyLoader(profile),
- profile,
- Manifest::INVALID_LOCATION,
- Manifest::EXTERNAL_POLICY_DOWNLOAD,
- Extension::NO_FLAGS)));
+ if (external_loader) {
+ provider_list->push_back(
+ linked_ptr<ExternalProviderInterface>(
+ new ExternalProviderImpl(
+ service,
+ external_loader,
+ profile,
+ crx_location,
+ Manifest::EXTERNAL_POLICY_DOWNLOAD,
+ Extension::NO_FLAGS)));
+ }
// In tests don't install extensions from default external sources.
// It would only slowdown tests and make them flaky.
diff --git a/chrome/browser/extensions/external_provider_impl.h b/chrome/browser/extensions/external_provider_impl.h
index 991d0bb87a..8d95e3e365 100644
--- a/chrome/browser/extensions/external_provider_impl.h
+++ b/chrome/browser/extensions/external_provider_impl.h
@@ -21,7 +21,6 @@ class Version;
}
namespace extensions {
-class ExternalLoader;
// A specialization of the ExternalProvider that uses an instance of
// ExternalLoader to provide external extensions. This class can be seen as a
@@ -37,7 +36,7 @@ class ExternalProviderImpl : public ExternalProviderInterface {
// If either of the origins is not supported by this provider, then it should
// be initialized as Manifest::INVALID_LOCATION.
ExternalProviderImpl(VisitorInterface* service,
- ExternalLoader* loader,
+ const scoped_refptr<ExternalLoader>& loader,
Profile* profile,
Manifest::Location crx_location,
Manifest::Location download_location,
diff --git a/chrome/browser/extensions/global_shortcut_listener.cc b/chrome/browser/extensions/global_shortcut_listener.cc
index 94547adfff..aad5453eca 100644
--- a/chrome/browser/extensions/global_shortcut_listener.cc
+++ b/chrome/browser/extensions/global_shortcut_listener.cc
@@ -1,62 +1,62 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/extensions/global_shortcut_listener.h"
-#include "chrome/browser/profiles/profile.h"
-#include "ui/base/accelerators/accelerator.h"
-
-namespace extensions {
-
-GlobalShortcutListener::GlobalShortcutListener() {
-}
-
-GlobalShortcutListener::~GlobalShortcutListener() {
- DCHECK(accelerator_map_.empty()); // Make sure we've cleaned up.
-}
-
-void GlobalShortcutListener::RegisterAccelerator(
- const ui::Accelerator& accelerator, Observer* observer) {
- AcceleratorMap::const_iterator it = accelerator_map_.find(accelerator);
- if (it == accelerator_map_.end()) {
- if (accelerator_map_.empty())
- GlobalShortcutListener::GetInstance()->StartListening();
- Observers* observers = new Observers;
- observers->AddObserver(observer);
- accelerator_map_[accelerator] = observers;
- } else {
- // Make sure we don't register the same accelerator twice.
- DCHECK(!accelerator_map_[accelerator]->HasObserver(observer));
- accelerator_map_[accelerator]->AddObserver(observer);
- }
-}
-
-void GlobalShortcutListener::UnregisterAccelerator(
- const ui::Accelerator& accelerator, Observer* observer) {
- AcceleratorMap::iterator it = accelerator_map_.find(accelerator);
- DCHECK(it != accelerator_map_.end());
- DCHECK(it->second->HasObserver(observer));
- it->second->RemoveObserver(observer);
- if (!it->second->might_have_observers()) {
- accelerator_map_.erase(it);
- if (accelerator_map_.empty())
- GlobalShortcutListener::GetInstance()->StopListening();
- }
-}
-
-void GlobalShortcutListener::NotifyKeyPressed(
- const ui::Accelerator& accelerator) {
- AcceleratorMap::iterator iter = accelerator_map_.find(accelerator);
- if (iter == accelerator_map_.end()) {
- // This should never occur, because if it does, we have failed to unregister
- // or failed to clean up the map after unregistering the shortcut.
- NOTREACHED();
- return; // No-one is listening to this key.
- }
- // The observer list should not be empty.
- DCHECK(iter->second->might_have_observers());
-
- FOR_EACH_OBSERVER(Observer, *(iter->second), OnKeyPressed(accelerator));
-}
-
-} // namespace extensions
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/global_shortcut_listener.h"
+#include "chrome/browser/profiles/profile.h"
+#include "ui/base/accelerators/accelerator.h"
+
+namespace extensions {
+
+GlobalShortcutListener::GlobalShortcutListener() {
+}
+
+GlobalShortcutListener::~GlobalShortcutListener() {
+ DCHECK(accelerator_map_.empty()); // Make sure we've cleaned up.
+}
+
+void GlobalShortcutListener::RegisterAccelerator(
+ const ui::Accelerator& accelerator, Observer* observer) {
+ AcceleratorMap::const_iterator it = accelerator_map_.find(accelerator);
+ if (it == accelerator_map_.end()) {
+ if (accelerator_map_.empty())
+ GlobalShortcutListener::GetInstance()->StartListening();
+ Observers* observers = new Observers;
+ observers->AddObserver(observer);
+ accelerator_map_[accelerator] = observers;
+ } else {
+ // Make sure we don't register the same accelerator twice.
+ DCHECK(!accelerator_map_[accelerator]->HasObserver(observer));
+ accelerator_map_[accelerator]->AddObserver(observer);
+ }
+}
+
+void GlobalShortcutListener::UnregisterAccelerator(
+ const ui::Accelerator& accelerator, Observer* observer) {
+ AcceleratorMap::iterator it = accelerator_map_.find(accelerator);
+ DCHECK(it != accelerator_map_.end());
+ DCHECK(it->second->HasObserver(observer));
+ it->second->RemoveObserver(observer);
+ if (!it->second->might_have_observers()) {
+ accelerator_map_.erase(it);
+ if (accelerator_map_.empty())
+ GlobalShortcutListener::GetInstance()->StopListening();
+ }
+}
+
+void GlobalShortcutListener::NotifyKeyPressed(
+ const ui::Accelerator& accelerator) {
+ AcceleratorMap::iterator iter = accelerator_map_.find(accelerator);
+ if (iter == accelerator_map_.end()) {
+ // This should never occur, because if it does, we have failed to unregister
+ // or failed to clean up the map after unregistering the shortcut.
+ NOTREACHED();
+ return; // No-one is listening to this key.
+ }
+ // The observer list should not be empty.
+ DCHECK(iter->second->might_have_observers());
+
+ FOR_EACH_OBSERVER(Observer, *(iter->second), OnKeyPressed(accelerator));
+}
+
+} // namespace extensions
diff --git a/chrome/browser/extensions/global_shortcut_listener.h b/chrome/browser/extensions/global_shortcut_listener.h
index 4ca692124c..c61abe65f0 100644
--- a/chrome/browser/extensions/global_shortcut_listener.h
+++ b/chrome/browser/extensions/global_shortcut_listener.h
@@ -1,65 +1,65 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_H_
-#define CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_H_
-
-#include <map>
-
-#include "base/observer_list.h"
-#include "ui/events/keycodes/keyboard_codes.h"
-#include "ui/gfx/native_widget_types.h"
-
-namespace ui {
-class Accelerator;
-}
-
-namespace extensions {
-
-// Platform-neutral implementation of a class that keeps track of observers and
-// monitors keystrokes. It relays messages to the appropriate observers when a
-// global shortcut has been struck by the user.
-class GlobalShortcutListener {
- public:
- class Observer {
- public:
- // Called when your global shortcut (|accelerator|) is struck.
- virtual void OnKeyPressed(const ui::Accelerator& accelerator) = 0;
- };
-
- virtual ~GlobalShortcutListener();
-
- static GlobalShortcutListener* GetInstance();
-
- // Implemented by platform-specific implementations of this class.
- virtual void StartListening() = 0;
- virtual void StopListening() = 0;
-
- // Register an observer for when a certain |accelerator| is struck.
- virtual void RegisterAccelerator(
- const ui::Accelerator& accelerator, Observer* observer);
- // Stop listening for the given |accelerator|.
- virtual void UnregisterAccelerator(
- const ui::Accelerator& accelerator, Observer* observer);
-
- protected:
- GlobalShortcutListener();
-
- // Called by platform specific implementations of this class whenever a key
- // is struck. Only called for keys that have observers registered.
- void NotifyKeyPressed(const ui::Accelerator& accelerator);
-
- // The map of accelerators that have been successfully registered as global
- // shortcuts and their observer lists.
- typedef ObserverList<Observer> Observers;
- typedef std::map< ui::Accelerator, Observers* > AcceleratorMap;
- AcceleratorMap accelerator_map_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(GlobalShortcutListener);
-};
-
-} // namespace extensions
-
-#endif // CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_H_
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_H_
+#define CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_H_
+
+#include <map>
+
+#include "base/observer_list.h"
+#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/gfx/native_widget_types.h"
+
+namespace ui {
+class Accelerator;
+}
+
+namespace extensions {
+
+// Platform-neutral implementation of a class that keeps track of observers and
+// monitors keystrokes. It relays messages to the appropriate observers when a
+// global shortcut has been struck by the user.
+class GlobalShortcutListener {
+ public:
+ class Observer {
+ public:
+ // Called when your global shortcut (|accelerator|) is struck.
+ virtual void OnKeyPressed(const ui::Accelerator& accelerator) = 0;
+ };
+
+ virtual ~GlobalShortcutListener();
+
+ static GlobalShortcutListener* GetInstance();
+
+ // Implemented by platform-specific implementations of this class.
+ virtual void StartListening() = 0;
+ virtual void StopListening() = 0;
+
+ // Register an observer for when a certain |accelerator| is struck.
+ virtual void RegisterAccelerator(
+ const ui::Accelerator& accelerator, Observer* observer);
+ // Stop listening for the given |accelerator|.
+ virtual void UnregisterAccelerator(
+ const ui::Accelerator& accelerator, Observer* observer);
+
+ protected:
+ GlobalShortcutListener();
+
+ // Called by platform specific implementations of this class whenever a key
+ // is struck. Only called for keys that have observers registered.
+ void NotifyKeyPressed(const ui::Accelerator& accelerator);
+
+ // The map of accelerators that have been successfully registered as global
+ // shortcuts and their observer lists.
+ typedef ObserverList<Observer> Observers;
+ typedef std::map< ui::Accelerator, Observers* > AcceleratorMap;
+ AcceleratorMap accelerator_map_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GlobalShortcutListener);
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_H_
diff --git a/chrome/browser/extensions/global_shortcut_listener_ozone.cc b/chrome/browser/extensions/global_shortcut_listener_ozone.cc
new file mode 100644
index 0000000000..f1067d45e8
--- /dev/null
+++ b/chrome/browser/extensions/global_shortcut_listener_ozone.cc
@@ -0,0 +1,75 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/global_shortcut_listener_ozone.h"
+
+#include "content/public/browser/browser_thread.h"
+
+using content::BrowserThread;
+
+namespace {
+
+static base::LazyInstance<extensions::GlobalShortcutListenerOzone> instance =
+ LAZY_INSTANCE_INITIALIZER;
+
+} // namespace
+
+namespace extensions {
+
+// static
+GlobalShortcutListener* GlobalShortcutListener::GetInstance() {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ return instance.Pointer();
+}
+
+GlobalShortcutListenerOzone::GlobalShortcutListenerOzone()
+ : is_listening_(false) {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ // TODO(implementor): Remove this.
+ LOG(ERROR) << "GlobalShortcutListenerOzone object created";
+}
+
+GlobalShortcutListenerOzone::~GlobalShortcutListenerOzone() {
+ if (is_listening_)
+ StopListening();
+}
+
+void GlobalShortcutListenerOzone::StartListening() {
+ DCHECK(!is_listening_); // Don't start twice.
+ NOTIMPLEMENTED();
+ is_listening_ = true;
+}
+
+void GlobalShortcutListenerOzone::StopListening() {
+ DCHECK(is_listening_); // No point if we are not already listening.
+ NOTIMPLEMENTED();
+ is_listening_ = false;
+}
+
+void GlobalShortcutListenerOzone::RegisterAccelerator(
+ const ui::Accelerator& accelerator,
+ GlobalShortcutListener::Observer* observer) {
+ NOTIMPLEMENTED();
+ // To implement:
+ // 1) Convert modifiers to platform specific modifiers.
+ // 2) Register for the hotkey.
+ // 3) If not successful, log why.
+ // 4) Else, call base class RegisterAccelerator.
+
+ GlobalShortcutListener::RegisterAccelerator(accelerator, observer);
+}
+
+void GlobalShortcutListenerOzone::UnregisterAccelerator(
+ const ui::Accelerator& accelerator,
+ GlobalShortcutListener::Observer* observer) {
+ NOTIMPLEMENTED();
+ // To implement:
+ // 1) Unregister for the hotkey.
+ // 2) Call base class UnregisterAccelerator.
+
+ GlobalShortcutListener::UnregisterAccelerator(accelerator, observer);
+}
+
+} // namespace extensions
diff --git a/chrome/browser/extensions/global_shortcut_listener_ozone.h b/chrome/browser/extensions/global_shortcut_listener_ozone.h
new file mode 100644
index 0000000000..01d2953553
--- /dev/null
+++ b/chrome/browser/extensions/global_shortcut_listener_ozone.h
@@ -0,0 +1,45 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_OZONE_H_
+#define CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_OZONE_H_
+
+#include "base/lazy_instance.h"
+#include "chrome/browser/extensions/global_shortcut_listener.h"
+
+namespace extensions {
+
+// Ozone-specific implementation of the GlobalShortcutListener class that
+// listens for global shortcuts. Handles basic keyboard intercepting and
+// forwards its output to the base class for processing.
+class GlobalShortcutListenerOzone : public GlobalShortcutListener {
+ public:
+ virtual ~GlobalShortcutListenerOzone();
+
+ virtual void StartListening() OVERRIDE;
+ virtual void StopListening() OVERRIDE;
+
+ private:
+ friend struct base::DefaultLazyInstanceTraits<GlobalShortcutListenerOzone>;
+
+ GlobalShortcutListenerOzone();
+
+ // Register an |accelerator| with the particular |observer|.
+ virtual void RegisterAccelerator(
+ const ui::Accelerator& accelerator,
+ GlobalShortcutListener::Observer* observer) OVERRIDE;
+ // Unregister an |accelerator| with the particular |observer|.
+ virtual void UnregisterAccelerator(
+ const ui::Accelerator& accelerator,
+ GlobalShortcutListener::Observer* observer) OVERRIDE;
+
+ // Whether this object is listening for global shortcuts.
+ bool is_listening_;
+
+ DISALLOW_COPY_AND_ASSIGN(GlobalShortcutListenerOzone);
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_OZONE_H_
diff --git a/chrome/browser/extensions/global_shortcut_listener_win.cc b/chrome/browser/extensions/global_shortcut_listener_win.cc
index 462ff673de..a5987f7ab9 100644
--- a/chrome/browser/extensions/global_shortcut_listener_win.cc
+++ b/chrome/browser/extensions/global_shortcut_listener_win.cc
@@ -1,112 +1,116 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/extensions/global_shortcut_listener_win.h"
-
-#include "base/win/win_util.h"
-#include "content/public/browser/browser_thread.h"
-#include "ui/base/accelerators/accelerator.h"
-#include "ui/events/event_constants.h"
-#include "ui/events/keycodes/keyboard_code_conversion_win.h"
-
-using content::BrowserThread;
-
-namespace {
-
-static base::LazyInstance<extensions::GlobalShortcutListenerWin> instance =
- LAZY_INSTANCE_INITIALIZER;
-
-} // namespace
-
-namespace extensions {
-
-// static
-GlobalShortcutListener* GlobalShortcutListener::GetInstance() {
- CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- return instance.Pointer();
-}
-
-GlobalShortcutListenerWin::GlobalShortcutListenerWin()
- : is_listening_(false) {
- CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-}
-
-GlobalShortcutListenerWin::~GlobalShortcutListenerWin() {
- if (is_listening_)
- StopListening();
-}
-
-void GlobalShortcutListenerWin::StartListening() {
- DCHECK(!is_listening_); // Don't start twice.
- DCHECK(!hotkey_ids_.empty()); // Also don't start if no hotkey is registered.
- gfx::SingletonHwnd::GetInstance()->AddObserver(this);
- is_listening_ = true;
-}
-
-void GlobalShortcutListenerWin::StopListening() {
- DCHECK(is_listening_); // No point if we are not already listening.
- DCHECK(hotkey_ids_.empty()); // Make sure the map is clean before ending.
- gfx::SingletonHwnd::GetInstance()->RemoveObserver(this);
- is_listening_ = false;
-}
-
-void GlobalShortcutListenerWin::OnWndProc(HWND hwnd,
- UINT message,
- WPARAM wparam,
- LPARAM lparam) {
- if (message != WM_HOTKEY)
- return;
-
- int key_code = HIWORD(lparam);
- int modifiers = 0;
- modifiers |= (LOWORD(lparam) & MOD_SHIFT) ? ui::EF_SHIFT_DOWN : 0;
- modifiers |= (LOWORD(lparam) & MOD_ALT) ? ui::EF_ALT_DOWN : 0;
- modifiers |= (LOWORD(lparam) & MOD_CONTROL) ? ui::EF_CONTROL_DOWN : 0;
- ui::Accelerator accelerator(
- ui::KeyboardCodeForWindowsKeyCode(key_code), modifiers);
-
- instance.Get().NotifyKeyPressed(accelerator);
-}
-
-void GlobalShortcutListenerWin::RegisterAccelerator(
- const ui::Accelerator& accelerator,
- GlobalShortcutListener::Observer* observer) {
- int modifiers = 0;
- modifiers |= accelerator.IsShiftDown() ? MOD_SHIFT : 0;
- modifiers |= accelerator.IsCtrlDown() ? MOD_CONTROL : 0;
- modifiers |= accelerator.IsAltDown() ? MOD_ALT : 0;
- static int hotkey_id = 0;
- bool success = !!RegisterHotKey(
- gfx::SingletonHwnd::GetInstance()->hwnd(),
- hotkey_id,
- modifiers,
- accelerator.key_code());
-
- if (!success) {
- // Most likely error: 1409 (Hotkey already registered).
- LOG(ERROR) << "RegisterHotKey failed, error: " << GetLastError();
- return;
- }
-
- hotkey_ids_[accelerator] = hotkey_id++;
- GlobalShortcutListener::RegisterAccelerator(accelerator, observer);
-}
-
-void GlobalShortcutListenerWin::UnregisterAccelerator(
- const ui::Accelerator& accelerator,
- GlobalShortcutListener::Observer* observer) {
- // We may get asked to unregister something that we couldn't register (for
- // example if the shortcut was already taken by another app), so we
- // need to handle that gracefully.
- HotkeyIdMap::iterator it = hotkey_ids_.find(accelerator);
- if (it == hotkey_ids_.end())
- return;
-
- UnregisterHotKey(gfx::SingletonHwnd::GetInstance()->hwnd(), it->second);
- hotkey_ids_.erase(it);
-
- GlobalShortcutListener::UnregisterAccelerator(accelerator, observer);
-}
-
-} // namespace extensions
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/global_shortcut_listener_win.h"
+
+#include "base/win/win_util.h"
+#include "content/public/browser/browser_thread.h"
+#include "ui/base/accelerators/accelerator.h"
+#include "ui/events/event_constants.h"
+#include "ui/events/keycodes/keyboard_code_conversion_win.h"
+
+using content::BrowserThread;
+
+namespace {
+
+static base::LazyInstance<extensions::GlobalShortcutListenerWin> instance =
+ LAZY_INSTANCE_INITIALIZER;
+
+} // namespace
+
+namespace extensions {
+
+// static
+GlobalShortcutListener* GlobalShortcutListener::GetInstance() {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ return instance.Pointer();
+}
+
+GlobalShortcutListenerWin::GlobalShortcutListenerWin()
+ : is_listening_(false) {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+}
+
+GlobalShortcutListenerWin::~GlobalShortcutListenerWin() {
+ if (is_listening_)
+ StopListening();
+}
+
+void GlobalShortcutListenerWin::StartListening() {
+ DCHECK(!is_listening_); // Don't start twice.
+ DCHECK(!hotkey_ids_.empty()); // Also don't start if no hotkey is registered.
+ gfx::SingletonHwnd::GetInstance()->AddObserver(this);
+ is_listening_ = true;
+}
+
+void GlobalShortcutListenerWin::StopListening() {
+ DCHECK(is_listening_); // No point if we are not already listening.
+ DCHECK(hotkey_ids_.empty()); // Make sure the map is clean before ending.
+ gfx::SingletonHwnd::GetInstance()->RemoveObserver(this);
+ is_listening_ = false;
+}
+
+void GlobalShortcutListenerWin::OnWndProc(HWND hwnd,
+ UINT message,
+ WPARAM wparam,
+ LPARAM lparam) {
+ if (message != WM_HOTKEY)
+ return;
+
+ int key_code = HIWORD(lparam);
+ int modifiers = 0;
+ modifiers |= (LOWORD(lparam) & MOD_SHIFT) ? ui::EF_SHIFT_DOWN : 0;
+ modifiers |= (LOWORD(lparam) & MOD_ALT) ? ui::EF_ALT_DOWN : 0;
+ modifiers |= (LOWORD(lparam) & MOD_CONTROL) ? ui::EF_CONTROL_DOWN : 0;
+ ui::Accelerator accelerator(
+ ui::KeyboardCodeForWindowsKeyCode(key_code), modifiers);
+
+ instance.Get().NotifyKeyPressed(accelerator);
+}
+
+void GlobalShortcutListenerWin::RegisterAccelerator(
+ const ui::Accelerator& accelerator,
+ GlobalShortcutListener::Observer* observer) {
+ int modifiers = 0;
+ modifiers |= accelerator.IsShiftDown() ? MOD_SHIFT : 0;
+ modifiers |= accelerator.IsCtrlDown() ? MOD_CONTROL : 0;
+ modifiers |= accelerator.IsAltDown() ? MOD_ALT : 0;
+ static int hotkey_id = 0;
+ bool success = !!RegisterHotKey(
+ gfx::SingletonHwnd::GetInstance()->hwnd(),
+ hotkey_id,
+ modifiers,
+ accelerator.key_code());
+
+ if (!success) {
+ // Most likely error: 1409 (Hotkey already registered).
+ LOG(ERROR) << "RegisterHotKey failed, error: " << GetLastError();
+ return;
+ }
+
+ hotkey_ids_[accelerator] = hotkey_id++;
+ GlobalShortcutListener::RegisterAccelerator(accelerator, observer);
+}
+
+void GlobalShortcutListenerWin::UnregisterAccelerator(
+ const ui::Accelerator& accelerator,
+ GlobalShortcutListener::Observer* observer) {
+ // We may get asked to unregister something that we couldn't register (for
+ // example if the shortcut was already taken by another app), so we
+ // need to handle that gracefully.
+ HotkeyIdMap::iterator it = hotkey_ids_.find(accelerator);
+ if (it == hotkey_ids_.end())
+ return;
+
+ bool success = !!UnregisterHotKey(
+ gfx::SingletonHwnd::GetInstance()->hwnd(), it->second);
+ // This call should always succeed, as long as we pass in the right HWND and
+ // an id we've used to register before.
+ DCHECK(success);
+
+ hotkey_ids_.erase(it);
+ GlobalShortcutListener::UnregisterAccelerator(accelerator, observer);
+}
+
+} // namespace extensions
diff --git a/chrome/browser/extensions/global_shortcut_listener_win.h b/chrome/browser/extensions/global_shortcut_listener_win.h
index 1844ee455d..f327f70043 100644
--- a/chrome/browser/extensions/global_shortcut_listener_win.h
+++ b/chrome/browser/extensions/global_shortcut_listener_win.h
@@ -1,59 +1,59 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_WIN_H_
-#define CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_WIN_H_
-
-#include <windows.h>
-
-#include "base/lazy_instance.h"
-#include "chrome/browser/extensions/global_shortcut_listener.h"
-#include "ui/gfx/win/singleton_hwnd.h"
-
-namespace extensions {
-
-// Windows-specific implementation of the GlobalShortcutListener class that
-// listens for global shortcuts. Handles setting up a keyboard hook and
-// forwarding its output to the base class for processing.
-class GlobalShortcutListenerWin : public GlobalShortcutListener,
- public gfx::SingletonHwnd::Observer {
- public:
- virtual ~GlobalShortcutListenerWin();
-
- virtual void StartListening() OVERRIDE;
- virtual void StopListening() OVERRIDE;
-
- private:
- friend struct base::DefaultLazyInstanceTraits<GlobalShortcutListenerWin>;
-
- GlobalShortcutListenerWin();
-
- // The implementation of our Window Proc, called by SingletonHwnd.
- virtual void OnWndProc(HWND hwnd,
- UINT message,
- WPARAM wparam,
- LPARAM lparam) OVERRIDE;
-
- // Register an |accelerator| with the particular |observer|.
- virtual void RegisterAccelerator(
- const ui::Accelerator& accelerator,
- GlobalShortcutListener::Observer* observer) OVERRIDE;
- // Unregister an |accelerator| with the particular |observer|.
- virtual void UnregisterAccelerator(
- const ui::Accelerator& accelerator,
- GlobalShortcutListener::Observer* observer) OVERRIDE;
-
- // Whether this object is listening for global shortcuts.
- bool is_listening_;
-
- // A map of registered accelerators and their registration ids.
- typedef std::map< ui::Accelerator, int > HotkeyIdMap;
- HotkeyIdMap hotkey_ids_;
-
- DISALLOW_COPY_AND_ASSIGN(GlobalShortcutListenerWin);
-};
-
-} // namespace extensions
-
-#endif // CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_WIN_H_
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_WIN_H_
+#define CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_WIN_H_
+
+#include <windows.h>
+
+#include "base/lazy_instance.h"
+#include "chrome/browser/extensions/global_shortcut_listener.h"
+#include "ui/gfx/win/singleton_hwnd.h"
+
+namespace extensions {
+
+// Windows-specific implementation of the GlobalShortcutListener class that
+// listens for global shortcuts. Handles setting up a keyboard hook and
+// forwarding its output to the base class for processing.
+class GlobalShortcutListenerWin : public GlobalShortcutListener,
+ public gfx::SingletonHwnd::Observer {
+ public:
+ virtual ~GlobalShortcutListenerWin();
+
+ virtual void StartListening() OVERRIDE;
+ virtual void StopListening() OVERRIDE;
+
+ private:
+ friend struct base::DefaultLazyInstanceTraits<GlobalShortcutListenerWin>;
+
+ GlobalShortcutListenerWin();
+
+ // The implementation of our Window Proc, called by SingletonHwnd.
+ virtual void OnWndProc(HWND hwnd,
+ UINT message,
+ WPARAM wparam,
+ LPARAM lparam) OVERRIDE;
+
+ // Register an |accelerator| with the particular |observer|.
+ virtual void RegisterAccelerator(
+ const ui::Accelerator& accelerator,
+ GlobalShortcutListener::Observer* observer) OVERRIDE;
+ // Unregister an |accelerator| with the particular |observer|.
+ virtual void UnregisterAccelerator(
+ const ui::Accelerator& accelerator,
+ GlobalShortcutListener::Observer* observer) OVERRIDE;
+
+ // Whether this object is listening for global shortcuts.
+ bool is_listening_;
+
+ // A map of registered accelerators and their registration ids.
+ typedef std::map< ui::Accelerator, int > HotkeyIdMap;
+ HotkeyIdMap hotkey_ids_;
+
+ DISALLOW_COPY_AND_ASSIGN(GlobalShortcutListenerWin);
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_WIN_H_
diff --git a/chrome/browser/extensions/global_shortcut_listener_x11.cc b/chrome/browser/extensions/global_shortcut_listener_x11.cc
index 53913c5968..0574c10984 100644
--- a/chrome/browser/extensions/global_shortcut_listener_x11.cc
+++ b/chrome/browser/extensions/global_shortcut_listener_x11.cc
@@ -156,7 +156,7 @@ void GlobalShortcutListenerX11::UnregisterAccelerator(
#if defined(TOOLKIT_GTK)
GdkFilterReturn GlobalShortcutListenerX11::OnXEvent(GdkXEvent* gdk_x_event,
- GdkEvent* gdk_event) {
+ GdkEvent* gdk_event) {
XEvent* x_event = static_cast<XEvent*>(gdk_x_event);
if (x_event->type == KeyPress)
OnXKeyPressEvent(x_event);
diff --git a/chrome/browser/extensions/lazy_background_page_apitest.cc b/chrome/browser/extensions/lazy_background_page_apitest.cc
index 7bd8ac95fe..df1bf3dfd3 100644
--- a/chrome/browser/extensions/lazy_background_page_apitest.cc
+++ b/chrome/browser/extensions/lazy_background_page_apitest.cc
@@ -104,7 +104,7 @@ IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, BrowserActionCreateTab) {
// Lazy Background Page doesn't exist yet.
ExtensionProcessManager* pm =
extensions::ExtensionSystem::Get(browser()->profile())->process_manager();
- EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_));
+ EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id()));
int num_tabs_before = browser()->tab_strip_model()->count();
// Observe background page being created and closed after
@@ -114,7 +114,7 @@ IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, BrowserActionCreateTab) {
page_complete.Wait();
// Background page created a new tab before it closed.
- EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_));
+ EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id()));
EXPECT_EQ(num_tabs_before + 1, browser()->tab_strip_model()->count());
EXPECT_EQ(std::string(chrome::kChromeUIExtensionsURL),
browser()->tab_strip_model()->GetActiveWebContents()->
@@ -128,7 +128,7 @@ IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest,
// Lazy Background Page doesn't exist yet.
ExtensionProcessManager* pm =
extensions::ExtensionSystem::Get(browser()->profile())->process_manager();
- EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_));
+ EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id()));
int num_tabs_before = browser()->tab_strip_model()->count();
// Observe background page being created and closed after
@@ -138,7 +138,7 @@ IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest,
page_complete.Wait();
// Background page is closed after creating a new tab.
- EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_));
+ EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id()));
EXPECT_EQ(num_tabs_before + 1, browser()->tab_strip_model()->count());
}
@@ -151,7 +151,7 @@ IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, BroadcastEvent) {
// Lazy Background Page doesn't exist yet.
ExtensionProcessManager* pm =
extensions::ExtensionSystem::Get(browser()->profile())->process_manager();
- EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_));
+ EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id()));
int num_page_actions = browser()->window()->GetLocationBar()->
GetLocationBarForTesting()->PageActionVisibleCount();
@@ -164,7 +164,7 @@ IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, BroadcastEvent) {
browser(), embedded_test_server()->GetURL("/extensions/test_file.html"));
page_complete.Wait();
- EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_));
+ EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id()));
// Page action is shown.
page_action_changed.Wait();
@@ -182,7 +182,7 @@ IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, Filters) {
// Lazy Background Page doesn't exist yet.
ExtensionProcessManager* pm =
extensions::ExtensionSystem::Get(browser()->profile())->process_manager();
- EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_));
+ EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id()));
// Open a tab to a URL that will fire a webNavigation event.
LazyBackgroundObserver page_complete;
@@ -201,7 +201,7 @@ IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, OnInstalled) {
// Lazy Background Page has been shut down.
ExtensionProcessManager* pm =
extensions::ExtensionSystem::Get(browser()->profile())->process_manager();
- EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_));
+ EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id()));
}
// Tests that the lazy background page stays alive until all visible views are
@@ -224,7 +224,7 @@ IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, WaitForView) {
// to an extension page.
ExtensionProcessManager* pm =
extensions::ExtensionSystem::Get(browser()->profile())->process_manager();
- EXPECT_TRUE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_));
+ EXPECT_TRUE(pm->GetBackgroundHostForExtension(last_loaded_extension_id()));
// Close the new tab.
browser()->tab_strip_model()->CloseWebContentsAt(
@@ -232,7 +232,7 @@ IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, WaitForView) {
page_complete.Wait();
// Lazy Background Page has been shut down.
- EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_));
+ EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id()));
}
// Tests that the lazy background page stays alive until all network requests
@@ -253,7 +253,7 @@ IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, WaitForRequest) {
ExtensionProcessManager* pm =
extensions::ExtensionSystem::Get(browser()->profile())->process_manager();
extensions::ExtensionHost* host =
- pm->GetBackgroundHostForExtension(last_loaded_extension_id_);
+ pm->GetBackgroundHostForExtension(last_loaded_extension_id());
ASSERT_TRUE(host);
// Abort the request.
@@ -264,7 +264,7 @@ IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, WaitForRequest) {
page_complete.Wait();
// Lazy Background Page has been shut down.
- EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_));
+ EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id()));
}
// Tests that the lazy background page stays alive until all visible views are
@@ -293,14 +293,14 @@ IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, MAYBE_WaitForNTP) {
// to an extension page.
ExtensionProcessManager* pm =
extensions::ExtensionSystem::Get(browser()->profile())->process_manager();
- EXPECT_TRUE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_));
+ EXPECT_TRUE(pm->GetBackgroundHostForExtension(last_loaded_extension_id()));
// Navigate away from the NTP, which should close the event page.
ui_test_utils::NavigateToURL(browser(), GURL("about:blank"));
lazybg.Wait();
// Lazy Background Page has been shut down.
- EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_));
+ EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id()));
}
// See crbug.com/248437
@@ -332,8 +332,8 @@ IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, MAYBE_IncognitoSplitMode) {
ExtensionProcessManager* pmi =
extensions::ExtensionSystem::Get(incognito_browser->profile())->
process_manager();
- EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_));
- EXPECT_FALSE(pmi->GetBackgroundHostForExtension(last_loaded_extension_id_));
+ EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id()));
+ EXPECT_FALSE(pmi->GetBackgroundHostForExtension(last_loaded_extension_id()));
// Trigger a browserAction event in the original profile and ensure only
// the original event page received it (since the event is scoped to the
@@ -347,8 +347,9 @@ IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, MAYBE_IncognitoSplitMode) {
page_complete.Wait();
// Only the original event page received the message.
- EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_));
- EXPECT_FALSE(pmi->GetBackgroundHostForExtension(last_loaded_extension_id_));
+ EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id()));
+ EXPECT_FALSE(
+ pmi->GetBackgroundHostForExtension(last_loaded_extension_id()));
EXPECT_TRUE(listener.was_satisfied());
EXPECT_FALSE(listener_incognito.was_satisfied());
}
@@ -370,8 +371,9 @@ IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, MAYBE_IncognitoSplitMode) {
page2_complete.Wait();
// Both pages received the message.
- EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_));
- EXPECT_FALSE(pmi->GetBackgroundHostForExtension(last_loaded_extension_id_));
+ EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id()));
+ EXPECT_FALSE(
+ pmi->GetBackgroundHostForExtension(last_loaded_extension_id()));
EXPECT_TRUE(listener.was_satisfied());
EXPECT_TRUE(listener_incognito.was_satisfied());
}
@@ -386,7 +388,7 @@ IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, Messaging) {
// Lazy Background Page doesn't exist yet.
ExtensionProcessManager* pm =
extensions::ExtensionSystem::Get(browser()->profile())->process_manager();
- EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_));
+ EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id()));
EXPECT_EQ(1, browser()->tab_strip_model()->count());
// Navigate to a page that opens a message channel to the background page.
@@ -399,14 +401,14 @@ IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, Messaging) {
// Background page got the content script's message and is still loaded
// until we close the channel.
EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
- EXPECT_TRUE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_));
+ EXPECT_TRUE(pm->GetBackgroundHostForExtension(last_loaded_extension_id()));
// Navigate away, closing the message channel and therefore the background
// page.
ui_test_utils::NavigateToURL(browser(), GURL("about:blank"));
lazybg.WaitUntilClosed();
- EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_));
+ EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id()));
}
// Tests that the lazy background page receives the unload event when we
@@ -418,7 +420,7 @@ IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, OnUnload) {
// Lazy Background Page has been shut down.
ExtensionProcessManager* pm =
extensions::ExtensionSystem::Get(browser()->profile())->process_manager();
- EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_));
+ EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id()));
// The browser action has a new title.
BrowserActionTestUtil browser_action(browser());
@@ -481,7 +483,7 @@ IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, UpdateExtensionsPage) {
// to an extension page.
ExtensionProcessManager* pm =
extensions::ExtensionSystem::Get(browser()->profile())->process_manager();
- EXPECT_TRUE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_));
+ EXPECT_TRUE(pm->GetBackgroundHostForExtension(last_loaded_extension_id()));
// Close the new tab.
LazyBackgroundObserver page_complete;
@@ -490,7 +492,7 @@ IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, UpdateExtensionsPage) {
page_complete.WaitUntilClosed();
// Lazy Background Page has been shut down.
- EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_));
+ EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id()));
// Verify that extensions page shows that the lazy background page is
// inactive.
diff --git a/chrome/browser/extensions/message_handler.cc b/chrome/browser/extensions/message_handler.cc
deleted file mode 100644
index 8389b9a428..0000000000
--- a/chrome/browser/extensions/message_handler.cc
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/extensions/message_handler.h"
-
-#include "chrome/browser/extensions/api/messaging/message_service.h"
-#include "chrome/browser/extensions/extension_system.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/common/extensions/extension_messages.h"
-#include "content/public/browser/render_process_host.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/web_contents.h"
-#include "extensions/browser/view_type_utils.h"
-
-using content::WebContents;
-
-namespace extensions {
-
-MessageHandler::MessageHandler(
- content::RenderViewHost* render_view_host)
- : content::RenderViewHostObserver(render_view_host) {
-}
-
-MessageHandler::~MessageHandler() {
-}
-
-bool MessageHandler::OnMessageReceived(
- const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(MessageHandler, message)
- IPC_MESSAGE_HANDLER(ExtensionHostMsg_PostMessage, OnPostMessage)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-void MessageHandler::RenderViewHostInitialized() {
- WebContents* web_contents =
- WebContents::FromRenderViewHost(render_view_host());
- Send(new ExtensionMsg_NotifyRenderViewType(
- routing_id(), extensions::GetViewType(web_contents)));
-}
-
-void MessageHandler::OnPostMessage(int port_id,
- const std::string& message) {
- Profile* profile = Profile::FromBrowserContext(
- render_view_host()->GetProcess()->GetBrowserContext());
- MessageService* message_service = MessageService::Get(profile);
- if (message_service) {
- message_service->PostMessage(port_id, message);
- }
-}
-
-} // namespace extensions
diff --git a/chrome/browser/extensions/message_handler.h b/chrome/browser/extensions/message_handler.h
deleted file mode 100644
index 140105d22f..0000000000
--- a/chrome/browser/extensions/message_handler.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_EXTENSIONS_MESSAGE_HANDLER_H_
-#define CHROME_BROWSER_EXTENSIONS_MESSAGE_HANDLER_H_
-
-#include <string>
-
-#include "content/public/browser/render_view_host_observer.h"
-
-namespace extensions {
-
-// Filters and dispatches extension-related IPC messages that arrive from
-// renderers. There is one of these objects for each RenderViewHost in Chrome.
-// Contrast this with extensions::TabHelper, which is only created for
-// WebContents.
-//
-// TODO(aa): Handling of content script messaging should be able to move to EFD
-// once there is an EFD for every RVHD where extension code can run. Then we
-// could eliminate this class. Right now, we don't end up with an EFD for tab
-// contents unless that tab contents is hosting chrome-extension:// URLs. That
-// still leaves content scripts. See also: crbug.com/80307.
-class MessageHandler : public content::RenderViewHostObserver {
- public:
- // |sender| is guaranteed to outlive this object.
- explicit MessageHandler(content::RenderViewHost* render_view_host);
- virtual ~MessageHandler();
-
- // RenderViewHostObserver overrides.
- virtual void RenderViewHostInitialized() OVERRIDE;
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
-
- private:
- // Message handlers.
- void OnPostMessage(int port_id, const std::string& message);
-
- DISALLOW_COPY_AND_ASSIGN(MessageHandler);
-};
-
-} // namespace extensions
-
-#endif // CHROME_BROWSER_EXTENSIONS_MESSAGE_HANDLER_H_
diff --git a/chrome/browser/extensions/notifications_apitest.cc b/chrome/browser/extensions/notifications_apitest.cc
index 0fd58123d4..b1299cf4a8 100644
--- a/chrome/browser/extensions/notifications_apitest.cc
+++ b/chrome/browser/extensions/notifications_apitest.cc
@@ -74,5 +74,5 @@ IN_PROC_BROWSER_TEST_F(NotificationIdleTest, MAYBE_NotificationsAllowUnload) {
// Lazy Background Page has been shut down.
ExtensionProcessManager* pm =
extensions::ExtensionSystem::Get(profile())->process_manager();
- EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_));
+ EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id()));
}
diff --git a/chrome/browser/extensions/page_action_browsertest.cc b/chrome/browser/extensions/page_action_browsertest.cc
index 52a0dd4fce..921b333d75 100644
--- a/chrome/browser/extensions/page_action_browsertest.cc
+++ b/chrome/browser/extensions/page_action_browsertest.cc
@@ -108,7 +108,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, UnloadPageAction) {
ui_test_utils::NavigateToURL(browser(), feed_url);
ASSERT_TRUE(WaitForPageActionCountChangeTo(1));
- UnloadExtension(last_loaded_extension_id_);
+ UnloadExtension(last_loaded_extension_id());
// Make sure the page action goes away when it's unloaded.
ASSERT_TRUE(WaitForPageActionCountChangeTo(0));
diff --git a/chrome/browser/extensions/policy_handlers.cc b/chrome/browser/extensions/policy_handlers.cc
new file mode 100644
index 0000000000..2637726236
--- /dev/null
+++ b/chrome/browser/extensions/policy_handlers.cc
@@ -0,0 +1,247 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/policy_handlers.h"
+
+#include "base/logging.h"
+#include "base/prefs/pref_value_map.h"
+#include "chrome/browser/extensions/external_policy_loader.h"
+#include "chrome/browser/policy/policy_error_map.h"
+#include "chrome/browser/policy/policy_map.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/pref_names.h"
+#include "grit/generated_resources.h"
+#include "policy/policy_constants.h"
+
+namespace extensions {
+
+// ExtensionListPolicyHandler implementation -----------------------------------
+
+ExtensionListPolicyHandler::ExtensionListPolicyHandler(const char* policy_name,
+ const char* pref_path,
+ bool allow_wildcards)
+ : policy::TypeCheckingPolicyHandler(policy_name, base::Value::TYPE_LIST),
+ pref_path_(pref_path),
+ allow_wildcards_(allow_wildcards) {}
+
+ExtensionListPolicyHandler::~ExtensionListPolicyHandler() {}
+
+bool ExtensionListPolicyHandler::CheckPolicySettings(
+ const policy::PolicyMap& policies,
+ policy::PolicyErrorMap* errors) {
+ return CheckAndGetList(policies, errors, NULL);
+}
+
+void ExtensionListPolicyHandler::ApplyPolicySettings(
+ const policy::PolicyMap& policies,
+ PrefValueMap* prefs) {
+ scoped_ptr<base::ListValue> list;
+ policy::PolicyErrorMap errors;
+ if (CheckAndGetList(policies, &errors, &list) && list)
+ prefs->SetValue(pref_path(), list.release());
+}
+
+const char* ExtensionListPolicyHandler::pref_path() const {
+ return pref_path_;
+}
+
+bool ExtensionListPolicyHandler::CheckAndGetList(
+ const policy::PolicyMap& policies,
+ policy::PolicyErrorMap* errors,
+ scoped_ptr<base::ListValue>* extension_ids) {
+ if (extension_ids)
+ extension_ids->reset();
+
+ const base::Value* value = NULL;
+ if (!CheckAndGetValue(policies, errors, &value))
+ return false;
+
+ if (!value)
+ return true;
+
+ const base::ListValue* list_value = NULL;
+ if (!value->GetAsList(&list_value)) {
+ NOTREACHED();
+ return false;
+ }
+
+ // Filter the list, rejecting any invalid extension IDs.
+ scoped_ptr<base::ListValue> filtered_list(new base::ListValue());
+ for (base::ListValue::const_iterator entry(list_value->begin());
+ entry != list_value->end(); ++entry) {
+ std::string id;
+ if (!(*entry)->GetAsString(&id)) {
+ errors->AddError(policy_name(),
+ entry - list_value->begin(),
+ IDS_POLICY_TYPE_ERROR,
+ ValueTypeToString(base::Value::TYPE_STRING));
+ continue;
+ }
+ if (!(allow_wildcards_ && id == "*") &&
+ !extensions::Extension::IdIsValid(id)) {
+ errors->AddError(policy_name(),
+ entry - list_value->begin(),
+ IDS_POLICY_VALUE_FORMAT_ERROR);
+ continue;
+ }
+ filtered_list->Append(base::Value::CreateStringValue(id));
+ }
+
+ if (extension_ids)
+ *extension_ids = filtered_list.Pass();
+
+ return true;
+}
+
+// ExtensionInstallForcelistPolicyHandler implementation -----------------------
+
+ExtensionInstallForcelistPolicyHandler::ExtensionInstallForcelistPolicyHandler()
+ : policy::TypeCheckingPolicyHandler(policy::key::kExtensionInstallForcelist,
+ base::Value::TYPE_LIST) {}
+
+ExtensionInstallForcelistPolicyHandler::
+ ~ExtensionInstallForcelistPolicyHandler() {}
+
+bool ExtensionInstallForcelistPolicyHandler::CheckPolicySettings(
+ const policy::PolicyMap& policies,
+ policy::PolicyErrorMap* errors) {
+ const base::Value* value;
+ return CheckAndGetValue(policies, errors, &value) &&
+ ParseList(value, NULL, errors);
+}
+
+void ExtensionInstallForcelistPolicyHandler::ApplyPolicySettings(
+ const policy::PolicyMap& policies,
+ PrefValueMap* prefs) {
+ const base::Value* value = NULL;
+ scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
+ if (CheckAndGetValue(policies, NULL, &value) &&
+ value &&
+ ParseList(value, dict.get(), NULL)) {
+ prefs->SetValue(prefs::kExtensionInstallForceList, dict.release());
+ }
+}
+
+bool ExtensionInstallForcelistPolicyHandler::ParseList(
+ const base::Value* policy_value,
+ base::DictionaryValue* extension_dict,
+ policy::PolicyErrorMap* errors) {
+ if (!policy_value)
+ return true;
+
+ const base::ListValue* policy_list_value = NULL;
+ if (!policy_value->GetAsList(&policy_list_value)) {
+ // This should have been caught in CheckPolicySettings.
+ NOTREACHED();
+ return false;
+ }
+
+ for (base::ListValue::const_iterator entry(policy_list_value->begin());
+ entry != policy_list_value->end(); ++entry) {
+ std::string entry_string;
+ if (!(*entry)->GetAsString(&entry_string)) {
+ if (errors) {
+ errors->AddError(policy_name(),
+ entry - policy_list_value->begin(),
+ IDS_POLICY_TYPE_ERROR,
+ ValueTypeToString(base::Value::TYPE_STRING));
+ }
+ continue;
+ }
+
+ // Each string item of the list has the following form:
+ // <extension_id>;<update_url>
+ // Note: The update URL might also contain semicolons.
+ size_t pos = entry_string.find(';');
+ if (pos == std::string::npos) {
+ if (errors) {
+ errors->AddError(policy_name(),
+ entry - policy_list_value->begin(),
+ IDS_POLICY_VALUE_FORMAT_ERROR);
+ }
+ continue;
+ }
+
+ std::string extension_id = entry_string.substr(0, pos);
+ std::string update_url = entry_string.substr(pos+1);
+ if (!extensions::Extension::IdIsValid(extension_id) ||
+ !GURL(update_url).is_valid()) {
+ if (errors) {
+ errors->AddError(policy_name(),
+ entry - policy_list_value->begin(),
+ IDS_POLICY_VALUE_FORMAT_ERROR);
+ }
+ continue;
+ }
+
+ if (extension_dict) {
+ extensions::ExternalPolicyLoader::AddExtension(
+ extension_dict, extension_id, update_url);
+ }
+ }
+
+ return true;
+}
+
+// ExtensionURLPatternListPolicyHandler implementation -------------------------
+
+ExtensionURLPatternListPolicyHandler::ExtensionURLPatternListPolicyHandler(
+ const char* policy_name,
+ const char* pref_path)
+ : policy::TypeCheckingPolicyHandler(policy_name, base::Value::TYPE_LIST),
+ pref_path_(pref_path) {}
+
+ExtensionURLPatternListPolicyHandler::~ExtensionURLPatternListPolicyHandler() {}
+
+bool ExtensionURLPatternListPolicyHandler::CheckPolicySettings(
+ const policy::PolicyMap& policies,
+ policy::PolicyErrorMap* errors) {
+ const base::Value* value = NULL;
+ if (!CheckAndGetValue(policies, errors, &value))
+ return false;
+
+ if (!value)
+ return true;
+
+ const base::ListValue* list_value = NULL;
+ if (!value->GetAsList(&list_value)) {
+ NOTREACHED();
+ return false;
+ }
+
+ // Check that the list contains valid URLPattern strings only.
+ for (base::ListValue::const_iterator entry(list_value->begin());
+ entry != list_value->end(); ++entry) {
+ std::string url_pattern_string;
+ if (!(*entry)->GetAsString(&url_pattern_string)) {
+ errors->AddError(policy_name(),
+ entry - list_value->begin(),
+ IDS_POLICY_TYPE_ERROR,
+ ValueTypeToString(base::Value::TYPE_STRING));
+ return false;
+ }
+
+ URLPattern pattern(URLPattern::SCHEME_ALL);
+ if (pattern.Parse(url_pattern_string) != URLPattern::PARSE_SUCCESS) {
+ errors->AddError(policy_name(),
+ entry - list_value->begin(),
+ IDS_POLICY_VALUE_FORMAT_ERROR);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void ExtensionURLPatternListPolicyHandler::ApplyPolicySettings(
+ const policy::PolicyMap& policies,
+ PrefValueMap* prefs) {
+ if (!pref_path_)
+ return;
+ const Value* value = policies.GetValue(policy_name());
+ if (value)
+ prefs->SetValue(pref_path_, value->DeepCopy());
+}
+
+} // namespace extensions
diff --git a/chrome/browser/extensions/policy_handlers.h b/chrome/browser/extensions/policy_handlers.h
new file mode 100644
index 0000000000..4446238e70
--- /dev/null
+++ b/chrome/browser/extensions/policy_handlers.h
@@ -0,0 +1,93 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_POLICY_HANDLERS_H_
+#define CHROME_BROWSER_EXTENSIONS_POLICY_HANDLERS_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+#include "chrome/browser/policy/configuration_policy_handler.h"
+
+namespace policy {
+class PolicyMap;
+class PolicyErrorMap;
+} // namespace policy
+
+namespace extensions {
+
+// Implements additional checks for policies that are lists of extension IDs.
+class ExtensionListPolicyHandler
+ : public policy::TypeCheckingPolicyHandler {
+ public:
+ ExtensionListPolicyHandler(const char* policy_name,
+ const char* pref_path,
+ bool allow_wildcards);
+ virtual ~ExtensionListPolicyHandler();
+
+ // ConfigurationPolicyHandler methods:
+ virtual bool CheckPolicySettings(const policy::PolicyMap& policies,
+ policy::PolicyErrorMap* errors) OVERRIDE;
+ virtual void ApplyPolicySettings(const policy::PolicyMap& policies,
+ PrefValueMap* prefs) OVERRIDE;
+
+ protected:
+ const char* pref_path() const;
+
+ // Runs sanity checks on the policy value and returns it in |extension_ids|.
+ bool CheckAndGetList(const policy::PolicyMap& policies,
+ policy::PolicyErrorMap* errors,
+ scoped_ptr<base::ListValue>* extension_ids);
+
+ private:
+ const char* pref_path_;
+ bool allow_wildcards_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExtensionListPolicyHandler);
+};
+
+class ExtensionInstallForcelistPolicyHandler
+ : public policy::TypeCheckingPolicyHandler {
+ public:
+ ExtensionInstallForcelistPolicyHandler();
+ virtual ~ExtensionInstallForcelistPolicyHandler();
+
+ // ConfigurationPolicyHandler methods:
+ virtual bool CheckPolicySettings(const policy::PolicyMap& policies,
+ policy::PolicyErrorMap* errors) OVERRIDE;
+ virtual void ApplyPolicySettings(const policy::PolicyMap& policies,
+ PrefValueMap* prefs) OVERRIDE;
+
+ private:
+ // Parses the data in |policy_value| and writes them to |extension_dict|.
+ bool ParseList(const base::Value* policy_value,
+ base::DictionaryValue* extension_dict,
+ policy::PolicyErrorMap* errors);
+
+ DISALLOW_COPY_AND_ASSIGN(ExtensionInstallForcelistPolicyHandler);
+};
+
+// Implements additional checks for policies that are lists of extension
+// URLPatterns.
+class ExtensionURLPatternListPolicyHandler
+ : public policy::TypeCheckingPolicyHandler {
+ public:
+ ExtensionURLPatternListPolicyHandler(const char* policy_name,
+ const char* pref_path);
+ virtual ~ExtensionURLPatternListPolicyHandler();
+
+ // ConfigurationPolicyHandler methods:
+ virtual bool CheckPolicySettings(const policy::PolicyMap& policies,
+ policy::PolicyErrorMap* errors) OVERRIDE;
+ virtual void ApplyPolicySettings(const policy::PolicyMap& policies,
+ PrefValueMap* prefs) OVERRIDE;
+
+ private:
+ const char* pref_path_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExtensionURLPatternListPolicyHandler);
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_POLICY_HANDLERS_H_
diff --git a/chrome/browser/extensions/policy_handlers_unittest.cc b/chrome/browser/extensions/policy_handlers_unittest.cc
new file mode 100644
index 0000000000..14b8409ba5
--- /dev/null
+++ b/chrome/browser/extensions/policy_handlers_unittest.cc
@@ -0,0 +1,283 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/pref_value_map.h"
+#include "chrome/browser/extensions/external_policy_loader.h"
+#include "chrome/browser/extensions/policy_handlers.h"
+#include "chrome/browser/policy/policy_error_map.h"
+#include "chrome/browser/policy/policy_map.h"
+#include "chrome/common/pref_names.h"
+#include "policy/policy_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+
+const char kTestPref[] = "unit_test.test_pref";
+
+TEST(ExtensionListPolicyHandlerTest, CheckPolicySettings) {
+ base::ListValue list;
+ policy::PolicyMap policy_map;
+ policy::PolicyErrorMap errors;
+ ExtensionListPolicyHandler handler(
+ policy::key::kExtensionInstallBlacklist, kTestPref, true);
+
+ policy_map.Set(policy::key::kExtensionInstallBlacklist,
+ policy::POLICY_LEVEL_MANDATORY,
+ policy::POLICY_SCOPE_USER,
+ list.DeepCopy(),
+ NULL);
+ errors.Clear();
+ EXPECT_TRUE(handler.CheckPolicySettings(policy_map, &errors));
+ EXPECT_TRUE(errors.empty());
+
+ list.Append(Value::CreateStringValue("abcdefghijklmnopabcdefghijklmnop"));
+ policy_map.Set(policy::key::kExtensionInstallBlacklist,
+ policy::POLICY_LEVEL_MANDATORY,
+ policy::POLICY_SCOPE_USER,
+ list.DeepCopy(),
+ NULL);
+ errors.Clear();
+ EXPECT_TRUE(handler.CheckPolicySettings(policy_map, &errors));
+ EXPECT_TRUE(errors.empty());
+
+ list.Append(Value::CreateStringValue("*"));
+ policy_map.Set(policy::key::kExtensionInstallBlacklist,
+ policy::POLICY_LEVEL_MANDATORY,
+ policy::POLICY_SCOPE_USER,
+ list.DeepCopy(),
+ NULL);
+ errors.Clear();
+ EXPECT_TRUE(handler.CheckPolicySettings(policy_map, &errors));
+ EXPECT_TRUE(errors.empty());
+
+ list.Append(Value::CreateStringValue("invalid"));
+ policy_map.Set(policy::key::kExtensionInstallBlacklist,
+ policy::POLICY_LEVEL_MANDATORY,
+ policy::POLICY_SCOPE_USER,
+ list.DeepCopy(),
+ NULL);
+ errors.Clear();
+ EXPECT_TRUE(handler.CheckPolicySettings(policy_map, &errors));
+ EXPECT_FALSE(errors.empty());
+ EXPECT_FALSE(
+ errors.GetErrors(policy::key::kExtensionInstallBlacklist).empty());
+}
+
+TEST(ExtensionListPolicyHandlerTest, ApplyPolicySettings) {
+ base::ListValue policy;
+ base::ListValue expected;
+ policy::PolicyMap policy_map;
+ PrefValueMap prefs;
+ base::Value* value = NULL;
+ ExtensionListPolicyHandler handler(
+ policy::key::kExtensionInstallBlacklist, kTestPref, false);
+
+ policy.Append(Value::CreateStringValue("abcdefghijklmnopabcdefghijklmnop"));
+ expected.Append(Value::CreateStringValue("abcdefghijklmnopabcdefghijklmnop"));
+
+ policy_map.Set(policy::key::kExtensionInstallBlacklist,
+ policy::POLICY_LEVEL_MANDATORY,
+ policy::POLICY_SCOPE_USER,
+ policy.DeepCopy(),
+ NULL);
+ handler.ApplyPolicySettings(policy_map, &prefs);
+ EXPECT_TRUE(prefs.GetValue(kTestPref, &value));
+ EXPECT_TRUE(base::Value::Equals(&expected, value));
+
+ policy.Append(Value::CreateStringValue("invalid"));
+ policy_map.Set(policy::key::kExtensionInstallBlacklist,
+ policy::POLICY_LEVEL_MANDATORY,
+ policy::POLICY_SCOPE_USER,
+ policy.DeepCopy(),
+ NULL);
+ handler.ApplyPolicySettings(policy_map, &prefs);
+ EXPECT_TRUE(prefs.GetValue(kTestPref, &value));
+ EXPECT_TRUE(base::Value::Equals(&expected, value));
+}
+
+TEST(ExtensionInstallForcelistPolicyHandlerTest, CheckPolicySettings) {
+ base::ListValue list;
+ policy::PolicyMap policy_map;
+ policy::PolicyErrorMap errors;
+ ExtensionInstallForcelistPolicyHandler handler;
+
+ policy_map.Set(policy::key::kExtensionInstallForcelist,
+ policy::POLICY_LEVEL_MANDATORY,
+ policy::POLICY_SCOPE_USER,
+ list.DeepCopy(),
+ NULL);
+ errors.Clear();
+ EXPECT_TRUE(handler.CheckPolicySettings(policy_map, &errors));
+ EXPECT_TRUE(errors.empty());
+
+ list.AppendString("abcdefghijklmnopabcdefghijklmnop;http://example.com");
+ policy_map.Set(policy::key::kExtensionInstallForcelist,
+ policy::POLICY_LEVEL_MANDATORY,
+ policy::POLICY_SCOPE_USER,
+ list.DeepCopy(),
+ NULL);
+ errors.Clear();
+ EXPECT_TRUE(handler.CheckPolicySettings(policy_map, &errors));
+ EXPECT_TRUE(errors.empty());
+
+ // Add an erroneous entry. This should generate an error, but the good
+ // entry should still be translated successfully.
+ list.AppendString("adfasdf;http://example.com");
+ policy_map.Set(policy::key::kExtensionInstallForcelist,
+ policy::POLICY_LEVEL_MANDATORY,
+ policy::POLICY_SCOPE_USER,
+ list.DeepCopy(),
+ NULL);
+ errors.Clear();
+ EXPECT_TRUE(handler.CheckPolicySettings(policy_map, &errors));
+ EXPECT_EQ(1U, errors.size());
+
+ // Add an entry with bad URL, which should generate another error.
+ list.AppendString("abcdefghijklmnopabcdefghijklmnop;nourl");
+ policy_map.Set(policy::key::kExtensionInstallForcelist,
+ policy::POLICY_LEVEL_MANDATORY,
+ policy::POLICY_SCOPE_USER,
+ list.DeepCopy(),
+ NULL);
+ errors.Clear();
+ EXPECT_TRUE(handler.CheckPolicySettings(policy_map, &errors));
+ EXPECT_EQ(2U, errors.size());
+
+ // Just an extension ID should also generate an error.
+ list.AppendString("abcdefghijklmnopabcdefghijklmnop");
+ policy_map.Set(policy::key::kExtensionInstallForcelist,
+ policy::POLICY_LEVEL_MANDATORY,
+ policy::POLICY_SCOPE_USER,
+ list.DeepCopy(),
+ NULL);
+ errors.Clear();
+ EXPECT_TRUE(handler.CheckPolicySettings(policy_map, &errors));
+ EXPECT_EQ(3U, errors.size());
+}
+
+TEST(ExtensionInstallForcelistPolicyHandlerTest, ApplyPolicySettings) {
+ base::ListValue policy;
+ base::DictionaryValue expected;
+ policy::PolicyMap policy_map;
+ PrefValueMap prefs;
+ base::Value* value = NULL;
+ ExtensionInstallForcelistPolicyHandler handler;
+
+ handler.ApplyPolicySettings(policy_map, &prefs);
+ EXPECT_FALSE(prefs.GetValue(prefs::kExtensionInstallForceList, &value));
+ EXPECT_FALSE(value);
+
+ policy_map.Set(policy::key::kExtensionInstallForcelist,
+ policy::POLICY_LEVEL_MANDATORY,
+ policy::POLICY_SCOPE_USER,
+ policy.DeepCopy(),
+ NULL);
+ handler.ApplyPolicySettings(policy_map, &prefs);
+ EXPECT_TRUE(prefs.GetValue(prefs::kExtensionInstallForceList, &value));
+ EXPECT_TRUE(base::Value::Equals(&expected, value));
+
+ policy.AppendString("abcdefghijklmnopabcdefghijklmnop;http://example.com");
+ extensions::ExternalPolicyLoader::AddExtension(
+ &expected, "abcdefghijklmnopabcdefghijklmnop", "http://example.com");
+ policy_map.Set(policy::key::kExtensionInstallForcelist,
+ policy::POLICY_LEVEL_MANDATORY,
+ policy::POLICY_SCOPE_USER,
+ policy.DeepCopy(),
+ NULL);
+ handler.ApplyPolicySettings(policy_map, &prefs);
+ EXPECT_TRUE(prefs.GetValue(prefs::kExtensionInstallForceList, &value));
+ EXPECT_TRUE(base::Value::Equals(&expected, value));
+
+ policy.AppendString("invalid");
+ policy_map.Set(policy::key::kExtensionInstallForcelist,
+ policy::POLICY_LEVEL_MANDATORY,
+ policy::POLICY_SCOPE_USER,
+ policy.DeepCopy(),
+ NULL);
+ handler.ApplyPolicySettings(policy_map, &prefs);
+ EXPECT_TRUE(prefs.GetValue(prefs::kExtensionInstallForceList, &value));
+ EXPECT_TRUE(base::Value::Equals(&expected, value));
+}
+
+TEST(ExtensionURLPatternListPolicyHandlerTest, CheckPolicySettings) {
+ base::ListValue list;
+ policy::PolicyMap policy_map;
+ policy::PolicyErrorMap errors;
+ ExtensionURLPatternListPolicyHandler handler(
+ policy::key::kExtensionInstallSources, kTestPref);
+
+ policy_map.Set(policy::key::kExtensionInstallSources,
+ policy::POLICY_LEVEL_MANDATORY,
+ policy::POLICY_SCOPE_USER,
+ list.DeepCopy(),
+ NULL);
+ errors.Clear();
+ EXPECT_TRUE(handler.CheckPolicySettings(policy_map, &errors));
+ EXPECT_TRUE(errors.empty());
+
+ list.Append(Value::CreateStringValue("http://*.google.com/*"));
+ policy_map.Set(policy::key::kExtensionInstallSources,
+ policy::POLICY_LEVEL_MANDATORY,
+ policy::POLICY_SCOPE_USER,
+ list.DeepCopy(),
+ NULL);
+ errors.Clear();
+ EXPECT_TRUE(handler.CheckPolicySettings(policy_map, &errors));
+ EXPECT_TRUE(errors.empty());
+
+ list.Append(Value::CreateStringValue("<all_urls>"));
+ policy_map.Set(policy::key::kExtensionInstallSources,
+ policy::POLICY_LEVEL_MANDATORY,
+ policy::POLICY_SCOPE_USER,
+ list.DeepCopy(),
+ NULL);
+ errors.Clear();
+ EXPECT_TRUE(handler.CheckPolicySettings(policy_map, &errors));
+ EXPECT_TRUE(errors.empty());
+
+ list.Append(Value::CreateStringValue("invalid"));
+ policy_map.Set(policy::key::kExtensionInstallSources,
+ policy::POLICY_LEVEL_MANDATORY,
+ policy::POLICY_SCOPE_USER,
+ list.DeepCopy(),
+ NULL);
+ errors.Clear();
+ EXPECT_FALSE(handler.CheckPolicySettings(policy_map, &errors));
+ EXPECT_FALSE(errors.empty());
+ EXPECT_FALSE(errors.GetErrors(policy::key::kExtensionInstallSources).empty());
+
+ // URLPattern syntax has a different way to express 'all urls'. Though '*'
+ // would be compatible today, it would be brittle, so we disallow.
+ list.Append(Value::CreateStringValue("*"));
+ policy_map.Set(policy::key::kExtensionInstallSources,
+ policy::POLICY_LEVEL_MANDATORY,
+ policy::POLICY_SCOPE_USER,
+ list.DeepCopy(),
+ NULL);
+ errors.Clear();
+ EXPECT_FALSE(handler.CheckPolicySettings(policy_map, &errors));
+ EXPECT_FALSE(errors.empty());
+ EXPECT_FALSE(errors.GetErrors(policy::key::kExtensionInstallSources).empty());
+}
+
+TEST(ExtensionURLPatternListPolicyHandlerTest, ApplyPolicySettings) {
+ base::ListValue list;
+ policy::PolicyMap policy_map;
+ PrefValueMap prefs;
+ base::Value* value = NULL;
+ ExtensionURLPatternListPolicyHandler handler(
+ policy::key::kExtensionInstallSources, kTestPref);
+
+ list.Append(Value::CreateStringValue("https://corp.monkey.net/*"));
+ policy_map.Set(policy::key::kExtensionInstallSources,
+ policy::POLICY_LEVEL_MANDATORY,
+ policy::POLICY_SCOPE_USER,
+ list.DeepCopy(),
+ NULL);
+ handler.ApplyPolicySettings(policy_map, &prefs);
+ ASSERT_TRUE(prefs.GetValue(kTestPref, &value));
+ EXPECT_TRUE(base::Value::Equals(&list, value));
+}
+
+} // namespace extensions
diff --git a/chrome/browser/extensions/user_script_master.cc b/chrome/browser/extensions/user_script_master.cc
index 95b8f6aa33..4a9ff1ca01 100644
--- a/chrome/browser/extensions/user_script_master.cc
+++ b/chrome/browser/extensions/user_script_master.cc
@@ -19,6 +19,7 @@
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/extensions/image_loader.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/api/i18n/default_locale_handler.h"
@@ -373,8 +374,9 @@ void UserScriptMaster::Observe(int type,
extensions_info_[extension->id()] =
ExtensionSet::ExtensionPathAndDefaultLocale(
extension->path(), LocaleInfo::GetDefaultLocale(extension));
- bool incognito_enabled = extensions::ExtensionSystem::Get(profile_)->
- extension_service()->IsIncognitoEnabled(extension->id());
+ bool incognito_enabled = extension_util::IsIncognitoEnabled(
+ extension->id(),
+ extensions::ExtensionSystem::Get(profile_)->extension_service());
const UserScriptList& scripts =
ContentScriptsInfo::GetContentScripts(extension);
for (UserScriptList::const_iterator iter = scripts.begin();
diff --git a/chrome/browser/extensions/webstore_installer.cc b/chrome/browser/extensions/webstore_installer.cc
index ab1d1c907e..5bf00a9447 100644
--- a/chrome/browser/extensions/webstore_installer.cc
+++ b/chrome/browser/extensions/webstore_installer.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/extensions/webstore_installer.h"
+#include <vector>
+
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/command_line.h"
@@ -19,6 +21,7 @@
#include "chrome/browser/download/download_prefs.h"
#include "chrome/browser/download/download_stats.h"
#include "chrome/browser/extensions/crx_installer.h"
+#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/extensions/install_tracker.h"
#include "chrome/browser/extensions/install_tracker_factory.h"
#include "chrome/browser/profiles/profile.h"
@@ -27,6 +30,7 @@
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
+#include "chrome/common/extensions/manifest_handlers/shared_module_info.h"
#include "chrome/common/omaha_query_params/omaha_query_params.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/download_manager.h"
@@ -68,6 +72,9 @@ const char kInstallCanceledError[] = "Install canceled";
const char kDownloadInterruptedError[] = "Download interrupted";
const char kInvalidDownloadError[] =
"Download was not a valid extension or user script";
+const char kDependencyNotFoundError[] = "Dependency not found";
+const char kDependencyNotSharedModuleError[] =
+ "Dependency is not shared module";
const char kInlineInstallSource[] = "inline";
const char kDefaultInstallSource[] = "ondemand";
const char kAppLauncherInstallSource[] = "applauncher";
@@ -124,7 +131,19 @@ namespace extensions {
// static
GURL WebstoreInstaller::GetWebstoreInstallURL(
- const std::string& extension_id, const std::string& install_source) {
+ const std::string& extension_id, InstallSource source) {
+ std::string install_source;
+ switch (source) {
+ case INSTALL_SOURCE_INLINE:
+ install_source = kInlineInstallSource;
+ break;
+ case INSTALL_SOURCE_APP_LAUNCHER:
+ install_source = kAppLauncherInstallSource;
+ break;
+ case INSTALL_SOURCE_OTHER:
+ install_source = kDefaultInstallSource;
+ }
+
CommandLine* cmd_line = CommandLine::ForCurrentProcess();
if (cmd_line->HasSwitch(switches::kAppsGalleryDownloadURL)) {
std::string download_url =
@@ -164,7 +183,7 @@ WebstoreInstaller::Approval::Approval()
skip_post_install_ui(false),
skip_install_dialog(false),
enable_launcher(false),
- strict_manifest_check(true) {
+ manifest_check_level(MANIFEST_CHECK_LEVEL_STRICT) {
}
scoped_ptr<WebstoreInstaller::Approval>
@@ -175,6 +194,15 @@ WebstoreInstaller::Approval::CreateWithInstallPrompt(Profile* profile) {
}
scoped_ptr<WebstoreInstaller::Approval>
+WebstoreInstaller::Approval::CreateForSharedModule(Profile* profile) {
+ scoped_ptr<Approval> result(new Approval());
+ result->profile = profile;
+ result->skip_install_dialog = true;
+ result->manifest_check_level = MANIFEST_CHECK_LEVEL_NONE;
+ return result.Pass();
+}
+
+scoped_ptr<WebstoreInstaller::Approval>
WebstoreInstaller::Approval::CreateWithNoInstallPrompt(
Profile* profile,
const std::string& extension_id,
@@ -187,7 +215,8 @@ WebstoreInstaller::Approval::CreateWithNoInstallPrompt(
new Manifest(Manifest::INVALID_LOCATION,
scoped_ptr<DictionaryValue>(parsed_manifest->DeepCopy())));
result->skip_install_dialog = true;
- result->strict_manifest_check = strict_manifest_check;
+ result->manifest_check_level = strict_manifest_check ?
+ MANIFEST_CHECK_LEVEL_STRICT : MANIFEST_CHECK_LEVEL_LOOSE;
return result.Pass();
}
@@ -208,25 +237,14 @@ WebstoreInstaller::WebstoreInstaller(Profile* profile,
delegate_(delegate),
controller_(controller),
id_(id),
+ install_source_(source),
download_item_(NULL),
- approval_(approval.release()) {
+ approval_(approval.release()),
+ total_modules_(0),
+ download_started_(false) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(controller_);
- const char* install_source = "";
- switch (source) {
- case INSTALL_SOURCE_INLINE:
- install_source = kInlineInstallSource;
- break;
- case INSTALL_SOURCE_APP_LAUNCHER:
- install_source = kAppLauncherInstallSource;
- break;
- case INSTALL_SOURCE_OTHER:
- install_source = kDefaultInstallSource;
- }
-
- download_url_ = GetWebstoreInstallURL(id, install_source);
-
registrar_.Add(this, chrome::NOTIFICATION_CRX_INSTALLER_DONE,
content::NotificationService::AllSources());
registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED,
@@ -244,12 +262,30 @@ void WebstoreInstaller::Start() {
return;
}
- base::FilePath download_path = DownloadPrefs::FromDownloadManager(
- BrowserContext::GetDownloadManager(profile_))->DownloadPath();
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(&GetDownloadFilePath, download_path, id_,
- base::Bind(&WebstoreInstaller::StartDownload, this)));
+ ExtensionService* extension_service =
+ ExtensionSystem::Get(profile_)->extension_service();
+ if (approval_.get() && approval_->dummy_extension) {
+ ExtensionService::ImportStatus status =
+ extension_service->CheckImports(approval_->dummy_extension,
+ &pending_modules_, &pending_modules_);
+ // For this case, it is because some imports are not shared modules.
+ if (status == ExtensionService::IMPORT_STATUS_UNRECOVERABLE) {
+ ReportFailure(kDependencyNotSharedModuleError,
+ FAILURE_REASON_DEPENDENCY_NOT_SHARED_MODULE);
+ return;
+ }
+ }
+
+ // Add the extension main module into the list.
+ SharedModuleInfo::ImportInfo info;
+ info.extension_id = id_;
+ pending_modules_.push_back(info);
+
+ total_modules_ = pending_modules_.size();
+
+ // TODO(crbug.com/305343): Query manifest of dependencises before
+ // downloading & installing those dependencies.
+ DownloadNextPendingModule();
std::string name;
if (!approval_->manifest->value()->GetString(manifest_keys::kName, &name)) {
@@ -282,8 +318,31 @@ void WebstoreInstaller::Observe(int type,
CHECK(profile_->IsSameProfile(content::Source<Profile>(source).ptr()));
const Extension* extension =
content::Details<const InstalledExtensionInfo>(details)->extension;
- if (id_ == extension->id())
+ CHECK(!pending_modules_.empty());
+ SharedModuleInfo::ImportInfo info = pending_modules_.front();
+ pending_modules_.pop_front();
+ CHECK_EQ(extension->id(), info.extension_id);
+
+ if (pending_modules_.empty()) {
+ CHECK_EQ(extension->id(), id_);
ReportSuccess();
+ } else {
+ const Version version_required(info.minimum_version);
+ if (version_required.IsValid() &&
+ extension->version()->CompareTo(version_required) < 0) {
+ // It should not happen, CrxInstaller will make sure the version is
+ // equal or newer than version_required.
+ ReportFailure(kDependencyNotFoundError,
+ FAILURE_REASON_DEPENDENCY_NOT_FOUND);
+ } else if (!SharedModuleInfo::IsSharedModule(extension)) {
+ // It should not happen, CrxInstaller will make sure it is a shared
+ // module.
+ ReportFailure(kDependencyNotSharedModuleError,
+ FAILURE_REASON_DEPENDENCY_NOT_SHARED_MODULE);
+ } else {
+ DownloadNextPendingModule();
+ }
+ }
break;
}
@@ -333,12 +392,33 @@ void WebstoreInstaller::OnDownloadStarted(
}
DCHECK_EQ(net::OK, error);
+ DCHECK(!pending_modules_.empty());
download_item_ = item;
download_item_->AddObserver(this);
- if (approval_)
- download_item_->SetUserData(kApprovalKey, approval_.release());
- if (delegate_)
- delegate_->OnExtensionDownloadStarted(id_, download_item_);
+ if (pending_modules_.size() > 1) {
+ // We are downloading a shared module. We need create an approval for it.
+ scoped_ptr<Approval> approval = Approval::CreateForSharedModule(profile_);
+ const SharedModuleInfo::ImportInfo& info = pending_modules_.front();
+ approval->extension_id = info.extension_id;
+ const Version version_required(info.minimum_version);
+
+ if (version_required.IsValid()) {
+ approval->minimum_version.reset(
+ new Version(version_required));
+ }
+ download_item_->SetUserData(kApprovalKey, approval.release());
+ } else {
+ // It is for the main module of the extension. We should use the provided
+ // |approval_|.
+ if (approval_)
+ download_item_->SetUserData(kApprovalKey, approval_.release());
+ }
+
+ if (!download_started_) {
+ if (delegate_)
+ delegate_->OnExtensionDownloadStarted(id_, download_item_);
+ download_started_ = true;
+ }
}
void WebstoreInstaller::OnDownloadUpdated(DownloadItem* download) {
@@ -355,23 +435,29 @@ void WebstoreInstaller::OnDownloadUpdated(DownloadItem* download) {
// Wait for other notifications if the download is really an extension.
if (!download_crx_util::IsExtensionDownload(*download)) {
ReportFailure(kInvalidDownloadError, FAILURE_REASON_OTHER);
- } else {
+ } else if (pending_modules_.empty()) {
+ // The download is the last module - the extension main module.
if (delegate_)
delegate_->OnExtensionDownloadProgress(id_, download);
-
extensions::InstallTracker* tracker =
extensions::InstallTrackerFactory::GetForProfile(profile_);
tracker->OnDownloadProgress(id_, 100);
}
break;
case DownloadItem::IN_PROGRESS: {
- if (delegate_)
+ if (delegate_ && pending_modules_.size() == 1) {
+ // Only report download progress for the main module to |delegrate_|.
delegate_->OnExtensionDownloadProgress(id_, download);
-
- extensions::InstallTracker* tracker =
+ }
+ int percent = download->PercentComplete();
+ // Only report progress if precent is more than 0
+ if (percent >= 0) {
+ int finished_modules = total_modules_ - pending_modules_.size();
+ percent = (percent + finished_modules * 100) / total_modules_;
+ extensions::InstallTracker* tracker =
extensions::InstallTrackerFactory::GetForProfile(profile_);
- tracker->OnDownloadProgress(id_, download->PercentComplete());
-
+ tracker->OnDownloadProgress(id_, percent);
+ }
break;
}
default:
@@ -386,6 +472,27 @@ void WebstoreInstaller::OnDownloadDestroyed(DownloadItem* download) {
download_item_ = NULL;
}
+void WebstoreInstaller::DownloadNextPendingModule() {
+ CHECK(!pending_modules_.empty());
+ if (pending_modules_.size() == 1) {
+ DCHECK_EQ(id_, pending_modules_.front().extension_id);
+ DownloadCrx(id_, install_source_);
+ } else {
+ DownloadCrx(pending_modules_.front().extension_id, INSTALL_SOURCE_OTHER);
+ }
+}
+
+void WebstoreInstaller::DownloadCrx(
+ const std::string& extension_id, InstallSource source) {
+ download_url_ = GetWebstoreInstallURL(extension_id, source);
+ base::FilePath download_path = DownloadPrefs::FromDownloadManager(
+ BrowserContext::GetDownloadManager(profile_))->DownloadPath();
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ base::Bind(&GetDownloadFilePath, download_path, id_,
+ base::Bind(&WebstoreInstaller::StartDownload, this)));
+}
+
// http://crbug.com/165634
// http://crbug.com/126013
// The current working theory is that one of the many pointers dereferenced in
diff --git a/chrome/browser/extensions/webstore_installer.h b/chrome/browser/extensions/webstore_installer.h
index 629788101c..56458e2ac1 100644
--- a/chrome/browser/extensions/webstore_installer.h
+++ b/chrome/browser/extensions/webstore_installer.h
@@ -5,15 +5,17 @@
#ifndef CHROME_BROWSER_EXTENSIONS_WEBSTORE_INSTALLER_H_
#define CHROME_BROWSER_EXTENSIONS_WEBSTORE_INSTALLER_H_
+#include <list>
#include <string>
-#include <vector>
#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/supports_user_data.h"
#include "base/values.h"
+#include "base/version.h"
#include "chrome/browser/extensions/extension_install_prompt.h"
+#include "chrome/common/extensions/manifest_handlers/shared_module_info.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/download_item.h"
#include "content/public/browser/notification_observer.h"
@@ -34,6 +36,7 @@ class NavigationController;
namespace extensions {
+class Extension;
class Manifest;
// Downloads and installs extensions from the web store.
@@ -52,9 +55,23 @@ class WebstoreInstaller :public content::NotificationObserver,
enum FailureReason {
FAILURE_REASON_CANCELLED,
+ FAILURE_REASON_DEPENDENCY_NOT_FOUND,
+ FAILURE_REASON_DEPENDENCY_NOT_SHARED_MODULE,
FAILURE_REASON_OTHER
};
+ enum ManifestCheckLevel {
+ // Do not check for any manifest equality.
+ MANIFEST_CHECK_LEVEL_NONE,
+
+ // Only check that the expected and actual permissions have the same
+ // effective permissions.
+ MANIFEST_CHECK_LEVEL_LOOSE,
+
+ // All data in the expected and actual manifests must match.
+ MANIFEST_CHECK_LEVEL_STRICT,
+ };
+
class Delegate {
public:
virtual void OnExtensionDownloadStarted(const std::string& id,
@@ -77,6 +94,9 @@ class WebstoreInstaller :public content::NotificationObserver,
struct Approval : public base::SupportsUserData::Data {
static scoped_ptr<Approval> CreateWithInstallPrompt(Profile* profile);
+ // Creates an Approval for installing a shared module.
+ static scoped_ptr<Approval> CreateForSharedModule(Profile* profile);
+
// Creates an Approval that will skip putting up an install confirmation
// prompt if the actual manifest from the extension to be installed matches
// |parsed_manifest|. The |strict_manifest_check| controls whether we want
@@ -115,9 +135,9 @@ class WebstoreInstaller :public content::NotificationObserver,
// Whether we should enable the launcher before installing the app.
bool enable_launcher;
- // Whether we want a strict manifest equality check, or just want a match
- // for effective permissions.
- bool strict_manifest_check;
+ // Manifest check level for checking actual manifest against expected
+ // manifest.
+ ManifestCheckLevel manifest_check_level;
// Used to show the install dialog.
ExtensionInstallPrompt::ShowDialogCallback show_dialog_callback;
@@ -125,6 +145,12 @@ class WebstoreInstaller :public content::NotificationObserver,
// The icon to use to display the extension while it is installing.
gfx::ImageSkia installing_icon;
+ // A dummy extension created from |manifest|;
+ scoped_refptr<Extension> dummy_extension;
+
+ // Required minimum version.
+ scoped_ptr<Version> minimum_version;
+
private:
Approval();
};
@@ -173,7 +199,7 @@ class WebstoreInstaller :public content::NotificationObserver,
// Helper to get install URL.
static GURL GetWebstoreInstallURL(const std::string& extension_id,
- const std::string& install_source);
+ InstallSource source);
// DownloadManager::DownloadUrl callback.
void OnDownloadStarted(content::DownloadItem* item, net::Error error);
@@ -182,6 +208,13 @@ class WebstoreInstaller :public content::NotificationObserver,
virtual void OnDownloadUpdated(content::DownloadItem* download) OVERRIDE;
virtual void OnDownloadDestroyed(content::DownloadItem* download) OVERRIDE;
+ // Downloads next pending module in |pending_modules_|.
+ void DownloadNextPendingModule();
+
+ // Downloads and installs a single Crx with the given |extension_id|.
+ // This function is used for both the extension Crx and dependences.
+ void DownloadCrx(const std::string& extension_id, InstallSource source);
+
// Starts downloading the extension to |file_path|.
void StartDownload(const base::FilePath& file_path);
@@ -199,11 +232,19 @@ class WebstoreInstaller :public content::NotificationObserver,
Delegate* delegate_;
content::NavigationController* controller_;
std::string id_;
+ InstallSource install_source_;
// The DownloadItem is owned by the DownloadManager and is valid from when
// OnDownloadStarted is called (with no error) until OnDownloadDestroyed().
content::DownloadItem* download_item_;
scoped_ptr<Approval> approval_;
GURL download_url_;
+
+ // Pending modules.
+ std::list<SharedModuleInfo::ImportInfo> pending_modules_;
+ // Total extension modules we need download and install (the main module and
+ // depedences).
+ int total_modules_;
+ bool download_started_;
};
} // namespace extensions
diff --git a/chrome/browser/extensions/webstore_installer_unittest.cc b/chrome/browser/extensions/webstore_installer_unittest.cc
index e46dad1ec3..734013afcd 100644
--- a/chrome/browser/extensions/webstore_installer_unittest.cc
+++ b/chrome/browser/extensions/webstore_installer_unittest.cc
@@ -24,7 +24,8 @@ bool Contains(const std::string& source, const std::string& target) {
TEST(WebstoreInstallerTest, PlatformParams) {
std::string id = extensions::id_util::GenerateId("some random string");
std::string source = "inline";
- GURL url = WebstoreInstaller::GetWebstoreInstallURL(id, source);
+ GURL url = WebstoreInstaller::GetWebstoreInstallURL(id,
+ WebstoreInstaller::INSTALL_SOURCE_INLINE);
std::string query = url.query();
EXPECT_TRUE(Contains(query,StringPrintf("os=%s", OmahaQueryParams::getOS())));
EXPECT_TRUE(Contains(query,StringPrintf("arch=%s",
diff --git a/chrome/browser/extensions/webstore_startup_installer_browsertest.cc b/chrome/browser/extensions/webstore_startup_installer_browsertest.cc
index 24de760250..0451bbc9d9 100644
--- a/chrome/browser/extensions/webstore_startup_installer_browsertest.cc
+++ b/chrome/browser/extensions/webstore_startup_installer_browsertest.cc
@@ -171,8 +171,18 @@ IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallerTest, InstallFromHostedApp) {
EXPECT_TRUE(extension_service->extensions()->Contains(kTestExtensionId));
}
-IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallerTest,
- InstallProhibitedForManagedUsers) {
+class WebstoreStartupInstallerManagedUsersTest
+ : public WebstoreStartupInstallerTest {
+ public:
+ // InProcessBrowserTest overrides:
+ virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+ WebstoreStartupInstallerTest::SetUpCommandLine(command_line);
+ command_line->AppendSwitch(switches::kNewProfileIsSupervised);
+ }
+};
+
+IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallerManagedUsersTest,
+ InstallProhibited) {
#if defined(OS_WIN) && defined(USE_ASH)
// Disable this test in Metro+Ash for now (http://crbug.com/262796).
if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
@@ -182,11 +192,6 @@ IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallerTest,
CommandLine::ForCurrentProcess()->AppendSwitchASCII(
switches::kAppsGalleryInstallAutoConfirmForTests, "accept");
- // Make the profile managed such that no extension installs are allowed.
- ManagedUserService* service =
- ManagedUserServiceFactory::GetForProfile(browser()->profile());
- service->InitForTesting();
-
ui_test_utils::NavigateToURL(
browser(), GenerateTestServerUrl(kAppDomain, "install_prohibited.html"));
diff --git a/chrome/browser/extensions/window_open_apitest.cc b/chrome/browser/extensions/window_open_apitest.cc
index 1a2c61979e..5cee30edcc 100644
--- a/chrome/browser/extensions/window_open_apitest.cc
+++ b/chrome/browser/extensions/window_open_apitest.cc
@@ -442,7 +442,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, WindowOpenExtension) {
test_data_dir_.AppendASCII("uitest").AppendASCII("window_open")));
GURL start_url(std::string("chrome-extension://") +
- last_loaded_extension_id_ + "/test.html");
+ last_loaded_extension_id() + "/test.html");
ui_test_utils::NavigateToURL(browser(), start_url);
WebContents* newtab = NULL;
ASSERT_NO_FATAL_FAILURE(
@@ -462,7 +462,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, WindowOpenInvalidExtension) {
test_data_dir_.AppendASCII("uitest").AppendASCII("window_open")));
GURL start_url(std::string("chrome-extension://") +
- last_loaded_extension_id_ + "/test.html");
+ last_loaded_extension_id() + "/test.html");
ui_test_utils::NavigateToURL(browser(), start_url);
ASSERT_NO_FATAL_FAILURE(
OpenWindow(browser()->tab_strip_model()->GetActiveWebContents(),
@@ -484,7 +484,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, WindowOpenNoPrivileges) {
WebContents* newtab = NULL;
ASSERT_NO_FATAL_FAILURE(
OpenWindow(browser()->tab_strip_model()->GetActiveWebContents(),
- GURL(std::string("chrome-extension://") + last_loaded_extension_id_ +
+ GURL(std::string("chrome-extension://") + last_loaded_extension_id() +
"/newtab.html"), false, &newtab));
// Extension API should succeed.
diff --git a/chrome/browser/favicon/favicon_service.cc b/chrome/browser/favicon/favicon_service.cc
index fd0f9eb557..9f0ff332cd 100644
--- a/chrome/browser/favicon/favicon_service.cc
+++ b/chrome/browser/favicon/favicon_service.cc
@@ -45,6 +45,22 @@ CancelableTaskTracker::TaskId RunWithEmptyResultAsync(
Bind(callback, std::vector<chrome::FaviconBitmapResult>()));
}
+// Return the TaskId to retreive the favicon from chrome specific URL.
+CancelableTaskTracker::TaskId GetFaviconForChromeURL(
+ Profile* profile,
+ const GURL& page_url,
+ const std::vector<ui::ScaleFactor>& desired_scale_factors,
+ const FaviconService::FaviconResultsCallback& callback,
+ CancelableTaskTracker* tracker) {
+ CancelableTaskTracker::IsCanceledCallback is_canceled_cb;
+ CancelableTaskTracker::TaskId id = tracker->NewTrackedTaskId(&is_canceled_cb);
+ FaviconService::FaviconResultsCallback cancelable_cb =
+ Bind(&CancelOrRunFaviconResultsCallback, is_canceled_cb, callback);
+ ChromeWebUIControllerFactory::GetInstance()->GetFaviconForURL(profile,
+ page_url, desired_scale_factors, cancelable_cb);
+ return id;
+}
+
} // namespace
FaviconService::FaviconService(HistoryService* history_service)
@@ -169,6 +185,29 @@ CancelableTaskTracker::TaskId FaviconService::GetRawFaviconForURL(
tracker);
}
+CancelableTaskTracker::TaskId FaviconService::GetLargestRawFaviconForURL(
+ Profile* profile,
+ const GURL& page_url,
+ const std::vector<int>& icon_types,
+ int minimum_size_in_pixels,
+ const FaviconRawCallback& callback,
+ CancelableTaskTracker* tracker) {
+ FaviconResultsCallback favicon_results_callback =
+ Bind(&FaviconService::RunFaviconRawCallbackWithBitmapResults,
+ base::Unretained(this), callback, 0, ui::ScaleFactor());
+ if (page_url.SchemeIs(chrome::kChromeUIScheme) ||
+ page_url.SchemeIs(extensions::kExtensionScheme)) {
+ std::vector<ui::ScaleFactor> scale_factor;
+ scale_factor.push_back(ui::SCALE_FACTOR_100P);
+ return GetFaviconForChromeURL(profile, page_url, scale_factor,
+ favicon_results_callback, tracker);
+ } else if (history_service_) {
+ return history_service_->GetLargestFaviconForURL(page_url, icon_types,
+ minimum_size_in_pixels, callback, tracker);
+ }
+ return RunWithEmptyResultAsync(favicon_results_callback, tracker);
+}
+
CancelableTaskTracker::TaskId FaviconService::GetFaviconForURL(
const FaviconForURLParams& params,
const FaviconResultsCallback& callback,
@@ -284,15 +323,8 @@ CancelableTaskTracker::TaskId FaviconService::GetFaviconForURLImpl(
CancelableTaskTracker* tracker) {
if (params.page_url.SchemeIs(chrome::kChromeUIScheme) ||
params.page_url.SchemeIs(extensions::kExtensionScheme)) {
- CancelableTaskTracker::IsCanceledCallback is_canceled_cb;
- CancelableTaskTracker::TaskId id =
- tracker->NewTrackedTaskId(&is_canceled_cb);
-
- FaviconResultsCallback cancelable_cb =
- Bind(&CancelOrRunFaviconResultsCallback, is_canceled_cb, callback);
- ChromeWebUIControllerFactory::GetInstance()->GetFaviconForURL(
- params.profile, params.page_url, desired_scale_factors, cancelable_cb);
- return id;
+ return GetFaviconForChromeURL(params.profile, params.page_url,
+ desired_scale_factors, callback, tracker);
} else if (history_service_) {
return history_service_->GetFaviconsForURL(params.page_url,
params.icon_types,
@@ -300,9 +332,8 @@ CancelableTaskTracker::TaskId FaviconService::GetFaviconForURLImpl(
desired_scale_factors,
callback,
tracker);
- } else {
- return RunWithEmptyResultAsync(callback, tracker);
}
+ return RunWithEmptyResultAsync(callback, tracker);
}
void FaviconService::RunFaviconImageCallbackWithBitmapResults(
diff --git a/chrome/browser/favicon/favicon_service.h b/chrome/browser/favicon/favicon_service.h
index 692a6ebe74..ed1bc3d249 100644
--- a/chrome/browser/favicon/favicon_service.h
+++ b/chrome/browser/favicon/favicon_service.h
@@ -67,11 +67,9 @@ class FaviconService : public CancelableRequestProvider,
typedef base::Callback<void(const chrome::FaviconImageResult&)>
FaviconImageCallback;
- // Callback for GetRawFavicon() and GetRawFaviconForURL().
- // FaviconBitmapResult::bitmap_data is the bitmap in the thumbnail database
- // for the passed in URL and icon types whose pixel size best matches the
- // passed in |desired_size_in_dip| and |desired_scale_factor|. Returns an
- // invalid chrome::FaviconBitmapResult if there are no matches.
+ // Callback for GetRawFavicon(), GetRawFaviconForURL() and
+ // GetLargestRawFavicon().
+ // See function for details on value.
typedef base::Callback<void(const chrome::FaviconBitmapResult&)>
FaviconRawCallback;
@@ -172,6 +170,15 @@ class FaviconService : public CancelableRequestProvider,
const FaviconRawCallback& callback,
CancelableTaskTracker* tracker);
+ // See HistoryService::GetLargestFaviconForURL().
+ CancelableTaskTracker::TaskId GetLargestRawFaviconForURL(
+ Profile* profile,
+ const GURL& page_url,
+ const std::vector<int>& icon_types,
+ int minimum_size_in_pixels,
+ const FaviconRawCallback& callback,
+ CancelableTaskTracker* tracker);
+
CancelableTaskTracker::TaskId GetFaviconForURL(
const FaviconForURLParams& params,
const FaviconResultsCallback& callback,
diff --git a/chrome/browser/geolocation/geolocation_browsertest.cc b/chrome/browser/geolocation/geolocation_browsertest.cc
index a1bec46ca9..d26eabf0a3 100644
--- a/chrome/browser/geolocation/geolocation_browsertest.cc
+++ b/chrome/browser/geolocation/geolocation_browsertest.cc
@@ -477,7 +477,8 @@ IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest,
CheckStringValueFromJavascript("1", "geoGetLastError()");
}
-IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, NoInfobarForSecondTab) {
+// See http://crbug.com/308358
+IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, DISABLED_NoInfobarForSecondTab) {
ASSERT_TRUE(Initialize(INITIALIZATION_NONE));
AddGeolocationWatch(true);
SetInfoBarResponse(current_url(), true);
diff --git a/chrome/browser/geolocation/geolocation_infobar_delegate.cc b/chrome/browser/geolocation/geolocation_infobar_delegate.cc
index 65e645ebf9..fba08a89ea 100644
--- a/chrome/browser/geolocation/geolocation_infobar_delegate.cc
+++ b/chrome/browser/geolocation/geolocation_infobar_delegate.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/geolocation/geolocation_infobar_delegate.h"
+#include "base/metrics/histogram.h"
#include "chrome/browser/content_settings/permission_queue_controller.h"
#include "chrome/browser/google/google_util.h"
#include "chrome/browser/infobars/infobar_service.h"
@@ -23,6 +24,41 @@ typedef GeolocationInfoBarDelegateAndroid DelegateType;
typedef GeolocationInfoBarDelegate DelegateType;
#endif
+namespace {
+
+enum GeolocationInfoBarDelegateEvent {
+ // NOTE: Do not renumber these as that would confuse interpretation of
+ // previously logged data. When making changes, also update the enum list
+ // in tools/metrics/histograms/histograms.xml to keep it in sync.
+
+ // The bar was created.
+ GEOLOCATION_INFO_BAR_DELEGATE_EVENT_CREATE = 0,
+
+ // User allowed use of geolocation.
+ GEOLOCATION_INFO_BAR_DELEGATE_EVENT_ALLOW = 1,
+
+ // User denied use of geolocation.
+ GEOLOCATION_INFO_BAR_DELEGATE_EVENT_DENY = 2,
+
+ // User dismissed the bar.
+ GEOLOCATION_INFO_BAR_DELEGATE_EVENT_DISMISS = 3,
+
+ // User clicked on link.
+ GEOLOCATION_INFO_BAR_DELEGATE_EVENT_LINK_CLICK = 4,
+
+ // User ignored the bar.
+ GEOLOCATION_INFO_BAR_DELEGATE_EVENT_IGNORED = 5,
+
+ // NOTE: Add entries only immediately above this line.
+ GEOLOCATION_INFO_BAR_DELEGATE_EVENT_COUNT = 6
+};
+
+void RecordUmaEvent(GeolocationInfoBarDelegateEvent event) {
+ UMA_HISTOGRAM_ENUMERATION("Geolocation.InfoBarDelegate.Event",
+ event, GEOLOCATION_INFO_BAR_DELEGATE_EVENT_COUNT);
+}
+
+} // namespace
// static
InfoBarDelegate* GeolocationInfoBarDelegate::Create(
@@ -31,6 +67,7 @@ InfoBarDelegate* GeolocationInfoBarDelegate::Create(
const PermissionRequestID& id,
const GURL& requesting_frame,
const std::string& display_languages) {
+ RecordUmaEvent(GEOLOCATION_INFO_BAR_DELEGATE_EVENT_CREATE);
const content::NavigationEntry* committed_entry =
infobar_service->web_contents()->GetController().GetLastCommittedEntry();
return infobar_service->AddInfoBar(scoped_ptr<InfoBarDelegate>(
@@ -51,13 +88,18 @@ GeolocationInfoBarDelegate::GeolocationInfoBarDelegate(
id_(id),
requesting_frame_(requesting_frame.GetOrigin()),
contents_unique_id_(contents_unique_id),
- display_languages_(display_languages) {
+ display_languages_(display_languages),
+ user_has_interacted_(false) {
}
GeolocationInfoBarDelegate::~GeolocationInfoBarDelegate() {
+ if (!user_has_interacted_)
+ RecordUmaEvent(GEOLOCATION_INFO_BAR_DELEGATE_EVENT_IGNORED);
}
bool GeolocationInfoBarDelegate::Accept() {
+ RecordUmaEvent(GEOLOCATION_INFO_BAR_DELEGATE_EVENT_ALLOW);
+ set_user_has_interacted();
SetPermission(true, true);
return true;
}
@@ -72,6 +114,8 @@ void GeolocationInfoBarDelegate::SetPermission(bool update_content_setting,
}
void GeolocationInfoBarDelegate::InfoBarDismissed() {
+ RecordUmaEvent(GEOLOCATION_INFO_BAR_DELEGATE_EVENT_DISMISS);
+ set_user_has_interacted();
SetPermission(false, false);
}
@@ -106,6 +150,8 @@ string16 GeolocationInfoBarDelegate::GetButtonLabel(
}
bool GeolocationInfoBarDelegate::Cancel() {
+ RecordUmaEvent(GEOLOCATION_INFO_BAR_DELEGATE_EVENT_DENY);
+ set_user_has_interacted();
SetPermission(true, false);
return true;
}
@@ -116,6 +162,7 @@ string16 GeolocationInfoBarDelegate::GetLinkText() const {
bool GeolocationInfoBarDelegate::LinkClicked(
WindowOpenDisposition disposition) {
+ RecordUmaEvent(GEOLOCATION_INFO_BAR_DELEGATE_EVENT_LINK_CLICK);
const char kGeolocationLearnMoreUrl[] =
#if defined(OS_CHROMEOS)
"https://www.google.com/support/chromeos/bin/answer.py?answer=142065";
diff --git a/chrome/browser/geolocation/geolocation_infobar_delegate.h b/chrome/browser/geolocation/geolocation_infobar_delegate.h
index 6dc4b45e62..7444a67890 100644
--- a/chrome/browser/geolocation/geolocation_infobar_delegate.h
+++ b/chrome/browser/geolocation/geolocation_infobar_delegate.h
@@ -42,6 +42,13 @@ class GeolocationInfoBarDelegate : public ConfirmInfoBarDelegate {
// Call back to the controller, to inform of the user's decision.
void SetPermission(bool update_content_setting, bool allowed);
+ // Marks a flag internally to indicate that the user has interacted with the
+ // bar. This makes it possible to log from the destructor when the bar has not
+ // been used, i.e. it has been ignored by the user.
+ void set_user_has_interacted() {
+ user_has_interacted_ = true;
+ }
+
private:
// ConfirmInfoBarDelegate:
virtual void InfoBarDismissed() OVERRIDE;
@@ -61,6 +68,9 @@ class GeolocationInfoBarDelegate : public ConfirmInfoBarDelegate {
int contents_unique_id_;
std::string display_languages_;
+ // Whether the user has interacted with the geolocation infobar.
+ bool user_has_interacted_;
+
DISALLOW_COPY_AND_ASSIGN(GeolocationInfoBarDelegate);
};
diff --git a/chrome/browser/geolocation/geolocation_infobar_delegate_android.cc b/chrome/browser/geolocation/geolocation_infobar_delegate_android.cc
index 52c2b5b1be..4193181ccb 100644
--- a/chrome/browser/geolocation/geolocation_infobar_delegate_android.cc
+++ b/chrome/browser/geolocation/geolocation_infobar_delegate_android.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/geolocation/geolocation_infobar_delegate_android.h"
+#include "base/metrics/histogram.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/android/google_location_settings_helper.h"
#include "grit/generated_resources.h"
@@ -11,6 +12,28 @@
#include "grit/theme_resources.h"
#include "ui/base/l10n/l10n_util.h"
+namespace {
+enum GeolocationInfoBarDelegateAndroidEvent {
+ // NOTE: Do not renumber these as that would confuse interpretation of
+ // previously logged data. When making changes, also update the enum list
+ // in tools/metrics/histograms/histograms.xml to keep it in sync.
+
+ // User allowed the page to use geolocation.
+ GEOLOCATION_INFO_BAR_DELEGATE_ANDROID_EVENT_ALLOW = 0,
+
+ // User opened geolocation settings.
+ GEOLOCATION_INFO_BAR_DELEGATE_ANDROID_EVENT_SETTINGS = 1,
+
+ // NOTE: Add entries only immediately above this line.
+ GEOLOCATION_INFO_BAR_DELEGATE_ANDROID_EVENT_COUNT = 2
+};
+
+void RecordUmaEvent(GeolocationInfoBarDelegateAndroidEvent event) {
+ UMA_HISTOGRAM_ENUMERATION("Geolocation.InfoBarDelegateAndroid.Event",
+ event, GEOLOCATION_INFO_BAR_DELEGATE_ANDROID_EVENT_COUNT);
+}
+} // namespace
+
GeolocationInfoBarDelegateAndroid::GeolocationInfoBarDelegateAndroid(
InfoBarService* infobar_service,
PermissionQueueController* controller,
@@ -29,13 +52,18 @@ GeolocationInfoBarDelegateAndroid::~GeolocationInfoBarDelegateAndroid() {
}
bool GeolocationInfoBarDelegateAndroid::Accept() {
+ set_user_has_interacted();
+
// Accept button text could be either 'Allow' or 'Google Location Settings'.
// If 'Allow' we follow the regular flow.
- if (google_location_settings_helper_->IsGoogleAppsLocationSettingEnabled())
+ if (google_location_settings_helper_->IsGoogleAppsLocationSettingEnabled()) {
+ RecordUmaEvent(GEOLOCATION_INFO_BAR_DELEGATE_ANDROID_EVENT_ALLOW);
return GeolocationInfoBarDelegate::Accept();
+ }
// If 'Google Location Settings', we need to open the system Google Location
// Settings activity.
+ RecordUmaEvent(GEOLOCATION_INFO_BAR_DELEGATE_ANDROID_EVENT_SETTINGS);
google_location_settings_helper_->ShowGoogleLocationSettings();
SetPermission(false, false);
return true;
diff --git a/chrome/browser/google_apis/auth_service.cc b/chrome/browser/google_apis/auth_service.cc
index bd9a6b646f..e9dca03192 100644
--- a/chrome/browser/google_apis/auth_service.cc
+++ b/chrome/browser/google_apis/auth_service.cc
@@ -208,7 +208,6 @@ void AuthService::OnAuthCompleted(const AuthStatusCallback& callback,
ClearRefreshToken();
}
- // TODO(zelidrag): Add retry, back-off logic when things go wrong here.
callback.Run(error, access_token);
}
diff --git a/chrome/browser/google_apis/drive_api_requests_unittest.cc b/chrome/browser/google_apis/drive_api_requests_unittest.cc
index 30c0a2af76..99878d3476 100644
--- a/chrome/browser/google_apis/drive_api_requests_unittest.cc
+++ b/chrome/browser/google_apis/drive_api_requests_unittest.cc
@@ -41,6 +41,14 @@ const char kTestUploadExistingFilePath[] = "/upload/existingfile/path";
const char kTestUploadNewFilePath[] = "/upload/newfile/path";
const char kTestDownloadPathPrefix[] = "/download/";
+// Used as a GetContentCallback.
+void AppendContent(std::string* out,
+ GDataErrorCode error,
+ scoped_ptr<std::string> content) {
+ EXPECT_EQ(HTTP_SUCCESS, error);
+ out->append(*content);
+}
+
} // namespace
class DriveApiRequestsTest : public testing::Test {
@@ -1555,4 +1563,39 @@ TEST_F(DriveApiRequestsTest, DownloadFileRequest) {
EXPECT_EQ(expected_contents, contents);
}
+TEST_F(DriveApiRequestsTest, DownloadFileRequest_GetContentCallback) {
+ const base::FilePath kDownloadedFilePath =
+ temp_dir_.path().AppendASCII("cache_file");
+ const std::string kTestId("dummyId");
+
+ GDataErrorCode result_code = GDATA_OTHER_ERROR;
+ base::FilePath temp_file;
+ std::string contents;
+ {
+ base::RunLoop run_loop;
+ drive::DownloadFileRequest* request = new drive::DownloadFileRequest(
+ request_sender_.get(),
+ *url_generator_,
+ kTestId,
+ kDownloadedFilePath,
+ test_util::CreateQuitCallback(
+ &run_loop,
+ test_util::CreateCopyResultCallback(&result_code, &temp_file)),
+ base::Bind(&AppendContent, &contents),
+ ProgressCallback());
+ request_sender_->StartRequestWithRetry(request);
+ run_loop.Run();
+ }
+
+ base::DeleteFile(temp_file, false);
+
+ EXPECT_EQ(HTTP_SUCCESS, result_code);
+ EXPECT_EQ(net::test_server::METHOD_GET, http_request_.method);
+ EXPECT_EQ(kTestDownloadPathPrefix + kTestId, http_request_.relative_url);
+ EXPECT_EQ(kDownloadedFilePath, temp_file);
+
+ const std::string expected_contents = kTestId + kTestId + kTestId;
+ EXPECT_EQ(expected_contents, contents);
+}
+
} // namespace google_apis
diff --git a/chrome/browser/google_apis/drive_entry_kinds.h b/chrome/browser/google_apis/drive_entry_kinds.h
index 06f1e69314..c64c4e4c4a 100644
--- a/chrome/browser/google_apis/drive_entry_kinds.h
+++ b/chrome/browser/google_apis/drive_entry_kinds.h
@@ -22,6 +22,7 @@ enum DriveEntryKind {
ENTRY_KIND_PRESENTATION,
ENTRY_KIND_DRAWING,
ENTRY_KIND_TABLE,
+ ENTRY_KIND_FORM,
// Hosted external application document.
ENTRY_KIND_EXTERNAL_APP,
// Folders; collections.
diff --git a/chrome/browser/google_apis/gdata_wapi_parser.cc b/chrome/browser/google_apis/gdata_wapi_parser.cc
index af90dd3c5f..d1d7b2fded 100644
--- a/chrome/browser/google_apis/gdata_wapi_parser.cc
+++ b/chrome/browser/google_apis/gdata_wapi_parser.cc
@@ -106,6 +106,7 @@ const EntryKindMap kEntryKindMap[] = {
{ ENTRY_KIND_PRESENTATION, "presentation", ".gslides" },
{ ENTRY_KIND_DRAWING, "drawing", ".gdraw"},
{ ENTRY_KIND_TABLE, "table", ".gtable"},
+ { ENTRY_KIND_FORM, "form", ".gform"},
{ ENTRY_KIND_EXTERNAL_APP, "externalapp", ".glink"},
{ ENTRY_KIND_SITE, "site", NULL},
{ ENTRY_KIND_FOLDER, "folder", NULL},
@@ -586,6 +587,7 @@ int ResourceEntry::ClassifyEntryKind(DriveEntryKind kind) {
case ENTRY_KIND_PRESENTATION:
case ENTRY_KIND_DRAWING:
case ENTRY_KIND_TABLE:
+ case ENTRY_KIND_FORM:
classes = KIND_OF_GOOGLE_DOCUMENT | KIND_OF_HOSTED_DOCUMENT;
break;
diff --git a/chrome/browser/google_apis/gdata_wapi_requests.cc b/chrome/browser/google_apis/gdata_wapi_requests.cc
index 1f99108084..0857a42792 100644
--- a/chrome/browser/google_apis/gdata_wapi_requests.cc
+++ b/chrome/browser/google_apis/gdata_wapi_requests.cc
@@ -5,17 +5,12 @@
#include "chrome/browser/google_apis/gdata_wapi_requests.h"
#include "base/location.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/stringprintf.h"
#include "base/task_runner_util.h"
#include "base/values.h"
#include "chrome/browser/google_apis/gdata_wapi_parser.h"
#include "chrome/browser/google_apis/gdata_wapi_url_generator.h"
#include "chrome/browser/google_apis/request_sender.h"
#include "chrome/browser/google_apis/request_util.h"
-#include "chrome/browser/google_apis/time_util.h"
-#include "net/base/escape.h"
-#include "net/base/url_util.h"
#include "third_party/libxml/chromium/libxml_utils.h"
using net::URLFetcher;
@@ -565,10 +560,7 @@ InitiateUploadNewFileRequest::InitiateUploadNewFileRequest(
int64 content_length,
const std::string& parent_resource_id,
const std::string& title)
- : InitiateUploadRequestBase(sender,
- callback,
- content_type,
- content_length),
+ : InitiateUploadRequestBase(sender, callback, content_type, content_length),
url_generator_(url_generator),
parent_resource_id_(parent_resource_id),
title_(title) {
@@ -614,10 +606,7 @@ InitiateUploadExistingFileRequest::InitiateUploadExistingFileRequest(
int64 content_length,
const std::string& resource_id,
const std::string& etag)
- : InitiateUploadRequestBase(sender,
- callback,
- content_type,
- content_length),
+ : InitiateUploadRequestBase(sender, callback, content_type, content_length),
url_generator_(url_generator),
resource_id_(resource_id),
etag_(etag) {
@@ -710,7 +699,6 @@ void GetUploadStatusRequest::OnRangeRequestComplete(
callback_.Run(response, ParseResourceEntry(value.Pass()));
}
-
//========================== DownloadFileRequest ==========================
DownloadFileRequest::DownloadFileRequest(
diff --git a/chrome/browser/google_apis/gdata_wapi_requests_unittest.cc b/chrome/browser/google_apis/gdata_wapi_requests_unittest.cc
index 08ca8e7b3c..399925b45e 100644
--- a/chrome/browser/google_apis/gdata_wapi_requests_unittest.cc
+++ b/chrome/browser/google_apis/gdata_wapi_requests_unittest.cc
@@ -494,9 +494,11 @@ TEST_F(GDataWapiRequestsTest, GetResourceEntryRequest_ValidResourceId) {
EXPECT_EQ("/feeds/default/private/full/file%3A2_file_resource_id"
"?v=3&alt=json&showroot=true",
http_request_.relative_url);
- EXPECT_TRUE(test_util::VerifyJsonData(
- test_util::GetTestFilePath("gdata/file_entry.json"),
- result_data.get()));
+ scoped_ptr<base::Value> expected_json =
+ test_util::LoadJSONFile("gdata/file_entry.json");
+ ASSERT_TRUE(expected_json);
+ EXPECT_TRUE(result_data);
+ EXPECT_TRUE(base::Value::Equals(expected_json.get(), result_data.get()));
}
TEST_F(GDataWapiRequestsTest, GetResourceEntryRequest_InvalidResourceId) {
diff --git a/chrome/browser/google_apis/request_sender.h b/chrome/browser/google_apis/request_sender.h
index 550a696009..f37754c673 100644
--- a/chrome/browser/google_apis/request_sender.h
+++ b/chrome/browser/google_apis/request_sender.h
@@ -7,7 +7,6 @@
#include <set>
#include <string>
-#include <vector>
#include "base/basictypes.h"
#include "base/callback_forward.h"
diff --git a/chrome/browser/google_apis/test_util.cc b/chrome/browser/google_apis/test_util.cc
index 934042e4f7..e1d18fcdd9 100644
--- a/chrome/browser/google_apis/test_util.cc
+++ b/chrome/browser/google_apis/test_util.cc
@@ -122,30 +122,6 @@ scoped_ptr<net::test_server::HttpResponse> HandleDownloadFileRequest(
GetTestFilePath(remaining_path)).PassAs<net::test_server::HttpResponse>();
}
-bool VerifyJsonData(const base::FilePath& expected_json_file_path,
- const base::Value* json_data) {
- if (!json_data) {
- LOG(ERROR) << "json_data is NULL";
- return false;
- }
-
- std::string expected_content;
- if (!base::ReadFileToString(expected_json_file_path, &expected_content)) {
- LOG(ERROR) << "Failed to read file: " << expected_json_file_path.value();
- return false;
- }
-
- scoped_ptr<base::Value> expected_json_data(
- base::JSONReader::Read(expected_content));
- if (!base::Value::Equals(expected_json_data.get(), json_data)) {
- LOG(ERROR)
- << "The value of json_data is different from the file's content.";
- return false;
- }
-
- return true;
-}
-
bool ParseContentRangeHeader(const std::string& value,
int64* start_position,
int64* end_position,
diff --git a/chrome/browser/google_apis/test_util.h b/chrome/browser/google_apis/test_util.h
index 42facc4df2..2976937c97 100644
--- a/chrome/browser/google_apis/test_util.h
+++ b/chrome/browser/google_apis/test_util.h
@@ -93,12 +93,6 @@ scoped_ptr<net::test_server::HttpResponse> HandleDownloadFileRequest(
net::test_server::HttpRequest* out_request,
const net::test_server::HttpRequest& request);
-// Returns true if |json_data| is not NULL and equals to the content in
-// |expected_json_file_path|. The failure reason will be logged into LOG(ERROR)
-// if necessary.
-bool VerifyJsonData(const base::FilePath& expected_json_file_path,
- const base::Value* json_data);
-
// Parses a value of Content-Range header, which looks like
// "bytes <start_position>-<end_position>/<length>".
// Returns true on success.
@@ -129,8 +123,6 @@ bool ParseContentRangeHeader(const std::string& value,
// :
//
// Note: The max arity of the supported function is 4 based on the usage.
-// TODO(hidehiko): Use replace CopyResultFromXxxCallback method defined above
-// by this one. (crbug.com/180569).
namespace internal {
// Following helper templates are to support Chrome's move semantics.
// Their goal is defining helper methods which are similar to:
diff --git a/chrome/browser/guestview/adview/adview_guest.cc b/chrome/browser/guestview/adview/adview_guest.cc
index e62bb4e2d0..0c887d4eaf 100644
--- a/chrome/browser/guestview/adview/adview_guest.cc
+++ b/chrome/browser/guestview/adview/adview_guest.cc
@@ -43,6 +43,7 @@ AdViewGuest::~AdViewGuest() {
void AdViewGuest::DidCommitProvisionalLoadForFrame(
int64 frame_id,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& url,
content::PageTransition transition_type,
@@ -55,6 +56,7 @@ void AdViewGuest::DidCommitProvisionalLoadForFrame(
void AdViewGuest::DidFailProvisionalLoad(
int64 frame_id,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& validated_url,
int error_code,
diff --git a/chrome/browser/guestview/adview/adview_guest.h b/chrome/browser/guestview/adview/adview_guest.h
index 9d4385cb13..932736342c 100644
--- a/chrome/browser/guestview/adview/adview_guest.h
+++ b/chrome/browser/guestview/adview/adview_guest.h
@@ -33,12 +33,14 @@ class AdViewGuest : public GuestView,
virtual void DidCommitProvisionalLoadForFrame(
int64 frame_id,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& url,
content::PageTransition transition_type,
content::RenderViewHost* render_view_host) OVERRIDE;
virtual void DidFailProvisionalLoad(
int64 frame_id,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& validated_url,
int error_code,
diff --git a/chrome/browser/guestview/webview/webview_guest.cc b/chrome/browser/guestview/webview/webview_guest.cc
index 3230f6af73..aa23b9e1be 100644
--- a/chrome/browser/guestview/webview/webview_guest.cc
+++ b/chrome/browser/guestview/webview/webview_guest.cc
@@ -450,6 +450,7 @@ WebViewGuest::~WebViewGuest() {
void WebViewGuest::DidCommitProvisionalLoadForFrame(
int64 frame_id,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& url,
content::PageTransition transition_type,
@@ -468,6 +469,7 @@ void WebViewGuest::DidCommitProvisionalLoadForFrame(
void WebViewGuest::DidFailProvisionalLoad(
int64 frame_id,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& validated_url,
int error_code,
diff --git a/chrome/browser/guestview/webview/webview_guest.h b/chrome/browser/guestview/webview/webview_guest.h
index 784e58f9b5..48e0ea4f75 100644
--- a/chrome/browser/guestview/webview/webview_guest.h
+++ b/chrome/browser/guestview/webview/webview_guest.h
@@ -124,12 +124,14 @@ class WebViewGuest : public GuestView,
// WebContentsObserver implementation.
virtual void DidCommitProvisionalLoadForFrame(
int64 frame_id,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& url,
content::PageTransition transition_type,
content::RenderViewHost* render_view_host) OVERRIDE;
virtual void DidFailProvisionalLoad(
int64 frame_id,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& validated_url,
int error_code,
diff --git a/chrome/browser/history/history_backend.cc b/chrome/browser/history/history_backend.cc
index ba569f7a9c..e899fb5378 100644
--- a/chrome/browser/history/history_backend.cc
+++ b/chrome/browser/history/history_backend.cc
@@ -1696,6 +1696,100 @@ void HistoryBackend::GetFavicons(
bitmap_results);
}
+void HistoryBackend::GetLargestFaviconForURL(
+ const GURL& page_url,
+ const std::vector<int>& icon_types,
+ int minimum_size_in_pixels,
+ chrome::FaviconBitmapResult* favicon_bitmap_result) {
+ DCHECK(favicon_bitmap_result);
+
+ if (!db_ || !thumbnail_db_)
+ return;
+
+ TimeTicks beginning_time = TimeTicks::Now();
+
+ std::vector<IconMapping> icon_mappings;
+ if (!thumbnail_db_->GetIconMappingsForPageURL(page_url, &icon_mappings) ||
+ icon_mappings.empty())
+ return;
+
+ int required_icon_types = 0;
+ for (std::vector<int>::const_iterator i = icon_types.begin();
+ i != icon_types.end(); ++i) {
+ required_icon_types |= *i;
+ }
+
+ // Find the largest bitmap for each IconType placing in
+ // |largest_favicon_bitmaps|.
+ std::map<chrome::IconType, FaviconBitmap> largest_favicon_bitmaps;
+ for (std::vector<IconMapping>::const_iterator i = icon_mappings.begin();
+ i != icon_mappings.end(); ++i) {
+ if (!(i->icon_type & required_icon_types))
+ continue;
+ std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
+ thumbnail_db_->GetFaviconBitmapIDSizes(i->icon_id, &bitmap_id_sizes);
+ FaviconBitmap& largest = largest_favicon_bitmaps[i->icon_type];
+ for (std::vector<FaviconBitmapIDSize>::const_iterator j =
+ bitmap_id_sizes.begin(); j != bitmap_id_sizes.end(); ++j) {
+ if (largest.bitmap_id == 0 ||
+ (largest.pixel_size.width() < j->pixel_size.width() &&
+ largest.pixel_size.height() < j->pixel_size.height())) {
+ largest.icon_id = i->icon_id;
+ largest.bitmap_id = j->bitmap_id;
+ largest.pixel_size = j->pixel_size;
+ }
+ }
+ }
+ if (largest_favicon_bitmaps.empty())
+ return;
+
+ // Find an icon which is larger than minimum_size_in_pixels in the order of
+ // icon_types.
+ FaviconBitmap largest_icon;
+ for (std::vector<int>::const_iterator t = icon_types.begin();
+ t != icon_types.end(); ++t) {
+ for (std::map<chrome::IconType, FaviconBitmap>::const_iterator f =
+ largest_favicon_bitmaps.begin(); f != largest_favicon_bitmaps.end();
+ ++f) {
+ if (f->first & *t &&
+ (largest_icon.bitmap_id == 0 ||
+ (largest_icon.pixel_size.height() < f->second.pixel_size.height() &&
+ largest_icon.pixel_size.width() < f->second.pixel_size.width()))) {
+ largest_icon = f->second;
+ }
+ }
+ if (largest_icon.pixel_size.width() > minimum_size_in_pixels &&
+ largest_icon.pixel_size.height() > minimum_size_in_pixels)
+ break;
+ }
+
+ GURL icon_url;
+ chrome::IconType icon_type;
+ if (!thumbnail_db_->GetFaviconHeader(largest_icon.icon_id, &icon_url,
+ &icon_type)) {
+ return;
+ }
+
+ base::Time last_updated;
+ chrome::FaviconBitmapResult bitmap_result;
+ bitmap_result.icon_url = icon_url;
+ bitmap_result.icon_type = icon_type;
+ if (!thumbnail_db_->GetFaviconBitmap(largest_icon.bitmap_id,
+ &last_updated,
+ &bitmap_result.bitmap_data,
+ &bitmap_result.pixel_size)) {
+ return;
+ }
+
+ bitmap_result.expired = (Time::Now() - last_updated) >
+ TimeDelta::FromDays(kFaviconRefetchDays);
+ if (bitmap_result.is_valid())
+ *favicon_bitmap_result = bitmap_result;
+
+ HISTOGRAM_TIMES("History.GetLargestFaviconForURL",
+ TimeTicks::Now() - beginning_time);
+}
+
void HistoryBackend::GetFaviconsForURL(
const GURL& page_url,
int icon_types,
diff --git a/chrome/browser/history/history_backend.h b/chrome/browser/history/history_backend.h
index 41765c7575..f85f6e0a34 100644
--- a/chrome/browser/history/history_backend.h
+++ b/chrome/browser/history/history_backend.h
@@ -242,6 +242,12 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
const std::vector<ui::ScaleFactor>& desired_scale_factors,
std::vector<chrome::FaviconBitmapResult>* bitmap_results);
+ void GetLargestFaviconForURL(
+ const GURL& page_url,
+ const std::vector<int>& icon_types,
+ int minimum_size_in_pixels,
+ chrome::FaviconBitmapResult* bitmap_result);
+
void GetFaviconsForURL(
const GURL& page_url,
int icon_types,
diff --git a/chrome/browser/history/history_backend_unittest.cc b/chrome/browser/history/history_backend_unittest.cc
index 04af2b41ff..a09b57bc01 100644
--- a/chrome/browser/history/history_backend_unittest.cc
+++ b/chrome/browser/history/history_backend_unittest.cc
@@ -1922,6 +1922,115 @@ TEST_F(HistoryBackendTest, MergeFaviconShowsUpInGetFaviconsForURLResult) {
EXPECT_TRUE(BitmapDataEqual('c', result.bitmap_data));
}
+// Tests GetFaviconsForURL with icon_types priority,
+TEST_F(HistoryBackendTest, TestGetFaviconsForURLWithIconTypesPriority) {
+ GURL page_url("http://www.google.com");
+ GURL icon_url("http://www.google.com/favicon.ico");
+ GURL touch_icon_url("http://wwww.google.com/touch_icon.ico");
+
+ std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
+ std::vector<gfx::Size> favicon_size;
+ favicon_size.push_back(gfx::Size(16, 16));
+ favicon_size.push_back(gfx::Size(32, 32));
+ GenerateFaviconBitmapData(icon_url, favicon_size, &favicon_bitmap_data);
+ ASSERT_EQ(2u, favicon_bitmap_data.size());
+
+ std::vector<chrome::FaviconBitmapData> touch_icon_bitmap_data;
+ std::vector<gfx::Size> touch_icon_size;
+ touch_icon_size.push_back(gfx::Size(64, 64));
+ GenerateFaviconBitmapData(icon_url, touch_icon_size, &touch_icon_bitmap_data);
+ ASSERT_EQ(1u, touch_icon_bitmap_data.size());
+
+ // Set some preexisting favicons for |page_url|.
+ backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data);
+ backend_->SetFavicons(page_url, chrome::TOUCH_ICON, touch_icon_bitmap_data);
+
+ chrome::FaviconBitmapResult result;
+ std::vector<int> icon_types;
+ icon_types.push_back(chrome::FAVICON);
+ icon_types.push_back(chrome::TOUCH_ICON);
+
+ backend_->GetLargestFaviconForURL(page_url, icon_types, 16, &result);
+
+ // Verify the result icon is 32x32 favicon.
+ EXPECT_EQ(gfx::Size(32, 32), result.pixel_size);
+ EXPECT_EQ(chrome::FAVICON, result.icon_type);
+
+ // Change Minimal size to 32x32 and verify the 64x64 touch icon returned.
+ backend_->GetLargestFaviconForURL(page_url, icon_types, 32, &result);
+ EXPECT_EQ(gfx::Size(64, 64), result.pixel_size);
+ EXPECT_EQ(chrome::TOUCH_ICON, result.icon_type);
+}
+
+// Test the the first types of icon is returned if its size equal to the
+// second types icon.
+TEST_F(HistoryBackendTest, TestGetFaviconsForURLReturnFavicon) {
+ GURL page_url("http://www.google.com");
+ GURL icon_url("http://www.google.com/favicon.ico");
+ GURL touch_icon_url("http://wwww.google.com/touch_icon.ico");
+
+ std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
+ std::vector<gfx::Size> favicon_size;
+ favicon_size.push_back(gfx::Size(16, 16));
+ favicon_size.push_back(gfx::Size(32, 32));
+ GenerateFaviconBitmapData(icon_url, favicon_size, &favicon_bitmap_data);
+ ASSERT_EQ(2u, favicon_bitmap_data.size());
+
+ std::vector<chrome::FaviconBitmapData> touch_icon_bitmap_data;
+ std::vector<gfx::Size> touch_icon_size;
+ touch_icon_size.push_back(gfx::Size(32, 32));
+ GenerateFaviconBitmapData(icon_url, touch_icon_size, &touch_icon_bitmap_data);
+ ASSERT_EQ(1u, touch_icon_bitmap_data.size());
+
+ // Set some preexisting favicons for |page_url|.
+ backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data);
+ backend_->SetFavicons(page_url, chrome::TOUCH_ICON, touch_icon_bitmap_data);
+
+ chrome::FaviconBitmapResult result;
+ std::vector<int> icon_types;
+ icon_types.push_back(chrome::FAVICON);
+ icon_types.push_back(chrome::TOUCH_ICON);
+
+ backend_->GetLargestFaviconForURL(page_url, icon_types, 16, &result);
+
+ // Verify the result icon is 32x32 favicon.
+ EXPECT_EQ(gfx::Size(32, 32), result.pixel_size);
+ EXPECT_EQ(chrome::FAVICON, result.icon_type);
+
+ // Change minimal size to 32x32 and verify the 32x32 favicon returned.
+ chrome::FaviconBitmapResult result1;
+ backend_->GetLargestFaviconForURL(page_url, icon_types, 32, &result1);
+ EXPECT_EQ(gfx::Size(32, 32), result1.pixel_size);
+ EXPECT_EQ(chrome::FAVICON, result1.icon_type);
+}
+
+// Test the favicon is returned if its size is smaller than minimal size,
+// because it is only one available.
+TEST_F(HistoryBackendTest, TestGetFaviconsForURLReturnFaviconEvenItSmaller) {
+ GURL page_url("http://www.google.com");
+ GURL icon_url("http://www.google.com/favicon.ico");
+
+ std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
+ std::vector<gfx::Size> favicon_size;
+ favicon_size.push_back(gfx::Size(16, 16));
+ GenerateFaviconBitmapData(icon_url, favicon_size, &favicon_bitmap_data);
+ ASSERT_EQ(1u, favicon_bitmap_data.size());
+
+ // Set preexisting favicons for |page_url|.
+ backend_->SetFavicons(page_url, chrome::FAVICON, favicon_bitmap_data);
+
+ chrome::FaviconBitmapResult result;
+ std::vector<int> icon_types;
+ icon_types.push_back(chrome::FAVICON);
+ icon_types.push_back(chrome::TOUCH_ICON);
+
+ backend_->GetLargestFaviconForURL(page_url, icon_types, 32, &result);
+
+ // Verify 16x16 icon is returned, even it small than minimal_size.
+ EXPECT_EQ(gfx::Size(16, 16), result.pixel_size);
+ EXPECT_EQ(chrome::FAVICON, result.icon_type);
+}
+
// Test UpdateFaviconMapingsAndFetch() when multiple icon types are passed in.
TEST_F(HistoryBackendTest, UpdateFaviconMappingsAndFetchMultipleIconTypes) {
GURL page_url1("http://www.google.com");
diff --git a/chrome/browser/history/history_service.cc b/chrome/browser/history/history_service.cc
index aee38c899a..52088ff33a 100644
--- a/chrome/browser/history/history_service.cc
+++ b/chrome/browser/history/history_service.cc
@@ -84,6 +84,12 @@ void RunWithFaviconResults(
callback.Run(*bitmap_results);
}
+void RunWithFaviconResult(
+ const FaviconService::FaviconRawCallback& callback,
+ chrome::FaviconBitmapResult* bitmap_result) {
+ callback.Run(*bitmap_result);
+}
+
// Extract history::URLRows into GURLs for VisitedLinkMaster.
class URLIteratorFromURLRows
: public visitedlink::VisitedLinkMaster::URLIterator {
@@ -644,6 +650,28 @@ CancelableTaskTracker::TaskId HistoryService::GetFaviconsForURL(
base::Bind(&RunWithFaviconResults, callback, base::Owned(results)));
}
+CancelableTaskTracker::TaskId HistoryService::GetLargestFaviconForURL(
+ const GURL& page_url,
+ const std::vector<int>& icon_types,
+ int minimum_size_in_pixels,
+ const FaviconService::FaviconRawCallback& callback,
+ CancelableTaskTracker* tracker) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ LoadBackendIfNecessary();
+
+ chrome::FaviconBitmapResult* result = new chrome::FaviconBitmapResult();
+ return tracker->PostTaskAndReply(
+ thread_->message_loop_proxy().get(),
+ FROM_HERE,
+ base::Bind(&HistoryBackend::GetLargestFaviconForURL,
+ history_backend_.get(),
+ page_url,
+ icon_types,
+ minimum_size_in_pixels,
+ result),
+ base::Bind(&RunWithFaviconResult, callback, base::Owned(result)));
+}
+
CancelableTaskTracker::TaskId HistoryService::GetFaviconForID(
chrome::FaviconID favicon_id,
int desired_size_in_dip,
diff --git a/chrome/browser/history/history_service.h b/chrome/browser/history/history_service.h
index 6891f38e71..fca534ae22 100644
--- a/chrome/browser/history/history_service.h
+++ b/chrome/browser/history/history_service.h
@@ -707,6 +707,24 @@ class HistoryService : public CancelableRequestProvider,
const FaviconService::FaviconResultsCallback& callback,
CancelableTaskTracker* tracker);
+ // Used by FaviconService to find the first favicon bitmap whose width and
+ // height are greater than that of |minimum_size_in_pixels|. This searches
+ // for icons by IconType. Each element of |icon_types| is a bitmask of
+ // IconTypes indicating the types to search for.
+ // If the largest icon of |icon_types[0]| is not larger than
+ // |minimum_size_in_pixel|, the next icon types of
+ // |icon_types| will be searched and so on.
+ // If no icon is larger than |minimum_size_in_pixel|, the largest one of all
+ // icon types in |icon_types| is returned.
+ // This feature is especially useful when some types of icon is perfered as
+ // long as its size is larger than a specific value.
+ CancelableTaskTracker::TaskId GetLargestFaviconForURL(
+ const GURL& page_url,
+ const std::vector<int>& icon_types,
+ int minimum_size_in_pixels,
+ const FaviconService::FaviconRawCallback& callback,
+ CancelableTaskTracker* tracker);
+
// Used by the FaviconService to get the favicon bitmap which most closely
// matches |desired_size_in_dip| and |desired_scale_factor| from the favicon
// with |favicon_id| from the history backend. If |desired_size_in_dip| is 0,
diff --git a/chrome/browser/icon_loader_chromeos.cc b/chrome/browser/icon_loader_chromeos.cc
index c55d7c8731..9c55d31e03 100644
--- a/chrome/browser/icon_loader_chromeos.cc
+++ b/chrome/browser/icon_loader_chromeos.cc
@@ -68,11 +68,13 @@ const IdrBySize kImageIdrs = {
IDR_FILE_MANAGER_IMG_FILETYPE_IMAGE,
IDR_FILE_MANAGER_IMG_FILETYPE_IMAGE
};
+#if defined(USE_PROPRIETARY_CODECS)
const IdrBySize kPdfIdrs = {
IDR_FILE_MANAGER_IMG_FILETYPE_PDF,
IDR_FILE_MANAGER_IMG_FILETYPE_PDF,
IDR_FILE_MANAGER_IMG_FILETYPE_PDF
};
+#endif
const IdrBySize kVideoIdrs = {
IDR_FILE_MANAGER_IMG_FILETYPE_VIDEO,
IDR_FILE_MANAGER_IMG_FILETYPE_LARGE_VIDEO,
diff --git a/chrome/browser/lifetime/application_lifetime.cc b/chrome/browser/lifetime/application_lifetime.cc
index 0693c58f08..da12a425f7 100644
--- a/chrome/browser/lifetime/application_lifetime.cc
+++ b/chrome/browser/lifetime/application_lifetime.cc
@@ -60,7 +60,8 @@ bool AreAllBrowsersCloseable() {
return true;
// If there are any downloads active, all browsers are not closeable.
- if (DownloadService::DownloadCountAllProfiles() > 0)
+ // However, this does not block for malicious downloads.
+ if (DownloadService::NonMaliciousDownloadCountAllProfiles() > 0)
return false;
// Check TabsNeedBeforeUnloadFired().
diff --git a/chrome/browser/lifetime/browser_close_manager.cc b/chrome/browser/lifetime/browser_close_manager.cc
index 49d65313be..e26b73f7eb 100644
--- a/chrome/browser/lifetime/browser_close_manager.cc
+++ b/chrome/browser/lifetime/browser_close_manager.cc
@@ -74,7 +74,7 @@ void BrowserCloseManager::OnBrowserReportCloseable(bool proceed) {
}
void BrowserCloseManager::CheckForDownloadsInProgress() {
- int download_count = DownloadService::DownloadCountAllProfiles();
+ int download_count = DownloadService::NonMaliciousDownloadCountAllProfiles();
if (download_count == 0) {
CloseBrowsers();
return;
@@ -113,7 +113,7 @@ void BrowserCloseManager::OnReportDownloadsCancellable(bool proceed) {
++it) {
DownloadService* download_service =
DownloadServiceFactory::GetForBrowserContext(*it);
- if (download_service->DownloadCount() > 0) {
+ if (download_service->NonMaliciousDownloadCount() > 0) {
Browser* browser =
chrome::FindOrCreateTabbedBrowser(*it, chrome::GetActiveDesktop());
DCHECK(browser);
diff --git a/chrome/browser/lifetime/browser_close_manager_browsertest.cc b/chrome/browser/lifetime/browser_close_manager_browsertest.cc
index ce61b24402..3023e55115 100644
--- a/chrome/browser/lifetime/browser_close_manager_browsertest.cc
+++ b/chrome/browser/lifetime/browser_close_manager_browsertest.cc
@@ -8,6 +8,9 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_shutdown.h"
#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/download/chrome_download_manager_delegate.h"
+#include "chrome/browser/download/download_service.h"
+#include "chrome/browser/download/download_service_factory.h"
#include "chrome/browser/lifetime/application_lifetime.h"
#include "chrome/browser/lifetime/browser_close_manager.h"
#include "chrome/browser/net/url_request_mock_util.h"
@@ -31,6 +34,7 @@
#include "content/public/browser/web_contents.h"
#include "content/public/test/download_test_observer.h"
#include "content/public/test/test_navigation_observer.h"
+#include "content/test/net/url_request_mock_http_job.h"
#include "content/test/net/url_request_slow_download_job.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
@@ -121,6 +125,7 @@ class TestBrowserCloseManager : public BrowserCloseManager {
enum UserChoice {
USER_CHOICE_USER_CANCELS_CLOSE,
USER_CHOICE_USER_ALLOWS_CLOSE,
+ NO_USER_CHOICE
};
static void AttemptClose(UserChoice user_choice) {
@@ -135,7 +140,9 @@ class TestBrowserCloseManager : public BrowserCloseManager {
virtual void ConfirmCloseWithPendingDownloads(
int download_count,
const base::Callback<void(bool)>& callback) OVERRIDE {
+ EXPECT_NE(NO_USER_CHOICE, user_choice_);
switch (user_choice_) {
+ case NO_USER_CHOICE:
case USER_CHOICE_USER_CANCELS_CLOSE: {
callback.Run(false);
break;
@@ -156,6 +163,38 @@ class TestBrowserCloseManager : public BrowserCloseManager {
DISALLOW_COPY_AND_ASSIGN(TestBrowserCloseManager);
};
+class TestDownloadManagerDelegate : public ChromeDownloadManagerDelegate {
+ public:
+ explicit TestDownloadManagerDelegate(Profile* profile)
+ : ChromeDownloadManagerDelegate(profile) {
+ SetNextId(content::DownloadItem::kInvalidId + 1);
+ }
+
+ virtual bool DetermineDownloadTarget(
+ content::DownloadItem* item,
+ const content::DownloadTargetCallback& callback) OVERRIDE {
+ content::DownloadTargetCallback dangerous_callback =
+ base::Bind(&TestDownloadManagerDelegate::SetDangerous, this, callback);
+ return ChromeDownloadManagerDelegate::DetermineDownloadTarget(
+ item, dangerous_callback);
+ }
+
+ void SetDangerous(
+ const content::DownloadTargetCallback& callback,
+ const base::FilePath& target_path,
+ content::DownloadItem::TargetDisposition disp,
+ content::DownloadDangerType danger_type,
+ const base::FilePath& intermediate_path) {
+ callback.Run(target_path,
+ disp,
+ content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL,
+ intermediate_path);
+ }
+
+ private:
+ virtual ~TestDownloadManagerDelegate() {}
+};
+
} // namespace
class BrowserCloseManagerBrowserTest
@@ -619,6 +658,49 @@ IN_PROC_BROWSER_TEST_P(BrowserCloseManagerBrowserTest,
EXPECT_TRUE(chrome::BrowserIterator().done());
}
+// Test shutdown with a DANGEROUS_URL download undecided.
+IN_PROC_BROWSER_TEST_P(BrowserCloseManagerBrowserTest,
+ TestWithDangerousUrlDownload) {
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
+ // Set up the fake delegate that forces the download to be malicious.
+ scoped_refptr<TestDownloadManagerDelegate> test_delegate(
+ new TestDownloadManagerDelegate(browser()->profile()));
+ DownloadServiceFactory::GetForBrowserContext(browser()->profile())->
+ SetDownloadManagerDelegateForTesting(test_delegate.get());
+
+ // Run a dangerous download, but the user doesn't make a decision.
+ // This .swf normally would be categorized as DANGEROUS_FILE, but
+ // TestDownloadManagerDelegate turns it into DANGEROUS_URL.
+ base::FilePath file(FILE_PATH_LITERAL("downloads/dangerous/dangerous.swf"));
+ GURL download_url(content::URLRequestMockHTTPJob::GetMockUrl(file));
+ content::DownloadTestObserverInterrupted observer(
+ content::BrowserContext::GetDownloadManager(browser()->profile()),
+ 1,
+ content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_QUIT);
+ ui_test_utils::NavigateToURLWithDisposition(
+ browser(),
+ GURL(download_url),
+ NEW_BACKGROUND_TAB,
+ ui_test_utils::BROWSER_TEST_NONE);
+ observer.WaitForFinished();
+
+ // Check that the download manager has the expected state.
+ EXPECT_EQ(1, content::BrowserContext::GetDownloadManager(
+ browser()->profile())->InProgressCount());
+ EXPECT_EQ(0, content::BrowserContext::GetDownloadManager(
+ browser()->profile())->NonMaliciousInProgressCount());
+
+ // Close the browser with no user action.
+ RepeatedNotificationObserver close_observer(
+ chrome::NOTIFICATION_BROWSER_CLOSED, 1);
+ TestBrowserCloseManager::AttemptClose(
+ TestBrowserCloseManager::NO_USER_CHOICE);
+ close_observer.Wait();
+ EXPECT_TRUE(browser_shutdown::IsTryingToQuit());
+ EXPECT_TRUE(chrome::BrowserIterator().done());
+}
+
// Test shutdown with a download in progress.
IN_PROC_BROWSER_TEST_P(BrowserCloseManagerBrowserTest, TestWithDownloads) {
ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
diff --git a/chrome/browser/local_discovery/privet_device_lister_impl.cc b/chrome/browser/local_discovery/privet_device_lister_impl.cc
index cf153a41bf..406bfae799 100644
--- a/chrome/browser/local_discovery/privet_device_lister_impl.cc
+++ b/chrome/browser/local_discovery/privet_device_lister_impl.cc
@@ -4,109 +4,42 @@
#include "chrome/browser/local_discovery/privet_device_lister_impl.h"
-#include <string>
#include <utility>
#include <vector>
-#include "base/bind.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "chrome/browser/local_discovery/privet_constants.h"
namespace local_discovery {
-PrivetDeviceListerImpl::PrivetDeviceListerImpl(
- ServiceDiscoveryClient* service_discovery_client,
- PrivetDeviceLister::Delegate* delegate)
- : delegate_(delegate),
- service_discovery_client_(service_discovery_client),
- service_type_(kPrivetDefaultDeviceType) {
-}
+namespace {
-PrivetDeviceListerImpl::PrivetDeviceListerImpl(
- ServiceDiscoveryClient* service_discovery_client,
- PrivetDeviceLister::Delegate* delegate,
- std::string subtype) : delegate_(delegate),
- service_discovery_client_(service_discovery_client),
- service_type_(
- base::StringPrintf(kPrivetSubtypeTemplate,
- subtype.c_str())) {
-}
-PrivetDeviceListerImpl::~PrivetDeviceListerImpl() {
-}
-
-void PrivetDeviceListerImpl::Start() {
- CreateServiceWatcher();
-}
-
-void PrivetDeviceListerImpl::DiscoverNewDevices(bool force_update) {
- service_watcher_->DiscoverNewServices(force_update);
-}
-
-void PrivetDeviceListerImpl::OnServiceUpdated(
- ServiceWatcher::UpdateType update,
- const std::string& service_name) {
- if (update == ServiceWatcher::UPDATE_INVALIDATED) {
- resolvers_.clear();
- CreateServiceWatcher();
-
- delegate_->DeviceCacheFlushed();
- return;
- }
-
- if (update != ServiceWatcher::UPDATE_REMOVED) {
- bool added = (update == ServiceWatcher::UPDATE_ADDED);
- std::pair<ServiceResolverMap::iterator, bool> insert_result =
- resolvers_.insert(make_pair(service_name,
- linked_ptr<ServiceResolver>(NULL)));
-
- // If there is already a resolver working on this service, don't add one.
- if (insert_result.second) {
- scoped_ptr<ServiceResolver> resolver =
- service_discovery_client_->CreateServiceResolver(
- service_name, base::Bind(
- &PrivetDeviceListerImpl::OnResolveComplete,
- base::Unretained(this),
- added));
-
- insert_result.first->second.reset(resolver.release());
- insert_result.first->second->StartResolving();
- }
- } else {
- delegate_->DeviceRemoved(service_name);
- }
-}
-
-void PrivetDeviceListerImpl::OnResolveComplete(
- bool added,
- ServiceResolver::RequestStatus status,
- const ServiceDescription& service_description) {
- if (status != ServiceResolver::STATUS_SUCCESS) {
- resolvers_.erase(service_description.service_name);
-
- // TODO(noamsml): Add retry logic.
- return;
+DeviceDescription::ConnectionState
+ConnectionStateFromString(const std::string& str) {
+ if (LowerCaseEqualsASCII(str, kPrivetConnectionStatusOnline)) {
+ return DeviceDescription::ONLINE;
+ } else if (LowerCaseEqualsASCII(str, kPrivetConnectionStatusOffline)) {
+ return DeviceDescription::OFFLINE;
+ } else if (LowerCaseEqualsASCII(str, kPrivetConnectionStatusConnecting)) {
+ return DeviceDescription::CONNECTING;
+ } else if (LowerCaseEqualsASCII(str, kPrivetConnectionStatusNotConfigured)) {
+ return DeviceDescription::NOT_CONFIGURED;
}
- DeviceDescription device_description;
- FillDeviceDescription(service_description, &device_description);
-
- std::string service_name = service_description.service_name;
- resolvers_.erase(service_name);
- delegate_->DeviceChanged(added, service_name, device_description);
+ return DeviceDescription::UNKNOWN;
}
-void PrivetDeviceListerImpl::FillDeviceDescription(
- const ServiceDescription& service_description,
- DeviceDescription* device_description) {
+void FillDeviceDescription(const ServiceDescription& service_description,
+ DeviceDescription* device_description) {
device_description->address = service_description.address;
device_description->ip_address = service_description.ip_address;
device_description->last_seen = service_description.last_seen;
for (std::vector<std::string>::const_iterator i =
service_description.metadata.begin();
- i < service_description.metadata.end();
+ i != service_description.metadata.end();
i++) {
size_t equals_pos = i->find_first_of('=');
if (equals_pos == std::string::npos)
@@ -131,29 +64,57 @@ void PrivetDeviceListerImpl::FillDeviceDescription(
}
}
-DeviceDescription::ConnectionState
-PrivetDeviceListerImpl::ConnectionStateFromString(const std::string& str) {
- if (LowerCaseEqualsASCII(str, kPrivetConnectionStatusOnline)) {
- return DeviceDescription::ONLINE;
- } else if (LowerCaseEqualsASCII(str, kPrivetConnectionStatusOffline)) {
- return DeviceDescription::OFFLINE;
- } else if (LowerCaseEqualsASCII(str, kPrivetConnectionStatusConnecting)) {
- return DeviceDescription::CONNECTING;
- } else if (LowerCaseEqualsASCII(str, kPrivetConnectionStatusNotConfigured)) {
- return DeviceDescription::NOT_CONFIGURED;
- }
+} // namespace
- return DeviceDescription::UNKNOWN;
+PrivetDeviceListerImpl::PrivetDeviceListerImpl(
+ ServiceDiscoveryClient* service_discovery_client,
+ PrivetDeviceLister::Delegate* delegate)
+ : delegate_(delegate),
+ device_lister_(this, service_discovery_client, kPrivetDefaultDeviceType) {
}
-void PrivetDeviceListerImpl::CreateServiceWatcher() {
- service_watcher_ =
- service_discovery_client_->CreateServiceWatcher(
- service_type_,
- base::Bind(&PrivetDeviceListerImpl::OnServiceUpdated,
- base::Unretained(this)));
- service_watcher_->Start();
+PrivetDeviceListerImpl::PrivetDeviceListerImpl(
+ ServiceDiscoveryClient* service_discovery_client,
+ PrivetDeviceLister::Delegate* delegate,
+ const std::string& subtype)
+ : delegate_(delegate),
+ device_lister_(
+ this,
+ service_discovery_client,
+ base::StringPrintf(kPrivetSubtypeTemplate, subtype.c_str())) {
+}
+PrivetDeviceListerImpl::~PrivetDeviceListerImpl() {
+}
+
+void PrivetDeviceListerImpl::Start() {
+ device_lister_.Start();
+}
+
+void PrivetDeviceListerImpl::DiscoverNewDevices(bool force_update) {
+ device_lister_.DiscoverNewDevices(force_update);
+}
+
+void PrivetDeviceListerImpl::OnDeviceChanged(
+ bool added, const ServiceDescription& service_description) {
+ if (!delegate_)
+ return;
+
+ DeviceDescription device_description;
+ FillDeviceDescription(service_description, &device_description);
+
+ delegate_->DeviceChanged(
+ added, service_description.service_name, device_description);
+}
+
+void PrivetDeviceListerImpl::OnDeviceRemoved(const std::string& service_name) {
+ if (delegate_)
+ delegate_->DeviceRemoved(service_name);
+}
+
+void PrivetDeviceListerImpl::OnDeviceCacheFlushed() {
+ if (delegate_)
+ delegate_->DeviceCacheFlushed();
}
} // namespace local_discovery
diff --git a/chrome/browser/local_discovery/privet_device_lister_impl.h b/chrome/browser/local_discovery/privet_device_lister_impl.h
index 64cfba1841..a1888aea00 100644
--- a/chrome/browser/local_discovery/privet_device_lister_impl.h
+++ b/chrome/browser/local_discovery/privet_device_lister_impl.h
@@ -5,23 +5,22 @@
#ifndef CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_DEVICE_LISTER_IMPL_H_
#define CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_DEVICE_LISTER_IMPL_H_
-#include <map>
#include <string>
-#include "base/callback.h"
-#include "base/memory/linked_ptr.h"
-#include "base/memory/scoped_ptr.h"
#include "chrome/browser/local_discovery/privet_device_lister.h"
-#include "chrome/common/local_discovery/service_discovery_client.h"
+#include "chrome/browser/local_discovery/service_discovery_device_lister.h"
namespace local_discovery {
-class PrivetDeviceListerImpl : public PrivetDeviceLister {
+class ServiceDiscoveryClient;
+
+class PrivetDeviceListerImpl : public PrivetDeviceLister,
+ public ServiceDiscoveryDeviceLister::Delegate {
public:
PrivetDeviceListerImpl(
ServiceDiscoveryClient* service_discovery_client,
PrivetDeviceLister::Delegate* delegate,
- std::string subtype);
+ const std::string& subtype);
PrivetDeviceListerImpl(
ServiceDiscoveryClient* service_discovery_client,
@@ -30,36 +29,18 @@ class PrivetDeviceListerImpl : public PrivetDeviceLister {
virtual ~PrivetDeviceListerImpl();
virtual void Start() OVERRIDE;
-
virtual void DiscoverNewDevices(bool force_update) OVERRIDE;
- private:
- typedef std::map<std::string, linked_ptr<ServiceResolver> >
- ServiceResolverMap;
-
- void OnServiceUpdated(ServiceWatcher::UpdateType update,
- const std::string& service_name);
-
- void OnResolveComplete(
+ protected:
+ virtual void OnDeviceChanged(
bool added,
- ServiceResolver::RequestStatus status,
- const ServiceDescription& description);
-
- void FillDeviceDescription(const ServiceDescription& service_description,
- DeviceDescription* device_description);
-
- DeviceDescription::ConnectionState ConnectionStateFromString(
- const std::string& str);
-
- // Create or recreate the service watcher
- void CreateServiceWatcher();
+ const ServiceDescription& service_description) OVERRIDE;
+ virtual void OnDeviceRemoved(const std::string& service_name) OVERRIDE;
+ virtual void OnDeviceCacheFlushed() OVERRIDE;
+ private:
PrivetDeviceLister::Delegate* delegate_;
-
- ServiceDiscoveryClient* service_discovery_client_;
- scoped_ptr<ServiceWatcher> service_watcher_;
- ServiceResolverMap resolvers_;
- std::string service_type_;
+ ServiceDiscoveryDeviceLister device_lister_;
};
} // namespace local_discovery
diff --git a/chrome/browser/local_discovery/privet_url_fetcher.cc b/chrome/browser/local_discovery/privet_url_fetcher.cc
index 52da7872ad..f45d4772b9 100644
--- a/chrome/browser/local_discovery/privet_url_fetcher.cc
+++ b/chrome/browser/local_discovery/privet_url_fetcher.cc
@@ -14,6 +14,7 @@ namespace local_discovery {
namespace {
const char kXPrivetTokenHeaderPrefix[] = "X-Privet-Token: ";
+const char kXPrivetEmptyToken[] = "\"\"";
}
PrivetURLFetcher::PrivetURLFetcher(
@@ -22,11 +23,15 @@ PrivetURLFetcher::PrivetURLFetcher(
net::URLFetcher::RequestType request_type,
net::URLRequestContextGetter* request_context,
PrivetURLFetcher::Delegate* delegate)
- : privet_access_token_(token), delegate_(delegate) {
+ : delegate_(delegate) {
+ std::string sent_token = token;
+ if (sent_token.empty())
+ sent_token = kXPrivetEmptyToken;
+
url_fetcher_.reset(net::URLFetcher::Create(url, request_type, this));
url_fetcher_->SetRequestContext(request_context);
url_fetcher_->AddExtraRequestHeader(std::string(kXPrivetTokenHeaderPrefix) +
- token);
+ sent_token);
// URLFetcher requires us to set upload data for POST requests.
if (request_type == net::URLFetcher::POST)
diff --git a/chrome/browser/local_discovery/privet_url_fetcher.h b/chrome/browser/local_discovery/privet_url_fetcher.h
index c96b894c28..a99ea482e8 100644
--- a/chrome/browser/local_discovery/privet_url_fetcher.h
+++ b/chrome/browser/local_discovery/privet_url_fetcher.h
@@ -54,7 +54,6 @@ class PrivetURLFetcher : public net::URLFetcherDelegate {
private:
scoped_ptr<net::URLFetcher> url_fetcher_;
- std::string privet_access_token_;
Delegate* delegate_;
DISALLOW_COPY_AND_ASSIGN(PrivetURLFetcher);
diff --git a/chrome/browser/local_discovery/privet_url_fetcher_unittest.cc b/chrome/browser/local_discovery/privet_url_fetcher_unittest.cc
index da9b743985..b7fa5f353c 100644
--- a/chrome/browser/local_discovery/privet_url_fetcher_unittest.cc
+++ b/chrome/browser/local_discovery/privet_url_fetcher_unittest.cc
@@ -17,6 +17,7 @@ namespace {
const char kSamplePrivetURL[] =
"http://10.0.0.8:7676/privet/register?action=start";
const char kSamplePrivetToken[] = "MyToken";
+const char kEmptyPrivetToken[] = "\"\"";
const char kSampleParsableJSON[] = "{ \"hello\" : 2 }";
const char kSampleUnparsableJSON[] = "{ \"hello\" : }";
@@ -141,6 +142,25 @@ TEST_F(PrivetURLFetcherTest, Header) {
EXPECT_EQ(kSamplePrivetToken, header_token);
}
+TEST_F(PrivetURLFetcherTest, Header2) {
+ privet_urlfetcher_.reset(new PrivetURLFetcher(
+ "",
+ GURL(kSamplePrivetURL),
+ net::URLFetcher::POST,
+ request_context_.get(),
+ &delegate_));
+
+ privet_urlfetcher_->Start();
+ net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
+ ASSERT_TRUE(fetcher != NULL);
+ net::HttpRequestHeaders headers;
+ fetcher->GetExtraRequestHeaders(&headers);
+
+ std::string header_token;
+ ASSERT_TRUE(headers.GetHeader("X-Privet-Token", &header_token));
+ EXPECT_EQ(kEmptyPrivetToken, header_token);
+}
+
TEST_F(PrivetURLFetcherTest, FetchHasError) {
privet_urlfetcher_->Start();
net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
diff --git a/chrome/browser/local_discovery/service_discovery_device_lister.cc b/chrome/browser/local_discovery/service_discovery_device_lister.cc
new file mode 100644
index 0000000000..a6c025ac5e
--- /dev/null
+++ b/chrome/browser/local_discovery/service_discovery_device_lister.cc
@@ -0,0 +1,92 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/local_discovery/service_discovery_device_lister.h"
+
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+
+namespace local_discovery {
+
+ServiceDiscoveryDeviceLister::ServiceDiscoveryDeviceLister(
+ Delegate* delegate,
+ ServiceDiscoveryClient* service_discovery_client,
+ const std::string& service_type)
+ : delegate_(delegate),
+ service_discovery_client_(service_discovery_client),
+ service_type_(service_type) {
+}
+
+ServiceDiscoveryDeviceLister::~ServiceDiscoveryDeviceLister() {
+}
+
+void ServiceDiscoveryDeviceLister::Start() {
+ CreateServiceWatcher();
+}
+
+void ServiceDiscoveryDeviceLister::DiscoverNewDevices(bool force_update) {
+ service_watcher_->DiscoverNewServices(force_update);
+}
+
+void ServiceDiscoveryDeviceLister::OnServiceUpdated(
+ ServiceWatcher::UpdateType update,
+ const std::string& service_name) {
+ if (update == ServiceWatcher::UPDATE_INVALIDATED) {
+ resolvers_.clear();
+ CreateServiceWatcher();
+
+ delegate_->OnDeviceCacheFlushed();
+ return;
+ }
+
+ if (update != ServiceWatcher::UPDATE_REMOVED) {
+ bool added = (update == ServiceWatcher::UPDATE_ADDED);
+ std::pair<ServiceResolverMap::iterator, bool> insert_result =
+ resolvers_.insert(make_pair(service_name,
+ linked_ptr<ServiceResolver>(NULL)));
+
+ // If there is already a resolver working on this service, don't add one.
+ if (insert_result.second) {
+ scoped_ptr<ServiceResolver> resolver =
+ service_discovery_client_->CreateServiceResolver(
+ service_name, base::Bind(
+ &ServiceDiscoveryDeviceLister::OnResolveComplete,
+ base::Unretained(this),
+ added));
+
+ insert_result.first->second.reset(resolver.release());
+ insert_result.first->second->StartResolving();
+ }
+ } else {
+ delegate_->OnDeviceRemoved(service_name);
+ }
+}
+
+void ServiceDiscoveryDeviceLister::OnResolveComplete(
+ bool added,
+ ServiceResolver::RequestStatus status,
+ const ServiceDescription& service_description) {
+ if (status != ServiceResolver::STATUS_SUCCESS) {
+ resolvers_.erase(service_description.service_name);
+
+ // TODO(noamsml): Add retry logic.
+ return;
+ }
+
+ delegate_->OnDeviceChanged(added, service_description);
+ resolvers_.erase(service_description.service_name);
+}
+
+void ServiceDiscoveryDeviceLister::CreateServiceWatcher() {
+ service_watcher_ =
+ service_discovery_client_->CreateServiceWatcher(
+ service_type_,
+ base::Bind(&ServiceDiscoveryDeviceLister::OnServiceUpdated,
+ base::Unretained(this)));
+ service_watcher_->Start();
+}
+
+} // namespace local_discovery
diff --git a/chrome/browser/local_discovery/service_discovery_device_lister.h b/chrome/browser/local_discovery/service_discovery_device_lister.h
new file mode 100644
index 0000000000..2baab45d50
--- /dev/null
+++ b/chrome/browser/local_discovery/service_discovery_device_lister.h
@@ -0,0 +1,63 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_LOCAL_DISCOVERY_SERVICE_DISCOVERY_DEVICE_LISTER_H_
+#define CHROME_BROWSER_LOCAL_DISCOVERY_SERVICE_DISCOVERY_DEVICE_LISTER_H_
+
+#include <map>
+#include <string>
+
+#include "base/memory/linked_ptr.h"
+#include "base/memory/scoped_ptr.h"
+#include "chrome/common/local_discovery/service_discovery_client.h"
+
+namespace local_discovery {
+
+class ServiceDiscoveryDeviceLister {
+ public:
+ class Delegate {
+ public:
+ virtual void OnDeviceChanged(
+ bool added,
+ const ServiceDescription& service_description) = 0;
+ virtual void OnDeviceRemoved(const std::string& service_name) = 0;
+ virtual void OnDeviceCacheFlushed() = 0;
+ };
+
+ ServiceDiscoveryDeviceLister(Delegate* delegate,
+ ServiceDiscoveryClient* service_discovery_client,
+ const std::string& service_type);
+ virtual ~ServiceDiscoveryDeviceLister();
+
+ void Start();
+ void DiscoverNewDevices(bool force_update);
+
+ std::string service_type() { return service_type_; }
+
+ private:
+ typedef std::map<std::string, linked_ptr<ServiceResolver> >
+ ServiceResolverMap;
+
+ void OnServiceUpdated(ServiceWatcher::UpdateType update,
+ const std::string& service_name);
+
+ void OnResolveComplete(
+ bool added,
+ ServiceResolver::RequestStatus status,
+ const ServiceDescription& description);
+
+ // Create or recreate the service watcher
+ void CreateServiceWatcher();
+
+ Delegate* const delegate_;
+ ServiceDiscoveryClient* const service_discovery_client_;
+ const std::string service_type_;
+
+ scoped_ptr<ServiceWatcher> service_watcher_;
+ ServiceResolverMap resolvers_;
+};
+
+} // namespace local_discovery
+
+#endif // CHROME_BROWSER_LOCAL_DISCOVERY_SERVICE_DISCOVERY_DEVICE_LISTER_H_
diff --git a/chrome/browser/managed_mode/managed_mode_browsertest.cc b/chrome/browser/managed_mode/managed_mode_browsertest.cc
index 67e54ed72a..86e3817d71 100644
--- a/chrome/browser/managed_mode/managed_mode_browsertest.cc
+++ b/chrome/browser/managed_mode/managed_mode_browsertest.cc
@@ -107,7 +107,6 @@ class ManagedModeBlockModeTest : public InProcessBrowserTest {
Profile* profile = browser()->profile();
managed_user_service_ = ManagedUserServiceFactory::GetForProfile(profile);
- managed_user_service_->InitForTesting();
ManagedUserSettingsService* managed_user_settings_service =
ManagedUserSettingsServiceFactory::GetForProfile(profile);
managed_user_settings_service->SetLocalSettingForTesting(
@@ -124,6 +123,8 @@ class ManagedModeBlockModeTest : public InProcessBrowserTest {
"MAP *.example.com " + host_port + "," +
"MAP *.new-example.com " + host_port + "," +
"MAP *.a.com " + host_port);
+
+ command_line->AppendSwitch(switches::kNewProfileIsSupervised);
}
// Acts like a synchronous call to history's QueryHistory. Modified from
diff --git a/chrome/browser/managed_mode/managed_mode_navigation_observer.cc b/chrome/browser/managed_mode/managed_mode_navigation_observer.cc
index 3b0548c1ce..78e6011ca3 100644
--- a/chrome/browser/managed_mode/managed_mode_navigation_observer.cc
+++ b/chrome/browser/managed_mode/managed_mode_navigation_observer.cc
@@ -181,6 +181,7 @@ void ManagedModeNavigationObserver::ProvisionalChangeToMainFrameUrl(
void ManagedModeNavigationObserver::DidCommitProvisionalLoadForFrame(
int64 frame_id,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& url,
content::PageTransition transition_type,
diff --git a/chrome/browser/managed_mode/managed_mode_navigation_observer.h b/chrome/browser/managed_mode/managed_mode_navigation_observer.h
index 03863f3151..ac19d81aca 100644
--- a/chrome/browser/managed_mode/managed_mode_navigation_observer.h
+++ b/chrome/browser/managed_mode/managed_mode_navigation_observer.h
@@ -53,6 +53,7 @@ class ManagedModeNavigationObserver
content::RenderViewHost* render_view_host) OVERRIDE;
virtual void DidCommitProvisionalLoadForFrame(
int64 frame_id,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& url,
content::PageTransition transition_type,
diff --git a/chrome/browser/managed_mode/managed_mode_resource_throttle_browsertest.cc b/chrome/browser/managed_mode/managed_mode_resource_throttle_browsertest.cc
index 9fdf8a64b0..9bfb4608aa 100644
--- a/chrome/browser/managed_mode/managed_mode_resource_throttle_browsertest.cc
+++ b/chrome/browser/managed_mode/managed_mode_resource_throttle_browsertest.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/managed_mode/managed_mode_resource_throttle.h"
+#include "base/command_line.h"
#include "base/prefs/pref_service.h"
#include "base/values.h"
#include "chrome/browser/managed_mode/managed_user_constants.h"
@@ -13,6 +14,7 @@
#include "chrome/browser/managed_mode/managed_user_settings_service_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/navigation_entry.h"
@@ -33,6 +35,7 @@ class ManagedModeResourceThrottleTest : public InProcessBrowserTest {
private:
virtual void SetUpOnMainThread() OVERRIDE;
+ virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE;
ManagedUserService* managed_user_service_;
};
@@ -40,7 +43,11 @@ class ManagedModeResourceThrottleTest : public InProcessBrowserTest {
void ManagedModeResourceThrottleTest::SetUpOnMainThread() {
managed_user_service_ =
ManagedUserServiceFactory::GetForProfile(browser()->profile());
- managed_user_service_->InitForTesting();
+}
+
+void ManagedModeResourceThrottleTest::SetUpCommandLine(
+ CommandLine* command_line) {
+ command_line->AppendSwitch(switches::kNewProfileIsSupervised);
}
// Tests that showing the blocking interstitial for a WebContents without a
diff --git a/chrome/browser/managed_mode/managed_user_service.cc b/chrome/browser/managed_mode/managed_user_service.cc
index 96bb3a1d2f..fe204fab9f 100644
--- a/chrome/browser/managed_mode/managed_user_service.cc
+++ b/chrome/browser/managed_mode/managed_user_service.cc
@@ -51,6 +51,7 @@
#include "ui/base/l10n/l10n_util.h"
#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/login/supervised_user_manager.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#endif
@@ -259,8 +260,8 @@ void ManagedUserService::GetCategoryNames(CategoryList* list) {
std::string ManagedUserService::GetCustodianEmailAddress() const {
#if defined(OS_CHROMEOS)
- return chromeos::UserManager::Get()->
- GetManagerDisplayEmailForManagedUser(
+ return chromeos::UserManager::Get()->GetSupervisedUserManager()->
+ GetManagerDisplayEmail(
chromeos::UserManager::Get()->GetActiveUser()->email());
#else
return profile_->GetPrefs()->GetString(prefs::kManagedUserCustodianEmail);
@@ -269,8 +270,8 @@ std::string ManagedUserService::GetCustodianEmailAddress() const {
std::string ManagedUserService::GetCustodianName() const {
#if defined(OS_CHROMEOS)
- return UTF16ToUTF8(chromeos::UserManager::Get()->
- GetManagerDisplayNameForManagedUser(
+ return UTF16ToUTF8(chromeos::UserManager::Get()->GetSupervisedUserManager()->
+ GetManagerDisplayName(
chromeos::UserManager::Get()->GetActiveUser()->email()));
#else
std::string name = profile_->GetPrefs()->GetString(
@@ -293,11 +294,6 @@ void ManagedUserService::DidBlockNavigation(
}
}
-void ManagedUserService::AddInitCallback(
- const base::Closure& callback) {
- init_callbacks_.push_back(callback);
-}
-
std::string ManagedUserService::GetDebugPolicyProviderName() const {
// Save the string space in official builds.
#ifdef NDEBUG
@@ -528,12 +524,6 @@ void ManagedUserService::GetManualExceptionsForHost(const std::string& host,
}
}
-void ManagedUserService::InitForTesting() {
- DCHECK(!profile_->IsManaged());
- profile_->GetPrefs()->SetString(prefs::kManagedUserId, "Test ID");
- Init();
-}
-
void ManagedUserService::InitSync(const std::string& refresh_token) {
ProfileSyncService* service =
ProfileSyncServiceFactory::GetForProfile(profile_);
@@ -611,14 +601,6 @@ void ManagedUserService::Init() {
UpdateSiteLists();
UpdateManualHosts();
UpdateManualURLs();
-
- // Call the callbacks to notify that the ManagedUserService has been
- // initialized.
- for (std::vector<base::Closure>::iterator it = init_callbacks_.begin();
- it != init_callbacks_.end();
- ++it) {
- it->Run();
- }
}
void ManagedUserService::RegisterAndInitSync(
diff --git a/chrome/browser/managed_mode/managed_user_service.h b/chrome/browser/managed_mode/managed_user_service.h
index b2d05f6655..baf790cb80 100644
--- a/chrome/browser/managed_mode/managed_user_service.h
+++ b/chrome/browser/managed_mode/managed_user_service.h
@@ -116,9 +116,6 @@ class ManagedUserService : public BrowserContextKeyedService,
// managed.
void Init();
- // Marks the profile as managed and initializes it.
- void InitForTesting();
-
// Initializes this profile for syncing, using the provided |refresh_token| to
// mint access tokens for Sync.
void InitSync(const std::string& refresh_token);
@@ -144,8 +141,6 @@ class ManagedUserService : public BrowserContextKeyedService,
void AddNavigationBlockedCallback(const NavigationBlockedCallback& callback);
void DidBlockNavigation(content::WebContents* web_contents);
- void AddInitCallback(const base::Closure& callback);
-
// extensions::ManagementPolicy::Provider implementation:
virtual std::string GetDebugPolicyProviderName() const OVERRIDE;
virtual bool UserMayLoad(const extensions::Extension* extension,
@@ -165,7 +160,7 @@ class ManagedUserService : public BrowserContextKeyedService,
virtual void OnBrowserSetLastActive(Browser* browser) OVERRIDE;
private:
- friend class ManagedUserServiceExtensionTest;
+ friend class ManagedUserServiceExtensionTestBase;
friend class ManagedUserServiceFactory;
FRIEND_TEST_ALL_PREFIXES(ManagedUserServiceTest,
ExtensionManagementPolicyProviderUnmanaged);
@@ -259,8 +254,6 @@ class ManagedUserService : public BrowserContextKeyedService,
bool waiting_for_sync_initialization_;
bool is_profile_active_;
- std::vector<base::Closure> init_callbacks_;
-
std::vector<NavigationBlockedCallback> navigation_blocked_callbacks_;
// Sets a profile in elevated state for testing if set to true.
diff --git a/chrome/browser/managed_mode/managed_user_service_browsertest.cc b/chrome/browser/managed_mode/managed_user_service_browsertest.cc
index 9af82f642f..571f413a21 100644
--- a/chrome/browser/managed_mode/managed_user_service_browsertest.cc
+++ b/chrome/browser/managed_mode/managed_user_service_browsertest.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/command_line.h"
#include "base/prefs/pref_service.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
@@ -14,24 +15,26 @@
#include "chrome/browser/profiles/profile_info_cache.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "content/public/test/test_utils.h"
typedef InProcessBrowserTest ManagedUserServiceTest;
+class ManagedUserServiceTestManaged : public InProcessBrowserTest {
+ public:
+ // content::BrowserTestBase:
+ virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+ command_line->AppendSwitch(switches::kNewProfileIsSupervised);
+ }
+};
+
IN_PROC_BROWSER_TEST_F(ManagedUserServiceTest, LocalPolicies) {
Profile* profile = browser()->profile();
PrefService* prefs = profile->GetPrefs();
EXPECT_FALSE(prefs->GetBoolean(prefs::kForceSafeSearch));
EXPECT_TRUE(prefs->IsUserModifiablePreference(prefs::kForceSafeSearch));
-
- ManagedUserService* managed_user_service =
- ManagedUserServiceFactory::GetForProfile(profile);
- managed_user_service->InitForTesting();
-
- EXPECT_TRUE(prefs->GetBoolean(prefs::kForceSafeSearch));
- EXPECT_FALSE(prefs->IsUserModifiablePreference(prefs::kForceSafeSearch));
}
IN_PROC_BROWSER_TEST_F(ManagedUserServiceTest, ProfileName) {
@@ -45,11 +48,22 @@ IN_PROC_BROWSER_TEST_F(ManagedUserServiceTest, ProfileName) {
size_t profile_index = cache.GetIndexOfProfileWithPath(profile->GetPath());
EXPECT_EQ(original_name,
UTF16ToUTF8(cache.GetNameOfProfileAtIndex(profile_index)));
+}
+
+IN_PROC_BROWSER_TEST_F(ManagedUserServiceTestManaged, LocalPolicies) {
+ Profile* profile = browser()->profile();
+ PrefService* prefs = profile->GetPrefs();
+ EXPECT_TRUE(prefs->GetBoolean(prefs::kForceSafeSearch));
+ EXPECT_FALSE(prefs->IsUserModifiablePreference(prefs::kForceSafeSearch));
+}
+
+IN_PROC_BROWSER_TEST_F(ManagedUserServiceTestManaged, ProfileName) {
+ Profile* profile = browser()->profile();
+ PrefService* prefs = profile->GetPrefs();
+ std::string original_name = prefs->GetString(prefs::kProfileName);
+ ProfileManager* profile_manager = g_browser_process->profile_manager();
+ const ProfileInfoCache& cache = profile_manager->GetProfileInfoCache();
- // Change the profile to a managed user.
- ManagedUserService* managed_user_service =
- ManagedUserServiceFactory::GetForProfile(profile);
- managed_user_service->InitForTesting();
ManagedUserSettingsService* settings =
ManagedUserSettingsServiceFactory::GetForProfile(profile);
@@ -59,7 +73,7 @@ IN_PROC_BROWSER_TEST_F(ManagedUserServiceTest, ProfileName) {
scoped_ptr<base::Value>(new base::StringValue(name)));
EXPECT_FALSE(prefs->IsUserModifiablePreference(prefs::kProfileName));
EXPECT_EQ(name, prefs->GetString(prefs::kProfileName));
- profile_index = cache.GetIndexOfProfileWithPath(profile->GetPath());
+ size_t profile_index = cache.GetIndexOfProfileWithPath(profile->GetPath());
EXPECT_EQ(name, UTF16ToUTF8(cache.GetNameOfProfileAtIndex(profile_index)));
// Change the name once more.
diff --git a/chrome/browser/managed_mode/managed_user_service_unittest.cc b/chrome/browser/managed_mode/managed_user_service_unittest.cc
index 42a2a32f63..97183ebbed 100644
--- a/chrome/browser/managed_mode/managed_user_service_unittest.cc
+++ b/chrome/browser/managed_mode/managed_user_service_unittest.cc
@@ -20,7 +20,7 @@
#include "chrome/common/extensions/extension_builder.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_profile.h"
-#include "content/public/test/test_browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
#include "content/public/test/test_utils.h"
#include "extensions/common/manifest_constants.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -66,16 +66,14 @@ class ManagedModeURLFilterObserver : public ManagedModeURLFilter::Observer {
class ManagedUserServiceTest : public ::testing::Test {
public:
- ManagedUserServiceTest() : ui_thread_(content::BrowserThread::UI,
- &message_loop_) {
+ ManagedUserServiceTest() {
managed_user_service_ = ManagedUserServiceFactory::GetForProfile(&profile_);
}
virtual ~ManagedUserServiceTest() {}
protected:
- base::MessageLoop message_loop_;
- content::TestBrowserThread ui_thread_;
+ content::TestBrowserThreadBundle thread_bundle_;
TestingProfile profile_;
ManagedUserService* managed_user_service_;
};
@@ -152,18 +150,19 @@ TEST_F(ManagedUserServiceTest, ShutDownCustodianProfileDownloader) {
downloader_service->DownloadProfile(base::Bind(&OnProfileDownloadedFail));
}
-class ManagedUserServiceExtensionTest : public ExtensionServiceTestBase {
+class ManagedUserServiceExtensionTestBase : public ExtensionServiceTestBase {
public:
- ManagedUserServiceExtensionTest() {}
- virtual ~ManagedUserServiceExtensionTest() {}
+ explicit ManagedUserServiceExtensionTestBase(bool is_managed)
+ : is_managed_(is_managed) {}
+ virtual ~ManagedUserServiceExtensionTestBase() {}
virtual void SetUp() OVERRIDE {
ExtensionServiceTestBase::SetUp();
- InitializeEmptyExtensionService();
- }
-
- virtual void TearDown() OVERRIDE {
- ExtensionServiceTestBase::TearDown();
+ ExtensionServiceTestBase::ExtensionServiceInitParams params =
+ CreateDefaultInitParams();
+ params.profile_is_managed = is_managed_;
+ InitializeExtensionService(params);
+ ManagedUserServiceFactory::GetForProfile(profile_.get())->Init();
}
protected:
@@ -193,10 +192,26 @@ class ManagedUserServiceExtensionTest : public ExtensionServiceTestBase {
builder.SetManifest(manifest.Pass()).Build();
return extension;
}
+
+ bool is_managed_;
+};
+
+class ManagedUserServiceExtensionTestUnmanaged
+ : public ManagedUserServiceExtensionTestBase {
+ public:
+ ManagedUserServiceExtensionTestUnmanaged()
+ : ManagedUserServiceExtensionTestBase(false) {}
};
-TEST_F(ManagedUserServiceExtensionTest,
- ExtensionManagementPolicyProviderUnmanaged) {
+class ManagedUserServiceExtensionTest
+ : public ManagedUserServiceExtensionTestBase {
+ public:
+ ManagedUserServiceExtensionTest()
+ : ManagedUserServiceExtensionTestBase(true) {}
+};
+
+TEST_F(ManagedUserServiceExtensionTestUnmanaged,
+ ExtensionManagementPolicyProvider) {
ManagedUserService* managed_user_service =
ManagedUserServiceFactory::GetForProfile(profile_.get());
EXPECT_FALSE(profile_->IsManaged());
@@ -212,14 +227,12 @@ TEST_F(ManagedUserServiceExtensionTest,
EXPECT_EQ(string16(), error_2);
}
-TEST_F(ManagedUserServiceExtensionTest,
- ExtensionManagementPolicyProviderManaged) {
+TEST_F(ManagedUserServiceExtensionTest, ExtensionManagementPolicyProvider) {
ManagedUserService* managed_user_service =
ManagedUserServiceFactory::GetForProfile(profile_.get());
- managed_user_service->InitForTesting();
ManagedModeURLFilterObserver observer(
managed_user_service->GetURLFilterForUIThread());
- EXPECT_TRUE(profile_->IsManaged());
+ ASSERT_TRUE(profile_->IsManaged());
// Wait for the initial update to finish (otherwise we'll get leaks).
observer.Wait();
@@ -247,11 +260,9 @@ TEST_F(ManagedUserServiceExtensionTest,
#endif
}
-
TEST_F(ManagedUserServiceExtensionTest, NoContentPacks) {
ManagedUserService* managed_user_service =
ManagedUserServiceFactory::GetForProfile(profile_.get());
- managed_user_service->Init();
ManagedModeURLFilter* url_filter =
managed_user_service->GetURLFilterForUIThread();
@@ -266,7 +277,6 @@ TEST_F(ManagedUserServiceExtensionTest, NoContentPacks) {
TEST_F(ManagedUserServiceExtensionTest, InstallContentPacks) {
ManagedUserService* managed_user_service =
ManagedUserServiceFactory::GetForProfile(profile_.get());
- managed_user_service->InitForTesting();
ManagedModeURLFilter* url_filter =
managed_user_service->GetURLFilterForUIThread();
ManagedModeURLFilterObserver observer(url_filter);
diff --git a/chrome/browser/managed_mode/managed_user_sync_service.cc b/chrome/browser/managed_mode/managed_user_sync_service.cc
index 5ce6b4d608..9b673a35c9 100644
--- a/chrome/browser/managed_mode/managed_user_sync_service.cc
+++ b/chrome/browser/managed_mode/managed_user_sync_service.cc
@@ -36,7 +36,11 @@ using sync_pb::ManagedUserSpecifics;
namespace {
+#if defined(OS_CHROMEOS)
+const char kChromeOSAvatarPrefix[] = "chromeos-avatar-index:";
+#else
const char kChromeAvatarPrefix[] = "chrome-avatar-index:";
+#endif
SyncData CreateLocalSyncData(const std::string& id,
const std::string& name,
@@ -120,10 +124,14 @@ bool ManagedUserSyncService::GetAvatarIndex(const std::string& avatar_str,
*avatar_index = kNoAvatar;
return true;
}
-
- size_t prefix_len = strlen(kChromeAvatarPrefix);
+#if defined(OS_CHROMEOS)
+ const char* prefix = kChromeOSAvatarPrefix;
+#else
+ const char* prefix = kChromeAvatarPrefix;
+#endif
+ size_t prefix_len = strlen(prefix);
if (avatar_str.size() <= prefix_len ||
- avatar_str.substr(0, prefix_len) != kChromeAvatarPrefix) {
+ avatar_str.substr(0, prefix_len) != prefix) {
return false;
}
@@ -132,7 +140,12 @@ bool ManagedUserSyncService::GetAvatarIndex(const std::string& avatar_str,
// static
std::string ManagedUserSyncService::BuildAvatarString(int avatar_index) {
- return base::StringPrintf("%s%d", kChromeAvatarPrefix, avatar_index);
+#if defined(OS_CHROMEOS)
+ const char* prefix = kChromeOSAvatarPrefix;
+#else
+ const char* prefix = kChromeAvatarPrefix;
+#endif
+ return base::StringPrintf("%s%d", prefix, avatar_index);
}
void ManagedUserSyncService::AddObserver(
@@ -155,19 +168,14 @@ void ManagedUserSyncService::AddManagedUser(const std::string& id,
value->SetString(kName, name);
value->SetString(kMasterKey, master_key);
std::string chrome_avatar;
-#if defined(CHROME_OS)
- // This is a dummy value that is passed when a supervised user is created on
- // Chrome OS.
- // TODO(ibraaaa): update this to use the correct avatar index
- // once avatar syncing for supervised users is implemented on Chrome OS.
- DCHECK_EQ(avatar_index, -111);
+ std::string chromeos_avatar;
+#if defined(OS_CHROMEOS)
+ chromeos_avatar = BuildAvatarString(avatar_index);
#else
chrome_avatar = BuildAvatarString(avatar_index);
#endif
value->SetString(kChromeAvatar, chrome_avatar);
- // TODO(ibraaaa): this should be updated to allow supervised
- // users avatar syncing on Chrome OS.
- value->SetString(kChromeOsAvatar, std::string());
+ value->SetString(kChromeOsAvatar, chromeos_avatar);
DCHECK(!dict->HasKey(id));
dict->SetWithoutPathExpansion(id, value);
@@ -180,7 +188,7 @@ void ManagedUserSyncService::AddManagedUser(const std::string& id,
FROM_HERE,
SyncChange::ACTION_ADD,
CreateLocalSyncData(id, name, false, master_key,
- chrome_avatar, std::string())));
+ chrome_avatar, chromeos_avatar)));
SyncError error =
sync_processor_->ProcessSyncChanges(FROM_HERE, change_list);
DCHECK(!error.IsSet()) << error.ToString();
diff --git a/chrome/browser/managed_mode/managed_user_sync_service.h b/chrome/browser/managed_mode/managed_user_sync_service.h
index e6f70934eb..d802707b58 100644
--- a/chrome/browser/managed_mode/managed_user_sync_service.h
+++ b/chrome/browser/managed_mode/managed_user_sync_service.h
@@ -54,7 +54,8 @@ class ManagedUserSyncService : public BrowserContextKeyedService,
// where INDEX is the integer to be extracted. |avatar_str| can be empty
// in case there is no avatar synced for a managed user in which case
// |avatar_index| is set to -1.
- static bool GetAvatarIndex(const std::string& avatar_str, int* avatar_index);
+ static bool GetAvatarIndex(const std::string& avatar_str,
+ int* avatar_index);
// Given an |avatar_index|, it returns a string of the form:
// "chrome-avatar-index:INDEX" where INDEX = |avatar_index|.
diff --git a/chrome/browser/managed_mode/managed_user_sync_service_unittest.cc b/chrome/browser/managed_mode/managed_user_sync_service_unittest.cc
index 9b06cae9ec..fd0e1561a3 100644
--- a/chrome/browser/managed_mode/managed_user_sync_service_unittest.cc
+++ b/chrome/browser/managed_mode/managed_user_sync_service_unittest.cc
@@ -171,8 +171,13 @@ TEST_F(ManagedUserSyncServiceTest, MergeExisting) {
const char kName3[] = "Crush";
const char kName4[] = "Dory";
const char kAvatar1[] = "";
+#if defined(OS_CHROMEOS)
+ const char kAvatar2[] = "chromeos-avatar-index:0";
+ const char kAvatar3[] = "chromeos-avatar-index:20";
+#else
const char kAvatar2[] = "chrome-avatar-index:0";
const char kAvatar3[] = "chrome-avatar-index:20";
+#endif
const char kAvatar4[] = "";
{
DictionaryPrefUpdate update(prefs(), prefs::kManagedUsers);
@@ -274,18 +279,42 @@ TEST_F(ManagedUserSyncServiceTest, GetAvatarIndex) {
EXPECT_EQ(ManagedUserSyncService::kNoAvatar, avatar);
std::string avatar_str = ManagedUserSyncService::BuildAvatarString(24);
+#if defined(OS_CHROMEOS)
+ EXPECT_EQ("chromeos-avatar-index:24", avatar_str);
+#else
EXPECT_EQ("chrome-avatar-index:24", avatar_str);
+#endif
EXPECT_TRUE(ManagedUserSyncService::GetAvatarIndex(avatar_str, &avatar));
EXPECT_EQ(24, avatar);
avatar_str = ManagedUserSyncService::BuildAvatarString(0);
+#if defined(OS_CHROMEOS)
+ EXPECT_EQ("chromeos-avatar-index:0", avatar_str);
+#else
EXPECT_EQ("chrome-avatar-index:0", avatar_str);
+#endif
EXPECT_TRUE(ManagedUserSyncService::GetAvatarIndex(avatar_str, &avatar));
EXPECT_EQ(0, avatar);
EXPECT_FALSE(ManagedUserSyncService::GetAvatarIndex("wrong-prefix:5",
&avatar));
+#if defined(OS_CHROMEOS)
+ EXPECT_FALSE(ManagedUserSyncService::GetAvatarIndex("chromeos-avatar-indes:2",
+ &avatar));
+
+ EXPECT_FALSE(
+ ManagedUserSyncService::GetAvatarIndex("chromeos-avatar-indexxx:2",
+ &avatar));
+ EXPECT_FALSE(ManagedUserSyncService::GetAvatarIndex("chromeos-avatar-index:",
+ &avatar));
+
+ EXPECT_FALSE(ManagedUserSyncService::GetAvatarIndex("chromeos-avatar-index:x",
+ &avatar));
+
+ EXPECT_FALSE(ManagedUserSyncService::GetAvatarIndex("chrome-avatar-index:5",
+ &avatar));
+#else
EXPECT_FALSE(ManagedUserSyncService::GetAvatarIndex("chrome-avatar-indes:2",
&avatar));
@@ -297,4 +326,8 @@ TEST_F(ManagedUserSyncServiceTest, GetAvatarIndex) {
EXPECT_FALSE(ManagedUserSyncService::GetAvatarIndex("chrome-avatar-index:x",
&avatar));
+
+ EXPECT_FALSE(ManagedUserSyncService::GetAvatarIndex("chromeos-avatar-index:5",
+ &avatar));
+#endif
}
diff --git a/chrome/browser/media/chrome_media_stream_infobar_browsertest.cc b/chrome/browser/media/chrome_media_stream_infobar_browsertest.cc
index 2aa9b3f921..3e54269df1 100644
--- a/chrome/browser/media/chrome_media_stream_infobar_browsertest.cc
+++ b/chrome/browser/media/chrome_media_stream_infobar_browsertest.cc
@@ -44,16 +44,24 @@ class MediaStreamInfoBarTest : public WebRtcTestBase {
protected:
content::WebContents* LoadTestPageInTab() {
+ return LoadTestPageInBrowser(browser());
+ }
+
+ content::WebContents* LoadTestPageInIncognitoTab() {
+ return LoadTestPageInBrowser(CreateIncognitoBrowser());
+ }
+
+ private:
+ content::WebContents* LoadTestPageInBrowser(Browser* browser) {
EXPECT_TRUE(test_server()->Start());
const char kMainWebrtcTestHtmlPage[] =
"files/webrtc/webrtc_jsep01_test.html";
ui_test_utils::NavigateToURL(
- browser(), test_server()->GetURL(kMainWebrtcTestHtmlPage));
- return browser()->tab_strip_model()->GetActiveWebContents();
+ browser, test_server()->GetURL(kMainWebrtcTestHtmlPage));
+ return browser->tab_strip_model()->GetActiveWebContents();
}
- private:
DISALLOW_COPY_AND_ASSIGN(MediaStreamInfoBarTest);
};
@@ -82,6 +90,11 @@ IN_PROC_BROWSER_TEST_F(MediaStreamInfoBarTest, TestDismissingInfobar) {
GetUserMediaAndDismiss(tab_contents);
}
+IN_PROC_BROWSER_TEST_F(MediaStreamInfoBarTest, TestDenyingUserMediaIncognito) {
+ content::WebContents* tab_contents = LoadTestPageInIncognitoTab();
+ GetUserMediaAndDeny(tab_contents);
+}
+
// Failing on ChromiumOS Debug and Win Aura, so disabling on Aura.
// See http://crbug.com/263333.
#if defined(USE_AURA)
diff --git a/chrome/browser/media/chrome_webrtc_apprtc_browsertest.cc b/chrome/browser/media/chrome_webrtc_apprtc_browsertest.cc
index fa5b0e0784..d0ba4c8a4a 100644
--- a/chrome/browser/media/chrome_webrtc_apprtc_browsertest.cc
+++ b/chrome/browser/media/chrome_webrtc_apprtc_browsertest.cc
@@ -62,8 +62,7 @@ class WebrtcApprtcBrowserTest : public WebRtcTestBase {
}
base::FilePath apprtc_dir =
- GetSourceDir().Append(
- FILE_PATH_LITERAL("third_party/webrtc_apprtc/apprtc"));
+ GetSourceDir().Append(FILE_PATH_LITERAL("out/apprtc"));
if (!base::PathExists(apprtc_dir)) {
LOG(ERROR) << "Missing AppRTC code at " <<
apprtc_dir.value() << ". " << kAdviseOnGclientSolution;
@@ -120,11 +119,14 @@ class WebrtcApprtcBrowserTest : public WebRtcTestBase {
base::ProcessHandle dev_appserver_;
};
-IN_PROC_BROWSER_TEST_F(WebrtcApprtcBrowserTest, MANUAL_WorksOnApprtc) {
- if (!LaunchApprtcInstanceOnLocalhost()) {
- // TODO(phoglund): assert on this once everything is in place on the bots.
- return;
- }
+#if defined (OS_WIN) || defined(OS_MACOSX)
+#define MAYBE_MANUAL_WorksOnApprtc DISABLED_MANUAL_WorksOnApprtc
+#else
+#define MAYBE_MANUAL_WorksOnApprtc MANUAL_WorksOnApprtc
+#endif
+
+IN_PROC_BROWSER_TEST_F(WebrtcApprtcBrowserTest, MAYBE_MANUAL_WorksOnApprtc) {
+ ASSERT_TRUE(LaunchApprtcInstanceOnLocalhost());
while (!LocalApprtcInstanceIsUp())
LOG(INFO) << "Waiting for AppRTC to come up...";
diff --git a/chrome/browser/media/chrome_webrtc_audio_quality_browsertest.cc b/chrome/browser/media/chrome_webrtc_audio_quality_browsertest.cc
index 73d9328ece..d7a83a5569 100644
--- a/chrome/browser/media/chrome_webrtc_audio_quality_browsertest.cc
+++ b/chrome/browser/media/chrome_webrtc_audio_quality_browsertest.cc
@@ -47,7 +47,7 @@ static const base::FilePath::CharType kToolsPath[] =
static const char kMainWebrtcTestHtmlPage[] =
"files/webrtc/webrtc_audio_quality_test.html";
-base::FilePath GetTestDataDir() {
+static base::FilePath GetTestDataDir() {
base::FilePath source_dir;
PathService::Get(chrome::DIR_TEST_DATA, &source_dir);
return source_dir;
@@ -55,6 +55,9 @@ base::FilePath GetTestDataDir() {
// Test we can set up a WebRTC call and play audio through it.
//
+// You must have the src-internal solution in your .gclient to put the required
+// pyauto_private directory into chrome/test/data/.
+//
// This test will only work on machines that have been configured to record
// their own input.
//
diff --git a/chrome/browser/media/chrome_webrtc_typing_detection_browsertest.cc b/chrome/browser/media/chrome_webrtc_typing_detection_browsertest.cc
new file mode 100644
index 0000000000..a6aa242531
--- /dev/null
+++ b/chrome/browser/media/chrome_webrtc_typing_detection_browsertest.cc
@@ -0,0 +1,171 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <ctime>
+
+#include "base/path_service.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/browser/media/webrtc_browsertest_base.h"
+#include "chrome/browser/media/webrtc_browsertest_common.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_tabstrip.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "chrome/test/ui/ui_test.h"
+#include "content/public/test/browser_test_utils.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "testing/perf/perf_test.h"
+
+static const base::FilePath::CharType kReferenceFile[] =
+#if defined (OS_WIN)
+ FILE_PATH_LITERAL("pyauto_private/webrtc/human-voice-win.wav");
+#else
+ FILE_PATH_LITERAL("pyauto_private/webrtc/human-voice-linux.wav");
+#endif
+
+// The javascript will load the reference file relative to its location,
+// which is in /webrtc on the web server. Therefore, prepend a '..' traversal.
+static const char kReferenceFileRelativeUrl[] =
+#if defined (OS_WIN)
+ "../pyauto_private/webrtc/human-voice-win.wav";
+#else
+ "../pyauto_private/webrtc/human-voice-linux.wav";
+#endif
+
+static const char kMainWebrtcTestHtmlPage[] =
+ "files/webrtc/webrtc_audio_quality_test.html";
+
+static base::FilePath GetTestDataDir() {
+ base::FilePath source_dir;
+ PathService::Get(chrome::DIR_TEST_DATA, &source_dir);
+ return source_dir;
+}
+
+// Test that the typing detection feature works.
+// You must have the src-internal solution in your .gclient to put the required
+// pyauto_private directory into chrome/test/data/.
+class WebrtcTypingDetectionBrowserTest : public WebRtcTestBase {
+ public:
+ // TODO(phoglund): clean up duplication from audio quality browser test when
+ // this test is complete and is proven to work.
+ virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
+ PeerConnectionServerRunner::KillAllPeerConnectionServersOnCurrentSystem();
+ }
+
+ bool HasAllRequiredResources() {
+ base::FilePath reference_file =
+ GetTestDataDir().Append(kReferenceFile);
+ if (!base::PathExists(reference_file)) {
+ LOG(ERROR) << "Cannot find the reference file to be used for audio "
+ << "quality comparison: " << reference_file.value();
+ return false;
+ }
+ return true;
+ }
+
+ void AddAudioFile(const std::string& input_file_relative_url,
+ content::WebContents* tab_contents) {
+ EXPECT_EQ("ok-added", ExecuteJavascript(
+ "addAudioFile('" + input_file_relative_url + "')", tab_contents));
+ }
+
+ void PlayAudioFile(content::WebContents* tab_contents) {
+ EXPECT_EQ("ok-playing", ExecuteJavascript("playAudioFile()", tab_contents));
+ }
+
+ void MixLocalStreamWithPreviouslyLoadedAudioFile(
+ content::WebContents* tab_contents) {
+ EXPECT_EQ("ok-mixed-in", ExecuteJavascript(
+ "mixLocalStreamWithPreviouslyLoadedAudioFile()", tab_contents));
+ }
+
+ // Ensures we didn't get any errors asynchronously (e.g. while no javascript
+ // call from this test was outstanding).
+ void AssertNoAsynchronousErrors(content::WebContents* tab_contents) {
+ EXPECT_EQ("ok-no-errors",
+ ExecuteJavascript("getAnyTestFailures()", tab_contents));
+ }
+
+ void EstablishCall(content::WebContents* from_tab,
+ content::WebContents* to_tab) {
+ EXPECT_EQ("ok-negotiating",
+ ExecuteJavascript("negotiateCall()", from_tab));
+
+ // Ensure the call gets up on both sides.
+ EXPECT_TRUE(PollingWaitUntil("getPeerConnectionReadyState()",
+ "active", from_tab));
+ EXPECT_TRUE(PollingWaitUntil("getPeerConnectionReadyState()",
+ "active", to_tab));
+ }
+
+ void HangUp(content::WebContents* from_tab) {
+ EXPECT_EQ("ok-call-hung-up", ExecuteJavascript("hangUp()", from_tab));
+ }
+
+ void WaitUntilHangupVerified(content::WebContents* tab_contents) {
+ EXPECT_TRUE(PollingWaitUntil("getPeerConnectionReadyState()",
+ "no-peer-connection", tab_contents));
+ }
+
+ PeerConnectionServerRunner peerconnection_server_;
+};
+
+// TODO(phoglund): enable when fully implemented.
+IN_PROC_BROWSER_TEST_F(WebrtcTypingDetectionBrowserTest,
+ DISABLED_MANUAL_TestTypingDetection) {
+ // TODO(phoglund): make this use embedded_test_server when that test server
+ // can handle files > ~400Kb.
+ ASSERT_TRUE(test_server()->Start());
+ ASSERT_TRUE(peerconnection_server_.Start());
+
+ ui_test_utils::NavigateToURL(
+ browser(), test_server()->GetURL(kMainWebrtcTestHtmlPage));
+ content::WebContents* left_tab =
+ browser()->tab_strip_model()->GetActiveWebContents();
+
+ chrome::AddBlankTabAt(browser(), -1, true);
+ content::WebContents* right_tab =
+ browser()->tab_strip_model()->GetActiveWebContents();
+ ui_test_utils::NavigateToURL(
+ browser(), test_server()->GetURL(kMainWebrtcTestHtmlPage));
+
+ ConnectToPeerConnectionServer("peer 1", left_tab);
+ ConnectToPeerConnectionServer("peer 2", right_tab);
+
+ GetUserMediaWithSpecificConstraintsAndAccept(left_tab,
+ kAudioOnlyCallConstraints);
+ EXPECT_EQ("ok-peerconnection-created",
+ ExecuteJavascript("preparePeerConnection(false, true)", left_tab));
+
+ AddAudioFile(kReferenceFileRelativeUrl, left_tab);
+ MixLocalStreamWithPreviouslyLoadedAudioFile(left_tab);
+
+ EstablishCall(left_tab, right_tab);
+
+ // Note: the media flow isn't necessarily established on the connection just
+ // because the ready state is ok on both sides. We sleep a bit between call
+ // establishment and playing to avoid cutting of the beginning of the audio
+ // file.
+ SleepInJavascript(left_tab, 2000);
+
+ PlayAudioFile(left_tab);
+
+ // TODO(phoglund): simulate key presses, look for changes in typing detection
+ // state.
+ SleepInJavascript(left_tab, 10000);
+
+ AssertNoAsynchronousErrors(left_tab);
+ AssertNoAsynchronousErrors(right_tab);
+
+ HangUp(left_tab);
+ WaitUntilHangupVerified(left_tab);
+ WaitUntilHangupVerified(right_tab);
+
+ AssertNoAsynchronousErrors(left_tab);
+ AssertNoAsynchronousErrors(right_tab);
+
+ ASSERT_TRUE(peerconnection_server_.Stop());
+}
diff --git a/chrome/browser/media/encrypted_media_browsertest.cc b/chrome/browser/media/encrypted_media_browsertest.cc
index e1e68aa75c..9c2484921d 100644
--- a/chrome/browser/media/encrypted_media_browsertest.cc
+++ b/chrome/browser/media/encrypted_media_browsertest.cc
@@ -11,6 +11,9 @@
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/chrome_switches.h"
#include "content/public/test/browser_test_utils.h"
+#if defined(OS_ANDROID)
+#include "base/android/build_info.h"
+#endif
#include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR.
@@ -47,8 +50,8 @@ const char kMP4VideoOnly[] = "video/mp4; codecs=\"avc1.4D4041\"";
#endif // defined(USE_PROPRIETARY_CODECS)
// EME-specific test results and errors.
-const char kEmeGkrException[] = "GENERATE_KEY_REQUEST_EXCEPTION";
const char kEmeKeyError[] = "KEYERROR";
+const char kEmeNotSupportedError[] = "NOTSUPPORTEDERROR";
// The type of video src used to load media.
enum SrcType {
@@ -56,20 +59,24 @@ enum SrcType {
MSE
};
-// Tests encrypted media playback with a combination of parameters:
-// - char*: Key system name.
-// - bool: True to load media using MSE, otherwise use src.
-class EncryptedMediaTest : public MediaBrowserTest,
- public testing::WithParamInterface<std::tr1::tuple<const char*, SrcType> > {
- public:
- // Can only be used in parameterized (*_P) tests.
- const char* CurrentKeySystem() {
- return std::tr1::get<0>(GetParam());
+// MSE is available on all desktop platforms and on Android 4.1 and later.
+static bool IsMSESupported() {
+#if defined(OS_ANDROID)
+ if (base::android::BuildInfo::GetInstance()->sdk_int() < 16) {
+ LOG(INFO) << "MSE is only supported in Android 4.1 and later.";
+ return false;
}
+#endif // defined(OS_ANDROID)
+ return true;
+}
- // Can only be used in parameterized (*_P) tests.
- SrcType CurrentSourceType() {
- return std::tr1::get<1>(GetParam());
+// Base class for encrypted media tests.
+class EncryptedMediaTestBase : public MediaBrowserTest {
+ public:
+ EncryptedMediaTestBase() : is_pepper_cdm_registered_(false) {}
+
+ bool IsExternalClearKey(const char* key_system) {
+ return (strcmp(key_system, kExternalClearKeyKeySystem) == 0);
}
#if defined(WIDEVINE_CDM_AVAILABLE)
@@ -78,42 +85,17 @@ class EncryptedMediaTest : public MediaBrowserTest,
}
#endif // defined(WIDEVINE_CDM_AVAILABLE)
- void TestSimplePlayback(const char* encrypted_media, const char* media_type) {
- RunSimpleEncryptedMediaTest(
- encrypted_media, media_type, CurrentKeySystem(), CurrentSourceType());
- }
-
- void TestFrameSizeChange() {
-#if defined(WIDEVINE_CDM_AVAILABLE)
- if (IsWidevine(CurrentKeySystem())) {
- LOG(INFO) << "FrameSizeChange test cannot run with Widevine.";
- return;
- }
-#endif // defined(WIDEVINE_CDM_AVAILABLE)
- RunEncryptedMediaTest("encrypted_frame_size_change.html",
- "frame_size_change-av-enc-v.webm", kWebMAudioVideo,
- CurrentKeySystem(), CurrentSourceType(), kEnded);
- }
-
- void TestConfigChange() {
-#if defined(WIDEVINE_CDM_AVAILABLE)
- if (IsWidevine(CurrentKeySystem())) {
- LOG(INFO) << "ConfigChange test cannot run with Widevine.";
- return;
- }
-#endif // defined(WIDEVINE_CDM_AVAILABLE)
- std::vector<StringPair> query_params;
- query_params.push_back(std::make_pair("keysystem", CurrentKeySystem()));
- query_params.push_back(std::make_pair("runencrypted", "1"));
- RunMediaTestPage("mse_config_change.html", &query_params, kEnded, true);
- }
-
void RunEncryptedMediaTest(const char* html_page,
const char* media_file,
const char* media_type,
const char* key_system,
SrcType src_type,
const char* expectation) {
+ if (src_type == MSE && !IsMSESupported()) {
+ LOG(INFO) << "Skipping test - MSE not supported.";
+ return;
+ }
+
std::vector<StringPair> query_params;
query_params.push_back(std::make_pair("mediafile", media_file));
query_params.push_back(std::make_pair("mediatype", media_type));
@@ -165,20 +147,11 @@ class EncryptedMediaTest : public MediaBrowserTest,
// We want to fail quickly when a test fails because an error is encountered.
virtual void AddWaitForTitles(content::TitleWatcher* title_watcher) OVERRIDE {
MediaBrowserTest::AddWaitForTitles(title_watcher);
- title_watcher->AlsoWaitForTitle(ASCIIToUTF16(kEmeGkrException));
+ title_watcher->AlsoWaitForTitle(ASCIIToUTF16(kEmeNotSupportedError));
title_watcher->AlsoWaitForTitle(ASCIIToUTF16(kEmeKeyError));
}
virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
-#if defined(ENABLE_PEPPER_CDMS)
- RegisterPepperCdm(command_line, kClearKeyCdmAdapterFileName,
- kExternalClearKeyKeySystem);
-#if defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)
- RegisterPepperCdm(command_line, kWidevineCdmAdapterFileName,
- kWidevineKeySystem);
-#endif // defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)
-#endif // defined(ENABLE_PEPPER_CDMS) }
-
#if defined(OS_ANDROID)
command_line->AppendSwitch(
switches::kDisableGestureRequirementForMediaPlayback);
@@ -191,10 +164,31 @@ class EncryptedMediaTest : public MediaBrowserTest,
#endif // defined(OS_CHROMEOS)
}
+ void SetUpCommandLineForKeySystem(const char* key_system,
+ CommandLine* command_line) {
+#if defined(ENABLE_PEPPER_CDMS)
+ if (IsExternalClearKey(key_system)) {
+ RegisterPepperCdm(command_line, kClearKeyCdmAdapterFileName,
+ kExternalClearKeyKeySystem);
+ }
+#if defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)
+ else if (IsWidevine(key_system)) {
+ RegisterPepperCdm(command_line, kWidevineCdmAdapterFileName,
+ kWidevineKeySystem);
+ }
+#endif // defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)
+#endif // defined(ENABLE_PEPPER_CDMS)
+ }
+
+ private:
#if defined(ENABLE_PEPPER_CDMS)
void RegisterPepperCdm(CommandLine* command_line,
const std::string& adapter_name,
const std::string& key_system) {
+ DCHECK(!is_pepper_cdm_registered_)
+ << "RegisterPepperCdm() can only be called once.";
+ is_pepper_cdm_registered_ = true;
+
// Append the switch to register the Clear Key CDM Adapter.
base::FilePath plugin_dir;
EXPECT_TRUE(PathService::Get(base::DIR_MODULE, &plugin_dir));
@@ -224,27 +218,117 @@ class EncryptedMediaTest : public MediaBrowserTest,
return "";
}
#endif // defined(ENABLE_PEPPER_CDMS)
+
+ bool is_pepper_cdm_registered_;
+};
+
+#if defined(ENABLE_PEPPER_CDMS)
+// Tests encrypted media playback using ExternalClearKey key system.
+class ECKEncryptedMediaTest : public EncryptedMediaTestBase {
+ protected:
+ virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+ EncryptedMediaTestBase::SetUpCommandLine(command_line);
+ SetUpCommandLineForKeySystem(kExternalClearKeyKeySystem, command_line);
+ }
+};
+
+#if defined(WIDEVINE_CDM_AVAILABLE)
+// Tests encrypted media playback using Widevine key system.
+class WVEncryptedMediaTest : public EncryptedMediaTestBase {
+ protected:
+ virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+ EncryptedMediaTestBase::SetUpCommandLine(command_line);
+ SetUpCommandLineForKeySystem(kWidevineKeySystem, command_line);
+ }
+};
+#endif // defined(WIDEVINE_CDM_AVAILABLE)
+#endif // defined(ENABLE_PEPPER_CDMS)
+
+// Tests encrypted media playback with a combination of parameters:
+// - char*: Key system name.
+// - bool: True to load media using MSE, otherwise use src.
+//
+// Note: Only parameterized (*_P) tests can be used. Non-parameterized (*_F)
+// tests will crash at GetParam(). To add non-parameterized tests, use
+// EncryptedMediaTestBase or one of its subclasses (e.g. WVEncryptedMediaTest).
+class EncryptedMediaTest : public EncryptedMediaTestBase,
+ public testing::WithParamInterface<std::tr1::tuple<const char*, SrcType> > {
+ public:
+ const char* CurrentKeySystem() {
+ return std::tr1::get<0>(GetParam());
+ }
+
+ SrcType CurrentSourceType() {
+ return std::tr1::get<1>(GetParam());
+ }
+
+ void TestSimplePlayback(const char* encrypted_media, const char* media_type) {
+ RunSimpleEncryptedMediaTest(
+ encrypted_media, media_type, CurrentKeySystem(), CurrentSourceType());
+ }
+
+ void TestFrameSizeChange() {
+#if defined(WIDEVINE_CDM_AVAILABLE)
+ if (IsWidevine(CurrentKeySystem())) {
+ LOG(INFO) << "FrameSizeChange test cannot run with Widevine.";
+ return;
+ }
+#endif // defined(WIDEVINE_CDM_AVAILABLE)
+ RunEncryptedMediaTest("encrypted_frame_size_change.html",
+ "frame_size_change-av-enc-v.webm", kWebMAudioVideo,
+ CurrentKeySystem(), CurrentSourceType(), kEnded);
+ }
+
+ void TestConfigChange() {
+ if (CurrentSourceType() != MSE || !IsMSESupported()) {
+ LOG(INFO) << "Skipping test - config change test requires MSE.";
+ return;
+ }
+#if defined(WIDEVINE_CDM_AVAILABLE)
+ if (IsWidevine(CurrentKeySystem())) {
+ LOG(INFO) << "ConfigChange test cannot run with Widevine.";
+ return;
+ }
+#endif // defined(WIDEVINE_CDM_AVAILABLE)
+ std::vector<StringPair> query_params;
+ query_params.push_back(std::make_pair("keysystem", CurrentKeySystem()));
+ query_params.push_back(std::make_pair("runencrypted", "1"));
+ RunMediaTestPage("mse_config_change.html", &query_params, kEnded, true);
+ }
+
+ protected:
+ virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+ EncryptedMediaTestBase::SetUpCommandLine(command_line);
+ SetUpCommandLineForKeySystem(CurrentKeySystem(), command_line);
+ }
};
-INSTANTIATE_TEST_CASE_P(ClearKey, EncryptedMediaTest,
- ::testing::Combine(
- ::testing::Values(kClearKeyKeySystem), ::testing::Values(SRC, MSE)));
+using ::testing::Combine;
+using ::testing::Values;
+
+#if !defined(OS_ANDROID)
+INSTANTIATE_TEST_CASE_P(SRC_ClearKey, EncryptedMediaTest,
+ Combine(Values(kClearKeyKeySystem), Values(SRC)));
+#endif // !defined(OS_ANDROID)
+
+INSTANTIATE_TEST_CASE_P(MSE_ClearKey, EncryptedMediaTest,
+ Combine(Values(kClearKeyKeySystem), Values(MSE)));
// External Clear Key is currently only used on platforms that use Pepper CDMs.
#if defined(ENABLE_PEPPER_CDMS)
-INSTANTIATE_TEST_CASE_P(ExternalClearKey, EncryptedMediaTest,
- ::testing::Combine(
- ::testing::Values(kExternalClearKeyKeySystem),
- ::testing::Values(SRC, MSE)));
+INSTANTIATE_TEST_CASE_P(SRC_ExternalClearKey, EncryptedMediaTest,
+ Combine(Values(kExternalClearKeyKeySystem), Values(SRC)));
+INSTANTIATE_TEST_CASE_P(MSE_ExternalClearKey, EncryptedMediaTest,
+ Combine(Values(kExternalClearKeyKeySystem), Values(MSE)));
+#endif // defined(ENABLE_PEPPER_CDMS)
#if defined(WIDEVINE_CDM_AVAILABLE)
// This test doesn't fully test playback with Widevine. So we only run Widevine
-// test with MSE (no SRC) to reduce test time.
-INSTANTIATE_TEST_CASE_P(Widevine, EncryptedMediaTest,
- ::testing::Combine(
- ::testing::Values(kWidevineKeySystem), ::testing::Values(MSE)));
+// test with MSE (no SRC) to reduce test time. Also, on Android EME only works
+// with MSE and we cannot run this test with SRC.
+INSTANTIATE_TEST_CASE_P(MSE_Widevine, EncryptedMediaTest,
+ Combine(Values(kWidevineKeySystem), Values(MSE)));
#endif // defined(WIDEVINE_CDM_AVAILABLE)
-#endif // defined(ENABLE_PEPPER_CDMS)
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_AudioOnly_WebM) {
TestSimplePlayback("bear-a-enc_a.webm", kWebMAudioOnly);
@@ -301,14 +385,19 @@ IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_AudioOnly_MP4) {
#if defined(WIDEVINE_CDM_AVAILABLE)
// The parent key system cannot be used in generateKeyRequest.
-IN_PROC_BROWSER_TEST_F(EncryptedMediaTest, WVParentThrowsException) {
- RunEncryptedMediaTest("encrypted_media_player.html", "bear-a-enc_a.webm",
- kWebMAudioOnly, "com.widevine", SRC, kEmeGkrException);
+IN_PROC_BROWSER_TEST_F(WVEncryptedMediaTest, ParentThrowsException) {
+ RunEncryptedMediaTest("encrypted_media_player.html",
+ "bear-a-enc_a.webm",
+ kWebMAudioOnly,
+ "com.widevine",
+ MSE,
+ kEmeNotSupportedError);
}
#endif // defined(WIDEVINE_CDM_AVAILABLE)
#if defined(ENABLE_PEPPER_CDMS)
-IN_PROC_BROWSER_TEST_F(EncryptedMediaTest, ExternalClearKeyInitializeCDMFail) {
+IN_PROC_BROWSER_TEST_F(ECKEncryptedMediaTest,
+ ExternalClearKeyInitializeCDMFail) {
RunEncryptedMediaTest("encrypted_media_player.html",
"bear-a-enc_a.webm",
kWebMAudioOnly,
diff --git a/chrome/browser/media/encrypted_media_istypesupported_browsertest.cc b/chrome/browser/media/encrypted_media_istypesupported_browsertest.cc
index 647fdaa242..1006a2fb6e 100644
--- a/chrome/browser/media/encrypted_media_istypesupported_browsertest.cc
+++ b/chrome/browser/media/encrypted_media_istypesupported_browsertest.cc
@@ -112,6 +112,10 @@ class EncryptedMediaIsTypeSupportedTest : public InProcessBrowserTest {
avc2_codec_.push_back("avc2");
+ avc3_codec_.push_back("avc3");
+
+ avc3_extended_codec_.push_back("avc3.64001f");
+
aac_codec_.push_back("mp4a");
avc1_and_aac_codecs_.push_back("avc1");
@@ -138,6 +142,10 @@ class EncryptedMediaIsTypeSupportedTest : public InProcessBrowserTest {
}
const CodecVector& avc1_dot_codec() const { return avc1_dot_codec_; }
const CodecVector& avc2_codec() const { return avc2_codec_; }
+ const CodecVector& avc3_codec() const { return avc3_codec_; }
+ const CodecVector& avc3_extended_codec() const {
+ return avc3_extended_codec_;
+ }
const CodecVector& aac_codec() const { return aac_codec_; }
const CodecVector& avc1_and_aac_codecs() const {
return avc1_and_aac_codecs_;
@@ -243,6 +251,8 @@ class EncryptedMediaIsTypeSupportedTest : public InProcessBrowserTest {
CodecVector avc1_extended_codec_;
CodecVector avc1_dot_codec_;
CodecVector avc2_codec_;
+ CodecVector avc3_codec_;
+ CodecVector avc3_extended_codec_;
CodecVector aac_codec_;
CodecVector avc1_and_aac_codecs_;
CodecVector unknown_codec_;
@@ -444,11 +454,15 @@ IN_PROC_BROWSER_TEST_F(EncryptedMediaIsTypeSupportedTest,
EXPECT_PROPRIETARY(IsSupportedKeySystemWithMediaMimeType(
"video/mp4", avc1_and_aac_codecs(), kPrefixedClearKey));
EXPECT_PROPRIETARY(IsSupportedKeySystemWithMediaMimeType(
+ "video/mp4", avc3_codec(), kPrefixedClearKey));
+ EXPECT_PROPRIETARY(IsSupportedKeySystemWithMediaMimeType(
"video/mp4", aac_codec(), kPrefixedClearKey));
// Extended codecs.
EXPECT_PROPRIETARY(IsSupportedKeySystemWithMediaMimeType(
"video/mp4", avc1_extended_codec(), kPrefixedClearKey));
+ EXPECT_PROPRIETARY(IsSupportedKeySystemWithMediaMimeType(
+ "video/mp4", avc3_extended_codec(), kPrefixedClearKey));
// Invalid codec format, but canPlayType() strips away the period.
EXPECT_PROPRIETARY(IsSupportedKeySystemWithMediaMimeType(
@@ -475,6 +489,8 @@ IN_PROC_BROWSER_TEST_F(EncryptedMediaIsTypeSupportedTest,
"audio/mp4", avc1_codec(), kPrefixedClearKey));
EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
"audio/mp4", avc1_and_aac_codecs(), kPrefixedClearKey));
+ EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
+ "audio/mp4", avc3_codec(), kPrefixedClearKey));
// Non-MP4 codec.
EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
@@ -614,11 +630,15 @@ IN_PROC_BROWSER_TEST_F(
EXPECT_ECKPROPRIETARY(IsSupportedKeySystemWithMediaMimeType(
"video/mp4", avc1_and_aac_codecs(), kExternalClearKey));
EXPECT_ECKPROPRIETARY(IsSupportedKeySystemWithMediaMimeType(
+ "video/mp4", avc3_codec(), kExternalClearKey));
+ EXPECT_ECKPROPRIETARY(IsSupportedKeySystemWithMediaMimeType(
"video/mp4", aac_codec(), kExternalClearKey));
// Extended codecs.
EXPECT_ECKPROPRIETARY(IsSupportedKeySystemWithMediaMimeType(
"video/mp4", avc1_extended_codec(), kExternalClearKey));
+ EXPECT_ECKPROPRIETARY(IsSupportedKeySystemWithMediaMimeType(
+ "video/mp4", avc3_extended_codec(), kExternalClearKey));
// Invalid codec format, but canPlayType() strips away the period.
EXPECT_ECKPROPRIETARY(IsSupportedKeySystemWithMediaMimeType(
@@ -645,6 +665,8 @@ IN_PROC_BROWSER_TEST_F(
"audio/mp4", avc1_codec(), kExternalClearKey));
EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
"audio/mp4", avc1_and_aac_codecs(), kExternalClearKey));
+ EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
+ "audio/mp4", avc3_codec(), kExternalClearKey));
// Non-MP4 codec.
EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
@@ -792,6 +814,8 @@ IN_PROC_BROWSER_TEST_F(EncryptedMediaIsTypeSupportedWidevineTest,
"video/mp4", avc1_codec(), kWidevineAlpha));
EXPECT_WVAVC1AAC(IsSupportedKeySystemWithMediaMimeType(
"video/mp4", avc1_and_aac_codecs(), kWidevineAlpha));
+ EXPECT_WVAVC1(IsSupportedKeySystemWithMediaMimeType(
+ "video/mp4", avc3_codec(), kWidevineAlpha));
EXPECT_WVAVC1AAC(IsSupportedKeySystemWithMediaMimeType(
"video/mp4", aac_codec(), kWidevineAlpha));
@@ -808,6 +832,8 @@ IN_PROC_BROWSER_TEST_F(EncryptedMediaIsTypeSupportedWidevineTest,
// Extended codecs.
EXPECT_WVAVC1(IsSupportedKeySystemWithMediaMimeType(
"video/mp4", avc1_extended_codec(), kWidevineAlpha));
+ EXPECT_WVAVC1(IsSupportedKeySystemWithMediaMimeType(
+ "video/mp4", avc3_extended_codec(), kWidevineAlpha));
// Invalid codec format, but canPlayType() strips away the period.
EXPECT_WVAVC1(IsSupportedKeySystemWithMediaMimeType(
@@ -840,6 +866,8 @@ IN_PROC_BROWSER_TEST_F(EncryptedMediaIsTypeSupportedWidevineTest,
"audio/mp4", avc1_codec(), kWidevineAlpha));
EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
"audio/mp4", avc1_and_aac_codecs(), kWidevineAlpha));
+ EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
+ "audio/mp4", avc3_codec(), kWidevineAlpha));
// Non-MP4 codec.
EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
diff --git a/chrome/browser/media/webrtc_log_upload_list.cc b/chrome/browser/media/webrtc_log_upload_list.cc
index fdaaad072f..15c2963a8a 100644
--- a/chrome/browser/media/webrtc_log_upload_list.cc
+++ b/chrome/browser/media/webrtc_log_upload_list.cc
@@ -6,19 +6,25 @@
#include "base/files/file_path.h"
#include "base/path_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_paths.h"
+namespace {
+
+const char* kWebRtcLogListFilename = "webrtc_log_uploads.log";
+
+}
+
// static
-const char* WebRtcLogUploadList::kWebRtcLogListFilename =
- "webrtc_log_uploads.log";
+WebRtcLogUploadList* WebRtcLogUploadList::Create(Delegate* delegate,
+ Profile* profile) {
+ return new WebRtcLogUploadList(delegate, GetFilePathForProfile(profile));
+}
// static
-WebRtcLogUploadList* WebRtcLogUploadList::Create(Delegate* delegate) {
- base::FilePath log_dir_path;
- PathService::Get(chrome::DIR_USER_DATA, &log_dir_path);
- base::FilePath upload_log_path =
- log_dir_path.AppendASCII(kWebRtcLogListFilename);
- return new WebRtcLogUploadList(delegate, upload_log_path);
+base::FilePath WebRtcLogUploadList::GetFilePathForProfile(Profile* profile) {
+ base::FilePath log_dir_path = profile->GetPath();
+ return log_dir_path.AppendASCII(kWebRtcLogListFilename);
}
WebRtcLogUploadList::WebRtcLogUploadList(Delegate* delegate,
diff --git a/chrome/browser/media/webrtc_log_upload_list.h b/chrome/browser/media/webrtc_log_upload_list.h
index b829d8e647..51e2c808cb 100644
--- a/chrome/browser/media/webrtc_log_upload_list.h
+++ b/chrome/browser/media/webrtc_log_upload_list.h
@@ -7,15 +7,17 @@
#include "chrome/browser/upload_list.h"
+class Profile;
+
// Loads and parses a text file list of uploaded WebRTC logs.
class WebRtcLogUploadList : public UploadList {
public:
- // Creates the WebRTC log upload list with the given callback delegate.
- static WebRtcLogUploadList* Create(Delegate* delegate);
+ // Creates the WebRTC log upload list with the given callback delegate for
+ // a profile.
+ static WebRtcLogUploadList* Create(Delegate* delegate, Profile* profile);
- // Used in this class when reading the list file and in WebRtcLogUploader when
- // writing to the list file.
- static const char* kWebRtcLogListFilename;
+ // Get the file path for the log list file for a profile.
+ static base::FilePath GetFilePathForProfile(Profile* profile);
// Creates a new WebRTC log upload list with the given callback delegate.
// |upload_log_path| is the full path to the file to read the list from.
diff --git a/chrome/browser/media/webrtc_log_uploader.cc b/chrome/browser/media/webrtc_log_uploader.cc
index 740e0ac776..15b2ba15c4 100644
--- a/chrome/browser/media/webrtc_log_uploader.cc
+++ b/chrome/browser/media/webrtc_log_uploader.cc
@@ -43,22 +43,21 @@ const char kMultipartBoundary[] =
WebRtcLogUploader::WebRtcLogUploader()
: log_count_(0),
- post_data_(NULL) {
- base::FilePath log_dir_path;
- PathService::Get(chrome::DIR_USER_DATA, &log_dir_path);
- upload_list_path_ =
- log_dir_path.AppendASCII(WebRtcLogUploadList::kWebRtcLogListFilename);
-}
+ post_data_(NULL) {}
WebRtcLogUploader::~WebRtcLogUploader() {}
void WebRtcLogUploader::OnURLFetchComplete(
const net::URLFetcher* source) {
+ DCHECK(upload_done_data_.find(source) != upload_done_data_.end());
int response_code = source->GetResponseCode();
std::string report_id;
- if (response_code == 200 && source->GetResponseAsString(&report_id))
- AddUploadedLogInfoToUploadListFile(report_id);
- DCHECK(upload_done_data_.find(source) != upload_done_data_.end());
+ if (response_code == 200 && source->GetResponseAsString(&report_id)) {
+ AddUploadedLogInfoToUploadListFile(
+ WebRtcLogUploadList::GetFilePathForProfile(
+ upload_done_data_[source].profile),
+ report_id);
+ }
content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
base::Bind(&WebRtcLoggingHandlerHost::UploadLogDone,
upload_done_data_[source].host));
@@ -249,11 +248,12 @@ void WebRtcLogUploader::DecreaseLogCount() {
}
void WebRtcLogUploader::AddUploadedLogInfoToUploadListFile(
+ const base::FilePath& upload_list_path,
const std::string& report_id) {
std::string contents;
- if (base::PathExists(upload_list_path_)) {
- bool read_ok = base::ReadFileToString(upload_list_path_, &contents);
+ if (base::PathExists(upload_list_path)) {
+ bool read_ok = base::ReadFileToString(upload_list_path, &contents);
DPCHECK(read_ok);
// Limit the number of log entries to |kLogListLimitLines| - 1, to make room
@@ -277,7 +277,7 @@ void WebRtcLogUploader::AddUploadedLogInfoToUploadListFile(
contents += base::DoubleToString(time_now.ToDoubleT()) +
"," + report_id + '\n';
- int written = file_util::WriteFile(upload_list_path_, &contents[0],
+ int written = file_util::WriteFile(upload_list_path, &contents[0],
contents.size());
DPCHECK(written == static_cast<int>(contents.size()));
}
diff --git a/chrome/browser/media/webrtc_log_uploader.h b/chrome/browser/media/webrtc_log_uploader.h
index 167ccbbdab..2eca66b43d 100644
--- a/chrome/browser/media/webrtc_log_uploader.h
+++ b/chrome/browser/media/webrtc_log_uploader.h
@@ -15,6 +15,8 @@
#include "chrome/browser/media/webrtc_logging_handler_host.h"
#include "net/url_request/url_fetcher_delegate.h"
+class Profile;
+
namespace base {
class SharedMemory;
}
@@ -26,8 +28,9 @@ class URLRequestContextGetter;
typedef struct z_stream_s z_stream;
-// Used when uploading is done to inform about that it's done.
+// Used when uploading is done to perform post-upload actions.
typedef struct {
+ Profile* profile;
WebRtcLoggingHandlerHost::UploadDoneCallback callback;
scoped_refptr<WebRtcLoggingHandlerHost> host;
} WebRtcLogUploadDoneData;
@@ -62,7 +65,7 @@ class WebRtcLogUploader : public net::URLFetcherDelegate {
// Notifies that that logging has stopped and that the log should be uploaded.
// Decreases log count. May only be called if permission to log has been
// granted by calling ApplyForStartLogging() and getting true in return. After
- // this function has been called, a new permission must be granted. Call
+ // this function has been called, a new permission must be granted. Call
// either this function or LoggingStoppedDontUpload().
void LoggingStoppedDoUpload(
net::URLRequestContextGetter* request_context,
@@ -101,14 +104,11 @@ class WebRtcLogUploader : public net::URLFetcherDelegate {
// time,id
// etc.
// where each line represents an uploaded log and "time" is Unix time.
- void AddUploadedLogInfoToUploadListFile(const std::string& report_id);
-
- void SetUploadPathForTesting(const base::FilePath& path) {
- upload_list_path_ = path;
- }
+ void AddUploadedLogInfoToUploadListFile(
+ const base::FilePath& upload_list_path,
+ const std::string& report_id);
int log_count_;
- base::FilePath upload_list_path_;
// For testing purposes, see OverrideUploadWithBufferForTesting. Only accessed
// on the FILE thread.
diff --git a/chrome/browser/media/webrtc_log_uploader_unittest.cc b/chrome/browser/media/webrtc_log_uploader_unittest.cc
index 69d1b7f86b..e2fb25af91 100644
--- a/chrome/browser/media/webrtc_log_uploader_unittest.cc
+++ b/chrome/browser/media/webrtc_log_uploader_unittest.cc
@@ -92,22 +92,25 @@ TEST_F(WebRtcLogUploaderTest, AddUploadedLogInfoToUploadListFile) {
EXPECT_TRUE(base::DeleteFile(test_list_path_, false));
scoped_ptr<WebRtcLogUploader> webrtc_log_uploader_(
new WebRtcLogUploader());
- webrtc_log_uploader_->SetUploadPathForTesting(test_list_path_);
- webrtc_log_uploader_->AddUploadedLogInfoToUploadListFile(kTestReportId);
- webrtc_log_uploader_->AddUploadedLogInfoToUploadListFile(kTestReportId);
+ webrtc_log_uploader_->AddUploadedLogInfoToUploadListFile(test_list_path_,
+ kTestReportId);
+ webrtc_log_uploader_->AddUploadedLogInfoToUploadListFile(test_list_path_,
+ kTestReportId);
ASSERT_TRUE(VerifyNumberOfLinesAndContentsOfLastLine(2));
const int expected_line_limit = 50;
ASSERT_TRUE(AddLinesToTestFile(expected_line_limit - 2));
ASSERT_TRUE(VerifyNumberOfLinesAndContentsOfLastLine(expected_line_limit));
- webrtc_log_uploader_->AddUploadedLogInfoToUploadListFile(kTestReportId);
+ webrtc_log_uploader_->AddUploadedLogInfoToUploadListFile(test_list_path_,
+ kTestReportId);
ASSERT_TRUE(VerifyNumberOfLinesAndContentsOfLastLine(expected_line_limit));
ASSERT_TRUE(AddLinesToTestFile(10));
ASSERT_TRUE(VerifyNumberOfLinesAndContentsOfLastLine(60));
- webrtc_log_uploader_->AddUploadedLogInfoToUploadListFile(kTestReportId);
+ webrtc_log_uploader_->AddUploadedLogInfoToUploadListFile(test_list_path_,
+ kTestReportId);
ASSERT_TRUE(VerifyNumberOfLinesAndContentsOfLastLine(expected_line_limit));
}
diff --git a/chrome/browser/media/webrtc_logging_handler_host.cc b/chrome/browser/media/webrtc_logging_handler_host.cc
index 7f19e9c9be..aed7964856 100644
--- a/chrome/browser/media/webrtc_logging_handler_host.cc
+++ b/chrome/browser/media/webrtc_logging_handler_host.cc
@@ -16,6 +16,7 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/media/webrtc_log_uploader.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/media/webrtc_logging_messages.h"
#include "chrome/common/partial_circular_buffer.h"
@@ -92,9 +93,11 @@ std::string IPAddressToSensitiveString(const net::IPAddressNumber& address) {
} // namespace
-WebRtcLoggingHandlerHost::WebRtcLoggingHandlerHost()
- : logging_state_(CLOSED),
+WebRtcLoggingHandlerHost::WebRtcLoggingHandlerHost(Profile* profile)
+ : profile_(profile),
+ logging_state_(CLOSED),
upload_log_on_render_close_(false) {
+ DCHECK(profile_);
}
WebRtcLoggingHandlerHost::~WebRtcLoggingHandlerHost() {}
@@ -350,6 +353,7 @@ void WebRtcLoggingHandlerHost::TriggerUploadLog() {
logging_state_ = UPLOADING;
WebRtcLogUploadDoneData upload_done_data;
+ upload_done_data.profile = profile_;
upload_done_data.callback = upload_callback_;
upload_done_data.host = this;
upload_callback_.Reset();
diff --git a/chrome/browser/media/webrtc_logging_handler_host.h b/chrome/browser/media/webrtc_logging_handler_host.h
index 9261c5a058..9f4e39aa2f 100644
--- a/chrome/browser/media/webrtc_logging_handler_host.h
+++ b/chrome/browser/media/webrtc_logging_handler_host.h
@@ -13,6 +13,7 @@ namespace net {
class URLRequestContextGetter;
} // namespace net
+class Profile;
class RenderProcessHost;
// WebRtcLoggingHandlerHost handles operations regarding the WebRTC logging:
@@ -30,7 +31,7 @@ class WebRtcLoggingHandlerHost : public content::BrowserMessageFilter {
typedef base::Callback<void(bool, const std::string&, const std::string&)>
UploadDoneCallback;
- WebRtcLoggingHandlerHost();
+ explicit WebRtcLoggingHandlerHost(Profile* profile);
// Sets meta data that will be uploaded along with the log and also written
// in the beginning of the log. Must be called on the IO thread before calling
@@ -111,6 +112,9 @@ class WebRtcLoggingHandlerHost : public content::BrowserMessageFilter {
scoped_refptr<net::URLRequestContextGetter> system_request_context_;
scoped_ptr<base::SharedMemory> shared_memory_;
+ // The profile associated with our renderer process.
+ Profile* profile_;
+
// These are only accessed on the IO thread, except when in STARTING state. In
// this state we are protected since entering any function that alters the
// state is not allowed.
diff --git a/chrome/browser/media_galleries/fileapi/iapps_finder_impl.cc b/chrome/browser/media_galleries/fileapi/iapps_finder_impl.cc
index 5c1b087ffd..e23a4d458f 100644
--- a/chrome/browser/media_galleries/fileapi/iapps_finder_impl.cc
+++ b/chrome/browser/media_galleries/fileapi/iapps_finder_impl.cc
@@ -22,7 +22,7 @@ void PostResultToUIThread(StorageInfo::Type type,
device_id = StorageInfo::MakeDeviceId(type, unique_id);
content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
- base::Bind(callback, unique_id));
+ base::Bind(callback, device_id));
}
} // namespace
diff --git a/chrome/browser/media_galleries/fileapi/iapps_finder_impl.h b/chrome/browser/media_galleries/fileapi/iapps_finder_impl.h
index 2b62d31227..95a24aa2d1 100644
--- a/chrome/browser/media_galleries/fileapi/iapps_finder_impl.h
+++ b/chrome/browser/media_galleries/fileapi/iapps_finder_impl.h
@@ -13,6 +13,7 @@
#if defined(OS_MACOSX)
+class MacPreferences;
#if defined(__OBJC__)
@class NSString;
#else // __OBJC__
@@ -28,6 +29,11 @@ namespace iapps {
extern NSString* const kIPhotoRecentDatabasesKey;
extern NSString* const kITunesRecentDatabasePathsKey;
+// Set the mac preferences to use for testing. The caller continues to own
+// |preferences| and should call this function again with NULL before freeing
+// it.
+void SetMacPreferencesForTesting(MacPreferences* preferences);
+
#endif // OS_MACOSX
typedef base::Callback<void(const IAppsFinderCallback&)> IAppsFinderTask;
diff --git a/chrome/browser/media_galleries/fileapi/iapps_finder_impl_mac.mm b/chrome/browser/media_galleries/fileapi/iapps_finder_impl_mac.mm
index 29fecba723..bf0e5afe68 100644
--- a/chrome/browser/media_galleries/fileapi/iapps_finder_impl_mac.mm
+++ b/chrome/browser/media_galleries/fileapi/iapps_finder_impl_mac.mm
@@ -10,6 +10,7 @@
#import "base/mac/foundation_util.h"
#import "base/mac/scoped_nsobject.h"
#include "base/time/time.h"
+#include "chrome/browser/policy/preferences_mac.h"
#include "chrome/browser/storage_monitor/storage_info.h"
#include "content/public/browser/browser_thread.h"
@@ -23,16 +24,24 @@ namespace {
typedef base::Callback<base::FilePath(NSString*)> PListPathExtractor;
+static MacPreferences* g_test_mac_preferences = NULL;
+
void FindMostRecentDatabase(
base::scoped_nsobject<NSString> recent_databases_key,
const PListPathExtractor& path_extractor,
const IAppsFinderCallback& callback) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
+ scoped_ptr<MacPreferences> real_preferences;
+ MacPreferences* prefs = g_test_mac_preferences;
+ if (!prefs) {
+ real_preferences.reset(new MacPreferences());
+ prefs = real_preferences.get();
+ }
+
CFStringRef iapp_id = CFSTR("com.apple.iApps");
base::scoped_nsobject<NSArray> plist(CFToNSCast(CFCast<CFArrayRef>(
- CFPreferencesCopyAppValue(NSToCFCast(recent_databases_key.get()),
- iapp_id))));
+ prefs->CopyAppValue(NSToCFCast(recent_databases_key.get()), iapp_id))));
if (!plist) {
callback.Run(std::string());
return;
@@ -81,14 +90,6 @@ base::FilePath ExtractITunesPath(NSString* path_ns) {
NSString* const kIPhotoRecentDatabasesKey = @"iPhotoRecentDatabases";
NSString* const kITunesRecentDatabasePathsKey = @"iTunesRecentDatabasePaths";
-void TestFunc(
- const PListPathExtractor& path_extractor,
- const IAppsFinderCallback& callback) {
-}
-void TestFunc2(
- const IAppsFinderCallback& callback) {
-}
-
void FindIPhotoLibrary(const IAppsFinderCallback& callback) {
FindIAppsOnFileThread(
StorageInfo::IPHOTO,
@@ -107,4 +108,8 @@ void FindITunesLibrary(const IAppsFinderCallback& callback) {
callback);
}
+void SetMacPreferencesForTesting(MacPreferences* preferences) {
+ g_test_mac_preferences = preferences;
+}
+
} // namespace iapps
diff --git a/chrome/browser/media_galleries/fileapi/iphoto_data_provider.cc b/chrome/browser/media_galleries/fileapi/iphoto_data_provider.cc
index 922007a516..64b5a43de4 100644
--- a/chrome/browser/media_galleries/fileapi/iphoto_data_provider.cc
+++ b/chrome/browser/media_galleries/fileapi/iphoto_data_provider.cc
@@ -12,21 +12,38 @@
#include "base/logging.h"
#include "base/platform_file.h"
#include "base/threading/thread_restrictions.h"
-#include "chrome/browser/media_galleries/fileapi/file_path_watcher_util.h"
#include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h"
+#include "chrome/browser/media_galleries/fileapi/safe_iapps_library_parser.h"
#include "content/public/browser/browser_thread.h"
namespace iphoto {
IPhotoDataProvider::IPhotoDataProvider(const base::FilePath& library_path)
- : iapps::IAppsDataProvider(library_path) {}
+ : iapps::IAppsDataProvider(library_path),
+ weak_factory_(this) {}
IPhotoDataProvider::~IPhotoDataProvider() {}
void IPhotoDataProvider::DoParseLibrary(
const base::FilePath& library_path,
const ReadyCallback& ready_callback) {
- set_valid(true);
- ready_callback.Run(true);
+ xml_parser_ = new iapps::SafeIAppsLibraryParser;
+ xml_parser_->ParseIPhotoLibrary(
+ library_path,
+ base::Bind(&IPhotoDataProvider::OnLibraryParsed,
+ weak_factory_.GetWeakPtr(),
+ ready_callback));
}
+
+void IPhotoDataProvider::OnLibraryParsed(const ReadyCallback& ready_callback,
+ bool result,
+ const parser::Library& library) {
+ DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
+ set_valid(result);
+ if (valid()) {
+ library_ = library;
+ }
+ ready_callback.Run(valid());
+}
+
} // namespace iphoto
diff --git a/chrome/browser/media_galleries/fileapi/iphoto_data_provider.h b/chrome/browser/media_galleries/fileapi/iphoto_data_provider.h
index b8fd2d2f47..e1e62c2369 100644
--- a/chrome/browser/media_galleries/fileapi/iphoto_data_provider.h
+++ b/chrome/browser/media_galleries/fileapi/iphoto_data_provider.h
@@ -15,6 +15,8 @@
#include "base/files/file_path_watcher.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/media_galleries/fileapi/iapps_data_provider.h"
+#include "chrome/browser/media_galleries/fileapi/safe_iapps_library_parser.h"
+#include "chrome/common/media_galleries/iphoto_library.h"
namespace iphoto {
@@ -32,6 +34,17 @@ class IPhotoDataProvider : public iapps::IAppsDataProvider {
const ReadyCallback& ready_callback) OVERRIDE;
private:
+ void OnLibraryParsed(const ReadyCallback& ready_callback,
+ bool result,
+ const parser::Library& library);
+
+ // The parsed and uniquified data.
+ parser::Library library_;
+
+ scoped_refptr<iapps::SafeIAppsLibraryParser> xml_parser_;
+
+ base::WeakPtrFactory<IPhotoDataProvider> weak_factory_;
+
DISALLOW_COPY_AND_ASSIGN(IPhotoDataProvider);
};
diff --git a/chrome/browser/media_galleries/fileapi/iphoto_file_util.cc b/chrome/browser/media_galleries/fileapi/iphoto_file_util.cc
index d2879a8421..47702f9a28 100644
--- a/chrome/browser/media_galleries/fileapi/iphoto_file_util.cc
+++ b/chrome/browser/media_galleries/fileapi/iphoto_file_util.cc
@@ -15,7 +15,6 @@
#include "chrome/browser/media_galleries/fileapi/media_path_filter.h"
#include "chrome/browser/media_galleries/imported_media_gallery_registry.h"
#include "content/public/browser/browser_thread.h"
-#include "webkit/browser/fileapi/file_system_file_util.h"
#include "webkit/browser/fileapi/file_system_operation_context.h"
#include "webkit/browser/fileapi/file_system_url.h"
#include "webkit/browser/fileapi/native_file_util.h"
diff --git a/chrome/browser/media_galleries/fileapi/itunes_data_provider.cc b/chrome/browser/media_galleries/fileapi/itunes_data_provider.cc
index 06f63c0aad..56af6d436d 100644
--- a/chrome/browser/media_galleries/fileapi/itunes_data_provider.cc
+++ b/chrome/browser/media_galleries/fileapi/itunes_data_provider.cc
@@ -187,12 +187,12 @@ ITunesDataProvider::~ITunesDataProvider() {}
void ITunesDataProvider::DoParseLibrary(
const base::FilePath& library_path,
const ReadyCallback& ready_callback) {
- xml_parser_ = new SafeITunesLibraryParser(
+ xml_parser_ = new iapps::SafeIAppsLibraryParser;
+ xml_parser_->ParseITunesLibrary(
library_path,
base::Bind(&ITunesDataProvider::OnLibraryParsed,
weak_factory_.GetWeakPtr(),
ready_callback));
- xml_parser_->Start();
}
const base::FilePath& ITunesDataProvider::auto_add_path() const {
diff --git a/chrome/browser/media_galleries/fileapi/itunes_data_provider.h b/chrome/browser/media_galleries/fileapi/itunes_data_provider.h
index 485a046262..cb4316c148 100644
--- a/chrome/browser/media_galleries/fileapi/itunes_data_provider.h
+++ b/chrome/browser/media_galleries/fileapi/itunes_data_provider.h
@@ -14,7 +14,7 @@
#include "base/files/file_path.h"
#include "base/files/file_path_watcher.h"
#include "chrome/browser/media_galleries/fileapi/iapps_data_provider.h"
-#include "chrome/browser/media_galleries/fileapi/safe_itunes_library_parser.h"
+#include "chrome/browser/media_galleries/fileapi/safe_iapps_library_parser.h"
namespace itunes {
@@ -79,7 +79,7 @@ class ITunesDataProvider : public iapps::IAppsDataProvider {
// The parsed and uniquified data.
Library library_;
- scoped_refptr<SafeITunesLibraryParser> xml_parser_;
+ scoped_refptr<iapps::SafeIAppsLibraryParser> xml_parser_;
// Hides parent class member, but it is private, and there's no way to get a
// WeakPtr<Derived> from a WeakPtr<Base> without using SupportsWeakPtr.
diff --git a/chrome/browser/media_galleries/fileapi/itunes_file_util.cc b/chrome/browser/media_galleries/fileapi/itunes_file_util.cc
index 1bdbdd6629..4f5e5fa34e 100644
--- a/chrome/browser/media_galleries/fileapi/itunes_file_util.cc
+++ b/chrome/browser/media_galleries/fileapi/itunes_file_util.cc
@@ -15,7 +15,6 @@
#include "chrome/browser/media_galleries/fileapi/media_path_filter.h"
#include "chrome/browser/media_galleries/imported_media_gallery_registry.h"
#include "content/public/browser/browser_thread.h"
-#include "webkit/browser/fileapi/file_system_file_util.h"
#include "webkit/browser/fileapi/file_system_operation_context.h"
#include "webkit/browser/fileapi/file_system_url.h"
#include "webkit/browser/fileapi/native_file_util.h"
diff --git a/chrome/browser/media_galleries/fileapi/itunes_file_util_unittest.cc b/chrome/browser/media_galleries/fileapi/itunes_file_util_unittest.cc
index a0995128eb..d15d5f6974 100644
--- a/chrome/browser/media_galleries/fileapi/itunes_file_util_unittest.cc
+++ b/chrome/browser/media_galleries/fileapi/itunes_file_util_unittest.cc
@@ -28,7 +28,6 @@
#include "webkit/browser/fileapi/file_system_operation_runner.h"
#include "webkit/browser/quota/mock_special_storage_policy.h"
-using fileapi::FileSystemFileUtil;
using fileapi::FileSystemOperationContext;
using fileapi::FileSystemOperation;
using fileapi::FileSystemURL;
diff --git a/chrome/browser/media_galleries/fileapi/media_path_filter.cc b/chrome/browser/media_galleries/fileapi/media_path_filter.cc
index 823e9e1a50..922d8d3c41 100644
--- a/chrome/browser/media_galleries/fileapi/media_path_filter.cc
+++ b/chrome/browser/media_galleries/fileapi/media_path_filter.cc
@@ -51,6 +51,7 @@ const base::FilePath::CharType* const kExtraSupportedExtensions[] = {
FILE_PATH_LITERAL("3gpp"),
FILE_PATH_LITERAL("avi"),
FILE_PATH_LITERAL("flv"),
+ FILE_PATH_LITERAL("mkv"),
FILE_PATH_LITERAL("mov"),
FILE_PATH_LITERAL("mpeg"),
FILE_PATH_LITERAL("mpeg4"),
diff --git a/chrome/browser/media_galleries/fileapi/picasa_data_provider_browsertest.cc b/chrome/browser/media_galleries/fileapi/picasa_data_provider_browsertest.cc
index 8e78827d80..a4f6b616c1 100644
--- a/chrome/browser/media_galleries/fileapi/picasa_data_provider_browsertest.cc
+++ b/chrome/browser/media_galleries/fileapi/picasa_data_provider_browsertest.cc
@@ -552,8 +552,14 @@ class PicasaDataProviderInvalidateInflightAlbumsIndexerTest
}
};
+// Flaky on Mac. crbug.com/309160.
+#if defined(OS_MACOSX)
+#define MAYBE_InvalidateInflightAlbumsIndexerTest DISABLED_InvalidateInflightAlbumsIndexerTest
+#else
+#define MAYBE_InvalidateInflightAlbumsIndexerTest InvalidateInflightAlbumsIndexerTest
+#endif
IN_PROC_BROWSER_TEST_F(PicasaDataProviderInvalidateInflightAlbumsIndexerTest,
- InvalidateInflightAlbumsIndexerTest) {
+ MAYBE_InvalidateInflightAlbumsIndexerTest) {
RunTest();
}
diff --git a/chrome/browser/media_galleries/fileapi/picasa_file_util_unittest.cc b/chrome/browser/media_galleries/fileapi/picasa_file_util_unittest.cc
index f115170306..21bfe396c8 100644
--- a/chrome/browser/media_galleries/fileapi/picasa_file_util_unittest.cc
+++ b/chrome/browser/media_galleries/fileapi/picasa_file_util_unittest.cc
@@ -31,14 +31,12 @@
#include "webkit/browser/fileapi/async_file_util.h"
#include "webkit/browser/fileapi/external_mount_points.h"
#include "webkit/browser/fileapi/file_system_context.h"
-#include "webkit/browser/fileapi/file_system_file_util.h"
#include "webkit/browser/fileapi/file_system_operation_context.h"
#include "webkit/browser/fileapi/file_system_operation_runner.h"
#include "webkit/browser/fileapi/isolated_context.h"
#include "webkit/browser/quota/mock_special_storage_policy.h"
#include "webkit/common/blob/shareable_file_reference.h"
-using fileapi::FileSystemFileUtil;
using fileapi::FileSystemOperationContext;
using fileapi::FileSystemOperation;
using fileapi::FileSystemURL;
diff --git a/chrome/browser/media_galleries/fileapi/safe_iapps_library_parser.cc b/chrome/browser/media_galleries/fileapi/safe_iapps_library_parser.cc
new file mode 100644
index 0000000000..2c30f2dd4f
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/safe_iapps_library_parser.cc
@@ -0,0 +1,176 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/media_galleries/fileapi/safe_iapps_library_parser.h"
+
+#include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h"
+#include "chrome/common/chrome_utility_messages.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/child_process_data.h"
+#include "ipc/ipc_platform_file.h"
+
+using content::BrowserThread;
+using content::UtilityProcessHost;
+
+namespace iapps {
+
+SafeIAppsLibraryParser::SafeIAppsLibraryParser()
+ : parser_state_(INITIAL_STATE) {}
+
+void SafeIAppsLibraryParser::ParseIPhotoLibrary(
+ const base::FilePath& library_file,
+ const IPhotoParserCallback& callback) {
+ library_file_ = library_file;
+ iphoto_callback_ = callback;
+ Start();
+}
+
+void SafeIAppsLibraryParser::ParseITunesLibrary(
+ const base::FilePath& library_file,
+ const ITunesParserCallback& callback) {
+ library_file_ = library_file;
+ itunes_callback_ = callback;
+ Start();
+}
+
+void SafeIAppsLibraryParser::Start() {
+ DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
+
+ // |library_platform_file_| will be closed on the IO thread once it
+ // has been handed off to the child process.
+ library_platform_file_ = base::CreatePlatformFile(
+ library_file_,
+ base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ,
+ NULL, // created
+ NULL); // error_code
+ if (library_platform_file_ == base::kInvalidPlatformFileValue) {
+ VLOG(1) << "Could not open iApps library XML file: "
+ << library_file_.value();
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&SafeIAppsLibraryParser::OnOpenLibraryFileFailed, this));
+ return;
+ }
+
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&SafeIAppsLibraryParser::StartProcessOnIOThread, this));
+}
+
+SafeIAppsLibraryParser::~SafeIAppsLibraryParser() {}
+
+void SafeIAppsLibraryParser::StartProcessOnIOThread() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_EQ(INITIAL_STATE, parser_state_);
+
+ scoped_refptr<base::MessageLoopProxy> message_loop_proxy =
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
+ utility_process_host_ =
+ UtilityProcessHost::Create(this, message_loop_proxy.get())->AsWeakPtr();
+ // Wait for the startup notification before sending the main IPC to the
+ // utility process, so that we can dup the file handle.
+ utility_process_host_->Send(new ChromeUtilityMsg_StartupPing);
+ parser_state_ = PINGED_UTILITY_PROCESS_STATE;
+}
+
+void SafeIAppsLibraryParser::OnUtilityProcessStarted() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (parser_state_ != PINGED_UTILITY_PROCESS_STATE)
+ return;
+
+ if (utility_process_host_->GetData().handle == base::kNullProcessHandle) {
+ DLOG(ERROR) << "Child process handle is null";
+ OnError();
+ return;
+ }
+
+ if (!itunes_callback_.is_null()) {
+ utility_process_host_->Send(
+ new ChromeUtilityMsg_ParseITunesLibraryXmlFile(
+ IPC::GetFileHandleForProcess(
+ library_platform_file_,
+ utility_process_host_->GetData().handle,
+ true /* close_source_handle */)));
+ } else if (!iphoto_callback_.is_null()) {
+#if defined(OS_MACOSX)
+ utility_process_host_->Send(
+ new ChromeUtilityMsg_ParseIPhotoLibraryXmlFile(
+ IPC::GetFileHandleForProcess(
+ library_platform_file_,
+ utility_process_host_->GetData().handle,
+ true /* close_source_handle */)));
+#endif
+ }
+
+ parser_state_ = STARTED_PARSING_STATE;
+}
+
+#if defined(OS_MACOSX)
+void SafeIAppsLibraryParser::OnGotIPhotoLibrary(
+ bool result, const iphoto::parser::Library& library) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK(!iphoto_callback_.is_null());
+
+ if (parser_state_ != STARTED_PARSING_STATE)
+ return;
+
+ MediaFileSystemBackend::MediaTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(iphoto_callback_, result, library));
+ parser_state_ = FINISHED_PARSING_STATE;
+}
+#endif
+
+void SafeIAppsLibraryParser::OnGotITunesLibrary(
+ bool result, const itunes::parser::Library& library) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK(!itunes_callback_.is_null());
+
+ if (parser_state_ != STARTED_PARSING_STATE)
+ return;
+
+ MediaFileSystemBackend::MediaTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(itunes_callback_, result, library));
+ parser_state_ = FINISHED_PARSING_STATE;
+}
+
+void SafeIAppsLibraryParser::OnOpenLibraryFileFailed() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ OnError();
+}
+
+void SafeIAppsLibraryParser::OnProcessCrashed(int exit_code) {
+ OnError();
+}
+
+void SafeIAppsLibraryParser::OnError() {
+ parser_state_ = FINISHED_PARSING_STATE;
+ if (!itunes_callback_.is_null())
+ OnGotITunesLibrary(false /* failed */, itunes::parser::Library());
+
+#if defined(OS_MACOSX)
+ if (!iphoto_callback_.is_null())
+ OnGotIPhotoLibrary(false /* failed */, iphoto::parser::Library());
+#endif
+}
+
+bool SafeIAppsLibraryParser::OnMessageReceived(
+ const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(SafeIAppsLibraryParser, message)
+ IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ProcessStarted,
+ OnUtilityProcessStarted)
+#if defined(OS_MACOSX)
+ IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GotIPhotoLibrary,
+ OnGotIPhotoLibrary)
+#endif
+ IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GotITunesLibrary,
+ OnGotITunesLibrary)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+} // namespace iapps
diff --git a/chrome/browser/media_galleries/fileapi/safe_itunes_library_parser.h b/chrome/browser/media_galleries/fileapi/safe_iapps_library_parser.h
index f041951074..ea77a30398 100644
--- a/chrome/browser/media_galleries/fileapi/safe_itunes_library_parser.h
+++ b/chrome/browser/media_galleries/fileapi/safe_iapps_library_parser.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_SAFE_ITUNES_LIBRARY_PARSER_H_
-#define CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_SAFE_ITUNES_LIBRARY_PARSER_H_
+#ifndef CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_SAFE_IAPPS_LIBRARY_PARSER_H_
+#define CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_SAFE_IAPPS_LIBRARY_PARSER_H_
#include <string>
@@ -12,6 +12,7 @@
#include "base/files/file_path.h"
#include "base/memory/weak_ptr.h"
#include "base/platform_file.h"
+#include "chrome/common/media_galleries/iphoto_library.h"
#include "chrome/common/media_galleries/itunes_library.h"
#include "content/public/browser/utility_process_host.h"
#include "content/public/browser/utility_process_host_client.h"
@@ -20,26 +21,34 @@ namespace IPC {
class Message;
}
-namespace itunes {
+namespace iapps {
-// SafeITunesLibraryParser parses the given iTunes library XML file safely via
-// a utility process. The SafeITunesLibraryParser object is ref-counted and
+// SafeIAppsLibraryParser parses the given iTunes library XML file safely via
+// a utility process. The SafeIAppsLibraryParser object is ref-counted and
// kept alive after Start() is called until the ParserCallback is called.
// The ParserCallback is guaranteed to be called eventually either when the
// utility process replies or when it dies.
-// Since iTunes library XML files can be big, SafeITunesLibraryParser passes
+// Since iApps library XML files can be big, SafeIAppsLibraryParser passes
// the file handle to the utility process.
-// SafeITunesLibraryParser lives on the Media Task Runner unless otherwise
+// SafeIAppsLibraryParser lives on the Media Task Runner unless otherwise
// noted.
-class SafeITunesLibraryParser : public content::UtilityProcessHostClient {
+class SafeIAppsLibraryParser : public content::UtilityProcessHostClient {
public:
- typedef base::Callback<void(bool, const parser::Library&)> ParserCallback;
+ typedef base::Callback<void(bool, const iphoto::parser::Library&)>
+ IPhotoParserCallback;
+ typedef base::Callback<void(bool, const itunes::parser::Library&)>
+ ITunesParserCallback;
- SafeITunesLibraryParser(const base::FilePath& itunes_library_file,
- const ParserCallback& callback);
+ SafeIAppsLibraryParser();
+
+ // Start the parse of the iPhoto library file.
+ void ParseIPhotoLibrary(const base::FilePath& library_file,
+ const IPhotoParserCallback& callback);
+
+ // Start the parse of the iTunes library file.
+ void ParseITunesLibrary(const base::FilePath& library_file,
+ const ITunesParserCallback& callback);
- // Posts a task to start the XML parsing in the utility process.
- void Start();
private:
enum ParserState {
@@ -50,7 +59,10 @@ class SafeITunesLibraryParser : public content::UtilityProcessHostClient {
};
// content::UtilityProcessHostClient is ref-counted.
- virtual ~SafeITunesLibraryParser();
+ virtual ~SafeIAppsLibraryParser();
+
+ // Posts a task to start the XML parsing in the utility process.
+ void Start();
// Launches the utility process. Must run on the IO thread.
void StartProcessOnIOThread();
@@ -60,38 +72,50 @@ class SafeITunesLibraryParser : public content::UtilityProcessHostClient {
// Runs on the IO thread.
void OnUtilityProcessStarted();
- // Notification from the utility process when it finishes parsing the XML.
- // Runs on the IO thread.
- void OnGotITunesLibrary(bool result, const parser::Library& library);
+ // Notification from the utility process when it finishes parsing the
+ // iPhoto XML. Runs on the IO thread.
+#if defined(OS_MACOSX)
+ void OnGotIPhotoLibrary(bool result, const iphoto::parser::Library& library);
+#endif
+
+ // Notification from the utility process when it finishes parsing the
+ // iTunes XML. Runs on the IO thread.
+ void OnGotITunesLibrary(bool result, const itunes::parser::Library& library);
// Sets |parser_state_| in case the library XML file cannot be opened.
// Runs on the IO thread.
void OnOpenLibraryFileFailed();
+ // Communicates an error to the callback given to the constructor.
+ void OnError();
+
// UtilityProcessHostClient implementation.
// Runs on the IO thread.
virtual void OnProcessCrashed(int exit_code) OVERRIDE;
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
- const base::FilePath itunes_library_file_;
+ base::FilePath library_file_;
// Once we have opened the file, we store the handle so that we can use it
// once the utility process has launched.
- base::PlatformFile itunes_library_platform_file_;
+ base::PlatformFile library_platform_file_;
// Only accessed on the IO thread.
base::WeakPtr<content::UtilityProcessHost> utility_process_host_;
// Only accessed on the Media Task Runner.
- const ParserCallback callback_;
+ ITunesParserCallback itunes_callback_;
+
+ // Only accessed on the Media Task Runner.
+ IPhotoParserCallback iphoto_callback_;
// Verifies the messages from the utility process came at the right time.
// Initialized on the Media Task Runner, but only accessed on the IO thread.
ParserState parser_state_;
- DISALLOW_COPY_AND_ASSIGN(SafeITunesLibraryParser);
+ DISALLOW_COPY_AND_ASSIGN(SafeIAppsLibraryParser);
};
-} // namespace itunes
+} // namespace iapps
-#endif // CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_SAFE_ITUNES_LIBRARY_PARSER_H_
+#endif // CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_SAFE_IAPPS_LIBRARY_PARSER_H_
diff --git a/chrome/browser/media_galleries/fileapi/safe_itunes_library_parser.cc b/chrome/browser/media_galleries/fileapi/safe_itunes_library_parser.cc
deleted file mode 100644
index 21dd102853..0000000000
--- a/chrome/browser/media_galleries/fileapi/safe_itunes_library_parser.cc
+++ /dev/null
@@ -1,117 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/media_galleries/fileapi/safe_itunes_library_parser.h"
-
-#include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h"
-#include "chrome/common/chrome_utility_messages.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/child_process_data.h"
-#include "ipc/ipc_platform_file.h"
-
-using content::BrowserThread;
-using content::UtilityProcessHost;
-
-namespace itunes {
-
-SafeITunesLibraryParser::SafeITunesLibraryParser(
- const base::FilePath& itunes_library_file,
- const ParserCallback& callback)
- : itunes_library_file_(itunes_library_file),
- callback_(callback),
- parser_state_(INITIAL_STATE) {}
-
-void SafeITunesLibraryParser::Start() {
- DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
-
- // |itunes_library_platform_file_| will be closed on the IO thread once it
- // has been handed off to the child process.
- itunes_library_platform_file_ = base::CreatePlatformFile(
- itunes_library_file_,
- base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ,
- NULL, // created
- NULL); // error_code
- if (itunes_library_platform_file_ == base::kInvalidPlatformFileValue) {
- VLOG(1) << "Could not open iTunes library XML file: "
- << itunes_library_file_.value();
- callback_.Run(false /* failed */, parser::Library());
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&SafeITunesLibraryParser::OnOpenLibraryFileFailed, this));
- return;
- }
-
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&SafeITunesLibraryParser::StartProcessOnIOThread, this));
-}
-
-SafeITunesLibraryParser::~SafeITunesLibraryParser() {}
-
-void SafeITunesLibraryParser::StartProcessOnIOThread() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DCHECK_EQ(INITIAL_STATE, parser_state_);
-
- scoped_refptr<base::MessageLoopProxy> message_loop_proxy =
- BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
- utility_process_host_ =
- UtilityProcessHost::Create(this, message_loop_proxy.get())->AsWeakPtr();
- // Wait for the startup notification before sending the main IPC to the
- // utility process, so that we can dup the file handle.
- utility_process_host_->Send(new ChromeUtilityMsg_StartupPing);
- parser_state_ = PINGED_UTILITY_PROCESS_STATE;
-}
-
-void SafeITunesLibraryParser::OnUtilityProcessStarted() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- if (parser_state_ != PINGED_UTILITY_PROCESS_STATE)
- return;
-
- if (utility_process_host_->GetData().handle == base::kNullProcessHandle)
- DLOG(ERROR) << "Child process handle is null";
- utility_process_host_->Send(
- new ChromeUtilityMsg_ParseITunesLibraryXmlFile(
- IPC::GetFileHandleForProcess(
- itunes_library_platform_file_,
- utility_process_host_->GetData().handle,
- true /* close_source_handle */)));
- parser_state_ = STARTED_PARSING_STATE;
-}
-
-void SafeITunesLibraryParser::OnGotITunesLibrary(
- bool result, const parser::Library& library) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
- if (parser_state_ != STARTED_PARSING_STATE)
- return;
-
- MediaFileSystemBackend::MediaTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(callback_, result, library));
- parser_state_ = FINISHED_PARSING_STATE;
-}
-
-void SafeITunesLibraryParser::OnOpenLibraryFileFailed() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- parser_state_ = FINISHED_PARSING_STATE;
-}
-
-void SafeITunesLibraryParser::OnProcessCrashed(int exit_code) {
- OnGotITunesLibrary(false /* failed */, parser::Library());
-}
-
-bool SafeITunesLibraryParser::OnMessageReceived(
- const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(SafeITunesLibraryParser, message)
- IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ProcessStarted,
- OnUtilityProcessStarted)
- IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GotITunesLibrary,
- OnGotITunesLibrary)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-} // namespace itunes
diff --git a/chrome/browser/media_galleries/linux/mtp_device_object_enumerator.h b/chrome/browser/media_galleries/linux/mtp_device_object_enumerator.h
index ef92b92154..7f8b611f52 100644
--- a/chrome/browser/media_galleries/linux/mtp_device_object_enumerator.h
+++ b/chrome/browser/media_galleries/linux/mtp_device_object_enumerator.h
@@ -10,21 +10,18 @@
#include "base/files/file_path.h"
#include "base/time/time.h"
#include "device/media_transfer_protocol/mtp_file_entry.pb.h"
-#include "webkit/browser/fileapi/file_system_file_util.h"
// Used to enumerate top-level files of an media file system.
-class MTPDeviceObjectEnumerator
- : public fileapi::FileSystemFileUtil::AbstractFileEnumerator {
+class MTPDeviceObjectEnumerator {
public:
explicit MTPDeviceObjectEnumerator(const std::vector<MtpFileEntry>& entries);
- virtual ~MTPDeviceObjectEnumerator();
+ ~MTPDeviceObjectEnumerator();
- // AbstractFileEnumerator:
- virtual base::FilePath Next() OVERRIDE;
- virtual int64 Size() OVERRIDE;
- virtual bool IsDirectory() OVERRIDE;
- virtual base::Time LastModifiedTime() OVERRIDE;
+ base::FilePath Next();
+ int64 Size();
+ bool IsDirectory();
+ base::Time LastModifiedTime();
// If the current file entry is valid, returns true and fills in |entry_id|
// with the entry identifier else returns false and |entry_id| is not set.
diff --git a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac_unittest.mm b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac_unittest.mm
index bdab3237be..7dbe116371 100644
--- a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac_unittest.mm
+++ b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac_unittest.mm
@@ -22,7 +22,6 @@
#include "content/public/browser/browser_thread.h"
#include "content/public/test/test_browser_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/fileapi/file_system_file_util.h"
#if !defined(MAC_OS_X_VERSION_10_7) || \
MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
@@ -161,16 +160,6 @@ const char kTestFileContents[] = "test";
@end
-// Advances the enumerator. When the method returns, signals the waiting
-// event.
-void EnumerateAndSignal(
- fileapi::FileSystemFileUtil::AbstractFileEnumerator* enumerator,
- base::WaitableEvent* event,
- base::FilePath* path) {
- *path = enumerator->Next();
- event->Signal();
-}
-
class MTPDeviceDelegateImplMacTest : public testing::Test {
public:
MTPDeviceDelegateImplMacTest() : camera_(NULL), delegate_(NULL) {}
diff --git a/chrome/browser/media_galleries/media_file_system_context.h b/chrome/browser/media_galleries/media_file_system_context.h
index 2a7d145fae..54b9a8e812 100644
--- a/chrome/browser/media_galleries/media_file_system_context.h
+++ b/chrome/browser/media_galleries/media_file_system_context.h
@@ -31,11 +31,6 @@ class MediaFileSystemContext {
// Revoke the passed |fsid|.
virtual void RevokeFileSystem(const std::string& fsid) = 0;
-
- // Signal the registry that a particular MTP device map entry is no longer
- // needed.
- virtual void RemoveScopedMTPDeviceMapEntry(
- const base::FilePath::StringType& device_location) = 0;
};
#endif // CHROME_BROWSER_MEDIA_GALLERIES_MEDIA_FILE_SYSTEM_CONTEXT_H_
diff --git a/chrome/browser/media_galleries/media_file_system_registry.cc b/chrome/browser/media_galleries/media_file_system_registry.cc
index 7d564af4b9..0eafc4c19c 100644
--- a/chrome/browser/media_galleries/media_file_system_registry.cc
+++ b/chrome/browser/media_galleries/media_file_system_registry.cc
@@ -23,7 +23,6 @@
#include "chrome/browser/media_galleries/media_galleries_dialog_controller.h"
#include "chrome/browser/media_galleries/media_galleries_histograms.h"
#include "chrome/browser/media_galleries/media_galleries_preferences_factory.h"
-#include "chrome/browser/media_galleries/scoped_mtp_device_map_entry.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/storage_monitor/media_storage_util.h"
#include "chrome/browser/storage_monitor/storage_monitor.h"
@@ -299,8 +298,6 @@ class ExtensionGalleriesHost
private:
typedef std::map<MediaGalleryPrefId, MediaFileSystemInfo> PrefIdFsInfoMap;
- typedef std::map<MediaGalleryPrefId, scoped_refptr<ScopedMTPDeviceMapEntry> >
- MediaDeviceEntryReferencesMap;
// Private destructor and friend declaration for ref counted implementation.
friend class base::RefCountedThreadSafe<ExtensionGalleriesHost>;
@@ -577,7 +574,7 @@ class MediaFileSystemRegistry::MediaFileSystemContextImpl
IsolatedContext::GetInstance()->RegisterFileSystemForPath(
fileapi::kFileSystemTypeDeviceMedia, path, &fs_name);
CHECK(!fsid.empty());
- registry_->GetOrCreateScopedMTPDeviceMapEntry(path.value(), fsid);
+ registry_->RegisterMTPFileSystem(path.value(), fsid);
return fsid;
}
@@ -592,11 +589,6 @@ class MediaFileSystemRegistry::MediaFileSystemContextImpl
registry_->RevokeMTPFileSystem(fsid);
}
- virtual void RemoveScopedMTPDeviceMapEntry(
- const base::FilePath::StringType& device_location) OVERRIDE {
- registry_->RemoveScopedMTPDeviceMapEntry(device_location);
- }
-
private:
MediaFileSystemRegistry* registry_;
@@ -615,7 +607,7 @@ MediaFileSystemRegistry::~MediaFileSystemRegistry() {
// and then can remove this.
if (StorageMonitor::GetInstance())
StorageMonitor::GetInstance()->RemoveObserver(this);
- DCHECK(mtp_device_delegate_map_.empty());
+ DCHECK(mtp_device_usage_map_.empty());
}
void MediaFileSystemRegistry::OnPermissionRemoved(
@@ -669,44 +661,43 @@ void MediaFileSystemRegistry::OnGalleryRemoved(
}
}
-scoped_refptr<ScopedMTPDeviceMapEntry>
-MediaFileSystemRegistry::GetOrCreateScopedMTPDeviceMapEntry(
+void MediaFileSystemRegistry::RegisterMTPFileSystem(
const base::FilePath::StringType& device_location,
const std::string& fsid) {
- MTPDeviceDelegateMap::iterator delegate_it =
- mtp_device_delegate_map_.find(device_location);
- if (delegate_it != mtp_device_delegate_map_.end())
- return delegate_it->second;
-
- scoped_refptr<ScopedMTPDeviceMapEntry> mtp_device_host =
- new ScopedMTPDeviceMapEntry(device_location, file_system_context_.get());
- // Note that this initializes the delegate asynchronously, but since
- // the delegate will only be used from the IO thread, it is guaranteed
- // to be created before use of it expects it to be there.
- InitMTPDeviceAsyncDelegate(device_location);
- mtp_device_delegate_map_[device_location] = mtp_device_host.get();
- mtp_device_map_[fsid] = mtp_device_host;
- return mtp_device_host;
-}
+ MTPDeviceUsageMap::iterator delegate_it =
+ mtp_device_usage_map_.find(device_location);
+ if (delegate_it == mtp_device_usage_map_.end()) {
+ // Note that this initializes the delegate asynchronously, but since
+ // the delegate will only be used from the IO thread, it is guaranteed
+ // to be created before use of it expects it to be there.
+ InitMTPDeviceAsyncDelegate(device_location);
+ mtp_device_usage_map_[device_location] = 0;
+ }
-void MediaFileSystemRegistry::RevokeMTPFileSystem(const std::string& fsid) {
- // If this was an MTP device, remove reference to it.
- mtp_device_map_.erase(fsid);
+ mtp_device_usage_map_[device_location]++;
+ mtp_device_map_[fsid] = device_location;
}
-void MediaFileSystemRegistry::RemoveScopedMTPDeviceMapEntry(
- const base::FilePath::StringType& device_location) {
- content::BrowserThread::PostTask(
- content::BrowserThread::IO,
- FROM_HERE,
- base::Bind(&MTPDeviceMapService::RemoveAsyncDelegate,
- base::Unretained(MTPDeviceMapService::GetInstance()),
- device_location));
-
- MTPDeviceDelegateMap::iterator delegate_it =
- mtp_device_delegate_map_.find(device_location);
- DCHECK(delegate_it != mtp_device_delegate_map_.end());
- mtp_device_delegate_map_.erase(delegate_it);
+// TODO(gbillock): Move all this accounting to the MTPDeviceMapService.
+void MediaFileSystemRegistry::RevokeMTPFileSystem(const std::string& fsid) {
+ MTPDeviceFileSystemMap::iterator i = mtp_device_map_.find(fsid);
+ if (i != mtp_device_map_.end()) {
+ base::FilePath::StringType device_location = i->second;
+ mtp_device_map_.erase(i);
+ MTPDeviceUsageMap::iterator delegate_it =
+ mtp_device_usage_map_.find(device_location);
+ DCHECK(delegate_it != mtp_device_usage_map_.end());
+ mtp_device_usage_map_[device_location]--;
+ if (mtp_device_usage_map_[device_location] == 0) {
+ mtp_device_usage_map_.erase(delegate_it);
+ content::BrowserThread::PostTask(
+ content::BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&MTPDeviceMapService::RemoveAsyncDelegate,
+ base::Unretained(MTPDeviceMapService::GetInstance()),
+ device_location));
+ }
+ }
}
void MediaFileSystemRegistry::OnExtensionGalleriesHostEmpty(
diff --git a/chrome/browser/media_galleries/media_file_system_registry.h b/chrome/browser/media_galleries/media_file_system_registry.h
index 5b8d804be2..59523ef40b 100644
--- a/chrome/browser/media_galleries/media_file_system_registry.h
+++ b/chrome/browser/media_galleries/media_file_system_registry.h
@@ -24,8 +24,6 @@ class ExtensionGalleriesHost;
class MediaFileSystemContext;
class MediaGalleriesPreferences;
class Profile;
-class ScopedMTPDeviceMapEntry;
-
namespace content {
class RenderViewHost;
@@ -65,6 +63,8 @@ struct MediaFileSystemInfo {
typedef base::Callback<void(const std::vector<MediaFileSystemInfo>&)>
MediaFileSystemsCallback;
+// Tracks usage of filesystems by extensions.
+// This object lives on the UI thread.
class MediaFileSystemRegistry
: public RemovableStorageObserver,
public MediaGalleriesPreferences::GalleryChangeObserver {
@@ -73,15 +73,15 @@ class MediaFileSystemRegistry
virtual ~MediaFileSystemRegistry();
// Passes to |callback| the list of media filesystem IDs and paths for a
- // given RVH. Called on the UI thread.
+ // given RVH.
void GetMediaFileSystemsForExtension(
const content::RenderViewHost* rvh,
const extensions::Extension* extension,
const MediaFileSystemsCallback& callback);
// Returns the media galleries preferences for the specified |profile|.
- // Called on the UI thread. Caller is responsible for ensuring that the
- // preferences are initialized before use.
+ // Caller is responsible for ensuring that the preferences are initialized
+ // before use.
MediaGalleriesPreferences* GetPreferences(Profile* profile);
// RemovableStorageObserver implementation.
@@ -100,15 +100,14 @@ class MediaFileSystemRegistry
// Map a profile and extension to the ExtensionGalleriesHost.
typedef std::map<Profile*, ExtensionHostMap> ExtensionGalleriesHostMap;
- // Map a filesystem id (fsid) to the reference to an MTP device.
- typedef std::map<std::string, scoped_refptr<ScopedMTPDeviceMapEntry> >
- MTPDeviceEntryMap;
+ // Map a filesystem id (fsid) to an MTP device location.
+ typedef std::map<std::string, base::FilePath::StringType>
+ MTPDeviceFileSystemMap;
- // Map a MTP or PTP device location to the raw pointer of
- // ScopedMTPDeviceMapEntry. It is safe to store a raw pointer in this
- // map.
- typedef std::map<const base::FilePath::StringType, ScopedMTPDeviceMapEntry*>
- MTPDeviceDelegateMap;
+ // Map a MTP or PTP device location to a count of current uses of that
+ // location.
+ typedef std::map<const base::FilePath::StringType, int>
+ MTPDeviceUsageMap;
virtual void OnPermissionRemoved(MediaGalleriesPreferences* pref,
const std::string& extension_id,
@@ -116,30 +115,25 @@ class MediaFileSystemRegistry
virtual void OnGalleryRemoved(MediaGalleriesPreferences* pref,
MediaGalleryPrefId pref_id) OVERRIDE;
- // Returns ScopedMTPDeviceMapEntry object for the given |device_location|.
- scoped_refptr<ScopedMTPDeviceMapEntry> GetOrCreateScopedMTPDeviceMapEntry(
+ // Register that an MTP filesystem is in use for the given |device_location|.
+ void RegisterMTPFileSystem(
const base::FilePath::StringType& device_location,
const std::string& fsid);
+ // Removes the MTP entry associated with the given
+ // |device_location|. Signals the MTPDeviceMapService to destroy the
+ // delegate if there are no more uses of it.
void RevokeMTPFileSystem(const std::string& fsid);
void OnExtensionGalleriesHostEmpty(Profile* profile,
const std::string& extension_id);
- // Removes the ScopedMTPDeviceMapEntry associated with the given
- // |device_location|.
- void RemoveScopedMTPDeviceMapEntry(
- const base::FilePath::StringType& device_location);
-
- // Only accessed on the UI thread. This map owns all the
- // ExtensionGalleriesHost objects created.
+ // This map owns all the ExtensionGalleriesHost objects created.
ExtensionGalleriesHostMap extension_hosts_map_;
- // Contains a map of fsid to ScopedMTPDeviceMapEntry.
- MTPDeviceEntryMap mtp_device_map_;
+ MTPDeviceFileSystemMap mtp_device_map_;
- // Only accessed on the UI thread.
- MTPDeviceDelegateMap mtp_device_delegate_map_;
+ MTPDeviceUsageMap mtp_device_usage_map_;
scoped_ptr<MediaFileSystemContext> file_system_context_;
diff --git a/chrome/browser/media_galleries/media_file_system_registry_unittest.cc b/chrome/browser/media_galleries/media_file_system_registry_unittest.cc
index 804524bca3..d21fdeb293 100644
--- a/chrome/browser/media_galleries/media_file_system_registry_unittest.cc
+++ b/chrome/browser/media_galleries/media_file_system_registry_unittest.cc
@@ -29,7 +29,6 @@
#include "chrome/browser/media_galleries/media_file_system_registry.h"
#include "chrome/browser/media_galleries/media_galleries_preferences_factory.h"
#include "chrome/browser/media_galleries/media_galleries_test_util.h"
-#include "chrome/browser/media_galleries/scoped_mtp_device_map_entry.h"
#include "chrome/browser/storage_monitor/removable_device_constants.h"
#include "chrome/browser/storage_monitor/storage_info.h"
#include "chrome/browser/storage_monitor/storage_monitor.h"
@@ -84,9 +83,6 @@ class TestMediaFileSystemContext : public MediaFileSystemContext {
virtual void RevokeFileSystem(const std::string& fsid) OVERRIDE;
- virtual void RemoveScopedMTPDeviceMapEntry(
- const base::FilePath::StringType& device_location) OVERRIDE;
-
base::FilePath GetPathForId(const std::string& fsid) const;
MediaFileSystemRegistry* registry() { return registry_; }
@@ -137,7 +133,7 @@ std::string TestMediaFileSystemContext::RegisterFileSystemForMTPDevice(
const std::string& device_id, const base::FilePath& path) {
CHECK(!StorageInfo::IsMassStorageDevice(device_id));
std::string fsid = AddFSEntry(device_id, path);
- registry_->GetOrCreateScopedMTPDeviceMapEntry(path.value(), fsid);
+ registry_->RegisterMTPFileSystem(path.value(), fsid);
return fsid;
}
@@ -148,11 +144,6 @@ void TestMediaFileSystemContext::RevokeFileSystem(const std::string& fsid) {
registry_->RevokeMTPFileSystem(fsid);
}
-void TestMediaFileSystemContext::RemoveScopedMTPDeviceMapEntry(
- const base::FilePath::StringType& device_location) {
- registry_->RemoveScopedMTPDeviceMapEntry(device_location);
-}
-
base::FilePath TestMediaFileSystemContext::GetPathForId(
const std::string& fsid) const {
std::map<std::string /*fsid*/, FSInfo>::const_iterator it =
diff --git a/chrome/browser/media_galleries/media_galleries_dialog_controller.cc b/chrome/browser/media_galleries/media_galleries_dialog_controller.cc
index eb008f2e43..87e1ccbe46 100644
--- a/chrome/browser/media_galleries/media_galleries_dialog_controller.cc
+++ b/chrome/browser/media_galleries/media_galleries_dialog_controller.cc
@@ -106,8 +106,6 @@ string16 MediaGalleriesDialogController::GetSubtext() const {
int id;
if (has_read_permission && has_copy_to_permission)
id = IDS_MEDIA_GALLERIES_DIALOG_SUBTEXT_READ_WRITE;
- else if (has_copy_to_permission)
- id = IDS_MEDIA_GALLERIES_DIALOG_SUBTEXT_WRITE_ONLY;
else
id = IDS_MEDIA_GALLERIES_DIALOG_SUBTEXT_READ_ONLY;
diff --git a/chrome/browser/media_galleries/media_galleries_test_util.cc b/chrome/browser/media_galleries/media_galleries_test_util.cc
index bc25749d04..8f5a661226 100644
--- a/chrome/browser/media_galleries/media_galleries_test_util.cc
+++ b/chrome/browser/media_galleries/media_galleries_test_util.cc
@@ -23,10 +23,17 @@
#include "extensions/common/manifest_constants.h"
#include "testing/gtest/include/gtest/gtest.h"
+#if defined(OS_MACOSX)
+#include "base/mac/foundation_util.h"
+#include "base/strings/sys_string_conversions.h"
+#include "chrome/browser/media_galleries/fileapi/iapps_finder_impl.h"
+#include "chrome/browser/policy/preferences_mock_mac.h"
+#endif // OS_MACOSX
+
#if defined(OS_WIN)
#include "base/test/test_reg_util_win.h"
#include "base/win/registry.h"
-#endif
+#endif // OS_WIN
scoped_refptr<extensions::Extension> AddMediaGalleriesApp(
const std::string& name,
@@ -102,7 +109,7 @@ void EnsureMediaDirectoriesExists::WriteCustomPicasaAppDataPathToRegistry(
KEY_SET_VALUE);
key.WriteValue(picasa::kPicasaRegistryAppDataKey, path.value().c_str());
}
-#endif
+#endif // OS_WIN
#if defined(OS_WIN) || defined(OS_MACOSX)
base::FilePath
@@ -110,7 +117,7 @@ EnsureMediaDirectoriesExists::GetFakePicasaFoldersRootPath() const {
DCHECK(fake_dir_.IsValid());
return fake_dir_.path().AppendASCII("picasa_folders");
}
-#endif
+#endif // OS_WIN || OS_MACOSX
void EnsureMediaDirectoriesExists::Init() {
#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
@@ -120,18 +127,36 @@ void EnsureMediaDirectoriesExists::Init() {
ASSERT_TRUE(fake_dir_.CreateUniqueTempDir());
#if defined(OS_WIN) || defined(OS_MACOSX)
- // This is to control whether or not tests think iTunes and Picasa are
- // installed.
+ // This is to control whether or not tests think iTunes (on Windows) and
+ // Picasa are installed.
app_data_override_.reset(new base::ScopedPathOverride(
base::DIR_APP_DATA, GetFakeAppDataPath()));
+#endif // OS_WIN || OS_MACOSX
+
#if defined(OS_WIN)
// Picasa on Windows is by default in the DIR_LOCAL_APP_DATA directory.
local_app_data_override_.reset(new base::ScopedPathOverride(
base::DIR_LOCAL_APP_DATA, GetFakeLocalAppDataPath()));
// Picasa also looks in the registry for an alternate path.
registry_override_.OverrideRegistry(HKEY_CURRENT_USER, L"hkcu_picasa");
-#endif
-#endif
+#endif // OS_WIN
+
+#if defined(OS_MACOSX)
+ mac_preferences_.reset(new MockPreferences);
+ iapps::SetMacPreferencesForTesting(mac_preferences_.get());
+
+ // iTunes override.
+ mac_preferences_->AddTestItem(
+ base::mac::NSToCFCast(iapps::kITunesRecentDatabasePathsKey),
+ base::SysUTF8ToNSString(fake_dir_.path().AppendASCII("itunes").value()),
+ false);
+
+ // iPhoto override.
+ mac_preferences_->AddTestItem(
+ base::mac::NSToCFCast(iapps::kIPhotoRecentDatabasesKey),
+ base::SysUTF8ToNSString(fake_dir_.path().AppendASCII("iphoto").value()),
+ false);
+#endif // OS_MACOSX
music_override_.reset(new base::ScopedPathOverride(
chrome::DIR_USER_MUSIC, fake_dir_.path().AppendASCII("music")));
@@ -140,5 +165,5 @@ void EnsureMediaDirectoriesExists::Init() {
video_override_.reset(new base::ScopedPathOverride(
chrome::DIR_USER_VIDEOS, fake_dir_.path().AppendASCII("videos")));
num_galleries_ = 3;
-#endif
+#endif // OS_CHROMEOS || OS_ANDROID
}
diff --git a/chrome/browser/media_galleries/media_galleries_test_util.h b/chrome/browser/media_galleries/media_galleries_test_util.h
index 2e7bee0221..81e7de78c4 100644
--- a/chrome/browser/media_galleries/media_galleries_test_util.h
+++ b/chrome/browser/media_galleries/media_galleries_test_util.h
@@ -25,6 +25,10 @@ class RegistryOverrideManager;
class Profile;
+#if defined(OS_MACOSX)
+class MockPreferences;
+#endif
+
scoped_refptr<extensions::Extension> AddMediaGalleriesApp(
const std::string& name,
const std::vector<std::string>& media_galleries_permissions,
@@ -62,6 +66,9 @@ class EnsureMediaDirectoriesExists {
registry_util::RegistryOverrideManager registry_override_;
#endif
+#if defined(OS_MACOSX)
+ scoped_ptr<MockPreferences> mac_preferences_;
+#endif
DISALLOW_COPY_AND_ASSIGN(EnsureMediaDirectoriesExists);
};
diff --git a/chrome/browser/media_galleries/scoped_mtp_device_map_entry.cc b/chrome/browser/media_galleries/scoped_mtp_device_map_entry.cc
deleted file mode 100644
index ae2757dab5..0000000000
--- a/chrome/browser/media_galleries/scoped_mtp_device_map_entry.cc
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/media_galleries/scoped_mtp_device_map_entry.h"
-
-#include "chrome/browser/media_galleries/media_file_system_context.h"
-
-ScopedMTPDeviceMapEntry::ScopedMTPDeviceMapEntry(
- const base::FilePath::StringType& device_location,
- MediaFileSystemContext* context)
- : device_location_(device_location),
- context_(context) {
-}
-
-ScopedMTPDeviceMapEntry::~ScopedMTPDeviceMapEntry() {
- context_->RemoveScopedMTPDeviceMapEntry(device_location_);
-}
diff --git a/chrome/browser/media_galleries/scoped_mtp_device_map_entry.h b/chrome/browser/media_galleries/scoped_mtp_device_map_entry.h
deleted file mode 100644
index 45d12e896f..0000000000
--- a/chrome/browser/media_galleries/scoped_mtp_device_map_entry.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_MEDIA_GALLERIES_SCOPED_MTP_DEVICE_MAP_ENTRY_H_
-#define CHROME_BROWSER_MEDIA_GALLERIES_SCOPED_MTP_DEVICE_MAP_ENTRY_H_
-
-#include "base/files/file_path.h"
-#include "base/memory/ref_counted.h"
-#include "base/sequenced_task_runner_helpers.h"
-#include "content/public/browser/browser_thread.h"
-
-class MediaFileSystemContext;
-class MTPDeviceAsyncDelegate;
-
-// ScopedMTPDeviceMapEntry manages the reference count on a particular
-// MTP device location. These objects are held reference counted in
-// the ExtensionGalleriesHost objects. When a particular location is
-// destroyed, the MediaFileSystemContext is notified, and the attendant
-// delegates are subsequently erased from the system-wide MTPServiceMap.
-class ScopedMTPDeviceMapEntry
- : public base::RefCountedThreadSafe<
- ScopedMTPDeviceMapEntry, content::BrowserThread::DeleteOnUIThread> {
- public:
- // Created on the UI thread.
- ScopedMTPDeviceMapEntry(const base::FilePath::StringType& device_location,
- MediaFileSystemContext* context);
-
- private:
- // Friend declarations for ref counted implementation.
- friend struct content::BrowserThread::DeleteOnThread<
- content::BrowserThread::UI>;
- friend class base::DeleteHelper<ScopedMTPDeviceMapEntry>;
-
- // Private because this class is ref-counted. Destroyed when:
- // - no extension is using the device.
- // - no extension has permission to access to device.
- // - the device is detached.
- // - the browser shuts down.
- // Destroyed on the UI thread.
- ~ScopedMTPDeviceMapEntry();
-
- // The MTP or PTP device location.
- const base::FilePath::StringType device_location_;
-
- // Notified when the object is destroyed.
- MediaFileSystemContext* context_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedMTPDeviceMapEntry);
-};
-
-#endif // CHROME_BROWSER_MEDIA_GALLERIES_SCOPED_MTP_DEVICE_MAP_ENTRY_H_
diff --git a/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc b/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc
index bfa81daf7d..09bf2b03f6 100644
--- a/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc
+++ b/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc
@@ -98,34 +98,32 @@ string16 GetFileObjectIdFromPathOnBlockingPoolThread(
// Returns a pointer to a new instance of AbstractFileEnumerator for the given
// |root| directory. Called on a blocking pool thread.
-scoped_ptr<fileapi::FileSystemFileUtil::AbstractFileEnumerator>
+scoped_ptr<MTPDeviceObjectEnumerator>
CreateFileEnumeratorOnBlockingPoolThread(
const MTPDeviceDelegateImplWin::StorageDeviceInfo& device_info,
const base::FilePath& root) {
base::ThreadRestrictions::AssertIOAllowed();
DCHECK(!device_info.registered_device_path.empty());
DCHECK(!root.empty());
- scoped_ptr<fileapi::FileSystemFileUtil::AbstractFileEnumerator>
- file_enumerator(new fileapi::FileSystemFileUtil::EmptyFileEnumerator());
IPortableDevice* device =
PortableDeviceMapService::GetInstance()->GetPortableDevice(
device_info.registered_device_path);
if (!device)
- return file_enumerator.Pass();
+ return scoped_ptr<MTPDeviceObjectEnumerator>();
string16 object_id = GetFileObjectIdFromPathOnBlockingPoolThread(device_info,
root);
if (object_id.empty())
- return file_enumerator.Pass();
+ return scoped_ptr<MTPDeviceObjectEnumerator>();
MTPDeviceObjectEntries entries;
if (!media_transfer_protocol::GetDirectoryEntries(device, object_id,
&entries) ||
entries.empty())
- return file_enumerator.Pass();
+ return scoped_ptr<MTPDeviceObjectEnumerator>();
- file_enumerator.reset(new MTPDeviceObjectEnumerator(entries));
- return file_enumerator.Pass();
+ return scoped_ptr<MTPDeviceObjectEnumerator>(
+ new MTPDeviceObjectEnumerator(entries));
}
// Opens the device for communication on a blocking pool thread.
@@ -195,8 +193,11 @@ base::PlatformFileError ReadDirectoryOnBlockingPoolThread(
return base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY;
base::FilePath current;
- scoped_ptr<fileapi::FileSystemFileUtil::AbstractFileEnumerator> file_enum =
+ scoped_ptr<MTPDeviceObjectEnumerator> file_enum =
CreateFileEnumeratorOnBlockingPoolThread(device_info, root);
+ if (!file_enum)
+ return error;
+
while (!(current = file_enum->Next()).empty()) {
fileapi::DirectoryEntry entry;
entry.is_directory = file_enum->IsDirectory();
@@ -291,7 +292,6 @@ void DeletePortableDeviceOnBlockingPoolThread(
registered_device_path);
}
-
} // namespace
// Used by CreateMTPDeviceAsyncDelegate() to create the MTP device
diff --git a/chrome/browser/media_galleries/win/mtp_device_object_enumerator.h b/chrome/browser/media_galleries/win/mtp_device_object_enumerator.h
index 32a50b52eb..ce2c3e9bbe 100644
--- a/chrome/browser/media_galleries/win/mtp_device_object_enumerator.h
+++ b/chrome/browser/media_galleries/win/mtp_device_object_enumerator.h
@@ -12,23 +12,20 @@
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "chrome/browser/media_galleries/win/mtp_device_object_entry.h"
-#include "webkit/browser/fileapi/file_system_file_util.h"
// MTPDeviceObjectEnumerator is used to enumerate the media transfer protocol
// (MTP) device objects from a given object entry list.
// MTPDeviceObjectEnumerator supports MTP device file operations.
// MTPDeviceObjectEnumerator may only be used on a single thread.
-class MTPDeviceObjectEnumerator
- : public fileapi::FileSystemFileUtil::AbstractFileEnumerator {
+class MTPDeviceObjectEnumerator {
public:
explicit MTPDeviceObjectEnumerator(const MTPDeviceObjectEntries& entries);
- virtual ~MTPDeviceObjectEnumerator();
+ ~MTPDeviceObjectEnumerator();
- // AbstractFileEnumerator:
- virtual base::FilePath Next() OVERRIDE;
- virtual int64 Size() OVERRIDE;
- virtual bool IsDirectory() OVERRIDE;
- virtual base::Time LastModifiedTime() OVERRIDE;
+ base::FilePath Next();
+ int64 Size();
+ bool IsDirectory();
+ base::Time LastModifiedTime();
// If the current file object entry is valid, returns an non-empty object id.
// Returns an empty string otherwise.
diff --git a/chrome/browser/metrics/metrics_log_serializer.cc b/chrome/browser/metrics/metrics_log_serializer.cc
index 65021307f1..6e5c1a9458 100644
--- a/chrome/browser/metrics/metrics_log_serializer.cc
+++ b/chrome/browser/metrics/metrics_log_serializer.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/metrics/metrics_log_serializer.h"
+#include <string>
+
#include "base/base64.h"
#include "base/md5.h"
#include "base/metrics/histogram.h"
@@ -52,8 +54,9 @@ MetricsLogSerializer::MetricsLogSerializer() {}
MetricsLogSerializer::~MetricsLogSerializer() {}
-void MetricsLogSerializer::SerializeLogs(const std::vector<std::string>& logs,
- MetricsLogManager::LogType log_type) {
+void MetricsLogSerializer::SerializeLogs(
+ const std::vector<MetricsLogManager::SerializedLog>& logs,
+ MetricsLogManager::LogType log_type) {
PrefService* local_state = g_browser_process->local_state();
DCHECK(local_state);
const char* pref = NULL;
@@ -77,8 +80,9 @@ void MetricsLogSerializer::SerializeLogs(const std::vector<std::string>& logs,
update.Get());
}
-void MetricsLogSerializer::DeserializeLogs(MetricsLogManager::LogType log_type,
- std::vector<std::string>* logs) {
+void MetricsLogSerializer::DeserializeLogs(
+ MetricsLogManager::LogType log_type,
+ std::vector<MetricsLogManager::SerializedLog>* logs) {
DCHECK(logs);
PrefService* local_state = g_browser_process->local_state();
DCHECK(local_state);
@@ -95,7 +99,7 @@ void MetricsLogSerializer::DeserializeLogs(MetricsLogManager::LogType log_type,
// static
void MetricsLogSerializer::WriteLogsToPrefList(
- const std::vector<std::string>& local_list,
+ const std::vector<MetricsLogManager::SerializedLog>& local_list,
size_t list_length_limit,
size_t byte_limit,
base::ListValue* list) {
@@ -112,9 +116,9 @@ void MetricsLogSerializer::WriteLogsToPrefList(
if (local_list.size() > list_length_limit) {
start = local_list.size();
size_t bytes_used = 0;
- for (std::vector<std::string>::const_reverse_iterator
+ for (std::vector<MetricsLogManager::SerializedLog>::const_reverse_iterator
it = local_list.rbegin(); it != local_list.rend(); ++it) {
- size_t log_size = it->length();
+ size_t log_size = it->log_text().length();
if (bytes_used >= byte_limit &&
(local_list.size() - start) >= list_length_limit)
break;
@@ -132,11 +136,12 @@ void MetricsLogSerializer::WriteLogsToPrefList(
base::MD5Context ctx;
base::MD5Init(&ctx);
std::string encoded_log;
- for (std::vector<std::string>::const_iterator it = local_list.begin() + start;
+ for (std::vector<MetricsLogManager::SerializedLog>::const_iterator it =
+ local_list.begin() + start;
it != local_list.end(); ++it) {
// We encode the compressed log as Value::CreateStringValue() expects to
// take a valid UTF8 string.
- if (!base::Base64Encode(*it, &encoded_log)) {
+ if (!base::Base64Encode(it->log_text(), &encoded_log)) {
list->Clear();
return;
}
@@ -154,7 +159,7 @@ void MetricsLogSerializer::WriteLogsToPrefList(
// static
MetricsLogSerializer::LogReadStatus MetricsLogSerializer::ReadLogsFromPrefList(
const ListValue& list,
- std::vector<std::string>* local_list) {
+ std::vector<MetricsLogManager::SerializedLog>* local_list) {
if (list.GetSize() == 0)
return MakeRecallStatusHistogram(LIST_EMPTY);
if (list.GetSize() < 3)
@@ -193,12 +198,14 @@ MetricsLogSerializer::LogReadStatus MetricsLogSerializer::ReadLogsFromPrefList(
base::MD5Update(&ctx, encoded_log);
- DCHECK_LT(local_index, local_list->size());
- std::string& decoded_log = (*local_list)[local_index];
- if (!base::Base64Decode(encoded_log, &decoded_log)) {
+ std::string log_text;
+ if (!base::Base64Decode(encoded_log, &log_text)) {
local_list->clear();
return MakeRecallStatusHistogram(DECODE_FAIL);
}
+
+ DCHECK_LT(local_index, local_list->size());
+ (*local_list)[local_index].SwapLogText(&log_text);
}
// Verify checksum.
diff --git a/chrome/browser/metrics/metrics_log_serializer.h b/chrome/browser/metrics/metrics_log_serializer.h
index 853e3e3b9f..ae85b1390f 100644
--- a/chrome/browser/metrics/metrics_log_serializer.h
+++ b/chrome/browser/metrics/metrics_log_serializer.h
@@ -5,6 +5,8 @@
#ifndef CHROME_BROWSER_METRICS_METRICS_LOG_SERIALIZER_H_
#define CHROME_BROWSER_METRICS_METRICS_LOG_SERIALIZER_H_
+#include <vector>
+
#include "base/basictypes.h"
#include "base/gtest_prod_util.h"
#include "chrome/common/metrics/metrics_log_manager.h"
@@ -38,10 +40,12 @@ class MetricsLogSerializer : public MetricsLogManager::LogSerializer {
virtual ~MetricsLogSerializer();
// Implementation of MetricsLogManager::LogSerializer
- virtual void SerializeLogs(const std::vector<std::string>& logs,
- MetricsLogManager::LogType log_type) OVERRIDE;
- virtual void DeserializeLogs(MetricsLogManager::LogType log_type,
- std::vector<std::string>* logs) OVERRIDE;
+ virtual void SerializeLogs(
+ const std::vector<MetricsLogManager::SerializedLog>& logs,
+ MetricsLogManager::LogType log_type) OVERRIDE;
+ virtual void DeserializeLogs(
+ MetricsLogManager::LogType log_type,
+ std::vector<MetricsLogManager::SerializedLog>* logs) OVERRIDE;
private:
// Encodes the textual log data from |local_list| and writes it to the given
@@ -49,16 +53,17 @@ class MetricsLogSerializer : public MetricsLogManager::LogSerializer {
// with the most recent, and working backward until at least
// |list_length_limit| logs and |byte_limit| bytes of logs have been
// stored. At least one of those two arguments must be non-zero.
- static void WriteLogsToPrefList(const std::vector<std::string>& local_list,
- size_t list_length_limit,
- size_t byte_limit,
- base::ListValue* list);
+ static void WriteLogsToPrefList(
+ const std::vector<MetricsLogManager::SerializedLog>& local_list,
+ size_t list_length_limit,
+ size_t byte_limit,
+ base::ListValue* list);
// Decodes and verifies the textual log data from |list|, populating
// |local_list| and returning a status code.
static LogReadStatus ReadLogsFromPrefList(
const base::ListValue& list,
- std::vector<std::string>* local_list);
+ std::vector<MetricsLogManager::SerializedLog>* local_list);
FRIEND_TEST_ALL_PREFIXES(MetricsLogSerializerTest, EmptyLogList);
FRIEND_TEST_ALL_PREFIXES(MetricsLogSerializerTest, SingleElementLogList);
diff --git a/chrome/browser/metrics/metrics_log_serializer_unittest.cc b/chrome/browser/metrics/metrics_log_serializer_unittest.cc
index 7e83f36099..ce5c5b2d41 100644
--- a/chrome/browser/metrics/metrics_log_serializer_unittest.cc
+++ b/chrome/browser/metrics/metrics_log_serializer_unittest.cc
@@ -13,15 +13,18 @@ namespace {
const size_t kListLengthLimit = 3;
const size_t kLogByteLimit = 1000;
-} // namespace
+void SetLogText(const std::string& log_text,
+ MetricsLogManager::SerializedLog* log) {
+ std::string log_text_copy = log_text;
+ log->SwapLogText(&log_text_copy);
+}
-class MetricsLogSerializerTest : public ::testing::Test {
-};
+} // namespace
// Store and retrieve empty list.
TEST(MetricsLogSerializerTest, EmptyLogList) {
ListValue list;
- std::vector<std::string> local_list;
+ std::vector<MetricsLogManager::SerializedLog> local_list;
MetricsLogSerializer::WriteLogsToPrefList(local_list, kListLengthLimit,
kLogByteLimit, &list);
@@ -38,8 +41,8 @@ TEST(MetricsLogSerializerTest, EmptyLogList) {
TEST(MetricsLogSerializerTest, SingleElementLogList) {
ListValue list;
- std::vector<std::string> local_list(1);
- local_list[0] = "Hello world!";
+ std::vector<MetricsLogManager::SerializedLog> local_list(1);
+ SetLogText("Hello world!", &local_list[0]);
MetricsLogSerializer::WriteLogsToPrefList(local_list, kListLengthLimit,
kLogByteLimit, &list);
@@ -81,20 +84,19 @@ TEST(MetricsLogSerializerTest, LongButTinyLogList) {
ListValue list;
size_t log_count = kListLengthLimit * 5;
- std::vector<std::string> local_list(log_count);
- for (size_t i = 0; i < local_list.size(); ++i) {
- local_list[0] = "x";
- }
+ std::vector<MetricsLogManager::SerializedLog> local_list(log_count);
+ for (size_t i = 0; i < local_list.size(); ++i)
+ SetLogText("x", &local_list[i]);
MetricsLogSerializer::WriteLogsToPrefList(local_list, kListLengthLimit,
kLogByteLimit, &list);
- std::vector<std::string> result_list;
+ std::vector<MetricsLogManager::SerializedLog> result_list;
EXPECT_EQ(
MetricsLogSerializer::RECALL_SUCCESS,
MetricsLogSerializer::ReadLogsFromPrefList(list, &result_list));
EXPECT_EQ(local_list.size(), result_list.size());
- EXPECT_TRUE(result_list.front().find("x") == 0);
+ EXPECT_TRUE(result_list.front().log_text().find("x") == 0);
}
// Store a set of logs over the length limit, but that doesn't reach the minimum
@@ -106,26 +108,28 @@ TEST(MetricsLogSerializerTest, LongButSmallLogList) {
// Make log_count logs each slightly larger than
// kLogByteLimit / (log_count - 2)
// so that the minimum is reached before the oldest (first) two logs.
- std::vector<std::string> local_list(log_count);
+ std::vector<MetricsLogManager::SerializedLog> local_list(log_count);
size_t log_size = (kLogByteLimit / (log_count - 2)) + 2;
- local_list[0] = "one";
- local_list[1] = "two";
- local_list[2] = "three";
- local_list[log_count - 1] = "last";
+ SetLogText("one", &local_list[0]);
+ SetLogText("two", &local_list[1]);
+ SetLogText("three", &local_list[2]);
+ SetLogText("last", &local_list[log_count - 1]);
for (size_t i = 0; i < local_list.size(); ++i) {
- local_list[i].resize(log_size, ' ');
+ std::string log_text = local_list[i].log_text();
+ log_text.resize(log_size, ' ');
+ local_list[i].SwapLogText(&log_text);
}
MetricsLogSerializer::WriteLogsToPrefList(local_list, kListLengthLimit,
kLogByteLimit, &list);
- std::vector<std::string> result_list;
+ std::vector<MetricsLogManager::SerializedLog> result_list;
EXPECT_EQ(
MetricsLogSerializer::RECALL_SUCCESS,
MetricsLogSerializer::ReadLogsFromPrefList(list, &result_list));
EXPECT_EQ(local_list.size() - 2, result_list.size());
- EXPECT_TRUE(result_list.front().find("three") == 0);
- EXPECT_TRUE(result_list.back().find("last") == 0);
+ EXPECT_TRUE(result_list.front().log_text().find("three") == 0);
+ EXPECT_TRUE(result_list.back().log_text().find("last") == 0);
}
// Store a set of logs within the length limit, but well over the minimum
@@ -133,16 +137,18 @@ TEST(MetricsLogSerializerTest, LongButSmallLogList) {
TEST(MetricsLogSerializerTest, ShortButLargeLogList) {
ListValue list;
- std::vector<std::string> local_list(kListLengthLimit);
+ std::vector<MetricsLogManager::SerializedLog> local_list(kListLengthLimit);
// Make the total byte count about twice the minimum.
size_t log_size = (kLogByteLimit / local_list.size()) * 2;
for (size_t i = 0; i < local_list.size(); ++i) {
- local_list[i].resize(log_size, ' ');
+ std::string log_text = local_list[i].log_text();
+ log_text.resize(log_size, ' ');
+ local_list[i].SwapLogText(&log_text);
}
MetricsLogSerializer::WriteLogsToPrefList(local_list, kListLengthLimit,
kLogByteLimit, &list);
- std::vector<std::string> result_list;
+ std::vector<MetricsLogManager::SerializedLog> result_list;
EXPECT_EQ(
MetricsLogSerializer::RECALL_SUCCESS,
MetricsLogSerializer::ReadLogsFromPrefList(list, &result_list));
@@ -155,31 +161,35 @@ TEST(MetricsLogSerializerTest, LongAndLargeLogList) {
ListValue list;
// Include twice the max number of logs.
- std::vector<std::string> local_list(kListLengthLimit * 2);
+ std::vector<MetricsLogManager::SerializedLog>
+ local_list(kListLengthLimit * 2);
// Make the total byte count about four times the minimum.
size_t log_size = (kLogByteLimit / local_list.size()) * 4;
- local_list[local_list.size() - kListLengthLimit] = "First to keep";
+ SetLogText("First to keep",
+ &local_list[local_list.size() - kListLengthLimit]);
for (size_t i = 0; i < local_list.size(); ++i) {
- local_list[i].resize(log_size, ' ');
+ std::string log_text = local_list[i].log_text();
+ log_text.resize(log_size, ' ');
+ local_list[i].SwapLogText(&log_text);
}
MetricsLogSerializer::WriteLogsToPrefList(local_list, kListLengthLimit,
kLogByteLimit, &list);
- std::vector<std::string> result_list;
+ std::vector<MetricsLogManager::SerializedLog> result_list;
EXPECT_EQ(
MetricsLogSerializer::RECALL_SUCCESS,
MetricsLogSerializer::ReadLogsFromPrefList(list, &result_list));
// The max length should control the resulting size.
EXPECT_EQ(kListLengthLimit, result_list.size());
- EXPECT_TRUE(result_list.front().find("First to keep") == 0);
+ EXPECT_TRUE(result_list.front().log_text().find("First to keep") == 0);
}
// Induce LIST_SIZE_TOO_SMALL corruption
TEST(MetricsLogSerializerTest, SmallRecoveredListSize) {
ListValue list;
- std::vector<std::string> local_list(1);
- local_list[0] = "Hello world!";
+ std::vector<MetricsLogManager::SerializedLog> local_list(1);
+ SetLogText("Hello world!", &local_list[0]);
MetricsLogSerializer::WriteLogsToPrefList(local_list, kListLengthLimit,
kLogByteLimit, &list);
@@ -199,9 +209,9 @@ TEST(MetricsLogSerializerTest, SmallRecoveredListSize) {
TEST(MetricsLogSerializerTest, RemoveSizeFromLogList) {
ListValue list;
- std::vector<std::string> local_list(2);
- local_list[0] = "one";
- local_list[1] = "two";
+ std::vector<MetricsLogManager::SerializedLog> local_list(2);
+ SetLogText("one", &local_list[0]);
+ SetLogText("two", &local_list[1]);
EXPECT_EQ(2U, local_list.size());
MetricsLogSerializer::WriteLogsToPrefList(local_list, kListLengthLimit,
kLogByteLimit, &list);
@@ -220,8 +230,8 @@ TEST(MetricsLogSerializerTest, RemoveSizeFromLogList) {
TEST(MetricsLogSerializerTest, CorruptSizeOfLogList) {
ListValue list;
- std::vector<std::string> local_list(1);
- local_list[0] = "Hello world!";
+ std::vector<MetricsLogManager::SerializedLog> local_list(1);
+ SetLogText("Hello world!", &local_list[0]);
MetricsLogSerializer::WriteLogsToPrefList(local_list, kListLengthLimit,
kLogByteLimit, &list);
@@ -241,8 +251,8 @@ TEST(MetricsLogSerializerTest, CorruptSizeOfLogList) {
TEST(MetricsLogSerializerTest, CorruptChecksumOfLogList) {
ListValue list;
- std::vector<std::string> local_list(1);
- local_list[0] = "Hello world!";
+ std::vector<MetricsLogManager::SerializedLog> local_list(1);
+ SetLogText("Hello world!", &local_list[0]);
MetricsLogSerializer::WriteLogsToPrefList(local_list, kListLengthLimit,
kLogByteLimit, &list);
diff --git a/chrome/browser/metrics/metrics_log_unittest.cc b/chrome/browser/metrics/metrics_log_unittest.cc
index 2676dbfd95..0f96916325 100644
--- a/chrome/browser/metrics/metrics_log_unittest.cc
+++ b/chrome/browser/metrics/metrics_log_unittest.cc
@@ -38,7 +38,7 @@
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/login/fake_user_manager.h"
#include "chrome/browser/chromeos/login/user_manager.h"
-#include "chromeos/dbus/mock_dbus_thread_manager_without_gmock.h"
+#include "chromeos/dbus/fake_dbus_thread_manager.h"
#endif // OS_CHROMEOS
using base::TimeDelta;
@@ -176,10 +176,9 @@ class MetricsLogTest : public testing::Test {
virtual void SetUp() OVERRIDE {
#if defined(OS_CHROMEOS)
- mock_dbus_thread_manager_ =
- new chromeos::MockDBusThreadManagerWithoutGMock();
+ fake_dbus_thread_manager_ = new chromeos::FakeDBusThreadManager();
chromeos::DBusThreadManager::InitializeForTesting(
- mock_dbus_thread_manager_);
+ fake_dbus_thread_manager_);
// Enable multi-profiles.
CommandLine::ForCurrentProcess()->AppendSwitch(switches::kMultiProfiles);
@@ -208,7 +207,7 @@ class MetricsLogTest : public testing::Test {
base::MessageLoop message_loop_;
#if defined(OS_CHROMEOS)
- chromeos::MockDBusThreadManagerWithoutGMock* mock_dbus_thread_manager_;
+ chromeos::FakeDBusThreadManager* fake_dbus_thread_manager_;
scoped_ptr<base::FieldTrialList> field_trial_list_;
#endif // OS_CHROMEOS
};
diff --git a/chrome/browser/metrics/metrics_service.cc b/chrome/browser/metrics/metrics_service.cc
index 66f68d5aee..98bbf813d3 100644
--- a/chrome/browser/metrics/metrics_service.cc
+++ b/chrome/browser/metrics/metrics_service.cc
@@ -1463,6 +1463,11 @@ void MetricsService::PrepareFetchWithStagedLog() {
current_fetch_->SetUploadData(kMimeType, compressed_log_text);
// Tell the server that we're uploading gzipped protobufs.
current_fetch_->SetExtraRequestHeaders("content-encoding: gzip");
+ const std::string hash =
+ base::HexEncode(log_manager_.staged_log_hash().data(),
+ log_manager_.staged_log_hash().size());
+ DCHECK(!hash.empty());
+ current_fetch_->AddExtraRequestHeader("X-Chrome-UMA-Log-SHA1: " + hash);
UMA_HISTOGRAM_PERCENTAGE(
"UMA.ProtoCompressionRatio",
100 * compressed_log_text.size() / log_text.size());
diff --git a/chrome/browser/metrics/perf_provider_chromeos.cc b/chrome/browser/metrics/perf_provider_chromeos.cc
index f3a1625555..f997cbf289 100644
--- a/chrome/browser/metrics/perf_provider_chromeos.cc
+++ b/chrome/browser/metrics/perf_provider_chromeos.cc
@@ -46,8 +46,6 @@ const size_t kPerfCommandStartIntervalLowerBoundMinutes = 10;
const size_t kPerfCommandStartIntervalUpperBoundMinutes = 20;
-const size_t kNumberOfSecondsInAMinute = 60;
-
// Default time in seconds perf is run for.
const size_t kPerfCommandDurationDefaultSeconds = 2;
diff --git a/chrome/browser/metrics/thread_watcher_unittest.cc b/chrome/browser/metrics/thread_watcher_unittest.cc
index f8cc88e16b..4b799e9c07 100644
--- a/chrome/browser/metrics/thread_watcher_unittest.cc
+++ b/chrome/browser/metrics/thread_watcher_unittest.cc
@@ -64,8 +64,8 @@ class CustomThreadWatcher : public ThreadWatcher {
CheckResponseState check_response_state_;
uint64 ping_sent_;
uint64 pong_received_;
- uint64 success_response_;
- uint64 failed_response_;
+ base::subtle::Atomic32 success_response_;
+ base::subtle::Atomic32 failed_response_;
base::TimeTicks saved_ping_time_;
uint64 saved_ping_sequence_number_;
@@ -147,10 +147,12 @@ class CustomThreadWatcher : public ThreadWatcher {
{
base::AutoLock auto_lock(custom_lock_);
if (responsive_) {
- ++success_response_;
+ base::subtle::Release_Store(&success_response_,
+ base::subtle::Acquire_Load(&success_response_) + 1);
check_response_state_ = SUCCESSFUL;
} else {
- ++failed_response_;
+ base::subtle::Release_Store(&failed_response_,
+ base::subtle::Acquire_Load(&failed_response_) + 1);
check_response_state_ = FAILED;
}
}
@@ -473,8 +475,10 @@ TEST_F(ThreadWatcherTest, ThreadResponding) {
// Verify watched thread is responding with ping/pong messaging.
io_watcher_->WaitForCheckResponse(
kUnresponsiveTime + TimeDelta::FromMinutes(1), SUCCESSFUL);
- EXPECT_GT(io_watcher_->success_response_, static_cast<uint64>(0));
- EXPECT_EQ(io_watcher_->failed_response_, static_cast<uint64>(0));
+ EXPECT_GT(base::subtle::NoBarrier_Load(&(io_watcher_->success_response_)),
+ static_cast<base::subtle::Atomic32>(0));
+ EXPECT_EQ(base::subtle::NoBarrier_Load(&(io_watcher_->failed_response_)),
+ static_cast<base::subtle::Atomic32>(0));
// DeActivate thread watching for shutdown.
WatchDogThread::PostTask(
@@ -508,8 +512,10 @@ TEST_F(ThreadWatcherTest, ThreadNotResponding) {
// Verify watched thread is not responding for ping messages.
io_watcher_->WaitForCheckResponse(
kUnresponsiveTime + TimeDelta::FromMinutes(1), FAILED);
- EXPECT_EQ(io_watcher_->success_response_, static_cast<uint64>(0));
- EXPECT_GT(io_watcher_->failed_response_, static_cast<uint64>(0));
+ EXPECT_EQ(base::subtle::NoBarrier_Load(&(io_watcher_->success_response_)),
+ static_cast<base::subtle::Atomic32>(0));
+ EXPECT_GT(base::subtle::NoBarrier_Load(&(io_watcher_->failed_response_)),
+ static_cast<base::subtle::Atomic32>(0));
// DeActivate thread watching for shutdown.
WatchDogThread::PostTask(
@@ -541,8 +547,10 @@ TEST_F(ThreadWatcherTest, MultipleThreadsResponding) {
EXPECT_GT(db_watcher_->ping_sent_, static_cast<uint64>(0));
EXPECT_GT(db_watcher_->pong_received_, static_cast<uint64>(0));
EXPECT_GE(db_watcher_->ping_sequence_number_, static_cast<uint64>(0));
- EXPECT_GT(db_watcher_->success_response_, static_cast<uint64>(0));
- EXPECT_EQ(db_watcher_->failed_response_, static_cast<uint64>(0));
+ EXPECT_GT(base::subtle::NoBarrier_Load(&(db_watcher_->success_response_)),
+ static_cast<base::subtle::Atomic32>(0));
+ EXPECT_EQ(base::subtle::NoBarrier_Load(&(db_watcher_->failed_response_)),
+ static_cast<base::subtle::Atomic32>(0));
// Verify IO thread is responding with ping/pong messaging.
io_watcher_->WaitForCheckResponse(
@@ -550,8 +558,10 @@ TEST_F(ThreadWatcherTest, MultipleThreadsResponding) {
EXPECT_GT(io_watcher_->ping_sent_, static_cast<uint64>(0));
EXPECT_GT(io_watcher_->pong_received_, static_cast<uint64>(0));
EXPECT_GE(io_watcher_->ping_sequence_number_, static_cast<uint64>(0));
- EXPECT_GT(io_watcher_->success_response_, static_cast<uint64>(0));
- EXPECT_EQ(io_watcher_->failed_response_, static_cast<uint64>(0));
+ EXPECT_GT(base::subtle::NoBarrier_Load(&(io_watcher_->success_response_)),
+ static_cast<base::subtle::Atomic32>(0));
+ EXPECT_EQ(base::subtle::NoBarrier_Load(&(io_watcher_->failed_response_)),
+ static_cast<base::subtle::Atomic32>(0));
// DeActivate thread watching for shutdown.
WatchDogThread::PostTask(
@@ -593,14 +603,18 @@ TEST_F(ThreadWatcherTest, MultipleThreadsNotResponding) {
// Verify DB thread is responding with ping/pong messaging.
db_watcher_->WaitForCheckResponse(
kUnresponsiveTime + TimeDelta::FromMinutes(1), SUCCESSFUL);
- EXPECT_GT(db_watcher_->success_response_, static_cast<uint64>(0));
- EXPECT_EQ(db_watcher_->failed_response_, static_cast<uint64>(0));
+ EXPECT_GT(base::subtle::NoBarrier_Load(&(db_watcher_->success_response_)),
+ static_cast<base::subtle::Atomic32>(0));
+ EXPECT_EQ(base::subtle::NoBarrier_Load(&(db_watcher_->failed_response_)),
+ static_cast<base::subtle::Atomic32>(0));
// Verify IO thread is not responding for ping messages.
io_watcher_->WaitForCheckResponse(
kUnresponsiveTime + TimeDelta::FromMinutes(1), FAILED);
- EXPECT_EQ(io_watcher_->success_response_, static_cast<uint64>(0));
- EXPECT_GT(io_watcher_->failed_response_, static_cast<uint64>(0));
+ EXPECT_EQ(base::subtle::NoBarrier_Load(&(io_watcher_->success_response_)),
+ static_cast<base::subtle::Atomic32>(0));
+ EXPECT_GT(base::subtle::NoBarrier_Load(&(io_watcher_->failed_response_)),
+ static_cast<base::subtle::Atomic32>(0));
// DeActivate thread watching for shutdown.
WatchDogThread::PostTask(
diff --git a/chrome/browser/metro_utils/metro_chrome_win.cc b/chrome/browser/metro_utils/metro_chrome_win.cc
index 95623a7c90..2959c2d108 100644
--- a/chrome/browser/metro_utils/metro_chrome_win.cc
+++ b/chrome/browser/metro_utils/metro_chrome_win.cc
@@ -9,6 +9,7 @@
#include "base/files/file_path.h"
#include "base/path_service.h"
+#include "base/win/metro.h"
#include "base/win/scoped_com_initializer.h"
#include "base/win/scoped_comptr.h"
#include "chrome/installer/util/browser_distribution.h"
@@ -53,4 +54,19 @@ bool ActivateMetroChrome() {
return true;
}
+Win8Environment GetWin8Environment(HostDesktopType desktop) {
+#if defined(USE_AURA) && defined(USE_ASH)
+ if (desktop == chrome::HOST_DESKTOP_TYPE_ASH)
+ return WIN_8_ENVIRONMENT_METRO_AURA;
+ else
+ return WIN_8_ENVIRONMENT_DESKTOP_AURA;
+#else
+ if (base::win::IsProcessImmersive(::GetCurrentProcess()))
+ return WIN_8_ENVIRONMENT_METRO;
+ else
+ return WIN_8_ENVIRONMENT_DESKTOP;
+#endif
+}
+
+
} // namespace chrome
diff --git a/chrome/browser/metro_utils/metro_chrome_win.h b/chrome/browser/metro_utils/metro_chrome_win.h
index 79b5782328..dadbb8e068 100644
--- a/chrome/browser/metro_utils/metro_chrome_win.h
+++ b/chrome/browser/metro_utils/metro_chrome_win.h
@@ -5,6 +5,8 @@
#ifndef CHROME_BROWSER_METRO_UTILS_METRO_CHROME_WIN_H_
#define CHROME_BROWSER_METRO_UTILS_METRO_CHROME_WIN_H_
+#include "chrome/browser/ui/host_desktop.h"
+
namespace chrome {
// Using IApplicationActivationManager::ActivateApplication, activate the
@@ -14,6 +16,16 @@ namespace chrome {
// PostTask to handle that case.
bool ActivateMetroChrome();
+enum Win8Environment {
+ WIN_8_ENVIRONMENT_METRO,
+ WIN_8_ENVIRONMENT_DESKTOP,
+ WIN_8_ENVIRONMENT_METRO_AURA,
+ WIN_8_ENVIRONMENT_DESKTOP_AURA,
+ WIN_8_ENVIRONMENT_MAX
+};
+
+Win8Environment GetWin8Environment(HostDesktopType desktop);
+
} // namespace chrome
#endif // CHROME_BROWSER_METRO_UTILS_METRO_CHROME_WIN_H_
diff --git a/chrome/browser/nacl_host/nacl_browser.cc b/chrome/browser/nacl_host/nacl_browser.cc
index 760638359d..b561432c21 100644
--- a/chrome/browser/nacl_host/nacl_browser.cc
+++ b/chrome/browser/nacl_host/nacl_browser.cc
@@ -176,11 +176,14 @@ void NaClBrowser::SetDelegate(NaClBrowserDelegate* delegate) {
}
NaClBrowserDelegate* NaClBrowser::GetDelegate() {
+ // The delegate is not owned by the IO thread. This accessor method can be
+ // called from other threads.
DCHECK(GetInstance()->browser_delegate_.get() != NULL);
return GetInstance()->browser_delegate_.get();
}
void NaClBrowser::EarlyStartup() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
InitIrtFilePath();
InitValidationCacheFilePath();
}
@@ -239,18 +242,21 @@ bool NaClBrowser::IsOk() const {
}
base::PlatformFile NaClBrowser::IrtFile() const {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
CHECK_EQ(irt_state_, NaClResourceReady);
CHECK_NE(irt_platform_file_, base::kInvalidPlatformFileValue);
return irt_platform_file_;
}
void NaClBrowser::EnsureAllResourcesAvailable() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
EnsureIrtAvailable();
EnsureValidationCacheAvailable();
}
// Load the IRT async.
void NaClBrowser::EnsureIrtAvailable() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
if (IsOk() && irt_state_ == NaClResourceUninitialized) {
irt_state_ = NaClResourceRequested;
// TODO(ncbray) use blocking pool.
@@ -271,6 +277,7 @@ void NaClBrowser::EnsureIrtAvailable() {
void NaClBrowser::OnIrtOpened(base::PlatformFileError error_code,
base::PassPlatformFile file,
bool created) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
DCHECK_EQ(irt_state_, NaClResourceRequested);
DCHECK(!created);
if (error_code == base::PLATFORM_FILE_OK) {
@@ -369,6 +376,7 @@ void NaClBrowser::InitValidationCacheFilePath() {
}
void NaClBrowser::EnsureValidationCacheAvailable() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
if (IsOk() && validation_cache_state_ == NaClResourceUninitialized) {
if (ValidationCacheIsEnabled()) {
validation_cache_state_ = NaClResourceRequested;
@@ -393,6 +401,7 @@ void NaClBrowser::EnsureValidationCacheAvailable() {
}
void NaClBrowser::OnValidationCacheLoaded(const std::string *data) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
// Did the cache get cleared before the load completed? If so, ignore the
// incoming data.
if (validation_cache_state_ == NaClResourceReady)
@@ -418,6 +427,7 @@ void NaClBrowser::RunWithoutValidationCache() {
}
void NaClBrowser::CheckWaiting() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
if (!IsOk() || IsReady()) {
// Queue the waiting tasks into the message loop. This helps avoid
// re-entrancy problems that could occur if the closure was invoked
@@ -448,6 +458,7 @@ const base::FilePath& NaClBrowser::GetIrtFilePath() {
void NaClBrowser::PutFilePath(const base::FilePath& path, uint64* file_token_lo,
uint64* file_token_hi) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
while (true) {
uint64 file_token[2] = {base::RandUint64(), base::RandUint64()};
// A zero file_token indicates there is no file_token, if we get zero, ask
@@ -468,6 +479,7 @@ void NaClBrowser::PutFilePath(const base::FilePath& path, uint64* file_token_lo,
bool NaClBrowser::GetFilePath(uint64 file_token_lo, uint64 file_token_hi,
base::FilePath* path) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
uint64 file_token[2] = {file_token_lo, file_token_hi};
std::string key(reinterpret_cast<char*>(file_token), sizeof(file_token));
PathCacheType::iterator iter = path_cache_.Peek(key);
@@ -483,6 +495,7 @@ bool NaClBrowser::GetFilePath(uint64 file_token_lo, uint64 file_token_hi,
bool NaClBrowser::QueryKnownToValidate(const std::string& signature,
bool off_the_record) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
if (off_the_record) {
// If we're off the record, don't reorder the main cache.
return validation_cache_.QueryKnownToValidate(signature, false) ||
@@ -498,6 +511,7 @@ bool NaClBrowser::QueryKnownToValidate(const std::string& signature,
void NaClBrowser::SetKnownToValidate(const std::string& signature,
bool off_the_record) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
if (off_the_record) {
off_the_record_validation_cache_.SetKnownToValidate(signature);
} else {
@@ -510,6 +524,7 @@ void NaClBrowser::SetKnownToValidate(const std::string& signature,
}
void NaClBrowser::ClearValidationCache(const base::Closure& callback) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
// Note: this method may be called before EnsureValidationCacheAvailable has
// been invoked. In other words, this method may be called before any NaCl
// processes have been created. This method must succeed and invoke the
@@ -561,6 +576,7 @@ void NaClBrowser::MarkValidationCacheAsModified() {
}
void NaClBrowser::PersistValidationCache() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
// validation_cache_is_modified_ may be false if the cache was cleared while
// this delayed task was pending.
// validation_cache_file_path_ may be empty if something went wrong during
diff --git a/chrome/browser/nacl_host/nacl_browser_delegate_impl.cc b/chrome/browser/nacl_host/nacl_browser_delegate_impl.cc
index eec61e5188..558c53e152 100644
--- a/chrome/browser/nacl_host/nacl_browser_delegate_impl.cc
+++ b/chrome/browser/nacl_host/nacl_browser_delegate_impl.cc
@@ -5,17 +5,33 @@
#include "chrome/browser/nacl_host/nacl_browser_delegate_impl.h"
#include "base/path_service.h"
+#include "base/strings/string_util.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/component_updater/pnacl/pnacl_component_installer.h"
+#include "chrome/browser/extensions/extension_info_map.h"
+#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/nacl_host/nacl_infobar_delegate.h"
#include "chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_paths_internal.h"
#include "chrome/common/chrome_version_info.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/manifest_handlers/shared_module_info.h"
#include "chrome/common/logging_chrome.h"
#include "content/public/browser/browser_thread.h"
+#include "extensions/common/constants.h"
#include "ppapi/c/private/ppb_nacl_private.h"
+using extensions::SharedModuleInfo;
+
+NaClBrowserDelegateImpl::NaClBrowserDelegateImpl(
+ ExtensionInfoMap* extension_info_map)
+ : extension_info_map_(extension_info_map) {
+}
+
+NaClBrowserDelegateImpl::~NaClBrowserDelegateImpl() {
+}
+
void NaClBrowserDelegateImpl::ShowNaClInfobar(int render_process_id,
int render_view_id,
int error_id) {
@@ -68,3 +84,64 @@ void NaClBrowserDelegateImpl::TryInstallPnacl(
else
installed.Run(false);
}
+
+// This function is security sensitive. Be sure to check with a security
+// person before you modify it.
+bool NaClBrowserDelegateImpl::MapUrlToLocalFilePath(
+ const GURL& file_url, bool use_blocking_api, base::FilePath* file_path) {
+ DCHECK(extension_info_map_);
+ // Check that the URL is recognized by the extension system.
+ const extensions::Extension* extension =
+ extension_info_map_->extensions().GetExtensionOrAppByURL(file_url);
+ if (!extension)
+ return false;
+
+ // This is a short-cut which avoids calling a blocking file operation
+ // (GetFilePath()), so that this can be called on the IO thread. It only
+ // handles a subset of the urls.
+ if (!use_blocking_api) {
+ if (file_url.SchemeIs(extensions::kExtensionScheme)) {
+ std::string path = file_url.path();
+ TrimString(path, "/", &path); // Remove first slash
+ *file_path = extension->path().AppendASCII(path);
+ return true;
+ }
+ return false;
+ }
+
+ std::string path = file_url.path();
+ extensions::ExtensionResource resource;
+
+ if (SharedModuleInfo::IsImportedPath(path)) {
+ // Check if this is a valid path that is imported for this extension.
+ std::string new_extension_id;
+ std::string new_relative_path;
+ SharedModuleInfo::ParseImportedPath(path, &new_extension_id,
+ &new_relative_path);
+ const extensions::Extension* new_extension =
+ extension_info_map_->extensions().GetByID(new_extension_id);
+ if (!new_extension)
+ return false;
+
+ if (!SharedModuleInfo::ImportsExtensionById(extension, new_extension_id) ||
+ !SharedModuleInfo::IsExportAllowed(new_extension, new_relative_path)) {
+ return false;
+ }
+
+ resource = new_extension->GetResource(new_relative_path);
+ } else {
+ // Check that the URL references a resource in the extension.
+ resource = extension->GetResource(path);
+ }
+
+ if (resource.empty())
+ return false;
+
+ // GetFilePath is a blocking function call.
+ const base::FilePath resource_file_path = resource.GetFilePath();
+ if (resource_file_path.empty())
+ return false;
+
+ *file_path = resource_file_path;
+ return true;
+}
diff --git a/chrome/browser/nacl_host/nacl_browser_delegate_impl.h b/chrome/browser/nacl_host/nacl_browser_delegate_impl.h
index 84933e0814..e71fbdd544 100644
--- a/chrome/browser/nacl_host/nacl_browser_delegate_impl.h
+++ b/chrome/browser/nacl_host/nacl_browser_delegate_impl.h
@@ -6,12 +6,13 @@
#define CHROME_BROWSER_NACL_HOST_NACL_BROWSER_DELEGATE_IMPL_H_
#include "base/compiler_specific.h"
+#include "chrome/browser/extensions/extension_info_map.h"
#include "components/nacl/common/nacl_browser_delegate.h"
class NaClBrowserDelegateImpl : public NaClBrowserDelegate {
public:
- NaClBrowserDelegateImpl() {}
- virtual ~NaClBrowserDelegateImpl() {}
+ explicit NaClBrowserDelegateImpl(ExtensionInfoMap* extension_info_map);
+ virtual ~NaClBrowserDelegateImpl();
virtual void ShowNaClInfobar(int render_process_id, int render_view_id,
int error_id) OVERRIDE;
@@ -25,6 +26,13 @@ class NaClBrowserDelegateImpl : public NaClBrowserDelegate {
content::BrowserPpapiHost* ppapi_host) OVERRIDE;
virtual void TryInstallPnacl(
const base::Callback<void(bool)>& installed) OVERRIDE;
+ virtual bool MapUrlToLocalFilePath(const GURL& url,
+ bool is_blocking,
+ base::FilePath* file_path) OVERRIDE;
+
+ private:
+ scoped_refptr<ExtensionInfoMap> extension_info_map_;
+ DISALLOW_COPY_AND_ASSIGN(NaClBrowserDelegateImpl);
};
diff --git a/chrome/browser/nacl_host/nacl_file_host.cc b/chrome/browser/nacl_host/nacl_file_host.cc
index 1acdf429df..e400df710a 100644
--- a/chrome/browser/nacl_host/nacl_file_host.cc
+++ b/chrome/browser/nacl_host/nacl_file_host.cc
@@ -11,10 +11,8 @@
#include "base/platform_file.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/sequenced_worker_pool.h"
-#include "chrome/browser/extensions/extension_info_map.h"
#include "chrome/browser/nacl_host/nacl_browser.h"
#include "chrome/browser/nacl_host/nacl_host_message_filter.h"
-#include "chrome/common/extensions/manifest_handlers/shared_module_info.h"
#include "components/nacl/common/nacl_browser_delegate.h"
#include "components/nacl/common/nacl_host_messages.h"
#include "components/nacl/common/pnacl_types.h"
@@ -24,7 +22,6 @@
#include "ipc/ipc_platform_file.h"
using content::BrowserThread;
-using extensions::SharedModuleInfo;
namespace {
@@ -152,67 +149,18 @@ void DoRegisterOpenedNaClExecutableFile(
nacl_host_message_filter->Send(reply_msg);
}
-// Convert the file URL into a file path in the extension directory.
-// This function is security sensitive. Be sure to check with a security
-// person before you modify it.
-bool GetExtensionFilePath(
- scoped_refptr<ExtensionInfoMap> extension_info_map,
- const GURL& file_url,
- base::FilePath* file_path) {
- // Check that the URL is recognized by the extension system.
- const extensions::Extension* extension =
- extension_info_map->extensions().GetExtensionOrAppByURL(file_url);
- if (!extension)
- return false;
-
- std::string path = file_url.path();
- extensions::ExtensionResource resource;
-
- if (SharedModuleInfo::IsImportedPath(path)) {
- // Check if this is a valid path that is imported for this extension.
- std::string new_extension_id;
- std::string new_relative_path;
- SharedModuleInfo::ParseImportedPath(path, &new_extension_id,
- &new_relative_path);
- const extensions::Extension* new_extension =
- extension_info_map->extensions().GetByID(new_extension_id);
- if (!new_extension)
- return false;
-
- if (!SharedModuleInfo::ImportsExtensionById(extension, new_extension_id) ||
- !SharedModuleInfo::IsExportAllowed(new_extension, new_relative_path)) {
- return false;
- }
-
- resource = new_extension->GetResource(new_relative_path);
- } else {
- // Check that the URL references a resource in the extension.
- resource = extension->GetResource(path);
- }
-
- if (resource.empty())
- return false;
-
- const base::FilePath resource_file_path = resource.GetFilePath();
- if (resource_file_path.empty())
- return false;
-
- *file_path = resource_file_path;
- return true;
-}
-
// Convert the file URL into a file descriptor.
// This function is security sensitive. Be sure to check with a security
// person before you modify it.
void DoOpenNaClExecutableOnThreadPool(
scoped_refptr<NaClHostMessageFilter> nacl_host_message_filter,
- scoped_refptr<ExtensionInfoMap> extension_info_map,
const GURL& file_url,
IPC::Message* reply_msg) {
DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
base::FilePath file_path;
- if (!GetExtensionFilePath(extension_info_map, file_url, &file_path)) {
+ if (!NaClBrowser::GetDelegate()->MapUrlToLocalFilePath(
+ file_url, true /* use_blocking_api */, &file_path)) {
NotifyRendererOfError(nacl_host_message_filter.get(), reply_msg);
return;
}
@@ -299,7 +247,6 @@ bool PnaclCanOpenFile(const std::string& filename,
void OpenNaClExecutable(
scoped_refptr<NaClHostMessageFilter> nacl_host_message_filter,
- scoped_refptr<ExtensionInfoMap> extension_info_map,
int render_view_id,
const GURL& file_url,
IPC::Message* reply_msg) {
@@ -309,7 +256,6 @@ void OpenNaClExecutable(
base::Bind(
&OpenNaClExecutable,
nacl_host_message_filter,
- extension_info_map,
render_view_id, file_url, reply_msg));
return;
}
@@ -339,7 +285,6 @@ void OpenNaClExecutable(
base::Bind(
&DoOpenNaClExecutableOnThreadPool,
nacl_host_message_filter,
- extension_info_map,
file_url, reply_msg))) {
NotifyRendererOfError(nacl_host_message_filter.get(), reply_msg);
}
diff --git a/chrome/browser/nacl_host/nacl_file_host.h b/chrome/browser/nacl_host/nacl_file_host.h
index b6e04fba6e..baf2d5a6af 100644
--- a/chrome/browser/nacl_host/nacl_file_host.h
+++ b/chrome/browser/nacl_host/nacl_file_host.h
@@ -10,7 +10,6 @@
#include "base/callback_forward.h"
#include "base/memory/ref_counted.h"
-class ExtensionInfoMap;
class GURL;
class NaClHostMessageFilter;
@@ -56,7 +55,6 @@ bool PnaclCanOpenFile(const std::string& filename,
// Opens a NaCl executable file for reading and executing.
void OpenNaClExecutable(
scoped_refptr<NaClHostMessageFilter> nacl_host_message_filter,
- scoped_refptr<ExtensionInfoMap> extension_info_map,
int render_view_id,
const GURL& file_url,
IPC::Message* reply_msg);
diff --git a/chrome/browser/nacl_host/nacl_file_host_unittest.cc b/chrome/browser/nacl_host/nacl_file_host_unittest.cc
index 3bf9e9aa0f..8d74850703 100644
--- a/chrome/browser/nacl_host/nacl_file_host_unittest.cc
+++ b/chrome/browser/nacl_host/nacl_file_host_unittest.cc
@@ -60,6 +60,12 @@ class TestNaClBrowserDelegate : public NaClBrowserDelegate {
return NULL;
}
+ virtual bool MapUrlToLocalFilePath(const GURL& file_url,
+ bool use_blocking_api,
+ base::FilePath* file_path) OVERRIDE {
+ return false;
+ }
+
virtual void TryInstallPnacl(
const base::Callback<void(bool)>& installed) OVERRIDE {
installed.Run(should_pnacl_install_succeed_);
diff --git a/chrome/browser/nacl_host/nacl_host_message_filter.cc b/chrome/browser/nacl_host/nacl_host_message_filter.cc
index 7ad5ac6be6..a8d6cfbefd 100644
--- a/chrome/browser/nacl_host/nacl_host_message_filter.cc
+++ b/chrome/browser/nacl_host/nacl_host_message_filter.cc
@@ -4,42 +4,25 @@
#include "chrome/browser/nacl_host/nacl_host_message_filter.h"
-#include "chrome/browser/extensions/extension_info_map.h"
#include "chrome/browser/nacl_host/nacl_browser.h"
#include "chrome/browser/nacl_host/nacl_file_host.h"
#include "chrome/browser/nacl_host/nacl_process_host.h"
#include "chrome/browser/nacl_host/pnacl_host.h"
#include "components/nacl/common/nacl_host_messages.h"
-#include "extensions/common/constants.h"
#include "ipc/ipc_platform_file.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
-
-static base::FilePath GetManifestPath(
- ExtensionInfoMap* extension_info_map, const std::string& manifest) {
- GURL manifest_url(manifest);
- const extensions::Extension* extension = extension_info_map->extensions()
- .GetExtensionOrAppByURL(manifest_url);
- if (extension != NULL &&
- manifest_url.SchemeIs(extensions::kExtensionScheme)) {
- std::string path = manifest_url.path();
- TrimString(path, "/", &path); // Remove first slash
- return extension->path().AppendASCII(path);
- }
- return base::FilePath();
-}
+#include "url/gurl.h"
NaClHostMessageFilter::NaClHostMessageFilter(
int render_process_id,
bool is_off_the_record,
const base::FilePath& profile_directory,
- ExtensionInfoMap* extension_info_map,
net::URLRequestContextGetter* request_context)
: render_process_id_(render_process_id),
off_the_record_(is_off_the_record),
profile_directory_(profile_directory),
request_context_(request_context),
- extension_info_map_(extension_info_map),
weak_ptr_factory_(this) {
}
@@ -94,9 +77,14 @@ void NaClHostMessageFilter::OnLaunchNaCl(
launch_params.enable_crash_throttling,
off_the_record_,
profile_directory_);
- base::FilePath manifest_url =
- GetManifestPath(extension_info_map_.get(), launch_params.manifest_url);
- host->Launch(this, reply_msg, manifest_url);
+ GURL manifest_url(launch_params.manifest_url);
+ base::FilePath manifest_path;
+ // We're calling MapUrlToLocalFilePath with the non-blocking API
+ // because we're running in the I/O thread. Ideally we'd use the other path,
+ // which would cover more cases.
+ NaClBrowser::GetDelegate()->MapUrlToLocalFilePath(
+ manifest_url, false /* use_blocking_api */, &manifest_path);
+ host->Launch(this, reply_msg, manifest_path);
}
void NaClHostMessageFilter::ReplyEnsurePnaclInstalled(
@@ -202,7 +190,7 @@ void NaClHostMessageFilter::OnNaClErrorStatus(int render_view_id,
void NaClHostMessageFilter::OnOpenNaClExecutable(int render_view_id,
const GURL& file_url,
IPC::Message* reply_msg) {
- nacl_file_host::OpenNaClExecutable(this, extension_info_map_,
- render_view_id, file_url, reply_msg);
+ nacl_file_host::OpenNaClExecutable(this, render_view_id, file_url,
+ reply_msg);
}
#endif
diff --git a/chrome/browser/nacl_host/nacl_host_message_filter.h b/chrome/browser/nacl_host/nacl_host_message_filter.h
index 4c05f22b82..f4493fc132 100644
--- a/chrome/browser/nacl_host/nacl_host_message_filter.h
+++ b/chrome/browser/nacl_host/nacl_host_message_filter.h
@@ -10,7 +10,6 @@
#include "base/platform_file.h"
#include "content/public/browser/browser_message_filter.h"
-class ExtensionInfoMap;
class GURL;
namespace nacl {
@@ -31,7 +30,6 @@ class NaClHostMessageFilter : public content::BrowserMessageFilter {
NaClHostMessageFilter(int render_process_id,
bool is_off_the_record,
const base::FilePath& profile_directory,
- ExtensionInfoMap* extension_info_map,
net::URLRequestContextGetter* request_context);
// content::BrowserMessageFilter methods:
@@ -82,7 +80,6 @@ class NaClHostMessageFilter : public content::BrowserMessageFilter {
bool off_the_record_;
base::FilePath profile_directory_;
scoped_refptr<net::URLRequestContextGetter> request_context_;
- scoped_refptr<ExtensionInfoMap> extension_info_map_;
base::WeakPtrFactory<NaClHostMessageFilter> weak_ptr_factory_;
diff --git a/chrome/browser/nacl_host/nacl_process_host.cc b/chrome/browser/nacl_host/nacl_process_host.cc
index 157a8d2f7a..68e5fd7da8 100644
--- a/chrome/browser/nacl_host/nacl_process_host.cc
+++ b/chrome/browser/nacl_host/nacl_process_host.cc
@@ -28,7 +28,6 @@
#include "chrome/browser/nacl_host/nacl_browser.h"
#include "chrome/browser/nacl_host/nacl_host_message_filter.h"
#include "chrome/common/chrome_switches.h"
-#include "components/nacl/common/nacl_browser_delegate.h"
#include "components/nacl/common/nacl_cmd_line.h"
#include "components/nacl/common/nacl_host_messages.h"
#include "components/nacl/common/nacl_messages.h"
@@ -313,8 +312,7 @@ void NaClProcessHost::OnProcessCrashed(int exit_status) {
// This is called at browser startup.
// static
-void NaClProcessHost::EarlyStartup(NaClBrowserDelegate* delegate) {
- NaClBrowser::SetDelegate(delegate);
+void NaClProcessHost::EarlyStartup() {
NaClBrowser::GetInstance()->EarlyStartup();
#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
// Open the IRT file early to make sure that it isn't replaced out from
diff --git a/chrome/browser/nacl_host/nacl_process_host.h b/chrome/browser/nacl_host/nacl_process_host.h
index 8a884fcf15..6db00bc395 100644
--- a/chrome/browser/nacl_host/nacl_process_host.h
+++ b/chrome/browser/nacl_host/nacl_process_host.h
@@ -23,7 +23,6 @@
class CommandLine;
class ExtensionInfoMap;
-class NaClBrowserDelegate;
class NaClHostMessageFilter;
namespace content {
@@ -76,7 +75,7 @@ class NaClProcessHost : public content::BrowserChildProcessHostDelegate {
virtual void OnProcessCrashed(int exit_status) OVERRIDE;
// Do any minimal work that must be done at browser startup.
- static void EarlyStartup(NaClBrowserDelegate* delegate);
+ static void EarlyStartup();
// Initialize the new NaCl process. Result is returned by sending ipc
// message reply_msg.
diff --git a/chrome/browser/net/OWNERS b/chrome/browser/net/OWNERS
index 525917bbfb..85296d3598 100644
--- a/chrome/browser/net/OWNERS
+++ b/chrome/browser/net/OWNERS
@@ -10,3 +10,6 @@ rdsmith@chromium.org
rtenneti@chromium.org
willchan@chromium.org
wtc@chromium.org
+
+per-file proxy_policy_handler*=joaodasilva@chromium.org
+per-file proxy_policy_handler*=dconnelly@chromium.org
diff --git a/chrome/browser/net/net_error_tab_helper.cc b/chrome/browser/net/net_error_tab_helper.cc
index c441c2cd18..cd40152f1f 100644
--- a/chrome/browser/net/net_error_tab_helper.cc
+++ b/chrome/browser/net/net_error_tab_helper.cc
@@ -95,6 +95,7 @@ void NetErrorTabHelper::DidStartProvisionalLoadForFrame(
void NetErrorTabHelper::DidCommitProvisionalLoadForFrame(
int64 frame_id,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& url,
PageTransition transition_type,
@@ -120,6 +121,7 @@ void NetErrorTabHelper::DidCommitProvisionalLoadForFrame(
void NetErrorTabHelper::DidFailProvisionalLoad(
int64 frame_id,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& validated_url,
int error_code,
diff --git a/chrome/browser/net/net_error_tab_helper.h b/chrome/browser/net/net_error_tab_helper.h
index 2a38e0c032..e9e1fc64d0 100644
--- a/chrome/browser/net/net_error_tab_helper.h
+++ b/chrome/browser/net/net_error_tab_helper.h
@@ -57,6 +57,7 @@ class NetErrorTabHelper
virtual void DidCommitProvisionalLoadForFrame(
int64 frame_id,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& url,
content::PageTransition transition_type,
@@ -64,6 +65,7 @@ class NetErrorTabHelper
virtual void DidFailProvisionalLoad(
int64 frame_id,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& validated_url,
int error_code,
diff --git a/chrome/browser/net/net_error_tab_helper_unittest.cc b/chrome/browser/net/net_error_tab_helper_unittest.cc
index 1d4a225fe8..488faeb443 100644
--- a/chrome/browser/net/net_error_tab_helper_unittest.cc
+++ b/chrome/browser/net/net_error_tab_helper_unittest.cc
@@ -78,6 +78,7 @@ class NetErrorTabHelperTest : public testing::Test {
void CommitProvisionalLoad(MainFrame main_frame) {
tab_helper_.DidCommitProvisionalLoadForFrame(
1, // frame id
+ string16(),
(main_frame == MAIN_FRAME),
bogus_url_, // url
content::PAGE_TRANSITION_TYPED,
@@ -94,6 +95,7 @@ class NetErrorTabHelperTest : public testing::Test {
tab_helper_.DidFailProvisionalLoad(
1, // frame id
+ string16(),
(main_frame == MAIN_FRAME),
bogus_url_, // validated_url
net_error,
diff --git a/chrome/browser/net/predictor_tab_helper.cc b/chrome/browser/net/predictor_tab_helper.cc
index 0b8be8f3b5..b1fd4509a4 100644
--- a/chrome/browser/net/predictor_tab_helper.cc
+++ b/chrome/browser/net/predictor_tab_helper.cc
@@ -4,8 +4,11 @@
#include "chrome/browser/net/predictor_tab_helper.h"
+#include "base/command_line.h"
#include "chrome/browser/net/predictor.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/url_constants.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/frame_navigate_params.h"
@@ -38,6 +41,20 @@ PredictorTabHelper::PredictorTabHelper(content::WebContents* web_contents)
PredictorTabHelper::~PredictorTabHelper() {
}
+void PredictorTabHelper::NavigateToPendingEntry(
+ const GURL& url,
+ content::NavigationController::ReloadType reload_type) {
+ Profile* profile =
+ Profile::FromBrowserContext(web_contents()->GetBrowserContext());
+ chrome_browser_net::Predictor* predictor = profile->GetNetworkPredictor();
+ if (!predictor)
+ return;
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kChromeFrame) &&
+ (url.SchemeIs(content::kHttpScheme) ||
+ url.SchemeIs(content::kHttpsScheme)))
+ predictor->PreconnectUrlAndSubresources(url, GURL());
+}
+
void PredictorTabHelper::DidNavigateMainFrame(
const content::LoadCommittedDetails& details,
const content::FrameNavigateParams& params) {
diff --git a/chrome/browser/net/predictor_tab_helper.h b/chrome/browser/net/predictor_tab_helper.h
index 2a2a898c58..90a121dfd4 100644
--- a/chrome/browser/net/predictor_tab_helper.h
+++ b/chrome/browser/net/predictor_tab_helper.h
@@ -19,6 +19,9 @@ class PredictorTabHelper
virtual ~PredictorTabHelper();
// content::WebContentsObserver implementation
+ virtual void NavigateToPendingEntry(
+ const GURL& url,
+ content::NavigationController::ReloadType reload_type) OVERRIDE;
virtual void DidNavigateMainFrame(
const content::LoadCommittedDetails& details,
const content::FrameNavigateParams& params) OVERRIDE;
diff --git a/chrome/browser/net/proxy_policy_handler.cc b/chrome/browser/net/proxy_policy_handler.cc
new file mode 100644
index 0000000000..d1ce622e5c
--- /dev/null
+++ b/chrome/browser/net/proxy_policy_handler.cc
@@ -0,0 +1,333 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/net/proxy_policy_handler.h"
+
+#include "base/logging.h"
+#include "base/prefs/pref_value_map.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/values.h"
+#include "chrome/browser/policy/configuration_policy_handler.h"
+#include "chrome/browser/policy/policy_error_map.h"
+#include "chrome/browser/policy/policy_map.h"
+#include "chrome/browser/prefs/proxy_config_dictionary.h"
+#include "chrome/browser/prefs/proxy_prefs.h"
+#include "chrome/common/pref_names.h"
+#include "grit/generated_resources.h"
+#include "policy/policy_constants.h"
+
+namespace {
+
+// This is used to check whether for a given ProxyMode value, the ProxyPacUrl,
+// the ProxyBypassList and the ProxyServer policies are allowed to be specified.
+// |error_message_id| is the message id of the localized error message to show
+// when the policies are not specified as allowed. Each value of ProxyMode
+// has a ProxyModeValidationEntry in the |kProxyModeValidationMap| below.
+struct ProxyModeValidationEntry {
+ const char* mode_value;
+ bool pac_url_allowed;
+ bool bypass_list_allowed;
+ bool server_allowed;
+ int error_message_id;
+};
+
+// List of entries determining which proxy policies can be specified, depending
+// on the ProxyMode.
+const ProxyModeValidationEntry kProxyModeValidationMap[] = {
+ { ProxyPrefs::kDirectProxyModeName,
+ false, false, false, IDS_POLICY_PROXY_MODE_DISABLED_ERROR },
+ { ProxyPrefs::kAutoDetectProxyModeName,
+ false, false, false, IDS_POLICY_PROXY_MODE_AUTO_DETECT_ERROR },
+ { ProxyPrefs::kPacScriptProxyModeName,
+ true, false, false, IDS_POLICY_PROXY_MODE_PAC_URL_ERROR },
+ { ProxyPrefs::kFixedServersProxyModeName,
+ false, true, true, IDS_POLICY_PROXY_MODE_FIXED_SERVERS_ERROR },
+ { ProxyPrefs::kSystemProxyModeName,
+ false, false, false, IDS_POLICY_PROXY_MODE_SYSTEM_ERROR },
+};
+
+} // namespace
+
+namespace policy {
+
+// The proxy policies have the peculiarity that they are loaded from individual
+// policies, but the providers then expose them through a unified
+// DictionaryValue. Once Dictionary policies are fully supported, the individual
+// proxy policies will be deprecated. http://crbug.com/108996
+
+ProxyPolicyHandler::ProxyPolicyHandler() {}
+
+ProxyPolicyHandler::~ProxyPolicyHandler() {
+}
+
+bool ProxyPolicyHandler::CheckPolicySettings(const PolicyMap& policies,
+ PolicyErrorMap* errors) {
+ const base::Value* mode = GetProxyPolicyValue(policies, key::kProxyMode);
+ const base::Value* server = GetProxyPolicyValue(policies, key::kProxyServer);
+ const base::Value* server_mode =
+ GetProxyPolicyValue(policies, key::kProxyServerMode);
+ const base::Value* pac_url = GetProxyPolicyValue(policies, key::kProxyPacUrl);
+ const base::Value* bypass_list =
+ GetProxyPolicyValue(policies, key::kProxyBypassList);
+
+ if ((server || pac_url || bypass_list) && !(mode || server_mode)) {
+ errors->AddError(key::kProxySettings,
+ key::kProxyMode,
+ IDS_POLICY_NOT_SPECIFIED_ERROR);
+ return false;
+ }
+
+ std::string mode_value;
+ if (!CheckProxyModeAndServerMode(policies, errors, &mode_value))
+ return false;
+
+ // If neither ProxyMode nor ProxyServerMode are specified, mode_value will be
+ // empty and the proxy shouldn't be configured at all.
+ if (mode_value.empty())
+ return true;
+
+ bool is_valid_mode = false;
+ for (size_t i = 0; i != arraysize(kProxyModeValidationMap); ++i) {
+ const ProxyModeValidationEntry& entry = kProxyModeValidationMap[i];
+ if (entry.mode_value != mode_value)
+ continue;
+
+ is_valid_mode = true;
+
+ if (!entry.pac_url_allowed && pac_url) {
+ errors->AddError(key::kProxySettings,
+ key::kProxyPacUrl,
+ entry.error_message_id);
+ }
+ if (!entry.bypass_list_allowed && bypass_list) {
+ errors->AddError(key::kProxySettings,
+ key::kProxyBypassList,
+ entry.error_message_id);
+ }
+ if (!entry.server_allowed && server) {
+ errors->AddError(key::kProxySettings,
+ key::kProxyServer,
+ entry.error_message_id);
+ }
+
+ if ((!entry.pac_url_allowed && pac_url) ||
+ (!entry.bypass_list_allowed && bypass_list) ||
+ (!entry.server_allowed && server)) {
+ return false;
+ }
+ }
+
+ if (!is_valid_mode) {
+ errors->AddError(key::kProxySettings,
+ mode ? key::kProxyMode : key::kProxyServerMode,
+ IDS_POLICY_OUT_OF_RANGE_ERROR,
+ mode_value);
+ return false;
+ }
+ return true;
+}
+
+void ProxyPolicyHandler::ApplyPolicySettings(const PolicyMap& policies,
+ PrefValueMap* prefs) {
+ const base::Value* mode = GetProxyPolicyValue(policies, key::kProxyMode);
+ const base::Value* server = GetProxyPolicyValue(policies, key::kProxyServer);
+ const base::Value* server_mode =
+ GetProxyPolicyValue(policies, key::kProxyServerMode);
+ const base::Value* pac_url = GetProxyPolicyValue(policies, key::kProxyPacUrl);
+ const base::Value* bypass_list =
+ GetProxyPolicyValue(policies, key::kProxyBypassList);
+
+ ProxyPrefs::ProxyMode proxy_mode;
+ if (mode) {
+ std::string string_mode;
+ CHECK(mode->GetAsString(&string_mode));
+ CHECK(ProxyPrefs::StringToProxyMode(string_mode, &proxy_mode));
+ } else if (server_mode) {
+ int int_mode = 0;
+ CHECK(server_mode->GetAsInteger(&int_mode));
+
+ switch (int_mode) {
+ case PROXY_SERVER_MODE:
+ proxy_mode = ProxyPrefs::MODE_DIRECT;
+ break;
+ case PROXY_AUTO_DETECT_PROXY_SERVER_MODE:
+ proxy_mode = ProxyPrefs::MODE_AUTO_DETECT;
+ break;
+ case PROXY_MANUALLY_CONFIGURED_PROXY_SERVER_MODE:
+ proxy_mode = ProxyPrefs::MODE_FIXED_SERVERS;
+ if (pac_url)
+ proxy_mode = ProxyPrefs::MODE_PAC_SCRIPT;
+ break;
+ case PROXY_USE_SYSTEM_PROXY_SERVER_MODE:
+ proxy_mode = ProxyPrefs::MODE_SYSTEM;
+ break;
+ default:
+ proxy_mode = ProxyPrefs::MODE_DIRECT;
+ NOTREACHED();
+ }
+ } else {
+ return;
+ }
+
+ switch (proxy_mode) {
+ case ProxyPrefs::MODE_DIRECT:
+ prefs->SetValue(prefs::kProxy, ProxyConfigDictionary::CreateDirect());
+ break;
+ case ProxyPrefs::MODE_AUTO_DETECT:
+ prefs->SetValue(prefs::kProxy, ProxyConfigDictionary::CreateAutoDetect());
+ break;
+ case ProxyPrefs::MODE_PAC_SCRIPT: {
+ std::string pac_url_string;
+ if (pac_url && pac_url->GetAsString(&pac_url_string)) {
+ prefs->SetValue(
+ prefs::kProxy,
+ ProxyConfigDictionary::CreatePacScript(pac_url_string, false));
+ } else {
+ NOTREACHED();
+ }
+ break;
+ }
+ case ProxyPrefs::MODE_FIXED_SERVERS: {
+ std::string proxy_server;
+ std::string bypass_list_string;
+ if (server->GetAsString(&proxy_server)) {
+ if (bypass_list)
+ bypass_list->GetAsString(&bypass_list_string);
+ prefs->SetValue(prefs::kProxy,
+ ProxyConfigDictionary::CreateFixedServers(
+ proxy_server, bypass_list_string));
+ }
+ break;
+ }
+ case ProxyPrefs::MODE_SYSTEM:
+ prefs->SetValue(prefs::kProxy, ProxyConfigDictionary::CreateSystem());
+ break;
+ case ProxyPrefs::kModeCount:
+ NOTREACHED();
+ }
+}
+
+const base::Value* ProxyPolicyHandler::GetProxyPolicyValue(
+ const PolicyMap& policies, const char* policy_name) {
+ // See note on the ProxyPolicyHandler implementation above.
+ const base::Value* value = policies.GetValue(key::kProxySettings);
+ const DictionaryValue* settings;
+ if (!value || !value->GetAsDictionary(&settings))
+ return NULL;
+
+ const base::Value* policy_value = NULL;
+ std::string tmp;
+ if (!settings->Get(policy_name, &policy_value) ||
+ policy_value->IsType(Value::TYPE_NULL) ||
+ (policy_value->IsType(Value::TYPE_STRING) &&
+ policy_value->GetAsString(&tmp) &&
+ tmp.empty())) {
+ return NULL;
+ }
+ return policy_value;
+}
+
+bool ProxyPolicyHandler::CheckProxyModeAndServerMode(const PolicyMap& policies,
+ PolicyErrorMap* errors,
+ std::string* mode_value) {
+ const base::Value* mode = GetProxyPolicyValue(policies, key::kProxyMode);
+ const base::Value* server = GetProxyPolicyValue(policies, key::kProxyServer);
+ const base::Value* server_mode =
+ GetProxyPolicyValue(policies, key::kProxyServerMode);
+ const base::Value* pac_url = GetProxyPolicyValue(policies, key::kProxyPacUrl);
+
+ // If there's a server mode, convert it into a mode.
+ // When both are specified, the mode takes precedence.
+ if (mode) {
+ if (server_mode) {
+ errors->AddError(key::kProxySettings,
+ key::kProxyServerMode,
+ IDS_POLICY_OVERRIDDEN,
+ key::kProxyMode);
+ }
+ if (!mode->GetAsString(mode_value)) {
+ errors->AddError(key::kProxySettings,
+ key::kProxyMode,
+ IDS_POLICY_TYPE_ERROR,
+ ValueTypeToString(Value::TYPE_BOOLEAN));
+ return false;
+ }
+
+ ProxyPrefs::ProxyMode mode;
+ if (!ProxyPrefs::StringToProxyMode(*mode_value, &mode)) {
+ errors->AddError(key::kProxySettings,
+ key::kProxyMode,
+ IDS_POLICY_INVALID_PROXY_MODE_ERROR);
+ return false;
+ }
+
+ if (mode == ProxyPrefs::MODE_PAC_SCRIPT && !pac_url) {
+ errors->AddError(key::kProxySettings,
+ key::kProxyPacUrl,
+ IDS_POLICY_NOT_SPECIFIED_ERROR);
+ return false;
+ } else if (mode == ProxyPrefs::MODE_FIXED_SERVERS && !server) {
+ errors->AddError(key::kProxySettings,
+ key::kProxyServer,
+ IDS_POLICY_NOT_SPECIFIED_ERROR);
+ return false;
+ }
+ } else if (server_mode) {
+ int server_mode_value;
+ if (!server_mode->GetAsInteger(&server_mode_value)) {
+ errors->AddError(key::kProxySettings,
+ key::kProxyServerMode,
+ IDS_POLICY_TYPE_ERROR,
+ ValueTypeToString(Value::TYPE_INTEGER));
+ return false;
+ }
+
+ switch (server_mode_value) {
+ case PROXY_SERVER_MODE:
+ *mode_value = ProxyPrefs::kDirectProxyModeName;
+ break;
+ case PROXY_AUTO_DETECT_PROXY_SERVER_MODE:
+ *mode_value = ProxyPrefs::kAutoDetectProxyModeName;
+ break;
+ case PROXY_MANUALLY_CONFIGURED_PROXY_SERVER_MODE:
+ if (server && pac_url) {
+ int message_id = IDS_POLICY_PROXY_BOTH_SPECIFIED_ERROR;
+ errors->AddError(key::kProxySettings,
+ key::kProxyServer,
+ message_id);
+ errors->AddError(key::kProxySettings,
+ key::kProxyPacUrl,
+ message_id);
+ return false;
+ }
+ if (!server && !pac_url) {
+ int message_id = IDS_POLICY_PROXY_NEITHER_SPECIFIED_ERROR;
+ errors->AddError(key::kProxySettings,
+ key::kProxyServer,
+ message_id);
+ errors->AddError(key::kProxySettings,
+ key::kProxyPacUrl,
+ message_id);
+ return false;
+ }
+ if (pac_url)
+ *mode_value = ProxyPrefs::kPacScriptProxyModeName;
+ else
+ *mode_value = ProxyPrefs::kFixedServersProxyModeName;
+ break;
+ case PROXY_USE_SYSTEM_PROXY_SERVER_MODE:
+ *mode_value = ProxyPrefs::kSystemProxyModeName;
+ break;
+ default:
+ errors->AddError(key::kProxySettings,
+ key::kProxyServerMode,
+ IDS_POLICY_OUT_OF_RANGE_ERROR,
+ base::IntToString(server_mode_value));
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace policy
diff --git a/chrome/browser/net/proxy_policy_handler.h b/chrome/browser/net/proxy_policy_handler.h
new file mode 100644
index 0000000000..b4208d4806
--- /dev/null
+++ b/chrome/browser/net/proxy_policy_handler.h
@@ -0,0 +1,64 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_NET_PROXY_POLICY_HANDLER_H_
+#define CHROME_BROWSER_NET_PROXY_POLICY_HANDLER_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "chrome/browser/policy/configuration_policy_handler.h"
+
+namespace policy {
+
+class ProxyMap;
+class ProxyErrorMap;
+
+// ConfigurationPolicyHandler for the proxy policies.
+class ProxyPolicyHandler : public ConfigurationPolicyHandler {
+ public:
+ // Constants for the "Proxy Server Mode" defined in the policies.
+ // Note that these diverge from internal presentation defined in
+ // ProxyPrefs::ProxyMode for legacy reasons. The following four
+ // PolicyProxyModeType types were not very precise and had overlapping use
+ // cases.
+ enum ProxyModeType {
+ // Disable Proxy, connect directly.
+ PROXY_SERVER_MODE = 0,
+ // Auto detect proxy or use specific PAC script if given.
+ PROXY_AUTO_DETECT_PROXY_SERVER_MODE = 1,
+ // Use manually configured proxy servers (fixed servers).
+ PROXY_MANUALLY_CONFIGURED_PROXY_SERVER_MODE = 2,
+ // Use system proxy server.
+ PROXY_USE_SYSTEM_PROXY_SERVER_MODE = 3,
+
+ MODE_COUNT
+ };
+
+ ProxyPolicyHandler();
+ virtual ~ProxyPolicyHandler();
+
+ // ConfigurationPolicyHandler methods:
+ virtual bool CheckPolicySettings(const PolicyMap& policies,
+ PolicyErrorMap* errors) OVERRIDE;
+ virtual void ApplyPolicySettings(const PolicyMap& policies,
+ PrefValueMap* prefs) OVERRIDE;
+
+ private:
+ const base::Value* GetProxyPolicyValue(const PolicyMap& policies,
+ const char* policy_name);
+
+ // Converts the deprecated ProxyServerMode policy value to a ProxyMode value
+ // and places the result in |mode_value|. Returns whether the conversion
+ // succeeded.
+ bool CheckProxyModeAndServerMode(const PolicyMap& policies,
+ PolicyErrorMap* errors,
+ std::string* mode_value);
+
+ DISALLOW_COPY_AND_ASSIGN(ProxyPolicyHandler);
+};
+
+} // namespace policy
+
+#endif // CHROME_BROWSER_NET_PROXY_POLICY_HANDLER_H_
diff --git a/chrome/browser/net/proxy_policy_handler_unittest.cc b/chrome/browser/net/proxy_policy_handler_unittest.cc
new file mode 100644
index 0000000000..4ff300a624
--- /dev/null
+++ b/chrome/browser/net/proxy_policy_handler_unittest.cc
@@ -0,0 +1,271 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "base/values.h"
+#include "chrome/browser/net/proxy_policy_handler.h"
+#include "chrome/browser/policy/configuration_policy_pref_store.h"
+#include "chrome/browser/policy/configuration_policy_pref_store_unittest.h"
+#include "chrome/browser/prefs/proxy_config_dictionary.h"
+#include "chrome/browser/prefs/proxy_prefs.h"
+#include "chrome/common/pref_names.h"
+#include "policy/policy_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace policy {
+
+// Test cases for the proxy policy settings.
+class ProxyPolicyHandlerTest
+ : public ConfigurationPolicyPrefStoreTest {
+ protected:
+ // Verify that all the proxy prefs are set to the specified expected values.
+ void VerifyProxyPrefs(
+ const std::string& expected_proxy_server,
+ const std::string& expected_proxy_pac_url,
+ const std::string& expected_proxy_bypass_list,
+ const ProxyPrefs::ProxyMode& expected_proxy_mode) {
+ const base::Value* value = NULL;
+ ASSERT_TRUE(store_->GetValue(prefs::kProxy, &value));
+ ASSERT_EQ(base::Value::TYPE_DICTIONARY, value->GetType());
+ ProxyConfigDictionary dict(
+ static_cast<const base::DictionaryValue*>(value));
+ std::string s;
+ if (expected_proxy_server.empty()) {
+ EXPECT_FALSE(dict.GetProxyServer(&s));
+ } else {
+ ASSERT_TRUE(dict.GetProxyServer(&s));
+ EXPECT_EQ(expected_proxy_server, s);
+ }
+ if (expected_proxy_pac_url.empty()) {
+ EXPECT_FALSE(dict.GetPacUrl(&s));
+ } else {
+ ASSERT_TRUE(dict.GetPacUrl(&s));
+ EXPECT_EQ(expected_proxy_pac_url, s);
+ }
+ if (expected_proxy_bypass_list.empty()) {
+ EXPECT_FALSE(dict.GetBypassList(&s));
+ } else {
+ ASSERT_TRUE(dict.GetBypassList(&s));
+ EXPECT_EQ(expected_proxy_bypass_list, s);
+ }
+ ProxyPrefs::ProxyMode mode;
+ ASSERT_TRUE(dict.GetMode(&mode));
+ EXPECT_EQ(expected_proxy_mode, mode);
+ }
+};
+
+TEST_F(ProxyPolicyHandlerTest, ManualOptions) {
+ PolicyMap policy;
+ policy.Set(key::kProxyBypassList, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+ base::Value::CreateStringValue("http://chromium.org/override"),
+ NULL);
+ policy.Set(key::kProxyServer, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+ base::Value::CreateStringValue("chromium.org"), NULL);
+ policy.Set(
+ key::kProxyServerMode, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+ base::Value::CreateIntegerValue(
+ ProxyPolicyHandler::PROXY_MANUALLY_CONFIGURED_PROXY_SERVER_MODE),
+ NULL);
+ UpdateProviderPolicy(policy);
+
+ VerifyProxyPrefs("chromium.org",
+ std::string(),
+ "http://chromium.org/override",
+ ProxyPrefs::MODE_FIXED_SERVERS);
+}
+
+TEST_F(ProxyPolicyHandlerTest, ManualOptionsReversedApplyOrder) {
+ PolicyMap policy;
+ policy.Set(
+ key::kProxyServerMode, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+ base::Value::CreateIntegerValue(
+ ProxyPolicyHandler::PROXY_MANUALLY_CONFIGURED_PROXY_SERVER_MODE),
+ NULL);
+ policy.Set(key::kProxyBypassList, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+ base::Value::CreateStringValue("http://chromium.org/override"),
+ NULL);
+ policy.Set(key::kProxyServer, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+ base::Value::CreateStringValue("chromium.org"), NULL);
+ UpdateProviderPolicy(policy);
+
+ VerifyProxyPrefs("chromium.org",
+ std::string(),
+ "http://chromium.org/override",
+ ProxyPrefs::MODE_FIXED_SERVERS);
+}
+
+TEST_F(ProxyPolicyHandlerTest, ManualOptionsInvalid) {
+ PolicyMap policy;
+ policy.Set(
+ key::kProxyServerMode, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+ base::Value::CreateIntegerValue(
+ ProxyPolicyHandler::PROXY_MANUALLY_CONFIGURED_PROXY_SERVER_MODE),
+ NULL);
+ UpdateProviderPolicy(policy);
+
+ const base::Value* value = NULL;
+ EXPECT_FALSE(store_->GetValue(prefs::kProxy, &value));
+}
+
+TEST_F(ProxyPolicyHandlerTest, NoProxyServerMode) {
+ PolicyMap policy;
+ policy.Set(key::kProxyServerMode, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+ base::Value::CreateIntegerValue(
+ ProxyPolicyHandler::PROXY_SERVER_MODE),
+ NULL);
+ UpdateProviderPolicy(policy);
+ VerifyProxyPrefs(
+ std::string(), std::string(), std::string(), ProxyPrefs::MODE_DIRECT);
+}
+
+TEST_F(ProxyPolicyHandlerTest, NoProxyModeName) {
+ PolicyMap policy;
+ policy.Set(key::kProxyMode, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+ base::Value::CreateStringValue(ProxyPrefs::kDirectProxyModeName),
+ NULL);
+ UpdateProviderPolicy(policy);
+ VerifyProxyPrefs(
+ std::string(), std::string(), std::string(), ProxyPrefs::MODE_DIRECT);
+}
+
+TEST_F(ProxyPolicyHandlerTest, AutoDetectProxyServerMode) {
+ PolicyMap policy;
+ policy.Set(
+ key::kProxyServerMode, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+ base::Value::CreateIntegerValue(
+ ProxyPolicyHandler::PROXY_AUTO_DETECT_PROXY_SERVER_MODE),
+ NULL);
+ UpdateProviderPolicy(policy);
+ VerifyProxyPrefs(std::string(),
+ std::string(),
+ std::string(),
+ ProxyPrefs::MODE_AUTO_DETECT);
+}
+
+TEST_F(ProxyPolicyHandlerTest, AutoDetectProxyModeName) {
+ PolicyMap policy;
+ policy.Set(key::kProxyMode, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+ base::Value::CreateStringValue(
+ ProxyPrefs::kAutoDetectProxyModeName),
+ NULL);
+ UpdateProviderPolicy(policy);
+ VerifyProxyPrefs(std::string(),
+ std::string(),
+ std::string(),
+ ProxyPrefs::MODE_AUTO_DETECT);
+}
+
+TEST_F(ProxyPolicyHandlerTest, PacScriptProxyMode) {
+ PolicyMap policy;
+ policy.Set(key::kProxyPacUrl, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+ base::Value::CreateStringValue("http://short.org/proxy.pac"),
+ NULL);
+ policy.Set(key::kProxyMode, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+ base::Value::CreateStringValue(
+ ProxyPrefs::kPacScriptProxyModeName),
+ NULL);
+ UpdateProviderPolicy(policy);
+ VerifyProxyPrefs(std::string(),
+ "http://short.org/proxy.pac",
+ std::string(),
+ ProxyPrefs::MODE_PAC_SCRIPT);
+}
+
+TEST_F(ProxyPolicyHandlerTest, PacScriptProxyModeInvalid) {
+ PolicyMap policy;
+ policy.Set(key::kProxyMode, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+ base::Value::CreateStringValue(
+ ProxyPrefs::kPacScriptProxyModeName),
+ NULL);
+ UpdateProviderPolicy(policy);
+ const base::Value* value = NULL;
+ EXPECT_FALSE(store_->GetValue(prefs::kProxy, &value));
+}
+
+// Regression test for http://crbug.com/78016, CPanel returns empty strings
+// for unset properties.
+TEST_F(ProxyPolicyHandlerTest, PacScriptProxyModeBug78016) {
+ PolicyMap policy;
+ policy.Set(key::kProxyServer,
+ POLICY_LEVEL_MANDATORY,
+ POLICY_SCOPE_USER,
+ base::Value::CreateStringValue(std::string()),
+ NULL);
+ policy.Set(key::kProxyPacUrl,
+ POLICY_LEVEL_MANDATORY,
+ POLICY_SCOPE_USER,
+ base::Value::CreateStringValue("http://short.org/proxy.pac"),
+ NULL);
+ policy.Set(key::kProxyMode, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+ base::Value::CreateStringValue(
+ ProxyPrefs::kPacScriptProxyModeName),
+ NULL);
+ UpdateProviderPolicy(policy);
+ VerifyProxyPrefs(std::string(),
+ "http://short.org/proxy.pac",
+ std::string(),
+ ProxyPrefs::MODE_PAC_SCRIPT);
+}
+
+TEST_F(ProxyPolicyHandlerTest, UseSystemProxyServerMode) {
+ PolicyMap policy;
+ policy.Set(key::kProxyServerMode, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+ base::Value::CreateIntegerValue(
+ ProxyPolicyHandler::PROXY_USE_SYSTEM_PROXY_SERVER_MODE),
+ NULL);
+ UpdateProviderPolicy(policy);
+ VerifyProxyPrefs(
+ std::string(), std::string(), std::string(), ProxyPrefs::MODE_SYSTEM);
+}
+
+TEST_F(ProxyPolicyHandlerTest, UseSystemProxyMode) {
+ PolicyMap policy;
+ policy.Set(key::kProxyMode, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+ base::Value::CreateStringValue(ProxyPrefs::kSystemProxyModeName),
+ NULL);
+ UpdateProviderPolicy(policy);
+ VerifyProxyPrefs(
+ std::string(), std::string(), std::string(), ProxyPrefs::MODE_SYSTEM);
+}
+
+TEST_F(ProxyPolicyHandlerTest,
+ ProxyModeOverridesProxyServerMode) {
+ PolicyMap policy;
+ policy.Set(key::kProxyServerMode, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+ base::Value::CreateIntegerValue(
+ ProxyPolicyHandler::PROXY_SERVER_MODE),
+ NULL);
+ policy.Set(key::kProxyMode, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+ base::Value::CreateStringValue(
+ ProxyPrefs::kAutoDetectProxyModeName),
+ NULL);
+ UpdateProviderPolicy(policy);
+ VerifyProxyPrefs(std::string(),
+ std::string(),
+ std::string(),
+ ProxyPrefs::MODE_AUTO_DETECT);
+}
+
+TEST_F(ProxyPolicyHandlerTest, ProxyInvalid) {
+ // No mode expects all three parameters being set.
+ PolicyMap policy;
+ policy.Set(key::kProxyPacUrl, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+ base::Value::CreateStringValue("http://short.org/proxy.pac"),
+ NULL);
+ policy.Set(key::kProxyBypassList, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+ base::Value::CreateStringValue("http://chromium.org/override"),
+ NULL);
+ policy.Set(key::kProxyServer, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+ base::Value::CreateStringValue("chromium.org"), NULL);
+ for (int i = 0; i < ProxyPolicyHandler::MODE_COUNT; ++i) {
+ policy.Set(key::kProxyServerMode, POLICY_LEVEL_MANDATORY,
+ POLICY_SCOPE_USER, base::Value::CreateIntegerValue(i), NULL);
+ UpdateProviderPolicy(policy);
+ const base::Value* value = NULL;
+ EXPECT_FALSE(store_->GetValue(prefs::kProxy, &value));
+ }
+}
+
+} // namespace policy
diff --git a/chrome/browser/net/spdyproxy/OWNERS b/chrome/browser/net/spdyproxy/OWNERS
index 845f1d7b66..a46d1ea6da 100644
--- a/chrome/browser/net/spdyproxy/OWNERS
+++ b/chrome/browser/net/spdyproxy/OWNERS
@@ -1 +1,2 @@
bengr@chromium.org
+marq@chromium.org
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings.cc b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings.cc
new file mode 100644
index 0000000000..4318d77054
--- /dev/null
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings.cc
@@ -0,0 +1,464 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/net/spdyproxy/data_reduction_proxy_settings.h"
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/metrics/field_trial.h"
+#include "base/metrics/histogram.h"
+#include "base/prefs/pref_member.h"
+#include "base/prefs/pref_service.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/prefs/proxy_prefs.h"
+#include "chrome/browser/prefs/scoped_user_pref_update.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/pref_names.h"
+#include "net/base/host_port_pair.h"
+#include "net/base/load_flags.h"
+#include "net/base/net_errors.h"
+#include "net/url_request/url_fetcher.h"
+#include "net/url_request/url_fetcher_delegate.h"
+#include "net/url_request/url_request_status.h"
+#include "url/gurl.h"
+
+using base::FieldTrialList;
+using base::StringPrintf;
+
+namespace {
+
+// Key of the UMA DataReductionProxy.StartupState histogram.
+const char kUMAProxyStartupStateHistogram[] =
+ "DataReductionProxy.StartupState";
+// Values of the UMA DataReductionProxy.StartupState histogram.
+enum ProxyStartupState {
+ PROXY_NOT_AVAILABLE = 0,
+ PROXY_DISABLED,
+ PROXY_ENABLED,
+ PROXY_STARTUP_STATE_COUNT,
+};
+
+const char kEnabled[] = "Enabled";
+
+int64 GetInt64PrefValue(const ListValue& list_value, size_t index) {
+ int64 val = 0;
+ std::string pref_value;
+ bool rv = list_value.GetString(index, &pref_value);
+ DCHECK(rv);
+ if (rv) {
+ rv = base::StringToInt64(pref_value, &val);
+ DCHECK(rv);
+ }
+ return val;
+}
+
+} // namespace
+
+DataReductionProxySettings::DataReductionProxySettings()
+ : has_turned_on_(false),
+ has_turned_off_(false),
+ disabled_by_carrier_(false),
+ enabled_by_user_(false) {
+}
+
+DataReductionProxySettings::~DataReductionProxySettings() {
+ if (IsDataReductionProxyAllowed())
+ spdy_proxy_auth_enabled_.Destroy();
+}
+
+void DataReductionProxySettings::InitPrefMembers() {
+ spdy_proxy_auth_enabled_.Init(
+ prefs::kSpdyProxyAuthEnabled,
+ GetOriginalProfilePrefs(),
+ base::Bind(&DataReductionProxySettings::OnProxyEnabledPrefChange,
+ base::Unretained(this)));
+}
+
+void DataReductionProxySettings::InitDataReductionProxySettings() {
+ // Disable the proxy if it is not allowed to be used.
+ if (!IsDataReductionProxyAllowed())
+ return;
+
+ InitPrefMembers();
+
+ AddDefaultProxyBypassRules();
+ net::NetworkChangeNotifier::AddIPAddressObserver(this);
+
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+
+ // Setting the kEnableSpdyProxyAuth switch has the same effect as enabling
+ // the feature via settings, in that once set, the preference will be sticky
+ // across instances of Chrome. Disabling the feature can only be done through
+ // the settings menu.
+ RecordDataReductionInit();
+ if (spdy_proxy_auth_enabled_.GetValue() ||
+ command_line.HasSwitch(switches::kEnableSpdyProxyAuth)) {
+ MaybeActivateDataReductionProxy(true);
+ } else {
+ // This is logged so we can use this information in user feedback.
+ LogProxyState(false /* enabled */, true /* at startup */);
+ }
+}
+
+void DataReductionProxySettings::AddHostPatternToBypass(
+ const std::string& pattern) {
+ bypass_rules_.push_back(pattern);
+}
+
+void DataReductionProxySettings::AddURLPatternToBypass(
+ const std::string& pattern) {
+ size_t pos = pattern.find("/");
+ if (pattern.find("/", pos + 1) == pos + 1)
+ pos = pattern.find("/", pos + 2);
+
+ std::string host_pattern;
+ if (pos != std::string::npos)
+ host_pattern = pattern.substr(0, pos);
+ else
+ host_pattern = pattern;
+
+ AddHostPatternToBypass(host_pattern);
+}
+
+bool DataReductionProxySettings::IsDataReductionProxyAllowed() {
+ return IsProxyOriginSetOnCommandLine() ||
+ (FieldTrialList::FindFullName("DataCompressionProxyRollout") == kEnabled);
+}
+
+bool DataReductionProxySettings::IsDataReductionProxyPromoAllowed() {
+ return IsProxyOriginSetOnCommandLine() ||
+ (IsDataReductionProxyAllowed() &&
+ FieldTrialList::FindFullName("DataCompressionProxyPromoVisibility") ==
+ kEnabled);
+}
+
+std::string DataReductionProxySettings::GetDataReductionProxyOrigin() {
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ if (command_line.HasSwitch(switches::kSpdyProxyAuthOrigin))
+ return command_line.GetSwitchValueASCII(switches::kSpdyProxyAuthOrigin);
+#if defined(SPDY_PROXY_AUTH_ORIGIN)
+ return SPDY_PROXY_AUTH_ORIGIN;
+#else
+ return std::string();
+#endif
+}
+
+std::string DataReductionProxySettings::GetDataReductionProxyAuth() {
+ if (!IsDataReductionProxyAllowed())
+ return std::string();
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ if (command_line.HasSwitch(switches::kSpdyProxyAuthOrigin)) {
+ // If an origin is provided via a switch, then only consider the value
+ // that is provided by a switch. Do not use the preprocessor constant.
+ // Don't expose SPDY_PROXY_AUTH_VALUE to a proxy passed in via the command
+ // line.
+ if (command_line.HasSwitch(switches::kSpdyProxyAuthValue))
+ return command_line.GetSwitchValueASCII(switches::kSpdyProxyAuthValue);
+ return std::string();
+ }
+#if defined(SPDY_PROXY_AUTH_VALUE)
+ return SPDY_PROXY_AUTH_VALUE;
+#else
+ return std::string();
+#endif
+}
+
+bool DataReductionProxySettings::IsDataReductionProxyEnabled() {
+ return spdy_proxy_auth_enabled_.GetValue();
+}
+
+bool DataReductionProxySettings::IsDataReductionProxyManaged() {
+ return spdy_proxy_auth_enabled_.IsManaged();
+}
+
+void DataReductionProxySettings::SetDataReductionProxyEnabled(bool enabled) {
+ // Prevent configuring the proxy when it is not allowed to be used.
+ if (!IsDataReductionProxyAllowed())
+ return;
+
+ spdy_proxy_auth_enabled_.SetValue(enabled);
+ OnProxyEnabledPrefChange();
+}
+
+int64 DataReductionProxySettings::GetDataReductionLastUpdateTime() {
+ PrefService* local_state = GetLocalStatePrefs();
+ int64 last_update_internal =
+ local_state->GetInt64(prefs::kDailyHttpContentLengthLastUpdateDate);
+ base::Time last_update = base::Time::FromInternalValue(last_update_internal);
+ return static_cast<int64>(last_update.ToJsTime());
+}
+
+std::vector<long long>
+DataReductionProxySettings::GetDailyOriginalContentLengths() {
+ return GetDailyContentLengths(prefs::kDailyHttpOriginalContentLength);
+}
+
+std::vector<long long>
+DataReductionProxySettings::GetDailyReceivedContentLengths() {
+ return GetDailyContentLengths(prefs::kDailyHttpReceivedContentLength);
+}
+
+void DataReductionProxySettings::OnURLFetchComplete(
+ const net::URLFetcher* source) {
+ net::URLRequestStatus status = source->GetStatus();
+ if (status.status() == net::URLRequestStatus::FAILED &&
+ status.error() == net::ERR_INTERNET_DISCONNECTED) {
+ return;
+ }
+
+ std::string response;
+ source->GetResponseAsString(&response);
+
+ if ("OK" == response.substr(0, 2)) {
+ DVLOG(1) << "The data reduction proxy is not blocked.";
+
+ if (enabled_by_user_ && disabled_by_carrier_) {
+ // The user enabled the proxy, but sometime previously in the session,
+ // the network operator had blocked the proxy. Now that the network
+ // operator is unblocking it, configure it to the user's desires.
+ SetProxyConfigs(true, false);
+ }
+ disabled_by_carrier_ = false;
+ return;
+ }
+ DVLOG(1) << "The data reduction proxy is blocked.";
+
+ if (enabled_by_user_ && !disabled_by_carrier_) {
+ // Disable the proxy.
+ SetProxyConfigs(false, false);
+ }
+ disabled_by_carrier_ = true;
+}
+
+std::string DataReductionProxySettings::GetDataReductionProxyOriginHostPort() {
+ std::string spdy_proxy = GetDataReductionProxyOrigin();
+ if (spdy_proxy.empty()) {
+ DLOG(ERROR) << "A SPDY proxy has not been set.";
+ return spdy_proxy;
+ }
+ // Remove a trailing slash from the proxy string if one exists as well as
+ // leading HTTPS scheme.
+ return net::HostPortPair::FromURL(GURL(spdy_proxy)).ToString();
+}
+
+void DataReductionProxySettings::OnIPAddressChanged() {
+ if (enabled_by_user_) {
+ DCHECK(IsDataReductionProxyAllowed());
+ ProbeWhetherDataReductionProxyIsAvailable();
+ }
+}
+
+void DataReductionProxySettings::OnProxyEnabledPrefChange() {
+ if (!IsDataReductionProxyAllowed())
+ return;
+ MaybeActivateDataReductionProxy(false);
+}
+
+void DataReductionProxySettings::AddDefaultProxyBypassRules() {
+ // localhost
+ AddHostPatternToBypass("<local>");
+ // RFC1918 private addresses.
+ AddHostPatternToBypass("10.0.0.0/8");
+ AddHostPatternToBypass("172.16.0.0/12");
+ AddHostPatternToBypass("192.168.0.0/16");
+ // RFC4193 private addresses.
+ AddHostPatternToBypass("fc00::/7");
+}
+
+void DataReductionProxySettings::LogProxyState(bool enabled, bool at_startup) {
+ // This must stay a LOG(WARNING); the output is used in processing customer
+ // feedback.
+ const char kAtStartup[] = "at startup";
+ const char kByUser[] = "by user action";
+ const char kOn[] = "ON";
+ const char kOff[] = "OFF";
+
+ LOG(WARNING) << "SPDY proxy " << (enabled ? kOn : kOff)
+ << " " << (at_startup ? kAtStartup : kByUser);
+}
+
+PrefService* DataReductionProxySettings::GetOriginalProfilePrefs() {
+ return g_browser_process->profile_manager()->GetLastUsedProfile()->
+ GetOriginalProfile()->GetPrefs();
+}
+
+PrefService* DataReductionProxySettings::GetLocalStatePrefs() {
+ return g_browser_process->local_state();
+}
+
+bool DataReductionProxySettings::IsProxyOriginSetOnCommandLine() {
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ return command_line.HasSwitch(switches::kSpdyProxyAuthOrigin);
+}
+
+void DataReductionProxySettings::ResetDataReductionStatistics() {
+ PrefService* prefs = GetLocalStatePrefs();
+ if (!prefs)
+ return;
+ ListPrefUpdate original_update(prefs, prefs::kDailyHttpOriginalContentLength);
+ ListPrefUpdate received_update(prefs, prefs::kDailyHttpReceivedContentLength);
+ original_update->Clear();
+ received_update->Clear();
+ for (size_t i = 0; i < spdyproxy::kNumDaysInHistory; ++i) {
+ original_update->AppendString(base::Int64ToString(0));
+ received_update->AppendString(base::Int64ToString(0));
+ }
+}
+
+void DataReductionProxySettings::MaybeActivateDataReductionProxy(
+ bool at_startup) {
+ PrefService* prefs = GetOriginalProfilePrefs();
+
+ // TODO(marq): Consider moving this so stats are wiped the first time the
+ // proxy settings are actually (not maybe) turned on.
+ if (spdy_proxy_auth_enabled_.GetValue() &&
+ !prefs->GetBoolean(prefs::kSpdyProxyAuthWasEnabledBefore)) {
+ prefs->SetBoolean(prefs::kSpdyProxyAuthWasEnabledBefore, true);
+ ResetDataReductionStatistics();
+ }
+
+ std::string spdy_proxy_origin = GetDataReductionProxyOriginHostPort();
+
+ // Configure use of the data reduction proxy if it is enabled and the proxy
+ // origin is non-empty.
+ enabled_by_user_=
+ spdy_proxy_auth_enabled_.GetValue() && !spdy_proxy_origin.empty();
+ SetProxyConfigs(enabled_by_user_ && !disabled_by_carrier_, at_startup);
+
+ // Check if the proxy has been disabled explicitly by the carrier.
+ if (enabled_by_user_)
+ ProbeWhetherDataReductionProxyIsAvailable();
+}
+
+void DataReductionProxySettings::SetProxyConfigs(bool enabled,
+ bool at_startup) {
+ LogProxyState(enabled, at_startup);
+ PrefService* prefs = GetOriginalProfilePrefs();
+ DCHECK(prefs);
+ DictionaryPrefUpdate update(prefs, prefs::kProxy);
+ base::DictionaryValue* dict = update.Get();
+ if (enabled) {
+ std::string proxy_server_config =
+ "http=" + GetDataReductionProxyOrigin() + ",direct://;";
+ dict->SetString("server", proxy_server_config);
+ dict->SetString("mode",
+ ProxyModeToString(ProxyPrefs::MODE_FIXED_SERVERS));
+ dict->SetString("bypass_list", JoinString(bypass_rules_, ", "));
+ } else {
+ dict->SetString("mode", ProxyModeToString(ProxyPrefs::MODE_SYSTEM));
+ dict->SetString("server", "");
+ dict->SetString("bypass_list", "");
+ }
+}
+
+// Metrics methods
+void DataReductionProxySettings::RecordDataReductionInit() {
+ ProxyStartupState state = PROXY_NOT_AVAILABLE;
+ if (IsDataReductionProxyAllowed())
+ state = IsDataReductionProxyEnabled() ? PROXY_ENABLED : PROXY_DISABLED;
+ UMA_HISTOGRAM_ENUMERATION(kUMAProxyStartupStateHistogram,
+ state,
+ PROXY_STARTUP_STATE_COUNT);
+}
+
+DataReductionProxySettings::ContentLengthList
+DataReductionProxySettings::GetDailyContentLengths(const char* pref_name) {
+ DataReductionProxySettings::ContentLengthList content_lengths;
+ const ListValue* list_value = GetLocalStatePrefs()->GetList(pref_name);
+ if (list_value->GetSize() == spdyproxy::kNumDaysInHistory) {
+ for (size_t i = 0; i < spdyproxy::kNumDaysInHistory; ++i) {
+ content_lengths.push_back(GetInt64PrefValue(*list_value, i));
+ }
+ }
+ return content_lengths;
+ }
+
+void DataReductionProxySettings::GetContentLengths(
+ unsigned int days,
+ int64* original_content_length,
+ int64* received_content_length,
+ int64* last_update_time) {
+ DCHECK_LE(days, spdyproxy::kNumDaysInHistory);
+ PrefService* local_state = GetLocalStatePrefs();
+ if (!local_state) {
+ *original_content_length = 0L;
+ *received_content_length = 0L;
+ *last_update_time = 0L;
+ return;
+ }
+
+ const ListValue* original_list =
+ local_state->GetList(prefs::kDailyHttpOriginalContentLength);
+ const ListValue* received_list =
+ local_state->GetList(prefs::kDailyHttpReceivedContentLength);
+
+ if (original_list->GetSize() != spdyproxy::kNumDaysInHistory ||
+ received_list->GetSize() != spdyproxy::kNumDaysInHistory) {
+ *original_content_length = 0L;
+ *received_content_length = 0L;
+ *last_update_time = 0L;
+ return;
+ }
+
+ int64 orig = 0L;
+ int64 recv = 0L;
+ // Include days from the end of the list going backwards.
+ for (size_t i = spdyproxy::kNumDaysInHistory - days;
+ i < spdyproxy::kNumDaysInHistory; ++i) {
+ orig += GetInt64PrefValue(*original_list, i);
+ recv += GetInt64PrefValue(*received_list, i);
+ }
+ *original_content_length = orig;
+ *received_content_length = recv;
+ *last_update_time =
+ local_state->GetInt64(prefs::kDailyHttpContentLengthLastUpdateDate);
+}
+
+std::string DataReductionProxySettings::GetProxyCheckURL() {
+ if (!IsDataReductionProxyAllowed())
+ return std::string();
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ if (command_line.HasSwitch(switches::kDataReductionProxyProbeURL)) {
+ return command_line.GetSwitchValueASCII(
+ switches::kDataReductionProxyProbeURL);
+ }
+#if defined(DATA_REDUCTION_PROXY_PROBE_URL)
+ return DATA_REDUCTION_PROXY_PROBE_URL;
+#else
+ return std::string();
+#endif
+}
+
+net::URLFetcher* DataReductionProxySettings::GetURLFetcher() {
+ std::string url = GetProxyCheckURL();
+ if (url.empty())
+ return NULL;
+ net::URLFetcher* fetcher = net::URLFetcher::Create(GURL(url),
+ net::URLFetcher::GET,
+ this);
+ fetcher->SetLoadFlags(net::LOAD_DISABLE_CACHE);
+ fetcher->SetLoadFlags(net::LOAD_BYPASS_PROXY);
+ Profile* profile = g_browser_process->profile_manager()->
+ GetDefaultProfile();
+ fetcher->SetRequestContext(profile->GetRequestContext());
+ // Configure max retries to be at most kMaxRetries times for 5xx errors.
+ static const int kMaxRetries = 5;
+ fetcher->SetMaxRetriesOn5xx(kMaxRetries);
+ return fetcher;
+}
+
+void
+DataReductionProxySettings::ProbeWhetherDataReductionProxyIsAvailable() {
+ net::URLFetcher* fetcher = GetURLFetcher();
+ if (!fetcher)
+ return;
+ fetcher_.reset(fetcher);
+ fetcher_->Start();
+}
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings.h b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings.h
new file mode 100644
index 0000000000..f066d66171
--- /dev/null
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings.h
@@ -0,0 +1,207 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_NET_SPDYPROXY_DATA_REDUCTION_PROXY_SETTINGS_H_
+#define CHROME_BROWSER_NET_SPDYPROXY_DATA_REDUCTION_PROXY_SETTINGS_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/prefs/pref_member.h"
+#include "net/base/network_change_notifier.h"
+#include "net/url_request/url_fetcher_delegate.h"
+
+class PrefService;
+
+namespace net {
+class URLFetcher;
+}
+
+namespace spdyproxy {
+
+// The number of days of bandwidth usage statistics that are tracked.
+const unsigned int kNumDaysInHistory = 60;
+
+// The number of days of bandwidth usage statistics that are presented.
+const unsigned int kNumDaysInHistorySummary = 30;
+
+COMPILE_ASSERT(kNumDaysInHistorySummary <= kNumDaysInHistory,
+ DataReductionProxySettings_summary_too_long);
+
+} // namespace spdyproxy
+
+// Central point for configuring the data reduction proxy.
+// This object lives on the UI thread and all of its methods are expected to
+// be called from there.
+class DataReductionProxySettings
+ : public net::URLFetcherDelegate,
+ public net::NetworkChangeNotifier::IPAddressObserver {
+ public:
+ typedef std::vector<long long> ContentLengthList;
+
+ DataReductionProxySettings();
+ virtual ~DataReductionProxySettings();
+
+ void InitDataReductionProxySettings();
+
+ // Add a host pattern to bypass. This should follow the same syntax used
+ // in net::ProxyBypassRules; that is, a hostname pattern, a hostname suffix
+ // pattern, an IP literal, a CIDR block, or the magic string '<local>'.
+ // Bypass settings persist for the life of this object and are applied
+ // each time the proxy is enabled, but are not updated while it is enabled.
+ void AddHostPatternToBypass(const std::string& pattern);
+
+ // Add a URL pattern to bypass the proxy. The base implementation strips
+ // everything in |pattern| after the first single slash and then treats it
+ // as a hostname pattern. Subclasses may implement other semantics.
+ virtual void AddURLPatternToBypass(const std::string& pattern);
+
+ // Returns true if the data reduction proxy is allowed to be used on this
+ // instance of Chrome. This could return false, for example, if this instance
+ // is not part of the field trial, or if the proxy name is not configured
+ // via gyp.
+ bool IsDataReductionProxyAllowed();
+
+ // Returns true if a screen promoting the data reduction proxy is allowed to
+ // be shown. Logic that decides when to show the promo should check its
+ // availability. This would return false if not part of a separate field
+ // trial that governs the use of the promotion.
+ bool IsDataReductionProxyPromoAllowed();
+
+ // Returns the URL of the data reduction proxy.
+ std::string GetDataReductionProxyOrigin();
+
+ // Returns a configuration string for the proxy.
+ std::string GetDataReductionProxyAuth();
+
+ // Returns true if the proxy is enabled.
+ bool IsDataReductionProxyEnabled();
+
+ // Returns true if the proxy is managed by an adminstrator's policy.
+ bool IsDataReductionProxyManaged();
+
+ // Enables or disables the data reduction proxy. If a probe URL is available,
+ // and a probe request fails at some point, the proxy won't be used until a
+ // probe succeeds.
+ void SetDataReductionProxyEnabled(bool enabled);
+
+ // Returns the time in microseconds that the last update was made to the
+ // daily original and received content lengths.
+ int64 GetDataReductionLastUpdateTime();
+
+ // Returns a vector containing the total size of all HTTP content that was
+ // received over the last |kNumDaysInHistory| before any compression by the
+ // data reduction proxy. Each element in the vector contains one day of data.
+ ContentLengthList GetDailyOriginalContentLengths();
+
+ // Returns an vector containing the aggregate received HTTP content in the
+ // last |kNumDaysInHistory| days.
+ ContentLengthList GetDailyReceivedContentLengths();
+
+ // net::URLFetcherDelegate:
+ virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
+
+ protected:
+ void InitPrefMembers();
+ virtual net::URLFetcher* GetURLFetcher();
+
+ // Virtualized for unit test support.
+ virtual PrefService* GetOriginalProfilePrefs();
+ virtual PrefService* GetLocalStatePrefs();
+
+ std::string GetDataReductionProxyOriginHostPort();
+
+ bool IsProxyOriginSetOnCommandLine();
+ void GetContentLengths(unsigned int days,
+ int64* original_content_length,
+ int64* received_content_length,
+ int64* last_update_time);
+ ContentLengthList GetDailyContentLengths(const char* pref_name);
+
+ // Sets the proxy configs, enabling or disabling the proxy according to
+ // the value of |enabled|. |at_startup| is true when this method is called
+ // from InitDataReductionProxySettings.
+ virtual void SetProxyConfigs(bool enabled, bool at_startup);
+
+ // Metrics methods. Subclasses should override if they wish to provide
+ // alternate methods.
+ virtual void RecordDataReductionInit();
+
+ virtual void AddDefaultProxyBypassRules();
+
+ // Writes a warning to the log that is used in backend processing of
+ // customer feedback.
+ void LogProxyState(bool enabled, bool at_startup);
+
+ bool HasTurnedOn() { return has_turned_on_; }
+ bool HasTurnedOff() { return has_turned_off_; }
+ // Note that these flags may only be toggled to true, never back to false.
+ void SetHasTurnedOn() { has_turned_on_ = true; }
+ void SetHasTurnedOff() { has_turned_off_ = true; }
+
+ // Accessor for unit tests.
+ std::vector<std::string> BypassRules() { return bypass_rules_;}
+
+ private:
+ friend class DataReductionProxySettingsTestBase;
+ friend class DataReductionProxySettingsTest;
+ FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
+ TestResetDataReductionStatistics);
+ FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
+ TestIsProxyEnabledOrManaged);
+ FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
+ TestContentLengths);
+ FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
+ TestGetDailyContentLengths);
+ FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
+ TestMaybeActivateDataReductionProxy);
+ FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
+ TestOnIPAddressChanged);
+ FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
+ TestOnProxyEnabledPrefChange);
+ FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
+ TestInitDataReductionProxyOn);
+ FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
+ TestInitDataReductionProxyOff);
+ FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
+ TestBypassList);
+
+ // NetworkChangeNotifier::IPAddressObserver:
+ virtual void OnIPAddressChanged() OVERRIDE;
+
+ void OnProxyEnabledPrefChange();
+
+ void ResetDataReductionStatistics();
+
+ void MaybeActivateDataReductionProxy(bool at_startup);
+
+ // Requests the proxy probe URL, if one is set. If unable to do so, disables
+ // the proxy, if enabled. Otherwise enables the proxy if disabled by a probe
+ // failure.
+ void ProbeWhetherDataReductionProxyIsAvailable();
+ std::string GetProxyCheckURL();
+
+ std::vector<std::string> bypass_rules_;
+
+ // Indicate whether a user has turned on the data reduction proxy previously
+ // in this session.
+ bool has_turned_on_;
+
+ // Indicate whether a user has turned off the data reduction proxy previously
+ // in this session.
+ bool has_turned_off_;
+
+ bool disabled_by_carrier_;
+ bool enabled_by_user_;
+
+ scoped_ptr<net::URLFetcher> fetcher_;
+ BooleanPrefMember spdy_proxy_auth_enabled_;
+
+ DISALLOW_COPY_AND_ASSIGN(DataReductionProxySettings);
+};
+
+#endif // CHROME_BROWSER_NET_SPDYPROXY_DATA_REDUCTION_PROXY_SETTINGS_H_
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.cc b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.cc
index be70d9212f..2c23fbff12 100644
--- a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.cc
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.cc
@@ -41,7 +41,6 @@ using base::android::ScopedJavaLocalRef;
using base::FieldTrialList;
using base::StringPrintf;
-
namespace {
// The C++ definition of enum SpdyProxyAuthState defined in
@@ -56,205 +55,80 @@ enum {
NUM_SPDY_PROXY_AUTH_STATE
};
-const char kEnabled[] = "Enabled";
-
-bool IsProxyOriginSetOnCommandLine() {
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
- return command_line.HasSwitch(switches::kSpdyProxyAuthOrigin);
-}
-
-bool IsProxyAllowed() {
- return IsProxyOriginSetOnCommandLine() ||
- (FieldTrialList::FindFullName("DataCompressionProxyRollout") == kEnabled);
-}
-
-bool IsProxyPromoAllowed() {
- return IsProxyOriginSetOnCommandLine() ||
- (IsProxyAllowed() &&
- FieldTrialList::FindFullName("DataCompressionProxyPromoVisibility") ==
- kEnabled);
-}
-
-int64 GetInt64PrefValue(const ListValue& list_value, size_t index) {
- int64 val = 0;
- std::string pref_value;
- bool rv = list_value.GetString(index, &pref_value);
- DCHECK(rv);
- if (rv) {
- rv = base::StringToInt64(pref_value, &val);
- DCHECK(rv);
- }
- return val;
-}
-
-std::string GetProxyCheckURL(){
- if (!IsProxyAllowed())
- return std::string();
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
- if (command_line.HasSwitch(switches::kDataReductionProxyProbeURL)) {
- return command_line.GetSwitchValueASCII(switches::kSpdyProxyAuthOrigin);
- }
-#if defined(DATA_REDUCTION_PROXY_PROBE_URL)
- return DATA_REDUCTION_PROXY_PROBE_URL;
-#else
- return std::string();
-#endif
-}
-
-std::string GetDataReductionProxyOriginInternal() {
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
- if (command_line.HasSwitch(switches::kSpdyProxyAuthOrigin)) {
- return command_line.GetSwitchValueASCII(switches::kSpdyProxyAuthOrigin);
- }
-#if defined(SPDY_PROXY_AUTH_ORIGIN)
- return SPDY_PROXY_AUTH_ORIGIN;
-#else
- return std::string();
-#endif
-}
-
-std::string GetDataReductionProxyOriginHostPort() {
- std::string spdy_proxy = GetDataReductionProxyOriginInternal();
- if (spdy_proxy.empty()) {
- DLOG(ERROR) << "A SPDY proxy has not been set.";
- return spdy_proxy;
- }
- // Remove a trailing slash from the proxy string if one exists as well as
- // leading HTTPS scheme.
- return net::HostPortPair::FromURL(GURL(spdy_proxy)).ToString();
-}
-
} // namespace
-
DataReductionProxySettingsAndroid::DataReductionProxySettingsAndroid(
- JNIEnv* env, jobject obj)
- : has_turned_on_(false),
- has_turned_off_(false),
- disabled_by_carrier_(false),
- enabled_by_user_(false) {
+ JNIEnv* env, jobject obj): DataReductionProxySettings() {
}
-DataReductionProxySettingsAndroid::~DataReductionProxySettingsAndroid() {
- if (IsProxyAllowed())
- spdy_proxy_auth_enabled_.Destroy();
-}
-
-void DataReductionProxySettingsAndroid::InitPrefMembers() {
- spdy_proxy_auth_enabled_.Init(
- prefs::kSpdyProxyAuthEnabled,
- GetOriginalProfilePrefs(),
- base::Bind(&DataReductionProxySettingsAndroid::OnProxyEnabledPrefChange,
- base::Unretained(this)));
-}
+DataReductionProxySettingsAndroid::~DataReductionProxySettingsAndroid() {}
void DataReductionProxySettingsAndroid::InitDataReductionProxySettings(
JNIEnv* env,
jobject obj) {
- // Disable the proxy if it is not allowed to be used.
- if (!IsProxyAllowed())
- return;
-
- InitPrefMembers();
-
- AddDefaultProxyBypassRules();
- net::NetworkChangeNotifier::AddIPAddressObserver(this);
-
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
-
- // Setting the kEnableSpdyProxyAuth switch has the same effect as enabling
- // the feature via settings, in that once set, the preference will be sticky
- // across instances of Chrome. Disabling the feature can only be done through
- // the settings menu.
- UMA_HISTOGRAM_ENUMERATION("SpdyProxyAuth.State", CHROME_STARTUP,
- NUM_SPDY_PROXY_AUTH_STATE);
- if (spdy_proxy_auth_enabled_.GetValue() ||
- command_line.HasSwitch(switches::kEnableSpdyProxyAuth)) {
- MaybeActivateDataReductionProxy(true);
- } else {
- LOG(WARNING) << "SPDY proxy OFF at startup.";
- }
+ DataReductionProxySettings::InitDataReductionProxySettings();
}
void DataReductionProxySettingsAndroid::BypassHostPattern(
JNIEnv* env, jobject obj, jstring pattern) {
- AddHostPatternToBypass(ConvertJavaStringToUTF8(env, pattern));
+ DataReductionProxySettings::AddHostPatternToBypass(
+ ConvertJavaStringToUTF8(env, pattern));
}
void DataReductionProxySettingsAndroid::BypassURLPattern(
JNIEnv* env, jobject obj, jstring pattern) {
AddURLPatternToBypass(ConvertJavaStringToUTF8(env, pattern));
}
+void DataReductionProxySettingsAndroid::AddURLPatternToBypass(
+ const std::string& pattern) {
+ pac_bypass_rules_.push_back(
+ StringPrintf("shExpMatch(%s, '%s')", "url", pattern.c_str()));
+}
+
jboolean DataReductionProxySettingsAndroid::IsDataReductionProxyAllowed(
JNIEnv* env, jobject obj) {
- return IsProxyAllowed();
+ return DataReductionProxySettings::IsDataReductionProxyAllowed();
}
jboolean DataReductionProxySettingsAndroid::IsDataReductionProxyPromoAllowed(
JNIEnv* env, jobject obj) {
- return IsProxyPromoAllowed();
+ return DataReductionProxySettings::IsDataReductionProxyPromoAllowed();
}
ScopedJavaLocalRef<jstring>
DataReductionProxySettingsAndroid::GetDataReductionProxyOrigin(
JNIEnv* env, jobject obj) {
- return ConvertUTF8ToJavaString(env, GetDataReductionProxyOriginInternal());
+ return ConvertUTF8ToJavaString(
+ env, DataReductionProxySettings::GetDataReductionProxyOrigin());
}
ScopedJavaLocalRef<jstring>
DataReductionProxySettingsAndroid::GetDataReductionProxyAuth(
JNIEnv* env, jobject obj) {
- if (!IsProxyAllowed())
- return ConvertUTF8ToJavaString(env, std::string());
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
- if (command_line.HasSwitch(switches::kSpdyProxyAuthOrigin)) {
- // If an origin is provided via a switch, then only consider the value
- // that is provided by a switch. Do not use the preprocessor constant.
- // Don't expose SPDY_PROXY_AUTH_VALUE to a proxy passed in via the command
- // line.
- if (command_line.HasSwitch(switches::kSpdyProxyAuthValue)) {
- return ConvertUTF8ToJavaString(
- env,
- command_line.GetSwitchValueASCII(switches::kSpdyProxyAuthValue));
- }
- return ConvertUTF8ToJavaString(env, std::string());
- }
-#if defined(SPDY_PROXY_AUTH_VALUE)
- return ConvertUTF8ToJavaString(env, SPDY_PROXY_AUTH_VALUE);
-#else
- return ConvertUTF8ToJavaString(env, std::string());
-#endif
+ return ConvertUTF8ToJavaString(
+ env, DataReductionProxySettings::GetDataReductionProxyAuth());
}
jboolean DataReductionProxySettingsAndroid::IsDataReductionProxyEnabled(
JNIEnv* env, jobject obj) {
- return spdy_proxy_auth_enabled_.GetValue();
+ return DataReductionProxySettings::IsDataReductionProxyEnabled();
}
jboolean DataReductionProxySettingsAndroid::IsDataReductionProxyManaged(
JNIEnv* env, jobject obj) {
- return spdy_proxy_auth_enabled_.IsManaged();
+ return DataReductionProxySettings::IsDataReductionProxyManaged();
}
void DataReductionProxySettingsAndroid::SetDataReductionProxyEnabled(
JNIEnv* env,
jobject obj,
jboolean enabled) {
- // Prevent configuring the proxy when it is not allowed to be used.
- if (!IsProxyAllowed())
- return;
-
- spdy_proxy_auth_enabled_.SetValue(enabled);
- OnProxyEnabledPrefChange();
+ DataReductionProxySettings::SetDataReductionProxyEnabled(enabled);
}
jlong DataReductionProxySettingsAndroid::GetDataReductionLastUpdateTime(
JNIEnv* env, jobject obj) {
- PrefService* local_state = GetLocalStatePrefs();
- int64 last_update_internal =
- local_state->GetInt64(prefs::kDailyHttpContentLengthLastUpdateDate);
- base::Time last_update = base::Time::FromInternalValue(last_update_internal);
- return static_cast<int64>(last_update.ToJsTime());
+ return DataReductionProxySettings::GetDataReductionLastUpdateTime();
}
base::android::ScopedJavaLocalRef<jobject>
@@ -263,10 +137,11 @@ DataReductionProxySettingsAndroid::GetContentLengths(JNIEnv* env,
int64 original_content_length;
int64 received_content_length;
int64 last_update_internal;
- GetContentLengthsInternal(spdyproxy::kNumDaysInHistorySummary,
- &original_content_length,
- &received_content_length,
- &last_update_internal);
+ DataReductionProxySettings::GetContentLengths(
+ spdyproxy::kNumDaysInHistorySummary,
+ &original_content_length,
+ &received_content_length,
+ &last_update_internal);
return Java_ContentLengths_create(env,
original_content_length,
@@ -291,158 +166,37 @@ bool DataReductionProxySettingsAndroid::Register(JNIEnv* env) {
return register_natives_impl_result;
}
-void DataReductionProxySettingsAndroid::OnURLFetchComplete(
- const net::URLFetcher* source) {
- net::URLRequestStatus status = source->GetStatus();
- if (status.status() == net::URLRequestStatus::FAILED &&
- status.error() == net::ERR_INTERNET_DISCONNECTED) {
- return;
- }
-
- std::string response;
- source->GetResponseAsString(&response);
-
- if ("OK" == response.substr(0, 2)) {
- DVLOG(1) << "The data reduction proxy is not blocked.";
-
- if (enabled_by_user_ && disabled_by_carrier_) {
- // The user enabled the proxy, but sometime previously in the session,
- // the network operator had blocked the proxy. Now that the network
- // operator is unblocking it, configure it to the user's desires.
- SetProxyPac(true, false);
- }
- disabled_by_carrier_ = false;
- return;
- }
- DVLOG(1) << "The data reduction proxy is blocked.";
-
- if (enabled_by_user_ && !disabled_by_carrier_) {
- // Disable the proxy.
- SetProxyPac(false, false);
- }
- disabled_by_carrier_ = true;
-}
-
-void DataReductionProxySettingsAndroid::OnIPAddressChanged() {
- if (enabled_by_user_) {
- DCHECK(IsProxyAllowed());
- ProbeWhetherDataReductionProxyIsAvailable();
- }
-}
-
-void DataReductionProxySettingsAndroid::OnProxyEnabledPrefChange() {
- if (!IsProxyAllowed())
- return;
- MaybeActivateDataReductionProxy(false);
+// Metrics methods -- obsolete; see crbug/241518
+void DataReductionProxySettingsAndroid::RecordDataReductionInit() {
+ UMA_HISTOGRAM_ENUMERATION("SpdyProxyAuth.State", CHROME_STARTUP,
+ NUM_SPDY_PROXY_AUTH_STATE);
}
void DataReductionProxySettingsAndroid::AddDefaultProxyBypassRules() {
- // localhost
- AddHostToBypass("localhost");
- AddHostPatternToBypass("localhost.*");
- AddHostToBypass("127.0.0.1");
- AddHostToBypass("::1");
- // TODO(bengr): revisit 192.168.*, 10.*, 172.16.0.0 - 172.31.255.255. The
- // concern was that adding these and other rules would add to the processing
- // time.
+ DataReductionProxySettings::AddDefaultProxyBypassRules();
// TODO(bengr): See http://crbug.com/169959. For some reason the data
// reduction proxy is breaking the omnibox SearchProvider. Remove this rule
// when this is fixed.
AddURLPatternToBypass("http://www.google.com/complete/search*");
-
- // Check for proxy availability
- std::string proxy_check_url = GetProxyCheckURL();
- if (!proxy_check_url.empty()) {
- AddURLPatternToBypass(GetProxyCheckURL());
- }
-}
-
-void DataReductionProxySettingsAndroid::AddURLPatternToBypass(
- const std::string& pattern) {
- AddPatternToBypass("url", pattern);
-}
-
-void DataReductionProxySettingsAndroid::AddHostPatternToBypass(
- const std::string& pattern) {
- AddPatternToBypass("host", pattern);
-}
-
-void DataReductionProxySettingsAndroid::AddPatternToBypass(
- const std::string& url_or_host,
- const std::string& pattern) {
- bypass_rules_.push_back(
- StringPrintf("shExpMatch(%s, '%s')",
- url_or_host.c_str(), pattern.c_str()));
-}
-
-void DataReductionProxySettingsAndroid::AddHostToBypass(
- const std::string& host) {
- bypass_rules_.push_back(
- StringPrintf("host == '%s'", host.c_str()));
-}
-
-PrefService* DataReductionProxySettingsAndroid::GetOriginalProfilePrefs() {
- return g_browser_process->profile_manager()->GetDefaultProfile()->
- GetOriginalProfile()->GetPrefs();
-}
-
-PrefService* DataReductionProxySettingsAndroid::GetLocalStatePrefs() {
- return g_browser_process->local_state();
-}
-
-void DataReductionProxySettingsAndroid::ResetDataReductionStatistics() {
- PrefService* prefs = GetLocalStatePrefs();
- if (!prefs)
- return;
- ListPrefUpdate original_update(prefs, prefs::kDailyHttpOriginalContentLength);
- ListPrefUpdate received_update(prefs, prefs::kDailyHttpReceivedContentLength);
- original_update->Clear();
- received_update->Clear();
- for (size_t i = 0; i < spdyproxy::kNumDaysInHistory; ++i) {
- original_update->AppendString(base::Int64ToString(0));
- received_update->AppendString(base::Int64ToString(0));
- }
-}
-
-void DataReductionProxySettingsAndroid::MaybeActivateDataReductionProxy(
- bool at_startup) {
- PrefService* prefs = GetOriginalProfilePrefs();
-
- if (spdy_proxy_auth_enabled_.GetValue() &&
- !prefs->GetBoolean(prefs::kSpdyProxyAuthWasEnabledBefore)) {
- prefs->SetBoolean(prefs::kSpdyProxyAuthWasEnabledBefore, true);
- ResetDataReductionStatistics();
- }
-
- std::string spdy_proxy_origin = GetDataReductionProxyOriginHostPort();
-
- // Configure use of the data reduction proxy if it is enabled and the proxy
- // origin is non-empty.
- enabled_by_user_=
- spdy_proxy_auth_enabled_.GetValue() && !spdy_proxy_origin.empty();
- SetProxyPac(enabled_by_user_ && !disabled_by_carrier_, at_startup);
-
- // Check if the proxy has been disabled explicitly by the carrier.
- if (enabled_by_user_)
- ProbeWhetherDataReductionProxyIsAvailable();
}
-void DataReductionProxySettingsAndroid::SetProxyPac(bool enable_spdy_proxy,
- bool at_startup) {
- PrefService* prefs = GetOriginalProfilePrefs();
- DCHECK(prefs);
+void DataReductionProxySettingsAndroid::SetProxyConfigs(bool enabled,
+ bool at_startup) {
// Keys duplicated from proxy_config_dictionary.cc
// TODO(bengr): Move these to proxy_config_dictionary.h and reuse them here.
const char kProxyMode[] = "mode";
const char kProxyPacURL[] = "pac_url";
- const char kAtStartup[] = "at startup";
- const char kByUser[] = "by user action";
+ const char kProxyBypassList[] = "bypass_list";
+
+ LogProxyState(enabled, at_startup);
+ PrefService* prefs = GetOriginalProfilePrefs();
+ DCHECK(prefs);
DictionaryPrefUpdate update(prefs, prefs::kProxy);
- DictionaryValue* dict = update.Get();
- if (enable_spdy_proxy) {
- LOG(WARNING) << "SPDY proxy ON " << (at_startup ? kAtStartup : kByUser);
+ base::DictionaryValue* dict = update.Get();
+ // TODO(marq): All of the UMA in here are obsolete.
+ if (enabled) {
// Convert to a data URI and update the PAC settings.
std::string base64_pac;
base::Base64Encode(GetProxyPacScript(), &base64_pac);
@@ -452,135 +206,72 @@ void DataReductionProxySettingsAndroid::SetProxyPac(bool enable_spdy_proxy,
base64_pac);
dict->SetString(kProxyMode,
ProxyModeToString(ProxyPrefs::MODE_PAC_SCRIPT));
+ dict->SetString(kProxyBypassList, JoinString(BypassRules(), ", "));
if (at_startup) {
UMA_HISTOGRAM_ENUMERATION("SpdyProxyAuth.State",
SPDY_PROXY_AUTH_ON_AT_STARTUP,
NUM_SPDY_PROXY_AUTH_STATE);
- } else if (!has_turned_on_) {
+ } else if (!DataReductionProxySettings::HasTurnedOn()) {
// SPDY proxy auth is turned on by user action for the first time in
// this session.
UMA_HISTOGRAM_ENUMERATION("SpdyProxyAuth.State",
SPDY_PROXY_AUTH_ON_BY_USER,
NUM_SPDY_PROXY_AUTH_STATE);
- has_turned_on_ = true;
+ DataReductionProxySettings::SetHasTurnedOn();
}
} else {
- LOG(WARNING) << "SPDY proxy OFF " << (at_startup ? kAtStartup : kByUser);
dict->SetString(kProxyMode, ProxyModeToString(ProxyPrefs::MODE_SYSTEM));
dict->SetString(kProxyPacURL, "");
+ dict->SetString(kProxyBypassList, "");
- if (!at_startup && !has_turned_off_) {
+ if (!at_startup && !DataReductionProxySettings::HasTurnedOff()) {
UMA_HISTOGRAM_ENUMERATION("SpdyProxyAuth.State",
SPDY_PROXY_AUTH_OFF_BY_USER,
NUM_SPDY_PROXY_AUTH_STATE);
- has_turned_off_ = true;
+ DataReductionProxySettings::SetHasTurnedOff();
}
}
}
ScopedJavaLocalRef<jlongArray>
DataReductionProxySettingsAndroid::GetDailyContentLengths(
- JNIEnv* env, const char* pref_name) {
+ JNIEnv* env, const char* pref_name) {
jlongArray result = env->NewLongArray(spdyproxy::kNumDaysInHistory);
- PrefService* local_state = GetLocalStatePrefs();
- if (!local_state)
- return ScopedJavaLocalRef<jlongArray>(env, result);
-
- const ListValue* list_value = local_state->GetList(pref_name);
- if (list_value->GetSize() != spdyproxy::kNumDaysInHistory)
- return ScopedJavaLocalRef<jlongArray>(env, result);
-
- jlong jval[spdyproxy::kNumDaysInHistory];
- for (size_t i = 0; i < spdyproxy::kNumDaysInHistory; ++i) {
- jval[i] = GetInt64PrefValue(*list_value, i);
- }
- env->SetLongArrayRegion(result, 0, spdyproxy::kNumDaysInHistory, jval);
- return ScopedJavaLocalRef<jlongArray>(env, result);
-}
-void DataReductionProxySettingsAndroid::GetContentLengthsInternal(
- unsigned int days,
- int64* original_content_length,
- int64* received_content_length,
- int64* last_update_time) {
- DCHECK_LE(days, spdyproxy::kNumDaysInHistory);
- PrefService* local_state = GetLocalStatePrefs();
- if (!local_state) {
- *original_content_length = 0L;
- *received_content_length = 0L;
- *last_update_time = 0L;
- return;
- }
+ DataReductionProxySettings::ContentLengthList lengths =
+ DataReductionProxySettings::GetDailyContentLengths(pref_name);
- const ListValue* original_list =
- local_state->GetList(prefs::kDailyHttpOriginalContentLength);
- const ListValue* received_list =
- local_state->GetList(prefs::kDailyHttpReceivedContentLength);
-
- if (original_list->GetSize() != spdyproxy::kNumDaysInHistory ||
- received_list->GetSize() != spdyproxy::kNumDaysInHistory) {
- *original_content_length = 0L;
- *received_content_length = 0L;
- *last_update_time = 0L;
- return;
+ if (!lengths.empty()) {
+ DCHECK_EQ(lengths.size(), spdyproxy::kNumDaysInHistory);
+ env->SetLongArrayRegion(result, 0, lengths.size(), &lengths[0]);
+ return ScopedJavaLocalRef<jlongArray>(env, result);
}
- int64 orig = 0L;
- int64 recv = 0L;
- // Include days from the end of the list going backwards.
- for (size_t i = spdyproxy::kNumDaysInHistory - days;
- i < spdyproxy::kNumDaysInHistory; ++i) {
- orig += GetInt64PrefValue(*original_list, i);
- recv += GetInt64PrefValue(*received_list, i);
- }
- *original_content_length = orig;
- *received_content_length = recv;
- *last_update_time =
- local_state->GetInt64(prefs::kDailyHttpContentLengthLastUpdateDate);
-}
-
-net::URLFetcher* DataReductionProxySettingsAndroid::GetURLFetcher() {
- std::string url = GetProxyCheckURL();
- if (url.empty())
- return NULL;
- net::URLFetcher* fetcher = net::URLFetcher::Create(GURL(url),
- net::URLFetcher::GET,
- this);
- fetcher->SetLoadFlags(net::LOAD_DISABLE_CACHE);
- Profile* profile = g_browser_process->profile_manager()->
- GetDefaultProfile();
- fetcher->SetRequestContext(profile->GetRequestContext());
- // Configure max retries to be at most kMaxRetries times for 5xx errors.
- static const int kMaxRetries = 5;
- fetcher->SetMaxRetriesOn5xx(kMaxRetries);
- return fetcher;
-}
-
-void
-DataReductionProxySettingsAndroid::ProbeWhetherDataReductionProxyIsAvailable() {
- net::URLFetcher* fetcher = GetURLFetcher();
- if (!fetcher)
- return;
- fetcher_.reset(fetcher);
- fetcher_->Start();
+ return ScopedJavaLocalRef<jlongArray>(env, result);
}
// TODO(bengr): Replace with our own ProxyResolver.
std::string DataReductionProxySettingsAndroid::GetProxyPacScript() {
- std::string bypass_clause = "(" + JoinString(bypass_rules_, ") || (") + ")";
+ // Compose the PAC-only bypass code; these will be URL patterns that
+ // are matched by regular expression. Host bypasses are handled outside
+ // of the PAC file using the regular proxy bypass list configs.
+ std::string bypass_clause =
+ "(" + JoinString(pac_bypass_rules_, ") || (") + ")";
// Generate a proxy PAC that falls back to direct loading when the proxy is
// unavailable and only process HTTP traffic. (With a statically configured
// proxy, proxy failures will simply result in a connection error presented to
// users.)
+ std::string proxy_host =
+ DataReductionProxySettings::GetDataReductionProxyOriginHostPort();
std::string pac = "function FindProxyForURL(url, host) {"
" if (" + bypass_clause + ") {"
" return 'DIRECT';"
" } "
" if (url.substring(0, 5) == 'http:') {"
- " return 'HTTPS " + GetDataReductionProxyOriginHostPort() +
+ " return 'HTTPS " + proxy_host +
"; DIRECT';"
" }"
" return 'DIRECT';"
@@ -594,5 +285,3 @@ static jint Init(JNIEnv* env, jobject obj) {
new DataReductionProxySettingsAndroid(env, obj);
return reinterpret_cast<jint>(settings);
}
-
-
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.h b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.h
index 3e28e736e1..10a00202aa 100644
--- a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.h
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.h
@@ -13,185 +13,82 @@
#include "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/prefs/pref_member.h"
-#include "net/base/network_change_notifier.h"
-#include "net/url_request/url_fetcher_delegate.h"
+#include "chrome/browser/net/spdyproxy/data_reduction_proxy_settings.h"
-using base::android::ScopedJavaLocalRef;
-
-class PrefService;
-
-namespace net {
-class URLFetcher;
-}
-
-namespace spdyproxy {
-
-// The number of days of bandwidth usage statistics that are tracked.
-const unsigned int kNumDaysInHistory = 60;
-
-// The number of days of bandwidth usage statistics that are presented.
-const unsigned int kNumDaysInHistorySummary = 30;
-COMPILE_ASSERT(kNumDaysInHistorySummary <= kNumDaysInHistory,
- DataReductionProxySettings_summary_too_long);
+using base::android::ScopedJavaLocalRef;
-} // namespace spdyproxy
// Central point for configuring the data reduction proxy on Android.
// This object lives on the UI thread and all of its methods are expected to
// be called from there.
-class DataReductionProxySettingsAndroid
- : public net::URLFetcherDelegate,
- public net::NetworkChangeNotifier::IPAddressObserver {
+class DataReductionProxySettingsAndroid : public DataReductionProxySettings {
public:
DataReductionProxySettingsAndroid(JNIEnv* env, jobject obj);
virtual ~DataReductionProxySettingsAndroid();
void InitDataReductionProxySettings(JNIEnv* env, jobject obj);
- // Add a host or URL pattern to bypass the proxy, respectively. Wildcards
- // should be compatible with the JavaScript function shExpMatch, which can be
- // used in proxy PAC resolution. These function must only be called before the
- // proxy is used.
+
void BypassHostPattern(JNIEnv* env, jobject obj, jstring pattern);
+ // Add a URL pattern to bypass the proxy. Wildcards
+ // should be compatible with the JavaScript function shExpMatch, which can be
+ // used in proxy PAC resolution. These functions must only be called before
+ // the proxy is used.
void BypassURLPattern(JNIEnv* env, jobject obj, jstring pattern);
- // Returns true if the data reduction proxy is allowed to be used on this
- // instance of Chrome. This could return false, for example, if this instance
- // is not part of the field trial, or if the proxy name is not configured
- // via gyp.
- jboolean IsDataReductionProxyAllowed(JNIEnv* env, jobject obj);
+ virtual void AddURLPatternToBypass(const std::string& pattern) OVERRIDE;
- // Returns true if a screen promoting the data reduction proxy is allowed to
- // be shown. Logic that decides when to show the promo should check its
- // availability. This would return false if not part of a separate field
- // trial that governs the use of the promotion.
+ // JNI wrapper interfaces to the indentically-named superclass methods.
+ jboolean IsDataReductionProxyAllowed(JNIEnv* env, jobject obj);
jboolean IsDataReductionProxyPromoAllowed(JNIEnv* env, jobject obj);
-
- // Returns the origin of the data reduction proxy.
ScopedJavaLocalRef<jstring> GetDataReductionProxyOrigin(JNIEnv* env,
jobject obj);
-
- // Returns a configuration string for the proxy.
ScopedJavaLocalRef<jstring> GetDataReductionProxyAuth(JNIEnv* env,
jobject obj);
-
- // Returns true if the proxy is enabled.
jboolean IsDataReductionProxyEnabled(JNIEnv* env, jobject obj);
-
- // Returns true if the proxy is managed by an adminstrator's policy.
jboolean IsDataReductionProxyManaged(JNIEnv* env, jobject obj);
-
- // Enables or disables the data reduction proxy. If a probe URL is available,
- // and a probe request fails at some point, the proxy won't be used until a
- // probe succeeds.
void SetDataReductionProxyEnabled(JNIEnv* env, jobject obj, jboolean enabled);
- // Returns the time in microseconds that the last update was made to the
- // daily original and received content lengths.
jlong GetDataReductionLastUpdateTime(JNIEnv* env, jobject obj);
-
- // Return a Java |ContentLengths| object containing the total number of bytes
- // of all received content, before and after compression by the data
- // reduction proxy.
- base::android::ScopedJavaLocalRef<jobject> GetContentLengths(JNIEnv* env,
- jobject obj);
-
- // Returns an array containing the total size of all HTTP content that was
- // received over the last |kNumDaysInHistory| before any compression by the
- // data reduction proxy. Each element in the array contains one day of data.
ScopedJavaLocalRef<jlongArray> GetDailyOriginalContentLengths(JNIEnv* env,
jobject obj);
-
- // Returns an array containing the aggregate received HTTP content in the last
- // |kNumDaysInHistory| days.
ScopedJavaLocalRef<jlongArray> GetDailyReceivedContentLengths(JNIEnv* env,
jobject obj);
+ // Return a Java |ContentLengths| object wrapping the results of a call to
+ // DataReductionProxySettings::GetContentLengths.
+ base::android::ScopedJavaLocalRef<jobject> GetContentLengths(JNIEnv* env,
+ jobject obj);
+
// Registers the native methods to be call from Java.
static bool Register(JNIEnv* env);
- // net::URLFetcherDelegate:
- virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
-
protected:
- void InitPrefMembers();
- virtual net::URLFetcher* GetURLFetcher();
- virtual PrefService* GetOriginalProfilePrefs();
- virtual PrefService* GetLocalStatePrefs();
+ // DataReductionProxySettings overrides.
+ virtual void AddDefaultProxyBypassRules() OVERRIDE;
+
+ // Configures the proxy settings by generating a data URL containing a PAC
+ // file.
+ virtual void SetProxyConfigs(bool enabled, bool at_startup) OVERRIDE;
+
+ virtual void RecordDataReductionInit() OVERRIDE;
private:
friend class DataReductionProxySettingsAndroidTest;
FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsAndroidTest,
- TestBypassRules);
- FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsAndroidTest,
- TestResetDataReductionStatistics);
- FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsAndroidTest,
- TestIsProxyEnabledOrManaged);
+ TestBypassPACRules);
FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsAndroidTest,
TestSetProxyPac);
FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsAndroidTest,
TestGetDailyContentLengths);
- FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsAndroidTest,
- TestContentLengthsInternal);
- FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsAndroidTest,
- TestMaybeActivateDataReductionProxy);
- FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsAndroidTest,
- TestOnIPAddressChanged);
- FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsAndroidTest,
- TestOnProxyEnabledPrefChange);
- FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsAndroidTest,
- TestInitDataReductionProxyOn);
- FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsAndroidTest,
- TestInitDataReductionProxyOff);
- // NetworkChangeNotifier::IPAddressObserver:
- virtual void OnIPAddressChanged() OVERRIDE;
-
- void OnProxyEnabledPrefChange();
-
- void AddDefaultProxyBypassRules();
- void AddURLPatternToBypass(const std::string& pattern);
- void AddHostPatternToBypass(const std::string& pattern);
- void AddPatternToBypass(const std::string& url_or_host,
- const std::string& pattern);
- void AddHostToBypass(const std::string& host);
-
- void ResetDataReductionStatistics();
-
- void MaybeActivateDataReductionProxy(bool at_startup);
- void SetProxyPac(bool enable_spdy_proxy, bool at_startup);
-
ScopedJavaLocalRef<jlongArray> GetDailyContentLengths(JNIEnv* env,
const char* pref_name);
- void GetContentLengthsInternal(unsigned int days,
- int64* original_content_length,
- int64* received_content_length,
- int64* last_update_time);
-
- // Requests the proxy probe URL, if one is set. If unable to do so, disables
- // the proxy, if enabled. Otherwise enables the proxy if disabled by a probe
- // failure.
- void ProbeWhetherDataReductionProxyIsAvailable();
-
std::string GetProxyPacScript();
- std::vector<std::string> bypass_rules_;
-
- // Indicate whether a user has turned on the data reduction proxy previously
- // in this session.
- bool has_turned_on_;
-
- // Indicate whether a user has turned off the data reduction proxy previously
- // in this session.
- bool has_turned_off_;
-
- bool disabled_by_carrier_;
- bool enabled_by_user_;
-
- scoped_ptr<net::URLFetcher> fetcher_;
- BooleanPrefMember spdy_proxy_auth_enabled_;
+ std::vector<std::string> pac_bypass_rules_;
DISALLOW_COPY_AND_ASSIGN(DataReductionProxySettingsAndroid);
};
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_ios.cc b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_ios.cc
new file mode 100644
index 0000000000..6a0df92e7a
--- /dev/null
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_ios.cc
@@ -0,0 +1,9 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/net/spdyproxy/data_reduction_proxy_settings_ios.h"
+
+DataReductionProxySettingsIOS::DataReductionProxySettingsIOS()
+ : DataReductionProxySettings() {
+}
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_ios.h b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_ios.h
new file mode 100644
index 0000000000..be5bf42141
--- /dev/null
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_ios.h
@@ -0,0 +1,22 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_NET_SPDYPROXY_DATA_REDUCTION_PROXY_SETTINGS_IOS_H_
+#define CHROME_BROWSER_NET_SPDYPROXY_DATA_REDUCTION_PROXY_SETTINGS_IOS_H_
+
+#include "chrome/browser/net/spdyproxy/data_reduction_proxy_settings.h"
+
+// Central point for configuring the data reduction proxy on iOS.
+// This object lives on the UI thread and all of its methods are expected to
+// be called from there.
+class DataReductionProxySettingsIOS : DataReductionProxySettings {
+ public:
+ DataReductionProxySettingsIOS();
+ virtual ~DataReductionProxySettingsIOS() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DataReductionProxySettingsIOS);
+};
+
+#endif // CHROME_BROWSER_NET_SPDYPROXY_DATA_REDUCTION_PROXY_SETTINGS_IOS_H_
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_unittest.cc b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_unittest.cc
new file mode 100644
index 0000000000..5721de91f2
--- /dev/null
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_unittest.cc
@@ -0,0 +1,418 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/net/spdyproxy/data_reduction_proxy_settings_unittest.h"
+
+#include "base/command_line.h"
+#include "base/metrics/field_trial.h"
+#include "base/prefs/pref_registry_simple.h"
+#include "base/prefs/pref_service.h"
+#include "base/prefs/testing_pref_service.h"
+#include "base/strings/string_number_conversions.h"
+#include "chrome/browser/net/spdyproxy/data_reduction_proxy_settings.h"
+#include "chrome/browser/prefs/proxy_prefs.h"
+#include "chrome/browser/prefs/scoped_user_pref_update.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/metrics/variations/variations_util.h"
+#include "chrome/common/pref_names.h"
+#include "components/variations/entropy_provider.h"
+#include "net/url_request/test_url_fetcher_factory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+const char kDataReductionProxyOrigin[] = "https://foo:443/";
+const char kDataReductionProxyAuth[] = "12345";
+
+const char kProbeURLWithOKResponse[] = "http://ok.org/";
+const char kProbeURLWithBadResponse[] = "http://bad.org/";
+const char kProbeURLWithNoResponse[] = "http://no.org/";
+
+class TestDataReductionProxySettings
+ : public DataReductionProxySettings {
+ public:
+ TestDataReductionProxySettings(PrefService* profile_prefs,
+ PrefService* local_state_prefs)
+ : DataReductionProxySettings(),
+ success_(false),
+ fake_fetcher_request_count_(0),
+ profile_prefs_(profile_prefs),
+ local_state_prefs_(local_state_prefs) {
+ }
+
+ // DataReductionProxySettings implementation:
+ virtual net::URLFetcher* GetURLFetcher() OVERRIDE {
+ if (test_url_.empty())
+ return NULL;
+ net::URLFetcher* fetcher =
+ new net::FakeURLFetcher(GURL(test_url_), this, response_, success_);
+ fake_fetcher_request_count_++;
+ return fetcher;
+ }
+
+ virtual PrefService* GetOriginalProfilePrefs() OVERRIDE {
+ return profile_prefs_;
+ }
+
+ virtual PrefService* GetLocalStatePrefs() OVERRIDE {
+ return local_state_prefs_;
+ }
+
+ void set_probe_result(const std::string& test_url,
+ const std::string& response,
+ bool success) {
+ test_url_ = test_url;
+ response_ = response;
+ success_ = success;
+ }
+
+ const int fake_fetcher_request_count() {
+ return fake_fetcher_request_count_;
+ }
+
+ private:
+ std::string test_url_;
+ std::string response_;
+ bool success_;
+ int fake_fetcher_request_count_;
+ PrefService* profile_prefs_;
+ PrefService* local_state_prefs_;
+};
+
+DataReductionProxySettingsTestBase::DataReductionProxySettingsTestBase()
+ : testing::Test() {
+}
+
+DataReductionProxySettingsTestBase::~DataReductionProxySettingsTestBase() {}
+
+void DataReductionProxySettingsTestBase::AddProxyToCommandLine() {
+ CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ switches::kSpdyProxyAuthOrigin, kDataReductionProxyOrigin);
+ CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ switches::kSpdyProxyAuthValue, kDataReductionProxyAuth);
+}
+
+// testing::Test implementation:
+void DataReductionProxySettingsTestBase::SetUp() {
+ PrefRegistrySimple* registry = pref_service_.registry();
+ registry->RegisterListPref(prefs::kDailyHttpOriginalContentLength);
+ registry->RegisterListPref(prefs::kDailyHttpReceivedContentLength);
+ registry->RegisterInt64Pref(
+ prefs::kDailyHttpContentLengthLastUpdateDate, 0L);
+ registry->RegisterDictionaryPref(prefs::kProxy);
+ registry->RegisterBooleanPref(prefs::kSpdyProxyAuthEnabled, false);
+ registry->RegisterBooleanPref(prefs::kSpdyProxyAuthWasEnabledBefore, false);
+ ResetSettings();
+
+ ListPrefUpdate original_update(&pref_service_,
+ prefs::kDailyHttpOriginalContentLength);
+ ListPrefUpdate received_update(&pref_service_,
+ prefs::kDailyHttpReceivedContentLength);
+ for (int64 i = 0; i < spdyproxy::kNumDaysInHistory; i++) {
+ original_update->Insert(0, new StringValue(base::Int64ToString(2 * i)));
+ received_update->Insert(0, new StringValue(base::Int64ToString(i)));
+ }
+ last_update_time_ = base::Time::Now().LocalMidnight();
+ pref_service_.SetInt64(
+ prefs::kDailyHttpContentLengthLastUpdateDate,
+ last_update_time_.ToInternalValue());
+}
+
+void DataReductionProxySettingsTestBase::CheckProxyPref(
+ const std::string& expected_servers,
+ const std::string& expected_mode) {
+ const DictionaryValue* dict = pref_service_.GetDictionary(prefs::kProxy);
+ std::string mode;
+ std::string server;
+ dict->GetString("mode", &mode);
+ ASSERT_EQ(expected_mode, mode);
+ dict->GetString("server", &server);
+ ASSERT_EQ(expected_servers, server);
+}
+
+void DataReductionProxySettingsTestBase::CheckProxyConfigs(
+ bool expected_enabled) {
+ if (expected_enabled) {
+ std::string servers =
+ "http=" + Settings()->GetDataReductionProxyOrigin() + ",direct://;";
+ CheckProxyPref(servers,
+ ProxyModeToString(ProxyPrefs::MODE_FIXED_SERVERS));
+ } else {
+ CheckProxyPref(std::string(), ProxyModeToString(ProxyPrefs::MODE_SYSTEM));
+ }
+}
+
+void DataReductionProxySettingsTestBase::CheckProbe(bool initially_enabled,
+ const std::string& probe_url,
+ const std::string& response,
+ bool request_success,
+ bool expected_enabled) {
+ pref_service_.SetBoolean(prefs::kSpdyProxyAuthEnabled, initially_enabled);
+ SetProbeResult(probe_url, response, request_success);
+ Settings()->MaybeActivateDataReductionProxy(false);
+ base::MessageLoop::current()->RunUntilIdle();
+ CheckProxyConfigs(expected_enabled);
+}
+
+void DataReductionProxySettingsTestBase::CheckProbeOnIPChange(
+ const std::string& probe_url,
+ const std::string& response,
+ bool request_success,
+ bool expected_enabled) {
+ SetProbeResult(probe_url, response, request_success);
+ Settings()->OnIPAddressChanged();
+ base::MessageLoop::current()->RunUntilIdle();
+ CheckProxyConfigs(expected_enabled);
+}
+
+void DataReductionProxySettingsTestBase::CheckOnPrefChange(
+ bool enabled,
+ const std::string& probe_url,
+ const std::string& response,
+ bool request_success,
+ bool expected_enabled) {
+ SetProbeResult(probe_url, response, request_success);
+ pref_service_.SetBoolean(prefs::kSpdyProxyAuthEnabled, enabled);
+ base::MessageLoop::current()->RunUntilIdle();
+ CheckProxyConfigs(expected_enabled);
+}
+
+void DataReductionProxySettingsTestBase::CheckInitDataReductionProxy(
+ bool enabled_at_startup) {
+ AddProxyToCommandLine();
+ base::MessageLoop loop(base::MessageLoop::TYPE_UI);
+ pref_service_.SetBoolean(prefs::kSpdyProxyAuthEnabled, enabled_at_startup);
+ SetProbeResult(kProbeURLWithOKResponse, "OK", true);
+ Settings()->InitDataReductionProxySettings();
+ base::MessageLoop::current()->RunUntilIdle();
+ if (enabled_at_startup) {
+ CheckProxyConfigs(enabled_at_startup);
+ } else {
+ // This presumes the proxy preference hadn't been set up by Chrome.
+ CheckProxyPref(std::string(), std::string());
+ }
+}
+
+class DataReductionProxySettingsTest:
+ public DataReductionProxySettingsTestBase {
+ public:
+ virtual void ResetSettings() OVERRIDE {
+ settings_.reset(new TestDataReductionProxySettings(&pref_service_,
+ &pref_service_));
+ }
+
+ virtual TestDataReductionProxySettings* Settings() OVERRIDE {
+ return settings_.get();
+ }
+
+ virtual void SetProbeResult(const std::string& test_url,
+ const std::string& response,
+ bool success) OVERRIDE {
+ settings_->set_probe_result(test_url, response, success);
+ }
+
+ scoped_ptr<TestDataReductionProxySettings> settings_;
+};
+
+TEST_F(DataReductionProxySettingsTest, TestGetDataReductionProxyOrigin) {
+ AddProxyToCommandLine();
+ // SetUp() adds the origin to the command line, which should be returned here.
+ std::string result = settings_->GetDataReductionProxyOrigin();
+ EXPECT_EQ(kDataReductionProxyOrigin, result);
+}
+
+TEST_F(DataReductionProxySettingsTest, TestGetDataReductionProxyAuth) {
+ AddProxyToCommandLine();
+ // SetUp() adds the auth string to the command line, which should be returned
+ // here.
+ std::string result = settings_->GetDataReductionProxyAuth();
+ EXPECT_EQ(kDataReductionProxyAuth, result);
+}
+
+// Test that the auth value set by preprocessor directive is not returned
+// when an origin is set via a switch. This test only does anything useful in
+// Chrome builds.
+TEST_F(DataReductionProxySettingsTest,
+ TestGetDataReductionProxyAuthWithOriginSetViaSwitch) {
+ CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ switches::kSpdyProxyAuthOrigin, kDataReductionProxyOrigin);
+ std::string result = settings_->GetDataReductionProxyAuth();
+ EXPECT_EQ("", result);
+}
+
+TEST_F(DataReductionProxySettingsTest, TestIsProxyEnabledOrManaged) {
+ settings_->InitPrefMembers();
+ EXPECT_FALSE(settings_->IsDataReductionProxyEnabled());
+ EXPECT_FALSE(settings_->IsDataReductionProxyManaged());
+
+ pref_service_.SetBoolean(prefs::kSpdyProxyAuthEnabled, true);
+ EXPECT_TRUE(settings_->IsDataReductionProxyEnabled());
+ EXPECT_FALSE(settings_->IsDataReductionProxyManaged());
+
+ pref_service_.SetManagedPref(prefs::kSpdyProxyAuthEnabled,
+ base::Value::CreateBooleanValue(true));
+ EXPECT_TRUE(settings_->IsDataReductionProxyEnabled());
+ EXPECT_TRUE(settings_->IsDataReductionProxyManaged());
+}
+
+TEST_F(DataReductionProxySettingsTest, TestResetDataReductionStatistics) {
+ int64 original_content_length;
+ int64 received_content_length;
+ int64 last_update_time;
+ settings_->ResetDataReductionStatistics();
+ settings_->GetContentLengths(spdyproxy::kNumDaysInHistory,
+ &original_content_length,
+ &received_content_length,
+ &last_update_time);
+ EXPECT_EQ(0L, original_content_length);
+ EXPECT_EQ(0L, received_content_length);
+ EXPECT_EQ(last_update_time_.ToInternalValue(), last_update_time);
+}
+
+TEST_F(DataReductionProxySettingsTest, TestContentLengths) {
+ int64 original_content_length;
+ int64 received_content_length;
+ int64 last_update_time;
+
+ // Request |kNumDaysInHistory| days.
+ settings_->GetContentLengths(spdyproxy::kNumDaysInHistory,
+ &original_content_length,
+ &received_content_length,
+ &last_update_time);
+ const unsigned int days = spdyproxy::kNumDaysInHistory;
+ // Received content length history values are 0 to |kNumDaysInHistory - 1|.
+ int64 expected_total_received_content_length = (days - 1L) * days / 2;
+ // Original content length history values are 0 to
+ // |2 * (kNumDaysInHistory - 1)|.
+ long expected_total_original_content_length = (days - 1L) * days;
+ EXPECT_EQ(expected_total_original_content_length, original_content_length);
+ EXPECT_EQ(expected_total_received_content_length, received_content_length);
+ EXPECT_EQ(last_update_time_.ToInternalValue(), last_update_time);
+
+ // Request |kNumDaysInHistory - 1| days.
+ settings_->GetContentLengths(spdyproxy::kNumDaysInHistory - 1,
+ &original_content_length,
+ &received_content_length,
+ &last_update_time);
+ expected_total_received_content_length -= (days - 1);
+ expected_total_original_content_length -= 2 * (days - 1);
+ EXPECT_EQ(expected_total_original_content_length, original_content_length);
+ EXPECT_EQ(expected_total_received_content_length, received_content_length);
+
+ // Request 0 days.
+ settings_->GetContentLengths(0,
+ &original_content_length,
+ &received_content_length,
+ &last_update_time);
+ expected_total_received_content_length = 0;
+ expected_total_original_content_length = 0;
+ EXPECT_EQ(expected_total_original_content_length, original_content_length);
+ EXPECT_EQ(expected_total_received_content_length, received_content_length);
+
+ // Request 1 day. First day had 0 bytes so should be same as 0 days.
+ settings_->GetContentLengths(1,
+ &original_content_length,
+ &received_content_length,
+ &last_update_time);
+ EXPECT_EQ(expected_total_original_content_length, original_content_length);
+ EXPECT_EQ(expected_total_received_content_length, received_content_length);
+}
+
+TEST_F(DataReductionProxySettingsTest, TestMaybeActivateDataReductionProxy) {
+ AddProxyToCommandLine();
+ settings_->InitPrefMembers();
+ // TODO(bengr): Test enabling/disabling while a probe is outstanding.
+ base::MessageLoop loop(base::MessageLoop::TYPE_UI);
+ // The proxy is enabled initially.
+ // Request succeeded but with bad response, expect proxy to be disabled.
+ CheckProbe(true, kProbeURLWithBadResponse, "Bad", true, false);
+ // Request succeeded with valid response, expect proxy to be enabled.
+ CheckProbe(true, kProbeURLWithOKResponse, "OK", true, true);
+ // Request failed, expect proxy to be disabled.
+ CheckProbe(true, kProbeURLWithNoResponse, "", false, false);
+
+ // The proxy is disabled initially. Probes should not be emitted to change
+ // state.
+ EXPECT_EQ(3, settings_->fake_fetcher_request_count());
+ CheckProbe(false, kProbeURLWithOKResponse, "OK", true, false);
+ EXPECT_EQ(3, settings_->fake_fetcher_request_count());
+}
+
+TEST_F(DataReductionProxySettingsTest, TestOnIPAddressChanged) {
+ AddProxyToCommandLine();
+ base::MessageLoop loop(base::MessageLoop::TYPE_UI);
+ // The proxy is enabled initially.
+ settings_->enabled_by_user_ = true;
+ settings_->SetProxyConfigs(true, true);
+ // IP address change triggers a probe that succeeds. Proxy remains enabled.
+ CheckProbeOnIPChange(kProbeURLWithOKResponse, "OK", true, true);
+ // IP address change triggers a probe that fails. Proxy is disabled.
+ CheckProbeOnIPChange(kProbeURLWithBadResponse, "Bad", true, false);
+ // IP address change triggers a probe that fails. Proxy remains disabled.
+ CheckProbeOnIPChange(kProbeURLWithBadResponse, "Bad", true, false);
+ // IP address change triggers a probe that succeed. Proxy is enabled.
+ CheckProbeOnIPChange(kProbeURLWithBadResponse, "OK", true, true);
+ EXPECT_EQ(4, settings_->fake_fetcher_request_count());
+}
+
+TEST_F(DataReductionProxySettingsTest, TestOnProxyEnabledPrefChange) {
+ AddProxyToCommandLine();
+ settings_->InitPrefMembers();
+ base::MessageLoop loop(base::MessageLoop::TYPE_UI);
+ // The proxy is enabled initially.
+ settings_->enabled_by_user_ = true;
+ settings_->SetProxyConfigs(true, true);
+ // The pref is disabled, so correspondingly should be the proxy.
+ CheckOnPrefChange(false, kProbeURLWithOKResponse, "OK", true, false);
+ // The pref is enabled, so correspondingly should be the proxy.
+ CheckOnPrefChange(true, kProbeURLWithOKResponse, "OK", true, true);
+ EXPECT_EQ(1, settings_->fake_fetcher_request_count());
+}
+
+TEST_F(DataReductionProxySettingsTest, TestInitDataReductionProxyOn) {
+ CheckInitDataReductionProxy(true);
+}
+
+TEST_F(DataReductionProxySettingsTest, TestInitDataReductionProxyOff) {
+ CheckInitDataReductionProxy(false);
+}
+
+TEST_F(DataReductionProxySettingsTest, TestGetDailyContentLengths) {
+ DataReductionProxySettings::ContentLengthList result =
+ settings_->GetDailyContentLengths(prefs::kDailyHttpOriginalContentLength);
+
+ ASSERT_FALSE(result.empty());
+ ASSERT_EQ(spdyproxy::kNumDaysInHistory, result.size());
+
+ for (size_t i = 0; i < spdyproxy::kNumDaysInHistory; ++i) {
+ long expected_length =
+ static_cast<long>((spdyproxy::kNumDaysInHistory - 1 - i) * 2);
+ ASSERT_EQ(expected_length, result[i]);
+ }
+}
+
+TEST_F(DataReductionProxySettingsTest, TestBypassList) {
+ settings_->AddHostPatternToBypass("http://www.google.com");
+ settings_->AddHostPatternToBypass("fefe:13::abc/33");
+ settings_->AddURLPatternToBypass("foo.org/images/*");
+ settings_->AddURLPatternToBypass("http://foo.com/*");
+ settings_->AddURLPatternToBypass("http://baz.com:22/bar/*");
+ settings_->AddURLPatternToBypass("http://*bat.com/bar/*");
+
+ std::string expected[] = {
+ "http://www.google.com",
+ "fefe:13::abc/33",
+ "foo.org",
+ "http://foo.com",
+ "http://baz.com:22",
+ "http://*bat.com"
+ };
+
+ ASSERT_EQ(settings_->bypass_rules_.size(), 6u);
+ int i = 0;
+ for (std::vector<std::string>::iterator it = settings_->bypass_rules_.begin();
+ it != settings_->bypass_rules_.end(); ++it) {
+ EXPECT_EQ(expected[i++], *it);
+ }
+}
+
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_unittest.h b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_unittest.h
new file mode 100644
index 0000000000..ea3e085169
--- /dev/null
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_unittest.h
@@ -0,0 +1,55 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_NET_SPDYPROXY_DATA_REDUCTION_PROXY_SETTINGS_UNITTEST_H_
+#define CHROME_BROWSER_NET_SPDYPROXY_DATA_REDUCTION_PROXY_SETTINGS_UNITTEST_H_
+
+
+#include "base/metrics/field_trial.h"
+#include "base/prefs/testing_pref_service.h"
+#include "chrome/browser/net/spdyproxy/data_reduction_proxy_settings.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class PrefService;
+class TestingPrefServiceSimple;
+
+class DataReductionProxySettingsTestBase : public testing::Test {
+ public:
+ DataReductionProxySettingsTestBase();
+ virtual ~DataReductionProxySettingsTestBase();
+
+ void AddProxyToCommandLine();
+ virtual void ResetSettings() = 0;
+ virtual DataReductionProxySettings* Settings() = 0;
+ virtual void SetProbeResult(const std::string& test_url,
+ const std::string& response,
+ bool success) = 0;
+
+ virtual void SetUp() OVERRIDE;
+ void CheckProxyPref(const std::string& expected_servers,
+ const std::string& expected_mode);
+ void CheckProxyConfigs(bool expected_enabled);
+ void CheckProbe(bool initially_enabled,
+ const std::string& probe_url,
+ const std::string& response,
+ bool request_success,
+ bool expected_enabled);
+ void CheckProbeOnIPChange(const std::string& probe_url,
+ const std::string& response,
+ bool request_success,
+ bool expected_enabled);
+ void CheckOnPrefChange(bool enabled,
+ const std::string& probe_url,
+ const std::string& response,
+ bool request_success,
+ bool expected_enabled);
+ void CheckInitDataReductionProxy(bool enabled_at_startup);
+
+ TestingPrefServiceSimple pref_service_;
+ base::Time last_update_time_;
+ // This is a singleton that will clear all set field trials on destruction.
+ scoped_ptr<base::FieldTrialList> field_trial_list_;
+};
+
+#endif // CHROME_BROWSER_NET_SPDYPROXY_DATA_REDUCTION_PROXY_SETTINGS_UNITTEST_H_
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_unittest_android.cc b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_unittest_android.cc
index d76bd172b9..98a4275ccf 100644
--- a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_unittest_android.cc
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_unittest_android.cc
@@ -2,13 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "chrome/browser/net/spdyproxy/data_reduction_proxy_settings_unittest.h"
+
+
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
#include "base/base64.h"
#include "base/command_line.h"
#include "base/metrics/field_trial.h"
-#include "base/prefs/pref_registry_simple.h"
#include "base/prefs/pref_service.h"
#include "base/prefs/testing_pref_service.h"
#include "base/strings/string_number_conversions.h"
@@ -24,32 +26,28 @@
#include "url/gurl.h"
const char kDataReductionProxyOrigin[] = "https://foo:443/";
-const char kDataReductionProxyOriginHostPort[] = "foo:443";
const char kDataReductionProxyAuth[] = "12345";
-const char kProbeURLWithOKResponse[] = "http://ok.org/";
-const char kProbeURLWithBadResponse[] = "http://bad.org/";
-const char kProbeURLWithNoResponse[] = "http://no.org/";
-
class TestDataReductionProxySettingsAndroid
: public DataReductionProxySettingsAndroid {
public:
- TestDataReductionProxySettingsAndroid(JNIEnv* env, jobject obj,
+ TestDataReductionProxySettingsAndroid(JNIEnv* env,
+ jobject obj,
PrefService* profile_prefs,
PrefService* local_state_prefs)
- : DataReductionProxySettingsAndroid(env, obj),
- success_(false),
- fake_fetcher_request_count_(0),
- profile_prefs_(profile_prefs),
- local_state_prefs_(local_state_prefs) {
+ : DataReductionProxySettingsAndroid(env, obj),
+ success_(false),
+ fake_fetcher_request_count_(0),
+ profile_prefs_(profile_prefs),
+ local_state_prefs_(local_state_prefs) {
}
- // DataReductionProxySettingsAndroid implementation:
+ // DataReductionProxySettings implementation:
virtual net::URLFetcher* GetURLFetcher() OVERRIDE {
if (test_url_.empty())
return NULL;
- net::URLFetcher* fetcher = new net::FakeURLFetcher(GURL(test_url_), this,
- response_, success_);
+ net::URLFetcher* fetcher =
+ new net::FakeURLFetcher(GURL(test_url_), this, response_, success_);
fake_fetcher_request_count_++;
return fetcher;
}
@@ -82,46 +80,34 @@ class TestDataReductionProxySettingsAndroid
PrefService* local_state_prefs_;
};
-class DataReductionProxySettingsAndroidTest : public testing::Test {
- protected:
- void AddProxyToCommandLine() {
- CommandLine::ForCurrentProcess()->AppendSwitchASCII(
- switches::kSpdyProxyAuthOrigin, kDataReductionProxyOrigin);
- CommandLine::ForCurrentProcess()->AppendSwitchASCII(
- switches::kSpdyProxyAuthValue, kDataReductionProxyAuth);
+class DataReductionProxySettingsAndroidTest
+ : public DataReductionProxySettingsTestBase {
+ public:
+ virtual void ResetSettings() OVERRIDE{
+ settings_.reset(new TestDataReductionProxySettingsAndroid(NULL, NULL,
+ &pref_service_,
+ &pref_service_));
}
- // testing::Test implementation:
+ virtual TestDataReductionProxySettingsAndroid* Settings() OVERRIDE {
+ return settings_.get();
+ }
+
+ virtual void SetProbeResult(const std::string& test_url,
+ const std::string& response,
+ bool success) OVERRIDE {
+ settings_->set_probe_result(test_url, response, success);
+ }
+
+ // DataReductionProxySettingsTest implementation:
virtual void SetUp() OVERRIDE {
env_ = base::android::AttachCurrentThread();
DataReductionProxySettingsAndroid::Register(env_);
- PrefRegistrySimple* registry = pref_service_.registry();
- registry->RegisterListPref(prefs::kDailyHttpOriginalContentLength);
- registry->RegisterListPref(prefs::kDailyHttpReceivedContentLength);
- registry->RegisterInt64Pref(
- prefs::kDailyHttpContentLengthLastUpdateDate, 0L);
- registry->RegisterDictionaryPref(prefs::kProxy);
- registry->RegisterBooleanPref(prefs::kSpdyProxyAuthEnabled, false);
- registry->RegisterBooleanPref(prefs::kSpdyProxyAuthWasEnabledBefore, false);
- settings_.reset(new TestDataReductionProxySettingsAndroid(NULL, NULL,
- &pref_service_,
- &pref_service_));
- ListPrefUpdate original_update(&pref_service_,
- prefs::kDailyHttpOriginalContentLength);
- ListPrefUpdate received_update(&pref_service_,
- prefs::kDailyHttpReceivedContentLength);
- for (int64 i = 0; i < spdyproxy::kNumDaysInHistory; i++) {
- original_update->Insert(0, new StringValue(base::Int64ToString(2 * i)));
- received_update->Insert(0, new StringValue(base::Int64ToString(i)));
- }
- last_update_time_ = base::Time::Now().LocalMidnight();
- pref_service_.SetInt64(
- prefs::kDailyHttpContentLengthLastUpdateDate,
- last_update_time_.ToInternalValue());
+ DataReductionProxySettingsTestBase::SetUp();
}
- void CheckProxyPref(const std::string& expected_pac_url,
- const std::string& expected_mode) {
+ void CheckProxyPacPref(const std::string& expected_pac_url,
+ const std::string& expected_mode) {
const DictionaryValue* dict = pref_service_.GetDictionary(prefs::kProxy);
std::string mode;
std::string pac_url;
@@ -131,68 +117,7 @@ class DataReductionProxySettingsAndroidTest : public testing::Test {
ASSERT_EQ(expected_pac_url, pac_url);
}
- void CheckProxyPac(bool expected_enabled) {
- if (expected_enabled) {
- std::string pac;
- base::Base64Encode(settings_->GetProxyPacScript(), &pac);
- std::string expected_pac_url =
- "data:application/x-ns-proxy-autoconfig;base64," + pac;
- CheckProxyPref(expected_pac_url,
- ProxyModeToString(ProxyPrefs::MODE_PAC_SCRIPT));
- } else {
- CheckProxyPref(std::string(), ProxyModeToString(ProxyPrefs::MODE_SYSTEM));
- }
- }
-
- void CheckProbe(bool initially_enabled, const std::string& probe_url,
- const std::string& response, bool request_success,
- bool expected_enabled) {
- pref_service_.SetBoolean(prefs::kSpdyProxyAuthEnabled, initially_enabled);
- settings_->set_probe_result(probe_url, response, request_success);
- settings_->MaybeActivateDataReductionProxy(false);
- base::MessageLoop::current()->RunUntilIdle();
- CheckProxyPac(expected_enabled);
- }
-
- void CheckProbeOnIPChange(const std::string& probe_url,
- const std::string& response,
- bool request_success,
- bool expected_enabled) {
- settings_->set_probe_result(probe_url, response, request_success);
- settings_->OnIPAddressChanged();
- base::MessageLoop::current()->RunUntilIdle();
- CheckProxyPac(expected_enabled);
- }
-
- void CheckOnPrefChange(bool enabled, const std::string& probe_url,
- const std::string& response, bool request_success,
- bool expected_enabled) {
- settings_->set_probe_result(probe_url, response, request_success);
- pref_service_.SetBoolean(prefs::kSpdyProxyAuthEnabled, enabled);
- base::MessageLoop::current()->RunUntilIdle();
- CheckProxyPac(expected_enabled);
- }
-
- void CheckInitDataReductionProxy(bool enabled_at_startup) {
- AddProxyToCommandLine();
- base::MessageLoop loop(base::MessageLoop::TYPE_UI);
- pref_service_.SetBoolean(prefs::kSpdyProxyAuthEnabled, enabled_at_startup);
- settings_->set_probe_result(kProbeURLWithOKResponse, "OK", true);
- settings_->InitDataReductionProxySettings(NULL, NULL);
- base::MessageLoop::current()->RunUntilIdle();
- if (enabled_at_startup) {
- CheckProxyPac(enabled_at_startup);
- } else {
- // This presumes the proxy pref hadn't been set up by Chrome.
- CheckProxyPref(std::string(), std::string());
- }
- }
-
- TestingPrefServiceSimple pref_service_;
scoped_ptr<TestDataReductionProxySettingsAndroid> settings_;
- base::Time last_update_time_;
- // This is a singleton that will clear all set field trials on destruction.
- scoped_ptr<base::FieldTrialList> field_trial_list_;
JNIEnv* env_;
};
@@ -235,37 +160,16 @@ TEST_F(DataReductionProxySettingsAndroidTest,
// Confirm that the bypass rule functions generate the intended JavaScript
// code for the Proxy PAC.
-TEST_F(DataReductionProxySettingsAndroidTest, TestBypassRules) {
+TEST_F(DataReductionProxySettingsAndroidTest, TestBypassPACRules) {
settings_->AddURLPatternToBypass("http://foo.com/*");
settings_->AddHostPatternToBypass("bar.com");
- settings_->AddHostToBypass("127.0.0.1");
-
- std::string expected[] = {
- "shExpMatch(url, 'http://foo.com/*')",
- "shExpMatch(host, 'bar.com')",
- "host == '127.0.0.1'"
- };
-
- int i = 0;
- for (std::vector<std::string>::iterator it = settings_->bypass_rules_.begin();
- it != settings_->bypass_rules_.end(); ++it) {
- EXPECT_EQ(expected[i++], *it);
- }
-}
-
-TEST_F(DataReductionProxySettingsAndroidTest, TestIsProxyEnabledOrManaged) {
- settings_->InitPrefMembers();
- EXPECT_FALSE(settings_->IsDataReductionProxyEnabled(NULL, NULL));
- EXPECT_FALSE(settings_->IsDataReductionProxyManaged(NULL, NULL));
- pref_service_.SetBoolean(prefs::kSpdyProxyAuthEnabled, true);
- EXPECT_TRUE(settings_->IsDataReductionProxyEnabled(NULL, NULL));
- EXPECT_FALSE(settings_->IsDataReductionProxyManaged(NULL, NULL));
+ EXPECT_EQ(settings_->pac_bypass_rules_.size(), 1u);
+ EXPECT_EQ("shExpMatch(url, 'http://foo.com/*')",
+ settings_->pac_bypass_rules_[0]);
- pref_service_.SetManagedPref(prefs::kSpdyProxyAuthEnabled,
- base::Value::CreateBooleanValue(true));
- EXPECT_TRUE(settings_->IsDataReductionProxyEnabled(NULL, NULL));
- EXPECT_TRUE(settings_->IsDataReductionProxyManaged(NULL, NULL));
+ EXPECT_EQ(settings_->BypassRules().size(), 1u);
+ EXPECT_EQ("bar.com", settings_->BypassRules()[0]);
}
TEST_F(DataReductionProxySettingsAndroidTest, TestSetProxyPac) {
@@ -275,21 +179,20 @@ TEST_F(DataReductionProxySettingsAndroidTest, TestSetProxyPac) {
std::string expected_pac_url =
"data:application/x-ns-proxy-autoconfig;base64," + pac;
// Test setting the PAC, without generating histograms.
- settings_->has_turned_on_ = true;
- settings_->SetProxyPac(true, false);
- CheckProxyPref(expected_pac_url,
- ProxyModeToString(ProxyPrefs::MODE_PAC_SCRIPT));
+ settings_->SetHasTurnedOn();
+ settings_->SetProxyConfigs(true, false);
+ CheckProxyPacPref(expected_pac_url,
+ ProxyModeToString(ProxyPrefs::MODE_PAC_SCRIPT));
// Test disabling the PAC, without generating histograms.
- settings_->has_turned_off_ = true;
- settings_->SetProxyPac(false, false);
- CheckProxyPref(std::string(), ProxyModeToString(ProxyPrefs::MODE_SYSTEM));
+ settings_->SetHasTurnedOff();
+ settings_->SetProxyConfigs(false, false);
+ CheckProxyPacPref(std::string(), ProxyModeToString(ProxyPrefs::MODE_SYSTEM));
}
TEST_F(DataReductionProxySettingsAndroidTest, TestGetDailyContentLengths) {
- ScopedJavaLocalRef<jlongArray> result =
- settings_->GetDailyContentLengths(env_,
- prefs::kDailyHttpOriginalContentLength);
+ ScopedJavaLocalRef<jlongArray> result = settings_->GetDailyContentLengths(
+ env_, prefs::kDailyHttpOriginalContentLength);
ASSERT_TRUE(result.obj());
jsize java_array_len = env_->GetArrayLength(result.obj());
@@ -303,133 +206,3 @@ TEST_F(DataReductionProxySettingsAndroidTest, TestGetDailyContentLengths) {
}
}
-TEST_F(DataReductionProxySettingsAndroidTest,
- TestResetDataReductionStatistics) {
- int64 original_content_length;
- int64 received_content_length;
- int64 last_update_time;
- settings_->ResetDataReductionStatistics();
- settings_->GetContentLengthsInternal(spdyproxy::kNumDaysInHistory,
- &original_content_length,
- &received_content_length,
- &last_update_time);
- EXPECT_EQ(0L, original_content_length);
- EXPECT_EQ(0L, received_content_length);
- EXPECT_EQ(last_update_time_.ToInternalValue(), last_update_time);
-}
-
-TEST_F(DataReductionProxySettingsAndroidTest, TestContentLengthsInternal) {
- int64 original_content_length;
- int64 received_content_length;
- int64 last_update_time;
-
- // Request |kNumDaysInHistory| days.
- settings_->GetContentLengthsInternal(spdyproxy::kNumDaysInHistory,
- &original_content_length,
- &received_content_length,
- &last_update_time);
- const unsigned int days = spdyproxy::kNumDaysInHistory;
- // Received content length history values are 0 to |kNumDaysInHistory - 1|.
- int64 expected_total_received_content_length = (days - 1L) * days / 2;
- // Original content length history values are 0 to
- // |2 * (kNumDaysInHistory - 1)|.
- long expected_total_original_content_length = (days - 1L) * days;
- EXPECT_EQ(expected_total_original_content_length, original_content_length);
- EXPECT_EQ(expected_total_received_content_length, received_content_length);
- EXPECT_EQ(last_update_time_.ToInternalValue(), last_update_time);
-
- // Request |kNumDaysInHistory - 1| days.
- settings_->GetContentLengthsInternal(spdyproxy::kNumDaysInHistory - 1,
- &original_content_length,
- &received_content_length,
- &last_update_time);
- expected_total_received_content_length -= (days - 1);
- expected_total_original_content_length -= 2 * (days - 1);
- EXPECT_EQ(expected_total_original_content_length, original_content_length);
- EXPECT_EQ(expected_total_received_content_length, received_content_length);
-
- // Request 0 days.
- settings_->GetContentLengthsInternal(0,
- &original_content_length,
- &received_content_length,
- &last_update_time);
- expected_total_received_content_length = 0;
- expected_total_original_content_length = 0;
- EXPECT_EQ(expected_total_original_content_length, original_content_length);
- EXPECT_EQ(expected_total_received_content_length, received_content_length);
-
- // Request 1 day. First day had 0 bytes so should be same as 0 days.
- settings_->GetContentLengthsInternal(1,
- &original_content_length,
- &received_content_length,
- &last_update_time);
- EXPECT_EQ(expected_total_original_content_length, original_content_length);
- EXPECT_EQ(expected_total_received_content_length, received_content_length);
-}
-
-TEST_F(DataReductionProxySettingsAndroidTest,
- TestMaybeActivateDataReductionProxy) {
- AddProxyToCommandLine();
- settings_->InitPrefMembers();
- // TODO(bengr): Test enabling/disabling while a probe is outstanding.
- base::MessageLoop loop(base::MessageLoop::TYPE_UI);
- // The proxy is enabled initially.
- // Request succeeded but with bad response, expect proxy to be disabled.
- CheckProbe(true, kProbeURLWithBadResponse, "Bad", true, false);
- // Request succeeded with valid response, expect proxy to be enabled.
- CheckProbe(true, kProbeURLWithOKResponse, "OK", true, true);
- // Request failed, expect proxy to be disabled.
- CheckProbe(true, kProbeURLWithNoResponse, "", false, false);
-
- // The proxy is disabled initially. Probes should not be emitted to change
- // state.
- EXPECT_EQ(3, settings_->fake_fetcher_request_count());
- CheckProbe(false, kProbeURLWithOKResponse, "OK", true, false);
- EXPECT_EQ(3, settings_->fake_fetcher_request_count());
-}
-
-TEST_F(DataReductionProxySettingsAndroidTest,
- TestOnIPAddressChanged) {
- AddProxyToCommandLine();
- base::MessageLoop loop(base::MessageLoop::TYPE_UI);
- // The proxy is enabled initially.
- settings_->enabled_by_user_ = true;
- settings_->SetProxyPac(true, true);
- // IP address change triggers a probe that succeeds. Proxy remains enabled.
- CheckProbeOnIPChange(kProbeURLWithOKResponse, "OK", true, true);
- // IP address change triggers a probe that fails. Proxy is disabled.
- CheckProbeOnIPChange(kProbeURLWithBadResponse, "Bad", true, false);
- // IP address change triggers a probe that fails. Proxy remains disabled.
- CheckProbeOnIPChange(kProbeURLWithBadResponse, "Bad", true, false);
- // IP address change triggers a probe that succeed. Proxy is enabled.
- CheckProbeOnIPChange(kProbeURLWithBadResponse, "OK", true, true);
- EXPECT_EQ(4, settings_->fake_fetcher_request_count());
-}
-
-TEST_F(DataReductionProxySettingsAndroidTest,
- TestOnProxyEnabledPrefChange) {
- AddProxyToCommandLine();
- settings_->InitPrefMembers();
- base::MessageLoop loop(base::MessageLoop::TYPE_UI);
- LOG(WARNING) << "Before init pref members";
- // The proxy is enabled initially.
- settings_->enabled_by_user_ = true;
- settings_->SetProxyPac(true, true);
- LOG(WARNING) << "after set proxy pac";
- // The pref is disabled, so correspondingly should be the proxy.
- CheckOnPrefChange(false, kProbeURLWithOKResponse, "OK", true, false);
- // The pref is enabled, so correspondingly should be the proxy.
- CheckOnPrefChange(true, kProbeURLWithOKResponse, "OK", true, true);
- EXPECT_EQ(1, settings_->fake_fetcher_request_count());
-}
-
-TEST_F(DataReductionProxySettingsAndroidTest,
- TestInitDataReductionProxyOn) {
- CheckInitDataReductionProxy(true);
-}
-
-TEST_F(DataReductionProxySettingsAndroidTest,
- TestInitDataReductionProxyOff) {
- CheckInitDataReductionProxy(false);
-}
-
diff --git a/chrome/browser/notifications/balloon_host.cc b/chrome/browser/notifications/balloon_host.cc
index 362804fe2a..c3de873cc9 100644
--- a/chrome/browser/notifications/balloon_host.cc
+++ b/chrome/browser/notifications/balloon_host.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/notifications/balloon_host.h"
#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/extensions/extension_web_contents_observer.h"
#include "chrome/browser/notifications/balloon.h"
#include "chrome/browser/notifications/balloon_collection_impl.h"
#include "chrome/browser/notifications/notification.h"
@@ -141,6 +142,8 @@ void BalloonHost::Init() {
extensions::SetViewType(
web_contents_.get(), extensions::VIEW_TYPE_NOTIFICATION);
web_contents_->SetDelegate(this);
+ extensions::ExtensionWebContentsObserver::CreateForWebContents(
+ web_contents_.get());
Observe(web_contents_.get());
renderer_preferences_util::UpdateFromSystemSettings(
web_contents_->GetMutableRendererPrefs(), balloon_->profile());
diff --git a/chrome/browser/notifications/desktop_notification_service.cc b/chrome/browser/notifications/desktop_notification_service.cc
index b671fbd08c..a910ecbbfe 100644
--- a/chrome/browser/notifications/desktop_notification_service.cc
+++ b/chrome/browser/notifications/desktop_notification_service.cc
@@ -209,10 +209,7 @@ void DesktopNotificationService::RegisterProfilePrefs(
registry->RegisterListPref(
prefs::kMessageCenterEnabledSyncNotifierIds,
user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
- registry->RegisterBooleanPref(
- prefs::kWelcomeNotificationDismissed,
- false,
- user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+ WelcomeNotification::RegisterProfilePrefs(registry);
}
// static
@@ -626,6 +623,17 @@ void DesktopNotificationService::SetNotifierEnabled(
}
}
+void DesktopNotificationService::ShowWelcomeNotificationIfNecessary(
+ const Notification& notification) {
+ if (!welcome_notification && message_center::IsRichNotificationEnabled()) {
+ welcome_notification.reset(
+ new WelcomeNotification(profile_, g_browser_process->message_center()));
+ }
+
+ if (welcome_notification)
+ welcome_notification->ShowWelcomeNotificationIfNecessary(notification);
+}
+
void DesktopNotificationService::OnStringListPrefChanged(
const char* pref_name, std::set<std::string>* ids_field) {
ids_field->clear();
diff --git a/chrome/browser/notifications/desktop_notification_service.h b/chrome/browser/notifications/desktop_notification_service.h
index c77720b4b0..46defd40f8 100644
--- a/chrome/browser/notifications/desktop_notification_service.h
+++ b/chrome/browser/notifications/desktop_notification_service.h
@@ -11,9 +11,11 @@
#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
#include "base/prefs/pref_member.h"
#include "base/strings/string16.h"
#include "chrome/browser/content_settings/content_settings_provider.h"
+#include "chrome/browser/notifications/welcome_notification.h"
#include "chrome/common/content_settings.h"
#include "components/browser_context_keyed_service/browser_context_keyed_service.h"
#include "content/public/browser/notification_observer.h"
@@ -162,6 +164,10 @@ class DesktopNotificationService : public BrowserContextKeyedService,
void SetNotifierEnabled(const message_center::NotifierId& notifier_id,
bool enabled);
+ // Adds in a the welcome notification if required for components built
+ // into Chrome that show notifications like Chrome Now.
+ void ShowWelcomeNotificationIfNecessary(const Notification& notification);
+
private:
// Takes a notification object and shows it in the UI.
void ShowNotification(const Notification& notification);
@@ -222,6 +228,9 @@ class DesktopNotificationService : public BrowserContextKeyedService,
// Registrar for the other kind of notifications (event signaling).
content::NotificationRegistrar registrar_;
+ // Welcome Notification
+ scoped_ptr<WelcomeNotification> welcome_notification;
+
DISALLOW_COPY_AND_ASSIGN(DesktopNotificationService);
};
diff --git a/chrome/browser/notifications/message_center_notification_manager.cc b/chrome/browser/notifications/message_center_notification_manager.cc
index 7aa64dceef..d4048909c0 100644
--- a/chrome/browser/notifications/message_center_notification_manager.cc
+++ b/chrome/browser/notifications/message_center_notification_manager.cc
@@ -92,6 +92,9 @@ void MessageCenterNotificationManager::Add(const Notification& notification,
if (Update(notification, profile))
return;
+ DesktopNotificationServiceFactory::GetForProfile(profile)->
+ ShowWelcomeNotificationIfNecessary(notification);
+
AddProfileNotification(
new ProfileNotification(profile, notification, message_center_));
}
diff --git a/chrome/browser/notifications/message_center_settings_controller.cc b/chrome/browser/notifications/message_center_settings_controller.cc
index 583ca0f0f1..b21fb16de2 100644
--- a/chrome/browser/notifications/message_center_settings_controller.cc
+++ b/chrome/browser/notifications/message_center_settings_controller.cc
@@ -162,7 +162,9 @@ void MessageCenterSettingsController::SwitchToNotifierGroup(size_t index) {
void MessageCenterSettingsController::GetNotifierList(
std::vector<Notifier*>* notifiers) {
DCHECK(notifiers);
- // TODO(mukai): Fix this for multi-profile.
+ if (notifier_groups_.empty())
+ return;
+
// Temporarily use the last used profile to prevent chrome from crashing when
// the default profile is not loaded.
message_center::ProfileNotifierGroup* group =
diff --git a/chrome/browser/notifications/message_center_settings_controller_unittest.cc b/chrome/browser/notifications/message_center_settings_controller_unittest.cc
index e46505c092..362da5e26e 100644
--- a/chrome/browser/notifications/message_center_settings_controller_unittest.cc
+++ b/chrome/browser/notifications/message_center_settings_controller_unittest.cc
@@ -69,3 +69,15 @@ TEST_F(MessageCenterSettingsControllerTest, NotifierGroups) {
EXPECT_EQ(controller->GetActiveNotifierGroup().name,
UTF8ToUTF16("Profile-1"));
}
+
+TEST_F(MessageCenterSettingsControllerTest, GuestNoBreak) {
+ // In the guest mode of ChromeOS, there're no notifier groups but
+ // GetNotifierList() shouldn't cause crash.
+ scoped_ptr<MessageCenterSettingsController> controller(
+ new MessageCenterSettingsController(GetCache()));
+
+ EXPECT_EQ(controller->GetNotifierGroupCount(), 0u);
+ std::vector<message_center::Notifier*> notifiers;
+ controller->GetNotifierList(&notifiers);
+ EXPECT_TRUE(notifiers.empty());
+}
diff --git a/chrome/browser/notifications/message_center_stats_collector.cc b/chrome/browser/notifications/message_center_stats_collector.cc
index f0257a9423..3279728b7a 100644
--- a/chrome/browser/notifications/message_center_stats_collector.cc
+++ b/chrome/browser/notifications/message_center_stats_collector.cc
@@ -134,5 +134,12 @@ void MessageCenterStatsCollector::OnCenterVisibilityChanged(
}
void MessageCenterStatsCollector::OnQuietModeChanged(bool in_quiet_mode) {
+ if (in_quiet_mode) {
+ content::RecordAction(
+ content::UserMetricsAction("Notifications.Mute"));
+ } else {
+ content::RecordAction(
+ content::UserMetricsAction("Notifications.Unmute"));
+ }
}
diff --git a/chrome/browser/notifications/notification_browsertest.cc b/chrome/browser/notifications/notification_browsertest.cc
index b246ebb5e2..de06963a73 100644
--- a/chrome/browser/notifications/notification_browsertest.cc
+++ b/chrome/browser/notifications/notification_browsertest.cc
@@ -856,12 +856,11 @@ IN_PROC_BROWSER_TEST_F(NotificationsTest, TestCloseTabWithPermissionInfobar) {
browser()->tab_strip_model()->ActivateTabAt(0, true);
ui_test_utils::NavigateToURL(browser(), GetTestPageURL());
ASSERT_TRUE(RequestPermissionAndWait(browser()));
- content::WindowedNotificationObserver observer(
- content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
- content::NotificationService::AllSources());
+ content::WebContentsDestroyedWatcher destroyed_watcher(
+ browser()->tab_strip_model()->GetWebContentsAt(0));
browser()->tab_strip_model()->CloseWebContentsAt(0,
TabStripModel::CLOSE_NONE);
- observer.Wait();
+ destroyed_watcher.Wait();
}
IN_PROC_BROWSER_TEST_F(
diff --git a/chrome/browser/notifications/sync_notifier/chrome_notifier_delegate.cc b/chrome/browser/notifications/sync_notifier/chrome_notifier_delegate.cc
index 96f74c9b1a..9585d81832 100644
--- a/chrome/browser/notifications/sync_notifier/chrome_notifier_delegate.cc
+++ b/chrome/browser/notifications/sync_notifier/chrome_notifier_delegate.cc
@@ -4,11 +4,14 @@
#include "chrome/browser/notifications/sync_notifier/chrome_notifier_delegate.h"
+
+#include "base/metrics/histogram.h"
#include "chrome/browser/notifications/sync_notifier/chrome_notifier_service.h"
#include "chrome/browser/notifications/sync_notifier/synced_notification.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "content/public/browser/page_navigator.h"
+#include "content/public/browser/user_metrics.h"
namespace notifier {
ChromeNotifierDelegate::ChromeNotifierDelegate(
@@ -26,6 +29,15 @@ content::RenderViewHost* ChromeNotifierDelegate::GetRenderViewHost() const {
return NULL;
}
+void ChromeNotifierDelegate::CollectAction(SyncedNotificationActionType type) {
+ DCHECK(!notification_id_.empty());
+
+ UMA_HISTOGRAM_ENUMERATION("SyncedNotifications.Actions",
+ type,
+ SYNCED_NOTIFICATION_ACTION_COUNT);
+}
+
+
// TODO(petewil) Add the ability to do URL actions also.
void ChromeNotifierDelegate::Click() {
SyncedNotification* notification =
@@ -36,6 +48,9 @@ void ChromeNotifierDelegate::Click() {
GURL destination = notification->GetDefaultDestinationUrl();
NavigateToUrl(destination);
chrome_notifier_->MarkNotificationAsRead(notification_id_);
+
+ // Record the action in UMA statistics.
+ CollectAction(SYNCED_NOTIFICATION_ACTION_CLICK);
}
// TODO(petewil) Add the ability to do URL actions also.
@@ -47,6 +62,9 @@ void ChromeNotifierDelegate::ButtonClick(int button_index) {
NavigateToUrl(destination);
chrome_notifier_->MarkNotificationAsRead(notification_id_);
}
+
+ // Now record the UMA statistics for this action.
+ CollectAction(SYNCED_NOTIFICATION_ACTION_BUTTON_CLICK);
}
void ChromeNotifierDelegate::NavigateToUrl(const GURL& destination) const {
@@ -68,6 +86,10 @@ void ChromeNotifierDelegate::NavigateToUrl(const GURL& destination) const {
void ChromeNotifierDelegate::Close(bool by_user) {
if (by_user)
chrome_notifier_->MarkNotificationAsRead(notification_id_);
+
+ CollectAction(by_user ?
+ SYNCED_NOTIFICATION_ACTION_CLOSE_BY_USER :
+ SYNCED_NOTIFICATION_ACTION_CLOSE_BY_SYSTEM);
}
} // namespace notifier
diff --git a/chrome/browser/notifications/sync_notifier/chrome_notifier_delegate.h b/chrome/browser/notifications/sync_notifier/chrome_notifier_delegate.h
index f0ea79bac5..4bf75fedf9 100644
--- a/chrome/browser/notifications/sync_notifier/chrome_notifier_delegate.h
+++ b/chrome/browser/notifications/sync_notifier/chrome_notifier_delegate.h
@@ -5,6 +5,7 @@
#ifndef CHROME_BROWSER_NOTIFICATIONS_SYNC_NOTIFIER_CHROME_NOTIFIER_DELEGATE_H_
#define CHROME_BROWSER_NOTIFICATIONS_SYNC_NOTIFIER_CHROME_NOTIFIER_DELEGATE_H_
+#include <map>
#include <string>
#include "chrome/browser/notifications/notification_delegate.h"
@@ -12,6 +13,19 @@
namespace notifier {
+enum SyncedNotificationActionType {
+ SYNCED_NOTIFICATION_ACTION_UNKNOWN,
+ SYNCED_NOTIFICATION_ACTION_CLICK,
+ SYNCED_NOTIFICATION_ACTION_BUTTON_CLICK,
+ SYNCED_NOTIFICATION_ACTION_CLOSE_BY_USER,
+ SYNCED_NOTIFICATION_ACTION_CLOSE_BY_SYSTEM,
+ SYNCED_NOTIFICATION_ACTION_TOAST_TIMEOUT,
+ // NOTE: Add new action types only immediately above this line. Also,
+ // make sure the enum list in tools/histogram/histograms.xml is
+ // updated with any change in here.
+ SYNCED_NOTIFICATION_ACTION_COUNT
+};
+
class ChromeNotifierService;
// ChromeNotifierDelegate is a NotificationDelegate which catches
@@ -35,6 +49,8 @@ class ChromeNotifierDelegate : public NotificationDelegate {
virtual content::RenderViewHost* GetRenderViewHost() const OVERRIDE;
+ void CollectAction(SyncedNotificationActionType type);
+
private:
virtual ~ChromeNotifierDelegate();
void NavigateToUrl(const GURL& destination) const;
diff --git a/chrome/browser/notifications/sync_notifier/chrome_notifier_service.cc b/chrome/browser/notifications/sync_notifier/chrome_notifier_service.cc
index 939c2d4e16..3118a9e4ff 100644
--- a/chrome/browser/notifications/sync_notifier/chrome_notifier_service.cc
+++ b/chrome/browser/notifications/sync_notifier/chrome_notifier_service.cc
@@ -12,6 +12,7 @@
#include <vector>
#include "base/command_line.h"
+#include "base/metrics/histogram.h"
#include "base/prefs/pref_service.h"
#include "base/values.h"
#include "chrome/browser/notifications/desktop_notification_service.h"
@@ -23,6 +24,7 @@
#include "chrome/common/pref_names.h"
#include "components/user_prefs/pref_registry_syncable.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/user_metrics.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "sync/api/sync_change.h"
@@ -36,6 +38,8 @@
#include "ui/message_center/notifier_settings.h"
#include "url/gurl.h"
+using content::UserMetricsAction;
+
namespace notifier {
const char kFirstSyncedNotificationServiceId[] = "Google+";
@@ -493,10 +497,46 @@ void ChromeNotifierService::OnSyncedNotificationServiceEnabled(
RemoveUnreadNotificationsFromSource(notifier_id_copy);
}
- // Otherwise, nothing to do, we can exit.
+ // Collect UMA statistics when a service is enabled or disabled.
+ if (enabled) {
+ content::RecordAction(
+ UserMetricsAction("SyncedNotifications.SendingServiceEnabled"));
+ } else {
+ content::RecordAction(
+ UserMetricsAction("SyncedNotifications.SendingServiceDisabled"));
+ }
+
+ // Collect individual service enabling/disabling statistics.
+ CollectPerServiceEnablingStatistics(notifier_id, enabled);
+
return;
}
+void ChromeNotifierService::CollectPerServiceEnablingStatistics(
+ const std::string& notifier_id,
+ bool enabled) {
+ // TODO(petewil) - This approach does not scale well as we add new services,
+ // but we are limited to using predefined ENUM values in histogram based UMA
+ // data, which does not permit arbitrary strings.
+ // Find a way to make it scale, or remove enum value this when we have enough
+ // data.
+
+ ChromeNotifierServiceActionType action =
+ CHROME_NOTIFIER_SERVICE_ACTION_UNKNOWN;
+
+ // Derive action type from notifier_id and enabled.
+ // TODO(petewil): Add more sending services as they are enabled.
+ if (notifier_id == std::string(kFirstSyncedNotificationServiceId)) {
+ action = enabled
+ ? CHROME_NOTIFIER_SERVICE_ACTION_FIRST_SERVICE_ENABLED
+ : CHROME_NOTIFIER_SERVICE_ACTION_FIRST_SERVICE_DISABLED;
+ }
+
+ UMA_HISTOGRAM_ENUMERATION("ChromeNotifierService.Actions",
+ action,
+ CHROME_NOTIFIER_SERVICE_ACTION_COUNT);
+}
+
void ChromeNotifierService::BuildServiceListValueInplace(
std::set<std::string> services, base::ListValue* list_value) {
std::set<std::string>::iterator iter;
@@ -616,6 +656,7 @@ void ChromeNotifierService::InitializePrefs() {
// Get the prefs from last session into our memeber varilables
OnEnabledSendingServiceListPrefChanged(&enabled_sending_services_);
OnInitializedSendingServiceListPrefChanged(&initialized_sending_services_);
+
synced_notification_first_run_ =
profile_->GetPrefs()->GetBoolean(prefs::kSyncedNotificationFirstRun);
}
diff --git a/chrome/browser/notifications/sync_notifier/chrome_notifier_service.h b/chrome/browser/notifications/sync_notifier/chrome_notifier_service.h
index 787fcbd5b4..356448fbd1 100644
--- a/chrome/browser/notifications/sync_notifier/chrome_notifier_service.h
+++ b/chrome/browser/notifications/sync_notifier/chrome_notifier_service.h
@@ -32,6 +32,16 @@ extern const char kFirstSyncedNotificationServiceId[];
extern const char kServiceEnabledOnce[];
extern const char kSyncedNotificationFirstRun[];
+enum ChromeNotifierServiceActionType {
+ CHROME_NOTIFIER_SERVICE_ACTION_UNKNOWN,
+ CHROME_NOTIFIER_SERVICE_ACTION_FIRST_SERVICE_ENABLED,
+ CHROME_NOTIFIER_SERVICE_ACTION_FIRST_SERVICE_DISABLED,
+ // NOTE: Add new action types only immediately above this line. Also,
+ // make sure the enum list in tools/histogram/histograms.xml is
+ // updated with any change in here.
+ CHROME_NOTIFIER_SERVICE_ACTION_COUNT
+};
+
// The ChromeNotifierService holds notifications which represent the state of
// delivered notifications for chrome. These are obtained from the sync service
// and kept up to date.
@@ -123,6 +133,11 @@ class ChromeNotifierService : public syncer::SyncableService,
// for that service, and remove them from the message center.
void RemoveUnreadNotificationsFromSource(const std::string& notifier_id);
+ // When we turn a sending service on or off, collect statistics about
+ // how often users turn it on or off.
+ void CollectPerServiceEnablingStatistics(const std::string& notifier_id,
+ bool enabled);
+
// When we start up or hear of a new service, turn it on by default.
void AddNewSendingServices();
diff --git a/chrome/browser/notifications/welcome_notification.cc b/chrome/browser/notifications/welcome_notification.cc
new file mode 100644
index 0000000000..ac48b752b4
--- /dev/null
+++ b/chrome/browser/notifications/welcome_notification.cc
@@ -0,0 +1,136 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/notifications/welcome_notification.h"
+
+#include "base/guid.h"
+#include "base/lazy_instance.h"
+#include "base/message_loop/message_loop.h"
+#include "base/prefs/pref_service.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/notifications/notification.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/url_constants.h"
+#include "components/user_prefs/pref_registry_syncable.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/message_center/message_center.h"
+#include "ui/message_center/notification.h"
+#include "ui/message_center/notification_delegate.h"
+#include "ui/message_center/notification_types.h"
+
+const char kChromeNowExtensionID[] = "pafkbggdmjlpgkdkcbjmhmfcdpncadgh";
+
+class WelcomeNotificationDelegate
+ : public message_center::NotificationDelegate {
+ public:
+ WelcomeNotificationDelegate(const std::string& id, Profile* profile)
+ : profile_(profile) {}
+
+ // Overridden from NotificationDelegate:
+ virtual void Display() OVERRIDE {}
+ virtual void Error() OVERRIDE {}
+
+ virtual void Close(bool by_user) OVERRIDE {
+ if (by_user) {
+ // Setting the preference here may cause the notification erasing
+ // to reenter. Posting a task avoids this issue.
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&WelcomeNotificationDelegate::MarkAsDismissed, this));
+ }
+ }
+
+ virtual void Click() OVERRIDE {}
+ virtual void ButtonClick(int index) OVERRIDE {}
+
+ private:
+ void MarkAsDismissed() {
+ profile_->GetPrefs()->
+ SetBoolean(prefs::kWelcomeNotificationDismissed, true);
+ }
+
+ virtual ~WelcomeNotificationDelegate() {}
+
+ Profile* const profile_;
+
+ DISALLOW_COPY_AND_ASSIGN(WelcomeNotificationDelegate);
+};
+
+WelcomeNotification::WelcomeNotification(
+ Profile* profile,
+ message_center::MessageCenter* message_center)
+ : profile_(profile),
+ message_center_(message_center) {
+ welcome_notification_dismissed_pref_.Init(
+ prefs::kWelcomeNotificationDismissed,
+ profile_->GetPrefs(),
+ base::Bind(
+ &WelcomeNotification::OnWelcomeNotificationDismissedChanged,
+ base::Unretained(this)));
+}
+
+WelcomeNotification::~WelcomeNotification() {}
+
+void WelcomeNotification::ShowWelcomeNotificationIfNecessary(
+ const Notification& notification) {
+ if (notification.notifier_id().id == kChromeNowExtensionID) {
+ PrefService* pref_service = profile_->GetPrefs();
+ if (!pref_service->GetBoolean(prefs::kWelcomeNotificationDismissed))
+ ShowWelcomeNotification();
+ }
+}
+
+// Static
+void WelcomeNotification::RegisterProfilePrefs(
+ user_prefs::PrefRegistrySyncable* prefs) {
+ prefs->RegisterBooleanPref(
+ prefs::kWelcomeNotificationDismissed,
+ false,
+ user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+}
+
+void WelcomeNotification::ShowWelcomeNotification() {
+ message_center::RichNotificationData rich_notification_data;
+ rich_notification_data.priority = 2;
+
+ if (welcome_notification_id_.empty())
+ welcome_notification_id_ = base::GenerateGUID();
+
+ if (!welcome_notification_id_.empty()) {
+ scoped_ptr<message_center::Notification> message_center_notification(
+ new message_center::Notification(
+ message_center::NOTIFICATION_TYPE_BASE_FORMAT,
+ welcome_notification_id_,
+ l10n_util::GetStringUTF16(IDS_NOTIFICATION_WELCOME_TITLE),
+ l10n_util::GetStringUTF16(IDS_NOTIFICATION_WELCOME_BODY),
+ ui::ResourceBundle::GetSharedInstance().GetImageNamed(
+ IDR_NOTIFICATION_WELCOME_ICON),
+ l10n_util::GetStringUTF16(IDS_NOTIFICATION_WELCOME_DISPLAY_SOURCE),
+ message_center::NotifierId(
+ message_center::NotifierId::SYSTEM_COMPONENT),
+ rich_notification_data,
+ new WelcomeNotificationDelegate(
+ welcome_notification_id_, profile_)));
+ message_center_->AddNotification(message_center_notification.Pass());
+ }
+}
+
+void WelcomeNotification::HideWelcomeNotification() {
+ if (!welcome_notification_id_.empty() &&
+ message_center_->HasNotification(welcome_notification_id_)) {
+ message_center_->RemoveNotification(welcome_notification_id_, false);
+ }
+}
+
+void WelcomeNotification::OnWelcomeNotificationDismissedChanged() {
+ const bool welcome_notification_dismissed =
+ profile_->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed);
+ if (welcome_notification_dismissed)
+ HideWelcomeNotification();
+}
diff --git a/chrome/browser/notifications/welcome_notification.h b/chrome/browser/notifications/welcome_notification.h
new file mode 100644
index 0000000000..54e1c432d8
--- /dev/null
+++ b/chrome/browser/notifications/welcome_notification.h
@@ -0,0 +1,63 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_NOTIFICATIONS_WELCOME_NOTIFICATION_H_
+#define CHROME_BROWSER_NOTIFICATIONS_WELCOME_NOTIFICATION_H_
+
+#include <string>
+
+#include "base/prefs/pref_member.h"
+
+namespace message_center {
+class MessageCenter;
+}
+
+namespace user_prefs {
+class PrefRegistrySyncable;
+}
+
+class Notification;
+class Profile;
+
+// WelcomeNotification is a part of DesktopNotificationService and manages
+// showing and hiding a welcome notification for built-in components that
+// show notifications.
+class WelcomeNotification {
+ public:
+ WelcomeNotification(
+ Profile* profile,
+ message_center::MessageCenter* message_center);
+ ~WelcomeNotification();
+
+ // Adds in a the welcome notification if required for components built
+ // into Chrome that show notifications like Chrome Now.
+ void ShowWelcomeNotificationIfNecessary(
+ const Notification& notification);
+
+ // Handles Preference Registeration for the Welcome Notification.
+ static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* prefs);
+
+ private:
+ // Unconditionally shows the welcome notification.
+ void ShowWelcomeNotification();
+
+ // Hides the welcome notification.
+ void HideWelcomeNotification();
+
+ // Called when the Welcome Notification Dismissed pref has been changed.
+ void OnWelcomeNotificationDismissedChanged();
+
+ // Prefs listener for welcome_notification_dismissed.
+ BooleanPrefMember welcome_notification_dismissed_pref_;
+
+ // The profile which owns this object.
+ Profile* profile_;
+
+ // Notification ID of the Welcome Notification.
+ std::string welcome_notification_id_;
+
+ message_center::MessageCenter* message_center_; // Weak reference.
+};
+
+#endif // CHROME_BROWSER_NOTIFICATIONS_WELCOME_NOTIFICATION_H_
diff --git a/chrome/browser/notifications/welcome_notification_unittest.cc b/chrome/browser/notifications/welcome_notification_unittest.cc
new file mode 100644
index 0000000000..71d5435a79
--- /dev/null
+++ b/chrome/browser/notifications/welcome_notification_unittest.cc
@@ -0,0 +1,235 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/notifications/welcome_notification.h"
+
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/prefs/pref_service.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/notifications/notification.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/base/testing_pref_service_syncable.h"
+#include "chrome/test/base/testing_profile.h"
+#include "components/user_prefs/pref_registry_syncable.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/message_center/fake_message_center.h"
+#include "ui/message_center/notification.h"
+
+const char kChromeNowExtensionID[] = "pafkbggdmjlpgkdkcbjmhmfcdpncadgh";
+
+class MockMessageCenter : public message_center::FakeMessageCenter {
+ public:
+ MockMessageCenter()
+ : add_notification_calls_(0),
+ remove_notification_calls_(0) {};
+
+ int add_notification_calls() { return add_notification_calls_; }
+ int remove_notification_calls() { return remove_notification_calls_; }
+
+ // message_center::FakeMessageCenter Overrides
+ virtual bool HasNotification(const std::string& id) OVERRIDE {
+ return last_notification.get() &&
+ (last_notification->id() == id);
+ }
+
+ virtual void AddNotification(
+ scoped_ptr<message_center::Notification> notification) OVERRIDE {
+ EXPECT_FALSE(last_notification.get());
+ last_notification.swap(notification);
+ add_notification_calls_++;
+ }
+
+ virtual void RemoveNotification(const std::string& id, bool by_user)
+ OVERRIDE {
+ EXPECT_TRUE(last_notification.get());
+ last_notification.reset();
+ remove_notification_calls_++;
+ }
+
+ void CloseCurrentNotification() {
+ EXPECT_TRUE(last_notification.get());
+ last_notification->delegate()->Close(true);
+ RemoveNotification(last_notification->id(), true);
+ }
+
+ private:
+ scoped_ptr<message_center::Notification> last_notification;
+ int add_notification_calls_;
+ int remove_notification_calls_;
+};
+
+class WelcomeNotificationTest : public testing::Test {
+ protected:
+ WelcomeNotificationTest() {
+ scoped_refptr<user_prefs::PrefRegistrySyncable> pref_registry(
+ new user_prefs::PrefRegistrySyncable());
+ WelcomeNotification::RegisterProfilePrefs(pref_registry.get());
+ }
+
+ virtual void SetUp() {
+ message_loop_.reset(new base::MessageLoop());
+ profile_.reset(new TestingProfile());
+ message_center_.reset(new MockMessageCenter());
+ welcome_notification_.reset(
+ new WelcomeNotification(profile_.get(), message_center_.get()));
+ }
+
+ virtual void TearDown() {
+ welcome_notification_.reset();
+ message_center_.reset();
+ profile_.reset();
+ message_loop_.reset();
+ }
+
+ void ShowChromeNowNotification() {
+ ShowNotification(
+ "ChromeNowNotification",
+ message_center::NotifierId(
+ message_center::NotifierId::APPLICATION,
+ kChromeNowExtensionID));
+ }
+
+ void ShowRegularNotification() {
+ ShowNotification(
+ "RegularNotification",
+ message_center::NotifierId(
+ message_center::NotifierId::APPLICATION,
+ "aaaabbbbccccddddeeeeffffggghhhhi"));
+ }
+
+ void FlushMessageLoop() {
+ message_loop_->RunUntilIdle();
+ }
+
+ TestingProfile* profile() { return profile_.get(); }
+ MockMessageCenter* message_center() { return message_center_.get(); }
+
+ private:
+ class TestNotificationDelegate : public NotificationDelegate {
+ public:
+ explicit TestNotificationDelegate(const std::string& id)
+ : id_(id) {}
+
+ // Overridden from NotificationDelegate:
+ virtual void Display() OVERRIDE {}
+ virtual void Error() OVERRIDE {}
+ virtual void Close(bool by_user) OVERRIDE {}
+ virtual void Click() OVERRIDE {}
+ virtual void ButtonClick(int index) OVERRIDE {}
+
+ virtual std::string id() const OVERRIDE { return id_; }
+
+ virtual content::RenderViewHost* GetRenderViewHost() const OVERRIDE {
+ return NULL;
+ }
+
+ private:
+ virtual ~TestNotificationDelegate() {}
+
+ const std::string id_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestNotificationDelegate);
+ };
+
+ void ShowNotification(
+ std::string notification_id,
+ const message_center::NotifierId& notifier_id) {
+ message_center::RichNotificationData rich_notification_data;
+ rich_notification_data.priority = 0;
+ Notification notification(
+ message_center::NOTIFICATION_TYPE_BASE_FORMAT,
+ GURL("http://tests.url"),
+ base::UTF8ToUTF16("Title"),
+ base::UTF8ToUTF16("Body"),
+ gfx::Image(),
+ WebKit::WebTextDirectionDefault,
+ notifier_id,
+ base::UTF8ToUTF16("Source"),
+ base::UTF8ToUTF16(notification_id),
+ rich_notification_data,
+ new TestNotificationDelegate("TestNotification"));
+ welcome_notification_->ShowWelcomeNotificationIfNecessary(notification);
+ }
+
+ scoped_ptr<TestingProfile> profile_;
+ scoped_ptr<MockMessageCenter> message_center_;
+ scoped_ptr<WelcomeNotification> welcome_notification_;
+ scoped_ptr<base::MessageLoop> message_loop_;
+};
+
+// Show a regular notification. Expect that WelcomeNotification will
+// not show a welcome notification.
+TEST_F(WelcomeNotificationTest, FirstRunShowRegularNotification) {
+ EXPECT_FALSE(
+ profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
+
+ ShowRegularNotification();
+
+ EXPECT_TRUE(message_center()->add_notification_calls() == 0);
+ EXPECT_TRUE(message_center()->remove_notification_calls() == 0);
+ EXPECT_FALSE(
+ profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
+}
+
+// Show a Chrome Now notification. Expect that WelcomeNotification will
+// show a welcome notification.
+TEST_F(WelcomeNotificationTest, FirstRunChromeNowNotification) {
+ EXPECT_FALSE(
+ profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
+
+ ShowChromeNowNotification();
+
+ EXPECT_TRUE(message_center()->add_notification_calls() == 1);
+ EXPECT_TRUE(message_center()->remove_notification_calls() == 0);
+ EXPECT_FALSE(
+ profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
+}
+
+// Don't show a welcome notification if it was previously dismissed
+TEST_F(WelcomeNotificationTest, WelcomeNotificationPreviouslyDismissed) {
+ profile()->GetPrefs()->SetBoolean(prefs::kWelcomeNotificationDismissed, true);
+ EXPECT_TRUE(
+ profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
+
+ ShowChromeNowNotification();
+
+ EXPECT_TRUE(message_center()->add_notification_calls() == 0);
+ EXPECT_TRUE(message_center()->remove_notification_calls() == 0);
+ EXPECT_TRUE(
+ profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
+}
+
+// Show a Chrome Now notification and dismiss it.
+// Expect welcome toast dismissed to be true.
+TEST_F(WelcomeNotificationTest, DismissWelcomeNotification) {
+ EXPECT_FALSE(
+ profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
+
+ ShowChromeNowNotification();
+ message_center()->CloseCurrentNotification();
+ FlushMessageLoop();
+
+ EXPECT_TRUE(message_center()->add_notification_calls() == 1);
+ EXPECT_TRUE(message_center()->remove_notification_calls() == 1);
+ EXPECT_TRUE(
+ profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
+}
+
+// Show a Chrome Now notification and dismiss it via a synced preference change.
+// Expect welcome toast dismissed to be true.
+TEST_F(WelcomeNotificationTest, SyncedDismissalWelcomeNotification) {
+ EXPECT_FALSE(
+ profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
+
+ ShowChromeNowNotification();
+ profile()->GetPrefs()->SetBoolean(prefs::kWelcomeNotificationDismissed, true);
+
+ EXPECT_TRUE(message_center()->add_notification_calls() == 1);
+ EXPECT_TRUE(message_center()->remove_notification_calls() == 1);
+ EXPECT_TRUE(
+ profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed));
+}
diff --git a/chrome/browser/password_manager/password_generation_manager.cc b/chrome/browser/password_manager/password_generation_manager.cc
index d00683ee03..cc058c3e8e 100644
--- a/chrome/browser/password_manager/password_generation_manager.cc
+++ b/chrome/browser/password_manager/password_generation_manager.cc
@@ -31,26 +31,11 @@ DEFINE_WEB_CONTENTS_USER_DATA_KEY(PasswordGenerationManager);
PasswordGenerationManager::PasswordGenerationManager(
content::WebContents* contents)
- : content::WebContentsObserver(contents),
- enabled_(false),
- weak_factory_(this) {
- RegisterWithSyncService();
-}
+ : content::WebContentsObserver(contents) {}
PasswordGenerationManager::~PasswordGenerationManager() {}
// static
-void PasswordGenerationManager::CreateForWebContents(
- content::WebContents* contents) {
- content::WebContentsUserData<PasswordGenerationManager>::
- CreateForWebContents(contents);
-
- // Start observing changes to relevant prefs. This is not called in the
- // constructor so that it's not enabled in testing.
- FromWebContents(contents)->SetUpPrefChangeRegistrar();
-}
-
-// static
void PasswordGenerationManager::RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable* registry) {
registry->RegisterBooleanPref(
@@ -74,31 +59,10 @@ void PasswordGenerationManager::DetectAccountCreationForms(
}
}
}
- SendAccountCreationFormsToRenderer(web_contents()->GetRenderViewHost(),
- account_creation_forms);
-}
-
-void PasswordGenerationManager::RegisterWithSyncService() {
- Profile* profile = Profile::FromBrowserContext(
- web_contents()->GetBrowserContext());
- ProfileSyncService* sync_service =
- ProfileSyncServiceFactory::GetForProfile(profile);
- if (sync_service)
- sync_service->AddObserver(this);
-}
-
-void PasswordGenerationManager::SetUpPrefChangeRegistrar() {
- registrar_.Init(Profile::FromBrowserContext(
- web_contents()->GetBrowserContext())->GetPrefs());
- registrar_.Add(
- prefs::kPasswordGenerationEnabled,
- base::Bind(&PasswordGenerationManager::OnPrefStateChanged,
- weak_factory_.GetWeakPtr()));
-}
-
-void PasswordGenerationManager::RenderViewCreated(
- content::RenderViewHost* host) {
- UpdateState(host, true);
+ if (!account_creation_forms.empty() && IsGenerationEnabled()) {
+ SendAccountCreationFormsToRenderer(web_contents()->GetRenderViewHost(),
+ account_creation_forms);
+ }
}
bool PasswordGenerationManager::OnMessageReceived(const IPC::Message& message) {
@@ -112,42 +76,21 @@ bool PasswordGenerationManager::OnMessageReceived(const IPC::Message& message) {
return handled;
}
-void PasswordGenerationManager::WebContentsDestroyed(
- content::WebContents* contents) {
- Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
- ProfileSyncService* sync_service =
- ProfileSyncServiceFactory::GetForProfile(profile);
- if (sync_service && sync_service->HasObserver(this))
- sync_service->RemoveObserver(this);
-}
-
-void PasswordGenerationManager::OnPrefStateChanged() {
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
- if (web_contents() && web_contents()->GetRenderViewHost())
- UpdateState(web_contents()->GetRenderViewHost(), false);
-}
-
-void PasswordGenerationManager::OnStateChanged() {
- // It is possible for sync state to change during tab contents destruction.
- // In this case, we don't need to update the renderer since it's going away.
- if (web_contents() && web_contents()->GetRenderViewHost())
- UpdateState(web_contents()->GetRenderViewHost(), false);
-}
-
// In order for password generation to be enabled, we need to make sure:
// (1) Password sync is enabled,
// (2) Password manager is enabled, and
// (3) Password generation preference check box is checked.
-void PasswordGenerationManager::UpdateState(content::RenderViewHost* host,
- bool new_renderer) {
+bool PasswordGenerationManager::IsGenerationEnabled() const {
+ if (!web_contents())
+ return false;
+
Profile* profile = Profile::FromBrowserContext(
web_contents()->GetBrowserContext());
- bool saving_passwords_enabled =
- PasswordManager::FromWebContents(web_contents())->IsSavingEnabled();
-
- bool preference_checked = profile->GetPrefs()->GetBoolean(
- prefs::kPasswordGenerationEnabled);
+ if (!PasswordManager::FromWebContents(web_contents())->IsSavingEnabled()) {
+ DVLOG(2) << "Generation disabled because password saving is disabled";
+ return false;
+ }
bool password_sync_enabled = false;
ProfileSyncService* sync_service =
@@ -157,21 +100,17 @@ void PasswordGenerationManager::UpdateState(content::RenderViewHost* host,
password_sync_enabled = (sync_service->HasSyncSetupCompleted() &&
sync_set.Has(syncer::PASSWORDS));
}
+ if (!password_sync_enabled) {
+ DVLOG(2) << "Generation disabled because passwords are not being synced";
+ return false;
+ }
- bool new_enabled = (password_sync_enabled &&
- saving_passwords_enabled &&
- preference_checked);
-
- if (new_enabled != enabled_ || new_renderer) {
- enabled_ = new_enabled;
- SendStateToRenderer(host, enabled_);
+ if (!profile->GetPrefs()->GetBoolean(prefs::kPasswordGenerationEnabled)) {
+ DVLOG(2) << "Generation disabled by user";
+ return false;
}
-}
-void PasswordGenerationManager::SendStateToRenderer(
- content::RenderViewHost* host, bool enabled) {
- host->Send(new AutofillMsg_PasswordGenerationEnabled(host->GetRoutingID(),
- enabled));
+ return true;
}
void PasswordGenerationManager::SendAccountCreationFormsToRenderer(
diff --git a/chrome/browser/password_manager/password_generation_manager.h b/chrome/browser/password_manager/password_generation_manager.h
index 585ec9e522..c9382bbfd0 100644
--- a/chrome/browser/password_manager/password_generation_manager.h
+++ b/chrome/browser/password_manager/password_generation_manager.h
@@ -7,9 +7,6 @@
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/prefs/pref_change_registrar.h"
-#include "chrome/browser/sync/profile_sync_service_observer.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
@@ -35,20 +32,19 @@ class PrefRegistrySyncable;
// not be enabled regardless of the above criteria without the switch being
// present.
//
-// When enabled we will send a message enabling this feature in the renderer,
-// which will show an icon next to password fields which we think are associated
-// with account creation. This class also manages the popup which is created
-// if the user chooses to generate a password.
+// This class is used to determine what forms we should offer to generate
+// passwords for and manages the popup which is created if the user chooses to
+// generate a password.
class PasswordGenerationManager
- : public ProfileSyncServiceObserver,
- public content::WebContentsObserver,
+ : public content::WebContentsObserver,
public content::WebContentsUserData<PasswordGenerationManager> {
public:
- static void CreateForWebContents(content::WebContents* contents);
static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
virtual ~PasswordGenerationManager();
// Detect account creation forms from forms with autofill type annotated.
+ // Will send a message to the renderer if we find a correctly annotated form
+ // and the feature is enabled.
void DetectAccountCreationForms(
const std::vector<autofill::FormStructure*>& forms);
@@ -60,30 +56,13 @@ class PasswordGenerationManager
friend class PasswordGenerationManagerTest;
// WebContentsObserver:
- virtual void RenderViewCreated(content::RenderViewHost* host) OVERRIDE;
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
- virtual void WebContentsDestroyed(content::WebContents* contents) OVERRIDE;
- // ProfileSyncServiceObserver:
- virtual void OnStateChanged() OVERRIDE;
-
- // Add ourselves as an observer to the sync service to be informed of changes
- // to the password sync state.
- void RegisterWithSyncService();
-
- // Start watching for changes to the password generation enabled pref.
- void SetUpPrefChangeRegistrar();
- void OnPrefStateChanged();
-
- // Determines current state of password generation and sends this information
- // to the renderer if it is different from |enabled_| or if |new_renderer|
- // is true.
- void UpdateState(content::RenderViewHost* host, bool new_renderer);
-
- // Sends a message to the renderer enabling or disabling this feature. This
- // is a separate function to aid in testing.
- virtual void SendStateToRenderer(content::RenderViewHost* host, bool enabled);
+ // Determines current state of password generation
+ bool IsGenerationEnabled() const;
+ // Sends a message to the renderer specifying form(s) that we should enable
+ // password generation on. This is a separate function to aid in testing.
virtual void SendAccountCreationFormsToRenderer(
content::RenderViewHost* host,
const std::vector<autofill::FormData>& forms);
@@ -95,15 +74,6 @@ class PasswordGenerationManager
int max_length,
const autofill::PasswordForm& form);
- // Whether password generation is enabled.
- bool enabled_;
-
- // Listens for changes to the state of the password generation pref.
- PrefChangeRegistrar registrar_;
-
- // For vending a weak_ptr for |registrar_|.
- base::WeakPtrFactory<PasswordGenerationManager> weak_factory_;
-
// Controls how passwords are generated.
scoped_ptr<autofill::PasswordGenerator> password_generator_;
diff --git a/chrome/browser/password_manager/password_generation_manager_unittest.cc b/chrome/browser/password_manager/password_generation_manager_unittest.cc
index 54c2b666ba..4dd5934dd7 100644
--- a/chrome/browser/password_manager/password_generation_manager_unittest.cc
+++ b/chrome/browser/password_manager/password_generation_manager_unittest.cc
@@ -42,11 +42,6 @@ class TestPasswordGenerationManager : public PasswordGenerationManager {
: PasswordGenerationManager(contents) {}
virtual ~TestPasswordGenerationManager() {}
- virtual void SendStateToRenderer(content::RenderViewHost* host,
- bool enabled) OVERRIDE {
- sent_states_.push_back(enabled);
- }
-
virtual void SendAccountCreationFormsToRenderer(
content::RenderViewHost* host,
const std::vector<autofill::FormData>& forms) OVERRIDE {
@@ -54,24 +49,15 @@ class TestPasswordGenerationManager : public PasswordGenerationManager {
sent_account_creation_forms_.begin(), forms.begin(), forms.end());
}
- const std::vector<bool>& GetSentStates() {
- return sent_states_;
- }
-
const std::vector<autofill::FormData>& GetSentAccountCreationForms() {
return sent_account_creation_forms_;
}
- void ClearSentStates() {
- sent_states_.clear();
- }
-
void ClearSentAccountCreationForms() {
sent_account_creation_forms_.clear();
}
private:
- std::vector<bool> sent_states_;
std::vector<autofill::FormData> sent_account_creation_forms_;
DISALLOW_COPY_AND_ASSIGN(TestPasswordGenerationManager);
@@ -91,8 +77,8 @@ class PasswordGenerationManagerTest : public ChromeRenderViewHostTestHarness {
ChromeRenderViewHostTestHarness::TearDown();
}
- void UpdateState(bool new_renderer) {
- password_generation_manager_->UpdateState(NULL, new_renderer);
+ bool IsGenerationEnabled() {
+ return password_generation_manager_->IsGenerationEnabled();
}
void DetectAccountCreationForms(
@@ -115,7 +101,7 @@ class IncognitoPasswordGenerationManagerTest :
}
};
-TEST_F(PasswordGenerationManagerTest, UpdateState) {
+TEST_F(PasswordGenerationManagerTest, IsGenerationEnabled) {
PasswordManagerDelegateImpl::CreateForWebContents(web_contents());
PasswordManager::CreateForWebContentsAndDelegate(
web_contents(),
@@ -133,95 +119,39 @@ TEST_F(PasswordGenerationManagerTest, UpdateState) {
preferred_set.Put(syncer::PASSWORDS);
sync_service->ChangePreferredDataTypes(preferred_set);
- // Enabled state remains false, should not sent.
+ // Pref is false, should not be enabled.
prefs->SetBoolean(prefs::kPasswordGenerationEnabled, false);
- UpdateState(false);
- EXPECT_EQ(0u, password_generation_manager_->GetSentStates().size());
+ EXPECT_FALSE(IsGenerationEnabled());
- // Enabled state from false to true, should sent true.
+ // Pref is true, should be enabled.
prefs->SetBoolean(prefs::kPasswordGenerationEnabled, true);
- UpdateState(false);
- EXPECT_EQ(1u, password_generation_manager_->GetSentStates().size());
- EXPECT_TRUE(password_generation_manager_->GetSentStates()[0]);
- password_generation_manager_->ClearSentStates();
+ EXPECT_TRUE(IsGenerationEnabled());
- // Enabled states remains true, should not sent.
- prefs->SetBoolean(prefs::kPasswordGenerationEnabled, true);
- UpdateState(false);
- EXPECT_EQ(0u, password_generation_manager_->GetSentStates().size());
+ // Change syncing preferences to not include passwords. Generation should
+ // be disabled.
+ preferred_set.Put(syncer::EXTENSIONS);
+ preferred_set.Remove(syncer::PASSWORDS);
+ sync_service->ChangePreferredDataTypes(preferred_set);
+ EXPECT_FALSE(IsGenerationEnabled());
- // Enabled states from true to false, should sent false.
- prefs->SetBoolean(prefs::kPasswordGenerationEnabled, false);
- UpdateState(false);
- EXPECT_EQ(1u, password_generation_manager_->GetSentStates().size());
- EXPECT_FALSE(password_generation_manager_->GetSentStates()[0]);
- password_generation_manager_->ClearSentStates();
-
- // When a new render_view is created, we send the state even if it's the
- // same.
- UpdateState(true);
- EXPECT_EQ(1u, password_generation_manager_->GetSentStates().size());
- EXPECT_FALSE(password_generation_manager_->GetSentStates()[0]);
- password_generation_manager_->ClearSentStates();
+ // Disable syncing. Generation should also be disabled.
+ sync_service->DisableForUser();
+ EXPECT_FALSE(IsGenerationEnabled());
}
-TEST_F(PasswordGenerationManagerTest, UpdatePasswordSyncState) {
+TEST_F(PasswordGenerationManagerTest, DetectAccountCreationForms) {
+ // Setup so that IsGenerationEnabled() returns true.
PasswordManagerDelegateImpl::CreateForWebContents(web_contents());
PasswordManager::CreateForWebContentsAndDelegate(
web_contents(),
PasswordManagerDelegateImpl::FromWebContents(web_contents()));
- PrefService* prefs = profile()->GetPrefs();
-
- // Allow this test to control what should get synced.
- prefs->SetBoolean(prefs::kSyncKeepEverythingSynced, false);
- // Always set password generation enabled check box so we can test the
- // behavior of password sync.
- prefs->SetBoolean(prefs::kPasswordGenerationEnabled, true);
-
- // Sync some things, but not passwords. Shouldn't send anything since
- // password generation is disabled by default.
ProfileSyncService* sync_service = ProfileSyncServiceFactory::GetForProfile(
profile());
sync_service->SetSyncSetupCompleted();
- syncer::ModelTypeSet preferred_set;
- preferred_set.Put(syncer::EXTENSIONS);
- preferred_set.Put(syncer::PREFERENCES);
- sync_service->ChangePreferredDataTypes(preferred_set);
- syncer::ModelTypeSet new_set = sync_service->GetActiveDataTypes();
- UpdateState(false);
- EXPECT_EQ(0u, password_generation_manager_->GetSentStates().size());
- // Now sync passwords.
- preferred_set.Put(syncer::PASSWORDS);
- sync_service->ChangePreferredDataTypes(preferred_set);
- UpdateState(false);
- EXPECT_EQ(1u, password_generation_manager_->GetSentStates().size());
- EXPECT_TRUE(password_generation_manager_->GetSentStates()[0]);
- password_generation_manager_->ClearSentStates();
-
- // Add some additional synced state. Nothing should be sent.
- preferred_set.Put(syncer::THEMES);
- sync_service->ChangePreferredDataTypes(preferred_set);
- UpdateState(false);
- EXPECT_EQ(0u, password_generation_manager_->GetSentStates().size());
+ profile()->GetPrefs()->SetBoolean(prefs::kPasswordGenerationEnabled, true);
- // Disable syncing. This should disable the feature.
- sync_service->DisableForUser();
- UpdateState(false);
- EXPECT_EQ(1u, password_generation_manager_->GetSentStates().size());
- EXPECT_FALSE(password_generation_manager_->GetSentStates()[0]);
- password_generation_manager_->ClearSentStates();
-
- // When a new render_view is created, we send the state even if it's the
- // same.
- UpdateState(true);
- EXPECT_EQ(1u, password_generation_manager_->GetSentStates().size());
- EXPECT_FALSE(password_generation_manager_->GetSentStates()[0]);
- password_generation_manager_->ClearSentStates();
-}
-
-TEST_F(PasswordGenerationManagerTest, DetectAccountCreationForms) {
autofill::FormData login_form;
login_form.origin = GURL("http://www.yahoo.com/login/");
autofill::FormFieldData username;
@@ -273,8 +203,8 @@ TEST_F(PasswordGenerationManagerTest, DetectAccountCreationForms) {
TEST_F(IncognitoPasswordGenerationManagerTest,
UpdatePasswordSyncStateIncognito) {
- // Disable password manager by going incognito, and enable syncing. The
- // feature should still be disabled, and nothing will be sent.
+ // Disable password manager by going incognito. Even though syncing is
+ // enabled, generation should still be disabled.
PasswordManagerDelegateImpl::CreateForWebContents(web_contents());
PasswordManager::CreateForWebContentsAndDelegate(
web_contents(),
@@ -290,6 +220,5 @@ TEST_F(IncognitoPasswordGenerationManagerTest,
browser_sync::SyncPrefs sync_prefs(profile()->GetPrefs());
sync_prefs.SetSyncSetupCompleted();
- UpdateState(false);
- EXPECT_EQ(0u, password_generation_manager_->GetSentStates().size());
+ EXPECT_FALSE(IsGenerationEnabled());
}
diff --git a/chrome/browser/password_manager/password_store.h b/chrome/browser/password_manager/password_store.h
index 266d3a60a6..c1446705ee 100644
--- a/chrome/browser/password_manager/password_store.h
+++ b/chrome/browser/password_manager/password_store.h
@@ -18,6 +18,7 @@
class PasswordStore;
class PasswordStoreConsumer;
+class PasswordSyncableService;
class Task;
namespace autofill {
@@ -133,10 +134,15 @@ class PasswordStore
protected:
friend class base::RefCountedThreadSafe<PasswordStore>;
+ // Sync's interaction with password store needs to be syncrhonous.
+ // Since the synchronous methods are private these classes are made
+ // as friends. This can be fixed by moving the private impl to a new
+ // class. See http://crbug.com/307750
friend class browser_sync::PasswordChangeProcessor;
friend class browser_sync::PasswordDataTypeController;
friend class browser_sync::PasswordModelAssociator;
friend class browser_sync::PasswordModelWorker;
+ friend class PasswordSyncableService;
friend void passwords_helper::AddLogin(PasswordStore*,
const autofill::PasswordForm&);
friend void passwords_helper::RemoveLogin(PasswordStore*,
diff --git a/chrome/browser/password_manager/password_syncable_service.cc b/chrome/browser/password_manager/password_syncable_service.cc
index 0db6b2fa2e..67355e2a96 100644
--- a/chrome/browser/password_manager/password_syncable_service.cc
+++ b/chrome/browser/password_manager/password_syncable_service.cc
@@ -5,9 +5,83 @@
#include "chrome/browser/password_manager/password_syncable_service.h"
#include "base/location.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/password_manager/password_store.h"
+#include "components/autofill/core/common/password_form.h"
+#include "net/base/escape.h"
#include "sync/api/sync_error_factory.h"
-PasswordSyncableService::PasswordSyncableService() {
+namespace {
+
+// Converts the |PasswordSpecifics| obtained from sync to an
+// object of type |PasswordForm|.
+void ExtractPasswordFromSpecifics(
+ const sync_pb::PasswordSpecificsData& password,
+ autofill::PasswordForm* new_password) {
+ new_password->scheme =
+ static_cast<autofill::PasswordForm::Scheme>(password.scheme());
+ new_password->signon_realm = password.signon_realm();
+ new_password->origin = GURL(password.origin());
+ new_password->action = GURL(password.action());
+ new_password->username_element =
+ UTF8ToUTF16(password.username_element());
+ new_password->password_element =
+ UTF8ToUTF16(password.password_element());
+ new_password->username_value =
+ UTF8ToUTF16(password.username_value());
+ new_password->password_value =
+ UTF8ToUTF16(password.password_value());
+ new_password->ssl_valid = password.ssl_valid();
+ new_password->preferred = password.preferred();
+ new_password->date_created =
+ base::Time::FromInternalValue(password.date_created());
+ new_password->blacklisted_by_user =
+ password.blacklisted();
+}
+
+// Merges the sync password (obtained from the password specifics) and
+// local password and stores the output in the |new_password_form| pointer.
+bool MergeLocalAndSyncPasswords(
+ const sync_pb::PasswordSpecificsData& password_specifics,
+ const autofill::PasswordForm& password_form,
+ autofill::PasswordForm* new_password_form) {
+ if (password_specifics.scheme() == password_form.scheme &&
+ password_form.signon_realm == password_specifics.signon_realm() &&
+ password_form.origin.spec() == password_specifics.origin() &&
+ password_form.action.spec() == password_specifics.action() &&
+ UTF16ToUTF8(password_form.username_element) ==
+ password_specifics.username_element() &&
+ UTF16ToUTF8(password_form.password_element) ==
+ password_specifics.password_element() &&
+ UTF16ToUTF8(password_form.username_value) ==
+ password_specifics.username_value() &&
+ UTF16ToUTF8(password_form.password_value) ==
+ password_specifics.password_value() &&
+ password_specifics.ssl_valid() == password_form.ssl_valid &&
+ password_specifics.preferred() == password_form.preferred &&
+ password_specifics.date_created() ==
+ password_form.date_created.ToInternalValue() &&
+ password_specifics.blacklisted() ==
+ password_form.blacklisted_by_user) {
+ return false;
+ }
+
+ // If the passwords differ, take the one that was created more recently.
+ if (base::Time::FromInternalValue(password_specifics.date_created()) <=
+ password_form.date_created) {
+ *new_password_form = password_form;
+ } else {
+ ExtractPasswordFromSpecifics(password_specifics, new_password_form);
+ }
+
+ return true;
+}
+
+} // namespace
+
+PasswordSyncableService::PasswordSyncableService(
+ scoped_refptr<PasswordStore> password_store)
+ : password_store_(password_store) {
}
PasswordSyncableService::~PasswordSyncableService() {}
@@ -47,3 +121,88 @@ syncer::SyncError PasswordSyncableService::ProcessSyncChanges(
return error;
}
+void PasswordSyncableService::WriteToPasswordStore(
+ PasswordForms* new_entries,
+ PasswordForms* updated_entries) {
+ for (std::vector<autofill::PasswordForm*>::const_iterator it =
+ new_entries->begin();
+ it != new_entries->end();
+ ++it) {
+ password_store_->AddLoginImpl(**it);
+ }
+
+ for (std::vector<autofill::PasswordForm*>::const_iterator it =
+ updated_entries->begin();
+ it != updated_entries->end();
+ ++it) {
+ password_store_->UpdateLoginImpl(**it);
+ }
+
+ if (!new_entries->empty() || !updated_entries->empty()) {
+ // We have to notify password store observers of the change by hand since
+ // we use internal password store interfaces to make changes synchronously.
+ password_store_->PostNotifyLoginsChanged();
+ }
+}
+
+syncer::SyncData PasswordSyncableService::CreateSyncData(
+ const autofill::PasswordForm& password_form) {
+ sync_pb::EntitySpecifics password_data;
+ sync_pb::PasswordSpecificsData* password_specifics =
+ password_data.mutable_password()->mutable_client_only_encrypted_data();
+ password_specifics->set_scheme(password_form.scheme);
+ password_specifics->set_signon_realm(password_form.signon_realm);
+ password_specifics->set_origin(password_form.origin.spec());
+ password_specifics->set_action(password_form.action.spec());
+ password_specifics->set_username_element(
+ UTF16ToUTF8(password_form.username_element));
+ password_specifics->set_password_element(
+ UTF16ToUTF8(password_form.password_element));
+ password_specifics->set_username_value(
+ UTF16ToUTF8(password_form.username_value));
+ password_specifics->set_password_value(
+ UTF16ToUTF8(password_form.password_value));
+ password_specifics->set_ssl_valid(password_form.ssl_valid);
+ password_specifics->set_preferred(password_form.preferred);
+ password_specifics->set_date_created(
+ password_form.date_created.ToInternalValue());
+ password_specifics->set_blacklisted(password_form.blacklisted_by_user);
+
+ std::string tag = MakeTag(*password_specifics);
+ return syncer::SyncData::CreateLocalData(tag, tag, password_data);
+}
+
+// static
+std::string PasswordSyncableService::MakeTag(
+ const std::string& origin_url,
+ const std::string& username_element,
+ const std::string& username_value,
+ const std::string& password_element,
+ const std::string& signon_realm) {
+ return net::EscapePath(origin_url) + "|" +
+ net::EscapePath(username_element) + "|" +
+ net::EscapePath(username_value) + "|" +
+ net::EscapePath(password_element) + "|" +
+ net::EscapePath(signon_realm);
+}
+
+// static
+std::string PasswordSyncableService::MakeTag(
+ const autofill::PasswordForm& password) {
+ return MakeTag(password.origin.spec(),
+ UTF16ToUTF8(password.username_element),
+ UTF16ToUTF8(password.username_value),
+ UTF16ToUTF8(password.password_element),
+ password.signon_realm);
+}
+
+// static
+std::string PasswordSyncableService::MakeTag(
+ const sync_pb::PasswordSpecificsData& password) {
+ return MakeTag(password.origin(),
+ password.username_element(),
+ password.username_value(),
+ password.password_element(),
+ password.signon_realm());
+}
+
diff --git a/chrome/browser/password_manager/password_syncable_service.h b/chrome/browser/password_manager/password_syncable_service.h
index 4b9c27edec..dd32b2c323 100644
--- a/chrome/browser/password_manager/password_syncable_service.h
+++ b/chrome/browser/password_manager/password_syncable_service.h
@@ -5,21 +5,36 @@
#ifndef CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_SYNCABLE_SERVICE_H__
#define CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_SYNCABLE_SERVICE_H__
+#include <string>
+#include <vector>
+
#include "base/memory/scoped_ptr.h"
#include "sync/api/sync_change.h"
#include "sync/api/sync_data.h"
#include "sync/api/sync_error.h"
#include "sync/api/syncable_service.h"
+#include "sync/protocol/password_specifics.pb.h"
+#include "sync/protocol/sync.pb.h"
+
+namespace autofill {
+struct PasswordForm;
+}
namespace syncer {
class SyncErrorFactory;
-} // namespace syncer
+}
class PasswordStore;
class PasswordSyncableService : public syncer::SyncableService {
public:
- PasswordSyncableService();
+ // TODO(lipalani) - The |PasswordStore| should outlive
+ // |PasswordSyncableService| and there should be a code
+ // guarantee to that effect. Currently this object is not instantiated.
+ // When this class is completed and instantiated the object lifetime
+ // guarantee will be implemented.
+ explicit PasswordSyncableService(
+ scoped_refptr<PasswordStore> password_store);
virtual ~PasswordSyncableService();
// syncer::SyncableServiceImplementations
@@ -35,9 +50,35 @@ class PasswordSyncableService : public syncer::SyncableService {
const tracked_objects::Location& from_here,
const syncer::SyncChangeList& change_list) OVERRIDE;
+ // Returns the unique tag that will serve as the sync identifier for the
+ // |password| entry.
+ static std::string MakeTag(const autofill::PasswordForm& password);
+ static std::string MakeTag(const sync_pb::PasswordSpecificsData& password);
+ static std::string MakeTag(const std::string& origin_url,
+ const std::string& username_element,
+ const std::string& username_value,
+ const std::string& password_element,
+ const std::string& signon_realm);
+
private:
+ typedef std::vector<autofill::PasswordForm*> PasswordForms;
+
+ // Use the |PasswordStore| APIs to add and update entries.
+ void WriteToPasswordStore(PasswordForms* new_entries,
+ PasswordForms* udpated_entries);
+
+ // Converts the |PasswordForm| to |SyncData| suitable for syncing.
+ syncer::SyncData CreateSyncData(const autofill::PasswordForm& password);
+
+ // The factory that creates sync errors. |SyncError| has rich data
+ // suitable for debugging.
scoped_ptr<syncer::SyncErrorFactory> sync_error_factory_;
+
+ // |SyncProcessor| will mirror the |PasswordStore| changes in the sync db.
scoped_ptr<syncer::SyncChangeProcessor> sync_processor_;
+
+ // The password store that adds/updates/deletes password entries.
+ scoped_refptr<PasswordStore> password_store_;
};
#endif // CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_SYNCABLE_SERVICE_H__
diff --git a/chrome/browser/plugins/chrome_plugin_service_filter.cc b/chrome/browser/plugins/chrome_plugin_service_filter.cc
index c4663801ad..992cd2b2e1 100644
--- a/chrome/browser/plugins/chrome_plugin_service_filter.cc
+++ b/chrome/browser/plugins/chrome_plugin_service_filter.cc
@@ -67,6 +67,12 @@ void ChromePluginServiceFilter::UnrestrictPlugin(
restricted_plugins_.erase(plugin_path);
}
+bool ChromePluginServiceFilter::IsPluginRestricted(
+ const base::FilePath& plugin_path) {
+ base::AutoLock auto_lock(lock_);
+ return restricted_plugins_.find(plugin_path) != restricted_plugins_.end();
+}
+
bool ChromePluginServiceFilter::IsPluginAvailable(
int render_process_id,
int render_view_id,
diff --git a/chrome/browser/plugins/chrome_plugin_service_filter.h b/chrome/browser/plugins/chrome_plugin_service_filter.h
index 513b1ff49b..ed53fdba96 100644
--- a/chrome/browser/plugins/chrome_plugin_service_filter.h
+++ b/chrome/browser/plugins/chrome_plugin_service_filter.h
@@ -58,6 +58,9 @@ class ChromePluginServiceFilter : public content::PluginServiceFilter,
// Authorizes all plug-ins for a given process.
void AuthorizeAllPlugins(int render_process_id);
+ // Returns whether the plugin is found in restricted_plugins_.
+ bool IsPluginRestricted(const base::FilePath& plugin_path);
+
// PluginServiceFilter implementation:
virtual bool IsPluginAvailable(
int render_process_id,
diff --git a/chrome/browser/plugins/plugin_info_message_filter.cc b/chrome/browser/plugins/plugin_info_message_filter.cc
index 92be4e9190..d75fe336a0 100644
--- a/chrome/browser/plugins/plugin_info_message_filter.cc
+++ b/chrome/browser/plugins/plugin_info_message_filter.cc
@@ -254,7 +254,9 @@ void PluginInfoMessageFilter::Context::DecidePluginStatus(
plugin_setting != CONTENT_SETTING_BLOCK &&
uses_default_content_setting &&
plugin_policy != PluginPrefs::POLICY_ENABLED &&
- group_policy != PluginPrefs::POLICY_ENABLED) {
+ group_policy != PluginPrefs::POLICY_ENABLED &&
+ !ChromePluginServiceFilter::GetInstance()->IsPluginRestricted(
+ plugin.path)) {
status->value = ChromeViewHostMsg_GetPluginInfo_Status::kBlocked;
return;
}
diff --git a/chrome/browser/policy/DEPS b/chrome/browser/policy/DEPS
index 31e99bfee6..0532c01027 100644
--- a/chrome/browser/policy/DEPS
+++ b/chrome/browser/policy/DEPS
@@ -44,16 +44,8 @@ specific_include_rules = {
r"configuration_policy_handler\.cc": [
"+chrome/browser/chrome_notification_types.h",
- "+chrome/browser/download/download_prefs.h",
- "+chrome/browser/extensions/external_policy_loader.h",
"+chrome/browser/policy/policy_path_parser.h",
- "+chrome/browser/prefs/proxy_config_dictionary.h",
- "+chrome/browser/prefs/proxy_prefs.h",
"+chrome/browser/prefs/session_startup_pref.h",
- "+chrome/browser/search_engines/search_terms_data.h",
- "+chrome/browser/search_engines/template_url.h",
- "+chrome/common/extensions/extension.h",
- "+content/public/browser/notification_service.h",
],
r"configuration_policy_handler\.h": [
@@ -61,13 +53,8 @@ specific_include_rules = {
"+chrome/common/content_settings.h",
],
- r"configuration_policy_handler_unittest\.cc": [
- "+chrome/browser/extensions/external_policy_loader.h",
- ],
-
r"configuration_policy_pref_store_unittest\.cc": [
"+chrome/browser/prefs/incognito_mode_prefs.h",
- "+chrome/browser/prefs/proxy_config_dictionary.h",
"+chrome/common/content_settings.h",
"+chrome/common/pref_names.h",
],
diff --git a/chrome/browser/policy/browser_policy_connector.cc b/chrome/browser/policy/browser_policy_connector.cc
index 6eb74685bf..4d99d09dda 100644
--- a/chrome/browser/policy/browser_policy_connector.cc
+++ b/chrome/browser/policy/browser_policy_connector.cc
@@ -17,11 +17,13 @@
#include "base/path_service.h"
#include "base/prefs/pref_registry_simple.h"
#include "base/prefs/pref_service.h"
+#include "base/sequenced_task_runner.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/sys_info.h"
+#include "base/threading/sequenced_worker_pool.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/policy/async_policy_provider.h"
#include "chrome/browser/policy/cloud/cloud_policy_client.h"
@@ -36,6 +38,7 @@
#include "chrome/common/chrome_switches.h"
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/pref_names.h"
+#include "components/policy/core/common/policy_pref_names.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/content_client.h"
#include "google_apis/gaia/gaia_auth_util.h"
@@ -70,7 +73,7 @@
#include "chrome/browser/chromeos/settings/device_settings_service.h"
#include "chromeos/chromeos_paths.h"
#include "chromeos/chromeos_switches.h"
-#include "chromeos/cryptohome/cryptohome_library.h"
+#include "chromeos/cryptohome/system_salt_getter.h"
#include "chromeos/dbus/cryptohome_client.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/network/network_handler.h"
@@ -98,6 +101,14 @@ const char kDefaultDeviceManagementServerUrl[] =
// Used in BrowserPolicyConnector::SetPolicyProviderForTesting.
ConfigurationPolicyProvider* g_testing_provider = NULL;
+// Helper that returns a new SequencedTaskRunner backed by the blocking pool.
+// Each SequencedTaskRunner returned is independent from the others.
+scoped_refptr<base::SequencedTaskRunner> GetBackgroundTaskRunner() {
+ base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool();
+ CHECK(pool);
+ return pool->GetSequencedTaskRunnerWithShutdownBehavior(
+ pool->GetSequenceToken(), base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+}
#if defined(OS_MACOSX) && !defined(OS_IOS)
base::FilePath GetManagedPolicyPath() {
@@ -198,11 +209,11 @@ BrowserPolicyConnector::BrowserPolicyConnector()
platform_provider_.reset(CreatePlatformProvider());
#if defined(OS_CHROMEOS)
- // CryptohomeLibrary or DBusThreadManager may be uninitialized on unit tests.
+ // SystemSaltGetter or DBusThreadManager may be uninitialized on unit tests.
- // TODO(satorux): Remove CryptohomeLibrary::IsInitialized() when it's ready
+ // TODO(satorux): Remove SystemSaltGetter::IsInitialized() when it's ready
// (removing it now breaks tests). crbug.com/141016.
- if (chromeos::CryptohomeLibrary::IsInitialized() &&
+ if (chromeos::SystemSaltGetter::IsInitialized() &&
chromeos::DBusThreadManager::IsInitialized()) {
chromeos::CryptohomeClient* cryptohome_client =
chromeos::DBusThreadManager::Get()->GetCryptohomeClient();
@@ -216,11 +227,13 @@ BrowserPolicyConnector::BrowserPolicyConnector()
scoped_ptr<DeviceCloudPolicyStoreChromeOS> device_cloud_policy_store(
new DeviceCloudPolicyStoreChromeOS(
chromeos::DeviceSettingsService::Get(),
- install_attributes_.get()));
+ install_attributes_.get(),
+ GetBackgroundTaskRunner()));
device_cloud_policy_manager_.reset(
new DeviceCloudPolicyManagerChromeOS(
device_cloud_policy_store.Pass(),
base::MessageLoopProxy::current(),
+ GetBackgroundTaskRunner(),
install_attributes_.get()));
}
#endif
@@ -281,7 +294,9 @@ void BrowserPolicyConnector::Init(
new DeviceLocalAccountPolicyService(
chromeos::DBusThreadManager::Get()->GetSessionManagerClient(),
chromeos::DeviceSettingsService::Get(),
- chromeos::CrosSettings::Get()));
+ chromeos::CrosSettings::Get(),
+ GetBackgroundTaskRunner(),
+ GetBackgroundTaskRunner()));
device_local_account_policy_service_->Connect(
device_management_service_.get());
}
@@ -502,7 +517,7 @@ bool BrowserPolicyConnector::IsNonEnterpriseUser(const std::string& username) {
// static
void BrowserPolicyConnector::RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterIntegerPref(
- prefs::kUserPolicyRefreshRate,
+ policy_prefs::kUserPolicyRefreshRate,
CloudPolicyRefreshScheduler::kDefaultRefreshDelayMs);
#if defined(OS_CHROMEOS)
registry->RegisterIntegerPref(
diff --git a/chrome/browser/policy/cloud/DEPS b/chrome/browser/policy/cloud/DEPS
index e806e8000c..cab579f5e9 100644
--- a/chrome/browser/policy/cloud/DEPS
+++ b/chrome/browser/policy/cloud/DEPS
@@ -37,27 +37,8 @@ specific_include_rules = {
],
# TODO(joaodasilva): remove these exceptions.
- r"cloud_external_data_manager_base_unittest\.cc": [
- "+content/public/test/test_browser_thread_bundle.h",
- ],
-
- r"cloud_policy_client_registration_helper\.cc": [
- "+chrome/browser/signin/android_profile_oauth2_token_service.h",
- "+chrome/browser/signin/oauth2_token_service.h",
- ],
-
- r"cloud_policy_constants\.cc": [
- "+chrome/common/chrome_switches.h",
- ],
-
- r"cloud_policy_core_unittest\.cc": [
- "+chrome/browser/prefs/browser_prefs.h",
- "+chrome/common/pref_names.h",
- ],
-
r"cloud_policy_invalidator\.cc": [
"+chrome/browser/invalidation/invalidation_service.h",
- "+chrome/common/chrome_switches.h",
],
r"cloud_policy_invalidator_unittest\.cc": [
@@ -68,32 +49,7 @@ specific_include_rules = {
"+chrome/browser/invalidation/fake_invalidation_service.h",
],
- r"cloud_policy_refresh_scheduler\.cc": [
- "+chrome/browser/chrome_notification_types.h",
- "+chrome/common/chrome_switches.h",
- "+content/public/browser/notification_details.h",
- ],
-
- r"cloud_policy_refresh_scheduler_unittest\.cc": [
- "+chrome/browser/prefs/browser_prefs.h",
- ],
-
- r"cloud_policy_validator\.cc": [
- "+content/public/browser/browser_thread.h",
- ],
-
- r"cloud_policy_validator_unittest\.cc": [
- "+content/public/test/test_browser_thread.h",
- ],
-
- r"component_cloud_policy_service_unittest\.cc": [
- "+content/public/browser/browser_thread.h",
- "+content/public/test/test_browser_thread.h",
- ],
-
r"test_request_interceptor\.cc": [
- "+content/public/browser/browser_thread.h",
- "+content/public/test/test_utils.h",
"+content/test/net/url_request_mock_http_job.h",
],
@@ -106,7 +62,6 @@ specific_include_rules = {
r"user_cloud_policy_invalidator_factory\.cc": [
"+chrome/browser/invalidation/invalidation_service_factory.h",
"+chrome/browser/profiles/profile.h",
- "+chrome/common/chrome_switches.h",
"+chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h",
"+chrome/browser/chromeos/policy/user_cloud_policy_manager_factory_chromeos.h",
],
@@ -116,20 +71,14 @@ specific_include_rules = {
"+content/public/browser/notification_registrar.h",
],
- r"user_cloud_policy_manager\.cc": [
- "+chrome/common/pref_names.h",
- ],
-
r"user_cloud_policy_manager_factory\.cc": [
"+chrome/browser/profiles/profile.h",
- "+chrome/common/chrome_switches.h",
],
r"user_cloud_policy_store\.cc": [
"+chrome/browser/profiles/profile.h",
"+chrome/browser/signin/signin_manager.h",
"+chrome/browser/signin/signin_manager_factory.h",
- "+content/public/browser/browser_thread.h",
],
r"user_cloud_policy_store_unittest\.cc": [
@@ -138,6 +87,5 @@ specific_include_rules = {
"+chrome/browser/signin/signin_manager_factory.h",
"+chrome/common/pref_names.h",
"+chrome/test/base/testing_profile.h",
- "+content/public/test/test_browser_thread.h",
],
}
diff --git a/chrome/browser/policy/cloud/cloud_policy_constants.cc b/chrome/browser/policy/cloud/cloud_policy_constants.cc
index 33c8b4f49e..bc45143e5a 100644
--- a/chrome/browser/policy/cloud/cloud_policy_constants.cc
+++ b/chrome/browser/policy/cloud/cloud_policy_constants.cc
@@ -5,7 +5,7 @@
#include "chrome/browser/policy/cloud/cloud_policy_constants.h"
#include "base/command_line.h"
-#include "chrome/common/chrome_switches.h"
+#include "components/policy/core/common/policy_switches.h"
namespace policy {
diff --git a/chrome/browser/policy/cloud/cloud_policy_core_unittest.cc b/chrome/browser/policy/cloud/cloud_policy_core_unittest.cc
index ef0313ed60..7d57735141 100644
--- a/chrome/browser/policy/cloud/cloud_policy_core_unittest.cc
+++ b/chrome/browser/policy/cloud/cloud_policy_core_unittest.cc
@@ -6,13 +6,13 @@
#include "base/basictypes.h"
#include "base/message_loop/message_loop.h"
+#include "base/prefs/pref_registry_simple.h"
#include "base/prefs/testing_pref_service.h"
#include "chrome/browser/policy/cloud/cloud_policy_constants.h"
#include "chrome/browser/policy/cloud/cloud_policy_refresh_scheduler.h"
#include "chrome/browser/policy/cloud/mock_cloud_policy_client.h"
#include "chrome/browser/policy/cloud/mock_cloud_policy_store.h"
-#include "chrome/browser/prefs/browser_prefs.h"
-#include "chrome/common/pref_names.h"
+#include "components/policy/core/common/policy_pref_names.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace policy {
@@ -29,7 +29,9 @@ class CloudPolicyCoreTest : public testing::Test,
refresh_scheduler_started_callback_count_(0),
core_disconnecting_callback_count_(0),
bad_callback_count_(0) {
- chrome::RegisterLocalState(prefs_.registry());
+ prefs_.registry()->RegisterIntegerPref(
+ policy_prefs::kUserPolicyRefreshRate,
+ CloudPolicyRefreshScheduler::kDefaultRefreshDelayMs);
core_.AddObserver(this);
}
@@ -120,11 +122,11 @@ TEST_F(CloudPolicyCoreTest, RefreshScheduler) {
int default_refresh_delay = core_.refresh_scheduler()->refresh_delay();
const int kRefreshRate = 1000 * 60 * 60;
- prefs_.SetInteger(prefs::kUserPolicyRefreshRate, kRefreshRate);
- core_.TrackRefreshDelayPref(&prefs_, prefs::kUserPolicyRefreshRate);
+ prefs_.SetInteger(policy_prefs::kUserPolicyRefreshRate, kRefreshRate);
+ core_.TrackRefreshDelayPref(&prefs_, policy_prefs::kUserPolicyRefreshRate);
EXPECT_EQ(kRefreshRate, core_.refresh_scheduler()->refresh_delay());
- prefs_.ClearPref(prefs::kUserPolicyRefreshRate);
+ prefs_.ClearPref(policy_prefs::kUserPolicyRefreshRate);
EXPECT_EQ(default_refresh_delay, core_.refresh_scheduler()->refresh_delay());
EXPECT_EQ(1, core_connected_callback_count_);
diff --git a/chrome/browser/policy/cloud/cloud_policy_invalidator.cc b/chrome/browser/policy/cloud/cloud_policy_invalidator.cc
index c55409b40d..b71b934042 100644
--- a/chrome/browser/policy/cloud/cloud_policy_invalidator.cc
+++ b/chrome/browser/policy/cloud/cloud_policy_invalidator.cc
@@ -18,7 +18,7 @@
#include "chrome/browser/policy/cloud/cloud_policy_client.h"
#include "chrome/browser/policy/cloud/cloud_policy_refresh_scheduler.h"
#include "chrome/browser/policy/cloud/enterprise_metrics.h"
-#include "chrome/common/chrome_switches.h"
+#include "components/policy/core/common/policy_switches.h"
#include "policy/policy_constants.h"
#include "sync/notifier/object_id_invalidation_map.h"
diff --git a/chrome/browser/policy/cloud/cloud_policy_manager_browsertest.cc b/chrome/browser/policy/cloud/cloud_policy_manager_browsertest.cc
index 8c4967cd95..7e0085c5a4 100644
--- a/chrome/browser/policy/cloud/cloud_policy_manager_browsertest.cc
+++ b/chrome/browser/policy/cloud/cloud_policy_manager_browsertest.cc
@@ -16,6 +16,7 @@
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/in_process_browser_test.h"
+#include "content/public/browser/browser_thread.h"
#include "net/base/net_errors.h"
#include "net/url_request/url_request_context_getter.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -31,6 +32,7 @@
#include "chrome/browser/signin/signin_manager_factory.h"
#endif
+using content::BrowserThread;
using testing::AnyNumber;
using testing::InvokeWithoutArgs;
using testing::Mock;
@@ -57,7 +59,9 @@ class CloudPolicyManagerTest : public InProcessBrowserTest {
ASSERT_TRUE(PolicyServiceIsEmpty(g_browser_process->policy_service()))
<< "Pre-existing policies in this machine will make this test fail.";
- interceptor_.reset(new TestRequestInterceptor("localhost"));
+ interceptor_.reset(new TestRequestInterceptor(
+ "localhost",
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)));
BrowserPolicyConnector* connector =
g_browser_process->browser_policy_connector();
diff --git a/chrome/browser/policy/cloud/cloud_policy_refresh_scheduler.cc b/chrome/browser/policy/cloud/cloud_policy_refresh_scheduler.cc
index 1af14990d6..aaf1c2964c 100644
--- a/chrome/browser/policy/cloud/cloud_policy_refresh_scheduler.cc
+++ b/chrome/browser/policy/cloud/cloud_policy_refresh_scheduler.cc
@@ -14,10 +14,8 @@
#include "base/sequenced_task_runner.h"
#include "base/time/default_tick_clock.h"
#include "base/time/tick_clock.h"
-#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/policy/cloud/cloud_policy_constants.h"
-#include "chrome/common/chrome_switches.h"
-#include "content/public/browser/notification_details.h"
+#include "components/policy/core/common/policy_switches.h"
namespace policy {
diff --git a/chrome/browser/policy/cloud/cloud_policy_refresh_scheduler.h b/chrome/browser/policy/cloud/cloud_policy_refresh_scheduler.h
index 675f964890..a3d121b246 100644
--- a/chrome/browser/policy/cloud/cloud_policy_refresh_scheduler.h
+++ b/chrome/browser/policy/cloud/cloud_policy_refresh_scheduler.h
@@ -37,7 +37,7 @@ class CloudPolicyRefreshScheduler
static const int64 kRefreshDelayMinMs;
static const int64 kRefreshDelayMaxMs;
- // |client|, |store| and |prefs| pointers must stay valid throughout the
+ // |client| and |store| pointers must stay valid throughout the
// lifetime of CloudPolicyRefreshScheduler.
CloudPolicyRefreshScheduler(
CloudPolicyClient* client,
diff --git a/chrome/browser/policy/cloud/cloud_policy_refresh_scheduler_unittest.cc b/chrome/browser/policy/cloud/cloud_policy_refresh_scheduler_unittest.cc
index 6f5cc3529c..85a256dce2 100644
--- a/chrome/browser/policy/cloud/cloud_policy_refresh_scheduler_unittest.cc
+++ b/chrome/browser/policy/cloud/cloud_policy_refresh_scheduler_unittest.cc
@@ -12,7 +12,6 @@
#include "chrome/browser/policy/cloud/cloud_policy_refresh_scheduler.h"
#include "chrome/browser/policy/cloud/mock_cloud_policy_client.h"
#include "chrome/browser/policy/cloud/mock_cloud_policy_store.h"
-#include "chrome/browser/prefs/browser_prefs.h"
#include "policy/policy_constants.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/policy/cloud/cloud_policy_validator.cc b/chrome/browser/policy/cloud/cloud_policy_validator.cc
index b45392e201..71649cea9a 100644
--- a/chrome/browser/policy/cloud/cloud_policy_validator.cc
+++ b/chrome/browser/policy/cloud/cloud_policy_validator.cc
@@ -6,10 +6,10 @@
#include "base/bind_helpers.h"
#include "base/message_loop/message_loop.h"
+#include "base/sequenced_task_runner.h"
#include "base/stl_util.h"
#include "chrome/browser/policy/cloud/cloud_policy_constants.h"
#include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
-#include "content/public/browser/browser_thread.h"
#include "crypto/signature_verifier.h"
#include "google_apis/gaia/gaia_auth_util.h"
@@ -114,7 +114,8 @@ void CloudPolicyValidatorBase::ValidateAgainstCurrentPolicy(
CloudPolicyValidatorBase::CloudPolicyValidatorBase(
scoped_ptr<em::PolicyFetchResponse> policy_response,
- google::protobuf::MessageLite* payload)
+ google::protobuf::MessageLite* payload,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner)
: status_(VALIDATION_OK),
policy_(policy_response.Pass()),
payload_(payload),
@@ -123,12 +124,13 @@ CloudPolicyValidatorBase::CloudPolicyValidatorBase(
timestamp_not_after_(0),
timestamp_option_(TIMESTAMP_REQUIRED),
dm_token_option_(DM_TOKEN_REQUIRED),
- allow_key_rotation_(false) {}
+ allow_key_rotation_(false),
+ background_task_runner_(background_task_runner) {}
void CloudPolicyValidatorBase::PostValidationTask(
const base::Closure& completion_callback) {
- content::BrowserThread::PostTask(
- content::BrowserThread::FILE, FROM_HERE,
+ background_task_runner_->PostTask(
+ FROM_HERE,
base::Bind(&CloudPolicyValidatorBase::PerformValidation,
base::Passed(scoped_ptr<CloudPolicyValidatorBase>(this)),
base::MessageLoop::current()->message_loop_proxy(),
diff --git a/chrome/browser/policy/cloud/cloud_policy_validator.h b/chrome/browser/policy/cloud/cloud_policy_validator.h
index 2635e4a29a..5b6ed4bd4f 100644
--- a/chrome/browser/policy/cloud/cloud_policy_validator.h
+++ b/chrome/browser/policy/cloud/cloud_policy_validator.h
@@ -13,6 +13,7 @@
#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+#include "base/sequenced_task_runner.h"
#include "base/time/time.h"
#include "chrome/browser/policy/proto/cloud/chrome_extension_policy.pb.h"
#include "policy/proto/cloud_policy.pb.h"
@@ -35,7 +36,7 @@ class PolicyFetchResponse;
namespace policy {
// Helper class that implements the gory details of validating a policy blob.
-// Since signature checks are expensive, validation can happen on the FILE
+// Since signature checks are expensive, validation can happen on a background
// thread. The pattern is to create a validator, configure its behavior through
// the ValidateXYZ() functions, and then call StartValidation(). Alternatively,
// RunValidation() can be used to perform validation on the current thread.
@@ -171,7 +172,8 @@ class CloudPolicyValidatorBase {
// valid for the lifetime of the validator.
CloudPolicyValidatorBase(
scoped_ptr<enterprise_management::PolicyFetchResponse> policy_response,
- google::protobuf::MessageLite* payload);
+ google::protobuf::MessageLite* payload,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner);
// Posts an asynchronous calls to PerformValidation, which will eventually
// report its result via |completion_callback|.
@@ -237,6 +239,7 @@ class CloudPolicyValidatorBase {
std::string settings_entity_id_;
std::string key_;
bool allow_key_rotation_;
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
DISALLOW_COPY_AND_ASSIGN(CloudPolicyValidatorBase);
};
@@ -252,11 +255,15 @@ class CloudPolicyValidator : public CloudPolicyValidatorBase {
virtual ~CloudPolicyValidator() {}
// Creates a new validator.
+ // |background_task_runner| is optional; if RunValidation() is used directly
+ // and StartValidation() is not used then it can be NULL.
static CloudPolicyValidator<PayloadProto>* Create(
- scoped_ptr<enterprise_management::PolicyFetchResponse> policy_response) {
+ scoped_ptr<enterprise_management::PolicyFetchResponse> policy_response,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner) {
return new CloudPolicyValidator(
policy_response.Pass(),
- scoped_ptr<PayloadProto>(new PayloadProto()));
+ scoped_ptr<PayloadProto>(new PayloadProto()),
+ background_task_runner);
}
scoped_ptr<PayloadProto>& payload() {
@@ -274,8 +281,11 @@ class CloudPolicyValidator : public CloudPolicyValidatorBase {
private:
CloudPolicyValidator(
scoped_ptr<enterprise_management::PolicyFetchResponse> policy_response,
- scoped_ptr<PayloadProto> payload)
- : CloudPolicyValidatorBase(policy_response.Pass(), payload.get()),
+ scoped_ptr<PayloadProto> payload,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner)
+ : CloudPolicyValidatorBase(policy_response.Pass(),
+ payload.get(),
+ background_task_runner),
payload_(payload.Pass()) {}
scoped_ptr<PayloadProto> payload_;
diff --git a/chrome/browser/policy/cloud/cloud_policy_validator_unittest.cc b/chrome/browser/policy/cloud/cloud_policy_validator_unittest.cc
index 1efe9a6c30..88f9f48440 100644
--- a/chrome/browser/policy/cloud/cloud_policy_validator_unittest.cc
+++ b/chrome/browser/policy/cloud/cloud_policy_validator_unittest.cc
@@ -7,11 +7,11 @@
#include "base/bind.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_proxy.h"
#include "base/strings/string_util.h"
#include "chrome/browser/policy/cloud/cloud_policy_constants.h"
#include "chrome/browser/policy/cloud/cloud_policy_validator.h"
#include "chrome/browser/policy/cloud/policy_builder.h"
-#include "content/public/test/test_browser_thread.h"
#include "crypto/rsa_private_key.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -39,8 +39,7 @@ class CloudPolicyValidatorTest : public testing::Test {
timestamp_option_(CloudPolicyValidatorBase::TIMESTAMP_REQUIRED),
ignore_missing_dm_token_(CloudPolicyValidatorBase::DM_TOKEN_REQUIRED),
allow_key_rotation_(true),
- existing_dm_token_(PolicyBuilder::kFakeToken),
- file_thread_(content::BrowserThread::FILE, &loop_) {
+ existing_dm_token_(PolicyBuilder::kFakeToken) {
policy_.SetDefaultNewSigningKey();
}
@@ -64,8 +63,8 @@ class CloudPolicyValidatorTest : public testing::Test {
PolicyBuilder::CreateTestSigningKey()->ExportPublicKey(&public_key));
policy_.Build();
- UserCloudPolicyValidator* validator =
- UserCloudPolicyValidator::Create(policy_.GetCopy());
+ UserCloudPolicyValidator* validator = UserCloudPolicyValidator::Create(
+ policy_.GetCopy(), base::MessageLoopProxy::current());
validator->ValidateTimestamp(timestamp_, timestamp_,
timestamp_option_);
validator->ValidateUsername(PolicyBuilder::kFakeUsername);
@@ -103,8 +102,6 @@ class CloudPolicyValidatorTest : public testing::Test {
private:
MOCK_METHOD1(ValidationCompletion, void(UserCloudPolicyValidator* validator));
- content::TestBrowserThread file_thread_;
-
DISALLOW_COPY_AND_ASSIGN(CloudPolicyValidatorTest);
};
diff --git a/chrome/browser/policy/cloud/component_cloud_policy_service_unittest.cc b/chrome/browser/policy/cloud/component_cloud_policy_service_unittest.cc
index deb7724cd7..b4fa459e80 100644
--- a/chrome/browser/policy/cloud/component_cloud_policy_service_unittest.cc
+++ b/chrome/browser/policy/cloud/component_cloud_policy_service_unittest.cc
@@ -25,8 +25,6 @@
#include "chrome/browser/policy/proto/cloud/chrome_extension_policy.pb.h"
#include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
#include "components/policy/core/common/schema.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/test/test_browser_thread.h"
#include "net/url_request/test_url_fetcher_factory.h"
#include "net/url_request/url_fetcher_delegate.h"
#include "net/url_request/url_request_context.h"
@@ -99,9 +97,7 @@ class TestURLRequestContextGetter : public net::URLRequestContextGetter {
class ComponentCloudPolicyServiceTest : public testing::Test {
protected:
- ComponentCloudPolicyServiceTest()
- : ui_thread_(content::BrowserThread::UI, &loop_),
- file_thread_(content::BrowserThread::FILE, &loop_) {}
+ ComponentCloudPolicyServiceTest() {}
virtual void SetUp() OVERRIDE {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
@@ -200,8 +196,6 @@ class ComponentCloudPolicyServiceTest : public testing::Test {
}
base::MessageLoop loop_;
- content::TestBrowserThread ui_thread_;
- content::TestBrowserThread file_thread_;
base::ScopedTempDir temp_dir_;
scoped_refptr<TestURLRequestContextGetter> request_context_;
net::TestURLFetcherFactory fetcher_factory_;
diff --git a/chrome/browser/policy/cloud/component_cloud_policy_store.cc b/chrome/browser/policy/cloud/component_cloud_policy_store.cc
index 334f9d6dc2..e049c3b011 100644
--- a/chrome/browser/policy/cloud/component_cloud_policy_store.cc
+++ b/chrome/browser/policy/cloud/component_cloud_policy_store.cc
@@ -261,7 +261,8 @@ bool ComponentCloudPolicyStore::ValidateProto(
return false;
scoped_ptr<ComponentCloudPolicyValidator> validator(
- ComponentCloudPolicyValidator::Create(proto.Pass()));
+ ComponentCloudPolicyValidator::Create(
+ proto.Pass(), scoped_refptr<base::SequencedTaskRunner>()));
validator->ValidateUsername(username_);
validator->ValidateDMToken(dm_token_,
ComponentCloudPolicyValidator::DM_TOKEN_REQUIRED);
diff --git a/chrome/browser/policy/cloud/device_management_service_browsertest.cc b/chrome/browser/policy/cloud/device_management_service_browsertest.cc
index 478629d2a2..1319048f82 100644
--- a/chrome/browser/policy/cloud/device_management_service_browsertest.cc
+++ b/chrome/browser/policy/cloud/device_management_service_browsertest.cc
@@ -98,7 +98,9 @@ class DeviceManagementServiceIntegrationTest
const em::DeviceManagementResponse&));
std::string InitCannedResponse() {
- interceptor_.reset(new TestRequestInterceptor("localhost"));
+ interceptor_.reset(new TestRequestInterceptor(
+ "localhost",
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)));
return "http://localhost";
}
diff --git a/chrome/browser/policy/cloud/mock_user_cloud_policy_store.cc b/chrome/browser/policy/cloud/mock_user_cloud_policy_store.cc
index 9c687ecb1a..75b5366192 100644
--- a/chrome/browser/policy/cloud/mock_user_cloud_policy_store.cc
+++ b/chrome/browser/policy/cloud/mock_user_cloud_policy_store.cc
@@ -7,7 +7,9 @@
namespace policy {
MockUserCloudPolicyStore::MockUserCloudPolicyStore()
- : UserCloudPolicyStore(NULL, base::FilePath()) {}
+ : UserCloudPolicyStore(NULL,
+ base::FilePath(),
+ scoped_refptr<base::SequencedTaskRunner>()) {}
MockUserCloudPolicyStore::~MockUserCloudPolicyStore() {}
diff --git a/chrome/browser/policy/cloud/test_request_interceptor.cc b/chrome/browser/policy/cloud/test_request_interceptor.cc
index 9e254a4a94..55492c06df 100644
--- a/chrome/browser/policy/cloud/test_request_interceptor.cc
+++ b/chrome/browser/policy/cloud/test_request_interceptor.cc
@@ -10,8 +10,8 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/memory/scoped_ptr.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/test/test_utils.h"
+#include "base/run_loop.h"
+#include "base/sequenced_task_runner.h"
#include "content/test/net/url_request_mock_http_job.h"
#include "net/base/net_errors.h"
#include "net/base/upload_bytes_element_reader.h"
@@ -29,12 +29,6 @@ namespace policy {
namespace {
-// Helper to execute a |task| on IO, and return only after it has completed.
-void PostToIOAndWait(const base::Closure& task) {
- content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, task);
- content::RunAllPendingInMessageLoop(content::BrowserThread::IO);
-}
-
// Helper callback for jobs that should fail with a network |error|.
net::URLRequestJob* ErrorJobCallback(int error,
net::URLRequest* request,
@@ -154,7 +148,8 @@ net::URLRequestJob* RegisterJobCallback(
class TestRequestInterceptor::Delegate
: public net::URLRequestJobFactory::ProtocolHandler {
public:
- explicit Delegate(const std::string& hostname);
+ Delegate(const std::string& hostname,
+ scoped_refptr<base::SequencedTaskRunner> io_task_runner);
virtual ~Delegate();
// ProtocolHandler implementation:
@@ -167,6 +162,7 @@ class TestRequestInterceptor::Delegate
private:
const std::string hostname_;
+ scoped_refptr<base::SequencedTaskRunner> io_task_runner_;
// The queue of pending callbacks. 'mutable' because MaybeCreateJob() is a
// const method; it can't reenter though, because it runs exclusively on
@@ -174,15 +170,17 @@ class TestRequestInterceptor::Delegate
mutable std::queue<JobCallback> pending_job_callbacks_;
};
-TestRequestInterceptor::Delegate::Delegate(const std::string& hostname)
- : hostname_(hostname) {}
+TestRequestInterceptor::Delegate::Delegate(
+ const std::string& hostname,
+ scoped_refptr<base::SequencedTaskRunner> io_task_runner)
+ : hostname_(hostname), io_task_runner_(io_task_runner) {}
TestRequestInterceptor::Delegate::~Delegate() {}
net::URLRequestJob* TestRequestInterceptor::Delegate::MaybeCreateJob(
net::URLRequest* request,
net::NetworkDelegate* network_delegate) const {
- CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+ CHECK(io_task_runner_->RunsTasksOnCurrentThread());
if (request->url().host() != hostname_) {
// Reject requests to other servers.
@@ -202,19 +200,21 @@ net::URLRequestJob* TestRequestInterceptor::Delegate::MaybeCreateJob(
void TestRequestInterceptor::Delegate::GetPendingSize(
size_t* pending_size) const {
- CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+ CHECK(io_task_runner_->RunsTasksOnCurrentThread());
*pending_size = pending_job_callbacks_.size();
}
void TestRequestInterceptor::Delegate::PushJobCallback(
const JobCallback& callback) {
- CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+ CHECK(io_task_runner_->RunsTasksOnCurrentThread());
pending_job_callbacks_.push(callback);
}
-TestRequestInterceptor::TestRequestInterceptor(const std::string& hostname)
- : hostname_(hostname) {
- delegate_ = new Delegate(hostname_);
+TestRequestInterceptor::TestRequestInterceptor(const std::string& hostname,
+ scoped_refptr<base::SequencedTaskRunner> io_task_runner)
+ : hostname_(hostname),
+ io_task_runner_(io_task_runner) {
+ delegate_ = new Delegate(hostname_, io_task_runner_);
scoped_ptr<net::URLRequestJobFactory::ProtocolHandler> handler(delegate_);
PostToIOAndWait(
base::Bind(&net::URLRequestFilter::AddHostnameProtocolHandler,
@@ -232,7 +232,7 @@ TestRequestInterceptor::~TestRequestInterceptor() {
"http", hostname_));
}
-size_t TestRequestInterceptor::GetPendingSize() const {
+size_t TestRequestInterceptor::GetPendingSize() {
size_t pending_size = std::numeric_limits<size_t>::max();
PostToIOAndWait(base::Bind(&Delegate::GetPendingSize,
base::Unretained(delegate_),
@@ -270,4 +270,17 @@ TestRequestInterceptor::JobCallback TestRequestInterceptor::FileJob(
return base::Bind(&FileJobCallback, file_path);
}
+void TestRequestInterceptor::PostToIOAndWait(const base::Closure& task) {
+ io_task_runner_->PostTask(FROM_HERE, task);
+ base::RunLoop run_loop;
+ io_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(
+ base::IgnoreResult(&base::MessageLoopProxy::PostTask),
+ base::MessageLoopProxy::current(),
+ FROM_HERE,
+ run_loop.QuitClosure()));
+ run_loop.Run();
+}
+
} // namespace policy
diff --git a/chrome/browser/policy/cloud/test_request_interceptor.h b/chrome/browser/policy/cloud/test_request_interceptor.h
index 7838587fc1..ec22353087 100644
--- a/chrome/browser/policy/cloud/test_request_interceptor.h
+++ b/chrome/browser/policy/cloud/test_request_interceptor.h
@@ -9,10 +9,12 @@
#include "base/basictypes.h"
#include "base/callback.h"
+#include "base/memory/ref_counted.h"
#include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
namespace base {
class FilePath;
+class SequencedTaskRunner;
}
namespace net {
@@ -34,11 +36,13 @@ class TestRequestInterceptor {
net::URLRequestJob*(net::URLRequest*, net::NetworkDelegate*)> JobCallback;
// Will intercept request to |hostname| made over HTTP.
- explicit TestRequestInterceptor(const std::string& hostname);
+ TestRequestInterceptor(
+ const std::string& hostname,
+ scoped_refptr<base::SequencedTaskRunner> io_task_runner);
virtual ~TestRequestInterceptor();
// Returns the number of pending callback jobs that haven't been used yet.
- size_t GetPendingSize() const;
+ size_t GetPendingSize();
// Queues |callback| to handle a request to |hostname_|. Each callback is
// used only once, and in the order that they're pushed.
@@ -66,8 +70,13 @@ class TestRequestInterceptor {
private:
class Delegate;
+ // Helper to execute a |task| on IO, and return only after it has completed.
+ void PostToIOAndWait(const base::Closure& task);
+
const std::string hostname_;
+ scoped_refptr<base::SequencedTaskRunner> io_task_runner_;
+
// Owned by URLRequestFilter. This handle is valid on IO and only while the
// interceptor is valid.
Delegate* delegate_;
diff --git a/chrome/browser/policy/cloud/user_cloud_policy_invalidator_factory.cc b/chrome/browser/policy/cloud/user_cloud_policy_invalidator_factory.cc
index c96a160c35..b73fa05eee 100644
--- a/chrome/browser/policy/cloud/user_cloud_policy_invalidator_factory.cc
+++ b/chrome/browser/policy/cloud/user_cloud_policy_invalidator_factory.cc
@@ -8,8 +8,8 @@
#include "chrome/browser/invalidation/invalidation_service_factory.h"
#include "chrome/browser/policy/cloud/user_cloud_policy_invalidator.h"
#include "chrome/browser/profiles/profile.h"
-#include "chrome/common/chrome_switches.h"
#include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
+#include "components/policy/core/common/policy_switches.h"
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h"
#include "chrome/browser/chromeos/policy/user_cloud_policy_manager_factory_chromeos.h"
diff --git a/chrome/browser/policy/cloud/user_cloud_policy_manager.cc b/chrome/browser/policy/cloud/user_cloud_policy_manager.cc
index 03a00da4aa..6cc03b2c37 100644
--- a/chrome/browser/policy/cloud/user_cloud_policy_manager.cc
+++ b/chrome/browser/policy/cloud/user_cloud_policy_manager.cc
@@ -13,7 +13,7 @@
#include "chrome/browser/policy/cloud/user_cloud_policy_manager_factory.h"
#include "chrome/browser/policy/cloud/user_cloud_policy_store.h"
#include "chrome/browser/policy/policy_types.h"
-#include "chrome/common/pref_names.h"
+#include "components/policy/core/common/policy_pref_names.h"
#include "net/url_request/url_request_context_getter.h"
namespace em = enterprise_management;
@@ -52,7 +52,8 @@ void UserCloudPolicyManager::Connect(
scoped_ptr<CloudPolicyClient> client) {
core()->Connect(client.Pass());
core()->StartRefreshScheduler();
- core()->TrackRefreshDelayPref(local_state, prefs::kUserPolicyRefreshRate);
+ core()->TrackRefreshDelayPref(local_state,
+ policy_prefs::kUserPolicyRefreshRate);
if (external_data_manager_)
external_data_manager_->Connect(request_context);
}
diff --git a/chrome/browser/policy/cloud/user_cloud_policy_manager_factory.cc b/chrome/browser/policy/cloud/user_cloud_policy_manager_factory.cc
index bad6ef8d9a..0279328446 100644
--- a/chrome/browser/policy/cloud/user_cloud_policy_manager_factory.cc
+++ b/chrome/browser/policy/cloud/user_cloud_policy_manager_factory.cc
@@ -4,14 +4,13 @@
#include "chrome/browser/policy/cloud/user_cloud_policy_manager_factory.h"
-#include "base/command_line.h"
#include "base/logging.h"
#include "base/message_loop/message_loop_proxy.h"
+#include "base/sequenced_task_runner.h"
#include "chrome/browser/policy/cloud/cloud_external_data_manager.h"
#include "chrome/browser/policy/cloud/user_cloud_policy_manager.h"
#include "chrome/browser/policy/cloud/user_cloud_policy_store.h"
#include "chrome/browser/profiles/profile.h"
-#include "chrome/common/chrome_switches.h"
#include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
namespace policy {
@@ -29,9 +28,12 @@ UserCloudPolicyManager* UserCloudPolicyManagerFactory::GetForProfile(
// static
scoped_ptr<UserCloudPolicyManager>
- UserCloudPolicyManagerFactory::CreateForProfile(Profile* profile,
- bool force_immediate_load) {
- return GetInstance()->CreateManagerForProfile(profile, force_immediate_load);
+UserCloudPolicyManagerFactory::CreateForProfile(
+ Profile* profile,
+ bool force_immediate_load,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner) {
+ return GetInstance()->CreateManagerForProfile(
+ profile, force_immediate_load, background_task_runner);
}
UserCloudPolicyManagerFactory::UserCloudPolicyManagerFactory()
@@ -52,12 +54,10 @@ UserCloudPolicyManager* UserCloudPolicyManagerFactory::GetManagerForProfile(
scoped_ptr<UserCloudPolicyManager>
UserCloudPolicyManagerFactory::CreateManagerForProfile(
Profile* profile,
- bool force_immediate_load) {
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableCloudPolicyOnSignin)) {
- return scoped_ptr<UserCloudPolicyManager>();
- }
- scoped_ptr<UserCloudPolicyStore> store(UserCloudPolicyStore::Create(profile));
+ bool force_immediate_load,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner) {
+ scoped_ptr<UserCloudPolicyStore> store(
+ UserCloudPolicyStore::Create(profile, background_task_runner));
if (force_immediate_load)
store->LoadImmediately();
scoped_ptr<UserCloudPolicyManager> manager(
diff --git a/chrome/browser/policy/cloud/user_cloud_policy_manager_factory.h b/chrome/browser/policy/cloud/user_cloud_policy_manager_factory.h
index b1690a9492..ec9c2515b3 100644
--- a/chrome/browser/policy/cloud/user_cloud_policy_manager_factory.h
+++ b/chrome/browser/policy/cloud/user_cloud_policy_manager_factory.h
@@ -8,11 +8,16 @@
#include <map>
#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
#include "base/memory/singleton.h"
#include "components/browser_context_keyed_service/browser_context_keyed_base_factory.h"
class Profile;
+namespace base {
+class SequencedTaskRunner;
+}
+
namespace policy {
class UserCloudPolicyManager;
@@ -47,7 +52,8 @@ class UserCloudPolicyManagerFactory : public BrowserContextKeyedBaseFactory {
// UserCloudPolicyStore at startup.
static scoped_ptr<UserCloudPolicyManager> CreateForProfile(
Profile* profile,
- bool force_immediate_load);
+ bool force_immediate_load,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner);
private:
friend class UserCloudPolicyManager;
@@ -60,7 +66,8 @@ class UserCloudPolicyManagerFactory : public BrowserContextKeyedBaseFactory {
UserCloudPolicyManager* GetManagerForProfile(Profile* profile);
scoped_ptr<UserCloudPolicyManager> CreateManagerForProfile(
Profile* profile,
- bool force_immediate_load);
+ bool force_immediate_load,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner);
// BrowserContextKeyedBaseFactory:
virtual void BrowserContextShutdown(
diff --git a/chrome/browser/policy/cloud/user_cloud_policy_store.cc b/chrome/browser/policy/cloud/user_cloud_policy_store.cc
index 981e87e1c4..cda8fb7f1c 100644
--- a/chrome/browser/policy/cloud/user_cloud_policy_store.cc
+++ b/chrome/browser/policy/cloud/user_cloud_policy_store.cc
@@ -6,12 +6,13 @@
#include "base/bind.h"
#include "base/file_util.h"
+#include "base/location.h"
+#include "base/task_runner_util.h"
#include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
#include "chrome/browser/policy/proto/cloud/device_management_local.pb.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/signin_manager.h"
#include "chrome/browser/signin/signin_manager_factory.h"
-#include "content/public/browser/browser_thread.h"
#include "policy/policy_constants.h"
#include "policy/proto/cloud_policy.pb.h"
@@ -68,11 +69,11 @@ policy::PolicyLoadResult LoadPolicyFromDisk(const base::FilePath& path) {
}
// Stores policy to the backing file (must be called via a task on
-// the FILE thread).
-void StorePolicyToDiskOnFileThread(const base::FilePath& path,
- const em::PolicyFetchResponse& policy) {
+// the background thread).
+void StorePolicyToDiskOnBackgroundThread(
+ const base::FilePath& path,
+ const em::PolicyFetchResponse& policy) {
DVLOG(1) << "Storing policy to " << path.value();
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
std::string data;
if (!policy.SerializeToString(&data)) {
DLOG(WARNING) << "Failed to serialize policy data";
@@ -92,21 +93,25 @@ void StorePolicyToDiskOnFileThread(const base::FilePath& path,
} // namespace
-UserCloudPolicyStore::UserCloudPolicyStore(Profile* profile,
- const base::FilePath& path)
- : weak_factory_(this),
+UserCloudPolicyStore::UserCloudPolicyStore(
+ Profile* profile,
+ const base::FilePath& path,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner)
+ : UserCloudPolicyStoreBase(background_task_runner),
+ weak_factory_(this),
profile_(profile),
- backing_file_path_(path) {
-}
+ backing_file_path_(path) {}
UserCloudPolicyStore::~UserCloudPolicyStore() {}
// static
scoped_ptr<UserCloudPolicyStore> UserCloudPolicyStore::Create(
- Profile* profile) {
+ Profile* profile,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner) {
base::FilePath path =
profile->GetPath().Append(kPolicyDir).Append(kPolicyCacheFile);
- return make_scoped_ptr(new UserCloudPolicyStore(profile, path));
+ return make_scoped_ptr(
+ new UserCloudPolicyStore(profile, path, background_task_runner));
}
void UserCloudPolicyStore::LoadImmediately() {
@@ -120,11 +125,10 @@ void UserCloudPolicyStore::LoadImmediately() {
}
void UserCloudPolicyStore::Clear() {
- content::BrowserThread::PostTask(
- content::BrowserThread::FILE, FROM_HERE,
- base::Bind(base::IgnoreResult(&base::DeleteFile),
- backing_file_path_,
- false));
+ background_task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(
+ base::IgnoreResult(&base::DeleteFile), backing_file_path_, false));
policy_.reset();
policy_map_.Clear();
NotifyStoreLoaded();
@@ -137,8 +141,9 @@ void UserCloudPolicyStore::Load() {
// Start a new Load operation and have us get called back when it is
// complete.
- content::BrowserThread::PostTaskAndReplyWithResult(
- content::BrowserThread::FILE, FROM_HERE,
+ base::PostTaskAndReplyWithResult(
+ background_task_runner(),
+ FROM_HERE,
base::Bind(&LoadPolicyFromDisk, backing_file_path_),
base::Bind(&UserCloudPolicyStore::PolicyLoaded,
weak_factory_.GetWeakPtr(), true));
@@ -146,7 +151,6 @@ void UserCloudPolicyStore::Load() {
void UserCloudPolicyStore::PolicyLoaded(bool validate_in_background,
PolicyLoadResult result) {
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
switch (result.status) {
case LOAD_RESULT_LOAD_ERROR:
status_ = STATUS_LOAD_ERROR;
@@ -248,9 +252,9 @@ void UserCloudPolicyStore::StorePolicyAfterValidation(
// Persist the validated policy (just fire a task - don't bother getting a
// reply because we can't do anything if it fails).
- content::BrowserThread::PostTask(
- content::BrowserThread::FILE, FROM_HERE,
- base::Bind(&StorePolicyToDiskOnFileThread,
+ background_task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&StorePolicyToDiskOnBackgroundThread,
backing_file_path_, *validator->policy()));
InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass());
status_ = STATUS_OK;
diff --git a/chrome/browser/policy/cloud/user_cloud_policy_store.h b/chrome/browser/policy/cloud/user_cloud_policy_store.h
index 892fc23754..b1fcdbe5f9 100644
--- a/chrome/browser/policy/cloud/user_cloud_policy_store.h
+++ b/chrome/browser/policy/cloud/user_cloud_policy_store.h
@@ -15,6 +15,10 @@
class Profile;
+namespace base {
+class SequencedTaskRunner;
+}
+
namespace policy {
// Implements a cloud policy store that is stored in a simple file in the user's
@@ -24,11 +28,16 @@ class UserCloudPolicyStore : public UserCloudPolicyStoreBase {
public:
// Creates a policy store associated with the user signed in to this
// |profile|.
- UserCloudPolicyStore(Profile* profile, const base::FilePath& policy_file);
+ UserCloudPolicyStore(
+ Profile* profile,
+ const base::FilePath& policy_file,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner);
virtual ~UserCloudPolicyStore();
// Factory method for creating a UserCloudPolicyStore for |profile|.
- static scoped_ptr<UserCloudPolicyStore> Create(Profile* profile);
+ static scoped_ptr<UserCloudPolicyStore> Create(
+ Profile* profile,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner);
// Loads policy immediately on the current thread. Virtual for mocks.
virtual void LoadImmediately();
diff --git a/chrome/browser/policy/cloud/user_cloud_policy_store_base.cc b/chrome/browser/policy/cloud/user_cloud_policy_store_base.cc
index 2d097ba7e0..ee1daa6085 100644
--- a/chrome/browser/policy/cloud/user_cloud_policy_store_base.cc
+++ b/chrome/browser/policy/cloud/user_cloud_policy_store_base.cc
@@ -17,8 +17,9 @@ void DecodePolicy(const enterprise_management::CloudPolicySettings& policy,
base::WeakPtr<CloudExternalDataManager> external_data_manager,
PolicyMap* policies);
-UserCloudPolicyStoreBase::UserCloudPolicyStoreBase() {
-}
+UserCloudPolicyStoreBase::UserCloudPolicyStoreBase(
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner)
+ : background_task_runner_(background_task_runner) {}
UserCloudPolicyStoreBase::~UserCloudPolicyStoreBase() {
}
@@ -28,7 +29,7 @@ scoped_ptr<UserCloudPolicyValidator> UserCloudPolicyStoreBase::CreateValidator(
CloudPolicyValidatorBase::ValidateTimestampOption timestamp_option) {
// Configure the validator.
UserCloudPolicyValidator* validator =
- UserCloudPolicyValidator::Create(policy.Pass());
+ UserCloudPolicyValidator::Create(policy.Pass(), background_task_runner_);
validator->ValidatePolicyType(GetChromeUserPolicyType());
validator->ValidateAgainstCurrentPolicy(
policy_.get(),
diff --git a/chrome/browser/policy/cloud/user_cloud_policy_store_base.h b/chrome/browser/policy/cloud/user_cloud_policy_store_base.h
index e00a3d29a3..068002ecf0 100644
--- a/chrome/browser/policy/cloud/user_cloud_policy_store_base.h
+++ b/chrome/browser/policy/cloud/user_cloud_policy_store_base.h
@@ -8,18 +8,24 @@
#include <string>
#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/policy/cloud/cloud_policy_store.h"
#include "chrome/browser/policy/cloud/cloud_policy_validator.h"
+namespace base {
+class SequencedTaskRunner;
+}
+
namespace policy {
// Base class that implements common cross-platform UserCloudPolicyStore
// functionality.
class UserCloudPolicyStoreBase : public CloudPolicyStore {
public:
- UserCloudPolicyStoreBase();
+ explicit UserCloudPolicyStoreBase(
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner);
virtual ~UserCloudPolicyStoreBase();
protected:
@@ -34,7 +40,14 @@ class UserCloudPolicyStoreBase : public CloudPolicyStore {
scoped_ptr<enterprise_management::PolicyData> policy_data,
scoped_ptr<enterprise_management::CloudPolicySettings> payload);
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner() const {
+ return background_task_runner_;
+ }
+
private:
+ // Task runner for background file operations.
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
+
DISALLOW_COPY_AND_ASSIGN(UserCloudPolicyStoreBase);
};
diff --git a/chrome/browser/policy/cloud/user_cloud_policy_store_unittest.cc b/chrome/browser/policy/cloud/user_cloud_policy_store_unittest.cc
index e3f378f10d..2c2876cca0 100644
--- a/chrome/browser/policy/cloud/user_cloud_policy_store_unittest.cc
+++ b/chrome/browser/policy/cloud/user_cloud_policy_store_unittest.cc
@@ -7,6 +7,7 @@
#include "base/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_proxy.h"
#include "base/prefs/pref_service.h"
#include "base/run_loop.h"
#include "chrome/browser/policy/cloud/mock_cloud_external_data_manager.h"
@@ -17,7 +18,6 @@
#include "chrome/browser/signin/signin_manager_factory.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_profile.h"
-#include "content/public/test/test_browser_thread.h"
#include "net/url_request/url_request_context_getter.h"
#include "policy/policy_constants.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -42,8 +42,6 @@ class UserCloudPolicyStoreTest : public testing::Test {
public:
UserCloudPolicyStoreTest()
: loop_(base::MessageLoop::TYPE_UI),
- ui_thread_(content::BrowserThread::UI, &loop_),
- file_thread_(content::BrowserThread::FILE, &loop_),
profile_(new TestingProfile()) {}
virtual void SetUp() OVERRIDE {
@@ -54,7 +52,8 @@ class UserCloudPolicyStoreTest : public testing::Test {
profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername,
PolicyBuilder::kFakeUsername);
signin->Initialize(profile_.get(), NULL);
- store_.reset(new UserCloudPolicyStore(profile_.get(), policy_file()));
+ store_.reset(new UserCloudPolicyStore(
+ profile_.get(), policy_file(), loop_.message_loop_proxy()));
external_data_manager_.reset(new MockCloudExternalDataManager);
external_data_manager_->SetPolicyStore(store_.get());
store_->AddObserver(&observer_);
@@ -104,8 +103,6 @@ class UserCloudPolicyStoreTest : public testing::Test {
// |ui_thread_| and |file_thread_| share the same MessageLoop |loop_| so
// callers can use RunLoop to manage both virtual threads.
base::MessageLoop loop_;
- content::TestBrowserThread ui_thread_;
- content::TestBrowserThread file_thread_;
scoped_ptr<TestingProfile> profile_;
base::ScopedTempDir tmp_dir_;
@@ -280,8 +277,8 @@ TEST_F(UserCloudPolicyStoreTest, StoreThenLoad) {
RunUntilIdle();
// Now, make sure the policy can be read back in from a second store.
- scoped_ptr<UserCloudPolicyStore> store2(
- new UserCloudPolicyStore(profile_.get(), policy_file()));
+ scoped_ptr<UserCloudPolicyStore> store2(new UserCloudPolicyStore(
+ profile_.get(), policy_file(), loop_.message_loop_proxy()));
store2->AddObserver(&observer_);
EXPECT_CALL(observer_, OnStoreLoaded(store2.get()));
store2->Load();
@@ -305,8 +302,8 @@ TEST_F(UserCloudPolicyStoreTest, StoreThenLoadImmediately) {
RunUntilIdle();
// Now, make sure the policy can be read back in from a second store.
- scoped_ptr<UserCloudPolicyStore> store2(
- new UserCloudPolicyStore(profile_.get(), policy_file()));
+ scoped_ptr<UserCloudPolicyStore> store2(new UserCloudPolicyStore(
+ profile_.get(), policy_file(), loop_.message_loop_proxy()));
store2->AddObserver(&observer_);
EXPECT_CALL(observer_, OnStoreLoaded(store2.get()));
store2->LoadImmediately(); // Should load without running the message loop.
@@ -345,8 +342,8 @@ TEST_F(UserCloudPolicyStoreTest, LoadValidationError) {
SigninManagerFactory::GetForProfile(profile_.get())->SetAuthenticatedUsername(
"foobar@foobar.com");
- scoped_ptr<UserCloudPolicyStore> store2(
- new UserCloudPolicyStore(profile_.get(), policy_file()));
+ scoped_ptr<UserCloudPolicyStore> store2(new UserCloudPolicyStore(
+ profile_.get(), policy_file(), loop_.message_loop_proxy()));
store2->AddObserver(&observer_);
ExpectError(store2.get(), CloudPolicyStore::STATUS_VALIDATION_ERROR);
store2->Load();
@@ -358,8 +355,8 @@ TEST_F(UserCloudPolicyStoreTest, LoadValidationError) {
// Sign out - we should be able to load the policy (don't check usernames
// when signed out).
SigninManagerFactory::GetForProfile(profile_.get())->SignOut();
- scoped_ptr<UserCloudPolicyStore> store3(
- new UserCloudPolicyStore(profile_.get(), policy_file()));
+ scoped_ptr<UserCloudPolicyStore> store3(new UserCloudPolicyStore(
+ profile_.get(), policy_file(), loop_.message_loop_proxy()));
store3->AddObserver(&observer_);
EXPECT_CALL(observer_, OnStoreLoaded(store3.get()));
store3->Load();
@@ -373,8 +370,8 @@ TEST_F(UserCloudPolicyStoreTest, LoadValidationError) {
SigninManagerFactory::GetForProfile(profile_.get()));
signin->set_auth_in_progress("foobar@foobar.com");
- scoped_ptr<UserCloudPolicyStore> store4(
- new UserCloudPolicyStore(profile_.get(), policy_file()));
+ scoped_ptr<UserCloudPolicyStore> store4(new UserCloudPolicyStore(
+ profile_.get(), policy_file(), loop_.message_loop_proxy()));
store4->AddObserver(&observer_);
ExpectError(store4.get(), CloudPolicyStore::STATUS_VALIDATION_ERROR);
store4->Load();
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service.cc b/chrome/browser/policy/cloud/user_policy_signin_service.cc
index 7075d1444a..db1349a20a 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service.cc
+++ b/chrome/browser/policy/cloud/user_policy_signin_service.cc
@@ -7,7 +7,6 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
-#include "base/prefs/pref_service.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/policy/cloud/cloud_policy_client_registration_helper.h"
@@ -17,7 +16,6 @@
#include "chrome/browser/signin/profile_oauth2_token_service.h"
#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
#include "chrome/browser/signin/signin_manager.h"
-#include "chrome/common/pref_names.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_source.h"
#include "google_apis/gaia/gaia_constants.h"
@@ -36,9 +34,6 @@ UserPolicySigninService::UserPolicySigninService(
request_context,
device_management_service),
oauth2_token_service_(token_service) {
- if (profile->GetPrefs()->GetBoolean(prefs::kDisableCloudPolicyOnSignin))
- return;
-
// ProfileOAuth2TokenService should not yet have loaded its tokens since this
// happens in the background after PKS initialization - so this service
// should always be created before the oauth token is available.
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_android.cc b/chrome/browser/policy/cloud/user_policy_signin_service_android.cc
index 8c42603ead..9035159eae 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service_android.cc
+++ b/chrome/browser/policy/cloud/user_policy_signin_service_android.cc
@@ -18,8 +18,8 @@
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
#include "chrome/browser/signin/signin_manager.h"
-#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
+#include "components/policy/core/common/policy_switches.h"
#include "net/base/network_change_notifier.h"
#include "net/url_request/url_request_context_getter.h"
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_base.cc b/chrome/browser/policy/cloud/user_policy_signin_service_base.cc
index 324d5c1e8c..86127d67f3 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service_base.cc
+++ b/chrome/browser/policy/cloud/user_policy_signin_service_base.cc
@@ -7,17 +7,14 @@
#include "base/bind.h"
#include "base/command_line.h"
#include "base/message_loop/message_loop.h"
-#include "base/prefs/pref_service.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/policy/browser_policy_connector.h"
#include "chrome/browser/policy/cloud/device_management_service.h"
#include "chrome/browser/policy/cloud/user_cloud_policy_manager.h"
#include "chrome/browser/policy/cloud/user_cloud_policy_manager_factory.h"
-#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/signin_manager.h"
#include "chrome/browser/signin/signin_manager_factory.h"
#include "chrome/common/chrome_switches.h"
-#include "chrome/common/pref_names.h"
#include "content/public/browser/notification_source.h"
#include "net/url_request/url_request_context_getter.h"
@@ -33,9 +30,6 @@ UserPolicySigninServiceBase::UserPolicySigninServiceBase(
request_context_(request_context),
device_management_service_(device_management_service),
weak_factory_(this) {
- if (profile_->GetPrefs()->GetBoolean(prefs::kDisableCloudPolicyOnSignin))
- return;
-
// Initialize/shutdown the UserCloudPolicyManager when the user signs out.
registrar_.Add(this,
chrome::NOTIFICATION_GOOGLE_SIGNED_OUT,
@@ -175,9 +169,6 @@ scoped_ptr<CloudPolicyClient> UserPolicySigninServiceBase::PrepareToRegister(
bool UserPolicySigninServiceBase::ShouldLoadPolicyForUser(
const std::string& username) {
- if (profile_->GetPrefs()->GetBoolean(prefs::kDisableCloudPolicyOnSignin))
- return false; // Cloud policy is disabled.
-
if (username.empty())
return false; // Not signed in.
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_factory.cc b/chrome/browser/policy/cloud/user_policy_signin_service_factory.cc
index 06b0150411..de102809f6 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service_factory.cc
+++ b/chrome/browser/policy/cloud/user_policy_signin_service_factory.cc
@@ -89,10 +89,6 @@ UserPolicySigninServiceFactory::ServiceIsCreatedWithBrowserContext() const {
void UserPolicySigninServiceFactory::RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable* user_prefs) {
- user_prefs->RegisterBooleanPref(
- prefs::kDisableCloudPolicyOnSignin,
- false,
- user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
#if defined(OS_ANDROID)
user_prefs->RegisterInt64Pref(
prefs::kLastPolicyCheckTime,
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc b/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc
index 965635dbca..14de910609 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc
+++ b/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc
@@ -58,12 +58,14 @@ namespace {
const char kTestUser[] = "testuser@test.com";
+#if !defined(OS_ANDROID)
const char kValidTokenResponse[] =
"{"
" \"access_token\": \"at1\","
" \"expires_in\": 3600,"
" \"token_type\": \"Bearer\""
"}";
+#endif
const char kHostedDomainResponse[] =
"{"
diff --git a/chrome/browser/policy/configuration_policy_handler.cc b/chrome/browser/policy/configuration_policy_handler.cc
index a708757e5d..b1565be098 100644
--- a/chrome/browser/policy/configuration_policy_handler.cc
+++ b/chrome/browser/policy/configuration_policy_handler.cc
@@ -11,24 +11,15 @@
#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/prefs/pref_value_map.h"
-#include "base/stl_util.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/download/download_prefs.h"
-#include "chrome/browser/extensions/external_policy_loader.h"
#include "chrome/browser/policy/configuration_policy_pref_store.h"
#include "chrome/browser/policy/external_data_fetcher.h"
#include "chrome/browser/policy/policy_error_map.h"
#include "chrome/browser/policy/policy_map.h"
-#include "chrome/browser/prefs/proxy_config_dictionary.h"
-#include "chrome/browser/prefs/proxy_prefs.h"
#include "chrome/browser/prefs/session_startup_pref.h"
-#include "chrome/browser/search_engines/search_terms_data.h"
-#include "chrome/browser/search_engines/template_url.h"
-#include "chrome/common/extensions/extension.h"
-#include "content/public/browser/notification_service.h"
#include "grit/generated_resources.h"
#include "policy/policy_constants.h"
#include "url/gurl.h"
@@ -41,40 +32,6 @@ namespace policy {
namespace {
-// Helper classes --------------------------------------------------------------
-
-// This is used to check whether for a given ProxyMode value, the ProxyPacUrl,
-// the ProxyBypassList and the ProxyServer policies are allowed to be specified.
-// |error_message_id| is the message id of the localized error message to show
-// when the policies are not specified as allowed. Each value of ProxyMode
-// has a ProxyModeValidationEntry in the |kProxyModeValidationMap| below.
-struct ProxyModeValidationEntry {
- const char* mode_value;
- bool pac_url_allowed;
- bool bypass_list_allowed;
- bool server_allowed;
- int error_message_id;
-};
-
-
-// Static data -----------------------------------------------------------------
-
-// List of entries determining which proxy policies can be specified, depending
-// on the ProxyMode.
-const ProxyModeValidationEntry kProxyModeValidationMap[] = {
- { ProxyPrefs::kDirectProxyModeName,
- false, false, false, IDS_POLICY_PROXY_MODE_DISABLED_ERROR },
- { ProxyPrefs::kAutoDetectProxyModeName,
- false, false, false, IDS_POLICY_PROXY_MODE_AUTO_DETECT_ERROR },
- { ProxyPrefs::kPacScriptProxyModeName,
- true, false, false, IDS_POLICY_PROXY_MODE_PAC_URL_ERROR },
- { ProxyPrefs::kFixedServersProxyModeName,
- false, true, true, IDS_POLICY_PROXY_MODE_FIXED_SERVERS_ERROR },
- { ProxyPrefs::kSystemProxyModeName,
- false, false, false, IDS_POLICY_PROXY_MODE_SYSTEM_ERROR },
-};
-
-
// Helper function -------------------------------------------------------------
// Utility function that returns a JSON representation of the given |dict| as
@@ -367,239 +324,6 @@ void IntPercentageToDoublePolicyHandler::ApplyPolicySettings(
}
-// ExtensionListPolicyHandler implementation -----------------------------------
-
-ExtensionListPolicyHandler::ExtensionListPolicyHandler(const char* policy_name,
- const char* pref_path,
- bool allow_wildcards)
- : TypeCheckingPolicyHandler(policy_name, base::Value::TYPE_LIST),
- pref_path_(pref_path),
- allow_wildcards_(allow_wildcards) {}
-
-ExtensionListPolicyHandler::~ExtensionListPolicyHandler() {}
-
-bool ExtensionListPolicyHandler::CheckPolicySettings(
- const PolicyMap& policies,
- PolicyErrorMap* errors) {
- return CheckAndGetList(policies, errors, NULL);
-}
-
-void ExtensionListPolicyHandler::ApplyPolicySettings(
- const PolicyMap& policies,
- PrefValueMap* prefs) {
- scoped_ptr<base::ListValue> list;
- PolicyErrorMap errors;
- if (CheckAndGetList(policies, &errors, &list) && list)
- prefs->SetValue(pref_path(), list.release());
-}
-
-const char* ExtensionListPolicyHandler::pref_path() const {
- return pref_path_;
-}
-
-bool ExtensionListPolicyHandler::CheckAndGetList(
- const PolicyMap& policies,
- PolicyErrorMap* errors,
- scoped_ptr<base::ListValue>* extension_ids) {
- if (extension_ids)
- extension_ids->reset();
-
- const base::Value* value = NULL;
- if (!CheckAndGetValue(policies, errors, &value))
- return false;
-
- if (!value)
- return true;
-
- const base::ListValue* list_value = NULL;
- if (!value->GetAsList(&list_value)) {
- NOTREACHED();
- return false;
- }
-
- // Filter the list, rejecting any invalid extension IDs.
- scoped_ptr<base::ListValue> filtered_list(new base::ListValue());
- for (base::ListValue::const_iterator entry(list_value->begin());
- entry != list_value->end(); ++entry) {
- std::string id;
- if (!(*entry)->GetAsString(&id)) {
- errors->AddError(policy_name(),
- entry - list_value->begin(),
- IDS_POLICY_TYPE_ERROR,
- ValueTypeToString(base::Value::TYPE_STRING));
- continue;
- }
- if (!(allow_wildcards_ && id == "*") &&
- !extensions::Extension::IdIsValid(id)) {
- errors->AddError(policy_name(),
- entry - list_value->begin(),
- IDS_POLICY_VALUE_FORMAT_ERROR);
- continue;
- }
- filtered_list->Append(base::Value::CreateStringValue(id));
- }
-
- if (extension_ids)
- *extension_ids = filtered_list.Pass();
-
- return true;
-}
-
-
-// ExtensionInstallForcelistPolicyHandler implementation -----------------------
-
-ExtensionInstallForcelistPolicyHandler::ExtensionInstallForcelistPolicyHandler(
- const char* pref_name)
- : TypeCheckingPolicyHandler(key::kExtensionInstallForcelist,
- base::Value::TYPE_LIST),
- pref_name_(pref_name) {}
-
-ExtensionInstallForcelistPolicyHandler::
- ~ExtensionInstallForcelistPolicyHandler() {}
-
-bool ExtensionInstallForcelistPolicyHandler::CheckPolicySettings(
- const PolicyMap& policies,
- PolicyErrorMap* errors) {
- const base::Value* value;
- return CheckAndGetValue(policies, errors, &value) &&
- ParseList(value, NULL, errors);
-}
-
-void ExtensionInstallForcelistPolicyHandler::ApplyPolicySettings(
- const PolicyMap& policies,
- PrefValueMap* prefs) {
- const base::Value* value = NULL;
- scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
- if (CheckAndGetValue(policies, NULL, &value) &&
- value &&
- ParseList(value, dict.get(), NULL)) {
- prefs->SetValue(pref_name_, dict.release());
- }
-}
-
-bool ExtensionInstallForcelistPolicyHandler::ParseList(
- const base::Value* policy_value,
- base::DictionaryValue* extension_dict,
- PolicyErrorMap* errors) {
- if (!policy_value)
- return true;
-
- const base::ListValue* policy_list_value = NULL;
- if (!policy_value->GetAsList(&policy_list_value)) {
- // This should have been caught in CheckPolicySettings.
- NOTREACHED();
- return false;
- }
-
- for (base::ListValue::const_iterator entry(policy_list_value->begin());
- entry != policy_list_value->end(); ++entry) {
- std::string entry_string;
- if (!(*entry)->GetAsString(&entry_string)) {
- if (errors) {
- errors->AddError(policy_name(),
- entry - policy_list_value->begin(),
- IDS_POLICY_TYPE_ERROR,
- ValueTypeToString(base::Value::TYPE_STRING));
- }
- continue;
- }
-
- // Each string item of the list has the following form:
- // <extension_id>;<update_url>
- // Note: The update URL might also contain semicolons.
- size_t pos = entry_string.find(';');
- if (pos == std::string::npos) {
- if (errors) {
- errors->AddError(policy_name(),
- entry - policy_list_value->begin(),
- IDS_POLICY_VALUE_FORMAT_ERROR);
- }
- continue;
- }
-
- std::string extension_id = entry_string.substr(0, pos);
- std::string update_url = entry_string.substr(pos+1);
- if (!extensions::Extension::IdIsValid(extension_id) ||
- !GURL(update_url).is_valid()) {
- if (errors) {
- errors->AddError(policy_name(),
- entry - policy_list_value->begin(),
- IDS_POLICY_VALUE_FORMAT_ERROR);
- }
- continue;
- }
-
- if (extension_dict) {
- extensions::ExternalPolicyLoader::AddExtension(
- extension_dict, extension_id, update_url);
- }
- }
-
- return true;
-}
-
-
-// ExtensionURLPatternListPolicyHandler implementation -------------------------
-
-ExtensionURLPatternListPolicyHandler::ExtensionURLPatternListPolicyHandler(
- const char* policy_name,
- const char* pref_path)
- : TypeCheckingPolicyHandler(policy_name, base::Value::TYPE_LIST),
- pref_path_(pref_path) {}
-
-ExtensionURLPatternListPolicyHandler::~ExtensionURLPatternListPolicyHandler() {}
-
-bool ExtensionURLPatternListPolicyHandler::CheckPolicySettings(
- const PolicyMap& policies,
- PolicyErrorMap* errors) {
- const base::Value* value = NULL;
- if (!CheckAndGetValue(policies, errors, &value))
- return false;
-
- if (!value)
- return true;
-
- const base::ListValue* list_value = NULL;
- if (!value->GetAsList(&list_value)) {
- NOTREACHED();
- return false;
- }
-
- // Check that the list contains valid URLPattern strings only.
- for (base::ListValue::const_iterator entry(list_value->begin());
- entry != list_value->end(); ++entry) {
- std::string url_pattern_string;
- if (!(*entry)->GetAsString(&url_pattern_string)) {
- errors->AddError(policy_name(),
- entry - list_value->begin(),
- IDS_POLICY_TYPE_ERROR,
- ValueTypeToString(base::Value::TYPE_STRING));
- return false;
- }
-
- URLPattern pattern(URLPattern::SCHEME_ALL);
- if (pattern.Parse(url_pattern_string) != URLPattern::PARSE_SUCCESS) {
- errors->AddError(policy_name(),
- entry - list_value->begin(),
- IDS_POLICY_VALUE_FORMAT_ERROR);
- return false;
- }
- }
-
- return true;
-}
-
-void ExtensionURLPatternListPolicyHandler::ApplyPolicySettings(
- const PolicyMap& policies,
- PrefValueMap* prefs) {
- if (!pref_path_)
- return;
- const Value* value = policies.GetValue(policy_name());
- if (value)
- prefs->SetValue(pref_path_, value->DeepCopy());
-}
-
-
// SimplePolicyHandler implementation ------------------------------------------
SimplePolicyHandler::SimplePolicyHandler(
@@ -662,41 +386,6 @@ void AutofillPolicyHandler::ApplyPolicySettings(const PolicyMap& policies,
// implementation.
#if !defined(OS_ANDROID)
-
-// DownloadDirPolicyHandler implementation -------------------------------------
-
-DownloadDirPolicyHandler::DownloadDirPolicyHandler(
- const char* default_directory_pref_name,
- const char* prompt_for_download_pref_name)
- : TypeCheckingPolicyHandler(key::kDownloadDirectory, Value::TYPE_STRING),
- default_directory_pref_name_(default_directory_pref_name),
- prompt_for_download_pref_name_(prompt_for_download_pref_name) {}
-
-DownloadDirPolicyHandler::~DownloadDirPolicyHandler() {
-}
-
-void DownloadDirPolicyHandler::ApplyPolicySettings(const PolicyMap& policies,
- PrefValueMap* prefs) {
- const Value* value = policies.GetValue(policy_name());
- base::FilePath::StringType string_value;
- if (!value || !value->GetAsString(&string_value))
- return;
-
- base::FilePath::StringType expanded_value =
- policy::path_parser::ExpandPathVariables(string_value);
- // Make sure the path isn't empty, since that will point to an undefined
- // location; the default location is used instead in that case.
- // This is checked after path expansion because a non-empty policy value can
- // lead to an empty path value after expansion (e.g. "\"\"").
- if (expanded_value.empty())
- expanded_value = DownloadPrefs::GetDefaultDownloadDirectory().value();
- prefs->SetValue(default_directory_pref_name_,
- Value::CreateStringValue(expanded_value));
- prefs->SetValue(prompt_for_download_pref_name_,
- Value::CreateBooleanValue(false));
-}
-
-
// DiskCacheDirPolicyHandler implementation ------------------------------------
DiskCacheDirPolicyHandler::DiskCacheDirPolicyHandler(const char* pref_name)
@@ -823,546 +512,6 @@ void IncognitoModePolicyHandler::ApplyPolicySettings(const PolicyMap& policies,
}
-// DefaultSearchEncodingsPolicyHandler implementation --------------------------
-
-DefaultSearchEncodingsPolicyHandler::DefaultSearchEncodingsPolicyHandler(
- const char* pref_name)
- : TypeCheckingPolicyHandler(key::kDefaultSearchProviderEncodings,
- Value::TYPE_LIST),
- pref_name_(pref_name) {}
-
-DefaultSearchEncodingsPolicyHandler::~DefaultSearchEncodingsPolicyHandler() {
-}
-
-void DefaultSearchEncodingsPolicyHandler::ApplyPolicySettings(
- const PolicyMap& policies, PrefValueMap* prefs) {
- // The DefaultSearchProviderEncodings policy has type list, but the related
- // preference has type string. Convert one into the other here, using
- // ';' as a separator.
- const Value* value = policies.GetValue(policy_name());
- const ListValue* list;
- if (!value || !value->GetAsList(&list))
- return;
-
- ListValue::const_iterator iter(list->begin());
- ListValue::const_iterator end(list->end());
- std::vector<std::string> string_parts;
- for (; iter != end; ++iter) {
- std::string s;
- if ((*iter)->GetAsString(&s)) {
- string_parts.push_back(s);
- }
- }
- std::string encodings = JoinString(string_parts, ';');
- prefs->SetValue(pref_name(), Value::CreateStringValue(encodings));
-}
-
-
-// DefaultSearchPolicyHandler implementation -----------------------------------
-
-DefaultSearchPolicyHandler::DefaultSearchPolicyHandler(
- const char* id_pref_name,
- const char* prepopulate_id_pref_name,
- const PolicyToPreferenceMapEntry policy_to_pref_map[])
- : id_pref_name_(id_pref_name),
- prepopulate_id_pref_name_(prepopulate_id_pref_name),
- policy_to_pref_map_(policy_to_pref_map) {
- for (size_t i = 0; i < DEFAULT_SEARCH_KEY_SIZE; ++i) {
- const char* policy_name = policy_to_pref_map[i].policy_name;
- if (policy_name == key::kDefaultSearchProviderEncodings) {
- handlers_.push_back(new DefaultSearchEncodingsPolicyHandler(
- policy_to_pref_map[i].preference_path));
- } else {
- handlers_.push_back(new SimplePolicyHandler(
- policy_name,
- policy_to_pref_map[i].preference_path,
- policy_to_pref_map[i].value_type));
- }
- }
-}
-
-DefaultSearchPolicyHandler::~DefaultSearchPolicyHandler() {
- STLDeleteElements(&handlers_);
-}
-
-bool DefaultSearchPolicyHandler::CheckPolicySettings(const PolicyMap& policies,
- PolicyErrorMap* errors) {
- if (!CheckIndividualPolicies(policies, errors))
- return false;
-
- if (DefaultSearchProviderIsDisabled(policies)) {
- // Add an error for all specified default search policies except
- // DefaultSearchProviderEnabled.
-
- for (std::vector<TypeCheckingPolicyHandler*>::const_iterator handler =
- handlers_.begin();
- handler != handlers_.end(); ++handler) {
- const char* policy_name = (*handler)->policy_name();
- if (policy_name != key::kDefaultSearchProviderEnabled &&
- HasDefaultSearchPolicy(policies, policy_name)) {
- errors->AddError(policy_name, IDS_POLICY_DEFAULT_SEARCH_DISABLED);
- }
- }
- return true;
- }
-
- const Value* url;
- std::string dummy;
- if (DefaultSearchURLIsValid(policies, &url, &dummy) ||
- !AnyDefaultSearchPoliciesSpecified(policies))
- return true;
- errors->AddError(key::kDefaultSearchProviderSearchURL, url ?
- IDS_POLICY_INVALID_SEARCH_URL_ERROR : IDS_POLICY_NOT_SPECIFIED_ERROR);
- return false;
-}
-
-#define PREF_FOR(x) policy_to_pref_map_[x].preference_path
-void DefaultSearchPolicyHandler::ApplyPolicySettings(const PolicyMap& policies,
- PrefValueMap* prefs) {
- if (DefaultSearchProviderIsDisabled(policies)) {
- prefs->SetBoolean(PREF_FOR(DEFAULT_SEARCH_ENABLED), false);
-
- // If default search is disabled, the other fields are ignored.
- prefs->SetString(PREF_FOR(DEFAULT_SEARCH_NAME), std::string());
- prefs->SetString(PREF_FOR(DEFAULT_SEARCH_SEARCH_URL), std::string());
- prefs->SetString(PREF_FOR(DEFAULT_SEARCH_SUGGEST_URL), std::string());
- prefs->SetString(PREF_FOR(DEFAULT_SEARCH_ICON_URL), std::string());
- prefs->SetString(PREF_FOR(DEFAULT_SEARCH_ENCODINGS), std::string());
- prefs->SetString(PREF_FOR(DEFAULT_SEARCH_KEYWORD), std::string());
- prefs->SetString(PREF_FOR(DEFAULT_SEARCH_INSTANT_URL), std::string());
- prefs->SetString(PREF_FOR(DEFAULT_SEARCH_NEW_TAB_URL), std::string());
- prefs->SetValue(PREF_FOR(DEFAULT_SEARCH_ALTERNATE_URLS), new ListValue());
- prefs->SetString(
- PREF_FOR(DEFAULT_SEARCH_TERMS_REPLACEMENT_KEY), std::string());
- prefs->SetString(PREF_FOR(DEFAULT_SEARCH_IMAGE_URL), std::string());
- prefs->SetString(
- PREF_FOR(DEFAULT_SEARCH_SEARCH_URL_POST_PARAMS), std::string());
- prefs->SetString(
- PREF_FOR(DEFAULT_SEARCH_SUGGEST_URL_POST_PARAMS), std::string());
- prefs->SetString(
- PREF_FOR(DEFAULT_SEARCH_INSTANT_URL_POST_PARAMS), std::string());
- prefs->SetString(
- PREF_FOR(DEFAULT_SEARCH_IMAGE_URL_POST_PARAMS), std::string());
- } else {
- // The search URL is required. The other entries are optional. Just make
- // sure that they are all specified via policy, so that the regular prefs
- // aren't used.
- const Value* dummy;
- std::string url;
- if (DefaultSearchURLIsValid(policies, &dummy, &url)) {
-
- for (std::vector<TypeCheckingPolicyHandler*>::const_iterator handler =
- handlers_.begin();
- handler != handlers_.end(); ++handler) {
- (*handler)->ApplyPolicySettings(policies, prefs);
- }
-
- EnsureStringPrefExists(prefs, PREF_FOR(DEFAULT_SEARCH_SUGGEST_URL));
- EnsureStringPrefExists(prefs, PREF_FOR(DEFAULT_SEARCH_ICON_URL));
- EnsureStringPrefExists(prefs, PREF_FOR(DEFAULT_SEARCH_ENCODINGS));
- EnsureStringPrefExists(prefs, PREF_FOR(DEFAULT_SEARCH_KEYWORD));
- EnsureStringPrefExists(prefs, PREF_FOR(DEFAULT_SEARCH_INSTANT_URL));
- EnsureStringPrefExists(prefs, PREF_FOR(DEFAULT_SEARCH_NEW_TAB_URL));
- EnsureListPrefExists(prefs, PREF_FOR(DEFAULT_SEARCH_ALTERNATE_URLS));
- EnsureStringPrefExists(
- prefs,
- PREF_FOR(DEFAULT_SEARCH_TERMS_REPLACEMENT_KEY));
- EnsureStringPrefExists(prefs, PREF_FOR(DEFAULT_SEARCH_IMAGE_URL));
- EnsureStringPrefExists(
- prefs,
- PREF_FOR(DEFAULT_SEARCH_SEARCH_URL_POST_PARAMS));
- EnsureStringPrefExists(
- prefs,
- PREF_FOR(DEFAULT_SEARCH_SUGGEST_URL_POST_PARAMS));
- EnsureStringPrefExists(
- prefs,
- PREF_FOR(DEFAULT_SEARCH_INSTANT_URL_POST_PARAMS));
- EnsureStringPrefExists(
- prefs,
- PREF_FOR(DEFAULT_SEARCH_IMAGE_URL_POST_PARAMS));
-
- // For the name and keyword, default to the host if not specified. If
- // there is no host (file: URLs? Not sure), use "_" to guarantee that the
- // keyword is non-empty.
- std::string name, keyword;
- std::string host(GURL(url).host());
- if (host.empty())
- host = "_";
- if (!prefs->GetString(PREF_FOR(DEFAULT_SEARCH_NAME), &name) ||
- name.empty()) {
- prefs->SetString(PREF_FOR(DEFAULT_SEARCH_NAME), host);
- }
- if (!prefs->GetString(PREF_FOR(DEFAULT_SEARCH_KEYWORD), &keyword) ||
- keyword.empty()) {
- prefs->SetString(PREF_FOR(DEFAULT_SEARCH_KEYWORD), host);
- }
-
- // And clear the IDs since these are not specified via policy.
- prefs->SetString(id_pref_name_, std::string());
- prefs->SetString(prepopulate_id_pref_name_, std::string());
- }
- }
- content::NotificationService::current()->Notify(
- chrome::NOTIFICATION_DEFAULT_SEARCH_POLICY_CHANGED,
- content::NotificationService::AllSources(),
- content::NotificationService::NoDetails());
-}
-#undef PREF_FOR
-
-bool DefaultSearchPolicyHandler::CheckIndividualPolicies(
- const PolicyMap& policies,
- PolicyErrorMap* errors) {
- for (std::vector<TypeCheckingPolicyHandler*>::const_iterator handler =
- handlers_.begin();
- handler != handlers_.end(); ++handler) {
- if (!(*handler)->CheckPolicySettings(policies, errors))
- return false;
- }
- return true;
-}
-
-bool DefaultSearchPolicyHandler::HasDefaultSearchPolicy(
- const PolicyMap& policies,
- const char* policy_name) {
- return policies.Get(policy_name) != NULL;
-}
-
-bool DefaultSearchPolicyHandler::AnyDefaultSearchPoliciesSpecified(
- const PolicyMap& policies) {
- for (std::vector<TypeCheckingPolicyHandler*>::const_iterator handler =
- handlers_.begin();
- handler != handlers_.end(); ++handler) {
- if (policies.Get((*handler)->policy_name()))
- return true;
- }
- return false;
-}
-
-bool DefaultSearchPolicyHandler::DefaultSearchProviderIsDisabled(
- const PolicyMap& policies) {
- const Value* provider_enabled =
- policies.GetValue(key::kDefaultSearchProviderEnabled);
- bool enabled = true;
- return provider_enabled && provider_enabled->GetAsBoolean(&enabled) &&
- !enabled;
-}
-
-bool DefaultSearchPolicyHandler::DefaultSearchURLIsValid(
- const PolicyMap& policies,
- const Value** url_value,
- std::string* url_string) {
- *url_value = policies.GetValue(key::kDefaultSearchProviderSearchURL);
- if (!*url_value || !(*url_value)->GetAsString(url_string) ||
- url_string->empty())
- return false;
- TemplateURLData data;
- data.SetURL(*url_string);
- SearchTermsData search_terms_data;
- return TemplateURL(NULL, data).SupportsReplacementUsingTermsData(
- search_terms_data);
-}
-
-void DefaultSearchPolicyHandler::EnsureStringPrefExists(
- PrefValueMap* prefs,
- const std::string& path) {
- std::string value;
- if (!prefs->GetString(path, &value))
- prefs->SetString(path, value);
-}
-
-void DefaultSearchPolicyHandler::EnsureListPrefExists(
- PrefValueMap* prefs,
- const std::string& path) {
- base::Value* value;
- base::ListValue* list_value;
- if (!prefs->GetValue(path, &value) || !value->GetAsList(&list_value))
- prefs->SetValue(path, new ListValue());
-}
-
-
-// ProxyPolicyHandler implementation -------------------------------------------
-
-// The proxy policies have the peculiarity that they are loaded from individual
-// policies, but the providers then expose them through a unified
-// DictionaryValue. Once Dictionary policies are fully supported, the individual
-// proxy policies will be deprecated. http://crbug.com/108996
-
-ProxyPolicyHandler::ProxyPolicyHandler(const char* pref_name)
- : pref_name_(pref_name) {}
-
-ProxyPolicyHandler::~ProxyPolicyHandler() {
-}
-
-bool ProxyPolicyHandler::CheckPolicySettings(const PolicyMap& policies,
- PolicyErrorMap* errors) {
- const Value* mode = GetProxyPolicyValue(policies, key::kProxyMode);
- const Value* server = GetProxyPolicyValue(policies, key::kProxyServer);
- const Value* server_mode =
- GetProxyPolicyValue(policies, key::kProxyServerMode);
- const Value* pac_url = GetProxyPolicyValue(policies, key::kProxyPacUrl);
- const Value* bypass_list =
- GetProxyPolicyValue(policies, key::kProxyBypassList);
-
- if ((server || pac_url || bypass_list) && !(mode || server_mode)) {
- errors->AddError(key::kProxySettings,
- key::kProxyMode,
- IDS_POLICY_NOT_SPECIFIED_ERROR);
- return false;
- }
-
- std::string mode_value;
- if (!CheckProxyModeAndServerMode(policies, errors, &mode_value))
- return false;
-
- // If neither ProxyMode nor ProxyServerMode are specified, mode_value will be
- // empty and the proxy shouldn't be configured at all.
- if (mode_value.empty())
- return true;
-
- bool is_valid_mode = false;
- for (size_t i = 0; i != arraysize(kProxyModeValidationMap); ++i) {
- const ProxyModeValidationEntry& entry = kProxyModeValidationMap[i];
- if (entry.mode_value != mode_value)
- continue;
-
- is_valid_mode = true;
-
- if (!entry.pac_url_allowed && pac_url) {
- errors->AddError(key::kProxySettings,
- key::kProxyPacUrl,
- entry.error_message_id);
- }
- if (!entry.bypass_list_allowed && bypass_list) {
- errors->AddError(key::kProxySettings,
- key::kProxyBypassList,
- entry.error_message_id);
- }
- if (!entry.server_allowed && server) {
- errors->AddError(key::kProxySettings,
- key::kProxyServer,
- entry.error_message_id);
- }
-
- if ((!entry.pac_url_allowed && pac_url) ||
- (!entry.bypass_list_allowed && bypass_list) ||
- (!entry.server_allowed && server)) {
- return false;
- }
- }
-
- if (!is_valid_mode) {
- errors->AddError(key::kProxySettings,
- mode ? key::kProxyMode : key::kProxyServerMode,
- IDS_POLICY_OUT_OF_RANGE_ERROR,
- mode_value);
- return false;
- }
- return true;
-}
-
-void ProxyPolicyHandler::ApplyPolicySettings(const PolicyMap& policies,
- PrefValueMap* prefs) {
- const Value* mode = GetProxyPolicyValue(policies, key::kProxyMode);
- const Value* server = GetProxyPolicyValue(policies, key::kProxyServer);
- const Value* server_mode =
- GetProxyPolicyValue(policies, key::kProxyServerMode);
- const Value* pac_url = GetProxyPolicyValue(policies, key::kProxyPacUrl);
- const Value* bypass_list =
- GetProxyPolicyValue(policies, key::kProxyBypassList);
-
- ProxyPrefs::ProxyMode proxy_mode;
- if (mode) {
- std::string string_mode;
- CHECK(mode->GetAsString(&string_mode));
- CHECK(ProxyPrefs::StringToProxyMode(string_mode, &proxy_mode));
- } else if (server_mode) {
- int int_mode = 0;
- CHECK(server_mode->GetAsInteger(&int_mode));
-
- switch (int_mode) {
- case PROXY_SERVER_MODE:
- proxy_mode = ProxyPrefs::MODE_DIRECT;
- break;
- case PROXY_AUTO_DETECT_PROXY_SERVER_MODE:
- proxy_mode = ProxyPrefs::MODE_AUTO_DETECT;
- break;
- case PROXY_MANUALLY_CONFIGURED_PROXY_SERVER_MODE:
- proxy_mode = ProxyPrefs::MODE_FIXED_SERVERS;
- if (pac_url)
- proxy_mode = ProxyPrefs::MODE_PAC_SCRIPT;
- break;
- case PROXY_USE_SYSTEM_PROXY_SERVER_MODE:
- proxy_mode = ProxyPrefs::MODE_SYSTEM;
- break;
- default:
- proxy_mode = ProxyPrefs::MODE_DIRECT;
- NOTREACHED();
- }
- } else {
- return;
- }
-
- switch (proxy_mode) {
- case ProxyPrefs::MODE_DIRECT:
- prefs->SetValue(pref_name_, ProxyConfigDictionary::CreateDirect());
- break;
- case ProxyPrefs::MODE_AUTO_DETECT:
- prefs->SetValue(pref_name_, ProxyConfigDictionary::CreateAutoDetect());
- break;
- case ProxyPrefs::MODE_PAC_SCRIPT: {
- std::string pac_url_string;
- if (pac_url && pac_url->GetAsString(&pac_url_string)) {
- prefs->SetValue(
- pref_name_,
- ProxyConfigDictionary::CreatePacScript(pac_url_string, false));
- } else {
- NOTREACHED();
- }
- break;
- }
- case ProxyPrefs::MODE_FIXED_SERVERS: {
- std::string proxy_server;
- std::string bypass_list_string;
- if (server->GetAsString(&proxy_server)) {
- if (bypass_list)
- bypass_list->GetAsString(&bypass_list_string);
- prefs->SetValue(pref_name_,
- ProxyConfigDictionary::CreateFixedServers(
- proxy_server, bypass_list_string));
- }
- break;
- }
- case ProxyPrefs::MODE_SYSTEM:
- prefs->SetValue(pref_name_, ProxyConfigDictionary::CreateSystem());
- break;
- case ProxyPrefs::kModeCount:
- NOTREACHED();
- }
-}
-
-const Value* ProxyPolicyHandler::GetProxyPolicyValue(
- const PolicyMap& policies, const char* policy_name) {
- // See note on the ProxyPolicyHandler implementation above.
- const Value* value = policies.GetValue(key::kProxySettings);
- const DictionaryValue* settings;
- if (!value || !value->GetAsDictionary(&settings))
- return NULL;
-
- const Value* policy_value = NULL;
- std::string tmp;
- if (!settings->Get(policy_name, &policy_value) ||
- policy_value->IsType(Value::TYPE_NULL) ||
- (policy_value->IsType(Value::TYPE_STRING) &&
- policy_value->GetAsString(&tmp) &&
- tmp.empty())) {
- return NULL;
- }
- return policy_value;
-}
-
-bool ProxyPolicyHandler::CheckProxyModeAndServerMode(const PolicyMap& policies,
- PolicyErrorMap* errors,
- std::string* mode_value) {
- const Value* mode = GetProxyPolicyValue(policies, key::kProxyMode);
- const Value* server = GetProxyPolicyValue(policies, key::kProxyServer);
- const Value* server_mode =
- GetProxyPolicyValue(policies, key::kProxyServerMode);
- const Value* pac_url = GetProxyPolicyValue(policies, key::kProxyPacUrl);
-
- // If there's a server mode, convert it into a mode.
- // When both are specified, the mode takes precedence.
- if (mode) {
- if (server_mode) {
- errors->AddError(key::kProxySettings,
- key::kProxyServerMode,
- IDS_POLICY_OVERRIDDEN,
- key::kProxyMode);
- }
- if (!mode->GetAsString(mode_value)) {
- errors->AddError(key::kProxySettings,
- key::kProxyMode,
- IDS_POLICY_TYPE_ERROR,
- ValueTypeToString(Value::TYPE_BOOLEAN));
- return false;
- }
-
- ProxyPrefs::ProxyMode mode;
- if (!ProxyPrefs::StringToProxyMode(*mode_value, &mode)) {
- errors->AddError(key::kProxySettings,
- key::kProxyMode,
- IDS_POLICY_INVALID_PROXY_MODE_ERROR);
- return false;
- }
-
- if (mode == ProxyPrefs::MODE_PAC_SCRIPT && !pac_url) {
- errors->AddError(key::kProxySettings,
- key::kProxyPacUrl,
- IDS_POLICY_NOT_SPECIFIED_ERROR);
- return false;
- } else if (mode == ProxyPrefs::MODE_FIXED_SERVERS && !server) {
- errors->AddError(key::kProxySettings,
- key::kProxyServer,
- IDS_POLICY_NOT_SPECIFIED_ERROR);
- return false;
- }
- } else if (server_mode) {
- int server_mode_value;
- if (!server_mode->GetAsInteger(&server_mode_value)) {
- errors->AddError(key::kProxySettings,
- key::kProxyServerMode,
- IDS_POLICY_TYPE_ERROR,
- ValueTypeToString(Value::TYPE_INTEGER));
- return false;
- }
-
- switch (server_mode_value) {
- case PROXY_SERVER_MODE:
- *mode_value = ProxyPrefs::kDirectProxyModeName;
- break;
- case PROXY_AUTO_DETECT_PROXY_SERVER_MODE:
- *mode_value = ProxyPrefs::kAutoDetectProxyModeName;
- break;
- case PROXY_MANUALLY_CONFIGURED_PROXY_SERVER_MODE:
- if (server && pac_url) {
- int message_id = IDS_POLICY_PROXY_BOTH_SPECIFIED_ERROR;
- errors->AddError(key::kProxySettings,
- key::kProxyServer,
- message_id);
- errors->AddError(key::kProxySettings,
- key::kProxyPacUrl,
- message_id);
- return false;
- }
- if (!server && !pac_url) {
- int message_id = IDS_POLICY_PROXY_NEITHER_SPECIFIED_ERROR;
- errors->AddError(key::kProxySettings,
- key::kProxyServer,
- message_id);
- errors->AddError(key::kProxySettings,
- key::kProxyPacUrl,
- message_id);
- return false;
- }
- if (pac_url)
- *mode_value = ProxyPrefs::kPacScriptProxyModeName;
- else
- *mode_value = ProxyPrefs::kFixedServersProxyModeName;
- break;
- case PROXY_USE_SYSTEM_PROXY_SERVER_MODE:
- *mode_value = ProxyPrefs::kSystemProxyModeName;
- break;
- default:
- errors->AddError(key::kProxySettings,
- key::kProxyServerMode,
- IDS_POLICY_OUT_OF_RANGE_ERROR,
- base::IntToString(server_mode_value));
- return false;
- }
- }
- return true;
-}
-
-
// JavascriptPolicyHandler implementation --------------------------------------
JavascriptPolicyHandler::JavascriptPolicyHandler(const char* pref_name)
diff --git a/chrome/browser/policy/configuration_policy_handler.h b/chrome/browser/policy/configuration_policy_handler.h
index 0fc8755183..668be54701 100644
--- a/chrome/browser/policy/configuration_policy_handler.h
+++ b/chrome/browser/policy/configuration_policy_handler.h
@@ -228,77 +228,6 @@ class IntPercentageToDoublePolicyHandler : public IntRangePolicyHandlerBase {
DISALLOW_COPY_AND_ASSIGN(IntPercentageToDoublePolicyHandler);
};
-// Implements additional checks for policies that are lists of extension IDs.
-class ExtensionListPolicyHandler : public TypeCheckingPolicyHandler {
- public:
- ExtensionListPolicyHandler(const char* policy_name,
- const char* pref_path,
- bool allow_wildcards);
- virtual ~ExtensionListPolicyHandler();
-
- // ConfigurationPolicyHandler methods:
- virtual bool CheckPolicySettings(const PolicyMap& policies,
- PolicyErrorMap* errors) OVERRIDE;
- virtual void ApplyPolicySettings(const PolicyMap& policies,
- PrefValueMap* prefs) OVERRIDE;
-
- protected:
- const char* pref_path() const;
-
- // Runs sanity checks on the policy value and returns it in |extension_ids|.
- bool CheckAndGetList(const PolicyMap& policies,
- PolicyErrorMap* errors,
- scoped_ptr<base::ListValue>* extension_ids);
-
- private:
- const char* pref_path_;
- bool allow_wildcards_;
-
- DISALLOW_COPY_AND_ASSIGN(ExtensionListPolicyHandler);
-};
-
-class ExtensionInstallForcelistPolicyHandler
- : public TypeCheckingPolicyHandler {
- public:
- explicit ExtensionInstallForcelistPolicyHandler(const char* pref_name);
- virtual ~ExtensionInstallForcelistPolicyHandler();
-
- // ConfigurationPolicyHandler methods:
- virtual bool CheckPolicySettings(const PolicyMap& policies,
- PolicyErrorMap* errors) OVERRIDE;
- virtual void ApplyPolicySettings(const PolicyMap& policies,
- PrefValueMap* prefs) OVERRIDE;
-
- private:
- // Parses the data in |policy_value| and writes them to |extension_dict|.
- bool ParseList(const base::Value* policy_value,
- base::DictionaryValue* extension_dict,
- PolicyErrorMap* errors);
-
- const char* pref_name_;
- DISALLOW_COPY_AND_ASSIGN(ExtensionInstallForcelistPolicyHandler);
-};
-
-// Implements additional checks for policies that are lists of extension
-// URLPatterns.
-class ExtensionURLPatternListPolicyHandler : public TypeCheckingPolicyHandler {
- public:
- ExtensionURLPatternListPolicyHandler(const char* policy_name,
- const char* pref_path);
- virtual ~ExtensionURLPatternListPolicyHandler();
-
- // ConfigurationPolicyHandler methods:
- virtual bool CheckPolicySettings(const PolicyMap& policies,
- PolicyErrorMap* errors) OVERRIDE;
- virtual void ApplyPolicySettings(const PolicyMap& policies,
- PrefValueMap* prefs) OVERRIDE;
-
- private:
- const char* pref_path_;
-
- DISALLOW_COPY_AND_ASSIGN(ExtensionURLPatternListPolicyHandler);
-};
-
// ConfigurationPolicyHandler for the SyncDisabled policy.
class SyncPolicyHandler : public TypeCheckingPolicyHandler {
public:
@@ -331,23 +260,6 @@ class AutofillPolicyHandler : public TypeCheckingPolicyHandler {
#if !defined(OS_ANDROID)
-// ConfigurationPolicyHandler for the DownloadDirectory policy.
-class DownloadDirPolicyHandler : public TypeCheckingPolicyHandler {
- public:
- DownloadDirPolicyHandler(const char* default_directory_pref_name,
- const char* prompt_for_download_pref_name);
- virtual ~DownloadDirPolicyHandler();
-
- // ConfigurationPolicyHandler methods:
- virtual void ApplyPolicySettings(const PolicyMap& policies,
- PrefValueMap* prefs) OVERRIDE;
-
- private:
- const char* default_directory_pref_name_;
- const char* prompt_for_download_pref_name_;
- DISALLOW_COPY_AND_ASSIGN(DownloadDirPolicyHandler);
-};
-
// ConfigurationPolicyHandler for the DiskCacheDir policy.
class DiskCacheDirPolicyHandler : public TypeCheckingPolicyHandler {
public:
@@ -402,151 +314,6 @@ class IncognitoModePolicyHandler : public ConfigurationPolicyHandler {
DISALLOW_COPY_AND_ASSIGN(IncognitoModePolicyHandler);
};
-// ConfigurationPolicyHandler for the DefaultSearchEncodings policy.
-class DefaultSearchEncodingsPolicyHandler : public TypeCheckingPolicyHandler {
- public:
- explicit DefaultSearchEncodingsPolicyHandler(const char* pref_name);
- virtual ~DefaultSearchEncodingsPolicyHandler();
-
- // ConfigurationPolicyHandler methods:
- virtual void ApplyPolicySettings(const PolicyMap& policies,
- PrefValueMap* prefs) OVERRIDE;
-
- const char* pref_name() const { return pref_name_; }
-
- private:
- const char* pref_name_;
- DISALLOW_COPY_AND_ASSIGN(DefaultSearchEncodingsPolicyHandler);
-};
-
-enum DefaultSearchKey {
- DEFAULT_SEARCH_ENABLED,
- DEFAULT_SEARCH_NAME,
- DEFAULT_SEARCH_KEYWORD,
- DEFAULT_SEARCH_SEARCH_URL,
- DEFAULT_SEARCH_SUGGEST_URL,
- DEFAULT_SEARCH_INSTANT_URL,
- DEFAULT_SEARCH_ICON_URL,
- DEFAULT_SEARCH_ENCODINGS,
- DEFAULT_SEARCH_ALTERNATE_URLS,
- DEFAULT_SEARCH_TERMS_REPLACEMENT_KEY,
- DEFAULT_SEARCH_IMAGE_URL,
- DEFAULT_SEARCH_NEW_TAB_URL,
- DEFAULT_SEARCH_SEARCH_URL_POST_PARAMS,
- DEFAULT_SEARCH_SUGGEST_URL_POST_PARAMS,
- DEFAULT_SEARCH_INSTANT_URL_POST_PARAMS,
- DEFAULT_SEARCH_IMAGE_URL_POST_PARAMS,
- // Must be last.
- DEFAULT_SEARCH_KEY_SIZE,
-};
-
-// ConfigurationPolicyHandler for the default search policies.
-class DefaultSearchPolicyHandler : public ConfigurationPolicyHandler {
- public:
- // Constructs a new handler for the DefaultSearch policy with the specified
- // preference names.
- // |id_pref_name|: Pref name for the search provider ID.
- // |prepopulate_id_pref_name|: Pref name for the prepopulated provider ID.
- // |policy_to_pref_map|: Defines the pref names for respective policy keys.
- // Must contain exactly DEFAULT_SEARCH_KEY_SIZE entries and be ordered
- // according to the DefaultSearchKey enum.
- DefaultSearchPolicyHandler(
- const char* id_pref_name,
- const char* prepopulate_id_pref_name,
- const PolicyToPreferenceMapEntry policy_to_pref_map[]);
- virtual ~DefaultSearchPolicyHandler();
-
- // ConfigurationPolicyHandler methods:
- virtual bool CheckPolicySettings(const PolicyMap& policies,
- PolicyErrorMap* errors) OVERRIDE;
- virtual void ApplyPolicySettings(const PolicyMap& policies,
- PrefValueMap* prefs) OVERRIDE;
-
- private:
- // Calls |CheckPolicySettings()| on each of the handlers in |handlers_|
- // and returns whether all of the calls succeeded.
- bool CheckIndividualPolicies(const PolicyMap& policies,
- PolicyErrorMap* errors);
-
- // Returns whether there is a value for |policy_name| in |policies|.
- bool HasDefaultSearchPolicy(const PolicyMap& policies,
- const char* policy_name);
-
- // Returns whether any default search policies are specified in |policies|.
- bool AnyDefaultSearchPoliciesSpecified(const PolicyMap& policies);
-
- // Returns whether the default search provider is disabled.
- bool DefaultSearchProviderIsDisabled(const PolicyMap& policies);
-
- // Returns whether the default search URL is set and valid. On success, both
- // outparams (which must be non-NULL) are filled with the search URL.
- bool DefaultSearchURLIsValid(const PolicyMap& policies,
- const Value** url_value,
- std::string* url_string);
-
- // Make sure that the |path| is present in |prefs_|. If not, set it to
- // a blank string.
- void EnsureStringPrefExists(PrefValueMap* prefs, const std::string& path);
-
- // Make sure that the |path| is present in |prefs_| and is a ListValue. If
- // not, set it to an empty list.
- void EnsureListPrefExists(PrefValueMap* prefs, const std::string& path);
-
- // The ConfigurationPolicyHandler handlers for each default search policy.
- std::vector<TypeCheckingPolicyHandler*> handlers_;
-
- const char* id_pref_name_;
- const char* prepopulate_id_pref_name_;
- const PolicyToPreferenceMapEntry* policy_to_pref_map_; // weak
-
- DISALLOW_COPY_AND_ASSIGN(DefaultSearchPolicyHandler);
-};
-
-// ConfigurationPolicyHandler for the proxy policies.
-class ProxyPolicyHandler : public ConfigurationPolicyHandler {
- public:
- // Constants for the "Proxy Server Mode" defined in the policies.
- // Note that these diverge from internal presentation defined in
- // ProxyPrefs::ProxyMode for legacy reasons. The following four
- // PolicyProxyModeType types were not very precise and had overlapping use
- // cases.
- enum ProxyModeType {
- // Disable Proxy, connect directly.
- PROXY_SERVER_MODE = 0,
- // Auto detect proxy or use specific PAC script if given.
- PROXY_AUTO_DETECT_PROXY_SERVER_MODE = 1,
- // Use manually configured proxy servers (fixed servers).
- PROXY_MANUALLY_CONFIGURED_PROXY_SERVER_MODE = 2,
- // Use system proxy server.
- PROXY_USE_SYSTEM_PROXY_SERVER_MODE = 3,
-
- MODE_COUNT
- };
-
- explicit ProxyPolicyHandler(const char* pref_name);
- virtual ~ProxyPolicyHandler();
-
- // ConfigurationPolicyHandler methods:
- virtual bool CheckPolicySettings(const PolicyMap& policies,
- PolicyErrorMap* errors) OVERRIDE;
- virtual void ApplyPolicySettings(const PolicyMap& policies,
- PrefValueMap* prefs) OVERRIDE;
-
- private:
- const Value* GetProxyPolicyValue(const PolicyMap& policies,
- const char* policy_name);
-
- // Converts the deprecated ProxyServerMode policy value to a ProxyMode value
- // and places the result in |mode_value|. Returns whether the conversion
- // succeeded.
- bool CheckProxyModeAndServerMode(const PolicyMap& policies,
- PolicyErrorMap* errors,
- std::string* mode_value);
-
- const char* pref_name_;
- DISALLOW_COPY_AND_ASSIGN(ProxyPolicyHandler);
-};
-
// Handles JavaScript policies.
class JavascriptPolicyHandler : public ConfigurationPolicyHandler {
public:
diff --git a/chrome/browser/policy/configuration_policy_handler_list.cc b/chrome/browser/policy/configuration_policy_handler_list.cc
index e2a57142be..47d7a15425 100644
--- a/chrome/browser/policy/configuration_policy_handler_list.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list.cc
@@ -10,10 +10,14 @@
#include "base/prefs/pref_value_map.h"
#include "base/stl_util.h"
#include "base/values.h"
+#include "chrome/browser/extensions/policy_handlers.h"
+#include "chrome/browser/net/proxy_policy_handler.h"
#include "chrome/browser/policy/configuration_policy_handler.h"
#include "chrome/browser/policy/policy_error_map.h"
#include "chrome/browser/policy/policy_map.h"
+#include "chrome/browser/search_engines/default_search_policy_handler.h"
#include "chrome/common/pref_names.h"
+#include "components/policy/core/common/policy_pref_names.h"
#include "extensions/common/manifest.h"
#include "grit/generated_resources.h"
#include "policy/policy_constants.h"
@@ -28,68 +32,16 @@
#include "chrome/browser/policy/configuration_policy_handler_android.h"
#endif // defined(OS_ANDROID)
+#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) && !defined(OS_IOS)
+#include "chrome/browser/download/download_dir_policy_handler.h"
+#endif
+
#if !defined(OS_MACOSX)
#include "apps/pref_names.h"
#endif
namespace policy {
-// List of policy types to preference names, for policies affecting the default
-// search provider.
-const PolicyToPreferenceMapEntry kDefaultSearchPolicyMap[] = {
- { key::kDefaultSearchProviderEnabled,
- prefs::kDefaultSearchProviderEnabled,
- Value::TYPE_BOOLEAN },
- { key::kDefaultSearchProviderName,
- prefs::kDefaultSearchProviderName,
- Value::TYPE_STRING },
- { key::kDefaultSearchProviderKeyword,
- prefs::kDefaultSearchProviderKeyword,
- Value::TYPE_STRING },
- { key::kDefaultSearchProviderSearchURL,
- prefs::kDefaultSearchProviderSearchURL,
- Value::TYPE_STRING },
- { key::kDefaultSearchProviderSuggestURL,
- prefs::kDefaultSearchProviderSuggestURL,
- Value::TYPE_STRING },
- { key::kDefaultSearchProviderInstantURL,
- prefs::kDefaultSearchProviderInstantURL,
- Value::TYPE_STRING },
- { key::kDefaultSearchProviderIconURL,
- prefs::kDefaultSearchProviderIconURL,
- Value::TYPE_STRING },
- { key::kDefaultSearchProviderEncodings,
- prefs::kDefaultSearchProviderEncodings,
- Value::TYPE_LIST },
- { key::kDefaultSearchProviderAlternateURLs,
- prefs::kDefaultSearchProviderAlternateURLs,
- Value::TYPE_LIST },
- { key::kDefaultSearchProviderSearchTermsReplacementKey,
- prefs::kDefaultSearchProviderSearchTermsReplacementKey,
- Value::TYPE_STRING },
- { key::kDefaultSearchProviderImageURL,
- prefs::kDefaultSearchProviderImageURL,
- Value::TYPE_STRING },
- { key::kDefaultSearchProviderNewTabURL,
- prefs::kDefaultSearchProviderNewTabURL,
- Value::TYPE_STRING },
- { key::kDefaultSearchProviderSearchURLPostParams,
- prefs::kDefaultSearchProviderSearchURLPostParams,
- Value::TYPE_STRING },
- { key::kDefaultSearchProviderSuggestURLPostParams,
- prefs::kDefaultSearchProviderSuggestURLPostParams,
- Value::TYPE_STRING },
- { key::kDefaultSearchProviderInstantURLPostParams,
- prefs::kDefaultSearchProviderInstantURLPostParams,
- Value::TYPE_STRING },
- { key::kDefaultSearchProviderImageURLPostParams,
- prefs::kDefaultSearchProviderImageURLPostParams,
- Value::TYPE_STRING },
-};
-
-COMPILE_ASSERT(DEFAULT_SEARCH_KEY_SIZE == arraysize(kDefaultSearchPolicyMap),
- wrong_policy_map_size);
-
namespace {
// List of policy types to preference names. This is used for simple policies
@@ -143,9 +95,6 @@ const PolicyToPreferenceMapEntry kSimplePolicyMap[] = {
{ key::kApplicationLocaleValue,
prefs::kApplicationLocale,
Value::TYPE_STRING },
- { key::kExtensionInstallForcelist,
- prefs::kExtensionInstallForceList,
- Value::TYPE_LIST },
{ key::kDisabledPlugins,
prefs::kPluginsDisabledPlugins,
Value::TYPE_LIST },
@@ -279,7 +228,7 @@ const PolicyToPreferenceMapEntry kSimplePolicyMap[] = {
prefs::kMediaCacheSize,
Value::TYPE_INTEGER },
{ key::kPolicyRefreshRate,
- prefs::kUserPolicyRefreshRate,
+ policy_prefs::kUserPolicyRefreshRate,
Value::TYPE_INTEGER },
{ key::kDevicePolicyRefreshRate,
prefs::kDevicePolicyRefreshRate,
@@ -509,33 +458,27 @@ ConfigurationPolicyHandlerList::ConfigurationPolicyHandlerList() {
handlers_.push_back(
new AutofillPolicyHandler(autofill::prefs::kAutofillEnabled));
- handlers_.push_back(
- new DefaultSearchPolicyHandler(prefs::kDefaultSearchProviderID,
- prefs::kDefaultSearchProviderPrepopulateID,
- kDefaultSearchPolicyMap));
+ handlers_.push_back(new DefaultSearchPolicyHandler());
handlers_.push_back(new FileSelectionDialogsHandler(
prefs::kAllowFileSelectionDialogs, prefs::kPromptForDownload));
handlers_.push_back(
new IncognitoModePolicyHandler(prefs::kIncognitoModeAvailability));
handlers_.push_back(
new JavascriptPolicyHandler(prefs::kManagedDefaultJavaScriptSetting));
- handlers_.push_back(new ProxyPolicyHandler(prefs::kProxy));
+ handlers_.push_back(new ProxyPolicyHandler());
handlers_.push_back(new RestoreOnStartupPolicyHandler(
prefs::kRestoreOnStartup, prefs::kURLsToRestoreOnStartup));
handlers_.push_back(new SyncPolicyHandler(prefs::kSyncManaged));
handlers_.push_back(new URLBlacklistPolicyHandler(prefs::kUrlBlacklist));
- handlers_.push_back(
- new ExtensionListPolicyHandler(key::kExtensionInstallWhitelist,
- prefs::kExtensionInstallAllowList,
- false));
- handlers_.push_back(
- new ExtensionListPolicyHandler(key::kExtensionInstallBlacklist,
- prefs::kExtensionInstallDenyList,
- true));
- handlers_.push_back(new ExtensionInstallForcelistPolicyHandler(
- prefs::kExtensionInstallForceList));
- handlers_.push_back(new ExtensionURLPatternListPolicyHandler(
+ handlers_.push_back(new extensions::ExtensionListPolicyHandler(
+ key::kExtensionInstallWhitelist,
+ prefs::kExtensionInstallAllowList,
+ false));
+ handlers_.push_back(new extensions::ExtensionListPolicyHandler(
+ key::kExtensionInstallBlacklist, prefs::kExtensionInstallDenyList, true));
+ handlers_.push_back(new extensions::ExtensionInstallForcelistPolicyHandler());
+ handlers_.push_back(new extensions::ExtensionURLPatternListPolicyHandler(
key::kExtensionInstallSources, prefs::kExtensionAllowedInstallSites));
handlers_.push_back(new StringToIntEnumListPolicyHandler(
key::kExtensionAllowedTypes,
@@ -543,16 +486,15 @@ ConfigurationPolicyHandlerList::ConfigurationPolicyHandlerList() {
kExtensionAllowedTypesMap,
kExtensionAllowedTypesMap + arraysize(kExtensionAllowedTypesMap)));
#if defined(OS_CHROMEOS)
- handlers_.push_back(
- new ExtensionListPolicyHandler(key::kAttestationExtensionWhitelist,
- prefs::kAttestationExtensionWhitelist,
- false));
+ handlers_.push_back(new extensions::ExtensionListPolicyHandler(
+ key::kAttestationExtensionWhitelist,
+ prefs::kAttestationExtensionWhitelist,
+ false));
#endif // defined(OS_CHROMEOS)
-#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
+#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) && !defined(OS_IOS)
handlers_.push_back(new DiskCacheDirPolicyHandler(prefs::kDiskCacheDir));
- handlers_.push_back(new DownloadDirPolicyHandler(
- prefs::kDownloadDefaultDirectory, prefs::kPromptForDownload));
+ handlers_.push_back(new DownloadDirPolicyHandler);
#endif // !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
#if defined(OS_CHROMEOS)
diff --git a/chrome/browser/policy/configuration_policy_handler_list.h b/chrome/browser/policy/configuration_policy_handler_list.h
index 599fd9a5e6..8ecde65951 100644
--- a/chrome/browser/policy/configuration_policy_handler_list.h
+++ b/chrome/browser/policy/configuration_policy_handler_list.h
@@ -18,11 +18,6 @@ class PolicyErrorMap;
class PolicyMap;
struct PolicyToPreferenceMapEntry;
-// Declares the array of policy key to preference name mappings. Contains
-// exactly DEFAULT_SEARCH_KEY entries, which are sorted according to the order
-// of entries in the DefaultSearchKey enum.
-extern const PolicyToPreferenceMapEntry kDefaultSearchPolicyMap[];
-
// Converts policies to their corresponding preferences. Also does error
// checking and cleans up policy values for displaying.
class ConfigurationPolicyHandlerList {
diff --git a/chrome/browser/policy/configuration_policy_handler_list_unittest.cc b/chrome/browser/policy/configuration_policy_handler_list_unittest.cc
deleted file mode 100644
index c37e94f214..0000000000
--- a/chrome/browser/policy/configuration_policy_handler_list_unittest.cc
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/policy/configuration_policy_handler.h"
-#include "chrome/browser/policy/configuration_policy_handler_list.h"
-#include "policy/policy_constants.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace policy {
-
-TEST(DefaultSearchPolicyHandlerTest, PolicyToPreferenceMapInitialization) {
- EXPECT_EQ(kDefaultSearchPolicyMap[DEFAULT_SEARCH_ENABLED].policy_name,
- (const char * const)key::kDefaultSearchProviderEnabled);
- EXPECT_EQ(kDefaultSearchPolicyMap[DEFAULT_SEARCH_NAME].policy_name,
- (const char * const)key::kDefaultSearchProviderName);
- EXPECT_EQ(kDefaultSearchPolicyMap[DEFAULT_SEARCH_KEYWORD].policy_name,
- (const char * const)key::kDefaultSearchProviderKeyword);
- EXPECT_EQ(kDefaultSearchPolicyMap[DEFAULT_SEARCH_SEARCH_URL].policy_name,
- (const char * const)key::kDefaultSearchProviderSearchURL);
- EXPECT_EQ(kDefaultSearchPolicyMap[DEFAULT_SEARCH_SUGGEST_URL].policy_name,
- (const char * const)key::kDefaultSearchProviderSuggestURL);
- EXPECT_EQ(kDefaultSearchPolicyMap[DEFAULT_SEARCH_INSTANT_URL].policy_name,
- (const char * const)key::kDefaultSearchProviderInstantURL);
- EXPECT_EQ(kDefaultSearchPolicyMap[DEFAULT_SEARCH_ICON_URL].policy_name,
- (const char * const)key::kDefaultSearchProviderIconURL);
- EXPECT_EQ(kDefaultSearchPolicyMap[DEFAULT_SEARCH_ENCODINGS].policy_name,
- (const char * const)key::kDefaultSearchProviderEncodings);
- EXPECT_EQ(kDefaultSearchPolicyMap[DEFAULT_SEARCH_ALTERNATE_URLS].policy_name,
- (const char * const)key::kDefaultSearchProviderAlternateURLs);
- EXPECT_EQ(
- kDefaultSearchPolicyMap[DEFAULT_SEARCH_TERMS_REPLACEMENT_KEY].policy_name,
- (const char * const)key::kDefaultSearchProviderSearchTermsReplacementKey);
- EXPECT_EQ(kDefaultSearchPolicyMap[DEFAULT_SEARCH_IMAGE_URL].policy_name,
- (const char * const)key::kDefaultSearchProviderImageURL);
- EXPECT_EQ(kDefaultSearchPolicyMap[DEFAULT_SEARCH_NEW_TAB_URL].policy_name,
- (const char * const)key::kDefaultSearchProviderNewTabURL);
- EXPECT_EQ(kDefaultSearchPolicyMap[DEFAULT_SEARCH_SEARCH_URL_POST_PARAMS]
- .policy_name,
- (const char * const)key::kDefaultSearchProviderSearchURLPostParams);
- EXPECT_EQ(
- kDefaultSearchPolicyMap[DEFAULT_SEARCH_SUGGEST_URL_POST_PARAMS]
- .policy_name,
- (const char * const)key::kDefaultSearchProviderSuggestURLPostParams);
- EXPECT_EQ(
- kDefaultSearchPolicyMap[DEFAULT_SEARCH_INSTANT_URL_POST_PARAMS]
- .policy_name,
- (const char * const)key::kDefaultSearchProviderInstantURLPostParams);
- EXPECT_EQ(
- kDefaultSearchPolicyMap[DEFAULT_SEARCH_IMAGE_URL_POST_PARAMS].policy_name,
- (const char * const)key::kDefaultSearchProviderImageURLPostParams);
-}
-
-} // namespace policy
diff --git a/chrome/browser/policy/configuration_policy_handler_unittest.cc b/chrome/browser/policy/configuration_policy_handler_unittest.cc
index 703b8b839a..7d66c1ff43 100644
--- a/chrome/browser/policy/configuration_policy_handler_unittest.cc
+++ b/chrome/browser/policy/configuration_policy_handler_unittest.cc
@@ -5,7 +5,6 @@
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "base/prefs/pref_value_map.h"
-#include "chrome/browser/extensions/external_policy_loader.h"
#include "chrome/browser/policy/configuration_policy_handler.h"
#include "chrome/browser/policy/external_data_fetcher.h"
#include "chrome/browser/policy/policy_error_map.h"
@@ -485,208 +484,4 @@ TEST(IntPercentageToDoublePolicyHandler, ApplyPolicySettingsDontClamp) {
EXPECT_TRUE(base::Value::Equals(expected.get(), value));
}
-TEST(ExtensionListPolicyHandlerTest, CheckPolicySettings) {
- base::ListValue list;
- PolicyMap policy_map;
- PolicyErrorMap errors;
- ExtensionListPolicyHandler handler(
- key::kExtensionInstallBlacklist, kTestPref, true);
-
- policy_map.Set(key::kExtensionInstallBlacklist, POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER, list.DeepCopy(), NULL);
- errors.Clear();
- EXPECT_TRUE(handler.CheckPolicySettings(policy_map, &errors));
- EXPECT_TRUE(errors.empty());
-
- list.Append(Value::CreateStringValue("abcdefghijklmnopabcdefghijklmnop"));
- policy_map.Set(key::kExtensionInstallBlacklist, POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER, list.DeepCopy(), NULL);
- errors.Clear();
- EXPECT_TRUE(handler.CheckPolicySettings(policy_map, &errors));
- EXPECT_TRUE(errors.empty());
-
- list.Append(Value::CreateStringValue("*"));
- policy_map.Set(key::kExtensionInstallBlacklist, POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER, list.DeepCopy(), NULL);
- errors.Clear();
- EXPECT_TRUE(handler.CheckPolicySettings(policy_map, &errors));
- EXPECT_TRUE(errors.empty());
-
- list.Append(Value::CreateStringValue("invalid"));
- policy_map.Set(key::kExtensionInstallBlacklist, POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER, list.DeepCopy(), NULL);
- errors.Clear();
- EXPECT_TRUE(handler.CheckPolicySettings(policy_map, &errors));
- EXPECT_FALSE(errors.empty());
- EXPECT_FALSE(errors.GetErrors(key::kExtensionInstallBlacklist).empty());
-}
-
-TEST(ExtensionListPolicyHandlerTest, ApplyPolicySettings) {
- base::ListValue policy;
- base::ListValue expected;
- PolicyMap policy_map;
- PrefValueMap prefs;
- base::Value* value = NULL;
- ExtensionListPolicyHandler handler(
- key::kExtensionInstallBlacklist, kTestPref, false);
-
- policy.Append(Value::CreateStringValue("abcdefghijklmnopabcdefghijklmnop"));
- expected.Append(Value::CreateStringValue("abcdefghijklmnopabcdefghijklmnop"));
-
- policy_map.Set(key::kExtensionInstallBlacklist, POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER, policy.DeepCopy(), NULL);
- handler.ApplyPolicySettings(policy_map, &prefs);
- EXPECT_TRUE(prefs.GetValue(kTestPref, &value));
- EXPECT_TRUE(base::Value::Equals(&expected, value));
-
- policy.Append(Value::CreateStringValue("invalid"));
- policy_map.Set(key::kExtensionInstallBlacklist, POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER, policy.DeepCopy(), NULL);
- handler.ApplyPolicySettings(policy_map, &prefs);
- EXPECT_TRUE(prefs.GetValue(kTestPref, &value));
- EXPECT_TRUE(base::Value::Equals(&expected, value));
-}
-
-TEST(ExtensionInstallForcelistPolicyHandlerTest, CheckPolicySettings) {
- base::ListValue list;
- PolicyMap policy_map;
- PolicyErrorMap errors;
- ExtensionInstallForcelistPolicyHandler handler(kTestPref);
-
- policy_map.Set(key::kExtensionInstallForcelist, POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER, list.DeepCopy(), NULL);
- errors.Clear();
- EXPECT_TRUE(handler.CheckPolicySettings(policy_map, &errors));
- EXPECT_TRUE(errors.empty());
-
- list.AppendString("abcdefghijklmnopabcdefghijklmnop;http://example.com");
- policy_map.Set(key::kExtensionInstallForcelist, POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER, list.DeepCopy(), NULL);
- errors.Clear();
- EXPECT_TRUE(handler.CheckPolicySettings(policy_map, &errors));
- EXPECT_TRUE(errors.empty());
-
- // Add an erroneous entry. This should generate an error, but the good
- // entry should still be translated successfully.
- list.AppendString("adfasdf;http://example.com");
- policy_map.Set(key::kExtensionInstallForcelist, POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER, list.DeepCopy(), NULL);
- errors.Clear();
- EXPECT_TRUE(handler.CheckPolicySettings(policy_map, &errors));
- EXPECT_EQ(1U, errors.size());
-
- // Add an entry with bad URL, which should generate another error.
- list.AppendString("abcdefghijklmnopabcdefghijklmnop;nourl");
- policy_map.Set(key::kExtensionInstallForcelist, POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER, list.DeepCopy(), NULL);
- errors.Clear();
- EXPECT_TRUE(handler.CheckPolicySettings(policy_map, &errors));
- EXPECT_EQ(2U, errors.size());
-
- // Just an extension ID should also generate an error.
- list.AppendString("abcdefghijklmnopabcdefghijklmnop");
- policy_map.Set(key::kExtensionInstallForcelist, POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER, list.DeepCopy(), NULL);
- errors.Clear();
- EXPECT_TRUE(handler.CheckPolicySettings(policy_map, &errors));
- EXPECT_EQ(3U, errors.size());
-}
-
-TEST(ExtensionInstallForcelistPolicyHandlerTest, ApplyPolicySettings) {
- base::ListValue policy;
- base::DictionaryValue expected;
- PolicyMap policy_map;
- PrefValueMap prefs;
- base::Value* value = NULL;
- ExtensionInstallForcelistPolicyHandler handler(kTestPref);
-
- handler.ApplyPolicySettings(policy_map, &prefs);
- EXPECT_FALSE(prefs.GetValue(kTestPref, &value));
- EXPECT_FALSE(value);
-
- policy_map.Set(key::kExtensionInstallForcelist, POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER, policy.DeepCopy(), NULL);
- handler.ApplyPolicySettings(policy_map, &prefs);
- EXPECT_TRUE(prefs.GetValue(kTestPref, &value));
- EXPECT_TRUE(base::Value::Equals(&expected, value));
-
- policy.AppendString("abcdefghijklmnopabcdefghijklmnop;http://example.com");
- extensions::ExternalPolicyLoader::AddExtension(
- &expected, "abcdefghijklmnopabcdefghijklmnop", "http://example.com");
- policy_map.Set(key::kExtensionInstallForcelist, POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER, policy.DeepCopy(), NULL);
- handler.ApplyPolicySettings(policy_map, &prefs);
- EXPECT_TRUE(prefs.GetValue(kTestPref, &value));
- EXPECT_TRUE(base::Value::Equals(&expected, value));
-
- policy.AppendString("invalid");
- policy_map.Set(key::kExtensionInstallForcelist, POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER, policy.DeepCopy(), NULL);
- handler.ApplyPolicySettings(policy_map, &prefs);
- EXPECT_TRUE(prefs.GetValue(kTestPref, &value));
- EXPECT_TRUE(base::Value::Equals(&expected, value));
-}
-
-TEST(ExtensionURLPatternListPolicyHandlerTest, CheckPolicySettings) {
- base::ListValue list;
- PolicyMap policy_map;
- PolicyErrorMap errors;
- ExtensionURLPatternListPolicyHandler handler(key::kExtensionInstallSources,
- kTestPref);
-
- policy_map.Set(key::kExtensionInstallSources, POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER, list.DeepCopy(), NULL);
- errors.Clear();
- EXPECT_TRUE(handler.CheckPolicySettings(policy_map, &errors));
- EXPECT_TRUE(errors.empty());
-
- list.Append(Value::CreateStringValue("http://*.google.com/*"));
- policy_map.Set(key::kExtensionInstallSources, POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER, list.DeepCopy(), NULL);
- errors.Clear();
- EXPECT_TRUE(handler.CheckPolicySettings(policy_map, &errors));
- EXPECT_TRUE(errors.empty());
-
- list.Append(Value::CreateStringValue("<all_urls>"));
- policy_map.Set(key::kExtensionInstallSources, POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER, list.DeepCopy(), NULL);
- errors.Clear();
- EXPECT_TRUE(handler.CheckPolicySettings(policy_map, &errors));
- EXPECT_TRUE(errors.empty());
-
- list.Append(Value::CreateStringValue("invalid"));
- policy_map.Set(key::kExtensionInstallSources, POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER, list.DeepCopy(), NULL);
- errors.Clear();
- EXPECT_FALSE(handler.CheckPolicySettings(policy_map, &errors));
- EXPECT_FALSE(errors.empty());
- EXPECT_FALSE(errors.GetErrors(key::kExtensionInstallSources).empty());
-
- // URLPattern syntax has a different way to express 'all urls'. Though '*'
- // would be compatible today, it would be brittle, so we disallow.
- list.Append(Value::CreateStringValue("*"));
- policy_map.Set(key::kExtensionInstallSources, POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER, list.DeepCopy(), NULL);
- errors.Clear();
- EXPECT_FALSE(handler.CheckPolicySettings(policy_map, &errors));
- EXPECT_FALSE(errors.empty());
- EXPECT_FALSE(errors.GetErrors(key::kExtensionInstallSources).empty());
-}
-
-TEST(ExtensionURLPatternListPolicyHandlerTest, ApplyPolicySettings) {
- base::ListValue list;
- PolicyMap policy_map;
- PrefValueMap prefs;
- base::Value* value = NULL;
- ExtensionURLPatternListPolicyHandler handler(key::kExtensionInstallSources,
- kTestPref);
-
- list.Append(Value::CreateStringValue("https://corp.monkey.net/*"));
- policy_map.Set(key::kExtensionInstallSources, POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER, list.DeepCopy(), NULL);
- handler.ApplyPolicySettings(policy_map, &prefs);
- ASSERT_TRUE(prefs.GetValue(kTestPref, &value));
- EXPECT_TRUE(base::Value::Equals(&list, value));
-}
-
} // namespace policy
diff --git a/chrome/browser/policy/configuration_policy_pref_store_unittest.cc b/chrome/browser/policy/configuration_policy_pref_store_unittest.cc
index 6df3ae942f..cc68d69158 100644
--- a/chrome/browser/policy/configuration_policy_pref_store_unittest.cc
+++ b/chrome/browser/policy/configuration_policy_pref_store_unittest.cc
@@ -2,28 +2,25 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "chrome/browser/policy/configuration_policy_pref_store_unittest.h"
+
#include <string>
#include "base/callback.h"
#include "base/files/file_path.h"
-#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
#include "base/prefs/pref_store_observer_mock.h"
#include "base/run_loop.h"
#include "chrome/browser/policy/configuration_policy_handler.h"
-#include "chrome/browser/policy/configuration_policy_handler_list.h"
#include "chrome/browser/policy/configuration_policy_pref_store.h"
#include "chrome/browser/policy/external_data_fetcher.h"
-#include "chrome/browser/policy/mock_configuration_policy_provider.h"
#include "chrome/browser/policy/policy_map.h"
#include "chrome/browser/policy/policy_service_impl.h"
#include "chrome/browser/prefs/incognito_mode_prefs.h"
-#include "chrome/browser/prefs/proxy_config_dictionary.h"
#include "chrome/common/content_settings.h"
#include "chrome/common/pref_names.h"
+#include "components/policy/core/common/policy_pref_names.h"
#include "policy/policy_constants.h"
#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
using testing::Mock;
using testing::Return;
@@ -46,36 +43,29 @@ class PolicyAndPref {
const char* pref_name_;
};
-class ConfigurationPolicyPrefStoreTest : public testing::Test {
- protected:
- ConfigurationPolicyPrefStoreTest() {
- EXPECT_CALL(provider_, IsInitializationComplete(_))
- .WillRepeatedly(Return(false));
- provider_.Init();
- PolicyServiceImpl::Providers providers;
- providers.push_back(&provider_);
- policy_service_.reset(new PolicyServiceImpl(providers));
- store_ = new ConfigurationPolicyPrefStore(policy_service_.get(),
- &handler_list_,
- POLICY_LEVEL_MANDATORY);
- }
+ConfigurationPolicyPrefStoreTest::ConfigurationPolicyPrefStoreTest() {
+ EXPECT_CALL(provider_, IsInitializationComplete(_))
+ .WillRepeatedly(Return(false));
+ provider_.Init();
+ PolicyServiceImpl::Providers providers;
+ providers.push_back(&provider_);
+ policy_service_.reset(new PolicyServiceImpl(providers));
+ store_ = new ConfigurationPolicyPrefStore(
+ policy_service_.get(), &handler_list_, POLICY_LEVEL_MANDATORY);
+}
- virtual void TearDown() OVERRIDE {
- provider_.Shutdown();
- }
+ConfigurationPolicyPrefStoreTest::~ConfigurationPolicyPrefStoreTest() {}
- void UpdateProviderPolicy(const PolicyMap& policy) {
- provider_.UpdateChromePolicy(policy);
- base::RunLoop loop;
- loop.RunUntilIdle();
- }
+void ConfigurationPolicyPrefStoreTest::TearDown() {
+ provider_.Shutdown();
+}
- ConfigurationPolicyHandlerList handler_list_;
- MockConfigurationPolicyProvider provider_;
- scoped_ptr<PolicyServiceImpl> policy_service_;
- scoped_refptr<ConfigurationPolicyPrefStore> store_;
- base::MessageLoop loop_;
-};
+void ConfigurationPolicyPrefStoreTest::UpdateProviderPolicy(
+ const PolicyMap& policy) {
+ provider_.UpdateChromePolicy(policy);
+ base::RunLoop loop;
+ loop.RunUntilIdle();
+}
// Test cases for list-valued policy settings.
class ConfigurationPolicyPrefStoreListTest
@@ -365,544 +355,10 @@ INSTANTIATE_TEST_CASE_P(
PolicyAndPref(key::kMediaCacheSize,
prefs::kMediaCacheSize),
PolicyAndPref(key::kPolicyRefreshRate,
- prefs::kUserPolicyRefreshRate),
+ policy_prefs::kUserPolicyRefreshRate),
PolicyAndPref(key::kMaxConnectionsPerProxy,
prefs::kMaxConnectionsPerProxy)));
-// Test cases for the proxy policy settings.
-class ConfigurationPolicyPrefStoreProxyTest
- : public ConfigurationPolicyPrefStoreTest {
- protected:
- // Verify that all the proxy prefs are set to the specified expected values.
- void VerifyProxyPrefs(
- const std::string& expected_proxy_server,
- const std::string& expected_proxy_pac_url,
- const std::string& expected_proxy_bypass_list,
- const ProxyPrefs::ProxyMode& expected_proxy_mode) {
- const base::Value* value = NULL;
- ASSERT_TRUE(store_->GetValue(prefs::kProxy, &value));
- ASSERT_EQ(base::Value::TYPE_DICTIONARY, value->GetType());
- ProxyConfigDictionary dict(
- static_cast<const base::DictionaryValue*>(value));
- std::string s;
- if (expected_proxy_server.empty()) {
- EXPECT_FALSE(dict.GetProxyServer(&s));
- } else {
- ASSERT_TRUE(dict.GetProxyServer(&s));
- EXPECT_EQ(expected_proxy_server, s);
- }
- if (expected_proxy_pac_url.empty()) {
- EXPECT_FALSE(dict.GetPacUrl(&s));
- } else {
- ASSERT_TRUE(dict.GetPacUrl(&s));
- EXPECT_EQ(expected_proxy_pac_url, s);
- }
- if (expected_proxy_bypass_list.empty()) {
- EXPECT_FALSE(dict.GetBypassList(&s));
- } else {
- ASSERT_TRUE(dict.GetBypassList(&s));
- EXPECT_EQ(expected_proxy_bypass_list, s);
- }
- ProxyPrefs::ProxyMode mode;
- ASSERT_TRUE(dict.GetMode(&mode));
- EXPECT_EQ(expected_proxy_mode, mode);
- }
-};
-
-TEST_F(ConfigurationPolicyPrefStoreProxyTest, ManualOptions) {
- PolicyMap policy;
- policy.Set(key::kProxyBypassList, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
- base::Value::CreateStringValue("http://chromium.org/override"),
- NULL);
- policy.Set(key::kProxyServer, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
- base::Value::CreateStringValue("chromium.org"), NULL);
- policy.Set(
- key::kProxyServerMode, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
- base::Value::CreateIntegerValue(
- ProxyPolicyHandler::PROXY_MANUALLY_CONFIGURED_PROXY_SERVER_MODE),
- NULL);
- UpdateProviderPolicy(policy);
-
- VerifyProxyPrefs("chromium.org",
- std::string(),
- "http://chromium.org/override",
- ProxyPrefs::MODE_FIXED_SERVERS);
-}
-
-TEST_F(ConfigurationPolicyPrefStoreProxyTest, ManualOptionsReversedApplyOrder) {
- PolicyMap policy;
- policy.Set(
- key::kProxyServerMode, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
- base::Value::CreateIntegerValue(
- ProxyPolicyHandler::PROXY_MANUALLY_CONFIGURED_PROXY_SERVER_MODE),
- NULL);
- policy.Set(key::kProxyBypassList, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
- base::Value::CreateStringValue("http://chromium.org/override"),
- NULL);
- policy.Set(key::kProxyServer, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
- base::Value::CreateStringValue("chromium.org"), NULL);
- UpdateProviderPolicy(policy);
-
- VerifyProxyPrefs("chromium.org",
- std::string(),
- "http://chromium.org/override",
- ProxyPrefs::MODE_FIXED_SERVERS);
-}
-
-TEST_F(ConfigurationPolicyPrefStoreProxyTest, ManualOptionsInvalid) {
- PolicyMap policy;
- policy.Set(
- key::kProxyServerMode, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
- base::Value::CreateIntegerValue(
- ProxyPolicyHandler::PROXY_MANUALLY_CONFIGURED_PROXY_SERVER_MODE),
- NULL);
- UpdateProviderPolicy(policy);
-
- const base::Value* value = NULL;
- EXPECT_FALSE(store_->GetValue(prefs::kProxy, &value));
-}
-
-
-TEST_F(ConfigurationPolicyPrefStoreProxyTest, NoProxyServerMode) {
- PolicyMap policy;
- policy.Set(key::kProxyServerMode, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
- base::Value::CreateIntegerValue(
- ProxyPolicyHandler::PROXY_SERVER_MODE),
- NULL);
- UpdateProviderPolicy(policy);
- VerifyProxyPrefs(
- std::string(), std::string(), std::string(), ProxyPrefs::MODE_DIRECT);
-}
-
-TEST_F(ConfigurationPolicyPrefStoreProxyTest, NoProxyModeName) {
- PolicyMap policy;
- policy.Set(key::kProxyMode, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
- base::Value::CreateStringValue(ProxyPrefs::kDirectProxyModeName),
- NULL);
- UpdateProviderPolicy(policy);
- VerifyProxyPrefs(
- std::string(), std::string(), std::string(), ProxyPrefs::MODE_DIRECT);
-}
-
-TEST_F(ConfigurationPolicyPrefStoreProxyTest, AutoDetectProxyServerMode) {
- PolicyMap policy;
- policy.Set(
- key::kProxyServerMode, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
- base::Value::CreateIntegerValue(
- ProxyPolicyHandler::PROXY_AUTO_DETECT_PROXY_SERVER_MODE),
- NULL);
- UpdateProviderPolicy(policy);
- VerifyProxyPrefs(std::string(),
- std::string(),
- std::string(),
- ProxyPrefs::MODE_AUTO_DETECT);
-}
-
-TEST_F(ConfigurationPolicyPrefStoreProxyTest, AutoDetectProxyModeName) {
- PolicyMap policy;
- policy.Set(key::kProxyMode, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
- base::Value::CreateStringValue(
- ProxyPrefs::kAutoDetectProxyModeName),
- NULL);
- UpdateProviderPolicy(policy);
- VerifyProxyPrefs(std::string(),
- std::string(),
- std::string(),
- ProxyPrefs::MODE_AUTO_DETECT);
-}
-
-TEST_F(ConfigurationPolicyPrefStoreProxyTest, PacScriptProxyMode) {
- PolicyMap policy;
- policy.Set(key::kProxyPacUrl, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
- base::Value::CreateStringValue("http://short.org/proxy.pac"),
- NULL);
- policy.Set(key::kProxyMode, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
- base::Value::CreateStringValue(
- ProxyPrefs::kPacScriptProxyModeName),
- NULL);
- UpdateProviderPolicy(policy);
- VerifyProxyPrefs(std::string(),
- "http://short.org/proxy.pac",
- std::string(),
- ProxyPrefs::MODE_PAC_SCRIPT);
-}
-
-TEST_F(ConfigurationPolicyPrefStoreProxyTest, PacScriptProxyModeInvalid) {
- PolicyMap policy;
- policy.Set(key::kProxyMode, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
- base::Value::CreateStringValue(
- ProxyPrefs::kPacScriptProxyModeName),
- NULL);
- UpdateProviderPolicy(policy);
- const base::Value* value = NULL;
- EXPECT_FALSE(store_->GetValue(prefs::kProxy, &value));
-}
-
-// Regression test for http://crbug.com/78016, CPanel returns empty strings
-// for unset properties.
-TEST_F(ConfigurationPolicyPrefStoreProxyTest, PacScriptProxyModeBug78016) {
- PolicyMap policy;
- policy.Set(key::kProxyServer,
- POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER,
- base::Value::CreateStringValue(std::string()),
- NULL);
- policy.Set(key::kProxyPacUrl,
- POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER,
- base::Value::CreateStringValue("http://short.org/proxy.pac"),
- NULL);
- policy.Set(key::kProxyMode, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
- base::Value::CreateStringValue(
- ProxyPrefs::kPacScriptProxyModeName),
- NULL);
- UpdateProviderPolicy(policy);
- VerifyProxyPrefs(std::string(),
- "http://short.org/proxy.pac",
- std::string(),
- ProxyPrefs::MODE_PAC_SCRIPT);
-}
-
-TEST_F(ConfigurationPolicyPrefStoreProxyTest, UseSystemProxyServerMode) {
- PolicyMap policy;
- policy.Set(key::kProxyServerMode, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
- base::Value::CreateIntegerValue(
- ProxyPolicyHandler::PROXY_USE_SYSTEM_PROXY_SERVER_MODE),
- NULL);
- UpdateProviderPolicy(policy);
- VerifyProxyPrefs(
- std::string(), std::string(), std::string(), ProxyPrefs::MODE_SYSTEM);
-}
-
-TEST_F(ConfigurationPolicyPrefStoreProxyTest, UseSystemProxyMode) {
- PolicyMap policy;
- policy.Set(key::kProxyMode, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
- base::Value::CreateStringValue(ProxyPrefs::kSystemProxyModeName),
- NULL);
- UpdateProviderPolicy(policy);
- VerifyProxyPrefs(
- std::string(), std::string(), std::string(), ProxyPrefs::MODE_SYSTEM);
-}
-
-TEST_F(ConfigurationPolicyPrefStoreProxyTest,
- ProxyModeOverridesProxyServerMode) {
- PolicyMap policy;
- policy.Set(key::kProxyServerMode, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
- base::Value::CreateIntegerValue(
- ProxyPolicyHandler::PROXY_SERVER_MODE),
- NULL);
- policy.Set(key::kProxyMode, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
- base::Value::CreateStringValue(
- ProxyPrefs::kAutoDetectProxyModeName),
- NULL);
- UpdateProviderPolicy(policy);
- VerifyProxyPrefs(std::string(),
- std::string(),
- std::string(),
- ProxyPrefs::MODE_AUTO_DETECT);
-}
-
-TEST_F(ConfigurationPolicyPrefStoreProxyTest, ProxyInvalid) {
- // No mode expects all three parameters being set.
- PolicyMap policy;
- policy.Set(key::kProxyPacUrl, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
- base::Value::CreateStringValue("http://short.org/proxy.pac"),
- NULL);
- policy.Set(key::kProxyBypassList, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
- base::Value::CreateStringValue("http://chromium.org/override"),
- NULL);
- policy.Set(key::kProxyServer, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
- base::Value::CreateStringValue("chromium.org"), NULL);
- for (int i = 0; i < ProxyPolicyHandler::MODE_COUNT; ++i) {
- policy.Set(key::kProxyServerMode, POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER, base::Value::CreateIntegerValue(i), NULL);
- UpdateProviderPolicy(policy);
- const base::Value* value = NULL;
- EXPECT_FALSE(store_->GetValue(prefs::kProxy, &value));
- }
-}
-
-class ConfigurationPolicyPrefStoreDefaultSearchTest
- : public ConfigurationPolicyPrefStoreTest {
- public:
- ConfigurationPolicyPrefStoreDefaultSearchTest() {
- default_alternate_urls_.AppendString(
- "http://www.google.com/#q={searchTerms}");
- default_alternate_urls_.AppendString(
- "http://www.google.com/search#q={searchTerms}");
- }
-
- protected:
- static const char* const kSearchURL;
- static const char* const kSuggestURL;
- static const char* const kIconURL;
- static const char* const kName;
- static const char* const kKeyword;
- static const char* const kReplacementKey;
- static const char* const kImageURL;
- static const char* const kImageParams;
- static const char* const kNewTabURL;
-
- // Build a default search policy by setting search-related keys in |policy| to
- // reasonable values. You can update any of the keys after calling this
- // method.
- void BuildDefaultSearchPolicy(PolicyMap* policy);
-
- base::ListValue default_alternate_urls_;
-};
-
-const char* const ConfigurationPolicyPrefStoreDefaultSearchTest::kSearchURL =
- "http://test.com/search?t={searchTerms}";
-const char* const ConfigurationPolicyPrefStoreDefaultSearchTest::kSuggestURL =
- "http://test.com/sugg?={searchTerms}";
-const char* const ConfigurationPolicyPrefStoreDefaultSearchTest::kIconURL =
- "http://test.com/icon.jpg";
-const char* const ConfigurationPolicyPrefStoreDefaultSearchTest::kName =
- "MyName";
-const char* const ConfigurationPolicyPrefStoreDefaultSearchTest::kKeyword =
- "MyKeyword";
-const char* const
- ConfigurationPolicyPrefStoreDefaultSearchTest::kReplacementKey = "espv";
-const char* const ConfigurationPolicyPrefStoreDefaultSearchTest::kImageURL =
- "http://test.com/searchbyimage/upload";
-const char* const ConfigurationPolicyPrefStoreDefaultSearchTest::kImageParams =
- "image_content=content,image_url=http://test.com/test.png";
-const char* const ConfigurationPolicyPrefStoreDefaultSearchTest::kNewTabURL =
- "http://test.com/newtab";
-
-void ConfigurationPolicyPrefStoreDefaultSearchTest::
- BuildDefaultSearchPolicy(PolicyMap* policy) {
- base::ListValue* encodings = new base::ListValue();
- encodings->AppendString("UTF-16");
- encodings->AppendString("UTF-8");
- policy->Set(key::kDefaultSearchProviderEnabled, POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER, base::Value::CreateBooleanValue(true), NULL);
- policy->Set(key::kDefaultSearchProviderSearchURL, POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER, base::Value::CreateStringValue(kSearchURL),
- NULL);
- policy->Set(key::kDefaultSearchProviderName, POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER, base::Value::CreateStringValue(kName), NULL);
- policy->Set(key::kDefaultSearchProviderKeyword, POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER, base::Value::CreateStringValue(kKeyword),
- NULL);
- policy->Set(key::kDefaultSearchProviderSuggestURL, POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER, base::Value::CreateStringValue(kSuggestURL),
- NULL);
- policy->Set(key::kDefaultSearchProviderIconURL, POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER, base::Value::CreateStringValue(kIconURL),
- NULL);
- policy->Set(key::kDefaultSearchProviderEncodings, POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER, encodings, NULL);
- policy->Set(key::kDefaultSearchProviderAlternateURLs, POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER, default_alternate_urls_.DeepCopy(), NULL);
- policy->Set(key::kDefaultSearchProviderSearchTermsReplacementKey,
- POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
- base::Value::CreateStringValue(kReplacementKey), NULL);
- policy->Set(key::kDefaultSearchProviderImageURL,
- POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
- base::Value::CreateStringValue(kImageURL), NULL);
- policy->Set(key::kDefaultSearchProviderImageURLPostParams,
- POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
- base::Value::CreateStringValue(kImageParams), NULL);
- policy->Set(key::kDefaultSearchProviderNewTabURL,
- POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
- base::Value::CreateStringValue(kNewTabURL), NULL);
-}
-
-// Checks that if the policy for default search is valid, i.e. there's a
-// search URL, that all the elements have been given proper defaults.
-TEST_F(ConfigurationPolicyPrefStoreDefaultSearchTest, MinimallyDefined) {
- PolicyMap policy;
- policy.Set(key::kDefaultSearchProviderEnabled, POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER, base::Value::CreateBooleanValue(true), NULL);
- policy.Set(key::kDefaultSearchProviderSearchURL, POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER, base::Value::CreateStringValue(kSearchURL),
- NULL);
- UpdateProviderPolicy(policy);
-
- const base::Value* value = NULL;
- EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderSearchURL, &value));
- EXPECT_TRUE(base::StringValue(kSearchURL).Equals(value));
-
- EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderName, &value));
- EXPECT_TRUE(base::StringValue("test.com").Equals(value));
-
- EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderKeyword, &value));
- EXPECT_TRUE(base::StringValue("test.com").Equals(value));
-
- EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderSuggestURL,
- &value));
- EXPECT_TRUE(base::StringValue(std::string()).Equals(value));
-
- EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderIconURL, &value));
- EXPECT_TRUE(base::StringValue(std::string()).Equals(value));
-
- EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderEncodings, &value));
- EXPECT_TRUE(base::StringValue(std::string()).Equals(value));
-
- EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderInstantURL,
- &value));
- EXPECT_TRUE(base::StringValue(std::string()).Equals(value));
-
- EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderAlternateURLs,
- &value));
- EXPECT_TRUE(base::ListValue().Equals(value));
-
- EXPECT_TRUE(
- store_->GetValue(prefs::kDefaultSearchProviderSearchTermsReplacementKey,
- &value));
- EXPECT_TRUE(base::StringValue(std::string()).Equals(value));
-
- EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderImageURL, &value));
- EXPECT_TRUE(base::StringValue(std::string()).Equals(value));
-
- EXPECT_TRUE(store_->GetValue(
- prefs::kDefaultSearchProviderSearchURLPostParams, &value));
- EXPECT_TRUE(base::StringValue(std::string()).Equals(value));
-
- EXPECT_TRUE(store_->GetValue(
- prefs::kDefaultSearchProviderSuggestURLPostParams, &value));
- EXPECT_TRUE(base::StringValue(std::string()).Equals(value));
-
- EXPECT_TRUE(store_->GetValue(
- prefs::kDefaultSearchProviderInstantURLPostParams, &value));
- EXPECT_TRUE(base::StringValue(std::string()).Equals(value));
-
- EXPECT_TRUE(store_->GetValue(
- prefs::kDefaultSearchProviderImageURLPostParams, &value));
- EXPECT_TRUE(base::StringValue(std::string()).Equals(value));
-
- EXPECT_TRUE(store_->GetValue(
- prefs::kDefaultSearchProviderNewTabURL, &value));
- EXPECT_TRUE(base::StringValue(std::string()).Equals(value));
-}
-
-// Checks that for a fully defined search policy, all elements have been
-// read properly.
-TEST_F(ConfigurationPolicyPrefStoreDefaultSearchTest, FullyDefined) {
- PolicyMap policy;
- BuildDefaultSearchPolicy(&policy);
- UpdateProviderPolicy(policy);
-
- const base::Value* value = NULL;
- EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderSearchURL, &value));
- EXPECT_TRUE(base::StringValue(kSearchURL).Equals(value));
-
- EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderName, &value));
- EXPECT_TRUE(base::StringValue(kName).Equals(value));
-
- EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderKeyword, &value));
- EXPECT_TRUE(base::StringValue(kKeyword).Equals(value));
-
- EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderSuggestURL,
- &value));
- EXPECT_TRUE(base::StringValue(kSuggestURL).Equals(value));
-
- EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderIconURL, &value));
- EXPECT_TRUE(base::StringValue(kIconURL).Equals(value));
-
- EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderEncodings, &value));
- EXPECT_TRUE(base::StringValue("UTF-16;UTF-8").Equals(value));
-
- EXPECT_TRUE(store_->GetValue(
- prefs::kDefaultSearchProviderAlternateURLs, &value));
- EXPECT_TRUE(default_alternate_urls_.Equals(value));
-
- EXPECT_TRUE(
- store_->GetValue(prefs::kDefaultSearchProviderSearchTermsReplacementKey,
- &value));
- EXPECT_TRUE(base::StringValue(kReplacementKey).Equals(value));
-
- EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderImageURL, &value));
- EXPECT_TRUE(base::StringValue(std::string(kImageURL)).Equals(value));
-
- EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderImageURLPostParams,
- &value));
- EXPECT_TRUE(base::StringValue(std::string(kImageParams)).Equals(value));
-
- EXPECT_TRUE(store_->GetValue(
- prefs::kDefaultSearchProviderSearchURLPostParams, &value));
- EXPECT_TRUE(base::StringValue(std::string()).Equals(value));
-
- EXPECT_TRUE(store_->GetValue(
- prefs::kDefaultSearchProviderSuggestURLPostParams, &value));
- EXPECT_TRUE(base::StringValue(std::string()).Equals(value));
-
- EXPECT_TRUE(store_->GetValue(
- prefs::kDefaultSearchProviderInstantURLPostParams, &value));
- EXPECT_TRUE(base::StringValue(std::string()).Equals(value));
-}
-
-// Checks that if the default search policy is missing, that no elements of the
-// default search policy will be present.
-TEST_F(ConfigurationPolicyPrefStoreDefaultSearchTest, MissingUrl) {
- PolicyMap policy;
- BuildDefaultSearchPolicy(&policy);
- policy.Erase(key::kDefaultSearchProviderSearchURL);
- UpdateProviderPolicy(policy);
-
- EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderSearchURL, NULL));
- EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderName, NULL));
- EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderKeyword, NULL));
- EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderSuggestURL, NULL));
- EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderIconURL, NULL));
- EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderEncodings, NULL));
- EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderAlternateURLs,
- NULL));
- EXPECT_FALSE(store_->GetValue(
- prefs::kDefaultSearchProviderSearchTermsReplacementKey, NULL));
- EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderImageURL, NULL));
- EXPECT_FALSE(store_->GetValue(
- prefs::kDefaultSearchProviderImageURLPostParams, NULL));
- EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderInstantURL, NULL));
- EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderNewTabURL, NULL));
-}
-
-// Checks that if the default search policy is invalid, that no elements of the
-// default search policy will be present.
-TEST_F(ConfigurationPolicyPrefStoreDefaultSearchTest, Invalid) {
- PolicyMap policy;
- BuildDefaultSearchPolicy(&policy);
- const char* const bad_search_url = "http://test.com/noSearchTerms";
- policy.Set(key::kDefaultSearchProviderSearchURL, POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER,
- base::Value::CreateStringValue(bad_search_url), NULL);
- UpdateProviderPolicy(policy);
-
- EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderSearchURL, NULL));
- EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderName, NULL));
- EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderKeyword, NULL));
- EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderSuggestURL, NULL));
- EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderIconURL, NULL));
- EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderEncodings, NULL));
- EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderAlternateURLs,
- NULL));
- EXPECT_FALSE(store_->GetValue(
- prefs::kDefaultSearchProviderSearchTermsReplacementKey, NULL));
- EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderImageURL, NULL));
- EXPECT_FALSE(store_->GetValue(
- prefs::kDefaultSearchProviderImageURLPostParams, NULL));
- EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderInstantURL, NULL));
- EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderNewTabURL, NULL));
-}
-
-// Checks that if the default search policy is invalid, that no elements of the
-// default search policy will be present.
-TEST_F(ConfigurationPolicyPrefStoreDefaultSearchTest, Disabled) {
- PolicyMap policy;
- policy.Set(key::kDefaultSearchProviderEnabled, POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER, base::Value::CreateBooleanValue(false), NULL);
- UpdateProviderPolicy(policy);
-
- const base::Value* value = NULL;
- EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderEnabled, &value));
- base::FundamentalValue expected_enabled(false);
- EXPECT_TRUE(base::Value::Equals(&expected_enabled, value));
- EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderSearchURL, &value));
- base::StringValue expected_search_url((std::string()));
- EXPECT_TRUE(base::Value::Equals(&expected_search_url, value));
-}
-
// Tests Incognito mode availability preference setting.
class ConfigurationPolicyPrefStoreIncognitoModeTest
: public ConfigurationPolicyPrefStoreTest {
@@ -1028,8 +484,8 @@ TEST_F(ConfigurationPolicyPrefStoreSyncTest, Disabled) {
EXPECT_TRUE(sync_managed);
}
-// Test cases for how the DownloadDirectory and AllowFileSelectionDialogs policy
-// influence the PromptForDownload preference.
+// Test cases for how the AllowFileSelectionDialogs policy influences the
+// PromptForDownload preference.
class ConfigurationPolicyPrefStorePromptDownloadTest
: public ConfigurationPolicyPrefStoreTest {};
@@ -1037,29 +493,6 @@ TEST_F(ConfigurationPolicyPrefStorePromptDownloadTest, Default) {
EXPECT_FALSE(store_->GetValue(prefs::kPromptForDownload, NULL));
}
-#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
-TEST_F(ConfigurationPolicyPrefStorePromptDownloadTest, SetDownloadDirectory) {
- PolicyMap policy;
- EXPECT_FALSE(store_->GetValue(prefs::kPromptForDownload, NULL));
- policy.Set(key::kDownloadDirectory,
- POLICY_LEVEL_MANDATORY,
- POLICY_SCOPE_USER,
- base::Value::CreateStringValue(std::string()),
- NULL);
- UpdateProviderPolicy(policy);
-
- // Setting a DownloadDirectory should disable the PromptForDownload pref.
- const base::Value* value = NULL;
- EXPECT_TRUE(store_->GetValue(prefs::kPromptForDownload,
- &value));
- ASSERT_TRUE(value);
- bool prompt_for_download = true;
- bool result = value->GetAsBoolean(&prompt_for_download);
- ASSERT_TRUE(result);
- EXPECT_FALSE(prompt_for_download);
-}
-#endif // !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
-
TEST_F(ConfigurationPolicyPrefStorePromptDownloadTest,
EnableFileSelectionDialogs) {
PolicyMap policy;
diff --git a/chrome/browser/policy/configuration_policy_pref_store_unittest.h b/chrome/browser/policy/configuration_policy_pref_store_unittest.h
new file mode 100644
index 0000000000..9fdf866156
--- /dev/null
+++ b/chrome/browser/policy/configuration_policy_pref_store_unittest.h
@@ -0,0 +1,40 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_PREF_STORE_UNITTEST_H_
+#define CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_PREF_STORE_UNITTEST_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "chrome/browser/policy/configuration_policy_handler_list.h"
+#include "chrome/browser/policy/mock_configuration_policy_provider.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace policy {
+
+class PolicyMap;
+class PolicyService;
+class ConfigurationPolicyPrefStore;
+
+class ConfigurationPolicyPrefStoreTest : public testing::Test {
+ protected:
+ ConfigurationPolicyPrefStoreTest();
+ virtual ~ConfigurationPolicyPrefStoreTest();
+ virtual void TearDown() OVERRIDE;
+ void UpdateProviderPolicy(const PolicyMap& policy);
+
+ ConfigurationPolicyHandlerList handler_list_;
+ MockConfigurationPolicyProvider provider_;
+ scoped_ptr<PolicyService> policy_service_;
+ scoped_refptr<ConfigurationPolicyPrefStore> store_;
+ base::MessageLoop loop_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ConfigurationPolicyPrefStoreTest);
+};
+
+} // namespace policy
+
+#endif // CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_PREF_STORE_UNITTEST_H_
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index eeb3e04c7a..95fe37c33a 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -469,62 +469,49 @@ class TestAudioObserver : public chromeos::CrasAudioHandler::AudioObserver {
};
#endif
-// This is a customized version of content::WindowedNotificationObserver that
-// waits until either of the two provided notification types is observed.
-// See content::WindowedNotificationObserver for further documentation.
-class OneOfTwoNotificationsObserver : public content::NotificationObserver {
+// This class waits until either a load stops or the WebContents is destroyed.
+class WebContentsLoadedOrDestroyedWatcher
+ : public content::WebContentsObserver {
public:
- // Set up to wait for one of two notifications.
- OneOfTwoNotificationsObserver(int notification_type1, int notification_type2);
- virtual ~OneOfTwoNotificationsObserver();
+ explicit WebContentsLoadedOrDestroyedWatcher(
+ content::WebContents* web_contents);
+ virtual ~WebContentsLoadedOrDestroyedWatcher();
- // Wait until one of the specified notifications is observed. If either
- // notification has already been received, Wait() returns immediately.
+ // Waits until the WebContents's load is done or until it is destroyed.
void Wait();
- // content::NotificationObserver:
- virtual void Observe(int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) OVERRIDE;
+ // Overridden WebContentsObserver methods.
+ virtual void WebContentsDestroyed(
+ content::WebContents* web_contents) OVERRIDE;
+ virtual void DidStopLoading(
+ content::RenderViewHost* render_view_host) OVERRIDE;
private:
- bool seen_;
- bool running_;
- content::NotificationRegistrar registrar_;
scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
- DISALLOW_COPY_AND_ASSIGN(OneOfTwoNotificationsObserver);
+ DISALLOW_COPY_AND_ASSIGN(WebContentsLoadedOrDestroyedWatcher);
};
-OneOfTwoNotificationsObserver::OneOfTwoNotificationsObserver(
- int notification_type1, int notification_type2)
- : seen_(false), running_(false) {
- registrar_.Add(this, notification_type1,
- content::NotificationService::AllSources());
- registrar_.Add(this, notification_type2,
- content::NotificationService::AllSources());
+WebContentsLoadedOrDestroyedWatcher::WebContentsLoadedOrDestroyedWatcher(
+ content::WebContents* web_contents)
+ : content::WebContentsObserver(web_contents),
+ message_loop_runner_(new content::MessageLoopRunner) {
}
-OneOfTwoNotificationsObserver::~OneOfTwoNotificationsObserver() {}
+WebContentsLoadedOrDestroyedWatcher::~WebContentsLoadedOrDestroyedWatcher() {}
-void OneOfTwoNotificationsObserver::Wait() {
- if (seen_)
- return;
- running_ = true;
- message_loop_runner_ = new content::MessageLoopRunner;
+void WebContentsLoadedOrDestroyedWatcher::Wait() {
message_loop_runner_->Run();
- EXPECT_TRUE(seen_);
}
-// NotificationObserver:
-void OneOfTwoNotificationsObserver::Observe(int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) {
- seen_ = true;
- if (!running_)
- return;
+void WebContentsLoadedOrDestroyedWatcher::WebContentsDestroyed(
+ content::WebContents* web_contents) {
+ message_loop_runner_->Quit();
+}
+
+void WebContentsLoadedOrDestroyedWatcher::DidStopLoading(
+ content::RenderViewHost* render_view_host) {
message_loop_runner_->Quit();
- running_ = false;
}
#if !defined(OS_MACOSX)
@@ -1533,7 +1520,9 @@ IN_PROC_BROWSER_TEST_F(PolicyTest, ExtensionInstallForcelist) {
base::FilePath test_path;
ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_path));
- TestRequestInterceptor interceptor("update.extension");
+ TestRequestInterceptor interceptor(
+ "update.extension",
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO));
interceptor.PushJobCallback(
TestRequestInterceptor::FileJob(
test_path.Append(kTestExtensionsDir).Append(kGood2CrxManifestName)));
@@ -1569,9 +1558,10 @@ IN_PROC_BROWSER_TEST_F(PolicyTest, ExtensionInstallForcelist) {
if (!(*iter)->IsLoading()) {
++iter;
} else {
- OneOfTwoNotificationsObserver(
- content::NOTIFICATION_LOAD_STOP,
- content::NOTIFICATION_WEB_CONTENTS_DESTROYED).Wait();
+ content::WebContents* web_contents =
+ content::WebContents::FromRenderViewHost(*iter);
+ ASSERT_TRUE(web_contents);
+ WebContentsLoadedOrDestroyedWatcher(web_contents).Wait();
// Test activity may have modified the set of extension processes during
// message processing, so re-start the iteration to catch added/removed
@@ -1753,6 +1743,7 @@ IN_PROC_BROWSER_TEST_F(PolicyTest, Javascript) {
EXPECT_TRUE(IsJavascriptEnabled(contents));
EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_DEV_TOOLS));
EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_DEV_TOOLS_CONSOLE));
+ EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_DEV_TOOLS_DEVICES));
// Disable Javascript via policy.
PolicyMap policies;
@@ -1765,6 +1756,7 @@ IN_PROC_BROWSER_TEST_F(PolicyTest, Javascript) {
// Developer tools still work when javascript is disabled.
EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_DEV_TOOLS));
EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_DEV_TOOLS_CONSOLE));
+ EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_DEV_TOOLS_DEVICES));
// Javascript is always enabled for the internal pages.
ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIAboutURL));
EXPECT_TRUE(IsJavascriptEnabled(contents));
diff --git a/chrome/browser/policy/policy_statistics_collector.cc b/chrome/browser/policy/policy_statistics_collector.cc
index fb648a17aa..e972c947c8 100644
--- a/chrome/browser/policy/policy_statistics_collector.cc
+++ b/chrome/browser/policy/policy_statistics_collector.cc
@@ -41,7 +41,7 @@ void PolicyStatisticsCollector::Initialize() {
TimeDelta update_rate = TimeDelta::FromMilliseconds(kStatisticsUpdateRate);
Time last_update = Time::FromInternalValue(
- prefs_->GetInt64(prefs::kLastPolicyStatisticsUpdate));
+ prefs_->GetInt64(policy_prefs::kLastPolicyStatisticsUpdate));
TimeDelta delay = std::max(Time::Now() - last_update, TimeDelta::FromDays(0));
if (delay >= update_rate)
CollectStatistics();
@@ -51,7 +51,7 @@ void PolicyStatisticsCollector::Initialize() {
// static
void PolicyStatisticsCollector::RegisterPrefs(PrefRegistrySimple* registry) {
- registry->RegisterInt64Pref(prefs::kLastPolicyStatisticsUpdate, 0);
+ registry->RegisterInt64Pref(policy_prefs::kLastPolicyStatisticsUpdate, 0);
}
void PolicyStatisticsCollector::RecordPolicyUse(int id) {
@@ -86,7 +86,7 @@ void PolicyStatisticsCollector::CollectStatistics() {
}
// Take care of next update.
- prefs_->SetInt64(prefs::kLastPolicyStatisticsUpdate,
+ prefs_->SetInt64(policy_prefs::kLastPolicyStatisticsUpdate,
base::Time::Now().ToInternalValue());
ScheduleUpdate(base::TimeDelta::FromMilliseconds(kStatisticsUpdateRate));
}
diff --git a/chrome/browser/policy/policy_statistics_collector_unittest.cc b/chrome/browser/policy/policy_statistics_collector_unittest.cc
index 11fca7ade7..e55d67a224 100644
--- a/chrome/browser/policy/policy_statistics_collector_unittest.cc
+++ b/chrome/browser/policy/policy_statistics_collector_unittest.cc
@@ -62,7 +62,8 @@ class PolicyStatisticsCollectorTest : public testing::Test {
}
virtual void SetUp() OVERRIDE {
- prefs_.registry()->RegisterInt64Pref(prefs::kLastPolicyStatisticsUpdate, 0);
+ prefs_.registry()->RegisterInt64Pref(
+ policy_prefs::kLastPolicyStatisticsUpdate, 0);
// Find ids for kTestPolicy1 and kTestPolicy2.
const policy::PolicyDefinitionList* policy_list =
@@ -123,7 +124,7 @@ class PolicyStatisticsCollectorTest : public testing::Test {
TEST_F(PolicyStatisticsCollectorTest, CollectPending) {
SetPolicy(kTestPolicy1);
- prefs_.SetInt64(prefs::kLastPolicyStatisticsUpdate,
+ prefs_.SetInt64(policy_prefs::kLastPolicyStatisticsUpdate,
(base::Time::Now() - update_delay_).ToInternalValue());
EXPECT_CALL(*policy_statistics_collector_.get(),
@@ -138,7 +139,7 @@ TEST_F(PolicyStatisticsCollectorTest, CollectPendingVeryOld) {
SetPolicy(kTestPolicy1);
// Must not be 0.0 (read comment for Time::FromDoubleT).
- prefs_.SetInt64(prefs::kLastPolicyStatisticsUpdate,
+ prefs_.SetInt64(policy_prefs::kLastPolicyStatisticsUpdate,
base::Time::FromDoubleT(1.0).ToInternalValue());
EXPECT_CALL(*policy_statistics_collector_.get(),
@@ -152,7 +153,7 @@ TEST_F(PolicyStatisticsCollectorTest, CollectPendingVeryOld) {
TEST_F(PolicyStatisticsCollectorTest, CollectLater) {
SetPolicy(kTestPolicy1);
- prefs_.SetInt64(prefs::kLastPolicyStatisticsUpdate,
+ prefs_.SetInt64(policy_prefs::kLastPolicyStatisticsUpdate,
(base::Time::Now() - update_delay_ / 2).ToInternalValue());
policy_statistics_collector_->Initialize();
@@ -164,7 +165,7 @@ TEST_F(PolicyStatisticsCollectorTest, MultiplePolicies) {
SetPolicy(kTestPolicy1);
SetPolicy(kTestPolicy2);
- prefs_.SetInt64(prefs::kLastPolicyStatisticsUpdate,
+ prefs_.SetInt64(policy_prefs::kLastPolicyStatisticsUpdate,
(base::Time::Now() - update_delay_).ToInternalValue());
EXPECT_CALL(*policy_statistics_collector_.get(),
diff --git a/chrome/browser/policy/profile_policy_connector.cc b/chrome/browser/policy/profile_policy_connector.cc
index b2ebe37137..fae3b36af7 100644
--- a/chrome/browser/policy/profile_policy_connector.cc
+++ b/chrome/browser/policy/profile_policy_connector.cc
@@ -44,9 +44,7 @@ ProfilePolicyConnector::ProfilePolicyConnector(Profile* profile)
ProfilePolicyConnector::~ProfilePolicyConnector() {}
-void ProfilePolicyConnector::Init(
- bool force_immediate_load,
- base::SequencedTaskRunner* sequenced_task_runner) {
+void ProfilePolicyConnector::Init(bool force_immediate_load) {
BrowserPolicyConnector* connector =
g_browser_process->browser_policy_connector();
// |providers| contains a list of the policy providers available for the
diff --git a/chrome/browser/policy/profile_policy_connector.h b/chrome/browser/policy/profile_policy_connector.h
index 26af539163..d7c4c26d9a 100644
--- a/chrome/browser/policy/profile_policy_connector.h
+++ b/chrome/browser/policy/profile_policy_connector.h
@@ -21,10 +21,6 @@
class Profile;
-namespace base {
-class SequencedTaskRunner;
-}
-
namespace net {
class CertTrustAnchorProvider;
}
@@ -49,8 +45,7 @@ class ProfilePolicyConnector : public BrowserContextKeyedService {
virtual ~ProfilePolicyConnector();
// If |force_immediate_load| then disk caches will be loaded synchronously.
- void Init(bool force_immediate_load,
- base::SequencedTaskRunner* sequenced_task_runner);
+ void Init(bool force_immediate_load);
void InitForTesting(scoped_ptr<PolicyService> service);
diff --git a/chrome/browser/policy/profile_policy_connector_factory.cc b/chrome/browser/policy/profile_policy_connector_factory.cc
index 9d052606f4..e8b7bc3505 100644
--- a/chrome/browser/policy/profile_policy_connector_factory.cc
+++ b/chrome/browser/policy/profile_policy_connector_factory.cc
@@ -37,10 +37,8 @@ ProfilePolicyConnector* ProfilePolicyConnectorFactory::GetForProfile(
scoped_ptr<ProfilePolicyConnector>
ProfilePolicyConnectorFactory::CreateForProfile(
Profile* profile,
- bool force_immediate_load,
- base::SequencedTaskRunner* sequenced_task_runner) {
- return GetInstance()->CreateForProfileInternal(
- profile, force_immediate_load, sequenced_task_runner);
+ bool force_immediate_load) {
+ return GetInstance()->CreateForProfileInternal(profile, force_immediate_load);
}
void ProfilePolicyConnectorFactory::SetServiceForTesting(
@@ -81,11 +79,10 @@ ProfilePolicyConnector*
scoped_ptr<ProfilePolicyConnector>
ProfilePolicyConnectorFactory::CreateForProfileInternal(
Profile* profile,
- bool force_immediate_load,
- base::SequencedTaskRunner* sequenced_task_runner) {
+ bool force_immediate_load) {
DCHECK(connectors_.find(profile) == connectors_.end());
ProfilePolicyConnector* connector = new ProfilePolicyConnector(profile);
- connector->Init(force_immediate_load, sequenced_task_runner);
+ connector->Init(force_immediate_load);
connectors_[profile] = connector;
return scoped_ptr<ProfilePolicyConnector>(connector);
}
diff --git a/chrome/browser/policy/profile_policy_connector_factory.h b/chrome/browser/policy/profile_policy_connector_factory.h
index a44fdeef03..837140833a 100644
--- a/chrome/browser/policy/profile_policy_connector_factory.h
+++ b/chrome/browser/policy/profile_policy_connector_factory.h
@@ -46,8 +46,7 @@ class ProfilePolicyConnectorFactory : public BrowserContextKeyedBaseFactory {
// startup.
static scoped_ptr<ProfilePolicyConnector> CreateForProfile(
Profile* profile,
- bool force_immediate_load,
- base::SequencedTaskRunner* sequenced_task_runner);
+ bool force_immediate_load);
// Overrides the |connector| for the given |profile|; use only in tests.
// Once this class becomes a proper PKS then it can reuse the testing
@@ -65,8 +64,7 @@ class ProfilePolicyConnectorFactory : public BrowserContextKeyedBaseFactory {
scoped_ptr<ProfilePolicyConnector> CreateForProfileInternal(
Profile* profile,
- bool force_immediate_load,
- base::SequencedTaskRunner* sequenced_task_runner);
+ bool force_immediate_load);
// BrowserContextKeyedBaseFactory:
virtual void BrowserContextShutdown(
diff --git a/chrome/browser/policy/profile_policy_connector_stub.cc b/chrome/browser/policy/profile_policy_connector_stub.cc
index 6c039426c1..49747c8df7 100644
--- a/chrome/browser/policy/profile_policy_connector_stub.cc
+++ b/chrome/browser/policy/profile_policy_connector_stub.cc
@@ -12,9 +12,7 @@ ProfilePolicyConnector::ProfilePolicyConnector(Profile* profile) {}
ProfilePolicyConnector::~ProfilePolicyConnector() {}
-void ProfilePolicyConnector::Init(
- bool force_immediate_load,
- base::SequencedTaskRunner* sequenced_task_runner) {
+void ProfilePolicyConnector::Init(bool force_immediate_load) {
policy_service_.reset(new PolicyServiceStub());
}
diff --git a/chrome/browser/policy/proto/chromeos/chrome_device_policy.proto b/chrome/browser/policy/proto/chromeos/chrome_device_policy.proto
index a7fc4fc562..3623b8f199 100644
--- a/chrome/browser/policy/proto/chromeos/chrome_device_policy.proto
+++ b/chrome/browser/policy/proto/chromeos/chrome_device_policy.proto
@@ -362,7 +362,7 @@ message AttestationSettingsProto {
// this is enabled a machine key will be generated and certified by the Chrome
// OS CA. If this setting is disabled, even users with attestation settings
// enabled will not be able to use those features on the device.
- optional bool attestation_enabled = 1;
+ optional bool attestation_enabled = 1 [default = false];
// Chrome OS devices can use remote attestation (Verified Access) to get a
// certificate issued by the Chrome OS CA that asserts the device is eligible
@@ -370,7 +370,7 @@ message AttestationSettingsProto {
// endorsement information to the Chrome OS CA which uniquely identifies the
// device. This setting allows this feature to be disabled for the device
// regardless of any user-specific settings.
- optional bool content_protection_enabled = 2;
+ optional bool content_protection_enabled = 2 [default = true];
}
message AccessibilitySettingsProto {
diff --git a/chrome/browser/policy/url_blacklist_manager.cc b/chrome/browser/policy/url_blacklist_manager.cc
index 062ed5a210..e4f6db4568 100644
--- a/chrome/browser/policy/url_blacklist_manager.cc
+++ b/chrome/browser/policy/url_blacklist_manager.cc
@@ -44,10 +44,10 @@ namespace {
// Maximum filters per policy. Filters over this index are ignored.
const size_t kMaxFiltersPerPolicy = 1000;
-const char kServiceLoginAuth[] = "/ServiceLoginAuth";
-
#if !defined(OS_CHROMEOS)
+const char kServiceLoginAuth[] = "/ServiceLoginAuth";
+
bool IsSigninFlowURL(const GURL& url) {
// Whitelist all the signin flow URLs flagged by the SigninManager.
if (SigninManager::IsWebBasedSigninFlowURL(url))
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 3d5a1c43d0..69b2c86849 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -486,7 +486,6 @@ void MigrateUserPrefs(Profile* profile) {
prefs->ClearPref(kSyncPromoErrorMessage);
#endif
- PrefsTabHelper::MigrateUserPrefs(prefs);
PromoResourceService::MigrateUserPrefs(prefs);
TranslatePrefs::MigrateUserPrefs(prefs);
diff --git a/chrome/browser/prefs/command_line_pref_store.cc b/chrome/browser/prefs/command_line_pref_store.cc
index f6006835e2..7a123da4a1 100644
--- a/chrome/browser/prefs/command_line_pref_store.cc
+++ b/chrome/browser/prefs/command_line_pref_store.cc
@@ -70,8 +70,6 @@ const CommandLinePrefStore::BooleanSwitchToPreferenceMapEntry
{ chromeos::switches::kEnableTouchpadThreeFingerClick,
prefs::kEnableTouchpadThreeFingerClick, true },
#endif
- { switches::kDisableCloudPolicyOnSignin,
- prefs::kDisableCloudPolicyOnSignin, true },
{ switches::kDisableAsyncDns, prefs::kBuiltInDnsClientEnabled, false },
{ switches::kEnableAsyncDns, prefs::kBuiltInDnsClientEnabled, true },
};
diff --git a/chrome/browser/prefs/pref_metrics_service.cc b/chrome/browser/prefs/pref_metrics_service.cc
index cf56bc40db..18153bfb1b 100644
--- a/chrome/browser/prefs/pref_metrics_service.cc
+++ b/chrome/browser/prefs/pref_metrics_service.cc
@@ -37,12 +37,14 @@ namespace {
const int kSessionStartupPrefValueMax = SessionStartupPref::kPrefValueMax;
+#if defined(OS_ANDROID)
// An unregistered preference to fill in indices in kTrackedPrefs below for
// preferences that aren't defined on every platform. This is fine as the code
// below (e.g. CheckTrackedPreferences()) skips unregistered preferences and
// should thus never report any data about that index on the platforms where
// that preference is unimplemented.
const char kUnregisteredPreference[] = "_";
+#endif
// These preferences must be kept in sync with the TrackedPreference enum in
// tools/metrics/histograms/histograms.xml. To add a new preference, append it
diff --git a/chrome/browser/prefs/pref_model_associator.cc b/chrome/browser/prefs/pref_model_associator.cc
index 28759a10b6..42cbae2485 100644
--- a/chrome/browser/prefs/pref_model_associator.cc
+++ b/chrome/browser/prefs/pref_model_associator.cc
@@ -48,6 +48,34 @@ sync_pb::PreferenceSpecifics* GetMutableSpecifics(
}
}
+// List of migrated preference name pairs. If a preference is migrated
+// (meaning renamed) adding the old and new preference names here will ensure
+// that the sync engine knows how to deal with the synced values coming in
+// with the old name. Preference migration itself doesn't happen here. It may
+// happen in session_startup_pref.cc.
+const struct MigratedPreferences {
+ const char* const old_name;
+ const char* const new_name;
+} kMigratedPreferences[] = {
+ { prefs::kURLsToRestoreOnStartupOld, prefs::kURLsToRestoreOnStartup },
+};
+
+std::string GetOldMigratedPreferenceName(const char* preference_name) {
+ for (size_t i = 0; i < arraysize(kMigratedPreferences); ++i) {
+ if (!strcmp(kMigratedPreferences[i].new_name, preference_name))
+ return kMigratedPreferences[i].old_name;
+ }
+ return std::string();
+}
+
+std::string GetNewMigratedPreferenceName(const char* old_preference_name) {
+ for (size_t i = 0; i < arraysize(kMigratedPreferences); ++i) {
+ if (!strcmp(kMigratedPreferences[i].old_name, old_preference_name))
+ return kMigratedPreferences[i].new_name;
+ }
+ return std::string();
+}
+
} // namespace
PrefModelAssociator::PrefModelAssociator(syncer::ModelType type)
@@ -71,15 +99,21 @@ PrefModelAssociator::~PrefModelAssociator() {
void PrefModelAssociator::InitPrefAndAssociate(
const syncer::SyncData& sync_pref,
const std::string& pref_name,
- syncer::SyncChangeList* sync_changes) {
+ syncer::SyncChangeList* sync_changes,
+ SyncDataMap* migrated_preference_list) {
const Value* user_pref_value = pref_service_->GetUserPrefValue(
pref_name.c_str());
VLOG(1) << "Associating preference " << pref_name;
+ // Set if a migrated pref name has been added to the synced_preferences_ list.
+ bool remembered_migrated_synced_preference = false;
+
if (sync_pref.IsValid()) {
const sync_pb::PreferenceSpecifics& preference = GetSpecifics(sync_pref);
- DCHECK_EQ(pref_name, preference.name());
-
+ DCHECK(pref_name == preference.name() ||
+ (IsMigratedPreference(pref_name.c_str()) &&
+ preference.name() ==
+ GetOldMigratedPreferenceName(pref_name.c_str())));
base::JSONReader reader;
scoped_ptr<Value> sync_value(reader.ReadToValue(preference.value()));
if (!sync_value.get()) {
@@ -115,10 +149,49 @@ void PrefModelAssociator::InitPrefAndAssociate(
LOG(ERROR) << "Failed to update preference.";
return;
}
- sync_changes->push_back(
+
+ if (IsMigratedPreference(pref_name.c_str())) {
+ // This preference has been migrated from an old version that must be
+ // kept in sync on older versions of Chrome.
+ std::string old_pref_name =
+ GetOldMigratedPreferenceName(pref_name.c_str());
+
+ if (preference.name() == old_pref_name) {
+ DCHECK(migrated_preference_list);
+ // If the name the syncer has is the old pre-migration value, then
+ // it's possible the new migrated preference name hasn't been synced
+ // yet. In that case the SyncChange should be an ACTION_ADD rather
+ // than an ACTION_UPDATE. Defer the decision of whether to sync with
+ // ACTION_ADD or ACTION_UPDATE until the migrated_preferences phase.
+ if (migrated_preference_list)
+ (*migrated_preference_list)[pref_name] = sync_data;
+ } else {
+ DCHECK_EQ(preference.name(), pref_name);
+ sync_changes->push_back(
+ syncer::SyncChange(FROM_HERE,
+ syncer::SyncChange::ACTION_UPDATE,
+ sync_data));
+ }
+
+ syncer::SyncData old_sync_data;
+ if (!CreatePrefSyncData(old_pref_name, *new_value, &old_sync_data)) {
+ LOG(ERROR) << "Failed to update preference.";
+ return;
+ }
+ if (migrated_preference_list)
+ (*migrated_preference_list)[old_pref_name] = old_sync_data;
+
+ // Keep track of the name of the synced pref. This will be idempotent
+ // with the insertion of pref_name below when the migrated value has
+ // already been synced, not so when it has not.
+ synced_preferences_.insert(preference.name());
+ remembered_migrated_synced_preference = true;
+ } else {
+ sync_changes->push_back(
syncer::SyncChange(FROM_HERE,
syncer::SyncChange::ACTION_UPDATE,
sync_data));
+ }
}
} else if (!sync_value->IsType(Value::TYPE_NULL)) {
// Only a server value exists. Just set the local user value.
@@ -148,7 +221,8 @@ void PrefModelAssociator::InitPrefAndAssociate(
// Make sure we add it to our list of synced preferences so we know what
// the server is aware of.
- synced_preferences_.insert(pref_name);
+ if (!remembered_migrated_synced_preference)
+ synced_preferences_.insert(pref_name);
return;
}
@@ -170,6 +244,11 @@ syncer::SyncMergeResult PrefModelAssociator::MergeDataAndStartSyncing(
syncer::SyncChangeList new_changes;
std::set<std::string> remaining_preferences = registered_preferences_;
+ // Maintains a list of old migrated preference names that we wish to sync.
+ // Keep track of these in a list such that when the preference iteration
+ // loops below are complete we can go back and determine whether
+ SyncDataMap migrated_preference_list;
+
// Go through and check for all preferences we care about that sync already
// knows about.
for (syncer::SyncDataList::const_iterator sync_iter =
@@ -179,19 +258,28 @@ syncer::SyncMergeResult PrefModelAssociator::MergeDataAndStartSyncing(
DCHECK_EQ(type_, sync_iter->GetDataType());
const sync_pb::PreferenceSpecifics& preference = GetSpecifics(*sync_iter);
- const std::string& sync_pref_name = preference.name();
+ std::string sync_pref_name = preference.name();
if (remaining_preferences.count(sync_pref_name) == 0) {
- // We're not syncing this preference locally, ignore the sync data.
- // TODO(zea): Eventually we want to be able to have the syncable service
- // reconstruct all sync data for it's datatype (therefore having
- // GetAllSyncData be a complete representation). We should store this data
- // somewhere, even if we don't use it.
- continue;
+ if (IsOldMigratedPreference(sync_pref_name.c_str())) {
+ // This old pref name is not syncable locally anymore but we accept
+ // changes from other Chrome installs of previous versions and migrate
+ // them to the new name. Note that we will be merging any differences
+ // between the new and old values and sync'ing them back.
+ sync_pref_name = GetNewMigratedPreferenceName(sync_pref_name.c_str());
+ } else {
+ // We're not syncing this preference locally, ignore the sync data.
+ // TODO(zea): Eventually we want to be able to have the syncable service
+ // reconstruct all sync data for its datatype (therefore having
+ // GetAllSyncData be a complete representation). We should store this
+ // data somewhere, even if we don't use it.
+ continue;
+ }
+ } else {
+ remaining_preferences.erase(sync_pref_name);
}
-
- remaining_preferences.erase(sync_pref_name);
- InitPrefAndAssociate(*sync_iter, sync_pref_name, &new_changes);
+ InitPrefAndAssociate(*sync_iter, sync_pref_name, &new_changes,
+ &migrated_preference_list);
}
// Go through and build sync data for any remaining preferences.
@@ -199,7 +287,21 @@ syncer::SyncMergeResult PrefModelAssociator::MergeDataAndStartSyncing(
remaining_preferences.begin();
pref_name_iter != remaining_preferences.end();
++pref_name_iter) {
- InitPrefAndAssociate(syncer::SyncData(), *pref_name_iter, &new_changes);
+ InitPrefAndAssociate(syncer::SyncData(), *pref_name_iter, &new_changes,
+ &migrated_preference_list);
+ }
+
+ // Now go over any migrated preference names and build sync data for them too.
+ for (SyncDataMap::const_iterator migrated_pref_iter =
+ migrated_preference_list.begin();
+ migrated_pref_iter != migrated_preference_list.end();
+ ++migrated_pref_iter) {
+ syncer::SyncChange::SyncChangeType change_type =
+ (synced_preferences_.count(migrated_pref_iter->first) == 0) ?
+ syncer::SyncChange::ACTION_ADD :
+ syncer::SyncChange::ACTION_UPDATE;
+ new_changes.push_back(
+ syncer::SyncChange(FROM_HERE, change_type, migrated_pref_iter->second));
}
// Push updates to sync.
@@ -225,7 +327,10 @@ scoped_ptr<Value> PrefModelAssociator::MergePreference(
const std::string& name,
const Value& local_value,
const Value& server_value) {
- if (name == prefs::kURLsToRestoreOnStartup) {
+ // This function special cases preferences individually, so don't attempt
+ // to merge for all migrated values.
+ if (name == prefs::kURLsToRestoreOnStartup ||
+ name == prefs::kURLsToRestoreOnStartupOld) {
return scoped_ptr<Value>(MergeListValues(local_value, server_value)).Pass();
}
@@ -321,6 +426,17 @@ Value* PrefModelAssociator::MergeDictionaryValues(
return result;
}
+// static
+bool PrefModelAssociator::IsMigratedPreference(const char* preference_name) {
+ return !GetOldMigratedPreferenceName(preference_name).empty();
+}
+
+// static
+bool PrefModelAssociator::IsOldMigratedPreference(
+ const char* old_preference_name) {
+ return !GetNewMigratedPreferenceName(old_preference_name).empty();
+}
+
// Note: This will build a model of all preferences registered as syncable
// with user controlled data. We do not track any information for preferences
// not registered locally as syncable and do not inform the syncer of
@@ -388,6 +504,13 @@ syncer::SyncError PrefModelAssociator::ProcessSyncChanges(
// Windows client, the Windows client does not support
// kConfirmToQuitEnabled. Ignore updates from these preferences.
const char* pref_name = name.c_str();
+ std::string new_name;
+ // We migrated this preference name, so do as if the name had not changed.
+ if (IsOldMigratedPreference(pref_name)) {
+ new_name = GetNewMigratedPreferenceName(pref_name);
+ pref_name = new_name.c_str();
+ }
+
if (!IsPrefRegistered(pref_name))
continue;
@@ -496,7 +619,7 @@ void PrefModelAssociator::ProcessPrefChange(const std::string& name) {
// Not in synced_preferences_ means no synced data. InitPrefAndAssociate(..)
// will determine if we care about its data (e.g. if it has a default value
// and hasn't been changed yet we don't) and take care syncing any new data.
- InitPrefAndAssociate(syncer::SyncData(), name, &changes);
+ InitPrefAndAssociate(syncer::SyncData(), name, &changes, NULL);
} else {
// We are already syncing this preference, just update it's sync node.
syncer::SyncData sync_data;
@@ -508,6 +631,24 @@ void PrefModelAssociator::ProcessPrefChange(const std::string& name) {
syncer::SyncChange(FROM_HERE,
syncer::SyncChange::ACTION_UPDATE,
sync_data));
+ // This preference has been migrated from an old version that must be kept
+ // in sync on older versions of Chrome.
+ if (IsMigratedPreference(name.c_str())) {
+ std::string old_pref_name = GetOldMigratedPreferenceName(name.c_str());
+ if (!CreatePrefSyncData(old_pref_name,
+ *preference->GetValue(),
+ &sync_data)) {
+ LOG(ERROR) << "Failed to update preference.";
+ return;
+ }
+
+ syncer::SyncChange::SyncChangeType change_type =
+ (synced_preferences_.count(old_pref_name) == 0) ?
+ syncer::SyncChange::ACTION_ADD :
+ syncer::SyncChange::ACTION_UPDATE;
+ changes.push_back(
+ syncer::SyncChange(FROM_HERE, change_type, sync_data));
+ }
}
syncer::SyncError error =
diff --git a/chrome/browser/prefs/pref_model_associator.h b/chrome/browser/prefs/pref_model_associator.h
index 539d38a301..0c0cb66e91 100644
--- a/chrome/browser/prefs/pref_model_associator.h
+++ b/chrome/browser/prefs/pref_model_associator.h
@@ -12,6 +12,7 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/containers/hash_tables.h"
+#include "base/gtest_prod_util.h"
#include "base/observer_list.h"
#include "base/threading/non_thread_safe.h"
#include "chrome/browser/prefs/synced_pref_observer.h"
@@ -110,6 +111,12 @@ class PrefModelAssociator
protected:
friend class ProfileSyncServicePreferenceTest;
+ FRIEND_TEST_ALL_PREFIXES(ProfileSyncServicePreferenceTest,
+ ModelAssociationCloudHasOldMigratedData);
+ FRIEND_TEST_ALL_PREFIXES(ProfileSyncServicePreferenceTest,
+ ModelAssociationCloudHasNewMigratedData);
+ FRIEND_TEST_ALL_PREFIXES(ProfileSyncServicePreferenceTest,
+ ModelAssociationCloudAddsOldAndNewMigratedData);
typedef std::map<std::string, syncer::SyncData> SyncDataMap;
@@ -118,18 +125,26 @@ class PrefModelAssociator
// with ours and append a new UPDATE SyncChange to |sync_changes|. If
// sync_pref is not set, we append an ADD SyncChange to |sync_changes| with
// the current preference data.
+ // |migrated_preference_list| points to a vector that may be updated with a
+ // string containing the old name of the preference described by |pref_name|.
// Note: We do not modify the sync data for preferences that are either
// controlled by policy (are not user modifiable) or have their default value
// (are not user controlled).
void InitPrefAndAssociate(const syncer::SyncData& sync_pref,
const std::string& pref_name,
- syncer::SyncChangeList* sync_changes);
+ syncer::SyncChangeList* sync_changes,
+ SyncDataMap* migrated_preference_list);
static base::Value* MergeListValues(
const base::Value& from_value, const base::Value& to_value);
static base::Value* MergeDictionaryValues(const base::Value& from_value,
const base::Value& to_value);
+ // Returns whether a given preference name is a new name of a migrated
+ // preference. Exposed here for testing.
+ static bool IsMigratedPreference(const char* preference_name);
+ static bool IsOldMigratedPreference(const char* old_preference_name);
+
// Do we have an active association between the preferences and sync models?
// Set when start syncing, reset in StopSyncing. While this is not set, we
// ignore any local preference changes (when we start syncing we will look
diff --git a/chrome/browser/prefs/session_startup_pref.cc b/chrome/browser/prefs/session_startup_pref.cc
index 478790a157..3ce2fa67b4 100644
--- a/chrome/browser/prefs/session_startup_pref.cc
+++ b/chrome/browser/prefs/session_startup_pref.cc
@@ -6,7 +6,9 @@
#include <string>
+#include "base/metrics/histogram.h"
#include "base/prefs/pref_service.h"
+#include "base/time/time.h"
#include "base/values.h"
#include "base/version.h"
#include "chrome/browser/prefs/scoped_user_pref_update.h"
@@ -21,6 +23,13 @@
namespace {
+enum StartupURLsMigrationMetrics {
+ STARTUP_URLS_MIGRATION_METRICS_PERFORMED,
+ STARTUP_URLS_MIGRATION_METRICS_NOT_PRESENT,
+ STARTUP_URLS_MIGRATION_METRICS_RESET,
+ STARTUP_URLS_MIGRATION_METRICS_MAX,
+};
+
// Converts a SessionStartupPref::Type to an integer written to prefs.
int TypeToPrefValue(SessionStartupPref::Type type) {
switch (type) {
@@ -62,10 +71,16 @@ void SessionStartupPref::RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
registry->RegisterListPref(prefs::kURLsToRestoreOnStartup,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+ registry->RegisterListPref(prefs::kURLsToRestoreOnStartupOld,
+ user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
registry->RegisterBooleanPref(
prefs::kRestoreOnStartupMigrated,
false,
user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+ registry->RegisterInt64Pref(
+ prefs::kRestoreStartupURLsMigrationTime,
+ false,
+ user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
}
// static
@@ -136,8 +151,56 @@ SessionStartupPref SessionStartupPref::GetStartupPref(PrefService* prefs) {
void SessionStartupPref::MigrateIfNecessary(PrefService* prefs) {
DCHECK(prefs);
+ // Check if we need to migrate the old version of the startup URLs preference
+ // to the new name, and also send metrics about the migration.
+ StartupURLsMigrationMetrics metrics_result =
+ STARTUP_URLS_MIGRATION_METRICS_MAX;
+ const base::ListValue* old_startup_urls =
+ prefs->GetList(prefs::kURLsToRestoreOnStartupOld);
+ if (!prefs->GetUserPrefValue(prefs::kRestoreStartupURLsMigrationTime)) {
+ // Record the absence of the migration timestamp, this will get overwritten
+ // below if migration occurs now.
+ metrics_result = STARTUP_URLS_MIGRATION_METRICS_NOT_PRESENT;
+
+ // Seems like we never migrated, do it if necessary.
+ if (!prefs->GetUserPrefValue(prefs::kURLsToRestoreOnStartup)) {
+ if (old_startup_urls && !old_startup_urls->empty()) {
+ prefs->Set(prefs::kURLsToRestoreOnStartup, *old_startup_urls);
+ prefs->ClearPref(prefs::kURLsToRestoreOnStartupOld);
+ }
+ metrics_result = STARTUP_URLS_MIGRATION_METRICS_PERFORMED;
+ }
+
+ prefs->SetInt64(prefs::kRestoreStartupURLsMigrationTime,
+ base::Time::Now().ToInternalValue());
+ } else if (old_startup_urls && !old_startup_urls->empty()) {
+ // Migration needs to be reset.
+ prefs->ClearPref(prefs::kURLsToRestoreOnStartupOld);
+ base::Time last_migration_time = base::Time::FromInternalValue(
+ prefs->GetInt64(prefs::kRestoreStartupURLsMigrationTime));
+ base::Time now = base::Time::Now();
+ prefs->SetInt64(prefs::kRestoreStartupURLsMigrationTime,
+ now.ToInternalValue());
+ if (now < last_migration_time)
+ last_migration_time = now;
+ HISTOGRAM_CUSTOM_TIMES("Settings.StartupURLsResetTime",
+ now - last_migration_time,
+ base::TimeDelta::FromDays(0),
+ base::TimeDelta::FromDays(7),
+ 50);
+ metrics_result = STARTUP_URLS_MIGRATION_METRICS_RESET;
+ }
+
+ // Record a metric migration event if something interesting happened.
+ if (metrics_result != STARTUP_URLS_MIGRATION_METRICS_MAX) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "Settings.StartupURLsMigration",
+ metrics_result,
+ STARTUP_URLS_MIGRATION_METRICS_MAX);
+ }
+
if (!prefs->GetBoolean(prefs::kRestoreOnStartupMigrated)) {
- // Read existing values
+ // Read existing values.
const base::Value* homepage_is_new_tab_page_value =
prefs->GetUserPrefValue(prefs::kHomePageIsNewTabPage);
bool homepage_is_new_tab_page = true;
diff --git a/chrome/browser/prerender/prerender_browsertest.cc b/chrome/browser/prerender/prerender_browsertest.cc
index e782149cf0..cf25d05843 100644
--- a/chrome/browser/prerender/prerender_browsertest.cc
+++ b/chrome/browser/prerender/prerender_browsertest.cc
@@ -8,6 +8,7 @@
#include "base/bind.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
+#include "base/memory/ref_counted_memory.h"
#include "base/path_service.h"
#include "base/prefs/pref_service.h"
#include "base/run_loop.h"
@@ -39,6 +40,7 @@
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/browser_navigator.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/chrome_paths.h"
@@ -822,7 +824,38 @@ class PrerenderBrowserTest : virtual public InProcessBrowserTest {
void NavigateToDestURLWithDisposition(
WindowOpenDisposition disposition,
bool expect_swap_to_succeed) const {
- NavigateToURLImpl(dest_url_, disposition, expect_swap_to_succeed);
+ NavigateToURLWithParams(
+ content::OpenURLParams(dest_url_, Referrer(), disposition,
+ content::PAGE_TRANSITION_TYPED, false),
+ expect_swap_to_succeed);
+ }
+
+ void NavigateToDestUrlAndWaitForPassTitle() {
+ string16 expected_title = ASCIIToUTF16(kPassTitle);
+ content::TitleWatcher title_watcher(
+ GetPrerenderContents()->prerender_contents(),
+ expected_title);
+ NavigateToDestURL();
+ EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
+ }
+
+ void NavigateToURL(const std::string& dest_html_file) const {
+ NavigateToURLWithDisposition(dest_html_file, CURRENT_TAB, true);
+ }
+
+ void NavigateToURLWithDisposition(const std::string& dest_html_file,
+ WindowOpenDisposition disposition,
+ bool expect_swap_to_succeed) const {
+ GURL dest_url = test_server()->GetURL(dest_html_file);
+ NavigateToURLWithParams(
+ content::OpenURLParams(dest_url, Referrer(), disposition,
+ content::PAGE_TRANSITION_TYPED, false),
+ expect_swap_to_succeed);
+ }
+
+ void NavigateToURLWithParams(const content::OpenURLParams& params,
+ bool expect_swap_to_succeed) const {
+ NavigateToURLImpl(params, expect_swap_to_succeed);
}
void OpenDestURLViaClick() const {
@@ -885,15 +918,6 @@ class PrerenderBrowserTest : virtual public InProcessBrowserTest {
test_server()->GetURL("files/prerender/prerender_page.html"));
}
- void NavigateToDestUrlAndWaitForPassTitle() {
- string16 expected_title = ASCIIToUTF16(kPassTitle);
- content::TitleWatcher title_watcher(
- GetPrerenderContents()->prerender_contents(),
- expected_title);
- NavigateToDestURL();
- EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
- }
-
// Called after the prerendered page has been navigated to and then away from.
// Navigates back through the history to the prerendered page.
void GoBackToPrerender() {
@@ -931,17 +955,6 @@ class PrerenderBrowserTest : virtual public InProcessBrowserTest {
EXPECT_TRUE(js_result);
}
- void NavigateToURL(const std::string& dest_html_file) const {
- NavigateToURLWithDisposition(dest_html_file, CURRENT_TAB, true);
- }
-
- void NavigateToURLWithDisposition(const std::string& dest_html_file,
- WindowOpenDisposition disposition,
- bool expect_swap_to_succeed) const {
- GURL dest_url = test_server()->GetURL(dest_html_file);
- NavigateToURLImpl(dest_url, disposition, expect_swap_to_succeed);
- }
-
bool UrlIsInPrerenderManager(const std::string& html_file) const {
return UrlIsInPrerenderManager(test_server()->GetURL(html_file));
}
@@ -1098,6 +1111,10 @@ class PrerenderBrowserTest : virtual public InProcessBrowserTest {
return explicitly_set_browser_ ? explicitly_set_browser_ : browser();
}
+ const GURL& dest_url() const {
+ return dest_url_;
+ }
+
void IncreasePrerenderMemory() {
// Increase the memory allowed in a prerendered page above normal settings.
// Debug build bots occasionally run against the default limit, and tests
@@ -1229,8 +1246,7 @@ class PrerenderBrowserTest : virtual public InProcessBrowserTest {
EXPECT_FALSE(HadPrerenderEventErrors());
}
- void NavigateToURLImpl(const GURL& dest_url,
- WindowOpenDisposition disposition,
+ void NavigateToURLImpl(const content::OpenURLParams& params,
bool expect_swap_to_succeed) const {
ASSERT_NE(static_cast<PrerenderManager*>(NULL), GetPrerenderManager());
// Make sure in navigating we have a URL to use in the PrerenderManager.
@@ -1238,7 +1254,7 @@ class PrerenderBrowserTest : virtual public InProcessBrowserTest {
// If opening the page in a background tab, it won't be shown when swapped
// in.
- if (disposition == NEW_BACKGROUND_TAB)
+ if (params.disposition == NEW_BACKGROUND_TAB)
GetPrerenderContents()->set_should_be_shown(false);
scoped_ptr<content::WindowedNotificationObserver> page_load_observer;
@@ -1260,20 +1276,21 @@ class PrerenderBrowserTest : virtual public InProcessBrowserTest {
// Navigate to the prerendered URL, but don't run the message loop. Browser
// issued navigations to prerendered pages will synchronously swap in the
// prerendered page.
- ui_test_utils::NavigateToURLWithDisposition(
- current_browser(), dest_url, disposition,
- ui_test_utils::BROWSER_TEST_NONE);
-
- if (call_javascript_ && web_contents && expect_swap_to_succeed) {
- if (page_load_observer.get())
- page_load_observer->Wait();
-
- bool display_test_result = false;
- ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
- web_contents,
- "window.domAutomationController.send(DidDisplayPass())",
- &display_test_result));
- EXPECT_TRUE(display_test_result);
+ WebContents* target_web_contents = current_browser()->OpenURL(params);
+
+ if (web_contents && expect_swap_to_succeed) {
+ EXPECT_EQ(web_contents, target_web_contents);
+ if (call_javascript_) {
+ if (page_load_observer.get())
+ page_load_observer->Wait();
+
+ bool display_test_result = false;
+ ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
+ web_contents,
+ "window.domAutomationController.send(DidDisplayPass())",
+ &display_test_result));
+ EXPECT_TRUE(display_test_result);
+ }
}
}
@@ -2749,7 +2766,7 @@ IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest,
manager->RegisterDevToolsClientHostFor(agent.get(), &client_host);
const char* url = "files/prerender/prerender_page.html";
PrerenderTestURL(url, FINAL_STATUS_DEVTOOLS_ATTACHED, 1);
- NavigateToURL(url);
+ NavigateToURLWithDisposition(url, CURRENT_TAB, false);
manager->ClientHostClosing(&client_host);
}
@@ -3195,4 +3212,31 @@ IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderDeferredSynchronousXHR) {
NavigateToDestURL();
}
+// Checks that prerenders are not swapped for navigations with extra headers.
+IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderExtraHeadersNoSwap) {
+ PrerenderTestURL("files/prerender/prerender_page.html",
+ FINAL_STATUS_APP_TERMINATING, 1);
+
+ content::OpenURLParams params(dest_url(), Referrer(), CURRENT_TAB,
+ content::PAGE_TRANSITION_TYPED, false);
+ params.extra_headers = "X-Custom-Header: 42\r\n";
+ NavigateToURLWithParams(params, false);
+}
+
+// Checks that prerenders are not swapped for navigations with browser-initiated
+// POST data.
+IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest,
+ PrerenderBrowserInitiatedPostNoSwap) {
+ PrerenderTestURL("files/prerender/prerender_page.html",
+ FINAL_STATUS_APP_TERMINATING, 1);
+
+ std::string post_data = "DATA";
+ content::OpenURLParams params(dest_url(), Referrer(), CURRENT_TAB,
+ content::PAGE_TRANSITION_TYPED, false);
+ params.uses_post = true;
+ params.browser_initiated_post_data =
+ base::RefCountedString::TakeString(&post_data);
+ NavigateToURLWithParams(params, false);
+}
+
} // namespace prerender
diff --git a/chrome/browser/prerender/prerender_contents.cc b/chrome/browser/prerender/prerender_contents.cc
index 13378955f9..1d4d672e6f 100644
--- a/chrome/browser/prerender/prerender_contents.cc
+++ b/chrome/browser/prerender/prerender_contents.cc
@@ -17,12 +17,12 @@
#include "chrome/browser/prerender/prerender_final_status.h"
#include "chrome/browser/prerender/prerender_handle.h"
#include "chrome/browser/prerender/prerender_manager.h"
-#include "chrome/browser/prerender/prerender_render_view_host_observer.h"
#include "chrome/browser/prerender/prerender_tracker.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_tab_contents.h"
#include "chrome/common/prerender_messages.h"
+#include "chrome/common/render_messages.h"
#include "chrome/common/url_constants.h"
#include "content/public/browser/browser_child_process_host.h"
#include "content/public/browser/notification_service.h"
@@ -277,10 +277,6 @@ void PrerenderContents::StartPrerendering(
// Set the size of the prerender WebContents.
prerender_contents_->GetView()->SizeContents(size_);
- // Register as an observer of the RenderViewHost so we get messages.
- render_view_host_observer_.reset(
- new PrerenderRenderViewHostObserver(this, GetRenderViewHostMutable()));
-
child_id_ = GetRenderViewHost()->GetProcess()->GetID();
route_id_ = GetRenderViewHost()->GetRoutingID();
@@ -508,6 +504,18 @@ void PrerenderContents::DidUpdateFaviconURL(
}
}
+bool PrerenderContents::OnMessageReceived(const IPC::Message& message) {
+ bool handled = true;
+ // The following messages we do want to consume.
+ IPC_BEGIN_MESSAGE_MAP(PrerenderContents, message)
+ IPC_MESSAGE_HANDLER(ChromeViewHostMsg_CancelPrerenderForPrinting,
+ OnCancelPrerenderForPrinting)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+
+ return handled;
+}
+
bool PrerenderContents::AddAliasURL(const GURL& url) {
const bool http = url.SchemeIs(content::kHttpScheme);
const bool https = url.SchemeIs(content::kHttpsScheme);
@@ -629,12 +637,6 @@ void PrerenderContents::Destroy(FinalStatus final_status) {
match_complete_status() == MATCH_COMPLETE_REPLACEMENT)) {
NotifyPrerenderStop();
}
-
- // We may destroy the PrerenderContents before we have initialized the
- // RenderViewHost. Otherwise set the Observer's PrerenderContents to NULL to
- // avoid any more messages being sent.
- if (render_view_host_observer_)
- render_view_host_observer_->set_prerender_contents(NULL);
}
base::ProcessMetrics* PrerenderContents::MaybeGetProcessMetrics() {
@@ -671,7 +673,6 @@ void PrerenderContents::DestroyWhenUsingTooManyResources() {
WebContents* PrerenderContents::ReleasePrerenderContents() {
prerender_contents_->SetDelegate(NULL);
- render_view_host_observer_.reset();
content::WebContentsObserver::Observe(NULL);
SessionStorageNamespace* session_storage_namespace =
GetSessionStorageNamespace();
@@ -728,5 +729,8 @@ SessionStorageNamespace* PrerenderContents::GetSessionStorageNamespace() const {
GetDefaultSessionStorageNamespace();
}
+void PrerenderContents::OnCancelPrerenderForPrinting() {
+ Destroy(FINAL_STATUS_WINDOW_PRINT);
+}
} // namespace prerender
diff --git a/chrome/browser/prerender/prerender_contents.h b/chrome/browser/prerender/prerender_contents.h
index ec0adbd1ff..8669cd90e5 100644
--- a/chrome/browser/prerender/prerender_contents.h
+++ b/chrome/browser/prerender/prerender_contents.h
@@ -44,7 +44,6 @@ namespace prerender {
class PrerenderHandle;
class PrerenderManager;
-class PrerenderRenderViewHostObserver;
class PrerenderContents : public content::NotificationObserver,
public content::WebContentsObserver {
@@ -231,6 +230,7 @@ class PrerenderContents : public content::NotificationObserver,
content::RenderViewHost* render_view_host) OVERRIDE;
virtual void DidUpdateFaviconURL(int32 page_id,
const std::vector<content::FaviconURL>& urls) OVERRIDE;
+ virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE;
@@ -330,11 +330,12 @@ class PrerenderContents : public content::NotificationObserver,
// Needs to be able to call the constructor.
friend class PrerenderContentsFactoryImpl;
- friend class PrerenderRenderViewHostObserver;
-
// Returns the ProcessMetrics for the render process, if it exists.
base::ProcessMetrics* MaybeGetProcessMetrics();
+ // Message handlers.
+ void OnCancelPrerenderForPrinting();
+
ObserverList<Observer> observer_list_;
// The prerender manager owning this object.
@@ -395,8 +396,6 @@ class PrerenderContents : public content::NotificationObserver,
// The prerendered WebContents; may be null.
scoped_ptr<content::WebContents> prerender_contents_;
- scoped_ptr<PrerenderRenderViewHostObserver> render_view_host_observer_;
-
scoped_ptr<WebContentsDelegateImpl> web_contents_delegate_;
// These are -1 before a RenderView is created.
diff --git a/chrome/browser/prerender/prerender_field_trial.cc b/chrome/browser/prerender/prerender_field_trial.cc
index ad1f3a0435..3813c5f9e1 100644
--- a/chrome/browser/prerender/prerender_field_trial.cc
+++ b/chrome/browser/prerender/prerender_field_trial.cc
@@ -326,7 +326,7 @@ bool IsUnencryptedSyncEnabled(Profile* profile) {
// Indicates whether the Local Predictor is enabled based on field trial
// selection.
-bool IsLocalPredictorEnabledBasedOnSelection() {
+bool IsLocalPredictorEnabled() {
#if defined(OS_ANDROID) || defined(OS_IOS)
return false;
#endif
@@ -337,27 +337,19 @@ bool IsLocalPredictorEnabledBasedOnSelection() {
return GetLocalPredictorSpecValue(kLocalPredictorKeyName) == kEnabledGroup;
}
-// Usually, we enable the Local Predictor based on field trial selection
-// (see above), so we can just return that setting.
-// However, via Finch, we can specify to not create a LocalPredictor if
-// UnencryptedSync is not enabled. Therefore, we have to perform this additional
-// check to determine whether or not we actually want to enable the
-// LocalPredictor.
-bool IsLocalPredictorEnabled(Profile* profile) {
- if (GetLocalPredictorSpecValue(kLocalPredictorUnencryptedSyncOnlyKeyName) ==
+bool DisableLocalPredictorBasedOnSyncAndConfiguration(Profile* profile) {
+ return
+ GetLocalPredictorSpecValue(kLocalPredictorUnencryptedSyncOnlyKeyName) ==
kEnabledGroup &&
- !IsUnencryptedSyncEnabled(profile)) {
- return false;
- }
- return IsLocalPredictorEnabledBasedOnSelection();
+ !IsUnencryptedSyncEnabled(profile);
}
bool IsLoggedInPredictorEnabled() {
- return IsLocalPredictorEnabledBasedOnSelection();
+ return IsLocalPredictorEnabled();
}
bool IsSideEffectFreeWhitelistEnabled() {
- return IsLocalPredictorEnabledBasedOnSelection() &&
+ return IsLocalPredictorEnabled() &&
GetLocalPredictorSpecValue(kSideEffectFreeWhitelistKeyName) !=
kDisabledGroup;
}
diff --git a/chrome/browser/prerender/prerender_field_trial.h b/chrome/browser/prerender/prerender_field_trial.h
index d19f067fee..33c4372076 100644
--- a/chrome/browser/prerender/prerender_field_trial.h
+++ b/chrome/browser/prerender/prerender_field_trial.h
@@ -22,7 +22,11 @@ void ConfigurePrefetchAndPrerender(const CommandLine& command_line);
bool IsOmniboxEnabled(Profile* profile);
// Returns true iff the Prerender Local Predictor is enabled.
-bool IsLocalPredictorEnabled(Profile* profile);
+bool IsLocalPredictorEnabled();
+
+// Indicates whether to disable the local predictor due to unencrypted sync
+// settings and configuration.
+bool DisableLocalPredictorBasedOnSyncAndConfiguration(Profile* profile);
// Returns true iff the LoggedIn Predictor is enabled.
bool IsLoggedInPredictorEnabled();
diff --git a/chrome/browser/prerender/prerender_local_predictor.cc b/chrome/browser/prerender/prerender_local_predictor.cc
index cf4ab36924..f86110acbb 100644
--- a/chrome/browser/prerender/prerender_local_predictor.cc
+++ b/chrome/browser/prerender/prerender_local_predictor.cc
@@ -846,6 +846,8 @@ bool PrerenderLocalPredictor::ApplyParsedPrerenderServiceResponse(
in_index == 1,
(1 - in_index_timed_out) == 1);
}
+ if (list->GetSize() > 0)
+ RecordEvent(EVENT_PRERENDER_SERIVCE_RETURNED_HINTING_CANDIDATES);
}
}
@@ -970,6 +972,11 @@ HistoryService* PrerenderLocalPredictor::GetHistoryIfExists() const {
void PrerenderLocalPredictor::Init() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
RecordEvent(EVENT_INIT_STARTED);
+ Profile* profile = prerender_manager_->profile();
+ if (!profile || DisableLocalPredictorBasedOnSyncAndConfiguration(profile)) {
+ RecordEvent(EVENT_INIT_FAILED_UNENCRYPTED_SYNC_NOT_ENABLED);
+ return;
+ }
HistoryService* history = GetHistoryIfExists();
if (history) {
CHECK(!is_visit_database_observer_);
@@ -1100,6 +1107,8 @@ void PrerenderLocalPredictor::ContinuePrerenderCheck(
RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_EXAMINE_NEXT_URL_SERVICE);
}
+ RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_EXAMINE_NEXT_URL_NOT_SKIPPED);
+
// We need to check whether we can issue a prerender for this URL.
// We test a set of conditions. Each condition can either rule out
// a prerender (in which case we reset url_info, so that it will not
diff --git a/chrome/browser/prerender/prerender_local_predictor.h b/chrome/browser/prerender/prerender_local_predictor.h
index bd722c46bf..720dc96256 100644
--- a/chrome/browser/prerender/prerender_local_predictor.h
+++ b/chrome/browser/prerender/prerender_local_predictor.h
@@ -129,6 +129,9 @@ class PrerenderLocalPredictor : public history::VisitDatabaseObserver,
EVENT_NAMESPACE_MISMATCH_MERGE_RESULT_TOO_MANY_TRANSACTIONS = 79,
EVENT_NAMESPACE_MISMATCH_MERGE_RESULT_NOT_MERGEABLE = 80,
EVENT_NAMESPACE_MISMATCH_MERGE_RESULT_MERGEABLE = 81,
+ EVENT_INIT_FAILED_UNENCRYPTED_SYNC_NOT_ENABLED = 82,
+ EVENT_CONTINUE_PRERENDER_CHECK_EXAMINE_NEXT_URL_NOT_SKIPPED = 83,
+ EVENT_PRERENDER_SERIVCE_RETURNED_HINTING_CANDIDATES = 84,
EVENT_MAX_VALUE
};
diff --git a/chrome/browser/prerender/prerender_manager.cc b/chrome/browser/prerender/prerender_manager.cc
index 33990322cf..954edb55bb 100644
--- a/chrome/browser/prerender/prerender_manager.cc
+++ b/chrome/browser/prerender/prerender_manager.cc
@@ -40,6 +40,7 @@
#include "chrome/browser/prerender/prerender_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_util.h"
+#include "chrome/browser/ui/browser_navigator.h"
#include "chrome/browser/ui/tab_contents/core_tab_helper.h"
#include "chrome/browser/ui/tab_contents/core_tab_helper_delegate.h"
#include "chrome/common/chrome_switches.h"
@@ -242,7 +243,7 @@ PrerenderManager::PrerenderManager(Profile* profile,
// the same thread that it was created on.
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (IsLocalPredictorEnabled(profile))
+ if (IsLocalPredictorEnabled())
local_predictor_.reset(new PrerenderLocalPredictor(this));
if (IsLoggedInPredictorEnabled() && !profile_->IsOffTheRecord()) {
@@ -409,11 +410,17 @@ void PrerenderManager::CancelAllPrerenders() {
}
}
-bool PrerenderManager::MaybeUsePrerenderedPage(WebContents* web_contents,
- const GURL& url) {
+bool PrerenderManager::MaybeUsePrerenderedPage(const GURL& url,
+ chrome::NavigateParams* params) {
DCHECK(CalledOnValidThread());
+
+ content::WebContents* web_contents = params->target_contents;
DCHECK(!IsWebContentsPrerendering(web_contents, NULL));
+ // Don't prerender if the navigation involves some special parameters.
+ if (params->uses_post || !params->extra_headers.empty())
+ return false;
+
DeleteOldEntries();
to_delete_prerenders_.clear();
// TODO(ajwong): This doesn't handle isolated apps correctly.
@@ -546,6 +553,9 @@ bool PrerenderManager::MaybeUsePrerenderedPage(WebContents* web_contents,
SwapTabContents(old_web_contents, new_web_contents);
prerender_contents->CommitHistory(new_web_contents);
+ // Record the new target_contents for the callers.
+ params->target_contents = new_web_contents;
+
GURL icon_url = prerender_contents->icon_url();
if (!icon_url.is_empty()) {
diff --git a/chrome/browser/prerender/prerender_manager.h b/chrome/browser/prerender/prerender_manager.h
index 91c547d1f2..c8e7f642be 100644
--- a/chrome/browser/prerender/prerender_manager.h
+++ b/chrome/browser/prerender/prerender_manager.h
@@ -38,6 +38,10 @@ namespace base {
class DictionaryValue;
}
+namespace chrome {
+struct NavigateParams;
+}
+
namespace content {
class WebContents;
}
@@ -156,11 +160,12 @@ class PrerenderManager : public base::SupportsWeakPtr<PrerenderManager>,
// Cancels all active prerenders.
void CancelAllPrerenders();
- // If |url| matches a valid prerendered page, try to swap it into
- // |web_contents| and merge browsing histories. Returns |true| if a
- // prerendered page is swapped in, |false| otherwise.
- bool MaybeUsePrerenderedPage(content::WebContents* web_contents,
- const GURL& url);
+ // If |url| matches a valid prerendered page and |params| are compatible, try
+ // to swap it and merge browsing histories. Returns |true| and updates
+ // |params->target_contents| if a prerendered page is swapped in, |false|
+ // otherwise.
+ bool MaybeUsePrerenderedPage(const GURL& url,
+ chrome::NavigateParams* params);
// Moves a PrerenderContents to the pending delete list from the list of
// active prerenders when prerendering should be cancelled.
diff --git a/chrome/browser/prerender/prerender_manager_factory.cc b/chrome/browser/prerender/prerender_manager_factory.cc
index 4a3d5d8bab..31049a08ba 100644
--- a/chrome/browser/prerender/prerender_manager_factory.cc
+++ b/chrome/browser/prerender/prerender_manager_factory.cc
@@ -16,6 +16,7 @@
#include "chrome/browser/prerender/prerender_manager.h"
#include "chrome/browser/profiles/incognito_helpers.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/sync/profile_sync_service_factory.h"
#include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
#if defined(OS_CHROMEOS)
@@ -48,6 +49,7 @@ PrerenderManagerFactory::PrerenderManagerFactory()
// PrerenderLocalPredictor observers the history visit DB.
DependsOn(HistoryServiceFactory::GetInstance());
DependsOn(predictors::PredictorDatabaseFactory::GetInstance());
+ DependsOn(ProfileSyncServiceFactory::GetInstance());
}
PrerenderManagerFactory::~PrerenderManagerFactory() {
diff --git a/chrome/browser/prerender/prerender_render_view_host_observer.cc b/chrome/browser/prerender/prerender_render_view_host_observer.cc
deleted file mode 100644
index 6445cc4b67..0000000000
--- a/chrome/browser/prerender/prerender_render_view_host_observer.cc
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/prerender/prerender_render_view_host_observer.h"
-
-#include "chrome/browser/prerender/prerender_contents.h"
-#include "chrome/common/render_messages.h"
-
-using content::RenderViewHost;
-
-namespace prerender {
-
-PrerenderRenderViewHostObserver::PrerenderRenderViewHostObserver(
- PrerenderContents* prerender_contents,
- RenderViewHost* render_view_host)
- : content::RenderViewHostObserver(render_view_host),
- prerender_contents_(prerender_contents) {
-}
-
-void PrerenderRenderViewHostObserver::RenderViewHostDestroyed(
- RenderViewHost* rvh) {
- // The base class deletes |this| on RenderViewHost destruction but we want the
- // lifetime to be tied to the PrerenderContents instead, so we'll do nothing
- // here.
-}
-
-bool PrerenderRenderViewHostObserver::OnMessageReceived(
- const IPC::Message& message) {
- if (!prerender_contents_)
- return content::RenderViewHostObserver::OnMessageReceived(message);
-
- bool handled = true;
- // The following messages we do want to consume.
- IPC_BEGIN_MESSAGE_MAP(PrerenderRenderViewHostObserver, message)
- IPC_MESSAGE_HANDLER(ChromeViewHostMsg_CancelPrerenderForPrinting,
- OnCancelPrerenderForPrinting)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
-
- // Pass the message through.
- if (!handled)
- handled = content::RenderViewHostObserver::OnMessageReceived(message);
-
- return handled;
-}
-
-void PrerenderRenderViewHostObserver::OnCancelPrerenderForPrinting() {
- prerender_contents_->Destroy(FINAL_STATUS_WINDOW_PRINT);
-}
-
-} // namespace prerender
diff --git a/chrome/browser/prerender/prerender_render_view_host_observer.h b/chrome/browser/prerender/prerender_render_view_host_observer.h
deleted file mode 100644
index 79339fe73a..0000000000
--- a/chrome/browser/prerender/prerender_render_view_host_observer.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_PRERENDER_PRERENDER_RENDER_VIEW_HOST_OBSERVER_H_
-#define CHROME_BROWSER_PRERENDER_PRERENDER_RENDER_VIEW_HOST_OBSERVER_H_
-
-#include "content/public/browser/render_view_host_observer.h"
-
-namespace content {
-class RenderViewHost;
-}
-
-namespace IPC {
-class Message;
-}
-
-namespace prerender {
-
-class PrerenderContents;
-
-// Observer for RenderViewHost messages.
-class PrerenderRenderViewHostObserver : public content::RenderViewHostObserver {
- public:
- PrerenderRenderViewHostObserver(PrerenderContents* prerender_contents,
- content::RenderViewHost* render_view_host);
-
- virtual void RenderViewHostDestroyed(content::RenderViewHost* rvh) OVERRIDE;
-
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
-
- void set_prerender_contents(PrerenderContents* prerender_contents) {
- prerender_contents_ = prerender_contents;
- }
-
- private:
- // Message handlers.
- void OnCancelPrerenderForPrinting();
-
- // The associated prerender contents.
- PrerenderContents* prerender_contents_;
-};
-
-} // namespace prerender
-
-#endif // CHROME_BROWSER_PRERENDER_PRERENDER_RENDER_VIEW_HOST_OBSERVER_H_
diff --git a/chrome/browser/prerender/prerender_tab_helper.cc b/chrome/browser/prerender/prerender_tab_helper.cc
index dddb53e9a4..80cfa3af98 100644
--- a/chrome/browser/prerender/prerender_tab_helper.cc
+++ b/chrome/browser/prerender/prerender_tab_helper.cc
@@ -193,6 +193,7 @@ void PrerenderTabHelper::ProvisionalChangeToMainFrameUrl(
void PrerenderTabHelper::DidCommitProvisionalLoadForFrame(
int64 frame_id,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& validated_url,
content::PageTransition transition_type,
diff --git a/chrome/browser/prerender/prerender_tab_helper.h b/chrome/browser/prerender/prerender_tab_helper.h
index 72ab579e69..ed22a49d89 100644
--- a/chrome/browser/prerender/prerender_tab_helper.h
+++ b/chrome/browser/prerender/prerender_tab_helper.h
@@ -66,6 +66,7 @@ class PrerenderTabHelper
content::RenderViewHost* render_view_host) OVERRIDE;
virtual void DidCommitProvisionalLoadForFrame(
int64 frame_id,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& validated_url,
content::PageTransition transition_type,
diff --git a/chrome/browser/prerender/prerender_util.cc b/chrome/browser/prerender/prerender_util.cc
index 1c4ab6ff59..3f775191a6 100644
--- a/chrome/browser/prerender/prerender_util.cc
+++ b/chrome/browser/prerender/prerender_util.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/prerender/prerender_util.h"
#include "base/logging.h"
+#include "base/metrics/histogram.h"
#include "base/metrics/sparse_histogram.h"
#include "base/strings/string_util.h"
#include "content/public/browser/resource_request_info.h"
@@ -13,9 +14,61 @@
#include "url/url_canon.h"
#include "url/url_parse.h"
#include "url/url_util.h"
+#include "webkit/common/resource_type.h"
namespace prerender {
+namespace {
+
+const char kModPagespeedHeader[] = "X-Mod-Pagespeed";
+const char kPageSpeedHeader[] = "X-Page-Speed";
+const char kPagespeedServerHistogram[] =
+ "Prerender.PagespeedHeader.ServerCounts";
+const char kPagespeedVersionHistogram[] =
+ "Prerender.PagespeedHeader.VersionCounts";
+
+enum PagespeedHeaderServerType {
+ PAGESPEED_TOTAL_RESPONSES = 0,
+ PAGESPEED_MOD_PAGESPEED_SERVER = 1,
+ PAGESPEED_NGX_PAGESPEED_SERVER = 2,
+ PAGESPEED_PAGESPEED_SERVICE_SERVER = 3,
+ PAGESPEED_UNKNOWN_SERVER = 4,
+ PAGESPEED_SERVER_MAXIMUM = 5
+};
+
+// Private function to parse the PageSpeed version number and encode it in
+// buckets 2 through 99: if it is in the format a.b.c.d-e the bucket will be
+// 2 + 2 * (max(c, 10) - 10) + (d > 1 ? 1 : 0); if it is not in this format
+// we return zero.
+int GetXModPagespeedBucketFromVersion(const std::string& version) {
+ int a, b, c, d, e;
+ int num_parsed = sscanf(version.c_str(), "%d.%d.%d.%d-%d",
+ &a, &b, &c, &d, &e);
+ int output = 0;
+ if (num_parsed == 5) {
+ output = 2;
+ if (c > 10)
+ output += 2 * (c - 10);
+ if (d > 1)
+ output++;
+ if (output < 2 || output > 99)
+ output = 0;
+ }
+ return output;
+}
+
+// Private function to parse the X-Page-Speed header value and determine
+// whether it is in the PageSpeed Service format, namely m_n_dc were m_n is
+// a version number and dc is an encoded 2-character value.
+bool IsPageSpeedServiceVersionNumber(const std::string& version) {
+ int a, b;
+ char c, d, e; // e is to detect EOL as we check that it /isn't/ converted.
+ int num_parsed = sscanf(version.c_str(), "%d_%d_%c%c%c", &a, &b, &c, &d, &e);
+ return (num_parsed == 4);
+}
+
+} // namespace
+
bool MaybeGetQueryStringBasedAliasURL(
const GURL& url, GURL* alias_url) {
DCHECK(alias_url);
@@ -89,44 +142,80 @@ bool IsControlGroupExperiment(uint8 experiment_id) {
return experiment_id == 7 || experiment_id == 8;
}
-void URLRequestResponseStarted(net::URLRequest* request) {
- static const char* kModPagespeedHeader = "X-Mod-Pagespeed";
- static const char* kModPagespeedHistogram = "Prerender.ModPagespeedHeader";
- const content::ResourceRequestInfo* info =
- content::ResourceRequestInfo::ForRequest(request);
- // Gather histogram information about the X-Mod-Pagespeed header.
- if (info->GetResourceType() == ResourceType::MAIN_FRAME &&
- request->url().SchemeIsHTTPOrHTTPS()) {
- UMA_HISTOGRAM_SPARSE_SLOWLY(kModPagespeedHistogram, 0);
- if (request->response_headers() &&
- request->response_headers()->HasHeader(kModPagespeedHeader)) {
- UMA_HISTOGRAM_SPARSE_SLOWLY(kModPagespeedHistogram, 1);
-
- // Attempt to parse the version number, and encode it in buckets
- // 2 through 99. 0 and 1 are used to store all pageviews and
- // # pageviews with the MPS header (see above).
- void* iter = NULL;
- std::string mps_version;
- if (request->response_headers()->EnumerateHeader(
- &iter, kModPagespeedHeader, &mps_version) &&
- !mps_version.empty()) {
- // Mod Pagespeed versions are of the form a.b.c.d-e
- int a, b, c, d, e;
- int num_parsed = sscanf(mps_version.c_str(), "%d.%d.%d.%d-%d",
- &a, &b, &c, &d, &e);
- if (num_parsed == 5) {
- int output = 2;
- if (c > 10)
- output += 2 * (c - 10);
- if (d > 1)
- output++;
- if (output < 2 || output >= 99)
- output = 99;
- UMA_HISTOGRAM_SPARSE_SLOWLY(kModPagespeedHistogram, output);
+void GatherPagespeedData(const ResourceType::Type resource_type,
+ const GURL& request_url,
+ const net::HttpResponseHeaders* response_headers) {
+ if (resource_type != ResourceType::MAIN_FRAME ||
+ !request_url.SchemeIsHTTPOrHTTPS())
+ return;
+
+ // bucket 0 counts every response seen.
+ UMA_HISTOGRAM_ENUMERATION(kPagespeedServerHistogram,
+ PAGESPEED_TOTAL_RESPONSES,
+ PAGESPEED_SERVER_MAXIMUM);
+ if (!response_headers)
+ return;
+
+ void* iter = NULL;
+ std::string name;
+ std::string value;
+ while (response_headers->EnumerateHeaderLines(&iter, &name, &value)) {
+ if (name == kModPagespeedHeader) {
+ // Bucket 1 counts occurences of the X-Mod-Pagespeed header.
+ UMA_HISTOGRAM_ENUMERATION(kPagespeedServerHistogram,
+ PAGESPEED_MOD_PAGESPEED_SERVER,
+ PAGESPEED_SERVER_MAXIMUM);
+ if (!value.empty()) {
+ // If the header value is in the X-Mod-Pagespeed version number format
+ // then increment the appropriate bucket, otherwise increment bucket 1,
+ // which is the catch-all "unknown version number" bucket.
+ int bucket = GetXModPagespeedBucketFromVersion(value);
+ if (bucket > 0) {
+ UMA_HISTOGRAM_SPARSE_SLOWLY(kPagespeedVersionHistogram, bucket);
+ } else {
+ UMA_HISTOGRAM_SPARSE_SLOWLY(kPagespeedVersionHistogram, 1);
+ }
+ }
+ break;
+ } else if (name == kPageSpeedHeader) {
+ // X-Page-Speed header versions are either in the X-Mod-Pagespeed format,
+ // indicating an nginx installation, or they're in the PageSpeed Service
+ // format, indicating a PSS installation, or in some other format,
+ // indicating an unknown installation [possibly IISpeed].
+ if (!value.empty()) {
+ int bucket = GetXModPagespeedBucketFromVersion(value);
+ if (bucket > 0) {
+ // Bucket 2 counts occurences of the X-Page-Speed header with a
+ // value in the X-Mod-Pagespeed version number format. We also
+ // count these responses in the version histogram.
+ UMA_HISTOGRAM_ENUMERATION(kPagespeedServerHistogram,
+ PAGESPEED_NGX_PAGESPEED_SERVER,
+ PAGESPEED_SERVER_MAXIMUM);
+ UMA_HISTOGRAM_SPARSE_SLOWLY(kPagespeedVersionHistogram, bucket);
+ } else if (IsPageSpeedServiceVersionNumber(value)) {
+ // Bucket 3 counts occurences of the X-Page-Speed header with a
+ // value in the PageSpeed Service version number format.
+ UMA_HISTOGRAM_ENUMERATION(kPagespeedServerHistogram,
+ PAGESPEED_PAGESPEED_SERVICE_SERVER,
+ PAGESPEED_SERVER_MAXIMUM);
+ } else {
+ // Bucket 4 counts occurences of all other values.
+ UMA_HISTOGRAM_ENUMERATION(kPagespeedServerHistogram,
+ PAGESPEED_UNKNOWN_SERVER,
+ PAGESPEED_SERVER_MAXIMUM);
}
}
+ break;
}
}
}
+void URLRequestResponseStarted(net::URLRequest* request) {
+ const content::ResourceRequestInfo* info =
+ content::ResourceRequestInfo::ForRequest(request);
+ GatherPagespeedData(info->GetResourceType(),
+ request->url(),
+ request->response_headers());
+}
+
} // namespace prerender
diff --git a/chrome/browser/prerender/prerender_util.h b/chrome/browser/prerender/prerender_util.h
index fd938878d4..04ae703438 100644
--- a/chrome/browser/prerender/prerender_util.h
+++ b/chrome/browser/prerender/prerender_util.h
@@ -7,8 +7,10 @@
#include "base/basictypes.h"
#include "url/gurl.h"
+#include "webkit/common/resource_type.h"
namespace net {
+class HttpResponseHeaders;
class URLRequest;
}
@@ -44,6 +46,13 @@ bool IsNoSwapInExperiment(uint8 experiment_id);
// iff this is the case for the experiment_id specified.
bool IsControlGroupExperiment(uint8 experiment_id);
+// Called by URLRequestResponseStarted to gather data about Pagespeed headers
+// into the Prerender.PagespeedHeader histogram. Public so it can be accessed
+// by the unit test.
+void GatherPagespeedData(const ResourceType::Type resource_type,
+ const GURL& request_url,
+ const net::HttpResponseHeaders* response_headers);
+
// Static method gathering stats about a URLRequest for which a response has
// just started.
void URLRequestResponseStarted(net::URLRequest* request);
diff --git a/chrome/browser/prerender/prerender_util_unittest.cc b/chrome/browser/prerender/prerender_util_unittest.cc
index 79a1ffa30b..af8dd1a47b 100644
--- a/chrome/browser/prerender/prerender_util_unittest.cc
+++ b/chrome/browser/prerender/prerender_util_unittest.cc
@@ -3,7 +3,13 @@
// found in the LICENSE file.
#include "chrome/browser/prerender/prerender_util.h"
+
+#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_samples.h"
+#include "base/metrics/statistics_recorder.h"
+#include "net/http/http_response_headers.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
namespace prerender {
@@ -72,4 +78,148 @@ TEST_F(PrerenderUtilTest, DetectGoogleSearchREsultURLTest) {
EXPECT_FALSE(IsGoogleSearchResultURL(GURL("http://www.chromium.org/search")));
}
+// Ensure that we count PageSpeed headers correctly.
+TEST_F(PrerenderUtilTest, CountPageSpeedHeadersTest) {
+ base::StatisticsRecorder::Initialize();
+ GURL url("http://google.com");
+ std::string temp("HTTP/1.1 200 OK\n\n");
+ std::replace(temp.begin(), temp.end(), '\n', '\0');
+ scoped_refptr<net::HttpResponseHeaders> headers(
+ new net::HttpResponseHeaders(temp));
+
+ int num_responses = 0;
+ int num_mps = 0;
+ int num_ngx = 0;
+ int num_pss = 0;
+ int num_other = 0;
+ int num_bucket_1 = 0; // unrecognized format/value bucket
+ int num_bucket_30 = 0; // 1.2.24.1 bucket
+ int num_bucket_33 = 0; // 1.3.25.2 bucket
+
+ scoped_ptr<base::HistogramSamples> server_samples;
+ scoped_ptr<base::HistogramSamples> version_samples;
+
+ // No PageSpeed header. The VersionCounts histogram isn't created yet.
+ GatherPagespeedData(ResourceType::MAIN_FRAME, url, headers.get());
+ base::HistogramBase* server_histogram =
+ base::StatisticsRecorder::FindHistogram(
+ "Prerender.PagespeedHeader.ServerCounts");
+ ASSERT_TRUE(server_histogram != NULL);
+ ASSERT_TRUE(NULL == base::StatisticsRecorder::FindHistogram(
+ "Prerender.PagespeedHeader.VersionCounts"));
+
+ server_samples = server_histogram->SnapshotSamples();
+ EXPECT_EQ(++num_responses, server_samples->GetCount(0));
+ EXPECT_EQ( num_mps, server_samples->GetCount(1));
+ EXPECT_EQ( num_ngx, server_samples->GetCount(2));
+ EXPECT_EQ( num_pss, server_samples->GetCount(3));
+ EXPECT_EQ( num_other, server_samples->GetCount(4));
+
+ // X-Mod-Pagespeed header in expected format. VersionCounts now exists.
+ headers->AddHeader("X-Mod-Pagespeed: 1.2.24.1-2300");
+ GatherPagespeedData(ResourceType::MAIN_FRAME, url, headers.get());
+ base::HistogramBase* version_histogram =
+ base::StatisticsRecorder::FindHistogram(
+ "Prerender.PagespeedHeader.VersionCounts");
+ ASSERT_TRUE(version_histogram != NULL);
+ server_samples = server_histogram->SnapshotSamples();
+ version_samples = version_histogram->SnapshotSamples();
+ EXPECT_EQ(++num_responses, server_samples->GetCount(0));
+ EXPECT_EQ(++num_mps, server_samples->GetCount(1));
+ EXPECT_EQ( num_ngx, server_samples->GetCount(2));
+ EXPECT_EQ( num_pss, server_samples->GetCount(3));
+ EXPECT_EQ( num_other, server_samples->GetCount(4));
+ EXPECT_EQ( num_bucket_1, version_samples->GetCount(1));
+ EXPECT_EQ(++num_bucket_30, version_samples->GetCount(30)); // +1 for #30
+ EXPECT_EQ( num_bucket_33, version_samples->GetCount(33));
+ headers->RemoveHeader("X-Mod-Pagespeed");
+
+ // X-Mod-Pagespeed header in unexpected format.
+ headers->AddHeader("X-Mod-Pagespeed: Powered By PageSpeed!");
+ GatherPagespeedData(ResourceType::MAIN_FRAME, url, headers.get());
+ server_samples = server_histogram->SnapshotSamples();
+ version_samples = version_histogram->SnapshotSamples();
+ EXPECT_EQ(++num_responses, server_samples->GetCount(0));
+ EXPECT_EQ(++num_mps, server_samples->GetCount(1));
+ EXPECT_EQ( num_ngx, server_samples->GetCount(2));
+ EXPECT_EQ( num_pss, server_samples->GetCount(3));
+ EXPECT_EQ( num_other, server_samples->GetCount(4));
+ EXPECT_EQ(++num_bucket_1, version_samples->GetCount(1)); // +1 for 'huh?'
+ EXPECT_EQ( num_bucket_30, version_samples->GetCount(30));
+ EXPECT_EQ( num_bucket_33, version_samples->GetCount(33));
+ headers->RemoveHeader("X-Mod-Pagespeed");
+
+ // X-Page-Speed header in mod_pagespeed format (so ngx_pagespeed).
+ headers->AddHeader("X-Page-Speed: 1.3.25.2-2530");
+ GatherPagespeedData(ResourceType::MAIN_FRAME, url, headers.get());
+ server_samples = server_histogram->SnapshotSamples();
+ version_samples = version_histogram->SnapshotSamples();
+ EXPECT_EQ(++num_responses, server_samples->GetCount(0));
+ EXPECT_EQ( num_mps, server_samples->GetCount(1));
+ EXPECT_EQ(++num_ngx, server_samples->GetCount(2));
+ EXPECT_EQ( num_pss, server_samples->GetCount(3));
+ EXPECT_EQ( num_other, server_samples->GetCount(4));
+ EXPECT_EQ( num_bucket_1, version_samples->GetCount(1));
+ EXPECT_EQ( num_bucket_30, version_samples->GetCount(30));
+ EXPECT_EQ(++num_bucket_33, version_samples->GetCount(33)); // +1 for #33
+ headers->RemoveHeader("X-Page-Speed");
+
+ // X-Page-Speed header in PageSpeed Service format.
+ headers->AddHeader("X-Page-Speed: 97_4_bo");
+ GatherPagespeedData(ResourceType::MAIN_FRAME, url, headers.get());
+ server_samples = server_histogram->SnapshotSamples();
+ version_samples = version_histogram->SnapshotSamples();
+ EXPECT_EQ(++num_responses, server_samples->GetCount(0));
+ EXPECT_EQ( num_mps, server_samples->GetCount(1)); // no change
+ EXPECT_EQ( num_ngx, server_samples->GetCount(2));
+ EXPECT_EQ(++num_pss, server_samples->GetCount(3)); // +1 for PSS
+ EXPECT_EQ( num_other, server_samples->GetCount(4));
+ EXPECT_EQ( num_bucket_1, version_samples->GetCount(1));
+ EXPECT_EQ( num_bucket_30, version_samples->GetCount(30));
+ EXPECT_EQ( num_bucket_33, version_samples->GetCount(33));
+ headers->RemoveHeader("X-Page-Speed");
+
+ // X-Page-Speed header in an unrecognized format (IISpeed in this case).
+ headers->AddHeader("X-Page-Speed: 1.0PS1.2-20130615");
+ GatherPagespeedData(ResourceType::MAIN_FRAME, url, headers.get());
+ server_samples = server_histogram->SnapshotSamples();
+ version_samples = version_histogram->SnapshotSamples();
+ EXPECT_EQ(++num_responses, server_samples->GetCount(0));
+ EXPECT_EQ( num_mps, server_samples->GetCount(1)); // no change
+ EXPECT_EQ( num_pss, server_samples->GetCount(3));
+ EXPECT_EQ(++num_other, server_samples->GetCount(4)); // +1 for 'other'
+ EXPECT_EQ( num_bucket_1, version_samples->GetCount(1));
+ EXPECT_EQ( num_bucket_30, version_samples->GetCount(30));
+ EXPECT_EQ( num_bucket_33, version_samples->GetCount(33));
+
+ // Not a main frame => not counted at all.
+ GatherPagespeedData(ResourceType::SUB_FRAME, url, headers.get());
+ server_samples = server_histogram->SnapshotSamples();
+ version_samples = version_histogram->SnapshotSamples();
+ EXPECT_EQ( num_responses, server_samples->GetCount(0));
+ EXPECT_EQ( num_mps, server_samples->GetCount(1));
+ EXPECT_EQ( num_ngx, server_samples->GetCount(2));
+ EXPECT_EQ( num_pss, server_samples->GetCount(3));
+ EXPECT_EQ( num_other, server_samples->GetCount(4));
+ EXPECT_EQ( num_bucket_1, version_samples->GetCount(1));
+ EXPECT_EQ( num_bucket_30, version_samples->GetCount(30));
+ EXPECT_EQ( num_bucket_33, version_samples->GetCount(33));
+
+ // Not a http/https URL => not counted at all.
+ GURL data_url("data:image/png;base64,yadda yadda==");
+ GatherPagespeedData(ResourceType::MAIN_FRAME, data_url, headers.get());
+ server_samples = server_histogram->SnapshotSamples();
+ version_samples = version_histogram->SnapshotSamples();
+ EXPECT_EQ( num_responses, server_samples->GetCount(0));
+ EXPECT_EQ( num_mps, server_samples->GetCount(1));
+ EXPECT_EQ( num_ngx, server_samples->GetCount(2));
+ EXPECT_EQ( num_pss, server_samples->GetCount(3));
+ EXPECT_EQ( num_other, server_samples->GetCount(4));
+ EXPECT_EQ( num_bucket_1, version_samples->GetCount(1));
+ EXPECT_EQ( num_bucket_30, version_samples->GetCount(30));
+ EXPECT_EQ( num_bucket_33, version_samples->GetCount(33));
+
+ headers->RemoveHeader("X-Page-Speed");
+}
+
} // namespace prerender
diff --git a/chrome/browser/printing/print_dialog_cloud_interative_uitest.cc b/chrome/browser/printing/print_dialog_cloud_interative_uitest.cc
deleted file mode 100644
index eab142376c..0000000000
--- a/chrome/browser/printing/print_dialog_cloud_interative_uitest.cc
+++ /dev/null
@@ -1,284 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/printing/print_dialog_cloud.h"
-#include "chrome/browser/printing/print_dialog_cloud_internal.h"
-
-#include <functional>
-
-#include "base/bind.h"
-#include "base/file_util.h"
-#include "base/files/file_path.h"
-#include "base/memory/singleton.h"
-#include "base/path_service.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/threading/thread_restrictions.h"
-#include "base/values.h"
-#include "chrome/browser/printing/cloud_print/cloud_print_url.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/common/url_constants.h"
-#include "chrome/test/base/in_process_browser_test.h"
-#include "chrome/test/base/ui_test_utils.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_types.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/test/test_browser_thread.h"
-#include "net/url_request/url_request.h"
-#include "net/url_request/url_request_filter.h"
-#include "net/url_request/url_request_test_job.h"
-#include "net/url_request/url_request_test_util.h"
-#include "ui/base/test/ui_controls.h"
-
-using content::BrowserThread;
-
-namespace {
-
-class TestData {
- public:
- static TestData* GetInstance() {
- return Singleton<TestData>::get();
- }
-
- const char* GetTestData() {
- // Fetching this data blocks the IO thread, but we don't really care because
- // this is a test.
- base::ThreadRestrictions::ScopedAllowIO allow_io;
-
- if (test_data_.empty()) {
- base::FilePath test_data_directory;
- PathService::Get(chrome::DIR_TEST_DATA, &test_data_directory);
- base::FilePath test_file =
- test_data_directory.AppendASCII("printing/cloud_print_uitest.html");
- base::ReadFileToString(test_file, &test_data_);
- }
- return test_data_.c_str();
- }
- private:
- TestData() {}
-
- std::string test_data_;
-
- friend struct DefaultSingletonTraits<TestData>;
-};
-
-// A simple test net::URLRequestJob. We don't care what it does, only that
-// whether it starts and finishes.
-class SimpleTestJob : public net::URLRequestTestJob {
- public:
- SimpleTestJob(net::URLRequest* request,
- net::NetworkDelegate* network_delegate)
- : net::URLRequestTestJob(request,
- network_delegate,
- test_headers(),
- TestData::GetInstance()->GetTestData(),
- true) {}
-
- virtual void GetResponseInfo(net::HttpResponseInfo* info) OVERRIDE {
- net::URLRequestTestJob::GetResponseInfo(info);
- if (request_->url().SchemeIsSecure()) {
- // Make up a fake certificate for this response since we don't have
- // access to the real SSL info.
- const char* kCertIssuer = "Chrome Internal";
- const int kLifetimeDays = 100;
-
- info->ssl_info.cert =
- new net::X509Certificate(request_->url().GetWithEmptyPath().spec(),
- kCertIssuer,
- base::Time::Now(),
- base::Time::Now() +
- base::TimeDelta::FromDays(kLifetimeDays));
- info->ssl_info.cert_status = 0;
- info->ssl_info.security_bits = -1;
- }
- }
-
- private:
- virtual ~SimpleTestJob() {}
-};
-
-class TestController {
- public:
- static TestController* GetInstance() {
- return Singleton<TestController>::get();
- }
- void set_result(bool value) {
- result_ = value;
- }
- bool result() {
- return result_;
- }
- void set_expected_url(const GURL& url) {
- expected_url_ = url;
- }
- const GURL expected_url() {
- return expected_url_;
- }
- void set_delegate(net::TestDelegate* delegate) {
- delegate_ = delegate;
- }
- net::TestDelegate* delegate() {
- return delegate_;
- }
- void set_use_delegate(bool value) {
- use_delegate_ = value;
- }
- bool use_delegate() {
- return use_delegate_;
- }
- private:
- TestController()
- : result_(false),
- use_delegate_(false),
- delegate_(NULL) {}
-
- bool result_;
- bool use_delegate_;
- GURL expected_url_;
- net::TestDelegate* delegate_;
-
- friend struct DefaultSingletonTraits<TestController>;
-};
-
-} // namespace
-
-class PrintDialogCloudTest : public InProcessBrowserTest {
- public:
- PrintDialogCloudTest() : handler_added_(false) {
- PathService::Get(chrome::DIR_TEST_DATA, &test_data_directory_);
- }
-
- // Must be static for handing into AddHostnameHandler.
- static net::URLRequest::ProtocolFactory Factory;
-
- class AutoQuitDelegate : public net::TestDelegate {
- public:
- AutoQuitDelegate() {}
-
- virtual void OnResponseCompleted(net::URLRequest* request) OVERRIDE {
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::MessageLoop::QuitClosure());
- }
- };
-
- virtual void SetUp() OVERRIDE {
- TestController::GetInstance()->set_result(false);
- InProcessBrowserTest::SetUp();
- }
-
- virtual void TearDown() OVERRIDE {
- if (handler_added_) {
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(UnregisterTestHandlers, scheme_, host_name_));
- handler_added_ = false;
- TestController::GetInstance()->set_delegate(NULL);
- }
- InProcessBrowserTest::TearDown();
- }
-
- // Normally this is something I would expect could go into SetUp(),
- // but there seems to be some timing or ordering related issue with
- // the test harness that made that flaky. Calling this from the
- // individual test functions seems to fix that.
- void AddTestHandlers() {
- if (!handler_added_) {
- GURL cloud_print_service_url =
- CloudPrintURL(browser()->profile()).
- GetCloudPrintServiceURL();
- scheme_ = cloud_print_service_url.scheme();
- host_name_ = cloud_print_service_url.host();
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(RegisterTestHandlers, scheme_, host_name_));
- handler_added_ = true;
-
- GURL cloud_print_dialog_url =
- CloudPrintURL(browser()->profile()).
- GetCloudPrintServiceDialogURL();
- TestController::GetInstance()->set_expected_url(cloud_print_dialog_url);
- TestController::GetInstance()->set_delegate(&delegate_);
- }
-
- CreateDialogForTest();
- }
-
- void CreateDialogForTest() {
- base::FilePath path_to_pdf =
- test_data_directory_.AppendASCII("printing/cloud_print_uitest.pdf");
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&print_dialog_cloud::CreatePrintDialogForFile,
- browser()->profile(), browser()->window()->GetNativeWindow(),
- path_to_pdf, string16(), string16(),
- std::string("application/pdf"), false));
- }
-
- private:
- static void RegisterTestHandlers(const std::string& scheme,
- const std::string& host_name) {
- net::URLRequestFilter::GetInstance()->AddHostnameHandler(
- scheme, host_name, &PrintDialogCloudTest::Factory);
- }
- static void UnregisterTestHandlers(const std::string& scheme,
- const std::string& host_name) {
- net::URLRequestFilter::GetInstance()->RemoveHostnameHandler(scheme,
- host_name);
- }
-
- bool handler_added_;
- std::string scheme_;
- std::string host_name_;
- base::FilePath test_data_directory_;
- AutoQuitDelegate delegate_;
-};
-
-net::URLRequestJob* PrintDialogCloudTest::Factory(
- net::URLRequest* request,
- net::NetworkDelegate* network_delegate,
- const std::string& scheme) {
- if (request &&
- (request->url() == TestController::GetInstance()->expected_url())) {
- if (TestController::GetInstance()->use_delegate())
- request->set_delegate(TestController::GetInstance()->delegate());
- TestController::GetInstance()->set_result(true);
- return new SimpleTestJob(request, network_delegate);
- }
- return new net::URLRequestTestJob(request,
- network_delegate,
- net::URLRequestTestJob::test_headers(),
- std::string(),
- true);
-}
-
-IN_PROC_BROWSER_TEST_F(PrintDialogCloudTest, HandlersRegistered) {
- AddTestHandlers();
-
- TestController::GetInstance()->set_use_delegate(true);
-
- content::RunMessageLoop();
-
- ASSERT_TRUE(TestController::GetInstance()->result());
-
- // Close the dialog before finishing the test.
- content::WindowedNotificationObserver tab_closed_observer(
- content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
- content::NotificationService::AllSources());
-
- // Can't use ui_test_utils::SendKeyPressSync or
- // ui_test_utils::SendKeyPressAndWait due to a race condition with closing
- // the window. See http://crbug.com/111269
- BrowserWindow* window = browser()->window();
- ASSERT_TRUE(window);
- gfx::NativeWindow native_window = window->GetNativeWindow();
- ASSERT_TRUE(native_window);
- bool key_sent = ui_controls::SendKeyPress(native_window, ui::VKEY_ESCAPE,
- false, false, false, false);
- EXPECT_TRUE(key_sent);
- if (key_sent)
- tab_closed_observer.Wait();
-}
diff --git a/chrome/browser/printing/print_job_worker.cc b/chrome/browser/printing/print_job_worker.cc
index a3298f5998..66477b1beb 100644
--- a/chrome/browser/printing/print_job_worker.cc
+++ b/chrome/browser/printing/print_job_worker.cc
@@ -13,6 +13,7 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/printing/print_job.h"
+#include "chrome/browser/printing/printing_ui_web_contents_observer.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_service.h"
#include "grit/generated_resources.h"
@@ -77,11 +78,12 @@ void PrintJobWorker::SetPrintDestination(
destination_ = destination;
}
-void PrintJobWorker::GetSettings(bool ask_user_for_settings,
- gfx::NativeView parent_view,
- int document_page_count,
- bool has_selection,
- MarginType margin_type) {
+void PrintJobWorker::GetSettings(
+ bool ask_user_for_settings,
+ scoped_ptr<PrintingUIWebContentsObserver> web_contents_observer,
+ int document_page_count,
+ bool has_selection,
+ MarginType margin_type) {
DCHECK_EQ(message_loop(), base::MessageLoop::current());
DCHECK_EQ(page_number_, PageNumber::npos());
@@ -100,8 +102,10 @@ void PrintJobWorker::GetSettings(bool ask_user_for_settings,
BrowserThread::UI, FROM_HERE,
base::Bind(&HoldRefCallback, make_scoped_refptr(owner_),
base::Bind(&PrintJobWorker::GetSettingsWithUI,
- base::Unretained(this), parent_view,
- document_page_count, has_selection)));
+ base::Unretained(this),
+ base::Passed(&web_contents_observer),
+ document_page_count,
+ has_selection)));
} else {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
@@ -169,11 +173,17 @@ void PrintJobWorker::GetSettingsDone(PrintingContext::Result result) {
result));
}
-void PrintJobWorker::GetSettingsWithUI(gfx::NativeView parent_view,
- int document_page_count,
- bool has_selection) {
+void PrintJobWorker::GetSettingsWithUI(
+ scoped_ptr<PrintingUIWebContentsObserver> web_contents_observer,
+ int document_page_count,
+ bool has_selection) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ gfx::NativeView parent_view = web_contents_observer->GetParentView();
+ if (!parent_view) {
+ GetSettingsWithUIDone(printing::PrintingContext::FAILED);
+ return;
+ }
printing_context_->AskUserForSettings(
parent_view, document_page_count, has_selection,
base::Bind(&PrintJobWorker::GetSettingsWithUIDone,
diff --git a/chrome/browser/printing/print_job_worker.h b/chrome/browser/printing/print_job_worker.h
index 2b639fafd3..beb3cd7f45 100644
--- a/chrome/browser/printing/print_job_worker.h
+++ b/chrome/browser/printing/print_job_worker.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROME_BROWSER_PRINTING_PRINT_JOB_WORKER_H__
-#define CHROME_BROWSER_PRINTING_PRINT_JOB_WORKER_H__
+#ifndef CHROME_BROWSER_PRINTING_PRINT_JOB_WORKER_H_
+#define CHROME_BROWSER_PRINTING_PRINT_JOB_WORKER_H_
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
@@ -13,7 +13,8 @@
#include "printing/print_destination_interface.h"
#include "printing/printing_context.h"
#include "printing/print_job_constants.h"
-#include "ui/gfx/native_widget_types.h"
+
+class PrintingUIWebContentsObserver;
namespace base {
class DictionaryValue;
@@ -45,11 +46,12 @@ class PrintJobWorker : public base::Thread {
// Initializes the print settings. If |ask_user_for_settings| is true, a
// Print... dialog box will be shown to ask the user his preference.
- void GetSettings(bool ask_user_for_settings,
- gfx::NativeView parent_view,
- int document_page_count,
- bool has_selection,
- MarginType margin_type);
+ void GetSettings(
+ bool ask_user_for_settings,
+ scoped_ptr<PrintingUIWebContentsObserver> web_contents_observer,
+ int document_page_count,
+ bool has_selection,
+ MarginType margin_type);
// Set the new print settings. This function takes ownership of
// |new_settings|.
@@ -95,9 +97,10 @@ class PrintJobWorker : public base::Thread {
// Asks the user for print settings. Must be called on the UI thread.
// Required on Mac and Linux. Windows can display UI from non-main threads,
// but sticks with this for consistency.
- void GetSettingsWithUI(gfx::NativeView parent_view,
- int document_page_count,
- bool has_selection);
+ void GetSettingsWithUI(
+ scoped_ptr<PrintingUIWebContentsObserver> web_contents_observer,
+ int document_page_count,
+ bool has_selection);
// The callback used by PrintingContext::GetSettingsWithUI() to notify this
// object that the print settings are set. This is needed in order to bounce
@@ -140,4 +143,4 @@ class PrintJobWorker : public base::Thread {
} // namespace printing
-#endif // CHROME_BROWSER_PRINTING_PRINT_JOB_WORKER_H__
+#endif // CHROME_BROWSER_PRINTING_PRINT_JOB_WORKER_H_
diff --git a/chrome/browser/printing/printer_query.cc b/chrome/browser/printing/printer_query.cc
index 6935975bbc..03198e235b 100644
--- a/chrome/browser/printing/printer_query.cc
+++ b/chrome/browser/printing/printer_query.cc
@@ -10,6 +10,7 @@
#include "base/threading/thread_restrictions.h"
#include "base/values.h"
#include "chrome/browser/printing/print_job_worker.h"
+#include "chrome/browser/printing/printing_ui_web_contents_observer.h"
namespace printing {
@@ -68,12 +69,13 @@ int PrinterQuery::cookie() const {
return cookie_;
}
-void PrinterQuery::GetSettings(GetSettingsAskParam ask_user_for_settings,
- gfx::NativeView parent_view,
- int expected_page_count,
- bool has_selection,
- MarginType margin_type,
- const base::Closure& callback) {
+void PrinterQuery::GetSettings(
+ GetSettingsAskParam ask_user_for_settings,
+ scoped_ptr<PrintingUIWebContentsObserver> web_contents_observer,
+ int expected_page_count,
+ bool has_selection,
+ MarginType margin_type,
+ const base::Closure& callback) {
DCHECK_EQ(io_message_loop_, base::MessageLoop::current());
DCHECK(!is_print_dialog_box_shown_);
@@ -85,8 +87,11 @@ void PrinterQuery::GetSettings(GetSettingsAskParam ask_user_for_settings,
FROM_HERE,
base::Bind(&PrintJobWorker::GetSettings,
base::Unretained(worker_.get()),
- is_print_dialog_box_shown_, parent_view,
- expected_page_count, has_selection, margin_type));
+ is_print_dialog_box_shown_,
+ base::Passed(&web_contents_observer),
+ expected_page_count,
+ has_selection,
+ margin_type));
}
void PrinterQuery::SetSettings(const DictionaryValue& new_settings,
diff --git a/chrome/browser/printing/printer_query.h b/chrome/browser/printing/printer_query.h
index 3256a917b7..aab4914324 100644
--- a/chrome/browser/printing/printer_query.h
+++ b/chrome/browser/printing/printer_query.h
@@ -10,7 +10,8 @@
#include "base/memory/scoped_ptr.h"
#include "chrome/browser/printing/print_job_worker_owner.h"
#include "printing/print_job_constants.h"
-#include "ui/gfx/native_widget_types.h"
+
+class PrintingUIWebContentsObserver;
namespace base {
class DictionaryValue;
@@ -19,8 +20,8 @@ class MessageLoop;
namespace printing {
- class PrintDestinationInterface;
- class PrintJobWorker;
+class PrintDestinationInterface;
+class PrintJobWorker;
// Query the printer for settings.
class PrinterQuery : public PrintJobWorkerOwner {
@@ -42,15 +43,16 @@ class PrinterQuery : public PrintJobWorkerOwner {
virtual int cookie() const OVERRIDE;
// Initializes the printing context. It is fine to call this function multiple
- // times to reinitialize the settings. |parent_view| parameter's window will
- // be the owner of the print setting dialog box. It is unused when
+ // times to reinitialize the settings. |web_contents_observer| can be queried
+ // to find the owner of the print setting dialog box. It is unused when
// |ask_for_user_settings| is DEFAULTS.
- void GetSettings(GetSettingsAskParam ask_user_for_settings,
- gfx::NativeView parent_view,
- int expected_page_count,
- bool has_selection,
- MarginType margin_type,
- const base::Closure& callback);
+ void GetSettings(
+ GetSettingsAskParam ask_user_for_settings,
+ scoped_ptr<PrintingUIWebContentsObserver> web_contents_observer,
+ int expected_page_count,
+ bool has_selection,
+ MarginType margin_type,
+ const base::Closure& callback);
// Updates the current settings with |new_settings| dictionary values.
void SetSettings(const base::DictionaryValue& new_settings,
diff --git a/chrome/browser/printing/printing_message_filter.cc b/chrome/browser/printing/printing_message_filter.cc
index 79a1194991..5b48b891b8 100644
--- a/chrome/browser/printing/printing_message_filter.cc
+++ b/chrome/browser/printing/printing_message_filter.cc
@@ -10,13 +10,13 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/printing/printer_query.h"
#include "chrome/browser/printing/print_job_manager.h"
+#include "chrome/browser/printing/printing_ui_web_contents_observer.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_io_data.h"
#include "chrome/common/print_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_view.h"
#if defined(ENABLE_FULL_PRINTING)
#include "chrome/browser/ui/webui/print_preview/print_preview_ui.h"
@@ -30,6 +30,7 @@
#include "base/file_util.h"
#include "base/lazy_instance.h"
#include "chrome/browser/printing/print_dialog_cloud.h"
+#include "content/public/browser/web_contents_view.h"
#endif
#if defined(OS_ANDROID)
@@ -273,10 +274,12 @@ void PrintingMessageFilter::GetPrintSettingsForRenderView(
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
content::WebContents* wc = GetWebContentsForRenderView(render_view_id);
if (wc) {
+ scoped_ptr<PrintingUIWebContentsObserver> wc_observer(
+ new PrintingUIWebContentsObserver(wc));
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&printing::PrinterQuery::GetSettings, printer_query,
- params.ask_user_for_settings, wc->GetView()->GetNativeView(),
+ params.ask_user_for_settings, base::Passed(&wc_observer),
params.expected_page_count, params.has_selection,
params.margin_type, callback));
} else {
diff --git a/chrome/browser/printing/printing_ui_web_contents_observer.cc b/chrome/browser/printing/printing_ui_web_contents_observer.cc
new file mode 100644
index 0000000000..03a09f7009
--- /dev/null
+++ b/chrome/browser/printing/printing_ui_web_contents_observer.cc
@@ -0,0 +1,20 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/printing/printing_ui_web_contents_observer.h"
+
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_view.h"
+
+PrintingUIWebContentsObserver::PrintingUIWebContentsObserver(
+ content::WebContents* web_contents)
+ : content::WebContentsObserver(web_contents) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+}
+
+gfx::NativeView PrintingUIWebContentsObserver::GetParentView() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ return web_contents() ? web_contents()->GetView()->GetNativeView() : NULL;
+}
diff --git a/chrome/browser/printing/printing_ui_web_contents_observer.h b/chrome/browser/printing/printing_ui_web_contents_observer.h
new file mode 100644
index 0000000000..66d51e7fba
--- /dev/null
+++ b/chrome/browser/printing/printing_ui_web_contents_observer.h
@@ -0,0 +1,25 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_PRINTING_PRINTING_UI_WEB_CONTENTS_OBSERVER_H_
+#define CHROME_BROWSER_PRINTING_PRINTING_UI_WEB_CONTENTS_OBSERVER_H_
+
+#include "base/basictypes.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "ui/gfx/native_widget_types.h"
+
+// Wrapper used to keep track of the lifetime of a WebContents.
+// Lives on the UI thread.
+class PrintingUIWebContentsObserver : public content::WebContentsObserver {
+ public:
+ explicit PrintingUIWebContentsObserver(content::WebContents* web_contents);
+
+ // Return the parent NativeView of the observed WebContents.
+ gfx::NativeView GetParentView();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PrintingUIWebContentsObserver);
+};
+
+#endif // CHROME_BROWSER_PRINTING_PRINTING_UI_WEB_CONTENTS_OBSERVER_H_
diff --git a/chrome/browser/profile_resetter/profile_resetter_unittest.cc b/chrome/browser/profile_resetter/profile_resetter_unittest.cc
index a1aaf6bc05..44bdb2cdc8 100644
--- a/chrome/browser/profile_resetter/profile_resetter_unittest.cc
+++ b/chrome/browser/profile_resetter/profile_resetter_unittest.cc
@@ -42,7 +42,7 @@ const char kDistributionConfig[] = "{"
" },"
" \"session\" : {"
" \"restore_on_startup\" : 4,"
- " \"urls_to_restore_on_startup\" : [\"http://goo.gl\", \"http://foo.de\"]"
+ " \"startup_urls\" : [\"http://goo.gl\", \"http://foo.de\"]"
" },"
" \"search_provider_overrides\" : ["
" {"
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
index 4d3f8cac46..b19122c546 100644
--- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
+++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -33,6 +33,7 @@
#include "chrome/browser/prerender/prerender_manager_factory.h"
#include "chrome/browser/printing/cloud_print/cloud_print_proxy_service_factory.h"
#include "chrome/browser/profiles/gaia_info_update_service_factory.h"
+#include "chrome/browser/search/hotword_service_factory.h"
#include "chrome/browser/search/instant_service_factory.h"
#include "chrome/browser/search_engines/template_url_fetcher_factory.h"
#include "chrome/browser/search_engines/template_url_service_factory.h"
@@ -89,6 +90,7 @@
#include "chrome/browser/extensions/api/socket/tcp_socket.h"
#include "chrome/browser/extensions/api/socket/udp_socket.h"
#include "chrome/browser/extensions/api/sockets_tcp/tcp_socket_event_dispatcher.h"
+#include "chrome/browser/extensions/api/sockets_tcp_server/tcp_server_socket_event_dispatcher.h"
#include "chrome/browser/extensions/api/sockets_udp/udp_socket_event_dispatcher.h"
#include "chrome/browser/extensions/api/streams_private/streams_private_api.h"
#include "chrome/browser/extensions/api/system_info/system_info_api.h"
@@ -218,6 +220,8 @@ EnsureBrowserContextKeyedServiceFactoriesBuilt() {
extensions::ActivityLogFactory::GetInstance();
extensions::ActivityLogAPI::GetFactoryInstance();
extensions::AlarmManager::GetFactoryInstance();
+ extensions::ApiResourceManager<extensions::ResumableTCPServerSocket>::
+ GetFactoryInstance();
extensions::ApiResourceManager<extensions::ResumableTCPSocket>::
GetFactoryInstance();
extensions::ApiResourceManager<extensions::ResumableUDPSocket>::
@@ -227,6 +231,7 @@ EnsureBrowserContextKeyedServiceFactoriesBuilt() {
extensions::ApiResourceManager<extensions::Socket>::GetFactoryInstance();
extensions::ApiResourceManager<extensions::UsbDeviceResource>::
GetFactoryInstance();
+ extensions::api::TCPServerSocketEventDispatcher::GetFactoryInstance();
extensions::api::TCPSocketEventDispatcher::GetFactoryInstance();
extensions::api::UDPSocketEventDispatcher::GetFactoryInstance();
extensions::AudioAPI::GetFactoryInstance();
@@ -294,6 +299,7 @@ EnsureBrowserContextKeyedServiceFactoriesBuilt() {
GlobalErrorServiceFactory::GetInstance();
GoogleURLTrackerFactory::GetInstance();
HistoryServiceFactory::GetInstance();
+ HotwordServiceFactory::GetInstance();
invalidation::InvalidationServiceFactory::GetInstance();
InstantServiceFactory::GetInstance();
#if defined(ENABLE_MDNS)
diff --git a/chrome/browser/profiles/profile_browsertest.cc b/chrome/browser/profiles/profile_browsertest.cc
index 0386d22517..063c13e352 100644
--- a/chrome/browser/profiles/profile_browsertest.cc
+++ b/chrome/browser/profiles/profile_browsertest.cc
@@ -24,6 +24,7 @@ namespace {
class MockProfileDelegate : public Profile::Delegate {
public:
+ MOCK_METHOD1(OnPrefsLoaded, void(Profile*));
MOCK_METHOD3(OnProfileCreated, void(Profile*, bool, bool));
};
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index d761103407..9c9c1de725 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -408,16 +408,16 @@ ProfileImpl::ProfileImpl(
#if defined(OS_CHROMEOS)
cloud_policy_manager_ =
policy::UserCloudPolicyManagerFactoryChromeOS::CreateForProfile(
- this, force_immediate_policy_load);
+ this, force_immediate_policy_load, sequenced_task_runner);
#else
cloud_policy_manager_ =
policy::UserCloudPolicyManagerFactory::CreateForProfile(
- this, force_immediate_policy_load);
+ this, force_immediate_policy_load, sequenced_task_runner);
#endif
#endif
profile_policy_connector_ =
policy::ProfilePolicyConnectorFactory::CreateForProfile(
- this, force_immediate_policy_load, sequenced_task_runner);
+ this, force_immediate_policy_load);
DCHECK(create_mode == CREATE_MODE_ASYNCHRONOUS ||
create_mode == CREATE_MODE_SYNCHRONOUS);
@@ -492,6 +492,10 @@ void ProfileImpl::DoFinalInit() {
prefs::kProfileName,
base::Bind(&ProfileImpl::UpdateProfileNameCache,
base::Unretained(this)));
+ pref_change_registrar_.Add(
+ prefs::kForceEphemeralProfiles,
+ base::Bind(&ProfileImpl::UpdateProfileIsEphemeralCache,
+ base::Unretained(this)));
// It would be nice to use PathService for fetching this directory, but
// the cache directory depends on the profile directory, which isn't available
@@ -783,6 +787,8 @@ void ProfileImpl::OnPrefsLoaded(bool success) {
// TODO(sky): remove this in a couple of releases (m28ish).
prefs_->SetBoolean(prefs::kSessionExitedCleanly, true);
+ g_browser_process->profile_manager()->InitProfileUserPrefs(this);
+
BrowserContextDependencyManager::GetInstance()->CreateBrowserContextServices(
this);
@@ -1189,6 +1195,16 @@ void ProfileImpl::UpdateProfileAvatarCache() {
}
}
+void ProfileImpl::UpdateProfileIsEphemeralCache() {
+ ProfileManager* profile_manager = g_browser_process->profile_manager();
+ ProfileInfoCache& cache = profile_manager->GetProfileInfoCache();
+ size_t index = cache.GetIndexOfProfileWithPath(GetPath());
+ if (index != std::string::npos) {
+ bool is_ephemeral = GetPrefs()->GetBoolean(prefs::kForceEphemeralProfiles);
+ cache.SetProfileIsEphemeralAtIndex(index, is_ephemeral);
+ }
+}
+
// Gets the cache parameters from the command line. If |is_media_context| is
// set to true then settings for the media context type is what we need,
// |cache_path| will be set to the user provided path, or will not be touched if
diff --git a/chrome/browser/profiles/profile_impl.h b/chrome/browser/profiles/profile_impl.h
index 47fce06a89..1401d1b533 100644
--- a/chrome/browser/profiles/profile_impl.h
+++ b/chrome/browser/profiles/profile_impl.h
@@ -185,6 +185,7 @@ class ProfileImpl : public Profile {
// Updates the ProfileInfoCache with data from this profile.
void UpdateProfileNameCache();
void UpdateProfileAvatarCache();
+ void UpdateProfileIsEphemeralCache();
void GetCacheParameters(bool is_media_context,
base::FilePath* cache_path,
diff --git a/chrome/browser/profiles/profile_info_cache.cc b/chrome/browser/profiles/profile_info_cache.cc
index 1f38167439..f57205eb12 100644
--- a/chrome/browser/profiles/profile_info_cache.cc
+++ b/chrome/browser/profiles/profile_info_cache.cc
@@ -51,6 +51,7 @@ const char kGAIAPictureFileNameKey[] = "gaia_picture_file_name";
const char kIsManagedKey[] = "is_managed";
const char kSigninRequiredKey[] = "signin_required";
const char kManagedUserId[] = "managed_user_id";
+const char kProfileIsEphemeral[] = "is_ephemeral";
const char kDefaultUrlPrefix[] = "chrome://theme/IDR_PROFILE_AVATAR_";
const char kGAIAPictureFileName[] = "Google Profile Picture.png";
@@ -216,6 +217,7 @@ void ProfileInfoCache::AddProfileToCache(const base::FilePath& profile_path,
// Default value for whether background apps are running is false.
info->SetBoolean(kBackgroundAppsKey, false);
info->SetString(kManagedUserId, managed_user_id);
+ info->SetBoolean(kProfileIsEphemeral, false);
cache->SetWithoutPathExpansion(key, info.release());
sorted_keys_.insert(FindPositionForProfile(key, name), key);
@@ -404,6 +406,12 @@ std::string ProfileInfoCache::GetManagedUserIdOfProfileAtIndex(
return managed_user_id;
}
+bool ProfileInfoCache::ProfileIsEphemeralAtIndex(size_t index) const {
+ bool value = false;
+ GetInfoForProfileAtIndex(index)->GetBoolean(kProfileIsEphemeral, &value);
+ return value;
+}
+
void ProfileInfoCache::OnGAIAPictureLoaded(const base::FilePath& path,
gfx::Image** image) const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -667,6 +675,16 @@ void ProfileInfoCache::SetProfileSigninRequiredAtIndex(size_t index,
SetInfoForProfileAtIndex(index, info.release());
}
+void ProfileInfoCache::SetProfileIsEphemeralAtIndex(size_t index, bool value) {
+ if (value == ProfileIsEphemeralAtIndex(index))
+ return;
+
+ scoped_ptr<DictionaryValue> info(GetInfoForProfileAtIndex(index)->DeepCopy());
+ info->SetBoolean(kProfileIsEphemeral, value);
+ // This takes ownership of |info|.
+ SetInfoForProfileAtIndex(index, info.release());
+}
+
string16 ProfileInfoCache::ChooseNameForNewProfile(size_t icon_index) const {
string16 name;
for (int name_index = 1; ; ++name_index) {
diff --git a/chrome/browser/profiles/profile_info_cache.h b/chrome/browser/profiles/profile_info_cache.h
index aeb48420bd..bf6cabe51c 100644
--- a/chrome/browser/profiles/profile_info_cache.h
+++ b/chrome/browser/profiles/profile_info_cache.h
@@ -80,6 +80,7 @@ class ProfileInfoCache : public ProfileInfoInterface,
virtual bool ProfileIsSigninRequiredAtIndex(size_t index) const OVERRIDE;
virtual std::string GetManagedUserIdOfProfileAtIndex(size_t index) const
OVERRIDE;
+ virtual bool ProfileIsEphemeralAtIndex(size_t index) const OVERRIDE;
size_t GetAvatarIconIndexOfProfileAtIndex(size_t index) const;
@@ -96,6 +97,7 @@ class ProfileInfoCache : public ProfileInfoInterface,
void SetGAIAPictureOfProfileAtIndex(size_t index, const gfx::Image* image);
void SetIsUsingGAIAPictureOfProfileAtIndex(size_t index, bool value);
void SetProfileSigninRequiredAtIndex(size_t index, bool value);
+ void SetProfileIsEphemeralAtIndex(size_t index, bool value);
// Returns unique name that can be assigned to a newly created profile.
string16 ChooseNameForNewProfile(size_t icon_index) const;
diff --git a/chrome/browser/profiles/profile_info_cache_unittest.cc b/chrome/browser/profiles/profile_info_cache_unittest.cc
index 1d5e6df7d0..1a6e089af5 100644
--- a/chrome/browser/profiles/profile_info_cache_unittest.cc
+++ b/chrome/browser/profiles/profile_info_cache_unittest.cc
@@ -18,6 +18,7 @@
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/notification_service.h"
+#include "content/public/test/test_browser_thread_bundle.h"
#include "content/public/test/test_utils.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/resource/resource_bundle.h"
@@ -459,6 +460,11 @@ TEST_F(ProfileInfoCacheTest, CreateManagedTestingProfile) {
std::string managed_user_id = is_managed ? "TEST_ID" : "";
EXPECT_EQ(managed_user_id, GetCache()->GetManagedUserIdOfProfileAtIndex(i));
}
+
+ // Managed profiles have a custom theme, which needs to be deleted on the FILE
+ // thread. Reset the profile manager now so everything is deleted while we
+ // still have a FILE thread.
+ TestingBrowserProcess::GetGlobal()->SetProfileManager(NULL);
}
TEST_F(ProfileInfoCacheTest, AddStubProfile) {
diff --git a/chrome/browser/profiles/profile_info_interface.h b/chrome/browser/profiles/profile_info_interface.h
index b359a86fbc..85d9e7eef5 100644
--- a/chrome/browser/profiles/profile_info_interface.h
+++ b/chrome/browser/profiles/profile_info_interface.h
@@ -58,6 +58,9 @@ class ProfileInfoInterface {
// This profile is associated with an account but has been signed-out.
virtual bool ProfileIsSigninRequiredAtIndex(size_t index) const = 0;
+ // Profile is known to be ephemeral and should be deleted when closed.
+ virtual bool ProfileIsEphemeralAtIndex(size_t index) const = 0;
+
protected:
virtual ~ProfileInfoInterface() {}
};
diff --git a/chrome/browser/profiles/profile_info_util.cc b/chrome/browser/profiles/profile_info_util.cc
index 1f56b3d552..0f8b1e5f85 100644
--- a/chrome/browser/profiles/profile_info_util.cc
+++ b/chrome/browser/profiles/profile_info_util.cc
@@ -4,15 +4,154 @@
#include "chrome/browser/profiles/profile_info_util.h"
-#include "skia/ext/image_operations.h"
+#include "base/memory/scoped_ptr.h"
+#include "third_party/skia/include/core/SkPaint.h"
+#include "third_party/skia/include/core/SkPath.h"
+#include "third_party/skia/include/core/SkScalar.h"
+#include "third_party/skia/include/core/SkXfermode.h"
#include "ui/gfx/canvas.h"
-#include "ui/gfx/rect.h"
+#include "ui/gfx/image/canvas_image_source.h"
+#include "ui/gfx/image/image_skia_operations.h"
namespace profiles {
const int kAvatarIconWidth = 38;
const int kAvatarIconHeight = 31;
-const int kAvatarIconBorder = 2;
+const int kAvatarIconPadding = 2;
+
+namespace internal {
+
+// A CanvasImageSource that draws a sized and positioned avatar with an
+// optional border independently of the scale factor.
+class AvatarImageSource : public gfx::CanvasImageSource {
+ public:
+ enum AvatarPosition {
+ POSITION_CENTER,
+ POSITION_BOTTOM_CENTER,
+ };
+
+ enum AvatarBorder {
+ BORDER_NONE,
+ BORDER_NORMAL,
+ BORDER_ETCHED,
+ };
+
+ AvatarImageSource(gfx::ImageSkia avatar,
+ const gfx::Size& canvas_size,
+ int size,
+ AvatarPosition position,
+ AvatarBorder border);
+ virtual ~AvatarImageSource();
+
+ // CanvasImageSource override:
+ virtual void Draw(gfx::Canvas* canvas) OVERRIDE;
+
+ private:
+ gfx::ImageSkia avatar_;
+ const gfx::Size canvas_size_;
+ const int size_;
+ const AvatarPosition position_;
+ const AvatarBorder border_;
+
+ DISALLOW_COPY_AND_ASSIGN(AvatarImageSource);
+};
+
+AvatarImageSource::AvatarImageSource(gfx::ImageSkia avatar,
+ const gfx::Size& canvas_size,
+ int size,
+ AvatarPosition position,
+ AvatarBorder border)
+ : gfx::CanvasImageSource(canvas_size, false),
+ canvas_size_(canvas_size),
+ size_(size - kAvatarIconPadding),
+ position_(position),
+ border_(border) {
+ // Resize the avatar to the desired square size.
+ avatar_ = gfx::ImageSkiaOperations::CreateResizedImage(
+ avatar, skia::ImageOperations::RESIZE_BEST, gfx::Size(size_, size_));
+}
+
+AvatarImageSource::~AvatarImageSource() {
+}
+
+void AvatarImageSource::Draw(gfx::Canvas* canvas) {
+ // Center the avatar horizontally.
+ int x = (canvas_size_.width() - size_) / 2;
+ int y;
+
+ if (position_ == POSITION_CENTER) {
+ // Draw the avatar centered on the canvas.
+ y = (canvas_size_.height() - size_) / 2;
+ } else {
+ // Draw the avatar on the bottom center of the canvas, leaving 1px below.
+ y = canvas_size_.height() - size_ - 1;
+ }
+
+ canvas->DrawImageInt(avatar_, x, y);
+
+ if (border_ == BORDER_NORMAL) {
+ // Draw a gray border on the inside of the avatar.
+ SkColor border_color = SkColorSetARGB(83, 0, 0, 0);
+
+ // Offset the rectangle by a half pixel so the border is drawn within the
+ // appropriate pixels no matter the scale factor. Subtract 1 from the right
+ // and bottom sizes to specify the endpoints, yielding -0.5.
+ SkPath path;
+ path.addRect(SkFloatToScalar(x + 0.5f), // left
+ SkFloatToScalar(y + 0.5f), // top
+ SkFloatToScalar(x + size_ - 0.5f), // right
+ SkFloatToScalar(y + size_ - 0.5f)); // bottom
+
+ SkPaint paint;
+ paint.setColor(border_color);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(SkIntToScalar(1));
+
+ canvas->DrawPath(path, paint);
+ } else if (border_ == BORDER_ETCHED) {
+ // Give the avatar an etched look by drawing a highlight on the bottom and
+ // right edges.
+ SkColor shadow_color = SkColorSetARGB(83, 0, 0, 0);
+ SkColor highlight_color = SkColorSetARGB(96, 255, 255, 255);
+
+ SkPaint paint;
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(SkIntToScalar(1));
+
+ SkPath path;
+
+ // Left and top shadows. To support higher scale factors than 1, position
+ // the orthogonal dimension of each line on the half-pixel to separate the
+ // pixel. For a vertical line, this means adding 0.5 to the x-value.
+ path.moveTo(SkFloatToScalar(x + 0.5f), SkIntToScalar(y + size_));
+
+ // Draw up to the top-left. Stop with the y-value at a half-pixel.
+ path.rLineTo(SkIntToScalar(0), SkFloatToScalar(-size_ + 0.5f));
+
+ // Draw right to the top-right, stopping within the last pixel.
+ path.rLineTo(SkFloatToScalar(size_ - 0.5f), SkIntToScalar(0));
+
+ paint.setColor(shadow_color);
+ canvas->DrawPath(path, paint);
+
+ path.reset();
+
+ // Bottom and right highlights. Note that the shadows own the shared corner
+ // pixels, so reduce the sizes accordingly.
+ path.moveTo(SkIntToScalar(x + 1), SkFloatToScalar(y + size_ - 0.5f));
+
+ // Draw right to the bottom-right.
+ path.rLineTo(SkFloatToScalar(size_ - 1.5f), SkIntToScalar(0));
+
+ // Draw up to the top-right.
+ path.rLineTo(SkIntToScalar(0), SkFloatToScalar(-size_ + 1.5f));
+
+ paint.setColor(highlight_color);
+ canvas->DrawPath(path, paint);
+ }
+}
+
+} // namespace internal
gfx::Image GetSizedAvatarIconWithBorder(const gfx::Image& image,
bool is_rectangle,
@@ -20,21 +159,18 @@ gfx::Image GetSizedAvatarIconWithBorder(const gfx::Image& image,
if (!is_rectangle)
return image;
- int length = std::min(width, height) - kAvatarIconBorder;
- SkBitmap bmp = skia::ImageOperations::Resize(
- *image.ToSkBitmap(), skia::ImageOperations::RESIZE_BEST, length, length);
- gfx::Canvas canvas(gfx::Size(width, height), 1.0f, false);
-
- // Draw the icon centered on the canvas.
- int x = (width - length) / 2;
- int y = (height - length) / 2;
- canvas.DrawImageInt(gfx::ImageSkia::CreateFrom1xBitmap(bmp), x, y);
+ gfx::Size size(width, height);
- // Draw a gray border on the inside of the icon.
- SkColor color = SkColorSetARGB(83, 0, 0, 0);
- canvas.DrawRect(gfx::Rect(x, y, length - 1, length - 1), color);
+ // Source for a centered, sized icon with a border.
+ scoped_ptr<gfx::ImageSkiaSource> source(
+ new internal::AvatarImageSource(
+ *image.ToImageSkia(),
+ size,
+ std::min(width, height),
+ internal::AvatarImageSource::POSITION_CENTER,
+ internal::AvatarImageSource::BORDER_NORMAL));
- return gfx::Image(gfx::ImageSkia(canvas.ExtractImageRep()));
+ return gfx::Image(gfx::ImageSkia(source.release(), size));
}
gfx::Image GetAvatarIconForMenu(const gfx::Image& image,
@@ -48,19 +184,18 @@ gfx::Image GetAvatarIconForWebUI(const gfx::Image& image,
if (!is_rectangle)
return image;
- int length =
- std::min(kAvatarIconWidth, kAvatarIconHeight) - kAvatarIconBorder;
- SkBitmap bmp = skia::ImageOperations::Resize(
- *image.ToSkBitmap(), skia::ImageOperations::RESIZE_BEST, length, length);
- gfx::Canvas canvas(
- gfx::Size(kAvatarIconWidth, kAvatarIconHeight), 1.0f, false);
+ gfx::Size size(kAvatarIconWidth, kAvatarIconHeight);
- // Draw the icon centered on the canvas.
- int x = (kAvatarIconWidth - length) / 2;
- int y = (kAvatarIconHeight - length) / 2;
- canvas.DrawImageInt(gfx::ImageSkia::CreateFrom1xBitmap(bmp), x, y);
+ // Source for a centered, sized icon.
+ scoped_ptr<gfx::ImageSkiaSource> source(
+ new internal::AvatarImageSource(
+ *image.ToImageSkia(),
+ size,
+ std::min(kAvatarIconWidth, kAvatarIconHeight),
+ internal::AvatarImageSource::POSITION_CENTER,
+ internal::AvatarImageSource::BORDER_NONE));
- return gfx::Image(gfx::ImageSkia(canvas.ExtractImageRep()));
+ return gfx::Image(gfx::ImageSkia(source.release(), size));
}
gfx::Image GetAvatarIconForTitleBar(const gfx::Image& image,
@@ -70,35 +205,21 @@ gfx::Image GetAvatarIconForTitleBar(const gfx::Image& image,
if (!is_rectangle)
return image;
- int length = std::min(std::min(kAvatarIconWidth, kAvatarIconHeight),
- std::min(dst_width, dst_height)) - kAvatarIconBorder;
- SkBitmap bmp = skia::ImageOperations::Resize(
- *image.ToSkBitmap(), skia::ImageOperations::RESIZE_BEST, length, length);
- gfx::Canvas canvas(gfx::Size(dst_width, dst_height), 1.0f, false);
-
- // Draw the icon on the bottom center of the canvas.
- int x1 = (dst_width - length) / 2;
- int x2 = x1 + length;
- int y1 = dst_height - length - 1;
- int y2 = y1 + length;
- canvas.DrawImageInt(gfx::ImageSkia::CreateFrom1xBitmap(bmp), x1, y1);
-
- // Give the icon an etched look by drawing a highlight on the bottom edge
- // and a shadow on the remaining edges.
- SkColor highlight_color = SkColorSetARGB(128, 255, 255, 255);
- SkColor shadow_color = SkColorSetARGB(83, 0, 0, 0);
- // Bottom highlight.
- canvas.DrawLine(gfx::Point(x1, y2 - 1), gfx::Point(x2, y2 - 1),
- highlight_color);
- // Top shadow.
- canvas.DrawLine(gfx::Point(x1, y1), gfx::Point(x2, y1), shadow_color);
- // Left shadow.
- canvas.DrawLine(gfx::Point(x1, y1 + 1), gfx::Point(x1, y2 - 1), shadow_color);
- // Right shadow.
- canvas.DrawLine(gfx::Point(x2 - 1, y1 + 1), gfx::Point(x2 - 1, y2 - 1),
- shadow_color);
-
- return gfx::Image(gfx::ImageSkia(canvas.ExtractImageRep()));
+ int size = std::min(std::min(kAvatarIconWidth, kAvatarIconHeight),
+ std::min(dst_width, dst_height));
+ gfx::Size dst_size(dst_width, dst_height);
+
+ // Source for a sized icon drawn at the bottom center of the canvas,
+ // with an etched border.
+ scoped_ptr<gfx::ImageSkiaSource> source(
+ new internal::AvatarImageSource(
+ *image.ToImageSkia(),
+ dst_size,
+ size,
+ internal::AvatarImageSource::POSITION_BOTTOM_CENTER,
+ internal::AvatarImageSource::BORDER_ETCHED));
+
+ return gfx::Image(gfx::ImageSkia(source.release(), dst_size));
}
} // namespace profiles
diff --git a/chrome/browser/profiles/profile_info_util.h b/chrome/browser/profiles/profile_info_util.h
index da04a11fb0..ce1b78e4ee 100644
--- a/chrome/browser/profiles/profile_info_util.h
+++ b/chrome/browser/profiles/profile_info_util.h
@@ -11,7 +11,7 @@ namespace profiles {
extern const int kAvatarIconWidth;
extern const int kAvatarIconHeight;
-extern const int kAvatarIconBorder;
+extern const int kAvatarIconPadding;
// Returns a version of |image| of a specific size and with a grey border.
// Note that no checks are done on the width/height so make sure they're
diff --git a/chrome/browser/profiles/profile_info_util_unittest.cc b/chrome/browser/profiles/profile_info_util_unittest.cc
index 47020ff873..786e5b7bd0 100644
--- a/chrome/browser/profiles/profile_info_util_unittest.cc
+++ b/chrome/browser/profiles/profile_info_util_unittest.cc
@@ -8,25 +8,50 @@
#include "grit/theme_resources.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/image/image_skia_rep.h"
#include "ui/gfx/image/image_unittest_util.h"
namespace {
+// Helper function to check that the image is sized properly
+// and supports multiple pixel densities.
+void VerifyScaling(gfx::Image& image, gfx::Size& size) {
+ gfx::Size canvas_size(100, 100);
+ gfx::Canvas canvas(canvas_size, 1.0f, false);
+ gfx::Canvas canvas2(canvas_size, 2.0f, false);
+
+ ASSERT_FALSE(gfx::test::IsEmpty(image));
+ EXPECT_EQ(image.Size(), size);
+
+ gfx::ImageSkia image_skia = *image.ToImageSkia();
+ canvas.DrawImageInt(image_skia, 15, 10);
+ EXPECT_TRUE(image.ToImageSkia()->HasRepresentation(1.0f));
+
+ canvas2.DrawImageInt(image_skia, 15, 10);
+ EXPECT_TRUE(image.ToImageSkia()->HasRepresentation(2.0f));
+}
+
TEST(ProfileInfoUtilTest, SizedMenuIcon) {
// Test that an avatar icon isn't changed.
const gfx::Image& profile_image(
ResourceBundle::GetSharedInstance().GetImageNamed(IDR_PROFILE_AVATAR_0));
gfx::Image result =
profiles::GetSizedAvatarIconWithBorder(profile_image, false, 50, 50);
+
EXPECT_FALSE(gfx::test::IsEmpty(result));
EXPECT_TRUE(gfx::test::IsEqual(profile_image, result));
// Test that a rectangular picture (e.g., GAIA image) is changed.
gfx::Image rect_picture(gfx::test::CreateImage());
+
+ gfx::Size size(30, 20);
gfx::Image result2 =
- profiles::GetSizedAvatarIconWithBorder(rect_picture, true, 50, 50);
- EXPECT_FALSE(gfx::test::IsEmpty(result2));
- EXPECT_FALSE(gfx::test::IsEqual(rect_picture, result2));
+ profiles::GetSizedAvatarIconWithBorder(
+ rect_picture, true, size.width(), size.height());
+
+ VerifyScaling(result2, size);
}
TEST(ProfileInfoUtilTest, MenuIcon) {
@@ -39,9 +64,10 @@ TEST(ProfileInfoUtilTest, MenuIcon) {
// Test that a rectangular picture is changed.
gfx::Image rect_picture(gfx::test::CreateImage());
+ gfx::Size size(profiles::kAvatarIconWidth, profiles::kAvatarIconHeight);
gfx::Image result2 = profiles::GetAvatarIconForMenu(rect_picture, true);
- EXPECT_FALSE(gfx::test::IsEmpty(result2));
- EXPECT_FALSE(gfx::test::IsEqual(rect_picture, result2));
+
+ VerifyScaling(result2, size);
}
TEST(ProfileInfoUtilTest, WebUIIcon) {
@@ -54,26 +80,32 @@ TEST(ProfileInfoUtilTest, WebUIIcon) {
// Test that a rectangular picture is changed.
gfx::Image rect_picture(gfx::test::CreateImage());
+ gfx::Size size(profiles::kAvatarIconWidth, profiles::kAvatarIconHeight);
gfx::Image result2 = profiles::GetAvatarIconForWebUI(rect_picture, true);
- EXPECT_FALSE(gfx::test::IsEmpty(result2));
- EXPECT_FALSE(gfx::test::IsEqual(rect_picture, result2));
+
+ VerifyScaling(result2, size);
}
TEST(ProfileInfoUtilTest, TitleBarIcon) {
+ int width = 100;
+ int height = 40;
+
// Test that an avatar icon isn't changed.
const gfx::Image& profile_image(
ResourceBundle::GetSharedInstance().GetImageNamed(IDR_PROFILE_AVATAR_0));
gfx::Image result = profiles::GetAvatarIconForTitleBar(
- profile_image, false, 100, 40);
+ profile_image, false, width, height);
EXPECT_FALSE(gfx::test::IsEmpty(result));
EXPECT_TRUE(gfx::test::IsEqual(profile_image, result));
// Test that a rectangular picture is changed.
gfx::Image rect_picture(gfx::test::CreateImage());
+
+ gfx::Size size(width, height);
gfx::Image result2 = profiles::GetAvatarIconForTitleBar(
- rect_picture, true, 100, 40);
- EXPECT_FALSE(gfx::test::IsEmpty(result2));
- EXPECT_FALSE(gfx::test::IsEqual(rect_picture, result2));
+ rect_picture, true, width, height);
+
+ VerifyScaling(result2, size);
}
} // namespace
diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc
index 5256afc691..43ca4f9008 100644
--- a/chrome/browser/profiles/profile_manager.cc
+++ b/chrome/browser/profiles/profile_manager.cc
@@ -552,6 +552,7 @@ bool ProfileManager::AddProfile(Profile* profile) {
}
RegisterProfile(profile, true);
+ InitProfileUserPrefs(profile);
DoFinalInit(profile, ShouldGoOffTheRecord(profile));
return true;
}
@@ -623,7 +624,10 @@ void ProfileManager::Observe(
DCHECK(browser);
Profile* profile = browser->profile();
DCHECK(profile);
- if (!profile->IsOffTheRecord() && ++browser_counts_[profile] == 1) {
+ bool is_ephemeral =
+ profile->GetPrefs()->GetBoolean(prefs::kForceEphemeralProfiles);
+ if (!profile->IsOffTheRecord() && !is_ephemeral &&
+ ++browser_counts_[profile] == 1) {
active_profiles_.push_back(profile);
save_active_profiles = true;
}
@@ -719,6 +723,12 @@ void ProfileManager::BrowserListObserver::OnBrowserSetLastActive(
return;
Profile* last_active = browser->profile();
+
+ // Don't remember ephemeral profiles as last because they are not going to
+ // persist after restart.
+ if (last_active->GetPrefs()->GetBoolean(prefs::kForceEphemeralProfiles))
+ return;
+
PrefService* local_state = g_browser_process->local_state();
DCHECK(local_state);
// Only keep track of profiles that we are managing; tests may create others.
@@ -731,7 +741,6 @@ void ProfileManager::BrowserListObserver::OnBrowserSetLastActive(
#endif // !defined(OS_ANDROID) && !defined(OS_IOS)
void ProfileManager::DoFinalInit(Profile* profile, bool go_off_the_record) {
- InitProfileUserPrefs(profile);
DoFinalInitForServices(profile, go_off_the_record);
AddProfileToCache(profile);
DoFinalInitLogging(profile);
@@ -1013,8 +1022,14 @@ void ProfileManager::InitProfileUserPrefs(Profile* profile) {
if (!profile->GetPrefs()->HasPrefPath(prefs::kProfileName))
profile->GetPrefs()->SetString(prefs::kProfileName, profile_name);
- if (!profile->GetPrefs()->HasPrefPath(prefs::kManagedUserId))
+ if (!profile->GetPrefs()->HasPrefPath(prefs::kManagedUserId)) {
+ if (managed_user_id.empty() &&
+ CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kNewProfileIsSupervised)) {
+ managed_user_id = "Test ID";
+ }
profile->GetPrefs()->SetString(prefs::kManagedUserId, managed_user_id);
+ }
}
void ProfileManager::SetGuestProfilePrefs(Profile* profile) {
diff --git a/chrome/browser/profiles/profile_manager.h b/chrome/browser/profiles/profile_manager.h
index f84ac9565f..a8674de09b 100644
--- a/chrome/browser/profiles/profile_manager.h
+++ b/chrome/browser/profiles/profile_manager.h
@@ -193,6 +193,10 @@ class ProfileManager : public base::NonThreadSafe,
// Sign-Out a profile against use until re-authentication.
void SignOutProfile(Profile* profile);
+ // Initializes user prefs of |profile|. This includes profile name and
+ // avatar values.
+ void InitProfileUserPrefs(Profile* profile);
+
// Register and add testing profile to the ProfileManager. Use ONLY in tests.
// This allows the creation of Profiles outside of the standard creation path
// for testing. If |addToCache|, adds to ProfileInfoCache as well.
@@ -277,10 +281,6 @@ class ProfileManager : public base::NonThreadSafe,
// Adds |profile| to the profile info cache if it hasn't been added yet.
void AddProfileToCache(Profile* profile);
- // Initializes user prefs of |profile|. This includes profile name and
- // avatar values
- void InitProfileUserPrefs(Profile* profile);
-
// Apply settings for (desktop) Guest User profile.
void SetGuestProfilePrefs(Profile* profile);
diff --git a/chrome/browser/profiles/profile_manager_unittest.cc b/chrome/browser/profiles/profile_manager_unittest.cc
index 87dd48894c..de575a98b7 100644
--- a/chrome/browser/profiles/profile_manager_unittest.cc
+++ b/chrome/browser/profiles/profile_manager_unittest.cc
@@ -620,6 +620,85 @@ TEST_F(ProfileManagerTest, LastOpenedProfilesDoesNotContainIncognito) {
#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
// There's no Browser object on Android and there's no multi-profiles on Chrome.
+TEST_F(ProfileManagerTest, EphemeralProfilesDontEndUpAsLastProfile) {
+ base::FilePath dest_path = temp_dir_.path();
+ dest_path = dest_path.Append(FILE_PATH_LITERAL("Ephemeral Profile"));
+
+ ProfileManager* profile_manager = g_browser_process->profile_manager();
+
+ TestingProfile* profile =
+ static_cast<TestingProfile*>(profile_manager->GetProfile(dest_path));
+ ASSERT_TRUE(profile);
+ profile->GetPrefs()->SetBoolean(prefs::kForceEphemeralProfiles, true);
+
+ // Here the last used profile is still the "Default" profile.
+ Profile* last_used_profile = profile_manager->GetLastUsedProfile();
+ EXPECT_NE(profile, last_used_profile);
+
+ // Create a browser for profile2.
+ Browser::CreateParams profile_params(profile, chrome::GetActiveDesktop());
+ scoped_ptr<Browser> browser(
+ chrome::CreateBrowserWithTestWindowForParams(&profile_params));
+ last_used_profile = profile_manager->GetLastUsedProfile();
+ EXPECT_NE(profile, last_used_profile);
+
+ // Close the browser.
+ browser.reset();
+ last_used_profile = profile_manager->GetLastUsedProfile();
+ EXPECT_NE(profile, last_used_profile);
+}
+
+TEST_F(ProfileManagerTest, EphemeralProfilesDontEndUpAsLastOpenedAtShutdown) {
+ base::FilePath dest_path1 = temp_dir_.path();
+ dest_path1 = dest_path1.Append(FILE_PATH_LITERAL("Normal Profile"));
+
+ base::FilePath dest_path2 = temp_dir_.path();
+ dest_path2 = dest_path2.Append(FILE_PATH_LITERAL("Ephemeral Profile"));
+
+ ProfileManager* profile_manager = g_browser_process->profile_manager();
+
+ // Successfully create the profiles.
+ TestingProfile* normal_profile =
+ static_cast<TestingProfile*>(profile_manager->GetProfile(dest_path1));
+ ASSERT_TRUE(normal_profile);
+
+ // Add one ephemeral profile which should not end up in this list.
+ TestingProfile* ephemeral_profile =
+ static_cast<TestingProfile*>(profile_manager->GetProfile(dest_path2));
+ ASSERT_TRUE(ephemeral_profile);
+ ephemeral_profile->GetPrefs()->SetBoolean(prefs::kForceEphemeralProfiles,
+ true);
+
+ // Create a browser for profile1.
+ Browser::CreateParams profile1_params(normal_profile,
+ chrome::GetActiveDesktop());
+ scoped_ptr<Browser> browser1(
+ chrome::CreateBrowserWithTestWindowForParams(&profile1_params));
+
+ // Create a browser for the ephemeral profile.
+ Browser::CreateParams profile2_params(ephemeral_profile,
+ chrome::GetActiveDesktop());
+ scoped_ptr<Browser> browser2(
+ chrome::CreateBrowserWithTestWindowForParams(&profile2_params));
+
+ std::vector<Profile*> last_opened_profiles =
+ profile_manager->GetLastOpenedProfiles();
+ ASSERT_EQ(1U, last_opened_profiles.size());
+ EXPECT_EQ(normal_profile, last_opened_profiles[0]);
+
+ // Simulate a shutdown.
+ content::NotificationService::current()->Notify(
+ chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST,
+ content::NotificationService::AllSources(),
+ content::NotificationService::NoDetails());
+ browser1.reset();
+ browser2.reset();
+
+ last_opened_profiles = profile_manager->GetLastOpenedProfiles();
+ ASSERT_EQ(1U, last_opened_profiles.size());
+ EXPECT_EQ(normal_profile, last_opened_profiles[0]);
+}
+
TEST_F(ProfileManagerTest, ActiveProfileDeleted) {
ProfileManager* profile_manager = g_browser_process->profile_manager();
ASSERT_TRUE(profile_manager);
diff --git a/chrome/browser/profiles/profiles_state.cc b/chrome/browser/profiles/profiles_state.cc
index 72e1295ba8..316527136f 100644
--- a/chrome/browser/profiles/profiles_state.cc
+++ b/chrome/browser/profiles/profiles_state.cc
@@ -7,9 +7,16 @@
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/prefs/pref_registry_simple.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_info_cache.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
+#include "grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/login/user_manager.h"
@@ -33,8 +40,7 @@ bool IsNewProfileManagementEnabled() {
switches::kNewProfileManagement);
}
-base::FilePath GetDefaultProfileDir(
- const base::FilePath& user_data_dir) {
+base::FilePath GetDefaultProfileDir(const base::FilePath& user_data_dir) {
base::FilePath default_profile_dir(user_data_dir);
default_profile_dir =
default_profile_dir.AppendASCII(chrome::kInitialProfile);
@@ -54,4 +60,20 @@ void RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterListPref(prefs::kProfilesLastActive);
}
+string16 GetActiveProfileDisplayName(Browser* browser) {
+ string16 profile_name;
+ Profile* profile = browser->profile();
+
+ if (profile->IsGuestSession()) {
+ profile_name = l10n_util::GetStringUTF16(IDS_GUEST_PROFILE_NAME);
+ } else {
+ ProfileInfoCache& cache =
+ g_browser_process->profile_manager()->GetProfileInfoCache();
+ size_t index = cache.GetIndexOfProfileWithPath(profile->GetPath());
+ if (index != std::string::npos)
+ profile_name = cache.GetNameOfProfileAtIndex(index);
+ }
+ return profile_name;
+}
+
} // namespace profiles
diff --git a/chrome/browser/profiles/profiles_state.h b/chrome/browser/profiles/profiles_state.h
index 2858e62cdb..3f6debcf00 100644
--- a/chrome/browser/profiles/profiles_state.h
+++ b/chrome/browser/profiles/profiles_state.h
@@ -5,6 +5,9 @@
#ifndef CHROME_BROWSER_PROFILES_PROFILES_STATE_H_
#define CHROME_BROWSER_PROFILES_PROFILES_STATE_H_
+#include "base/strings/string16.h"
+
+class Browser;
class PrefRegistrySimple;
namespace base { class FilePath; }
@@ -26,6 +29,9 @@ base::FilePath GetProfilePrefsPath(const base::FilePath& profile_dir);
// Register multi-profile related preferences in Local State.
void RegisterPrefs(PrefRegistrySimple* registry);
+// Returns the display name of the active on-the-record profile (or guest).
+string16 GetActiveProfileDisplayName(Browser* browser);
+
} // namespace profiles
#endif // CHROME_BROWSER_PROFILES_PROFILES_STATE_H_
diff --git a/chrome/browser/renderer_host/chrome_render_view_host_observer.cc b/chrome/browser/renderer_host/chrome_render_view_host_observer.cc
deleted file mode 100644
index 2a6f67a7fe..0000000000
--- a/chrome/browser/renderer_host/chrome_render_view_host_observer.cc
+++ /dev/null
@@ -1,250 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/renderer_host/chrome_render_view_host_observer.h"
-
-#include <vector>
-
-#include "base/command_line.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_system.h"
-#include "chrome/browser/net/predictor.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/search_engines/search_terms_data.h"
-#include "chrome/browser/search_engines/template_url.h"
-#include "chrome/browser/search_engines/template_url_service.h"
-#include "chrome/browser/search_engines/template_url_service_factory.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_messages.h"
-#include "chrome/common/render_messages.h"
-#include "chrome/common/url_constants.h"
-#include "content/public/browser/child_process_security_policy.h"
-#include "content/public/browser/page_navigator.h"
-#include "content/public/browser/render_process_host.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/site_instance.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/common/page_transition_types.h"
-#include "extensions/common/constants.h"
-#include "extensions/common/manifest.h"
-#include "net/http/http_request_headers.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/base/window_open_disposition.h"
-#include "ui/gfx/codec/jpeg_codec.h"
-#include "ui/gfx/size.h"
-
-#if defined(OS_WIN)
-#include "base/win/win_util.h"
-#endif // OS_WIN
-
-using content::ChildProcessSecurityPolicy;
-using content::OpenURLParams;
-using content::RenderViewHost;
-using content::SiteInstance;
-using content::WebContents;
-using extensions::Extension;
-using extensions::Manifest;
-
-ChromeRenderViewHostObserver::ChromeRenderViewHostObserver(
- RenderViewHost* render_view_host, chrome_browser_net::Predictor* predictor)
- : content::RenderViewHostObserver(render_view_host),
- predictor_(predictor) {
- SiteInstance* site_instance = render_view_host->GetSiteInstance();
- profile_ = Profile::FromBrowserContext(
- site_instance->GetBrowserContext());
-
- InitRenderViewForExtensions();
-}
-
-ChromeRenderViewHostObserver::~ChromeRenderViewHostObserver() {
- if (render_view_host())
- RemoveRenderViewHostForExtensions(render_view_host());
-}
-
-void ChromeRenderViewHostObserver::RenderViewHostInitialized() {
- // This reinitializes some state in the case where a render process crashes
- // but we keep the same RenderViewHost instance.
- InitRenderViewForExtensions();
-}
-
-void ChromeRenderViewHostObserver::RenderViewHostDestroyed(
- RenderViewHost* rvh) {
- RemoveRenderViewHostForExtensions(rvh);
- delete this;
-}
-
-void ChromeRenderViewHostObserver::Navigate(const GURL& url) {
- if (!predictor_)
- return;
- if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kChromeFrame) &&
- (url.SchemeIs(content::kHttpScheme) ||
- url.SchemeIs(content::kHttpsScheme)))
- predictor_->PreconnectUrlAndSubresources(url, GURL());
-}
-
-bool ChromeRenderViewHostObserver::OnMessageReceived(
- const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(ChromeRenderViewHostObserver, message)
- IPC_MESSAGE_HANDLER(ChromeViewHostMsg_FocusedNodeTouched,
- OnFocusedNodeTouched)
- IPC_MESSAGE_HANDLER(ChromeViewHostMsg_RequestThumbnailForContextNode_ACK,
- OnRequestThumbnailForContextNodeACK)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-void ChromeRenderViewHostObserver::InitRenderViewForExtensions() {
- const Extension* extension = GetExtension();
- if (!extension)
- return;
-
- content::RenderProcessHost* process = render_view_host()->GetProcess();
-
- // Some extensions use chrome:// URLs.
- // This is a temporary solution. Replace it with access to chrome-static://
- // once it is implemented. See: crbug.com/226927.
- Manifest::Type type = extension->GetType();
- if (type == Manifest::TYPE_EXTENSION ||
- type == Manifest::TYPE_LEGACY_PACKAGED_APP ||
- (type == Manifest::TYPE_PLATFORM_APP &&
- extension->location() == Manifest::COMPONENT)) {
- ChildProcessSecurityPolicy::GetInstance()->GrantScheme(
- process->GetID(), chrome::kChromeUIScheme);
- }
-
- // Some extensions use file:// URLs.
- if (type == Manifest::TYPE_EXTENSION ||
- type == Manifest::TYPE_LEGACY_PACKAGED_APP) {
- if (extensions::ExtensionSystem::Get(profile_)->extension_service()->
- extension_prefs()->AllowFileAccess(extension->id())) {
- ChildProcessSecurityPolicy::GetInstance()->GrantScheme(
- process->GetID(), chrome::kFileScheme);
- }
- }
-
- switch (type) {
- case Manifest::TYPE_EXTENSION:
- case Manifest::TYPE_USER_SCRIPT:
- case Manifest::TYPE_HOSTED_APP:
- case Manifest::TYPE_LEGACY_PACKAGED_APP:
- case Manifest::TYPE_PLATFORM_APP:
- // Always send a Loaded message before ActivateExtension so that
- // ExtensionDispatcher knows what Extension is active, not just its ID.
- // This is important for classifying the Extension's JavaScript context
- // correctly (see ExtensionDispatcher::ClassifyJavaScriptContext).
- Send(new ExtensionMsg_Loaded(
- std::vector<ExtensionMsg_Loaded_Params>(
- 1, ExtensionMsg_Loaded_Params(extension))));
- Send(new ExtensionMsg_ActivateExtension(extension->id()));
- break;
-
- case Manifest::TYPE_UNKNOWN:
- case Manifest::TYPE_THEME:
- case Manifest::TYPE_SHARED_MODULE:
- break;
- }
-}
-
-const Extension* ChromeRenderViewHostObserver::GetExtension() {
- // Note that due to ChromeContentBrowserClient::GetEffectiveURL(), hosted apps
- // (excluding bookmark apps) will have a chrome-extension:// URL for their
- // site, so we can ignore that wrinkle here.
- SiteInstance* site_instance = render_view_host()->GetSiteInstance();
- const GURL& site = site_instance->GetSiteURL();
-
- if (!site.SchemeIs(extensions::kExtensionScheme))
- return NULL;
-
- ExtensionService* service =
- extensions::ExtensionSystem::Get(profile_)->extension_service();
- if (!service)
- return NULL;
-
- // Reload the extension if it has crashed.
- // TODO(yoz): This reload doesn't happen synchronously for unpacked
- // extensions. It seems to be fast enough, but there is a race.
- // We should delay loading until the extension has reloaded.
- if (service->GetTerminatedExtension(site.host()))
- service->ReloadExtension(site.host());
-
- // May be null if the extension doesn't exist, for example if somebody typos
- // a chrome-extension:// URL.
- return service->extensions()->GetByID(site.host());
-}
-
-void ChromeRenderViewHostObserver::RemoveRenderViewHostForExtensions(
- RenderViewHost* rvh) {
- ExtensionProcessManager* process_manager =
- extensions::ExtensionSystem::Get(profile_)->process_manager();
- if (process_manager)
- process_manager->UnregisterRenderViewHost(rvh);
-}
-
-void ChromeRenderViewHostObserver::OnFocusedNodeTouched(bool editable) {
-#if defined(OS_WIN) && defined(USE_AURA)
- if (editable) {
- base::win::DisplayVirtualKeyboard();
- } else {
- base::win::DismissVirtualKeyboard();
- }
-#endif // OS_WIN && USE_AURA
-}
-
-// Handles the image thumbnail for the context node, composes a image search
-// request based on the received thumbnail and opens the request in a new tab.
-void ChromeRenderViewHostObserver::OnRequestThumbnailForContextNodeACK(
- const SkBitmap& bitmap,
- const gfx::Size& original_size) {
- if (bitmap.isNull())
- return;
- WebContents* web_contents =
- WebContents::FromRenderViewHost(render_view_host());
- const TemplateURL* const default_provider =
- TemplateURLServiceFactory::GetForProfile(profile_)->
- GetDefaultSearchProvider();
- if (!web_contents || !default_provider)
- return;
-
- const int kDefaultQualityForImageSearch = 90;
- std::vector<unsigned char> data;
- if (!gfx::JPEGCodec::Encode(
- reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)),
- gfx::JPEGCodec::FORMAT_SkBitmap, bitmap.width(), bitmap.height(),
- static_cast<int>(bitmap.rowBytes()), kDefaultQualityForImageSearch,
- &data))
- return;
-
- TemplateURLRef::SearchTermsArgs search_args =
- TemplateURLRef::SearchTermsArgs(base::string16());
- search_args.image_thumbnail_content = std::string(data.begin(), data.end());
- // TODO(jnd): Add a method in WebContentsViewDelegate to get the image URL
- // from the ContextMenuParams which creates current context menu.
- search_args.image_url = GURL();
- search_args.image_original_size = original_size;
- TemplateURLRef::PostContent post_content;
- GURL result(default_provider->image_url_ref().ReplaceSearchTerms(
- search_args, &post_content));
- if (!result.is_valid())
- return;
-
- OpenURLParams open_url_params(result, content::Referrer(), NEW_FOREGROUND_TAB,
- content::PAGE_TRANSITION_LINK, false);
- const std::string& content_type = post_content.first;
- std::string* post_data = &post_content.second;
- if (!post_data->empty()) {
- DCHECK(!content_type.empty());
- open_url_params.uses_post = true;
- open_url_params.browser_initiated_post_data =
- base::RefCountedString::TakeString(post_data);
- open_url_params.extra_headers += base::StringPrintf(
- "%s: %s\r\n", net::HttpRequestHeaders::kContentType,
- content_type.c_str());
- }
- web_contents->OpenURL(open_url_params);
-}
diff --git a/chrome/browser/renderer_host/chrome_render_view_host_observer.h b/chrome/browser/renderer_host/chrome_render_view_host_observer.h
deleted file mode 100644
index 213fc0d582..0000000000
--- a/chrome/browser/renderer_host/chrome_render_view_host_observer.h
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_RENDERER_HOST_CHROME_RENDER_VIEW_HOST_OBSERVER_H_
-#define CHROME_BROWSER_RENDERER_HOST_CHROME_RENDER_VIEW_HOST_OBSERVER_H_
-
-#include <string>
-
-#include "content/public/browser/render_view_host_observer.h"
-
-class Profile;
-class SkBitmap;
-
-namespace chrome_browser_net {
-class Predictor;
-}
-
-namespace extensions {
-class Extension;
-}
-
-namespace gfx {
-class Size;
-}
-
-// This class holds the Chrome specific parts of RenderViewHost, and has the
-// same lifetime.
-class ChromeRenderViewHostObserver : public content::RenderViewHostObserver {
- public:
- ChromeRenderViewHostObserver(content::RenderViewHost* render_view_host,
- chrome_browser_net::Predictor* predictor);
- virtual ~ChromeRenderViewHostObserver();
-
- // content::RenderViewHostObserver overrides.
- virtual void RenderViewHostInitialized() OVERRIDE;
- virtual void RenderViewHostDestroyed(content::RenderViewHost* rvh) OVERRIDE;
- virtual void Navigate(const GURL& url) OVERRIDE;
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
-
- private:
- // Does extension-specific initialization when a new renderer process is
- // created by a RenderViewHost.
- void InitRenderViewForExtensions();
- // Gets the extension or app (if any) that is associated with the RVH.
- const extensions::Extension* GetExtension();
- // Cleans up when a RenderViewHost is removed, or on destruction.
- void RemoveRenderViewHostForExtensions(content::RenderViewHost* rvh);
-
- void OnFocusedNodeTouched(bool editable);
-
- void OnRequestThumbnailForContextNodeACK(const SkBitmap& bitmap,
- const gfx::Size& original_size);
-
- Profile* profile_;
- chrome_browser_net::Predictor* predictor_;
-
- DISALLOW_COPY_AND_ASSIGN(ChromeRenderViewHostObserver);
-};
-
-#endif // CHROME_BROWSER_RENDERER_HOST_CHROME_RENDER_VIEW_HOST_OBSERVER_H_
diff --git a/chrome/browser/renderer_host/pepper/device_id_fetcher.cc b/chrome/browser/renderer_host/pepper/device_id_fetcher.cc
index 42754fa3a2..5f3a1c22e1 100644
--- a/chrome/browser/renderer_host/pepper/device_id_fetcher.cc
+++ b/chrome/browser/renderer_host/pepper/device_id_fetcher.cc
@@ -10,7 +10,7 @@
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#if defined(OS_CHROMEOS)
-#include "chromeos/cryptohome/cryptohome_library.h"
+#include "chromeos/cryptohome/system_salt_getter.h"
#endif
#include "components/user_prefs/pref_registry_syncable.h"
#include "content/public/browser/browser_context.h"
@@ -42,7 +42,7 @@ void GetMachineIDAsync(const DeviceIDFetcher::IDCallback& callback) {
#if defined(OS_WIN) && defined(ENABLE_RLZ)
rlz_lib::GetMachineId(&result);
#elif defined(OS_CHROMEOS)
- result = chromeos::CryptohomeLibrary::Get()->GetSystemSaltSync();
+ result = chromeos::SystemSaltGetter::Get()->GetSystemSaltSync();
if (result.empty()) {
// cryptohome must not be running; re-request after a delay.
const int64 kRequestSystemSaltDelayMs = 500;
diff --git a/chrome/browser/renderer_host/pepper/pepper_extensions_common_message_filter.cc b/chrome/browser/renderer_host/pepper/pepper_extensions_common_message_filter.cc
index e7661283a9..1ce27bfa4e 100644
--- a/chrome/browser/renderer_host/pepper/pepper_extensions_common_message_filter.cc
+++ b/chrome/browser/renderer_host/pepper/pepper_extensions_common_message_filter.cc
@@ -15,7 +15,8 @@
#include "content/public/browser/browser_ppapi_host.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/render_view_host_observer.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
#include "extensions/common/constants.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_message_macros.h"
@@ -27,13 +28,15 @@
namespace chrome {
class PepperExtensionsCommonMessageFilter::DispatcherOwner
- : public content::RenderViewHostObserver,
+ : public content::WebContentsObserver,
public ExtensionFunctionDispatcher::Delegate {
public:
DispatcherOwner(PepperExtensionsCommonMessageFilter* message_filter,
Profile* profile,
- content::RenderViewHost* view_host)
- : content::RenderViewHostObserver(view_host),
+ content::RenderViewHost* view_host,
+ content::WebContents* web_contents)
+ : content::WebContentsObserver(web_contents),
+ render_view_host_(view_host),
message_filter_(message_filter),
dispatcher_(profile, this) {
}
@@ -42,6 +45,13 @@ class PepperExtensionsCommonMessageFilter::DispatcherOwner
message_filter_->DetachDispatcherOwner();
}
+ // content::WebContentsObserver implementation.
+ virtual void RenderViewDeleted(
+ content::RenderViewHost* render_view_host) OVERRIDE {
+ if (render_view_host == render_view_host_)
+ delete this;
+ }
+
// ExtensionFunctionDispatcher::Delegate implementation.
virtual extensions::WindowController* GetExtensionWindowController(
) const OVERRIDE {
@@ -55,11 +65,10 @@ class PepperExtensionsCommonMessageFilter::DispatcherOwner
}
ExtensionFunctionDispatcher* dispatcher() { return &dispatcher_; }
- content::RenderViewHost* render_view_host() {
- return content::RenderViewHostObserver::render_view_host();
- }
+ content::RenderViewHost* render_view_host() { return render_view_host_; }
private:
+ content::RenderViewHost* render_view_host_;
scoped_refptr<PepperExtensionsCommonMessageFilter> message_filter_;
ExtensionFunctionDispatcher dispatcher_;
@@ -154,6 +163,8 @@ void PepperExtensionsCommonMessageFilter::EnsureDispatcherOwnerInitialized() {
render_process_id_, render_view_id_);
if (!view_host)
return;
+ content::WebContents* web_contents =
+ content::WebContents::FromRenderViewHost(view_host);
if (!document_url_.SchemeIs(extensions::kExtensionScheme))
return;
@@ -164,7 +175,8 @@ void PepperExtensionsCommonMessageFilter::EnsureDispatcherOwnerInitialized() {
Profile* profile = profile_manager->GetProfile(profile_directory_);
// It will be automatically destroyed when |view_host| goes away.
- dispatcher_owner_ = new DispatcherOwner(this, profile, view_host);
+ dispatcher_owner_ = new DispatcherOwner(
+ this, profile, view_host, web_contents);
}
void PepperExtensionsCommonMessageFilter::DetachDispatcherOwner() {
diff --git a/chrome/browser/renderer_host/pepper/pepper_platform_verification_message_filter.cc b/chrome/browser/renderer_host/pepper/pepper_platform_verification_message_filter.cc
index 23c2b7a29b..e51c4e519f 100644
--- a/chrome/browser/renderer_host/pepper/pepper_platform_verification_message_filter.cc
+++ b/chrome/browser/renderer_host/pepper/pepper_platform_verification_message_filter.cc
@@ -43,9 +43,6 @@ int32_t PepperPlatformVerificationMessageFilter::OnResourceMessageReceived(
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
IPC_BEGIN_MESSAGE_MAP(PepperPlatformVerificationMessageFilter, msg)
- PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
- PpapiHostMsg_PlatformVerification_CanChallengePlatform,
- OnCanChallengePlatform)
PPAPI_DISPATCH_HOST_RESOURCE_CALL(
PpapiHostMsg_PlatformVerification_ChallengePlatform,
OnChallengePlatform)
@@ -54,18 +51,6 @@ int32_t PepperPlatformVerificationMessageFilter::OnResourceMessageReceived(
return PP_ERROR_FAILED;
}
-int32_t PepperPlatformVerificationMessageFilter::OnCanChallengePlatform(
- ppapi::host::HostMessageContext* context) {
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
- if (!pv_)
- pv_.reset(new PlatformVerificationFlow());
- pv_->CheckPlatformState(base::Bind(
- &PepperPlatformVerificationMessageFilter::CanChallengePlatformCallback,
- this,
- context->MakeReplyMessageContext()));
- return PP_OK_COMPLETIONPENDING;
-}
-
int32_t PepperPlatformVerificationMessageFilter::OnChallengePlatform(
ppapi::host::HostMessageContext* context,
const std::string& service_id,
@@ -101,16 +86,6 @@ int32_t PepperPlatformVerificationMessageFilter::OnChallengePlatform(
return PP_OK_COMPLETIONPENDING;
}
-void PepperPlatformVerificationMessageFilter::CanChallengePlatformCallback(
- ppapi::host::ReplyMessageContext reply_context,
- bool can_challenge_platform) {
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
- reply_context.params.set_result(PP_OK);
- SendReply(reply_context,
- PpapiHostMsg_PlatformVerification_CanChallengePlatformReply(
- can_challenge_platform));
-}
-
void PepperPlatformVerificationMessageFilter::ChallengePlatformCallback(
ppapi::host::ReplyMessageContext reply_context,
chromeos::attestation::PlatformVerificationFlow::Result challenge_result,
diff --git a/chrome/browser/renderer_host/pepper/pepper_platform_verification_message_filter.h b/chrome/browser/renderer_host/pepper/pepper_platform_verification_message_filter.h
index f13d3203c4..a5ffe5074c 100644
--- a/chrome/browser/renderer_host/pepper/pepper_platform_verification_message_filter.h
+++ b/chrome/browser/renderer_host/pepper/pepper_platform_verification_message_filter.h
@@ -38,15 +38,11 @@ class PepperPlatformVerificationMessageFilter
const IPC::Message& msg,
ppapi::host::HostMessageContext* context) OVERRIDE;
- int32_t OnCanChallengePlatform(ppapi::host::HostMessageContext* context);
int32_t OnChallengePlatform(ppapi::host::HostMessageContext* context,
const std::string& service_id,
const std::vector<uint8_t>& challenge);
// PlatformVerificationFlow callbacks.
- void CanChallengePlatformCallback(
- ppapi::host::ReplyMessageContext reply_context,
- bool can_challenge_platform);
void ChallengePlatformCallback(
ppapi::host::ReplyMessageContext reply_context,
chromeos::attestation::PlatformVerificationFlow::Result challenge_result,
diff --git a/chrome/browser/resources/chromeos/about_sys.html b/chrome/browser/resources/chromeos/about_sys.html
index 4626fe9810..392bd36646 100644
--- a/chrome/browser/resources/chromeos/about_sys.html
+++ b/chrome/browser/resources/chromeos/about_sys.html
@@ -22,8 +22,7 @@
<p id="status"></p>
<table class="list" id="details">
<tr jsselect="details">
- <td class="name"<div
- jscontent="statName"></div></td>
+ <td class="name"><div jscontent="statName"></div></td>
<td class="button-cell"><button jsvalues="id:statName + '-value-btn'"
class="expand-status"></button></td>
<td class="number"><div class="stat-value" jscontent="statValue"
diff --git a/chrome/browser/resources/chromeos/cryptohome.html b/chrome/browser/resources/chromeos/cryptohome.html
index 5743596da2..c6f57654a0 100644
--- a/chrome/browser/resources/chromeos/cryptohome.html
+++ b/chrome/browser/resources/chromeos/cryptohome.html
@@ -10,7 +10,7 @@
<div id="refresh-message">
(To auto-refresh this page: about:cryptohome/&lt;secs&gt;)
</div>
- <h3>CryptohomeLibrary:</h3>
+ <h3>Cryptohome:</h3>
<table>
<tr>
<td>IsMounted</td>
diff --git a/chrome/browser/resources/chromeos/diagnostics/main.js b/chrome/browser/resources/chromeos/diagnostics/main.js
index 09f27818c3..d8ccf5b9bc 100644
--- a/chrome/browser/resources/chromeos/diagnostics/main.js
+++ b/chrome/browser/resources/chromeos/diagnostics/main.js
@@ -24,10 +24,12 @@ cr.define('diag', function() {
* List of network adapter types.
*/
DiagPage.AdapterType = [
- {adapter: 'wlan0', name: localStrings.getString('wlan0'), kind: 'wifi'},
- {adapter: 'eth0', name: localStrings.getString('eth0'), kind: 'ethernet'},
- {adapter: 'eth1', name: localStrings.getString('eth1'), kind: 'ethernet'},
- {adapter: 'wwan0', name: localStrings.getString('wwan0'), kind: '3g'},
+ {adapter: 'wifi', name: localStrings.getString('wifi'), kind: 'wifi'},
+ {adapter: 'ethernet', name: localStrings.getString('ethernet1'),
+ kind: 'ethernet'},
+ {adapter: 'ethernet2', name: localStrings.getString('ethernet2'),
+ kind: 'ethernet'},
+ {adapter: 'cellular', name: localStrings.getString('3g'), kind: '3g'},
];
/**
@@ -105,30 +107,49 @@ cr.define('diag', function() {
},
/**
- * Updates the connectivity status with netif information.
- * @param {Object} netifStatus Dictionary of network adapter status.
+ * Updates the connectivity status with the device information.
+ * @param {Object} deviceStatus Dictionary of network adapter status.
*/
- setNetifStatus_: function(netifStatus) {
+ setDeviceStatus: function(deviceStatus) {
// Hide the "loading" message and show the "choose-adapter" message.
$('loading').hidden = true;
$('choose-adapter').hidden = false;
- // Update netif state.
- var foundValidIp = false;
+ // Reset all adapters status.
+ var adapterLookup = {};
for (var i = 0; i < DiagPage.AdapterType.length; i++) {
- var adapterType = DiagPage.AdapterType[i];
- var status = netifStatus[adapterType.adapter];
- if (!status)
- this.adapterStatus_[i] = DiagPage.AdapterStatus.NOT_FOUND;
- else if (!status.flags || status.flags.indexOf('up') == -1)
- this.adapterStatus_[i] = DiagPage.AdapterStatus.DISABLED;
- else if (!status.ipv4)
- this.adapterStatus_[i] = DiagPage.AdapterStatus.NO_IP;
- else
- this.adapterStatus_[i] = DiagPage.AdapterStatus.VALID_IP;
+ this.adapterStatus_[i] = DiagPage.AdapterStatus.NOT_FOUND;
+ adapterLookup[DiagPage.AdapterType[i].adapter] = i;
+ }
- if (this.adapterStatus_[i] == DiagPage.AdapterStatus.VALID_IP)
- foundValidIp = true;
+ // Update adapter status from data.
+ var foundValidIp = false;
+ for (var devicePath in deviceStatus) {
+ var device = deviceStatus[devicePath];
+ var type = device['Type'];
+ var idx = adapterLookup[type];
+ if (idx == null) {
+ console.warning('Unexpected adapter type: ' + type);
+ continue;
+ }
+
+ // Special case for multiple ethernet adapters.
+ if (type == 'ethernet' &&
+ this.adapterStatus_[idx] != DiagPage.AdapterStatus.NOT_FOUND) {
+ type = 'ethernet2';
+ idx = adapterLookup[type];
+ }
+
+ this.adapterStatus_[idx] = device['Powered'] == true ?
+ DiagPage.AdapterStatus.NO_IP : DiagPage.AdapterStatus.DISABLED;
+ var ipconfigs = device['ipconfigs'];
+ for (var ipconfigPath in ipconfigs) {
+ var ipconfig = ipconfigs[ipconfigPath];
+ if (ipconfig['Address']) {
+ this.adapterStatus_[idx] = DiagPage.AdapterStatus.VALID_IP;
+ foundValidIp = true;
+ }
+ }
}
// If we have valid IP, start ping test.
@@ -313,8 +334,8 @@ cr.define('diag', function() {
}
};
- DiagPage.setNetifStatus = function(netifStatus) {
- DiagPage.getInstance().setNetifStatus_(netifStatus);
+ DiagPage.setDeviceStatus = function(deviceStatus) {
+ DiagPage.getInstance().setDeviceStatus(deviceStatus);
}
DiagPage.setTestICMPStatus = function(testICMPStatus) {
diff --git a/chrome/browser/resources/chromeos/drive_internals.html b/chrome/browser/resources/chromeos/drive_internals.html
index 6b25ee5d6a..d1bf25500b 100644
--- a/chrome/browser/resources/chromeos/drive_internals.html
+++ b/chrome/browser/resources/chromeos/drive_internals.html
@@ -92,7 +92,7 @@
<table>
<tbody id='cache-contents'>
<tr>
- <th>Resource ID</th>
+ <th>Local ID</th>
<th>MD5</th>
<th>Present</th>
<th>Pinned</th>
diff --git a/chrome/browser/resources/chromeos/drive_internals.js b/chrome/browser/resources/chromeos/drive_internals.js
index 46c2fee688..c8736212e9 100644
--- a/chrome/browser/resources/chromeos/drive_internals.js
+++ b/chrome/browser/resources/chromeos/drive_internals.js
@@ -91,7 +91,7 @@ function updateFileSystemContents(directoryContentsAsText) {
*/
function updateCacheContents(cacheEntry) {
var tr = document.createElement('tr');
- tr.appendChild(createElementFromText('td', cacheEntry.resource_id));
+ tr.appendChild(createElementFromText('td', cacheEntry.local_id));
tr.appendChild(createElementFromText('td', cacheEntry.md5));
tr.appendChild(createElementFromText('td', cacheEntry.is_present));
tr.appendChild(createElementFromText('td', cacheEntry.is_pinned));
diff --git a/chrome/browser/resources/chromeos/login/bubble.js b/chrome/browser/resources/chromeos/login/bubble.js
index 89a20f864a..cce6f8d23e 100644
--- a/chrome/browser/resources/chromeos/login/bubble.js
+++ b/chrome/browser/resources/chromeos/login/bubble.js
@@ -50,6 +50,8 @@ cr.define('cr.ui', function() {
window.addEventListener('blur', this.handleWindowBlur_.bind(this));
this.addEventListener('webkitTransitionEnd',
this.handleTransitionEnd_.bind(this));
+ // Guard timer for 200ms + epsilon.
+ ensureTransitionEndEvent(this, 250);
},
/**
diff --git a/chrome/browser/resources/chromeos/login/header_bar.js b/chrome/browser/resources/chromeos/login/header_bar.js
index 82a04c4867..06e7434da3 100644
--- a/chrome/browser/resources/chromeos/login/header_bar.js
+++ b/chrome/browser/resources/chromeos/login/header_bar.js
@@ -222,6 +222,9 @@ cr.define('login', function() {
launcher.removeEventListener('webkitTransitionEnd', f);
callback();
});
+ // Guard timer for 2 seconds + 200 ms + epsilon.
+ ensureTransitionEndEvent(launcher, 2250);
+
this.classList.remove('login-header-bar-animate-slow');
this.classList.add('login-header-bar-animate-fast');
this.classList.add('login-header-bar-hidden');
diff --git a/chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.css b/chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.css
index 86b5c4344c..15ed19c947 100644
--- a/chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.css
+++ b/chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.css
@@ -36,6 +36,12 @@
overflow-x: auto;
}
+#managed-user-creation .button-link {
+ font-size: small;
+ padding: 0 20px;
+ position: absolute;
+}
+
.below-marketing::-webkit-scrollbar {
width: 8px;
}
@@ -191,6 +197,31 @@ input.managed-user-creation-manager-password,
margin-left: 10px !important;
}
+.import-pod {
+ height: 32px;
+ opacity: 0.8;
+ padding: 6px;
+ width: 626px;
+}
+
+.import-pod .import-pod-name {
+ color: #000;
+ display: inline;
+ max-height: 30px;
+ vertical-align: top;
+}
+
+.import-pod.imported .import-pod-name {
+ color: rgb(141, 141, 141);
+}
+
+.import-pod .import-pod-image {
+ border: 1px solid gray;
+ display: inline;
+ height: 30px;
+ width: 30px;
+}
+
.manager-pod {
height: 32px;
opacity: 0.8;
@@ -265,6 +296,16 @@ input.managed-user-creation-manager-password,
opacity: 1;
}
+.import-pod.imported.focused {
+ background-color: rgb(238, 238, 238);
+ opacity: 1;
+}
+
+.import-pod.focused {
+ background-color: rgb(66, 129, 244);
+ opacity: 1;
+}
+
.manager-pod.focused .managed-user-creation-manager-email {
color: #fff;
}
@@ -273,6 +314,13 @@ input.managed-user-creation-manager-password,
color: #fff;
}
+#managed-user-creation-import-pane {
+ border: 1px solid #c8c8c8;
+ height: 400px;
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+
.manager-pod .password-error,
#managed-user-creation .password-error,
#managed-user-creation .duplicate-name {
diff --git a/chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.html b/chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.html
index 5c0b4ed34d..a3bbf47e75 100644
--- a/chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.html
+++ b/chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.html
@@ -82,6 +82,21 @@
</div>
</div>
</div>
+
+ <div id="managed-user-creation-import" class="page-no-marketing" hidden>
+ <div class="logo-padded-text">
+ <div>
+ <div class="page-title"
+ i18n-content="importExistingSupervisedUserTitle"></div>
+ <div class="page-title-explanation"
+ i18n-content="importExistingSupervisedUserText"></div>
+ </div>
+ </div>
+ <div class="logo-padded-text">
+ <div id="managed-user-creation-import-pane"></div>
+ </div>
+ </div>
+
<div id="managed-user-creation-created" class="step-no-logo" hidden>
<div class="marketing">
<img src="chrome://theme/IDR_SUPERVISED_ILLUSTRATION_DONE">
@@ -115,6 +130,12 @@
<div class="id-spinner inline-spinner"></div>
</div>
</div>
+ <div class="template-import-supervised-user-link button-link" hidden>
+ <a href="#" class="signin-link" i18n-content="importSupervisedUserLink"></a>
+ </div>
+ <div class="template-create-supervised-user-link button-link" hidden>
+ <a href="#" class="signin-link" i18n-content="createSupervisedUserLink"></a>
+ </div>
<div id="managed-user-creation-manager-template" hidden
class="manager-pod">
<div class="managed-user-creation-manager-info-block">
@@ -129,4 +150,8 @@
i18n-values="placeholder:createManagedUserManagerPasswordHint" />
</div>
</div>
+ <div id="managed-user-creation-import-template" hidden class="import-pod">
+ <img class="import-pod-image"></img>
+ <div class="import-pod-name"></div>
+ </div>
</div> \ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.js b/chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.js
index 762d000936..950415efca 100644
--- a/chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.js
+++ b/chrome/browser/resources/chromeos/login/screen_locally_managed_user_creation.js
@@ -10,6 +10,7 @@ login.createScreen('LocallyManagedUserCreationScreen',
'managed-user-creation', function() {
var MAX_NAME_LENGTH = 50;
var UserImagesGrid = options.UserImagesGrid;
+ var ButtonImages = UserImagesGrid.ButtonImages;
var ManagerPod = cr.ui.define(function() {
var node = $('managed-user-creation-manager-template').cloneNode(true);
@@ -174,7 +175,7 @@ login.createScreen('LocallyManagedUserCreationScreen',
},
selectPod: function(podToSelect) {
- if ((this.selectedPod_ == podToSelect) && (podToSelect != null)) {
+ if ((this.selectedPod_ == podToSelect) && !!podToSelect) {
podToSelect.focusInput();
return;
}
@@ -186,7 +187,7 @@ login.createScreen('LocallyManagedUserCreationScreen',
pod.passwordBlock.hidden = true;
}
}
- if (podToSelect == null)
+ if (!podToSelect)
return;
podToSelect.classList.add('focused');
podToSelect.passwordBlock.hidden = false;
@@ -194,13 +195,209 @@ login.createScreen('LocallyManagedUserCreationScreen',
podToSelect.focusInput();
chrome.send('managerSelectedOnLocallyManagedUserCreationFlow',
[podToSelect.user.username]);
+ },
+ };
+
+ var ImportPod = cr.ui.define(function() {
+ var node = $('managed-user-creation-import-template').cloneNode(true);
+ node.removeAttribute('id');
+ node.removeAttribute('hidden');
+ return node;
+ });
+
+ /**
+ * UI element for displaying single supervised user in list of possible users
+ * for importing existing users.
+ * @type {Object}
+ */
+ ImportPod.prototype = {
+ __proto__: HTMLDivElement.prototype,
+ /** @override */
+ decorate: function() {
+ // Mousedown has to be used instead of click to be able to prevent 'focus'
+ // event later.
+ this.addEventListener('mousedown',
+ this.handleMouseDown_.bind(this));
+ },
+
+ /**
+ * Updates UI elements from user data.
+ */
+ update: function() {
+ this.imageElement.src = this.user.avatarurl;
+ this.nameElement.textContent = this.user.name;
+ if (this.user.exists) {
+ if (this.user.conflict == 'imported') {
+ this.nameElement.textContent =
+ loadTimeData.getStringF('importUserExists', this.user.name);
+ } else {
+ this.nameElement.textContent =
+ loadTimeData.getStringF('importUsernameExists', this.user.name);
+ }
+ }
+ this.classList.toggle('imported', this.user.exists);
+ },
+
+ /**
+ * Gets image element.
+ * @type {!HTMLImageElement}
+ */
+ get imageElement() {
+ return this.querySelector('.import-pod-image');
+ },
+
+ /**
+ * Gets name element.
+ * @type {!HTMLDivElement}
+ */
+ get nameElement() {
+ return this.querySelector('.import-pod-name');
+ },
+
+ /** @override */
+ handleMouseDown_: function(e) {
+ this.parentNode.selectPod(this);
+ // Prevent default so that we don't trigger 'focus' event.
+ e.preventDefault();
+ },
+
+ /**
+ * The user that this pod represents.
+ * @type {Object}
+ */
+ user_: undefined,
+
+ get user() {
+ return this.user_;
+ },
+
+ set user(userDict) {
+ this.user_ = userDict;
+ this.update();
+ },
+ };
+
+ var ImportPodList = cr.ui.define('div');
+
+ /**
+ * UI element for selecting existing supervised user for import.
+ * @type {Object}
+ */
+ ImportPodList.prototype = {
+ __proto__: HTMLDivElement.prototype,
+
+ selectedPod_: null,
+
+ /** @override */
+ decorate: function() {
+ },
+
+ /**
+ * Returns all the pods in this pod list.
+ * @type {NodeList}
+ */
+ get pods() {
+ return this.children;
+ },
+
+ addPod: function(user) {
+ var importPod = new ImportPod({user: user});
+ this.appendChild(importPod);
+ importPod.update();
+ },
+
+ clearPods: function() {
+ this.innerHTML = '';
+ this.selectedPod_ = null;
+ },
+
+ scrollIntoView: function(pod) {
+ scroller = this.parentNode;
+ var itemHeight = pod.getBoundingClientRect().height;
+ var scrollTop = scroller.scrollTop;
+ var top = pod.offsetTop - scroller.offsetTop;
+ var clientHeight = scroller.clientHeight;
+
+ var self = scroller;
+
+ // Function to adjust the tops of viewport and row.
+ function scrollToAdjustTop() {
+ self.scrollTop = top;
+ return true;
+ };
+ // Function to adjust the bottoms of viewport and row.
+ function scrollToAdjustBottom() {
+ var cs = getComputedStyle(self);
+ var paddingY = parseInt(cs.paddingTop, 10) +
+ parseInt(cs.paddingBottom, 10);
+
+ if (top + itemHeight > scrollTop + clientHeight - paddingY) {
+ self.scrollTop = top + itemHeight - clientHeight + paddingY;
+ return true;
+ }
+ return false;
+ };
+
+ // Check if the entire of given indexed row can be shown in the viewport.
+ if (itemHeight <= clientHeight) {
+ if (top < scrollTop)
+ return scrollToAdjustTop();
+ if (scrollTop + clientHeight < top + itemHeight)
+ return scrollToAdjustBottom();
+ } else {
+ if (scrollTop < top)
+ return scrollToAdjustTop();
+ if (top + itemHeight < scrollTop + clientHeight)
+ return scrollToAdjustBottom();
+ }
+ return false;
+ },
+
+ /**
+ * @param {Element} podToSelect - pod to select, can be null.
+ */
+ selectPod: function(podToSelect) {
+ if ((this.selectedPod_ == podToSelect) && !!podToSelect) {
+ return;
+ }
+ this.selectedPod_ = podToSelect;
+ for (var i = 0; i < this.pods.length; i++) {
+ var pod = this.pods[i];
+ if (pod != podToSelect)
+ pod.classList.remove('focused');
+ }
+ if (!podToSelect)
+ return;
+ podToSelect.classList.add('focused');
+ var screen = $('managed-user-creation');
+ if (!this.selectedPod_) {
+ screen.getScreenButton('import').disabled = true;
+ } else {
+ screen.getScreenButton('import').disabled =
+ this.selectedPod_.user.exists;
+ if (!this.selectedPod_.user.exists) {
+ chrome.send('userSelectedForImportInManagedUserCreationFlow',
+ [podToSelect.user.id]);
+ }
+ }
+ },
+
+ selectUser: function(user_id) {
+ for (var i = 0, pod; pod = this.pods[i]; ++i) {
+ if (pod.user.id == user_id) {
+ this.selectPod(pod);
+ this.scrollIntoView(pod);
+ break;
+ }
+ }
},
};
return {
EXTERNAL_API: [
'loadManagers',
+ 'managedUserSuggestImport',
'managedUserNameError',
'managedUserNameOk',
'showErrorPage',
@@ -215,13 +412,16 @@ login.createScreen('LocallyManagedUserCreationScreen',
'showPage',
'setDefaultImages',
'setCameraPresent',
+ 'setExistingManagedUsers',
],
lastVerifiedName_: null,
lastIncorrectUserName_: null,
managerList_: null,
+ importList_: null,
currentPage_: null,
+ imagesRequested_: false,
// Contains data that can be auto-shared with handler.
context_: {},
@@ -229,8 +429,10 @@ login.createScreen('LocallyManagedUserCreationScreen',
/** @override */
decorate: function() {
this.managerList_ = new ManagerPodList();
- $('managed-user-creation-managers-pane').
- appendChild(this.managerList_);
+ $('managed-user-creation-managers-pane').appendChild(this.managerList_);
+
+ this.importList_ = new ImportPodList();
+ $('managed-user-creation-import-pane').appendChild(this.importList_);
var userNameField = $('managed-user-creation-name');
var passwordField = $('managed-user-creation-password');
@@ -284,13 +486,14 @@ login.createScreen('LocallyManagedUserCreationScreen',
imageGrid.previewElement = previewElement;
imageGrid.selectionType = 'default';
+ imageGrid.addEventListener('activate',
+ this.handleActivate_.bind(this));
imageGrid.addEventListener('select',
this.handleSelect_.bind(this));
imageGrid.addEventListener('phototaken',
this.handlePhotoTaken_.bind(this));
imageGrid.addEventListener('photoupdated',
this.handlePhotoUpdated_.bind(this));
-
// Set the title for camera item in the grid.
imageGrid.setCameraTitles(
loadTimeData.getString('takePhoto'),
@@ -315,7 +518,6 @@ login.createScreen('LocallyManagedUserCreationScreen',
'webkitTransitionEnd', function(e) {
previewElement.classList.remove('animation');
});
- chrome.send('supervisedUserGetImages');
},
buttonIds: [],
@@ -449,6 +651,23 @@ login.createScreen('LocallyManagedUserCreationScreen',
var status = this.makeFromTemplate('status-container', 'status');
buttons.push(status);
+ var importLink = this.makeFromTemplate('import-supervised-user-link',
+ 'import-link');
+ importLink.hidden = true;
+ buttons.push(importLink);
+ var linkElement = importLink.querySelector('.signin-link');
+ linkElement.addEventListener('click',
+ this.importLinkPressed_.bind(this));
+
+ var createLink = this.makeFromTemplate('create-supervised-user-link',
+ 'create-link');
+ createLink.hidden = true;
+ buttons.push(createLink);
+
+ linkElement = createLink.querySelector('.signin-link');
+ linkElement.addEventListener('click',
+ this.createLinkPressed_.bind(this));
+
buttons.push(this.makeButton(
'start',
'managedUserCreationFlow',
@@ -471,6 +690,13 @@ login.createScreen('LocallyManagedUserCreationScreen',
[]));
buttons.push(this.makeButton(
+ 'import',
+ 'managedUserCreationFlow',
+ this.importButtonPressed_.bind(this),
+ ['import'],
+ []));
+
+ buttons.push(this.makeButton(
'gotit',
'managedUserCreationFlow',
this.gotItButtonPressed_.bind(this),
@@ -528,6 +754,24 @@ login.createScreen('LocallyManagedUserCreationScreen',
},
/**
+ * Does sanity check and calls backend with selected existing supervised
+ * user id to import user.
+ * @private
+ */
+ importSupervisedUser_: function() {
+ var selectedPod = this.importList_.selectedPod_;
+ if (!selectedPod)
+ return;
+ var userId = selectedPod.user.id;
+
+ this.disabled = true;
+ this.context_.importUserId = userId;
+ this.context_.managedName = selectedPod.user.name;
+
+ chrome.send('importSupervisedUser', [userId]);
+ },
+
+ /**
* Calls backend part to check if current user name is valid/not taken.
* Results in call to either managedUserNameOk or managedUserNameError.
* @private
@@ -568,6 +812,7 @@ login.createScreen('LocallyManagedUserCreationScreen',
* @param {string} errorText - reason why this name is invalid.
*/
managedUserNameError: function(name, errorText) {
+ this.disabled = false;
this.lastIncorrectUserName_ = name;
this.lastVerifiedName_ = null;
@@ -581,7 +826,36 @@ login.createScreen('LocallyManagedUserCreationScreen',
12, 4);
this.setButtonDisabledStatus('next', true);
}
+ },
+
+ managedUserSuggestImport: function(name, user_id) {
this.disabled = false;
+ this.lastIncorrectUserName_ = name;
+ this.lastVerifiedName_ = null;
+
+ var userNameField = $('managed-user-creation-name');
+ var creationScreen = this;
+
+ if (userNameField.value == this.lastIncorrectUserName_) {
+ this.nameErrorVisible = true;
+ var link = this.ownerDocument.createElement('div');
+ link.innerHTML = loadTimeData.getStringF(
+ 'importBubbleText',
+ '<a class="signin-link" href="#">',
+ name,
+ '</a>');
+ link.querySelector('.signin-link').addEventListener('click',
+ function(e) {
+ creationScreen.handleSuggestImport_(user_id);
+ e.stopPropagation();
+ });
+ $('bubble').showContentForElement(
+ $('managed-user-creation-name'),
+ cr.ui.Bubble.Attachment.RIGHT,
+ link,
+ 12, 4);
+ this.setButtonDisabledStatus('next', true);
+ }
},
/**
@@ -676,13 +950,19 @@ login.createScreen('LocallyManagedUserCreationScreen',
this.disabled = false;
this.updateText_();
$('bubble').hide();
+ if (!this.imagesRequested_) {
+ chrome.send('supervisedUserGetImages');
+ this.imagesRequested_ = true;
+ }
var pageNames = ['intro',
'manager',
'username',
+ 'import',
'error',
'created'];
var pageButtons = {'intro' : 'start',
'error' : 'error',
+ 'import' : 'import',
'created' : 'gotit'};
this.hideStatus_();
for (i in pageNames) {
@@ -699,11 +979,14 @@ login.createScreen('LocallyManagedUserCreationScreen',
button.disabled = false;
}
- var pagesWithCancel = ['intro', 'manager', 'username', 'error'];
+ var pagesWithCancel = ['intro', 'manager', 'username', 'error', 'import'];
var cancelButton = $('cancel-add-user-button');
cancelButton.hidden = pagesWithCancel.indexOf(visiblePage) < 0;
cancelButton.disabled = false;
+ this.getScreenElement('import-link').hidden = true;
+ this.getScreenElement('create-link').hidden = true;
+
if (pageButtons[visiblePage])
this.getScreenButton(pageButtons[visiblePage]).focus();
@@ -725,11 +1008,20 @@ login.createScreen('LocallyManagedUserCreationScreen',
chrome.send('supervisedUserSelectImage',
[selected.url, 'default']);
this.getScreenElement('image-grid').redraw();
+ this.checkUserName_();
this.updateNextButtonForUser_();
this.getScreenElement('name').focus();
+ this.getScreenElement('import-link').hidden =
+ this.importList_.pods.length == 0;
} else {
this.getScreenElement('image-grid').stopCamera();
}
+ if (visiblePage == 'import') {
+ this.getScreenElement('create-link').hidden = false;
+ this.getScreenButton('import').disabled =
+ !this.importList_.selectedPod_ ||
+ this.importList_.selectedPod_.user.exists;
+ }
chrome.send('currentSupervisedUserPage', [this.currentPage_]);
},
@@ -760,6 +1052,27 @@ login.createScreen('LocallyManagedUserCreationScreen',
this.validateAndCreateLocallyManagedUser_();
}
},
+
+ importButtonPressed_: function() {
+ this.importSupervisedUser_();
+ },
+
+ importLinkPressed_: function() {
+ this.setVisiblePage_('import');
+ },
+
+ handleSuggestImport_: function(user_id) {
+ this.setVisiblePage_('import');
+ this.importList_.selectUser(user_id);
+ },
+
+ createLinkPressed_: function() {
+ this.setVisiblePage_('username');
+ this.lastIncorrectUserName_ = null;
+ this.lastVerifiedName_ = null;
+ this.checkUserName_();
+ },
+
prevButtonPressed_: function() {
this.setVisiblePage_('intro');
},
@@ -771,6 +1084,8 @@ login.createScreen('LocallyManagedUserCreationScreen',
statusText.classList.remove('error');
status.querySelector('.id-spinner').hidden = false;
status.hidden = false;
+ this.getScreenElement('import-link').hidden = true;
+ this.getScreenElement('create-link').hidden = true;
},
showStatusError: function(text) {
@@ -780,6 +1095,8 @@ login.createScreen('LocallyManagedUserCreationScreen',
statusText.classList.add('error');
status.querySelector('.id-spinner').hidden = true;
status.hidden = false;
+ this.getScreenElement('import-link').hidden = true;
+ this.getScreenElement('create-link').hidden = true;
},
hideStatus_: function() {
@@ -971,6 +1288,16 @@ login.createScreen('LocallyManagedUserCreationScreen',
this.imagesData_ = imagesData;
},
+
+ handleActivate_: function() {
+ var imageGrid = this.getScreenElement('image-grid');
+ if (imageGrid.selectedItemUrl == ButtonImages.TAKE_PHOTO) {
+ this.handleTakePhoto_();
+ return;
+ }
+ this.nextButtonPressed_();
+ },
+
/**
* Handles selection change.
* @param {Event} e Selection change event.
@@ -1029,6 +1356,28 @@ login.createScreen('LocallyManagedUserCreationScreen',
setCameraPresent: function(present) {
this.getScreenElement('image-grid').cameraPresent = present;
},
+
+ setExistingManagedUsers: function(users) {
+ var userList = users;
+
+ userList.sort(function(a, b) {
+ // Put existing users last.
+ if (a.exists != b.exists)
+ return a.exists ? 1 : -1;
+ // Sort rest by name.
+ return a.name.localeCompare(b.name, [], {sensitivity: 'base'});
+ });
+
+ this.importList_.clearPods();
+ for (var i = 0; i < userList.length; ++i)
+ this.importList_.addPod(userList[i]);
+
+ if (userList.length == 1)
+ this.importList_.selectPod(this.managerList_.pods[0]);
+
+ if (userList.length > 0 && this.currentPage_ == 'username')
+ this.getScreenElement('import-link').hidden = false;
+ },
};
});
diff --git a/chrome/browser/resources/chromeos/login/user_pod_row.css b/chrome/browser/resources/chromeos/login/user_pod_row.css
index f833c3d28d..428288ffb8 100644
--- a/chrome/browser/resources/chromeos/login/user_pod_row.css
+++ b/chrome/browser/resources/chromeos/login/user_pod_row.css
@@ -349,7 +349,10 @@ html[oobe=old] .pod.focused .action-box-area {
.pod.public-account .name,
.side-pane-name {
-webkit-padding-end: 16px;
+ height: 42px;
outline: none;
+ overflow: hidden;
+ text-overflow: ellipsis;
}
.learn-more,
diff --git a/chrome/browser/resources/chromeos/login/user_pod_row.js b/chrome/browser/resources/chromeos/login/user_pod_row.js
index 7969895a09..f5d24c8938 100644
--- a/chrome/browser/resources/chromeos/login/user_pod_row.js
+++ b/chrome/browser/resources/chromeos/login/user_pod_row.js
@@ -1569,6 +1569,8 @@ cr.define('login', function() {
}
}
});
+ // Guard timer for 1 second -- it would conver all possible animations.
+ ensureTransitionEndEvent(focusedPod, 1000);
}
},
diff --git a/chrome/browser/resources/chromeos/login/user_pod_template.html b/chrome/browser/resources/chromeos/login/user_pod_template.html
index 6a150bb895..6a05bdae48 100644
--- a/chrome/browser/resources/chromeos/login/user_pod_template.html
+++ b/chrome/browser/resources/chromeos/login/user_pod_template.html
@@ -42,8 +42,10 @@
<div class="side-pane-divider"></div>
<div class="side-pane-container">
<div class="side-pane-contents">
- <div class="side-pane-name"></div>
- <div class="side-pane-learn-more"></div>
+ <div class="side-pane-name-plus-learn">
+ <div class="side-pane-name"></div>
+ <div class="side-pane-learn-more"></div>
+ </div>
<p class="info"></p>
<p class="reminder" i18n-content="publicAccountReminder"></p>
<button class="enter-button"
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/js/util.js b/chrome/browser/resources/chromeos/wallpaper_manager/js/util.js
index 4d07a5820c..397f1805e4 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/js/util.js
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/js/util.js
@@ -86,8 +86,7 @@ WallpaperUtil.fetchURL = function(url, type, onSuccess, onFailure, opt_xhr) {
*/
WallpaperUtil.setOnlineWallpaper = function(url, layout, onSuccess, onFailure) {
var self = this;
- chrome.wallpaperPrivate.setWallpaperIfExists(url, layout,
- Constants.WallpaperSourceEnum.Online, function(exists) {
+ chrome.wallpaperPrivate.setWallpaperIfExists(url, layout, function(exists) {
if (exists) {
onSuccess();
return;
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_manager.js b/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_manager.js
index 9f1d66127b..b7a19ed214 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_manager.js
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_manager.js
@@ -243,8 +243,7 @@ function WallpaperManager(dialogDom) {
});
window.addEventListener('offline', function() {
- chrome.wallpaperPrivate.getOfflineWallpaperList(
- Constants.WallpaperSourceEnum.Online, function(lists) {
+ chrome.wallpaperPrivate.getOfflineWallpaperList(function(lists) {
if (!self.downloadedListMap_)
self.downloadedListMap_ = {};
for (var i = 0; i < lists.length; i++) {
@@ -395,8 +394,7 @@ function WallpaperManager(dialogDom) {
// If device is offline, gets the available offline wallpaper list first.
// Wallpapers which are not in the list will display a grayscaled
// thumbnail.
- chrome.wallpaperPrivate.getOfflineWallpaperList(
- Constants.WallpaperSourceEnum.Online, function(lists) {
+ chrome.wallpaperPrivate.getOfflineWallpaperList(function(lists) {
if (!self.downloadedListMap_)
self.downloadedListMap_ = {};
for (var i = 0; i < lists.length; i++)
@@ -490,7 +488,6 @@ function WallpaperManager(dialogDom) {
chrome.wallpaperPrivate.setWallpaperIfExists(wallpaperURL,
selectedItem.layout,
- selectedItem.source,
function(exists) {
if (exists) {
self.currentWallpaper_ = wallpaperURL;
diff --git a/chrome/browser/resources/downloads/downloads.css b/chrome/browser/resources/downloads/downloads.css
index b0327921c9..bbc2c1065b 100644
--- a/chrome/browser/resources/downloads/downloads.css
+++ b/chrome/browser/resources/downloads/downloads.css
@@ -126,6 +126,10 @@ html[dir=rtl] .download.otr > .show-dangerous {
opacity: 1;
}
+.malware-description {
+ color: rgb(196, 42, 23);
+}
+
.progress {
height: 48px;
left: 0;
diff --git a/chrome/browser/resources/downloads/downloads.js b/chrome/browser/resources/downloads/downloads.js
index 7522c5f2a9..ecbb73c108 100644
--- a/chrome/browser/resources/downloads/downloads.js
+++ b/chrome/browser/resources/downloads/downloads.js
@@ -355,14 +355,32 @@ function Download(download) {
this.danger_ = createElementWithClassName('div', 'show-dangerous');
this.node.appendChild(this.danger_);
+ this.dangerNodeImg_ = createElementWithClassName('img', 'icon');
+ this.danger_.appendChild(this.dangerNodeImg_);
+
this.dangerDesc_ = document.createElement('div');
this.danger_.appendChild(this.dangerDesc_);
- this.dangerSave_ = createButton(this.saveDangerous_.bind(this),
+ // Buttons for the malicious case.
+ this.malwareNodeControls_ = createElementWithClassName('div', 'controls');
+ this.malwareSave_ = createLink(
+ this.saveDangerous_.bind(this),
+ loadTimeData.getString('danger_restore'));
+ this.malwareNodeControls_.appendChild(this.malwareSave_);
+ this.malwareDiscard_ = createLink(
+ this.discardDangerous_.bind(this),
+ loadTimeData.getString('control_removefromlist'));
+ this.malwareNodeControls_.appendChild(this.malwareDiscard_);
+ this.danger_.appendChild(this.malwareNodeControls_);
+
+ // Buttons for the dangerous but not malicious case.
+ this.dangerSave_ = createButton(
+ this.saveDangerous_.bind(this),
loadTimeData.getString('danger_save'));
this.danger_.appendChild(this.dangerSave_);
- this.dangerDiscard_ = createButton(this.discardDangerous_.bind(this),
+ this.dangerDiscard_ = createButton(
+ this.discardDangerous_.bind(this),
loadTimeData.getString('danger_discard'));
this.danger_.appendChild(this.dangerDiscard_);
@@ -426,7 +444,6 @@ Download.prototype.update = function(download) {
this.state_ = download.state;
this.fileExternallyRemoved_ = download.file_externally_removed;
this.dangerType_ = download.danger_type;
- this.finchString_ = download.finch_string;
this.lastReasonDescription_ = download.last_reason_text;
this.byExtensionId_ = download.by_ext_id;
this.byExtensionName_ = download.by_ext_name;
@@ -440,28 +457,7 @@ Download.prototype.update = function(download) {
this.received_ = download.received;
if (this.state_ == Download.States.DANGEROUS) {
- if (this.dangerType_ == Download.DangerType.DANGEROUS_FILE) {
- this.dangerDesc_.textContent = loadTimeData.getStringF('danger_file_desc',
- this.fileName_);
- } else if (this.dangerType_ == Download.DangerType.DANGEROUS_URL) {
- this.dangerDesc_.textContent = loadTimeData.getString('danger_url_desc');
- } else if (this.dangerType_ == Download.DangerType.DANGEROUS_CONTENT ||
- this.dangerType_ == Download.DangerType.DANGEROUS_HOST) {
- this.dangerDesc_.textContent = loadTimeData.getStringF(
- 'danger_content_desc', this.fileName_);
- } else if (this.dangerType_ == Download.DangerType.UNCOMMON_CONTENT) {
- this.dangerDesc_.textContent = loadTimeData.getStringF(
- 'danger_uncommon_desc', this.fileName_);
- } else if (this.dangerType_ == Download.DangerType.POTENTIALLY_UNWANTED) {
- this.dangerDesc_.textContent = loadTimeData.getStringF(
- 'danger_potentially_unwanted_desc', this.fileName_);
- }
- if (this.finchString_) {
- // Finch trial overrides the normal display string.
- this.dangerDesc_.textContent = this.finchString_;
- }
- this.danger_.style.display = 'block';
- this.safe_.style.display = 'none';
+ this.updateDangerousFile();
} else {
downloads.scheduleIconLoad(this.nodeImg_,
'chrome://fileicon/' +
@@ -567,6 +563,67 @@ Download.prototype.update = function(download) {
};
/**
+ * Decorates the icons, strings, and buttons for a download to reflect the
+ * danger level of a file. Dangerous & malicious files are treated differently.
+ */
+Download.prototype.updateDangerousFile = function() {
+ switch (this.dangerType_) {
+ case Download.DangerType.DANGEROUS_FILE: {
+ this.dangerDesc_.textContent = loadTimeData.getStringF(
+ 'danger_file_desc', this.fileName_);
+ break;
+ }
+ case Download.DangerType.DANGEROUS_URL: {
+ this.dangerDesc_.textContent = loadTimeData.getString('danger_url_desc');
+ break;
+ }
+ case Download.DangerType.DANGEROUS_CONTENT: // Fall through.
+ case Download.DangerType.DANGEROUS_HOST: {
+ this.dangerDesc_.textContent = loadTimeData.getStringF(
+ 'danger_content_desc', this.fileName_);
+ break;
+ }
+ case Download.DangerType.UNCOMMON_CONTENT: {
+ this.dangerDesc_.textContent = loadTimeData.getStringF(
+ 'danger_uncommon_desc', this.fileName_);
+ break;
+ }
+ case Download.DangerType.POTENTIALLY_UNWANTED: {
+ this.dangerDesc_.textContent = loadTimeData.getStringF(
+ 'danger_potentially_unwanted_desc', this.fileName_);
+ break;
+ }
+ }
+
+ if (this.dangerType_ == Download.DangerType.DANGEROUS_FILE) {
+ downloads.scheduleIconLoad(
+ this.dangerNodeImg_,
+ 'chrome://theme/IDR_WARNING?scale=' + window.devicePixelRatio + 'x');
+ } else {
+ downloads.scheduleIconLoad(
+ this.dangerNodeImg_,
+ 'chrome://theme/IDR_SAFEBROWSING_WARNING?scale=' +
+ window.devicePixelRatio + 'x');
+ this.dangerDesc_.className = 'malware-description';
+ }
+
+ if (this.dangerType_ == Download.DangerType.DANGEROUS_CONTENT ||
+ this.dangerType_ == Download.DangerType.DANGEROUS_HOST ||
+ this.dangerType_ == Download.DangerType.DANGEROUS_URL) {
+ this.malwareNodeControls_.style.display = 'block';
+ this.dangerDiscard_.style.display = 'none';
+ this.dangerSave_.style.display = 'none';
+ } else {
+ this.malwareNodeControls_.style.display = 'none';
+ this.dangerDiscard_.style.display = 'inline';
+ this.dangerSave_.style.display = 'inline';
+ }
+
+ this.danger_.style.display = 'block';
+ this.safe_.style.display = 'none';
+};
+
+/**
* Removes applicable bits from the DOM in preparation for deletion.
*/
Download.prototype.clear = function() {
@@ -579,6 +636,9 @@ Download.prototype.clear = function() {
this.controlPause_.onclick = null;
this.controlResume_.onclick = null;
this.dangerDiscard_.onclick = null;
+ this.dangerSave_.onclick = null;
+ this.malwareDiscard_.onclick = null;
+ this.malwareSave_.onclick = null;
this.node.innerHTML = '';
};
diff --git a/chrome/browser/resources/extensions/extension_command_list.js b/chrome/browser/resources/extensions/extension_command_list.js
index 3f1b05ff25..3d6d779210 100644
--- a/chrome/browser/resources/extensions/extension_command_list.js
+++ b/chrome/browser/resources/extensions/extension_command_list.js
@@ -262,6 +262,29 @@ cr.define('options', function() {
commandClear.title = loadTimeData.getString('extensionCommandsDelete');
commandClear.addEventListener('click', this.handleClear_.bind(this));
+ if (command.scope_ui_visible) {
+ var commandScope = node.querySelector('.command-scope');
+ commandScope.hidden = false;
+ commandScope.id = this.createElementId_(
+ 'toggleCommandScope', command.extension_id, command.command_name);
+ if (command.global) {
+ // TODO(finnur): Use another icon, this is just a placeholder.
+ commandScope.src = 'chrome://theme/IDR_ACCESSED_COOKIES';
+ commandScope.title =
+ loadTimeData.getString('extensionCommandsGlobalTooltip');
+ } else {
+ commandScope.src = 'chrome://theme/IDR_PRODUCT_LOGO_16';
+ var tooltip = command.extension_action ?
+ 'extensionCommandsNotGlobalPermanentTooltip' :
+ 'extensionCommandsNotGlobalTooltip';
+ commandScope.title = loadTimeData.getString(tooltip);
+ }
+ if (!command.extension_action) {
+ commandScope.addEventListener(
+ 'click', this.handleToggleCommandScope_.bind(this));
+ }
+ }
+
this.appendChild(node);
},
@@ -423,6 +446,17 @@ cr.define('options', function() {
},
/**
+ * A handler for the toggling the scope of the command.
+ * @param {Event} event The mouse event to consider.
+ * @private
+ */
+ handleToggleCommandScope_: function(event) {
+ var parsed = this.parseElementId_('toggleCommandScope', event.target.id);
+ chrome.send('toggleCommandScope',
+ [parsed.extensionId, parsed.commandName]);
+ },
+
+ /**
* A utility function to create a unique element id based on a namespace,
* extension id and a command name.
* @param {string} namespace The namespace to prepend the id with.
diff --git a/chrome/browser/resources/extensions/extension_commands_overlay.css b/chrome/browser/resources/extensions/extension_commands_overlay.css
index 13624174b8..098619d244 100644
--- a/chrome/browser/resources/extensions/extension_commands_overlay.css
+++ b/chrome/browser/resources/extensions/extension_commands_overlay.css
@@ -56,6 +56,11 @@
margin-top: 1px;
}
+.command-scope {
+ padding-left: 0.3em;
+ padding-top: 0.6em;
+}
+
.capturing {
background: rgb(243, 244, 255);
border: solid 1px rgb(140, 147, 255);
diff --git a/chrome/browser/resources/extensions/extension_commands_overlay.html b/chrome/browser/resources/extensions/extension_commands_overlay.html
index 8bd0af637a..b07e838410 100644
--- a/chrome/browser/resources/extensions/extension_commands_overlay.html
+++ b/chrome/browser/resources/extensions/extension_commands_overlay.html
@@ -46,6 +46,7 @@
src="chrome://theme/IDR_EXTENSION_COMMAND_CLOSE"
><span class="command-shortcut-text" tabindex="0"
></span></span></span>
+ <img class="command-scope" width="16" height="16" hidden>
</div>
</div>
</div>
diff --git a/chrome/browser/resources/feedback/js/feedback.js b/chrome/browser/resources/feedback/js/feedback.js
index db9932ab28..a559be6957 100644
--- a/chrome/browser/resources/feedback/js/feedback.js
+++ b/chrome/browser/resources/feedback/js/feedback.js
@@ -208,6 +208,9 @@ function performanceFeedbackChanged() {
* .) Screenshot taken -> . Show Feedback window.
*/
function initialize() {
+ // TODO(rkc): Remove logging once crbug.com/284662 is closed.
+ console.log('FEEDBACK_DEBUG: feedback.js: initialize()');
+
// Add listener to receive the feedback info object.
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.sentFromEventPage) {
@@ -260,6 +263,8 @@ function initialize() {
});
window.addEventListener('DOMContentLoaded', function() {
+ // TODO(rkc): Remove logging once crbug.com/284662 is closed.
+ console.log('FEEDBACK_DEBUG: feedback.js: DOMContentLoaded');
// Ready to receive the feedback object.
chrome.runtime.sendMessage({ready: true});
diff --git a/chrome/browser/resources/file_manager/css/file_manager.css b/chrome/browser/resources/file_manager/css/file_manager.css
index b057fb015c..5bba9a943c 100644
--- a/chrome/browser/resources/file_manager/css/file_manager.css
+++ b/chrome/browser/resources/file_manager/css/file_manager.css
@@ -1925,6 +1925,15 @@ menuitem#thumbnail-view[lead]:not([disabled]) {
display: none;
}
+#conflict-confirm-dialog .apply-all-line {
+ margin: 8px;
+ text-align: end;
+}
+
+#conflict-confirm-dialog input {
+ width: auto;
+}
+
/* Progress center */
#progress-center {
@@ -1983,6 +1992,8 @@ menuitem#thumbnail-view[lead]:not([disabled]) {
display: block;
height: 17px;
opacity: 1;
+ overflow: hidden;
+ text-overflow: ellipsis;
white-space: nowrap;
}
diff --git a/chrome/browser/resources/file_manager/css/file_types.css b/chrome/browser/resources/file_manager/css/file_types.css
index 91f5be131a..91459ed92b 100644
--- a/chrome/browser/resources/file_manager/css/file_types.css
+++ b/chrome/browser/resources/file_manager/css/file_types.css
@@ -173,6 +173,20 @@ list.autocomplete-suggestions [selected] [file-type-icon='gtable'] {
url('../images/files/file_types/200/gtable_white.png') 2x);
}
+[file-type-icon='gform'] {
+ background-image: -webkit-image-set(
+ url('../images/files/file_types/100/form.png') 1x,
+ url('../images/files/file_types/200/form.png') 2x);
+}
+
+tree:focus .tree-item[selected] > .tree-row > [file-type-icon='gform'],
+list:focus [selected] [file-type-icon='gform'],
+list.autocomplete-suggestions [selected] [file-type-icon='gform'] {
+ background-image: -webkit-image-set(
+ url('../images/files/file_types/100/form_white.png') 1x,
+ url('../images/files/file_types/200/form_white.png') 2x);
+}
+
[file-type-icon='image'] {
background-image: -webkit-image-set(
url('../images/files/file_types/100/image.png') 1x,
diff --git a/chrome/browser/resources/file_manager/css/gallery.css b/chrome/browser/resources/file_manager/css/gallery.css
index ebad7bd2a3..7680f4d310 100644
--- a/chrome/browser/resources/file_manager/css/gallery.css
+++ b/chrome/browser/resources/file_manager/css/gallery.css
@@ -74,41 +74,41 @@ body {
.gallery[tools] .image-container[cursor='move'] {
cursor: -webkit-image-set(
url('../images/gallery/cursor_move.png') 1x,
- url('../images/gallery/2x/cursor_move.png') 2x) 15 15;
+ url('../images/gallery/2x/cursor_move.png') 2x) 15 15, auto;
}
.gallery[tools] .image-container[cursor='crop'] {
cursor: -webkit-image-set(
url('../images/gallery/cursor_crop.png') 1x,
- url('../images/gallery/2x/cursor_crop.png') 2x) 15 15;
+ url('../images/gallery/2x/cursor_crop.png') 2x) 15 15, auto;
}
.gallery[tools] .image-container[cursor='n-resize'],
.gallery[tools] .image-container[cursor='s-resize'] {
cursor: -webkit-image-set(
url('../images/gallery/cursor_updown.png') 1x,
- url('../images/gallery/2x/cursor_updown.png') 2x) 15 15;
+ url('../images/gallery/2x/cursor_updown.png') 2x) 15 15, auto;
}
.gallery[tools] .image-container[cursor='e-resize'],
.gallery[tools] .image-container[cursor='w-resize'] {
cursor: -webkit-image-set(
url('../images/gallery/cursor_leftright.png') 1x,
- url('../images/gallery/2x/cursor_leftright.png') 2x) 15 15;
+ url('../images/gallery/2x/cursor_leftright.png') 2x) 15 15, auto;
}
.gallery[tools] .image-container[cursor='nw-resize'],
.gallery[tools] .image-container[cursor='se-resize'] {
cursor: -webkit-image-set(
url('../images/gallery/cursor_nwse.png') 1x,
- url('../images/gallery/2x/cursor_nwse.png') 2x) 15 15;
+ url('../images/gallery/2x/cursor_nwse.png') 2x) 15 15, auto;
}
.gallery[tools] .image-container[cursor='ne-resize'],
.gallery[tools] .image-container[cursor='sw-resize'] {
cursor: -webkit-image-set(
url('../images/gallery/cursor_swne.png') 1x,
- url('../images/gallery/2x/cursor_swne.png') 2x) 15 15;
+ url('../images/gallery/2x/cursor_swne.png') 2x) 15 15, auto;
}
.gallery .image-container > .image {
diff --git a/chrome/browser/resources/file_manager/js/background.js b/chrome/browser/resources/file_manager/js/background.js
index d63ab6210f..379b2fd288 100644
--- a/chrome/browser/resources/file_manager/js/background.js
+++ b/chrome/browser/resources/file_manager/js/background.js
@@ -594,6 +594,7 @@ function initApp() {
// Fetch strings and initialize the context menu.
queue.run(function(callback) {
chrome.fileBrowserPrivate.getStrings(function(strings) {
+ loadTimeData.data = strings;
initContextMenu(strings);
chrome.storage.local.set({strings: strings}, callback);
});
diff --git a/chrome/browser/resources/file_manager/js/file_grid.js b/chrome/browser/resources/file_manager/js/file_grid.js
index 5d31df09b2..2daec0cd4a 100644
--- a/chrome/browser/resources/file_manager/js/file_grid.js
+++ b/chrome/browser/resources/file_manager/js/file_grid.js
@@ -43,6 +43,7 @@ FileGrid.decorate = function(self, metadataCache) {
self.scrollBar_ = new MainPanelScrollBar();
self.scrollBar_.initialize(self.parentNode, self);
+ self.setBottomMarginForPanel(0);
self.itemConstructor = function(entry) {
var item = self.ownerDocument.createElement('LI');
@@ -228,7 +229,9 @@ FileGrid.Item.decorate = function(li, entry, grid) {
* @param {number} margin Margin to be set in px.
*/
FileGrid.prototype.setBottomMarginForPanel = function(margin) {
- this.style.paddingBottom = margin + 'px';
+ // +20 bottom margin is needed to match the bottom margin size with the
+ // margin between its items.
+ this.style.paddingBottom = (margin + 20) + 'px';
this.scrollBar_.setBottomMarginForPanel(margin);
};
diff --git a/chrome/browser/resources/file_manager/js/file_manager.js b/chrome/browser/resources/file_manager/js/file_manager.js
index d0ed3f3c75..95c76b4114 100644
--- a/chrome/browser/resources/file_manager/js/file_manager.js
+++ b/chrome/browser/resources/file_manager/js/file_manager.js
@@ -15,6 +15,28 @@
*/
function FileManager() {
this.initializeQueue_ = new AsyncUtil.Group();
+
+ /**
+ * Current list type.
+ * @type {ListType}
+ * @private
+ */
+ this.listType_ = null;
+
+ /**
+ * Whether to suppress the focus moving or not.
+ * This is used to filter out focusing by mouse.
+ * @type {boolean}
+ * @private
+ */
+ this.suppressFocus_ = false;
+
+ /**
+ * SelectionHandler.
+ * @type {SelectionHandler}
+ * @private
+ */
+ this.selectionHandler_ = null;
}
/**
@@ -161,8 +183,6 @@ var BOTTOM_MARGIN_FOR_PREVIEW_PANEL_PX = 52;
// Get startup preferences.
this.viewOptions_ = {};
group.add(function(done) {
- this.dialogType = this.params_.type || DialogType.FULL_PAGE;
- this.startupPrefName_ = 'file-manager-' + this.dialogType;
util.platform.getPreference(this.startupPrefName_, function(value) {
// Load the global default options.
try {
@@ -251,7 +271,7 @@ var BOTTOM_MARGIN_FOR_PREVIEW_PANEL_PX = 52;
dm.addEventListener('scan-cancelled', this.onScanCancelled_.bind(this));
dm.addEventListener('scan-updated', this.onScanUpdated_.bind(this));
dm.addEventListener('rescan-completed',
- this.refreshCurrentDirectoryMetadata_.bind(this));
+ this.onRescanCompleted_.bind(this));
var sm = this.directoryModel_.getFileListSelection();
sm.addEventListener('change', function() {
@@ -461,10 +481,6 @@ var BOTTOM_MARGIN_FOR_PREVIEW_PANEL_PX = 52;
};
FileManager.prototype.onMaximize = function() {
- // Do not maximize when running via chrome://files in a browser.
- if (util.platform.runningInBrowser())
- return;
-
var appWindow = chrome.app.window.current();
if (appWindow.isMaximized())
appWindow.restore();
@@ -473,10 +489,6 @@ var BOTTOM_MARGIN_FOR_PREVIEW_PANEL_PX = 52;
};
FileManager.prototype.onClose = function() {
- // Do not close when running via chrome://files in a browser.
- if (util.platform.runningInBrowser())
- return;
-
window.close();
};
@@ -546,6 +558,7 @@ var BOTTOM_MARGIN_FOR_PREVIEW_PANEL_PX = 52;
FileManager.prototype.initializeUI = function(dialogDom, callback) {
this.dialogDom_ = dialogDom;
+ this.document_ = this.dialogDom_.ownerDocument;
this.initializeQueue_.add(
this.initEssentialUI_.bind(this),
@@ -580,6 +593,12 @@ var BOTTOM_MARGIN_FOR_PREVIEW_PANEL_PX = 52;
{};
this.defaultPath = this.params_.defaultPath;
}
+
+ // Initialize the member variables that depend this.params_.
+ this.dialogType = this.params_.type || DialogType.FULL_PAGE;
+ this.startupPrefName_ = 'file-manager-' + this.dialogType;
+ this.fileTypes_ = this.params_.typeList || [];
+
callback();
};
@@ -653,20 +672,7 @@ var BOTTOM_MARGIN_FOR_PREVIEW_PANEL_PX = 52;
* @private
*/
FileManager.prototype.initEssentialUI_ = function(callback) {
- this.listType_ = null;
-
- this.filesystemObserverId_ = null;
- this.driveObserverId_ = null;
-
- this.document_ = this.dialogDom_.ownerDocument;
- this.dialogType = this.params_.type || DialogType.FULL_PAGE;
- this.startupPrefName_ = 'file-manager-' + this.dialogType;
-
- // Used to filter out focusing by mouse.
- this.suppressFocus_ = false;
-
// Optional list of file types.
- this.fileTypes_ = this.params_.typeList || [];
metrics.recordEnum('Create', this.dialogType,
[DialogType.SELECT_FOLDER,
DialogType.SELECT_UPLOAD_FOLDER,
@@ -675,34 +681,14 @@ var BOTTOM_MARGIN_FOR_PREVIEW_PANEL_PX = 52;
DialogType.SELECT_OPEN_MULTI_FILE,
DialogType.FULL_PAGE]);
- this.selectionHandler_ = null;
-
+ // Create the metadata cache.
this.metadataCache_ = MetadataCache.createFull();
- this.hasFooterPanel_ =
- this.dialogType == DialogType.SELECT_SAVEAS_FILE ||
- this.dialogType == DialogType.SELECT_FOLDER;
-
- // If the footer panel exists, the buttons are placed there. Otherwise,
- // the buttons are on the preview panel.
- var parentPanelOfButtons = this.dialogDom_.querySelector(
- !this.hasFooterPanel_ ? '.preview-panel' : '.dialog-footer');
- parentPanelOfButtons.classList.add('button-panel');
- this.fileTypeSelector_ = parentPanelOfButtons.querySelector('.file-type');
- this.okButton_ = parentPanelOfButtons.querySelector('.ok');
- this.cancelButton_ = parentPanelOfButtons.querySelector('.cancel');
-
- // Pre-populate the static localized strings.
- i18nTemplate.process(this.document_, loadTimeData);
-
- // Initialize the header.
- this.dialogDom_.querySelector('#app-name').innerText =
- chrome.runtime.getManifest().name;
-
- this.initDialogType_();
-
// Create the root view of FileManager.
- this.ui_ = new FileManagerUI(this.dialogDom_);
+ this.ui_ = new FileManagerUI(this.dialogDom_, this.dialogType);
+ this.fileTypeSelector_ = this.ui_.fileTypeSelector;
+ this.okButton_ = this.ui_.okButton;
+ this.cancelButton_ = this.ui_.cancelButton;
// Show the window as soon as the UI pre-initialization is done.
if (this.dialogType == DialogType.FULL_PAGE &&
@@ -798,13 +784,6 @@ var BOTTOM_MARGIN_FOR_PREVIEW_PANEL_PX = 52;
this.backgroundPage_.progressCenter.getSummarizedItem());
}
this.backgroundPage_.progressCenter.addEventListener(
- ProgressCenterEvent.ITEM_ADDED,
- function(event) {
- this.progressCenterPanel_.updateItem(
- event.item,
- this.backgroundPage_.progressCenter.getSummarizedItem());
- }.bind(this));
- this.backgroundPage_.progressCenter.addEventListener(
ProgressCenterEvent.ITEM_UPDATED,
function(event) {
this.progressCenterPanel_.updateItem(
@@ -1114,8 +1093,6 @@ var BOTTOM_MARGIN_FOR_PREVIEW_PANEL_PX = 52;
for (var i = 0; i < cm.totalSize; i++) {
prefs.columns.push(cm.getWidth(i));
}
- if (DialogType.isModal(this.dialogType))
- prefs.listType = this.listType;
// Save the global default.
util.platform.setPreference(this.startupPrefName_, JSON.stringify(prefs));
@@ -1576,50 +1553,6 @@ var BOTTOM_MARGIN_FOR_PREVIEW_PANEL_PX = 52;
};
/**
- * Tweak the UI to become a particular kind of dialog, as determined by the
- * dialog type parameter passed to the constructor.
- *
- * @private
- */
- FileManager.prototype.initDialogType_ = function() {
- var defaultTitle;
- var okLabel = str('OPEN_LABEL');
-
- switch (this.dialogType) {
- case DialogType.SELECT_FOLDER:
- defaultTitle = str('SELECT_FOLDER_TITLE');
- break;
-
- case DialogType.SELECT_UPLOAD_FOLDER:
- defaultTitle = str('SELECT_UPLOAD_FOLDER_TITLE');
- okLabel = str('UPLOAD_LABEL');
- break;
-
- case DialogType.SELECT_OPEN_FILE:
- defaultTitle = str('SELECT_OPEN_FILE_TITLE');
- break;
-
- case DialogType.SELECT_OPEN_MULTI_FILE:
- defaultTitle = str('SELECT_OPEN_MULTI_FILE_TITLE');
- break;
-
- case DialogType.SELECT_SAVEAS_FILE:
- defaultTitle = str('SELECT_SAVEAS_FILE_TITLE');
- okLabel = str('SAVE_LABEL');
- break;
-
- case DialogType.FULL_PAGE:
- break;
-
- default:
- throw new Error('Unknown dialog type: ' + this.dialogType);
- }
-
- this.okButton_.textContent = okLabel;
- this.dialogDom_.setAttribute('type', this.dialogType);
- };
-
- /**
* Unmounts device.
* @param {string} path Path to a volume to unmount.
*/
@@ -2732,6 +2665,15 @@ var BOTTOM_MARGIN_FOR_PREVIEW_PANEL_PX = 52;
};
/**
+ * Handle the 'rescan-completed' from the DirectoryModel.
+ * @private
+ */
+ FileManager.prototype.onRescanCompleted_ = function() {
+ this.refreshCurrentDirectoryMetadata_();
+ this.selectionHandler_.onFileSelectionChanged();
+ };
+
+ /**
* @private
*/
FileManager.prototype.cancelSpinnerTimeout_ = function() {
@@ -3666,6 +3608,7 @@ var BOTTOM_MARGIN_FOR_PREVIEW_PANEL_PX = 52;
}
this.defaultActionMenuItem_.label = defaultItem.title;
+ this.defaultActionMenuItem_.disabled = !!defaultItem.disabled;
this.defaultActionMenuItem_.taskId = defaultItem.taskId;
}
@@ -3674,6 +3617,8 @@ var BOTTOM_MARGIN_FOR_PREVIEW_PANEL_PX = 52;
this.openWithCommand_.canExecuteChange();
this.openWithCommand_.setHidden(!(defaultItem && isMultiple));
+ this.openWithCommand_.disabled = defaultItem && !!defaultItem.disabled;
+
this.defaultActionMenuItem_.hidden = !defaultItem;
defaultActionSeparator.hidden = !defaultItem;
};
diff --git a/chrome/browser/resources/file_manager/js/file_operation_manager.js b/chrome/browser/resources/file_manager/js/file_operation_manager.js
index 48a8b7b8a3..3f17f51bff 100644
--- a/chrome/browser/resources/file_manager/js/file_operation_manager.js
+++ b/chrome/browser/resources/file_manager/js/file_operation_manager.js
@@ -275,6 +275,8 @@ function FileOperationManager() {
this.unloadTimeout_ = null;
this.eventRouter_ = new FileOperationManager.EventRouter();
+
+ Object.seal(this);
}
/**
@@ -315,14 +317,16 @@ FileOperationManager.EventRouter.prototype.__proto__ = cr.EventTarget.prototype;
* "ERROR" or "CANCELLED". TODO(hidehiko): Use enum.
* @param {Object} status Current FileOperationManager's status. See also
* FileOperationManager.getStatus().
+ * @param {string} taskId ID of task related with the event.
* @param {FileOperationManager.Error=} opt_error The info for the error. This
* should be set iff the reason is "ERROR".
*/
FileOperationManager.EventRouter.prototype.sendProgressEvent = function(
- reason, status, opt_error) {
+ reason, status, taskId, opt_error) {
var event = new Event('copy-progress');
event.reason = reason;
event.status = status;
+ event.taskId = taskId;
if (opt_error)
event.error = opt_error;
this.dispatchEvent(event);
@@ -349,9 +353,10 @@ FileOperationManager.EventRouter.prototype.sendEntryChangedEvent = function(
* or "ERROR". TODO(hidehiko): Use enum.
* @param {Array.<string>} urls An array of URLs which are affected by delete
* operation.
+ * @param {string} taskId ID of task related with the event.
*/
FileOperationManager.EventRouter.prototype.sendDeleteEvent = function(
- reason, urls) {
+ reason, urls, taskId) {
var event = new Event('delete');
event.reason = reason;
event.urls = urls;
@@ -1083,9 +1088,10 @@ FileOperationManager.prototype.requestCancel = function(opt_callback) {
* @private
*/
FileOperationManager.prototype.doCancel_ = function() {
+ var taskId = this.copyTasks_[0].taskId;
this.resetQueue_();
this.cancelRequested_ = false;
- this.eventRouter_.sendProgressEvent('CANCELLED', this.getStatus());
+ this.eventRouter_.sendProgressEvent('CANCELLED', this.getStatus(), taskId);
};
/**
@@ -1121,6 +1127,7 @@ FileOperationManager.prototype.paste = function(
this.eventRouter_.sendProgressEvent(
'ERROR',
this.getStatus(),
+ this.generateTaskId_(null),
new FileOperationManager.Error(
util.FileOperationErrorType.FILESYSTEM_ERROR, error));
}.bind(this);
@@ -1213,6 +1220,7 @@ FileOperationManager.prototype.queueCopy_ = function(
task = new FileOperationManager.CopyTask(entries, targetDirEntry);
}
+ task.taskId = this.generateTaskId_(this.copyTasks_);
task.initialize(function() {
this.copyTasks_.push(task);
this.maybeScheduleCloseBackgroundPage_();
@@ -1223,7 +1231,9 @@ FileOperationManager.prototype.queueCopy_ = function(
} else {
// Force to update the progress of butter bar when there are new tasks
// coming while servicing current task.
- this.eventRouter_.sendProgressEvent('PROGRESS', this.getStatus());
+ this.eventRouter_.sendProgressEvent('PROGRESS',
+ this.getStatus(),
+ task.taskId);
}
}.bind(this));
@@ -1240,7 +1250,9 @@ FileOperationManager.prototype.serviceAllTasks_ = function() {
var self = this;
var onTaskProgress = function() {
- self.eventRouter_.sendProgressEvent('PROGRESS', self.getStatus());
+ self.eventRouter_.sendProgressEvent('PROGRESS',
+ self.getStatus(),
+ self.copyTasks_[0].taskId);
};
var onEntryChanged = function(kind, entry) {
@@ -1248,9 +1260,13 @@ FileOperationManager.prototype.serviceAllTasks_ = function() {
};
var onTaskError = function(err) {
+ var taskId = self.copyTasks_[0].taskId;
if (self.maybeCancel_())
return;
- self.eventRouter_.sendProgressEvent('ERROR', self.getStatus(), err);
+ self.eventRouter_.sendProgressEvent('ERROR',
+ self.getStatus(),
+ taskId,
+ err);
self.resetQueue_();
};
@@ -1259,12 +1275,15 @@ FileOperationManager.prototype.serviceAllTasks_ = function() {
return;
// The task at the front of the queue is completed. Pop it from the queue.
+ var taskId = self.copyTasks_[0].taskId;
self.copyTasks_.shift();
self.maybeScheduleCloseBackgroundPage_();
if (!self.copyTasks_.length) {
// All tasks have been serviced, clean up and exit.
- self.eventRouter_.sendProgressEvent('SUCCESS', self.getStatus());
+ self.eventRouter_.sendProgressEvent('SUCCESS',
+ self.getStatus(),
+ taskId);
self.resetQueue_();
return;
}
@@ -1273,14 +1292,18 @@ FileOperationManager.prototype.serviceAllTasks_ = function() {
// right after one task finished in the queue. We treat all tasks as one
// big task logically, so there is only one BEGIN/SUCCESS event pair for
// these continuous tasks.
- self.eventRouter_.sendProgressEvent('PROGRESS', self.getStatus());
+ self.eventRouter_.sendProgressEvent('PROGRESS',
+ self.getStatus(),
+ self.copyTasks_[0].taskId);
self.copyTasks_[0].run(
onEntryChanged, onTaskProgress, onTaskSuccess, onTaskError);
};
// If the queue size is 1 after pushing our task, it was empty before,
// so we need to kick off queue processing and dispatch BEGIN event.
- this.eventRouter_.sendProgressEvent('BEGIN', this.getStatus());
+ this.eventRouter_.sendProgressEvent('BEGIN',
+ this.getStatus(),
+ self.copyTasks_[0].taskId);
this.copyTasks_[0].run(
onEntryChanged, onTaskProgress, onTaskSuccess, onTaskError);
};
@@ -1296,7 +1319,10 @@ FileOperationManager.DELETE_TIMEOUT = 30 * 1000;
* @param {Array.<Entry>} entries The entries.
*/
FileOperationManager.prototype.deleteEntries = function(entries) {
- var task = { entries: entries };
+ var task = {
+ entries: entries,
+ taskId: this.generateTaskId_(this.deleteTasks_)
+ };
this.deleteTasks_.push(task);
this.maybeScheduleCloseBackgroundPage_();
if (this.deleteTasks_.length == 1)
@@ -1320,10 +1346,12 @@ FileOperationManager.prototype.serviceAllDeleteTasks_ = function() {
};
var onTaskSuccess = function() {
- var urls = getTaskUrls(this.deleteTasks_.shift());
+ var urls = getTaskUrls(this.deleteTasks_[0]);
+ var taskId = this.deleteTasks_[0].taskId;
+ this.deleteTasks_.shift();
if (!this.deleteTasks_.length) {
// All tasks have been serviced, clean up and exit.
- this.eventRouter_.sendDeleteEvent('SUCCESS', urls);
+ this.eventRouter_.sendDeleteEvent('SUCCESS', urls, taskId);
this.maybeScheduleCloseBackgroundPage_();
return;
}
@@ -1332,21 +1360,28 @@ FileOperationManager.prototype.serviceAllDeleteTasks_ = function() {
// right after one task finished in the queue. We treat all tasks as one
// big task logically, so there is only one BEGIN/SUCCESS event pair for
// these continuous tasks.
- this.eventRouter_.sendDeleteEvent('PROGRESS', urls);
+ this.eventRouter_.sendDeleteEvent('PROGRESS',
+ urls,
+ this.deleteTasks_[0].taskId);
this.serviceDeleteTask_(this.deleteTasks_[0], onTaskSuccess, onTaskFailure);
}.bind(this);
var onTaskFailure = function(error) {
var urls = getTaskUrls(this.deleteTasks_[0]);
+ var taskId = this.deleteTasks_[0].taskId;
this.deleteTasks_ = [];
- this.eventRouter_.sendDeleteEvent('ERROR', urls);
+ this.eventRouter_.sendDeleteEvent('ERROR',
+ urls,
+ taskId);
this.maybeScheduleCloseBackgroundPage_();
}.bind(this);
// If the queue size is 1 after pushing our task, it was empty before,
// so we need to kick off queue processing and dispatch BEGIN event.
- this.eventRouter_.sendDeleteEvent('BEGIN', getTaskUrls(this.deleteTasks_[0]));
+ this.eventRouter_.sendDeleteEvent('BEGIN',
+ getTaskUrls(this.deleteTasks_[0]),
+ this.deleteTasks_[0].taskId);
this.serviceDeleteTask_(this.deleteTasks_[0], onTaskSuccess, onTaskFailure);
};
@@ -1409,6 +1444,7 @@ FileOperationManager.prototype.zipSelection = function(
var self = this;
var zipTask = new FileOperationManager.ZipTask(
selectionEntries, dirEntry, dirEntry);
+ zipTask.taskId = this.generateTaskId_(this.copyTasks_);
zipTask.zip = true;
zipTask.initialize(function() {
self.copyTasks_.push(zipTask);
@@ -1419,7 +1455,28 @@ FileOperationManager.prototype.zipSelection = function(
} else {
// Force to update the progress of butter bar when there are new tasks
// coming while servicing current task.
- self.eventRouter_.sendProgressEvent('PROGRESS', self.getStatus());
+ self.eventRouter_.sendProgressEvent('PROGRESS',
+ self.getStatus(),
+ self.copyTasks_[0].taskId);
}
});
};
+
+/**
+ * Generates new task ID.
+ *
+ * TODO(hirono): Remove the queue argument. The ID should be generated
+ * independenting on the queue.
+ * @param {Array.<FileOperationManager.Task>} queue Qeueu that the task is
+ * inserted to.
+ * @return {string} New task ID.
+ * @private
+ */
+FileOperationManager.prototype.generateTaskId_ = function(queue) {
+ if (queue) {
+ queue.taskIdCounter = queue.taskIdCounter || 0;
+ if (!queue.length)
+ queue.taskIdCounter++;
+ }
+ return 'file-operation-' + queue.taskIdCounter;
+};
diff --git a/chrome/browser/resources/file_manager/js/file_selection.js b/chrome/browser/resources/file_manager/js/file_selection.js
index d814b6b91a..34a75e1a0d 100644
--- a/chrome/browser/resources/file_manager/js/file_selection.js
+++ b/chrome/browser/resources/file_manager/js/file_selection.js
@@ -164,6 +164,29 @@ function FileSelectionHandler(fileManager) {
}
/**
+ * Create the temporary disabled action menu item.
+ * @return {Object} Created disabled item.
+ * @private
+ */
+FileSelectionHandler.createTemporaryDisabledActionMenuItem_ = function() {
+ if (!FileSelectionHandler.cachedDisabledActionMenuItem_) {
+ FileSelectionHandler.cachedDisabledActionMenuItem_ = {
+ label: str('ACTION_OPEN'),
+ disabled: true
+ };
+ }
+
+ return FileSelectionHandler.cachedDisabledActionMenuItem_;
+};
+
+/**
+ * Cached the temporary disabled action menu item. Used inside
+ * FileSelectionHandler.createTemporaryDisabledActionMenuItem_().
+ * @private
+ */
+FileSelectionHandler.cachedDisabledActionMenuItem_ = null;
+
+/**
* FileSelectionHandler extends cr.EventTarget.
*/
FileSelectionHandler.prototype.__proto__ = cr.EventTarget.prototype;
@@ -226,6 +249,17 @@ FileSelectionHandler.prototype.onFileSelectionChanged = function(event) {
}
this.lastFileSelectionTime_ = now;
+ if (this.fileManager_.dialogType === DialogType.FULL_PAGE &&
+ selection.directoryCount === 0 && selection.fileCount > 0) {
+ // Show disabled items for position calculation of the menu. They will be
+ // overridden in this.updateFileSelectionAsync().
+ this.fileManager_.updateContextMenuActionItems(
+ FileSelectionHandler.createTemporaryDisabledActionMenuItem_(), true);
+ } else {
+ // Update context menu.
+ this.fileManager_.updateContextMenuActionItems(null, false);
+ }
+
this.selectionUpdateTimer_ = setTimeout(function() {
this.selectionUpdateTimer_ = null;
if (this.selection == selection)
@@ -296,8 +330,8 @@ FileSelectionHandler.prototype.updateFileSelectionAsync = function(selection) {
if (this.selection != selection) return;
// Update the file tasks.
- if (this.fileManager_.dialogType == DialogType.FULL_PAGE &&
- selection.directoryCount == 0 && selection.fileCount > 0) {
+ if (this.fileManager_.dialogType === DialogType.FULL_PAGE &&
+ selection.directoryCount === 0 && selection.fileCount > 0) {
selection.createTasks(function() {
if (this.selection != selection)
return;
@@ -325,9 +359,6 @@ FileSelectionHandler.prototype.updateFileSelectionAsync = function(selection) {
if (this.fileManager_.commandHandler)
this.fileManager_.commandHandler.updateAvailability();
- // Update context menu.
- this.fileManager_.updateContextMenuActionItems(null, false);
-
// Inform tests it's OK to click buttons now.
if (selection.totalCount > 0) {
chrome.test.sendMessage('selection-change-complete');
diff --git a/chrome/browser/resources/file_manager/js/file_tasks.js b/chrome/browser/resources/file_manager/js/file_tasks.js
index 41176b6341..2584d06f62 100644
--- a/chrome/browser/resources/file_manager/js/file_tasks.js
+++ b/chrome/browser/resources/file_manager/js/file_tasks.js
@@ -244,9 +244,6 @@ FileTasks.prototype.processTasks_ = function(tasks) {
} else if (taskParts[2] == 'view-in-browser') {
task.iconType = 'generic';
task.title = loadTimeData.getString('ACTION_VIEW');
- } else if (taskParts[2] == 'install-crx') {
- task.iconType = 'generic';
- task.title = loadTimeData.getString('INSTALL_CRX');
}
}
diff --git a/chrome/browser/resources/file_manager/js/file_transfer_controller.js b/chrome/browser/resources/file_manager/js/file_transfer_controller.js
index 008147446e..106ac0dd5f 100644
--- a/chrome/browser/resources/file_manager/js/file_transfer_controller.js
+++ b/chrome/browser/resources/file_manager/js/file_transfer_controller.js
@@ -291,7 +291,6 @@ FileTransferController.prototype = {
*/
onDragStart_: function(list, event) {
// Check if a drag selection should be initiated or not.
- // TODO(hirono): Support drag selection on the grid view. crbug.com/247278
if (list.shouldStartDragSelection(event)) {
this.dragSelector_.startDragSelection(list, event);
return;
diff --git a/chrome/browser/resources/file_manager/js/file_type.js b/chrome/browser/resources/file_manager/js/file_type.js
index a30523549c..ea0ae9278e 100644
--- a/chrome/browser/resources/file_manager/js/file_type.js
+++ b/chrome/browser/resources/file_manager/js/file_type.js
@@ -89,6 +89,8 @@ FileType.types = [
subtype: 'table', pattern: /\.gtable$/i},
{type: 'hosted', icon: 'glink', name: 'GLINK_DOCUMENT_FILE_TYPE',
subtype: 'glink', pattern: /\.glink$/i},
+ {type: 'hosted', icon: 'gform', name: 'GFORM_DOCUMENT_FILE_TYPE',
+ subtype: 'form', pattern: /\.gform$/i},
// Others
{type: 'document', icon: 'pdf', name: 'PDF_DOCUMENT_FILE_TYPE',
diff --git a/chrome/browser/resources/file_manager/js/main_scripts.js b/chrome/browser/resources/file_manager/js/main_scripts.js
index 69b7efd558..eb335f509a 100644
--- a/chrome/browser/resources/file_manager/js/main_scripts.js
+++ b/chrome/browser/resources/file_manager/js/main_scripts.js
@@ -105,6 +105,7 @@
//<include src="text_measure.js"/>
//<include src="tree.css.js"/>
//<include src="ui/breadcrumbs_controller.js"/>
+//<include src="ui/conflict_dialog.js"/>
//<include src="ui/file_manager_ui.js"/>
//<include src="ui/preview_panel.js"/>
//<include src="ui/progress_center_panel.js"/>
diff --git a/chrome/browser/resources/file_manager/js/progress_center.js b/chrome/browser/resources/file_manager/js/progress_center.js
index 71e485e1ce..43c8b5c58b 100644
--- a/chrome/browser/resources/file_manager/js/progress_center.js
+++ b/chrome/browser/resources/file_manager/js/progress_center.js
@@ -12,13 +12,6 @@ var ProgressCenter = function() {
cr.EventTarget.call(this);
/**
- * ID counter.
- * @type {number}
- * @private
- */
- this.idCounter_ = 1;
-
- /**
* Default container.
* @type {ProgressItemContainer}
* @private
@@ -90,34 +83,19 @@ ProgressCenter.prototype = {
};
/**
- * Adds an item to the progress center.
- * @param {ProgressItem} item Item to be added.
- */
-ProgressCenter.prototype.addItem = function(item) {
- // If application window is opening, the item is displayed in the window.
- // Otherwise the item is displayed in notification.
- item.id = this.idCounter_++;
- item.container = this.targetContainer_;
- this.items_.push(item);
-
- if (item.status !== ProgressItemState.PROGRESSING)
- this.resetTimeout_.request(ProgressCenter.RESET_DELAY_TIME_MS_);
-
- var event = new Event(ProgressCenterEvent.ITEM_ADDED);
- event.item = item;
- this.dispatchEvent(event);
-};
-
-/**
* Updates the item in the progress center.
+ * If the item has a new ID, the item is added to the item list.
*
- * @param {ProgressCenterItem} item New contents of the item.
+ * @param {ProgressCenterItem} item Updated item.
*/
ProgressCenter.prototype.updateItem = function(item) {
var index = this.getItemIndex_(item.id);
- if (index === -1)
- return;
- this.items_[index] = item;
+ if (index === -1) {
+ item.container = this.targetContainer_;
+ this.items_.push(item);
+ } else {
+ this.items_[index] = item;
+ }
if (item.status !== ProgressItemState.PROGRESSING)
this.resetTimeout_.request(ProgressCenter.RESET_DELAY_TIME_MS_);
@@ -129,12 +107,12 @@ ProgressCenter.prototype.updateItem = function(item) {
/**
* Requests to cancel the progress item.
- * @param {number} id Progress ID to be requested to cancel.
+ * @param {string} id Progress ID to be requested to cancel.
*/
ProgressCenter.prototype.requestCancel = function(id) {
- var index = this.getItemIndex_(id);
- if (this.items_[index].cancelCallback)
- this.items_[index].cancelCallback();
+ var item = this.getItemById(id);
+ if (item && item.cancelCallback)
+ item.cancelCallback();
};
/**
@@ -163,20 +141,6 @@ ProgressCenter.prototype.switchContainer = function(newContainer) {
};
/**
- * Obtains item index that have the specifying ID.
- * @param {number} id Item ID.
- * @return {number} Item index. Returns -1 If the item is not found.
- * @private
- */
-ProgressCenter.prototype.getItemIndex_ = function(id) {
- for (var i = 0; i < this.items_.length; i++) {
- if (this.items_[i].id === id)
- return i;
- }
- return -1;
-};
-
-/**
* Obtains the summarized item to be displayed in the closed progress center
* panel.
* @return {ProgressCenterItem} Summarized item. Returns null if there is no
@@ -230,6 +194,30 @@ ProgressCenter.prototype.getSummarizedItem = function() {
};
/**
+ * Obtains item by ID.
+ * @param {string} id ID of progress item.
+ * @return {ProgressCenterItem} Progress center item having the specified
+ * ID. Null if the item is not found.
+ */
+ProgressCenter.prototype.getItemById = function(id) {
+ return this.items_[this.getItemIndex_(id)];
+};
+
+/**
+ * Obtains item index that have the specifying ID.
+ * @param {string} id Item ID.
+ * @return {number} Item index. Returns -1 If the item is not found.
+ * @private
+ */
+ProgressCenter.prototype.getItemIndex_ = function(id) {
+ for (var i = 0; i < this.items_.length; i++) {
+ if (this.items_[i].id === id)
+ return i;
+ }
+ return -1;
+};
+
+/**
* Passes the item to the ChromeOS's message center.
*
* TODO(hirono): Implement the method.
@@ -266,18 +254,11 @@ ProgressCenter.prototype.reset_ = function() {
*/
var ProgressCenterHandler = function(fileOperationManager, progressCenter) {
/**
- * Copying progress item.
- * @type {ProgressCenterItem}
- * @private
- */
- this.copyingItem_ = null;
-
- /**
- * Deleting progress item.
- * @type {ProgressCenterItem}
+ * Number of deleted files.
+ * @type {number}
* @private
*/
- this.deletingItem_ = null;
+ this.totalDeleted_ = 0;
/**
* File operation manager.
@@ -304,61 +285,133 @@ var ProgressCenterHandler = function(fileOperationManager, progressCenter) {
};
/**
+ * Generate a progress message from the event.
+ * @param {Event} event Progress event.
+ * @return {string} message.
+ * @private
+ */
+ProgressCenterHandler.getMessage_ = function(event) {
+ if (event.reason === 'ERROR') {
+ switch (event.error.code) {
+ case util.FileOperationErrorType.TARGET_EXISTS:
+ var name = event.error.data.name;
+ if (event.error.data.isDirectory)
+ name += '/';
+ switch (event.status.operationType) {
+ case 'COPY': return strf('COPY_TARGET_EXISTS_ERROR', name);
+ case 'MOVE': return strf('MOVE_TARGET_EXISTS_ERROR', name);
+ case 'ZIP': return strf('ZIP_TARGET_EXISTS_ERROR', name);
+ default: return strf('TRANSFER_TARGET_EXISTS_ERROR', name);
+ }
+
+ case util.FileOperationErrorType.FILESYSTEM_ERROR:
+ var detail = util.getFileErrorString(event.error.data.code);
+ switch (event.status.operationType) {
+ case 'COPY': return strf('COPY_FILESYSTEM_ERROR', detail);
+ case 'MOVE': return strf('MOVE_FILESYSTEM_ERROR', detail);
+ case 'ZIP': return strf('ZIP_FILESYSTEM_ERROR', detail);
+ default: return strf('TRANSFER_FILESYSTEM_ERROR', detail);
+ }
+
+ default:
+ switch (event.status.operationType) {
+ case 'COPY': return strf('COPY_UNEXPECTED_ERROR', event.error);
+ case 'MOVE': return strf('MOVE_UNEXPECTED_ERROR', event.error);
+ case 'ZIP': return strf('ZIP_UNEXPECTED_ERROR', event.error);
+ default: return strf('TRANSFER_UNEXPECTED_ERROR', event.error);
+ }
+ }
+ } else if (event.status.numRemainingItems === 1) {
+ var name = event.status.processingEntry.name;
+ switch (event.status.operationType) {
+ case 'COPY': return strf('COPY_FILE_NAME', name);
+ case 'MOVE': return strf('MOVE_FILE_NAME', name);
+ case 'ZIP': return strf('ZIP_FILE_NAME', name);
+ default: return strf('TRANSFER_FILE_NAME', name);
+ }
+ } else {
+ var remainNumber = event.status.numRemainingItems;
+ switch (event.status.operationType) {
+ case 'COPY': return strf('COPY_ITEMS_REMAINING', remainNumber);
+ case 'MOVE': return strf('MOVE_ITEMS_REMAINING', remainNumber);
+ case 'ZIP': return strf('ZIP_ITEMS_REMAINING', remainNumber);
+ default: return strf('TRANSFER_ITEMS_REMAINING', remainNumber);
+ }
+ }
+};
+
+/**
+ * Generate a delete message from the event.
+ * @param {Event} event Progress event.
+ * @param {number} totalDeleted Total number of deleted files.
+ * @return {string} message.
+ * @private
+ */
+ProgressCenterHandler.getDeleteMessage_ = function(event, totalDeleted) {
+ if (totalDeleted === 1) {
+ var fullPath = util.extractFilePath(event.urls[0]);
+ var fileName = PathUtil.split(fullPath).pop();
+ return strf('DELETED_MESSAGE', fileName);
+ } else {
+ return strf('DELETED_MESSAGE_PLURAL', totalDeleted);
+ }
+};
+
+/**
* Handles the copy-progress event.
* @param {Event} event The copy-progress event.
* @private
*/
ProgressCenterHandler.prototype.onCopyProgress_ = function(event) {
var progressCenter = this.progressCenter_;
+ var item;
switch (event.reason) {
case 'BEGIN':
- if (this.copyingItem_) {
- console.error('Previous copy is not completed.');
- return;
- }
- this.copyingItem_ = new ProgressCenterItem();
- // TODO(hirono): Specifying the correct message.
- this.copyingItem_.message = 'Copying ...';
- this.copyingItem_.progressMax = event.status.totalBytes;
- this.copyingItem_.progressValue = event.status.processedBytes;
- this.copyingItem_.cancelCallback = function() {
+ item = new ProgressCenterItem();
+ item.id = event.taskId;
+ item.message = ProgressCenterHandler.getMessage_(event);
+ item.progressMax = event.status.totalBytes;
+ item.progressValue = event.status.processedBytes;
+ item.cancelCallback = function(inItem) {
this.fileOperationManager_.requestCancel(function() {
- this.copyingItem_.message = 'Canceled.';
- this.copyingItem_.state = ProgressItemState.CANCELED;
- progressCenter.updateItem(this.copyingItem_);
- this.copyingItem_ = null;
+ inItem.message = strf('COPY_CANCELLED');
+ inItem.state = ProgressItemState.CANCELED;
+ progressCenter.updateItem(inItem);
}.bind(this));
- }.bind(this);
+ }.bind(this, item);
- progressCenter.addItem(this.copyingItem_);
+ progressCenter.updateItem(item);
break;
case 'PROGRESS':
- if (!this.copyingItem_) {
+ item = progressCenter.getItemById(event.taskId);
+ if (!item) {
console.error('Cannot find copying item.');
return;
}
- this.copyingItem_.progressValue = event.status.processedBytes;
- progressCenter.updateItem(this.copyingItem_);
+ item.message = ProgressCenterHandler.getMessage_(event);
+ item.progressValue = event.status.processedBytes;
+ progressCenter.updateItem(item);
break;
case 'SUCCESS':
case 'ERROR':
- if (!this.copyingItem_) {
- console.error('Cannot find copying item.');
- return;
+ item = progressCenter.getItemById(event.taskId);
+ if (!item) {
+ // ERROR events can be dispatched before BEGIN events.
+ item = new ProgressCenterItem();
+ item.id = event.taskId;
+ item.progressMax = 1;
}
- // TODO(hirono): Replace the message with the string assets.
if (event.reason === 'SUCCESS') {
- this.copyingItem_.message = 'Complete.';
- this.copyingItem_.state = ProgressItemState.COMPLETE;
- this.copyingItem_.progressValue = this.copyingItem_.progressMax;
+ // TODO(hirono): Add a message for complete.
+ item.state = ProgressItemState.COMPLETE;
+ item.progressValue = item.progressMax;
} else {
- this.copyingItem_.message = 'Error.';
- this.copyingItem_.state = ProgressItemState.ERROR;
+ item.message = ProgressCenterHandler.getMessage_(event);
+ item.state = ProgressItemState.ERROR;
}
- progressCenter.updateItem(this.copyingItem_);
- this.copyingItem_ = null;
+ progressCenter.updateItem(item);
break;
}
};
@@ -369,43 +422,50 @@ ProgressCenterHandler.prototype.onCopyProgress_ = function(event) {
* @private
*/
ProgressCenterHandler.prototype.onDeleteProgress_ = function(event) {
+ var progressCenter = this.progressCenter_;
+ var item;
switch (event.reason) {
case 'BEGIN':
- if (this.deletingItem_) {
- console.error('Previous delete is not completed.');
- return;
- }
- this.deletingItem_ = new ProgressCenterItem();
+ this.totalDeleted_ = 0;
+ item = new ProgressCenterItem();
+ item.id = event.taskId;
// TODO(hirono): Specifying the correct message.
- this.deletingItem_.message = 'Deleting...';
- this.deletingItem_.progressMax = 100;
- progressCenter.addItem(this.deletingItem_);
+ item.message =
+ ProgressCenterHandler.getDeleteMessage_(event, this.totalDeleted_);
+ item.progressMax = 100;
+ progressCenter.updateItem(item);
break;
case 'PROGRESS':
- if (!this.deletingItem_) {
+ item = progressCenter.getItemById(event.taskId);
+ if (!item) {
console.error('Cannot find deleting item.');
return;
}
- progressCenter.updateItem(this.deletingItem_);
+ this.totalDeleted_ += event.urls.length;
+ item.message =
+ ProgressCenterHandler.getDeleteMessage_(event, this.totalDeleted_);
+ progressCenter.updateItem(item);
break;
case 'SUCCESS':
case 'ERROR':
- if (!this.deletingItem_) {
+ item = progressCenter.getItemById(event.taskId);
+ if (!item) {
console.error('Cannot find deleting item.');
return;
}
if (event.reason === 'SUCCESS') {
- this.deletingItem_.message = 'Complete.';
- this.deletingItem_.state = ProgressItemState.COMPLETE;
- this.deletingItem_.progressValue = this.deletingItem_.progressMax;
+ this.totalDeleted_ += event.urls.length;
+ item.message =
+ ProgressCenterHandler.getDeleteMessage_(event, this.totalDeleted_);
+ item.state = ProgressItemState.COMPLETE;
+ item.progressValue = item.progressMax;
} else {
- this.deletingItem_.message = 'Error.';
- this.deletingItem_.state = ProgressItemState.ERROR;
+ item.message = str('DELETE_ERROR');
+ item.state = ProgressItemState.ERROR;
}
- progressCenter.updateItem(this.deletingItem_);
- this.deletingItem_ = null;
+ progressCenter.updateItem(item);
break;
}
};
diff --git a/chrome/browser/resources/file_manager/js/progress_center_common.js b/chrome/browser/resources/file_manager/js/progress_center_common.js
index bf7696d102..608d2dbf06 100644
--- a/chrome/browser/resources/file_manager/js/progress_center_common.js
+++ b/chrome/browser/resources/file_manager/js/progress_center_common.js
@@ -21,11 +21,6 @@ var ProgressItemContainer = Object.freeze({
*/
var ProgressCenterEvent = Object.freeze({
/**
- * Background page notifies item added to application windows.
- */
- ITEM_ADDED: 'itemAdded',
-
- /**
* Background page notifies item update to application windows.
*/
ITEM_UPDATED: 'itemUpdated',
@@ -55,7 +50,7 @@ var ProgressItemState = Object.freeze({
var ProgressCenterItem = function() {
/**
* Item ID.
- * @type {?number}
+ * @type {string}
* @private
*/
this.id_ = null;
@@ -108,7 +103,7 @@ var ProgressCenterItem = function() {
ProgressCenterItem.prototype = {
/**
* Setter of Item ID.
- * @param {number} value New value of ID.
+ * @param {string} value New value of ID.
*/
set id(value) {
if (!this.id_)
@@ -119,7 +114,7 @@ ProgressCenterItem.prototype = {
/**
* Getter of Item ID.
- * @return {number} Item ID.
+ * @return {string} Item ID.
*/
get id() {
return this.id_;
diff --git a/chrome/browser/resources/file_manager/js/tree.css.js b/chrome/browser/resources/file_manager/js/tree.css.js
index d641d4cea2..6b89acbdb8 100644
--- a/chrome/browser/resources/file_manager/js/tree.css.js
+++ b/chrome/browser/resources/file_manager/js/tree.css.js
@@ -54,6 +54,6 @@
}
prepareTriangle(
- 'tree-triangle', 'rgba(122, 122, 122, 0.6)', 'rgba(0, 0, 0, 0.6)');
+ 'tree-triangle', 'rgba(122, 122, 122, 0.6)', 'rgba(0, 0, 0, 0)');
prepareTriangle('tree-triangle-inverted', '#ffffff', '#ffffff');
})();
diff --git a/chrome/browser/resources/file_manager/js/ui/conflict_dialog.js b/chrome/browser/resources/file_manager/js/ui/conflict_dialog.js
new file mode 100644
index 0000000000..9bbd39a23c
--- /dev/null
+++ b/chrome/browser/resources/file_manager/js/ui/conflict_dialog.js
@@ -0,0 +1,135 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+'use strict';
+
+/**
+ * Dialog to confirm the operation for conflicted file operations.
+ *
+ * @param {HTMLElement} parentNode Node to be parent for this dialog.
+ * @constructor
+ * @extends {FileManagerDialogBase}
+ */
+function ConflictDialog(parentNode) {
+ FileManagerDialogBase.call(this, parentNode);
+
+ /**
+ * Callback to be called when the showing task is completed. The first
+ * argument is which button is pressed. The second argument is whether to
+ * apply all or not.
+ *
+ * @type {function(ConflictDialog.Result, boolean)}
+ * @private
+ */
+ this.callback_ = null;
+
+ /**
+ * Checkbox to specify whether to apply the selection to all entries or not.
+ * @type {HTMLElement}
+ * @private
+ */
+ this.applyAllCheckbox_ = parentNode.ownerDocument.createElement('input');
+ this.applyAllCheckbox_.id = 'conflict-confirm-dialog-apply-all-checkbox';
+ this.applyAllCheckbox_.type = 'checkbox';
+
+ // Apply all line.
+ var applyAllLabel = parentNode.ownerDocument.createElement('label');
+ applyAllLabel.textContent = str('CONFLICT_DIALOG_APPLY_TO_ALL');
+ applyAllLabel.setAttribute('for', this.applyAllCheckbox_.id);
+ var applyAllLine = parentNode.ownerDocument.createElement('div');
+ applyAllLine.className = 'apply-all-line';
+ applyAllLine.appendChild(this.applyAllCheckbox_);
+ applyAllLine.appendChild(applyAllLabel);
+
+ /**
+ * Element of the keep both button.
+ * @type {HTMLElement}
+ * @private
+ */
+ this.keepBothButton_ = parentNode.ownerDocument.createElement('button');
+ this.keepBothButton_.textContent = str('CONFLICT_DIALOG_KEEP_BOTH');
+ this.keepBothButton_.addEventListener(
+ 'click',
+ this.hideWithResult_.bind(this, ConflictDialog.Result.KEEP_BOTH));
+
+ /**
+ * Element of the replace button.
+ * @type {HTMLElement}
+ * @private
+ */
+ this.replaceButton_ = parentNode.ownerDocument.createElement('button');
+ this.replaceButton_.textContent = str('CONFLICT_DIALOG_REPLACE');
+ this.replaceButton_.addEventListener(
+ 'click',
+ this.hideWithResult_.bind(this, ConflictDialog.Result.REPLACE));
+
+ // Buttons line.
+ var buttons = this.okButton_.parentNode;
+ buttons.replaceChild(this.keepBothButton_, this.okButton_);
+ buttons.appendChild(this.replaceButton_);
+
+ // Frame
+ this.frame_.id = 'conflict-confirm-dialog';
+ this.frame_.insertBefore(applyAllLine, buttons);
+}
+
+/**
+ * Result of conflict confirm dialogs.
+ * @enum {string}
+ * @const
+ */
+ConflictDialog.Result = Object.freeze({
+ KEEP_BOTH: 'keepBoth',
+ CANCEL: 'cancel',
+ REPLACE: 'replace'
+});
+
+ConflictDialog.prototype = {
+ __proto__: FileManagerDialogBase.prototype
+};
+
+/**
+ * Shows the conflict confirm dialog.
+ *
+ * @param {string} fileName Filename that is conflicted.
+ * @param {function(ConflictDialog.Result, boolean)} callback Complete
+ * callbak. See also ConflictDialog#callback_.
+ * @return {boolean} True if the dialog can show successfully. False if the
+ * dialog failed to show due to an existing dialog.
+ */
+ConflictDialog.prototype.show = function(fileName, callback) {
+ if (this.callback_)
+ return false;
+
+ this.callback_ = callback;
+ FileManagerDialogBase.prototype.showOkCancelDialog.call(
+ this,
+ str('CONFLICT_DIALOG_TITLE'),
+ strf('CONFLICT_DIALOG_MESSAGE', fileName));
+ return true;
+};
+
+/**
+ * Handles cancellation.
+ * @param {Event} event Click event.
+ * @private
+ */
+ConflictDialog.prototype.onCancelClick_ = function(event) {
+ this.hideWithResult_(ConflictDialog.Result.CANCEL);
+};
+
+/**
+ * Hides the dialog box with the result.
+ * @param {ConflictDialog.Result} result Result.
+ * @private
+ */
+ConflictDialog.prototype.hideWithResult_ = function(result) {
+ this.hide(function() {
+ if (!this.callback_)
+ return;
+ this.callback_(result, this.applyAllCheckbox_.checked);
+ this.callback_ = null;
+ this.applyAllCheckbox_.checked = false;
+ }.bind(this));
+};
diff --git a/chrome/browser/resources/file_manager/js/ui/file_manager_ui.js b/chrome/browser/resources/file_manager/js/ui/file_manager_ui.js
index 1a894d3b5b..99f8a608a7 100644
--- a/chrome/browser/resources/file_manager/js/ui/file_manager_ui.js
+++ b/chrome/browser/resources/file_manager/js/ui/file_manager_ui.js
@@ -8,9 +8,10 @@
* The root of the file manager's view managing the DOM of Files.app.
*
* @param {HTMLElement} element Top level element of Files.app.
+ * @param {DialogType} dialogType Dialog type.
* @constructor.
*/
-var FileManagerUI = function(element) {
+var FileManagerUI = function(element, dialogType) {
/**
* Top level element of Files.app.
* @type {HTMLElement}
@@ -19,6 +20,13 @@ var FileManagerUI = function(element) {
this.element_ = element;
/**
+ * Dialog type.
+ * @type {DialogType}
+ * @private
+ */
+ this.dialogType_ = dialogType;
+
+ /**
* Error dialog.
* @type {ErrorDialog}
*/
@@ -61,12 +69,105 @@ var FileManagerUI = function(element) {
this.suggestAppsDialog = null;
/**
+ * Conflict dialog.
+ * @type {ConflictDialog}
+ */
+ this.conflictDialog = null;
+
+ /**
* Search box.
* @type {SearchBox}
*/
this.searchBox = null;
+ /**
+ * File type selector in the footer.
+ * @type {HTMLElement}
+ */
+ this.fileTypeSelector = null;
+
+ /**
+ * OK button in the footer.
+ * @type {HTMLElement}
+ */
+ this.okButton = null;
+
+ /**
+ * Cancel button in the footer.
+ * @type {HTMLElement}
+ */
+ this.cancelButton = null;
+
Object.seal(this);
+
+ // Initialize the header.
+ this.element_.querySelector('#app-name').innerText =
+ chrome.runtime.getManifest().name;
+
+ // Initialize dialog type.
+ this.initDialogType_();
+
+ // Pre-populate the static localized strings.
+ i18nTemplate.process(this.element_.ownerDocument, loadTimeData);
+};
+
+/**
+ * Tweak the UI to become a particular kind of dialog, as determined by the
+ * dialog type parameter passed to the constructor.
+ *
+ * @private
+ */
+FileManagerUI.prototype.initDialogType_ = function() {
+ // Obtain elements.
+ var hasFooterPanel =
+ this.dialogType_ == DialogType.SELECT_SAVEAS_FILE ||
+ this.dialogType_ == DialogType.SELECT_FOLDER;
+
+ // If the footer panel exists, the buttons are placed there. Otherwise,
+ // the buttons are on the preview panel.
+ var parentPanelOfButtons = this.element_.ownerDocument.querySelector(
+ !hasFooterPanel ? '.preview-panel' : '.dialog-footer');
+ parentPanelOfButtons.classList.add('button-panel');
+ this.fileTypeSelector = parentPanelOfButtons.querySelector('.file-type');
+ this.okButton = parentPanelOfButtons.querySelector('.ok');
+ this.cancelButton = parentPanelOfButtons.querySelector('.cancel');
+
+ // Set attributes.
+ var defaultTitle;
+ var okLabel = str('OPEN_LABEL');
+
+ switch (this.dialogType_) {
+ case DialogType.SELECT_FOLDER:
+ defaultTitle = str('SELECT_FOLDER_TITLE');
+ break;
+
+ case DialogType.SELECT_UPLOAD_FOLDER:
+ defaultTitle = str('SELECT_UPLOAD_FOLDER_TITLE');
+ okLabel = str('UPLOAD_LABEL');
+ break;
+
+ case DialogType.SELECT_OPEN_FILE:
+ defaultTitle = str('SELECT_OPEN_FILE_TITLE');
+ break;
+
+ case DialogType.SELECT_OPEN_MULTI_FILE:
+ defaultTitle = str('SELECT_OPEN_MULTI_FILE_TITLE');
+ break;
+
+ case DialogType.SELECT_SAVEAS_FILE:
+ defaultTitle = str('SELECT_SAVEAS_FILE_TITLE');
+ okLabel = str('SAVE_LABEL');
+ break;
+
+ case DialogType.FULL_PAGE:
+ break;
+
+ default:
+ throw new Error('Unknown dialog type: ' + this.dialogType);
+ }
+
+ this.okButton.textContent = okLabel;
+ this.element_.setAttribute('type', this.dialogType_);
};
/**
@@ -89,6 +190,7 @@ FileManagerUI.prototype.initDialogs = function() {
new cr.filebrowser.DefaultActionDialog(this.element_);
this.suggestAppsDialog = new SuggestAppsDialog(
this.element_, appState.suggestAppsDialogState || {});
+ this.conflictDialog = new ConflictDialog(this.element_);
};
/**
diff --git a/chrome/browser/resources/file_manager/js/ui/progress_center_panel.js b/chrome/browser/resources/file_manager/js/ui/progress_center_panel.js
index f50d6d5de0..e8e9405122 100644
--- a/chrome/browser/resources/file_manager/js/ui/progress_center_panel.js
+++ b/chrome/browser/resources/file_manager/js/ui/progress_center_panel.js
@@ -8,7 +8,7 @@
* Progress center panel.
*
* @param {HTMLElement} element DOM Element of the process center panel.
- * @param {function(number)} cancelCallback Callback to becalled with the ID of
+ * @param {function(string)} cancelCallback Callback to becalled with the ID of
* the progress item when the cancel button is clicked.
* @constructor
*/
@@ -31,7 +31,6 @@ var ProgressCenterPanel = function(element, cancelCallback) {
element.addEventListener('click', this.onClick_.bind(this));
element.addEventListener(
'webkitTransitionEnd', this.onItemTransitionEnd_.bind(this));
-
};
/**
@@ -41,7 +40,7 @@ var ProgressCenterPanel = function(element, cancelCallback) {
* @type {boolean}
* @private
*/
-ProgressCenterPanel.ENABLED_ = false;
+ProgressCenterPanel.ENABLED_ = true;
/**
* Update item element.
@@ -80,7 +79,6 @@ ProgressCenterPanel.updateItemElement_ = function(element, item) {
previousWidthRate > item.progressRateByPercent ? '0' : null;
track.style.width = item.progressRateByPercent + '%';
}, 0);
- // track.style.transitionDuration = null;
element.setAttribute('data-progress-id', item.id);
element.setAttribute('data-progress-max', item.progressMax);
element.setAttribute('data-progress-value', item.progressValue);
@@ -123,12 +121,12 @@ ProgressCenterPanel.prototype.reset = function() {
/**
* Gets an item element having the specified ID.
- * @param {number} id progress item ID.
+ * @param {string} id progress item ID.
* @return {HTMLElement} Item element having the ID.
* @private
*/
ProgressCenterPanel.prototype.getItemElement_ = function(id) {
- var query = 'li[data-progress-id="$ID"]'.replace('$ID', id);
+ var query = 'li[data-progress-id="' + id + '"]';
return this.openView_.querySelector(query);
};
@@ -193,6 +191,6 @@ ProgressCenterPanel.prototype.onClick_ = function(event) {
else if ((event.target.classList.contains('toggle') &&
this.closeView_.classList.contains('single')) ||
event.target.classList.contains('cancel'))
- this.cancelCallback_(parseInt(
- event.target.parentNode.parentNode.getAttribute('data-progress-id')));
+ this.cancelCallback_(
+ event.target.parentNode.parentNode.getAttribute('data-progress-id'));
};
diff --git a/chrome/browser/resources/file_manager/js/util.js b/chrome/browser/resources/file_manager/js/util.js
index 5e1c4498bd..9f6e88f7ef 100644
--- a/chrome/browser/resources/file_manager/js/util.js
+++ b/chrome/browser/resources/file_manager/js/util.js
@@ -725,8 +725,8 @@ function strf(id, var_args) {
*/
util.platform = {
/**
- * @return {boolean} True if Files.app is running via "chrome://files", open
- * files or select folder dialog. False otherwise.
+ * @return {boolean} True if Files.app is running as an open files or a select
+ * folder dialog. False otherwise.
*/
runningInBrowser: function() {
return !window.appID;
diff --git a/chrome/browser/resources/file_manager/main.html b/chrome/browser/resources/file_manager/main.html
index ee6830152d..af0940b512 100644
--- a/chrome/browser/resources/file_manager/main.html
+++ b/chrome/browser/resources/file_manager/main.html
@@ -118,6 +118,7 @@
<script src="js/text_measure.js"></script>
<script src="js/tree.css.js"></script>
<script src="js/ui/breadcrumbs_controller.js"></script>
+ <script src="js/ui/conflict_dialog.js"></script>
<script src="js/ui/file_manager_ui.js"></script>
<script src="js/ui/preview_panel.js"></script>
<script src="js/ui/progress_center_panel.js"></script>
@@ -303,7 +304,7 @@
</div>
<div id="progress-center-open-view"></div>
</div>
- <div id="butter-bar-container">
+ <div id="butter-bar-container" hidden>
<div id="butter-bar">
<div class="content">
<div class="butter-message"></div>
diff --git a/chrome/browser/resources/file_manager/manifest.json b/chrome/browser/resources/file_manager/manifest.json
index 06236a774f..07b6d88b81 100644
--- a/chrome/browser/resources/file_manager/manifest.json
+++ b/chrome/browser/resources/file_manager/manifest.json
@@ -120,14 +120,6 @@
]
},
{
- "id": "install-crx",
- "default_title": "__MSG_INSTALL_CRX__",
- "default_icon": "images/filetype_generic.png",
- "file_filters": [
- "filesystem:*.crx"
- ]
- },
- {
"id": "gallery",
"default_title": "__MSG_OPEN_ACTION__",
"default_icon": "images/filetype_image.png",
@@ -162,7 +154,8 @@
"default_icon": "images/filetype_generic.png",
"file_filters": [
"filesystem:*.gdraw",
- "filesystem:*.gtable"
+ "filesystem:*.gtable",
+ "filesystem:*.gform"
]
},
{
@@ -213,9 +206,6 @@
"file_filters": []
}
],
- "chrome_url_overrides": {
- "files": "main.html"
- },
// Required to import scripts in a web worker. Note, that in Apps v2, it is
// enough that anything is passed to web_accessible_resources. If there is
// at least any file, then all files are allowed. http://crbug.com/179127.
@@ -223,6 +213,7 @@
"app": {
"background": {
"scripts": [
+ "chrome://resources/js/load_time_data.js",
"chrome://resources/js/cr.js",
"chrome://resources/js/cr/event_target.js",
"chrome://resources/js/cr/ui/array_data_model.js",
diff --git a/chrome/browser/resources/gaia_auth/inline_injected.js b/chrome/browser/resources/gaia_auth/inline_injected.js
index a56336d56d..2f0d020b17 100644
--- a/chrome/browser/resources/gaia_auth/inline_injected.js
+++ b/chrome/browser/resources/gaia_auth/inline_injected.js
@@ -28,10 +28,13 @@
return;
}
+ var checkboxElement = $('advanced-box');
+ var chooseWhatToSync = checkboxElement && checkboxElement.checked;
var msg = {method: 'attemptLogin',
email: gaiaLoginForm['Email'].value,
password: gaiaLoginForm['Passwd'].value,
- attemptToken: new Date().getTime()};
+ attemptToken: new Date().getTime(),
+ chooseWhatToSync: chooseWhatToSync};
extWindow.postMessage(msg, 'chrome://inline-login');
console.log('Credentials sent');
diff --git a/chrome/browser/resources/gaia_auth/main.css b/chrome/browser/resources/gaia_auth/main.css
index dda571fca4..397947616e 100644
--- a/chrome/browser/resources/gaia_auth/main.css
+++ b/chrome/browser/resources/gaia_auth/main.css
@@ -18,6 +18,8 @@ iframe {
webview {
display: inline-block;
- height: 300px;
- width: 300px;
+ height: 100%;
+ margin: 0;
+ padding: 0;
+ width: 100%;
}
diff --git a/chrome/browser/resources/gaia_auth/main.js b/chrome/browser/resources/gaia_auth/main.js
index 2169174e1e..1f41917417 100644
--- a/chrome/browser/resources/gaia_auth/main.js
+++ b/chrome/browser/resources/gaia_auth/main.js
@@ -39,9 +39,9 @@ Authenticator.prototype = {
samlSupportChannel_: null,
GAIA_URL: 'https://accounts.google.com/',
- GAIA_PAGE_PATH: 'ServiceLogin?service=chromeoslogin' +
- '&skipvpage=true&sarp=1&rm=hide',
+ GAIA_PAGE_PATH: 'ServiceLogin?skipvpage=true&sarp=1&rm=hide',
PARENT_PAGE: 'chrome://oobe/',
+ SERVICE_ID: 'chromeoslogin',
CONTINUE_URL: Authenticator.THIS_EXTENSION_ORIGIN + '/success.html',
initialize: function() {
@@ -50,7 +50,11 @@ Authenticator.prototype = {
this.gaiaUrl_ = params.gaiaUrl || this.GAIA_URL;
this.inputLang_ = params.hl;
this.inputEmail_ = params.email;
+ this.service_ = params.service || this.SERVICE_ID;
this.continueUrl_ = params.continueUrl || this.CONTINUE_URL;
+ this.continueUrlWithoutParams_ =
+ this.continueUrl_.substring(0, this.continueUrl_.indexOf('?')) ||
+ this.continueUrl_;
this.inlineMode_ = params.inlineMode;
document.addEventListener('DOMContentLoaded', this.onPageLoad.bind(this));
@@ -74,8 +78,9 @@ Authenticator.prototype = {
getFrameUrl_: function() {
var url = this.gaiaUrl_;
- url += this.GAIA_PAGE_PATH + '&continue=' +
- encodeURIComponent(this.continueUrl_);
+ url += this.GAIA_PAGE_PATH +
+ '&service=' + encodeURIComponent(this.service_) +
+ '&continue=' + encodeURIComponent(this.continueUrl_);
if (this.inputLang_)
url += '&hl=' + encodeURIComponent(this.inputLang_);
@@ -94,7 +99,8 @@ Authenticator.prototype = {
gaiaFrame.contentWindow.postMessage('', gaiaFrame.src);
});
this.onLoginUILoaded();
- } else if (gaiaFrame.src.lastIndexOf(this.continueUrl_, 0) == 0) {
+ } else if (gaiaFrame.src.lastIndexOf(
+ this.continueUrlWithoutParams_, 0) == 0) {
// Detect when login is finished by the load stop event of the continue
// URL. Cannot reuse the login complete flow in success.html, because
// webview does not support extension pages yet.
diff --git a/chrome/browser/resources/gaia_auth_host/gaia_auth_host.js b/chrome/browser/resources/gaia_auth_host/gaia_auth_host.js
index edcb4133a5..20eb832df2 100644
--- a/chrome/browser/resources/gaia_auth_host/gaia_auth_host.js
+++ b/chrome/browser/resources/gaia_auth_host/gaia_auth_host.js
@@ -56,6 +56,7 @@ cr.define('cr.login', function() {
'gaiaUrl', // Gaia url to use;
'hl', // Language code for the user interface;
'email', // Pre-fill the email field in Gaia UI;
+ 'service', // Name of Gaia service;
'continueUrl' // Continue url to use;
];
@@ -290,6 +291,7 @@ cr.define('cr.login', function() {
if (e.origin == GAIA_ORIGIN && msg.method == 'attemptLogin') {
this.email_ = msg.email;
this.password_ = msg.password;
+ this.chooseWhatToSync_ = msg.chooseWhatToSync;
return;
}
@@ -305,7 +307,8 @@ cr.define('cr.login', function() {
this.onAuthSuccess_({email: msg.email || this.email_,
password: msg.password || this.password_,
authCode: msg.authCode,
- useOffline: msg.method == 'offlineLogin'});
+ useOffline: msg.method == 'offlineLogin',
+ chooseWhatToSync: this.chooseWhatToSync_});
return;
}
diff --git a/chrome/browser/resources/google_now/background.js b/chrome/browser/resources/google_now/background.js
index 1b7ba8503a..ef01369e63 100644
--- a/chrome/browser/resources/google_now/background.js
+++ b/chrome/browser/resources/google_now/background.js
@@ -81,10 +81,17 @@ var DISMISS_CARD_TASK_NAME = 'dismiss-card';
var RETRY_DISMISS_TASK_NAME = 'retry-dismiss';
var STATE_CHANGED_TASK_NAME = 'state-changed';
var SHOW_ON_START_TASK_NAME = 'show-cards-on-start';
+var ON_PUSH_MESSAGE_START_TASK_NAME = 'on-push-message';
var LOCATION_WATCH_NAME = 'location-watch';
/**
+ * Chrome push messaging subchannel for messages causing an immediate poll.
+ */
+var SUBCHANNEL_ID_POLL_NOW = 0;
+
+/**
+/**
* Notification as it's sent by the server.
*
* @typedef {{
@@ -152,7 +159,6 @@ wrapper.instrumentChromeApiFunction(
'notifications.onButtonClicked.addListener', 0);
wrapper.instrumentChromeApiFunction('notifications.onClicked.addListener', 0);
wrapper.instrumentChromeApiFunction('notifications.onClosed.addListener', 0);
-wrapper.instrumentChromeApiFunction('omnibox.onInputEntered.addListener', 0);
wrapper.instrumentChromeApiFunction(
'preferencesPrivate.googleGeolocationAccessEnabled.get',
1);
@@ -160,6 +166,7 @@ wrapper.instrumentChromeApiFunction(
'preferencesPrivate.googleGeolocationAccessEnabled.onChange.addListener',
0);
wrapper.instrumentChromeApiFunction('permissions.contains', 1);
+wrapper.instrumentChromeApiFunction('pushMessaging.onMessage.addListener', 0);
wrapper.instrumentChromeApiFunction('runtime.onInstalled.addListener', 0);
wrapper.instrumentChromeApiFunction('runtime.onStartup.addListener', 0);
wrapper.instrumentChromeApiFunction('tabs.create', 1);
@@ -515,25 +522,53 @@ function parseAndShowNotificationCards(response) {
}
/**
+ * Requests notification cards from the server for specified groups.
+ * @param {Array.<string>} groupNames Names of groups that need to be refreshed.
+ */
+function requestNotificationGroups(groupNames) {
+ console.log('requestNotificationGroups from ' + NOTIFICATION_CARDS_URL +
+ ', groupNames=' + JSON.stringify(groupNames));
+
+ recordEvent(GoogleNowEvent.REQUEST_FOR_CARDS_TOTAL);
+
+ var requestParameters = '?timeZoneOffsetMs=' +
+ (-new Date().getTimezoneOffset() * MS_IN_MINUTE);
+
+ groupNames.forEach(function(groupName) {
+ requestParameters += ('&requestTypes=' + groupName);
+ });
+
+ console.log('requestNotificationGroups: request=' + requestParameters);
+
+ var request = buildServerRequest('GET', 'notifications' + requestParameters);
+
+ request.onloadend = function(event) {
+ console.log('requestNotificationGroups-onloadend ' + request.status);
+ if (request.status == HTTP_OK) {
+ recordEvent(GoogleNowEvent.REQUEST_FOR_CARDS_SUCCESS);
+ parseAndShowNotificationCards(request.response);
+ }
+ };
+
+ setAuthorization(request, function(success) {
+ if (success)
+ request.send();
+ });
+}
+
+/**
* Requests notification cards from the server.
* @param {Location} position Location of this computer.
*/
function requestNotificationCards(position) {
- console.log('requestNotificationCards ' + JSON.stringify(position) +
- ' from ' + NOTIFICATION_CARDS_URL);
-
- if (!NOTIFICATION_CARDS_URL)
- return;
-
- recordEvent(GoogleNowEvent.REQUEST_FOR_CARDS_TOTAL);
+ console.log('requestNotificationCards ' + JSON.stringify(position));
instrumented.storage.local.get('notificationGroups', function(items) {
console.log('requestNotificationCards-storage-get ' +
JSON.stringify(items));
items = items || {};
- var requestParameters = '?timeZoneOffsetMs=' +
- (-new Date().getTimezoneOffset() * MS_IN_MINUTE);
+ var groupsToRequest = [];
if (items.notificationGroups) {
var now = Date.now();
@@ -541,27 +576,11 @@ function requestNotificationCards(position) {
for (var groupName in items.notificationGroups) {
var group = items.notificationGroups[groupName];
if (group.nextPollTime <= now)
- requestParameters += ('&requestTypes=' + groupName);
+ groupsToRequest.push(groupName);
}
}
- console.log('requestNotificationCards: request=' + requestParameters);
-
- var request = buildServerRequest('GET',
- 'notifications' + requestParameters);
-
- request.onloadend = function(event) {
- console.log('requestNotificationCards-onloadend ' + request.status);
- if (request.status == HTTP_OK) {
- recordEvent(GoogleNowEvent.REQUEST_FOR_CARDS_SUCCESS);
- parseAndShowNotificationCards(request.response);
- }
- };
-
- setAuthorization(request, function(success) {
- if (success)
- request.send();
- });
+ requestNotificationGroups(groupsToRequest);
});
}
@@ -942,7 +961,7 @@ function updateRunningState(
function onStateChange() {
tasks.add(STATE_CHANGED_TASK_NAME, function() {
authenticationManager.isSignedIn(function(token) {
- var signedIn = !!token && !!NOTIFICATION_CARDS_URL;
+ var signedIn = !!token;
instrumented.metricsPrivate.getVariationParams(
'GoogleNow',
function(response) {
@@ -1030,7 +1049,24 @@ instrumented.location.onLocationUpdate.addListener(function(position) {
updateNotificationsCards(position);
});
-instrumented.omnibox.onInputEntered.addListener(function(text) {
- localStorage['server_url'] = NOTIFICATION_CARDS_URL = text;
- initialize();
+instrumented.pushMessaging.onMessage.addListener(function(message) {
+ // message.payload will be '' when the extension first starts.
+ // Each time after signing in, we'll get latest payload for all channels.
+ // So, we need to poll the server only when the payload is non-empty and has
+ // changed.
+ console.log('pushMessaging.onMessage ' + JSON.stringify(message));
+ if (message.subchannelId == SUBCHANNEL_ID_POLL_NOW && message.payload) {
+ tasks.add(ON_PUSH_MESSAGE_START_TASK_NAME, function() {
+ instrumented.storage.local.get('lastPollNowPayload', function(items) {
+ if (items && items.lastPollNowPayload != message.payload) {
+ chrome.storage.local.set({lastPollNowPayload: message.payload});
+
+ updateCardsAttempts.isRunning(function(running) {
+ if (running)
+ requestNotificationGroups([]);
+ });
+ }
+ });
+ });
+ }
});
diff --git a/chrome/browser/resources/google_now/background_test_util.js b/chrome/browser/resources/google_now/background_test_util.js
index 4f5134bbed..2d7109ee1d 100644
--- a/chrome/browser/resources/google_now/background_test_util.js
+++ b/chrome/browser/resources/google_now/background_test_util.js
@@ -22,8 +22,8 @@ mockChromeEvent(instrumented, 'location.onLocationUpdate');
mockChromeEvent(instrumented, 'notifications.onButtonClicked');
mockChromeEvent(instrumented, 'notifications.onClicked');
mockChromeEvent(instrumented, 'notifications.onClosed');
-mockChromeEvent(instrumented, 'omnibox.onInputEntered');
mockChromeEvent(
instrumented, 'preferencesPrivate.googleGeolocationAccessEnabled.onChange');
+mockChromeEvent(instrumented, 'pushMessaging.onMessage');
mockChromeEvent(instrumented, 'runtime.onInstalled');
mockChromeEvent(instrumented, 'runtime.onStartup');
diff --git a/chrome/browser/resources/google_now/background_unittest.gtestjs b/chrome/browser/resources/google_now/background_unittest.gtestjs
index 21bd188282..a0c41ca729 100644
--- a/chrome/browser/resources/google_now/background_unittest.gtestjs
+++ b/chrome/browser/resources/google_now/background_unittest.gtestjs
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// TODO(robliao,vadimt): Determine the granularity of testing to perform.
+
/**
* Test fixture for background.js.
* @constructor
@@ -413,50 +415,13 @@ function expectInitialization(mockApisObj) {
TEST_F(
'GoogleNowBackgroundUnitTest',
- 'Initialize_ToastStateEmpty1',
- function() {
- // Tests the case when the user isn't signed in and NOTIFICATION_CARDS_URL
- // is not set. Since NOTIFICATION_CARDS_URL is empty,
- // nothing should start.
-
- // Setup and expectations.
- NOTIFICATION_CARDS_URL = undefined;
- var testIdentityToken = undefined;
- var testGeolocationPref = false;
- var testExperimentVariationParams = {};
-
- mockInitializeDependencies(this);
-
- this.mockGlobals.expects(once()).recordEvent(
- GoogleNowEvent.EXTENSION_START);
-
- this.mockGlobals.expects(once()).recordEvent(
- GoogleNowEvent.STOPPED);
-
- expectInitialization(this.mockApis);
-
- expectStateMachineCalls(
- this,
- testIdentityToken,
- testGeolocationPref,
- testExperimentVariationParams);
-
- // TODO(robliao,vadimt): Determine the granularity of testing to perform.
-
- // Invoking the tested function.
- initialize();
- });
-
-TEST_F(
- 'GoogleNowBackgroundUnitTest',
- 'Initialize_ToastStateEmpty2',
+ 'Initialize_ToastStateEmpty',
function() {
- // Tests the case when NOTIFICATION_CARDS_URL is but getAuthToken fails
- // most likely because the user is not signed in. In this case, the
- // function should quietly exit after finding out that getAuthToken fails.
+ // Tests the case when getAuthToken fails most likely because the user is
+ // not signed in. In this case, the function should quietly exit after
+ // finding out that getAuthToken fails.
// Setup and expectations.
- NOTIFICATION_CARDS_URL = 'https://some.server.url.com';
var testIdentityToken = undefined;
var testGeolocationPref = false;
var testExperimentVariationParams = {};
@@ -483,14 +448,13 @@ TEST_F(
TEST_F(
'GoogleNowBackgroundUnitTest',
- 'DISABLED_Initialize_ToastStateEmpty3',
+ 'DISABLED_Initialize_ToastStateEmpty2',
function() {
- // Tests the case when NOTIFICATION_CARDS_URL is set, getAuthToken
- // succeeds, and the user has never responded to the toast.
+ // Tests the case when getAuthToken succeeds, and the user has never
+ // responded to the toast.
// In this case, the function should invoke showWelcomeToast().
// Setup and expectations.
- NOTIFICATION_CARDS_URL = 'https://some.server.url.com';
var testIdentityToken = 'some identity token';
var testGeolocationPref = false;
var testExperimentVariationParams = {};
@@ -525,7 +489,6 @@ TEST_F('GoogleNowBackgroundUnitTest', 'Initialize_RunGoogleNow', function() {
// of the required state is fulfilled.
// Setup and expectations.
- NOTIFICATION_CARDS_URL = 'https://some.server.url.com';
var testIdentityToken = 'some identity token';
var testGeolocationPref = true;
var testExperimentVariationParams = {};
@@ -557,7 +520,6 @@ TEST_F(
// Geolocation Preference after the user responded to the toast.
// Setup and expectations.
- NOTIFICATION_CARDS_URL = 'https://some.server.url.com';
var testIdentityToken = 'some identity token';
var testGeolocationPref = false;
var testExperimentVariationParams = {};
diff --git a/chrome/browser/resources/google_now/manifest.json b/chrome/browser/resources/google_now/manifest.json
index 3bbf433483..d0668ef07d 100644
--- a/chrome/browser/resources/google_now/manifest.json
+++ b/chrome/browser/resources/google_now/manifest.json
@@ -1,21 +1,22 @@
{
- //chrome-extension://pmofbkohncoogjjhahejjfbppikbjigm
+ //chrome-extension://pafkbggdmjlpgkdkcbjmhmfcdpncadgh
"name": "Google Now",
"version": "1.2.0.1",
"description": "Integrates Google Now into Chrome.",
- "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDh/njCc/GTuP7uYix39uinhkX+7RyEoMaOQyoc065gsQ5b9cLpZToK78xgpsc9ThrpLVDOwqz6cGeLgIk+kPeRMQe07T+/mh3U5klegDx9pfr9T3aiRNQnJYJv8niVs9aJ/sBSqxtHt2LlhEt9ajFXue7Q3LkzyTlXpxoEFH1keQIDAQAB",
+ "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkhqJr32OFD/bMXW4Md7jMfd7LbwHXVc6x5bBQG5U+dloofoxrICDR20yur/40mQ8O//0sS1b8srvbab1CRlSrxoNCr9T80NAkfzx0gHyVS+p1Zow+1FzLMu9PiGwwFyN80HIB7GI/dIa0wC9K/2OrrzcHEhVH96DacTtWQqjfDVtZPjT7Xwv23dgoWcpbkRC86jMJot3dmX9xnn0KzoVc9gDOHSIkBLbkkr6Sp3LGXCCM4L0DJgxdFwaLr5WBzgC3y5x0/wwPIwN4PtIaK3BhH6njlksfnKwwIJ9iRT41V4BqbWu4mszO/7VJ3HJyw2DBpIc2grU9ZRRxrV3fRQG4wIDAQAB",
"permissions": [
"alarms",
+ "identity",
"location",
"metricsPrivate",
"notifications",
"preferencesPrivate",
+ "pushMessaging",
"storage",
"tabs",
// TODO(vadimt): Replace <all_urls> with real URL patterns once we know
// them.
- "<all_urls>",
- "identity"
+ "<all_urls>"
],
"optional_permissions": ["background"],
"manifest_version": 2,
@@ -23,8 +24,6 @@
"scripts": ["utility.js", "cards.js", "background.js"],
"persistent": false
},
- // TODO(vadimt): Remove using chrome.omnibox.
- "omnibox": { "keyword" : "gn_url" },
"oauth2": {
"auto_approve": true,
"scopes": ["https://www.googleapis.com/auth/googlenow"]
diff --git a/chrome/browser/resources/google_now/utility.js b/chrome/browser/resources/google_now/utility.js
index a8e96d7d69..418b6f3098 100644
--- a/chrome/browser/resources/google_now/utility.js
+++ b/chrome/browser/resources/google_now/utility.js
@@ -22,18 +22,28 @@
* when a task completes.
*/
-// TODO(vadimt): Figure out the server name. Use it in the manifest and for
-// NOTIFICATION_CARDS_URL. Meanwhile, to use the feature, you need to manually
-// set the server name via local storage.
+// TODO(vadimt): Use server name in the manifest.
/**
* Notification server URL.
*/
-var NOTIFICATION_CARDS_URL = localStorage['server_url'];
+var NOTIFICATION_CARDS_URL = 'https://www.googleapis.com/chromenow/v1beta1';
var DEBUG_MODE = localStorage['debug_mode'];
/**
+ * Initializes for debug or release modes of operation.
+ */
+function initializeDebug() {
+ if (DEBUG_MODE) {
+ NOTIFICATION_CARDS_URL =
+ localStorage['server_url'] || NOTIFICATION_CARDS_URL;
+ }
+}
+
+initializeDebug();
+
+/**
* Builds an error object with a message that may be sent to the server.
* @param {string} message Error message. This message may be sent to the
* server.
@@ -89,8 +99,8 @@ function sendErrorReport(error) {
if (topFrame) {
// Examples of a frame:
// 1. '\n at someFunction (chrome-extension://
- // pmofbkohncoogjjhahejjfbppikbjigm/background.js:915:15)\n'
- // 2. '\n at chrome-extension://pmofbkohncoogjjhahejjfbppikbjigm/
+ // pafkbggdmjlpgkdkcbjmhmfcdpncadgh/background.js:915:15)\n'
+ // 2. '\n at chrome-extension://pafkbggdmjlpgkdkcbjmhmfcdpncadgh/
// utility.js:269:18\n'
// 3. '\n at Function.target.(anonymous function) (extensions::
// SafeBuiltins:19:14)\n'
@@ -107,7 +117,7 @@ function sendErrorReport(error) {
var topFrameElements = errorLocation.split(':');
// topFrameElements is an array that ends like:
- // [N-3] //pmofbkohncoogjjhahejjfbppikbjigm/utility.js
+ // [N-3] //pafkbggdmjlpgkdkcbjmhmfcdpncadgh/utility.js
// [N-2] 308
// [N-1] 19
if (topFrameElements.length >= 3) {
diff --git a/chrome/browser/resources/history/history.js b/chrome/browser/resources/history/history.js
index 15884eeef7..a524b7e614 100644
--- a/chrome/browser/resources/history/history.js
+++ b/chrome/browser/resources/history/history.js
@@ -1544,21 +1544,19 @@ function load() {
cr.ui.FocusManager.disableMouseFocusOnButtons();
if (isMobileVersion()) {
- if (searchField) {
- // Move the search box out of the header.
- var resultsDisplay = $('results-display');
- resultsDisplay.parentNode.insertBefore($('search-field'), resultsDisplay);
-
- window.addEventListener(
- 'resize', historyView.updateClearBrowsingDataButton_);
-
- // When the search field loses focus, add a delay before updating the
- // visibility, otherwise the button will flash on the screen before the
- // keyboard animates away.
- searchField.addEventListener('blur', function() {
- setTimeout(historyView.updateClearBrowsingDataButton_, 250);
- });
- }
+ // Move the search box out of the header.
+ var resultsDisplay = $('results-display');
+ resultsDisplay.parentNode.insertBefore($('search-field'), resultsDisplay);
+
+ window.addEventListener(
+ 'resize', historyView.updateClearBrowsingDataButton_);
+
+ // When the search field loses focus, add a delay before updating the
+ // visibility, otherwise the button will flash on the screen before the
+ // keyboard animates away.
+ searchField.addEventListener('blur', function() {
+ setTimeout(historyView.updateClearBrowsingDataButton_, 250);
+ });
// Move the button to the bottom of the page.
$('history-page').appendChild($('clear-browsing-data'));
diff --git a/chrome/browser/resources/inspect/OWNERS b/chrome/browser/resources/inspect/OWNERS
index 2abc7be24f..c847e419ec 100644
--- a/chrome/browser/resources/inspect/OWNERS
+++ b/chrome/browser/resources/inspect/OWNERS
@@ -1 +1,2 @@
+kaznacheev@chromium.org
pfeldman@chromium.org
diff --git a/chrome/browser/resources/inspect/inspect.css b/chrome/browser/resources/inspect/inspect.css
index 2883653f92..6c4c680223 100644
--- a/chrome/browser/resources/inspect/inspect.css
+++ b/chrome/browser/resources/inspect/inspect.css
@@ -17,6 +17,7 @@ img {
height: 16px;
padding-left: 2px;
padding-right: 5px;
+ position: absolute;
width: 16px;
}
@@ -153,6 +154,10 @@ img {
margin-right: 0.5em;
}
+.subrow.main {
+ margin-left: 21px;
+}
+
.webview-thumbnail {
-webkit-box-align: center;
-webkit-box-orient: horizontal;
diff --git a/chrome/browser/resources/inspect/inspect.js b/chrome/browser/resources/inspect/inspect.js
index bd1e769b0b..988b425cdf 100644
--- a/chrome/browser/resources/inspect/inspect.js
+++ b/chrome/browser/resources/inspect/inspect.js
@@ -313,11 +313,13 @@ function addToPagesList(data) {
}
function addToExtensionsList(data) {
- addTargetToList(data, $('extensions-list'), ['name', 'url']);
+ var row = addTargetToList(data, $('extensions-list'), ['name', 'url']);
+ addFavicon(row, data);
}
function addToAppsList(data) {
var row = addTargetToList(data, $('apps-list'), ['name', 'url']);
+ addFavicon(row, data);
if (data.guests) {
Array.prototype.forEach.call(data.guests, function(guest) {
var guestRow = addTargetToList(guest, row, ['name', 'url']);
diff --git a/chrome/browser/resources/media/webrtc_logs.css b/chrome/browser/resources/media/webrtc_logs.css
index 49e6aa9e1a..a2dd3e4ac1 100644
--- a/chrome/browser/resources/media/webrtc_logs.css
+++ b/chrome/browser/resources/media/webrtc_logs.css
@@ -41,8 +41,3 @@ html[dir=rtl] h1 {
#log-list > div:not(:last-child) {
border-bottom: 1px solid #bbb;
}
-
-#disabled-mode h2 {
- color: rgb(141, 51, 42);
- font-size: 125%;
-}
diff --git a/chrome/browser/resources/media/webrtc_logs.html b/chrome/browser/resources/media/webrtc_logs.html
index 59517c2518..0e6241778c 100644
--- a/chrome/browser/resources/media/webrtc_logs.html
+++ b/chrome/browser/resources/media/webrtc_logs.html
@@ -11,15 +11,9 @@
</head>
<body i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize">
<header><h1 i18n-content="webrtcLogsTitle"></h1></header>
- <div id="enabled-mode">
- <h2 id="log-banner"></h2>
- <div id="log-list"></div>
- <p id="no-logs" i18n-content="noLogsMessage" hidden></p>
- </div>
- <div id="disabled-mode" hidden>
- <h2 i18n-content="disabledHeader"></h2>
- <p i18n-values=".innerHTML:disabledMessage"></p>
- </div>
+ <h2 id="log-banner"></h2>
+ <div id="log-list"></div>
+ <p id="no-logs" i18n-content="noLogsMessage" hidden></p>
<script src="chrome://resources/js/i18n_template2.js"></script>
<script src="chrome://resources/js/jstemplate_compiled.js"></script>
</body>
diff --git a/chrome/browser/resources/media/webrtc_logs.js b/chrome/browser/resources/media/webrtc_logs.js
index 8537551713..508af7d00c 100644
--- a/chrome/browser/resources/media/webrtc_logs.js
+++ b/chrome/browser/resources/media/webrtc_logs.js
@@ -11,22 +11,15 @@ function requestUploads() {
/**
* Callback from backend with the list of uploads. Builds the UI.
- * @param {boolean} enabled Whether or not uploading is enabled.
* @param {array} uploads The list of uploads.
* @param {string} version The browser version.
*/
-function updateWebRtcLogsList(enabled, uploads, version) {
+function updateWebRtcLogsList(uploads, version) {
$('log-banner').textContent = loadTimeData.getStringF('webrtcLogCountFormat',
uploads.length);
var logSection = $('log-list');
- $('enabled-mode').hidden = !enabled;
- $('disabled-mode').hidden = enabled;
-
- if (!enabled)
- return;
-
// Clear any previous list.
logSection.textContent = '';
diff --git a/chrome/browser/resources/net_internals/cros_log_analyzer_view.html b/chrome/browser/resources/net_internals/cros_log_analyzer_view.html
index 4c18f5c536..19c76ffe51 100644
--- a/chrome/browser/resources/net_internals/cros_log_analyzer_view.html
+++ b/chrome/browser/resources/net_internals/cros_log_analyzer_view.html
@@ -46,7 +46,7 @@
<label for="checkbox-info">Info</label>
</span>
<span class="cros-log-analyzer-filter-level-block">
- <input type='checkbox' id='checkbox-unknown'checked=true>
+ <input type='checkbox' id='checkbox-unknown' checked=true>
<label for="checkbox-unknown">Unknown</label>
</span>
</div>
diff --git a/chrome/browser/resources/net_internals/cros_log_visualizer_view.html b/chrome/browser/resources/net_internals/cros_log_visualizer_view.html
index 0803884e5f..ee6aa32dff 100644
--- a/chrome/browser/resources/net_internals/cros_log_visualizer_view.html
+++ b/chrome/browser/resources/net_internals/cros_log_visualizer_view.html
@@ -45,7 +45,7 @@
<label for="checkbox-info">Info</label>
</span>
<span class="cros-log-visualizer-filter-level-block">
- <input type='checkbox' id='checkbox-unknown'checked=true>
+ <input type='checkbox' id='checkbox-unknown' checked=true>
<label for="checkbox-unknown">Unknown</label>
</span>
</div>
diff --git a/chrome/browser/resources/options/browser_options.css b/chrome/browser/resources/options/browser_options.css
index 13ad987c9a..d2a120762a 100644
--- a/chrome/browser/resources/options/browser_options.css
+++ b/chrome/browser/resources/options/browser_options.css
@@ -402,3 +402,12 @@ list:not([disabled]) > .network-group[selected] {
/* Same as .settings-row {margin}. */
-webkit-border-vertical-spacing: 0.65em;
}
+
+#accessibility-autoclick .controlled-setting-with-label {
+ -webkit-box-align: baseline;
+}
+
+#accessibility-autoclick label + select {
+ /* Same as .controlled-setting-with-label > input + span. */
+ -webkit-margin-start: 0.6em;
+}
diff --git a/chrome/browser/resources/options/browser_options.html b/chrome/browser/resources/options/browser_options.html
index 06abb969b1..5fd32d5d04 100644
--- a/chrome/browser/resources/options/browser_options.html
+++ b/chrome/browser/resources/options/browser_options.html
@@ -747,6 +747,46 @@
</label>
</div>
</div>
+ <div class="option-name" id="accessibility-autoclick" hidden>
+ <div class="checkbox">
+ <span class="controlled-setting-with-label">
+ <input id="accessibility-autoclick-check"
+ pref="settings.a11y.autoclick" type="checkbox">
+ <span>
+ <div>
+ <div>
+ <label for="accessibility-autoclick-check"
+ i18n-content="accessibilityAutoclick">
+ </label>
+ <span class="controlled-setting-indicator"
+ pref="settings.a11y.autoclick">
+ </span>
+ </div>
+ <div>
+ <label for="accessibility-autoclick-dropdown"
+ i18n-content="accessibilityAutoclickDropdown">
+ </label>
+ <select id="accessibility-autoclick-dropdown" class="control"
+ data-type="number"
+ pref="settings.a11y.autoclick_delay_ms">
+ <option value="200"
+ i18n-content="autoclickDelayExtremelyShort"></option>
+ <option value="400"
+ i18n-content="autoclickDelayVeryShort"></option>
+ <option value="600" i18n-content="autoclickDelayShort"></option>
+ <option value="800" i18n-content="autoclickDelayLong"></option>
+ <option value="1000"
+ i18n-content="autoclickDelayVeryLong"></option>
+ </select>
+ <span class="controlled-setting-indicator"
+ pref="settings.a11y.autoclick_delay_ms">
+ </span>
+ </div>
+ </div>
+ </span>
+ </span>
+ </div>
+ </div>
</section>
<if expr="pp_ifdef('chromeos')">
<section id="factory-reset-section" hidden>
diff --git a/chrome/browser/resources/options/browser_options.js b/chrome/browser/resources/options/browser_options.js
index 9a5d39a00e..270ac8bd4b 100644
--- a/chrome/browser/resources/options/browser_options.js
+++ b/chrome/browser/resources/options/browser_options.js
@@ -106,7 +106,7 @@ cr.define('options', function() {
Preferences.getInstance().addEventListener('session.restore_on_startup',
this.onRestoreOnStartupChanged_.bind(this));
Preferences.getInstance().addEventListener(
- 'session.urls_to_restore_on_startup',
+ 'session.startup_urls',
function(event) {
$('startup-set-pages').disabled = event.value.disabled;
});
@@ -445,6 +445,8 @@ cr.define('options', function() {
};
$('accessibility-sticky-keys').hidden =
!loadTimeData.getBoolean('enableStickyKeys');
+ $('accessibility-autoclick').hidden =
+ !loadTimeData.getBoolean('enableAutoclick');
}
// Display management section (CrOS only).
diff --git a/chrome/browser/resources/options/chromeos/internet_detail.js b/chrome/browser/resources/options/chromeos/internet_detail.js
index 9b3d45edd3..cbc07f21d2 100644
--- a/chrome/browser/resources/options/chromeos/internet_detail.js
+++ b/chrome/browser/resources/options/chromeos/internet_detail.js
@@ -73,6 +73,17 @@ cr.define('options.internet', function() {
return value ? String(value) : '';
}
+ /**
+ * Sends the 'checked' state of a control to chrome for a network.
+ * @param {string} path The service path of the network.
+ * @param {string} message The message to send to chrome.
+ * @param {HTMLInputElement} checkbox The checkbox storing the value to send.
+ */
+ function sendCheckedIfEnabled(path, message, checkbox) {
+ if (!checkbox.hidden && !checkbox.disabled)
+ chrome.send(message, [path, checkbox.checked ? 'true' : 'false']);
+ }
+
/////////////////////////////////////////////////////////////////////////////
// DetailsInternetPage class:
@@ -708,28 +719,22 @@ cr.define('options.internet', function() {
var data = $('connection-state').data;
var servicePath = data.servicePath;
if (data.type == Constants.TYPE_WIFI) {
- chrome.send('setPreferNetwork',
- [servicePath,
- $('prefer-network-wifi').checked ? 'true' : 'false']);
- chrome.send('setAutoConnect',
- [servicePath,
- $('auto-connect-network-wifi').checked ? 'true' : 'false']);
+ sendCheckedIfEnabled(servicePath, 'setPreferNetwork',
+ $('prefer-network-wifi'));
+ sendCheckedIfEnabled(servicePath, 'setAutoConnect',
+ $('auto-connect-network-wifi'));
} else if (data.type == Constants.TYPE_WIMAX) {
- chrome.send('setAutoConnect',
- [servicePath,
- $('auto-connect-network-wimax').checked ? 'true' : 'false']);
+ sendCheckedIfEnabled(servicePath, 'setAutoConnect',
+ $('auto-connect-network-wimax'));
} else if (data.type == Constants.TYPE_CELLULAR) {
- chrome.send('setAutoConnect',
- [servicePath,
- $('auto-connect-network-cellular').checked ? 'true' :
- 'false']);
+ sendCheckedIfEnabled(servicePath, 'setAutoConnect',
+ $('auto-connect-network-cellular'));
} else if (data.type == Constants.TYPE_VPN) {
chrome.send('setServerHostname',
[servicePath,
$('inet-server-hostname').value]);
- chrome.send('setAutoConnect',
- [servicePath,
- $('auto-connect-network-vpn').checked ? 'true' : 'false']);
+ sendCheckedIfEnabled(servicePath, 'setAutoConnect',
+ $('auto-connect-network-vpn'));
}
var nameServerTypes = ['automatic', 'google', 'user'];
@@ -1240,7 +1245,8 @@ cr.define('options.internet', function() {
indicators[i].handlePrefChange(event);
var forElement = $(indicators[i].getAttribute('for'));
if (forElement) {
- forElement.disabled = propData.controlledBy == 'policy';
+ if (propData.controlledBy == 'policy')
+ forElement.disabled = true;
if (forElement.resetHandler)
indicators[i].resetHandler = forElement.resetHandler;
}
diff --git a/chrome/browser/resources/options/options_page.js b/chrome/browser/resources/options/options_page.js
index d9d2a34970..c0a1787121 100644
--- a/chrome/browser/resources/options/options_page.js
+++ b/chrome/browser/resources/options/options_page.js
@@ -226,10 +226,8 @@ cr.define('options', function() {
// The page is already in history (the user may have clicked the same link
// twice). Do nothing.
- if (path == page.name &&
- !document.documentElement.classList.contains('loading')) {
+ if (path == page.name && this.loading)
return;
- }
var hash = opt_params && opt_params.ignoreHash ? '' : window.location.hash;
@@ -804,6 +802,15 @@ cr.define('options', function() {
},
/**
+ * Whether the page is still loading (i.e. onload hasn't finished running).
+ * @return {boolean} Whether the page is still loading.
+ * @private
+ */
+ get loading() {
+ return document.documentElement.classList.contains('loading');
+ },
+
+ /**
* Gets page visibility state.
* @type {boolean}
*/
@@ -874,14 +881,17 @@ cr.define('options', function() {
}
var self = this;
- // TODO(flackr): Use an event delegate to avoid having to subscribe and
- // unsubscribe for webkitTransitionEnd events.
- container.addEventListener('webkitTransitionEnd', function f(e) {
- if (e.target != e.currentTarget || e.propertyName != 'opacity')
- return;
- container.removeEventListener('webkitTransitionEnd', f);
- self.fadeCompleted_();
- });
+ var loading = this.loading;
+ if (!loading) {
+ // TODO(flackr): Use an event delegate to avoid having to subscribe and
+ // unsubscribe for webkitTransitionEnd events.
+ container.addEventListener('webkitTransitionEnd', function f(e) {
+ if (e.target != e.currentTarget || e.propertyName != 'opacity')
+ return;
+ container.removeEventListener('webkitTransitionEnd', f);
+ self.fadeCompleted_();
+ });
+ }
if (visible) {
container.hidden = false;
@@ -903,6 +913,8 @@ cr.define('options', function() {
document.activeElement.blur();
container.classList.add('transparent');
}
+ if (loading)
+ this.fadeCompleted_();
},
/**
diff --git a/chrome/browser/resources/options/startup_overlay.html b/chrome/browser/resources/options/startup_overlay.html
index f025cca69e..645bb7ce3b 100644
--- a/chrome/browser/resources/options/startup_overlay.html
+++ b/chrome/browser/resources/options/startup_overlay.html
@@ -5,7 +5,7 @@
its 'controlled-by' attribute will get set when the urls preference is
managed by a policy, so that the managed prefs bar will show up.
-->
- <input type="text" pref="session.urls_to_restore_on_startup" hidden>
+ <input type="text" pref="session.startup_urls" hidden>
<div class="content-area">
<list id="startupPagesList"></list>
</div>
diff --git a/chrome/browser/resources/options/startup_overlay.js b/chrome/browser/resources/options/startup_overlay.js
index dc74f48254..d63b49d102 100644
--- a/chrome/browser/resources/options/startup_overlay.js
+++ b/chrome/browser/resources/options/startup_overlay.js
@@ -34,7 +34,7 @@ cr.define('options', function() {
autocompleteList_: null,
startup_pages_pref_: {
- 'name': 'session.urls_to_restore_on_startup',
+ 'name': 'session.startup_urls',
'disabled': false
},
@@ -108,7 +108,7 @@ cr.define('options', function() {
/**
* Handles change events of the preference
- * 'session.urls_to_restore_on_startup'.
+ * 'session.startup_urls'.
* @param {event} preference changed event.
* @private
*/
diff --git a/chrome/browser/resources/options/startup_section.html b/chrome/browser/resources/options/startup_section.html
index 676dbbdb01..2eaea81c0b 100644
--- a/chrome/browser/resources/options/startup_section.html
+++ b/chrome/browser/resources/options/startup_section.html
@@ -44,7 +44,7 @@
i18n-content="startupSetPages">
</button>
<span class="controlled-setting-indicator"
- pref="session.urls_to_restore_on_startup">
+ pref="session.startup_urls">
</span>
</span>
</label>
diff --git a/chrome/browser/resources/plugin_metadata/plugins_win.json b/chrome/browser/resources/plugin_metadata/plugins_win.json
index 5bdbc8d3c3..bed9d9545e 100644
--- a/chrome/browser/resources/plugin_metadata/plugins_win.json
+++ b/chrome/browser/resources/plugin_metadata/plugins_win.json
@@ -1,5 +1,5 @@
{
- "x-version": 10,
+ "x-version": 11,
"google-talk": {
"mime_types": [
],
@@ -54,18 +54,9 @@
],
"versions": [
{
- "version": "6.0.450",
+ "version": "10.45",
"status": "requires_authorization",
- "comment": "Java SE 6 Update 45. '450' is not a typo."
- },
- {
- "version": "7",
- "status": "out_of_date"
- },
- {
- "version": "10.21",
- "status": "requires_authorization",
- "comment": "Java SE 7u17"
+ "comment": "Java SE 7u45"
}
],
"lang": "en-US",
@@ -164,9 +155,9 @@
],
"versions": [
{
- "version": "12.0.2.122",
+ "version": "12.0.4.144",
"status": "requires_authorization",
- "reference": "https://www.adobe.com/support/security/bulletins/apsb13-12.html"
+ "reference": "https://www.adobe.com/support/security/bulletins/apsb13-23.html"
}
],
"lang": "en-US",
@@ -186,33 +177,24 @@
],
"versions": [
{
- "version": "9.5.5",
- "status": "requires_authorization",
- "reference": "https://www.adobe.com/support/security/bulletins/apsb13-15.html"
- },
- {
- "version": "10",
- "status": "out_of_date"
- },
- {
- "version": "10.1.7",
+ "version": "10.1.8",
"status": "requires_authorization",
- "reference": "https://www.adobe.com/support/security/bulletins/apsb13-15.html"
+ "reference": "https://www.adobe.com/support/security/bulletins/apsb13-22.html"
},
{
"version": "11",
"status": "out_of_date"
},
{
- "version": "11.0.3",
+ "version": "11.0.5",
"status": "up_to_date",
- "reference": "https://www.adobe.com/support/security/bulletins/apsb13-15.html"
+ "reference": "https://www.adobe.com/support/security/bulletins/apsb13-25.html"
}
],
"lang": "en-US",
"name": "Adobe Reader",
"help_url": "https://support.google.com/chrome/?p=plugin_pdf",
- "url": "http://ardownload.adobe.com/pub/adobe/reader/win/11.x/11.0.03/en_US/AdbeRdr11003_en_US.exe",
+ "url": "http://www.adobe.com/support/downloads/detail.jsp?ftpID=5674",
"group_name_matcher": "*Adobe Acrobat*"
},
"apple-quicktime": {
diff --git a/chrome/browser/resources/print_preview/print_preview.css b/chrome/browser/resources/print_preview/print_preview.css
index df354a65d6..d430924809 100644
--- a/chrome/browser/resources/print_preview/print_preview.css
+++ b/chrome/browser/resources/print_preview/print_preview.css
@@ -113,7 +113,7 @@ h1 {
#print-preview .navbar-link {
-webkit-margin-start: 20px;
- height: 29px;
+ height: 32px;
outline: 0;
padding: 0;
text-align: start;
diff --git a/chrome/browser/resources/ssl/blocking.css b/chrome/browser/resources/ssl/blocking.css
new file mode 100644
index 0000000000..221dc3487a
--- /dev/null
+++ b/chrome/browser/resources/ssl/blocking.css
@@ -0,0 +1,29 @@
+/* Copyright 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+.explanation-par {
+ line-height: 18px;
+ padding: 0 20px 20px 20px;
+}
+
+#icon-lock {
+ content: -webkit-image-set(
+ url('images/1x/locked_page.png') 1x,
+ url('images/2x/locked_page.png') 2x);
+ padding-bottom: 15px;
+ padding-top: 10px;
+}
+
+/* Decrease padding at low sizes. */
+@media (max-width: 640px),
+@media (max-height: 640px) {
+ .explanation-par,
+ .ssl-help-box-inner {
+ padding: 0;
+ }
+}
+
+.ssl-help-box-inner {
+ padding: 0 20px;
+}
diff --git a/chrome/browser/resources/ssl/blocking.html b/chrome/browser/resources/ssl/blocking.html
new file mode 100644
index 0000000000..004cf225cf
--- /dev/null
+++ b/chrome/browser/resources/ssl/blocking.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html i18n-values="dir:textDirection">
+<head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0,
+ maximum-scale=1.0, user-scalable=no">
+ <title i18n-content="title"></title>
+ <link rel="stylesheet" href="../../../renderer/resources/neterror.css">
+ <link rel="stylesheet" href="blocking.css">
+ <script src="../../../../ui/webui/resources/js/util.js"></script>
+ <script src="../../../renderer/resources/neterror.js"></script>
+ <script src="ssl_errors_common.js"></script>
+ <script src="blocking.js"></script>
+</head>
+<body>
+ <div id="main-frame-error">
+ <div id="box">
+ <div id="content-top">
+ <h1>
+ <div>
+ <img class="icon" id="icon-lock">
+ </div>
+ <span i18n-content="headline"></span>
+ </h1>
+ <p i18n-values=".innerHTML:message" class="explanation-par"></p>
+ <div id="buttons">
+ <button id="reload-button" i18n-content="reloadMsg"></button>
+ <button id="more-less-button" i18n-content="more"></button>
+ </div>
+ </div>
+ <div id="help-box-outer" class="hidden">
+ <div id="help-box-inner">
+ <div class="ssl-help-box-inner">
+ <h2 i18n-content="moreTitle"></h2>
+ <p i18n-values=".innerHTML:moreMessage"></p>
+ </div>
+ <div class="ssl-help-box-inner">
+ <h2 i18n-content="techTitle"></h2>
+ <p>
+ <span i18n-content="failure"></span><br>
+ <span i18n-content="errorType"></span><br>
+ <span i18n-content="subject"></span><br>
+ <span i18n-content="issuer"></span><br>
+ <span i18n-content="fingerprint"></span>
+ </p>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/chrome/browser/resources/ssl/blocking.js b/chrome/browser/resources/ssl/blocking.js
new file mode 100644
index 0000000000..6442c386fd
--- /dev/null
+++ b/chrome/browser/resources/ssl/blocking.js
@@ -0,0 +1,25 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function toggleMoreBox() {
+ var helpBoxOuter = $('help-box-outer');
+ helpBoxOuter.classList.toggle('hidden');
+ var moreLessButton = $('more-less-button');
+ if (helpBoxOuter.classList.contains('hidden')) {
+ moreLessButton.innerText = templateData.more;
+ } else {
+ moreLessButton.innerText = templateData.less;
+ }
+}
+
+function reloadPage() {
+ sendCommand(CMD_RELOAD);
+}
+
+function setupEvents() {
+ $('reload-button').addEventListener('click', reloadPage);
+ $('more-less-button').addEventListener('click', toggleMoreBox);
+}
+
+document.addEventListener('DOMContentLoaded', setupEvents);
diff --git a/chrome/browser/resources/ssl/images/1x/locked_page.png b/chrome/browser/resources/ssl/images/1x/locked_page.png
new file mode 100644
index 0000000000..fb7e2185be
--- /dev/null
+++ b/chrome/browser/resources/ssl/images/1x/locked_page.png
Binary files differ
diff --git a/chrome/browser/resources/ssl/images/2x/locked_page.png b/chrome/browser/resources/ssl/images/2x/locked_page.png
new file mode 100644
index 0000000000..94aa4e970f
--- /dev/null
+++ b/chrome/browser/resources/ssl/images/2x/locked_page.png
Binary files differ
diff --git a/chrome/browser/resources/ssl/roadblock.html b/chrome/browser/resources/ssl/roadblock.html
index 8bebfc610d..f2c7f4369c 100644
--- a/chrome/browser/resources/ssl/roadblock.html
+++ b/chrome/browser/resources/ssl/roadblock.html
@@ -78,95 +78,8 @@
}
</style>
<script src="../../../../ui/webui/resources/js/assert.js"></script>
- <script>
- // Should match SSLBlockingPageCommands in ssl_blocking_page.cc.
- var CMD_DONT_PROCEED = 0;
- var CMD_PROCEED = 1;
- var CMD_FOCUS = 2;
- var CMD_MORE = 3;
-
- var showedMore = false;
- var keyPressState = 0;
- var gainFocus = false;
- var setupExperiment = false;
-
- function $(o) {
- return document.getElementById(o);
- }
-
- function sendCommand(cmd) {
- window.domAutomationController.setAutomationId(1);
- window.domAutomationController.send(cmd);
- }
-
- function toggleMoreInfo(collapse) {
- $('more-info-long').hidden = collapse;
- $('more-info-short').hidden = !collapse;
- if (!collapse && !showedMore) {
- sendCommand(CMD_MORE);
- showedMore = true;
- }
- }
-
- // This allows errors to be skippped by typing "proceed" into the page.
- function keyPressHandler(e) {
- var sequence = 'proceed';
- if (sequence.charCodeAt(keyPressState) == e.keyCode) {
- keyPressState++;
- if (keyPressState == sequence.length) {
- sendCommand(CMD_PROCEED);
- keyPressState = 0;
- }
- } else {
- keyPressState = 0;
- }
- }
-
- // Supports UMA timing, which starts after the warning is first viewed.
- function handleFocusEvent() {
- if (gainFocus == false) {
- sendCommand(CMD_FOCUS);
- gainFocus = true;
- }
- }
-
- // UI modifications and event listeners that take place after load.
- function setupEvents() {
- if (templateData.errorType == "overridable") {
- // This is the blocking page you can click through.
- $('proceed-button').hidden = false;
- $('proceed-button').addEventListener('click', function() {
- sendCommand(CMD_PROCEED);
- });
- } else {
- document.addEventListener('keypress', keyPressHandler);
- }
-
- if ($('more-info-title').textContent == '') {
- $('more-info-short').hidden = true;
- $('more-info-long').hidden = true;
- $('twisty-closed').style.display = 'none';
- } else {
- $('more-info-short').addEventListener('click', function() {
- toggleMoreInfo(false);
- });
- $('more-info-long').addEventListener('click', function() {
- toggleMoreInfo(true);
- });
- }
-
- $('exit-button').addEventListener('click', function() {
- sendCommand(CMD_DONT_PROCEED);
- });
-
- document.addEventListener('contextmenu', function(e) {
- e.preventDefault();
- });
- }
-
- window.addEventListener('focus', handleFocusEvent);
- document.addEventListener('DOMContentLoaded', setupEvents);
- </script>
+ <script src="ssl_errors_common.js"></script>
+ <script src="roadblock.js"></script>
</head>
<body>
<div class="box">
diff --git a/chrome/browser/resources/ssl/roadblock.js b/chrome/browser/resources/ssl/roadblock.js
new file mode 100644
index 0000000000..8e0d27f15f
--- /dev/null
+++ b/chrome/browser/resources/ssl/roadblock.js
@@ -0,0 +1,41 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var showedMore = false;
+
+function toggleMoreInfo(collapse) {
+ $('more-info-long').hidden = collapse;
+ $('more-info-short').hidden = !collapse;
+ if (!collapse && !showedMore) {
+ sendCommand(CMD_MORE);
+ showedMore = true;
+ }
+}
+
+// UI modifications and event listeners that take place after load.
+function setupEvents() {
+ $('proceed-button').hidden = false;
+ $('proceed-button').addEventListener('click', function() {
+ sendCommand(CMD_PROCEED);
+ });
+
+ if ($('more-info-title').textContent == '') {
+ $('more-info-short').hidden = true;
+ $('more-info-long').hidden = true;
+ $('twisty-closed').style.display = 'none';
+ } else {
+ $('more-info-short').addEventListener('click', function() {
+ toggleMoreInfo(false);
+ });
+ $('more-info-long').addEventListener('click', function() {
+ toggleMoreInfo(true);
+ });
+ }
+
+ $('exit-button').addEventListener('click', function() {
+ sendCommand(CMD_DONT_PROCEED);
+ });
+}
+
+document.addEventListener('DOMContentLoaded', setupEvents);
diff --git a/chrome/browser/resources/ssl/ssl_errors_common.js b/chrome/browser/resources/ssl/ssl_errors_common.js
new file mode 100644
index 0000000000..2c488e3e4f
--- /dev/null
+++ b/chrome/browser/resources/ssl/ssl_errors_common.js
@@ -0,0 +1,44 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Should match SSLBlockingPageCommands in ssl_blocking_page.cc.
+var CMD_DONT_PROCEED = 0;
+var CMD_PROCEED = 1;
+var CMD_FOCUS = 2;
+var CMD_MORE = 3;
+var CMD_RELOAD = 4;
+
+var keyPressState = 0;
+
+function $(o) {
+ return document.getElementById(o);
+}
+
+function sendCommand(cmd) {
+ window.domAutomationController.setAutomationId(1);
+ window.domAutomationController.send(cmd);
+}
+
+// This allows errors to be skippped by typing "proceed" into the page.
+function keyPressHandler(e) {
+ var sequence = 'proceed';
+ if (sequence.charCodeAt(keyPressState) == e.keyCode) {
+ keyPressState++;
+ if (keyPressState == sequence.length) {
+ sendCommand(CMD_PROCEED);
+ keyPressState = 0;
+ }
+ } else {
+ keyPressState = 0;
+ }
+}
+
+function sharedSetup() {
+ document.addEventListener('contextmenu', function(e) {
+ e.preventDefault();
+ });
+ document.addEventListener('keypress', keyPressHandler);
+}
+
+document.addEventListener('DOMContentLoaded', sharedSetup);
diff --git a/chrome/browser/search/hotword_service.cc b/chrome/browser/search/hotword_service.cc
new file mode 100644
index 0000000000..1ebecaf49c
--- /dev/null
+++ b/chrome/browser/search/hotword_service.cc
@@ -0,0 +1,15 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/search/hotword_service.h"
+
+#include "chrome/browser/profiles/profile.h"
+
+
+HotwordService::HotwordService(Profile* profile)
+ : profile_(profile) {
+}
+
+HotwordService::~HotwordService() {
+}
diff --git a/chrome/browser/search/hotword_service.h b/chrome/browser/search/hotword_service.h
new file mode 100644
index 0000000000..17bf69dfa3
--- /dev/null
+++ b/chrome/browser/search/hotword_service.h
@@ -0,0 +1,26 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SEARCH_HOTWORD_SERVICE_H_
+#define CHROME_BROWSER_SEARCH_HOTWORD_SERVICE_H_
+
+#include "base/basictypes.h"
+#include "components/browser_context_keyed_service/browser_context_keyed_service.h"
+
+class Profile;
+
+// Provides an interface for the Hotword component that does voice triggered
+// search.
+class HotwordService : public BrowserContextKeyedService {
+ public:
+ explicit HotwordService(Profile* profile);
+ virtual ~HotwordService();
+
+ private:
+ Profile* profile_;
+
+ DISALLOW_COPY_AND_ASSIGN(HotwordService);
+};
+
+#endif // CHROME_BROWSER_SEARCH_HOTWORD_SERVICE_H_
diff --git a/chrome/browser/search/hotword_service_factory.cc b/chrome/browser/search/hotword_service_factory.cc
new file mode 100644
index 0000000000..c465e08cc2
--- /dev/null
+++ b/chrome/browser/search/hotword_service_factory.cc
@@ -0,0 +1,54 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/search/hotword_service_factory.h"
+
+#include "base/prefs/pref_service.h"
+#include "chrome/browser/profiles/incognito_helpers.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/search/hotword_service.h"
+#include "chrome/common/pref_names.h"
+#include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
+#include "components/user_prefs/pref_registry_syncable.h"
+
+// static
+HotwordService* HotwordServiceFactory::GetForProfile(Profile* profile) {
+ if (!profile->GetPrefs()->GetBoolean(prefs::kHotwordSearchEnabled))
+ return NULL;
+
+ return static_cast<HotwordService*>(
+ GetInstance()->GetServiceForBrowserContext(profile, true));
+}
+
+// static
+HotwordServiceFactory* HotwordServiceFactory::GetInstance() {
+ return Singleton<HotwordServiceFactory>::get();
+}
+
+HotwordServiceFactory::HotwordServiceFactory()
+ : BrowserContextKeyedServiceFactory(
+ "HotwordService",
+ BrowserContextDependencyManager::GetInstance()) {
+ // No dependencies.
+}
+
+HotwordServiceFactory::~HotwordServiceFactory() {
+}
+
+void HotwordServiceFactory::RegisterProfilePrefs(
+ user_prefs::PrefRegistrySyncable* prefs) {
+ prefs->RegisterBooleanPref(prefs::kHotwordSearchEnabled,
+ false,
+ user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+}
+
+content::BrowserContext* HotwordServiceFactory::GetBrowserContextToUse(
+ content::BrowserContext* context) const {
+ return chrome::GetBrowserContextOwnInstanceInIncognito(context);
+}
+
+BrowserContextKeyedService* HotwordServiceFactory::BuildServiceInstanceFor(
+ content::BrowserContext* profile) const {
+ return new HotwordService(static_cast<Profile*>(profile));
+}
diff --git a/chrome/browser/search/hotword_service_factory.h b/chrome/browser/search/hotword_service_factory.h
new file mode 100644
index 0000000000..227a23b1e0
--- /dev/null
+++ b/chrome/browser/search/hotword_service_factory.h
@@ -0,0 +1,40 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SEARCH_HOTWORD_SERVICE_FACTORY_H_
+#define CHROME_BROWSER_SEARCH_HOTWORD_SERVICE_FACTORY_H_
+
+#include "base/memory/singleton.h"
+#include "components/browser_context_keyed_service/browser_context_keyed_service_factory.h"
+
+class BrowserContextKeyedService;
+class HotwordService;
+class Profile;
+
+// Singleton that owns all HotwordServices and associates them with Profiles.
+class HotwordServiceFactory : public BrowserContextKeyedServiceFactory {
+ public:
+ // Returns the HotwordService for |profile|.
+ static HotwordService* GetForProfile(Profile* profile);
+
+ static HotwordServiceFactory* GetInstance();
+
+ private:
+ friend struct DefaultSingletonTraits<HotwordServiceFactory>;
+
+ HotwordServiceFactory();
+ virtual ~HotwordServiceFactory();
+
+ // Overrides from BrowserContextKeyedServiceFactory:
+ virtual void RegisterProfilePrefs(
+ user_prefs::PrefRegistrySyncable* registry) OVERRIDE;
+ virtual content::BrowserContext* GetBrowserContextToUse(
+ content::BrowserContext* context) const OVERRIDE;
+ virtual BrowserContextKeyedService* BuildServiceInstanceFor(
+ content::BrowserContext* profile) const OVERRIDE;
+
+ DISALLOW_COPY_AND_ASSIGN(HotwordServiceFactory);
+};
+
+#endif // CHROME_BROWSER_SEARCH_HOTWORD_SERVICE_FACTORY_H_
diff --git a/chrome/browser/search/search.cc b/chrome/browser/search/search.cc
index c12ad8ef0c..c063cbce1e 100644
--- a/chrome/browser/search/search.cc
+++ b/chrome/browser/search/search.cc
@@ -35,6 +35,12 @@
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
+#if defined(ENABLE_MANAGED_USERS)
+#include "chrome/browser/managed_mode/managed_mode_url_filter.h"
+#include "chrome/browser/managed_mode/managed_user_service.h"
+#include "chrome/browser/managed_mode/managed_user_service_factory.h"
+#endif
+
namespace chrome {
namespace {
@@ -257,6 +263,20 @@ string16 GetSearchTermsImpl(const content::WebContents* contents,
return GetSearchTermsFromURL(profile, entry->GetVirtualURL());
}
+bool IsURLAllowedForSupervisedUser(const GURL& url, Profile* profile) {
+#if defined(ENABLE_MANAGED_USERS)
+ ManagedUserService* managed_user_service =
+ ManagedUserServiceFactory::GetForProfile(profile);
+ ManagedModeURLFilter* url_filter =
+ managed_user_service->GetURLFilterForUIThread();
+ if (url_filter->GetFilteringBehaviorForURL(url) ==
+ ManagedModeURLFilter::BLOCK) {
+ return false;
+ }
+#endif
+ return true;
+}
+
} // namespace
// Negative start-margin values prevent the "es_sm" parameter from being used.
@@ -419,13 +439,18 @@ GURL GetInstantURL(Profile* profile, int start_margin) {
// Extended mode requires HTTPS. Force it unless the base URL was overridden
// on the command line, in which case we allow HTTP (see comments on
// IsSuitableURLForInstant()).
- if (instant_url.SchemeIsSecure() ||
- google_util::StartsWithCommandLineGoogleBaseURL(instant_url))
- return instant_url;
- GURL::Replacements replacements;
- const std::string secure_scheme(content::kHttpsScheme);
- replacements.SetSchemeStr(secure_scheme);
- return instant_url.ReplaceComponents(replacements);
+ if (!instant_url.SchemeIsSecure() &&
+ !google_util::StartsWithCommandLineGoogleBaseURL(instant_url)) {
+ GURL::Replacements replacements;
+ const std::string secure_scheme(content::kHttpsScheme);
+ replacements.SetSchemeStr(secure_scheme);
+ instant_url = instant_url.ReplaceComponents(replacements);
+ }
+
+ if (!IsURLAllowedForSupervisedUser(instant_url, profile))
+ return GURL();
+
+ return instant_url;
}
// Returns URLs associated with the default search engine for |profile|.
@@ -460,6 +485,9 @@ GURL GetNewTabPageURL(Profile* profile) {
if (!url.is_valid() || !url.SchemeIsSecure())
return GURL(chrome::kChromeSearchLocalNtpUrl);
+ if (!IsURLAllowedForSupervisedUser(url, profile))
+ return GURL(chrome::kChromeSearchLocalNtpUrl);
+
return url;
}
diff --git a/chrome/browser/search/search_unittest.cc b/chrome/browser/search/search_unittest.cc
index 4c49936db5..af006e6a6a 100644
--- a/chrome/browser/search/search_unittest.cc
+++ b/chrome/browser/search/search_unittest.cc
@@ -8,6 +8,9 @@
#include "base/metrics/histogram_samples.h"
#include "base/metrics/statistics_recorder.h"
#include "base/prefs/pref_service.h"
+#include "chrome/browser/managed_mode/managed_mode_url_filter.h"
+#include "chrome/browser/managed_mode/managed_user_service.h"
+#include "chrome/browser/managed_mode/managed_user_service_factory.h"
#include "chrome/browser/search/instant_service.h"
#include "chrome/browser/search/instant_service_factory.h"
#include "chrome/browser/search/search.h"
@@ -743,6 +746,25 @@ TEST_F(SearchTest, UseLocalNTPIfNTPURLIsNotSet) {
chrome::GetNewTabPageURL(profile()));
}
+TEST_F(SearchTest, UseLocalNTPIfNTPURLIsBlockedForSupervisedUser) {
+ EnableInstantExtendedAPIForTesting();
+ ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("InstantExtended",
+ "Group1 use_cacheable_ntp:1"));
+
+ // Block access to foo.com in the URL filter.
+ ManagedUserService* managed_user_service =
+ ManagedUserServiceFactory::GetForProfile(profile());
+ ManagedModeURLFilter* url_filter =
+ managed_user_service->GetURLFilterForUIThread();
+ std::map<std::string, bool> hosts;
+ hosts["foo.com"] = false;
+ url_filter->SetManualHosts(&hosts);
+
+ EXPECT_EQ(GURL(chrome::kChromeSearchLocalNtpUrl),
+ chrome::GetNewTabPageURL(profile()));
+ EXPECT_EQ(GURL(), GetInstantURL(profile(), kDisableStartMargin));
+}
+
TEST_F(SearchTest, GetInstantURLExtendedEnabled) {
// Instant is disabled, so no Instant URL.
EXPECT_EQ(GURL(), GetInstantURL(profile(), kDisableStartMargin));
diff --git a/chrome/browser/search_engines/OWNERS b/chrome/browser/search_engines/OWNERS
index dd79a14220..09c675917d 100644
--- a/chrome/browser/search_engines/OWNERS
+++ b/chrome/browser/search_engines/OWNERS
@@ -2,4 +2,7 @@ estade@chromium.org
pkasting@chromium.org
stevet@chromium.org
-per-file *_android.*=yfriedman@chromium.org \ No newline at end of file
+per-file *_android.*=yfriedman@chromium.org
+
+per-file default_search_policy_handler*=joaodasilva@chromium.org
+per-file default_search_policy_handler*=dconnelly@chromium.org
diff --git a/chrome/browser/search_engines/default_search_policy_handler.cc b/chrome/browser/search_engines/default_search_policy_handler.cc
new file mode 100644
index 0000000000..5a5e1900ad
--- /dev/null
+++ b/chrome/browser/search_engines/default_search_policy_handler.cc
@@ -0,0 +1,323 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/search_engines/default_search_policy_handler.h"
+
+#include "base/prefs/pref_value_map.h"
+#include "base/stl_util.h"
+#include "base/strings/string_util.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/policy/policy_error_map.h"
+#include "chrome/browser/policy/policy_map.h"
+#include "chrome/browser/search_engines/search_terms_data.h"
+#include "chrome/browser/search_engines/template_url.h"
+#include "chrome/common/pref_names.h"
+#include "content/public/browser/notification_service.h"
+#include "grit/generated_resources.h"
+#include "policy/policy_constants.h"
+
+namespace policy {
+
+// List of policy types to preference names, for policies affecting the default
+// search provider.
+const PolicyToPreferenceMapEntry kDefaultSearchPolicyMap[] = {
+ { key::kDefaultSearchProviderEnabled,
+ prefs::kDefaultSearchProviderEnabled,
+ Value::TYPE_BOOLEAN },
+ { key::kDefaultSearchProviderName,
+ prefs::kDefaultSearchProviderName,
+ Value::TYPE_STRING },
+ { key::kDefaultSearchProviderKeyword,
+ prefs::kDefaultSearchProviderKeyword,
+ Value::TYPE_STRING },
+ { key::kDefaultSearchProviderSearchURL,
+ prefs::kDefaultSearchProviderSearchURL,
+ Value::TYPE_STRING },
+ { key::kDefaultSearchProviderSuggestURL,
+ prefs::kDefaultSearchProviderSuggestURL,
+ Value::TYPE_STRING },
+ { key::kDefaultSearchProviderInstantURL,
+ prefs::kDefaultSearchProviderInstantURL,
+ Value::TYPE_STRING },
+ { key::kDefaultSearchProviderIconURL,
+ prefs::kDefaultSearchProviderIconURL,
+ Value::TYPE_STRING },
+ { key::kDefaultSearchProviderEncodings,
+ prefs::kDefaultSearchProviderEncodings,
+ Value::TYPE_LIST },
+ { key::kDefaultSearchProviderAlternateURLs,
+ prefs::kDefaultSearchProviderAlternateURLs,
+ Value::TYPE_LIST },
+ { key::kDefaultSearchProviderSearchTermsReplacementKey,
+ prefs::kDefaultSearchProviderSearchTermsReplacementKey,
+ Value::TYPE_STRING },
+ { key::kDefaultSearchProviderImageURL,
+ prefs::kDefaultSearchProviderImageURL,
+ Value::TYPE_STRING },
+ { key::kDefaultSearchProviderNewTabURL,
+ prefs::kDefaultSearchProviderNewTabURL,
+ Value::TYPE_STRING },
+ { key::kDefaultSearchProviderSearchURLPostParams,
+ prefs::kDefaultSearchProviderSearchURLPostParams,
+ Value::TYPE_STRING },
+ { key::kDefaultSearchProviderSuggestURLPostParams,
+ prefs::kDefaultSearchProviderSuggestURLPostParams,
+ Value::TYPE_STRING },
+ { key::kDefaultSearchProviderInstantURLPostParams,
+ prefs::kDefaultSearchProviderInstantURLPostParams,
+ Value::TYPE_STRING },
+ { key::kDefaultSearchProviderImageURLPostParams,
+ prefs::kDefaultSearchProviderImageURLPostParams,
+ Value::TYPE_STRING },
+};
+
+// DefaultSearchEncodingsPolicyHandler implementation --------------------------
+
+DefaultSearchEncodingsPolicyHandler::DefaultSearchEncodingsPolicyHandler()
+ : TypeCheckingPolicyHandler(key::kDefaultSearchProviderEncodings,
+ Value::TYPE_LIST) {}
+
+DefaultSearchEncodingsPolicyHandler::~DefaultSearchEncodingsPolicyHandler() {
+}
+
+void DefaultSearchEncodingsPolicyHandler::ApplyPolicySettings(
+ const PolicyMap& policies, PrefValueMap* prefs) {
+ // The DefaultSearchProviderEncodings policy has type list, but the related
+ // preference has type string. Convert one into the other here, using
+ // ';' as a separator.
+ const Value* value = policies.GetValue(policy_name());
+ const ListValue* list;
+ if (!value || !value->GetAsList(&list))
+ return;
+
+ ListValue::const_iterator iter(list->begin());
+ ListValue::const_iterator end(list->end());
+ std::vector<std::string> string_parts;
+ for (; iter != end; ++iter) {
+ std::string s;
+ if ((*iter)->GetAsString(&s)) {
+ string_parts.push_back(s);
+ }
+ }
+ std::string encodings = JoinString(string_parts, ';');
+ prefs->SetValue(prefs::kDefaultSearchProviderEncodings,
+ Value::CreateStringValue(encodings));
+}
+
+
+// DefaultSearchPolicyHandler implementation -----------------------------------
+
+DefaultSearchPolicyHandler::DefaultSearchPolicyHandler() {
+ for (size_t i = 0; i < arraysize(kDefaultSearchPolicyMap); ++i) {
+ const char* policy_name = kDefaultSearchPolicyMap[i].policy_name;
+ if (policy_name == key::kDefaultSearchProviderEncodings) {
+ handlers_.push_back(new DefaultSearchEncodingsPolicyHandler());
+ } else {
+ handlers_.push_back(new SimplePolicyHandler(
+ policy_name,
+ kDefaultSearchPolicyMap[i].preference_path,
+ kDefaultSearchPolicyMap[i].value_type));
+ }
+ }
+}
+
+DefaultSearchPolicyHandler::~DefaultSearchPolicyHandler() {
+ STLDeleteElements(&handlers_);
+}
+
+bool DefaultSearchPolicyHandler::CheckPolicySettings(const PolicyMap& policies,
+ PolicyErrorMap* errors) {
+ if (!CheckIndividualPolicies(policies, errors))
+ return false;
+
+ if (DefaultSearchProviderIsDisabled(policies)) {
+ // Add an error for all specified default search policies except
+ // DefaultSearchProviderEnabled.
+
+ for (std::vector<TypeCheckingPolicyHandler*>::const_iterator handler =
+ handlers_.begin();
+ handler != handlers_.end(); ++handler) {
+ const char* policy_name = (*handler)->policy_name();
+ if (policy_name != key::kDefaultSearchProviderEnabled &&
+ HasDefaultSearchPolicy(policies, policy_name)) {
+ errors->AddError(policy_name, IDS_POLICY_DEFAULT_SEARCH_DISABLED);
+ }
+ }
+ return true;
+ }
+
+ const Value* url;
+ std::string dummy;
+ if (DefaultSearchURLIsValid(policies, &url, &dummy) ||
+ !AnyDefaultSearchPoliciesSpecified(policies))
+ return true;
+ errors->AddError(key::kDefaultSearchProviderSearchURL, url ?
+ IDS_POLICY_INVALID_SEARCH_URL_ERROR : IDS_POLICY_NOT_SPECIFIED_ERROR);
+ return false;
+}
+
+void DefaultSearchPolicyHandler::ApplyPolicySettings(const PolicyMap& policies,
+ PrefValueMap* prefs) {
+ if (DefaultSearchProviderIsDisabled(policies)) {
+ prefs->SetBoolean(prefs::kDefaultSearchProviderEnabled, false);
+
+ // If default search is disabled, the other fields are ignored.
+ prefs->SetString(prefs::kDefaultSearchProviderName, std::string());
+ prefs->SetString(prefs::kDefaultSearchProviderSearchURL, std::string());
+ prefs->SetString(prefs::kDefaultSearchProviderSuggestURL, std::string());
+ prefs->SetString(prefs::kDefaultSearchProviderIconURL, std::string());
+ prefs->SetString(prefs::kDefaultSearchProviderEncodings, std::string());
+ prefs->SetString(prefs::kDefaultSearchProviderKeyword, std::string());
+ prefs->SetString(prefs::kDefaultSearchProviderInstantURL, std::string());
+ prefs->SetString(prefs::kDefaultSearchProviderNewTabURL, std::string());
+ prefs->SetValue(prefs::kDefaultSearchProviderAlternateURLs,
+ new ListValue());
+ prefs->SetString(
+ prefs::kDefaultSearchProviderSearchTermsReplacementKey, std::string());
+ prefs->SetString(prefs::kDefaultSearchProviderImageURL, std::string());
+ prefs->SetString(
+ prefs::kDefaultSearchProviderSearchURLPostParams, std::string());
+ prefs->SetString(
+ prefs::kDefaultSearchProviderSuggestURLPostParams, std::string());
+ prefs->SetString(
+ prefs::kDefaultSearchProviderInstantURLPostParams, std::string());
+ prefs->SetString(
+ prefs::kDefaultSearchProviderImageURLPostParams, std::string());
+ } else {
+ // The search URL is required. The other entries are optional. Just make
+ // sure that they are all specified via policy, so that the regular prefs
+ // aren't used.
+ const Value* dummy;
+ std::string url;
+ if (DefaultSearchURLIsValid(policies, &dummy, &url)) {
+
+ for (std::vector<TypeCheckingPolicyHandler*>::const_iterator handler =
+ handlers_.begin();
+ handler != handlers_.end(); ++handler) {
+ (*handler)->ApplyPolicySettings(policies, prefs);
+ }
+
+ EnsureStringPrefExists(prefs, prefs::kDefaultSearchProviderSuggestURL);
+ EnsureStringPrefExists(prefs, prefs::kDefaultSearchProviderIconURL);
+ EnsureStringPrefExists(prefs, prefs::kDefaultSearchProviderEncodings);
+ EnsureStringPrefExists(prefs, prefs::kDefaultSearchProviderKeyword);
+ EnsureStringPrefExists(prefs, prefs::kDefaultSearchProviderInstantURL);
+ EnsureStringPrefExists(prefs, prefs::kDefaultSearchProviderNewTabURL);
+ EnsureListPrefExists(prefs, prefs::kDefaultSearchProviderAlternateURLs);
+ EnsureStringPrefExists(
+ prefs,
+ prefs::kDefaultSearchProviderSearchTermsReplacementKey);
+ EnsureStringPrefExists(prefs, prefs::kDefaultSearchProviderImageURL);
+ EnsureStringPrefExists(
+ prefs,
+ prefs::kDefaultSearchProviderSearchURLPostParams);
+ EnsureStringPrefExists(
+ prefs,
+ prefs::kDefaultSearchProviderSuggestURLPostParams);
+ EnsureStringPrefExists(
+ prefs,
+ prefs::kDefaultSearchProviderInstantURLPostParams);
+ EnsureStringPrefExists(
+ prefs,
+ prefs::kDefaultSearchProviderImageURLPostParams);
+
+ // For the name and keyword, default to the host if not specified. If
+ // there is no host (file: URLs? Not sure), use "_" to guarantee that the
+ // keyword is non-empty.
+ std::string name, keyword;
+ std::string host(GURL(url).host());
+ if (host.empty())
+ host = "_";
+ if (!prefs->GetString(prefs::kDefaultSearchProviderName, &name) ||
+ name.empty()) {
+ prefs->SetString(prefs::kDefaultSearchProviderName, host);
+ }
+ if (!prefs->GetString(prefs::kDefaultSearchProviderKeyword, &keyword) ||
+ keyword.empty()) {
+ prefs->SetString(prefs::kDefaultSearchProviderKeyword, host);
+ }
+
+ // And clear the IDs since these are not specified via policy.
+ prefs->SetString(prefs::kDefaultSearchProviderID, std::string());
+ prefs->SetString(prefs::kDefaultSearchProviderPrepopulateID,
+ std::string());
+ }
+ }
+ content::NotificationService::current()->Notify(
+ chrome::NOTIFICATION_DEFAULT_SEARCH_POLICY_CHANGED,
+ content::NotificationService::AllSources(),
+ content::NotificationService::NoDetails());
+}
+
+bool DefaultSearchPolicyHandler::CheckIndividualPolicies(
+ const PolicyMap& policies,
+ PolicyErrorMap* errors) {
+ for (std::vector<TypeCheckingPolicyHandler*>::const_iterator handler =
+ handlers_.begin();
+ handler != handlers_.end(); ++handler) {
+ if (!(*handler)->CheckPolicySettings(policies, errors))
+ return false;
+ }
+ return true;
+}
+
+bool DefaultSearchPolicyHandler::HasDefaultSearchPolicy(
+ const PolicyMap& policies,
+ const char* policy_name) {
+ return policies.Get(policy_name) != NULL;
+}
+
+bool DefaultSearchPolicyHandler::AnyDefaultSearchPoliciesSpecified(
+ const PolicyMap& policies) {
+ for (std::vector<TypeCheckingPolicyHandler*>::const_iterator handler =
+ handlers_.begin();
+ handler != handlers_.end(); ++handler) {
+ if (policies.Get((*handler)->policy_name()))
+ return true;
+ }
+ return false;
+}
+
+bool DefaultSearchPolicyHandler::DefaultSearchProviderIsDisabled(
+ const PolicyMap& policies) {
+ const Value* provider_enabled =
+ policies.GetValue(key::kDefaultSearchProviderEnabled);
+ bool enabled = true;
+ return provider_enabled && provider_enabled->GetAsBoolean(&enabled) &&
+ !enabled;
+}
+
+bool DefaultSearchPolicyHandler::DefaultSearchURLIsValid(
+ const PolicyMap& policies,
+ const Value** url_value,
+ std::string* url_string) {
+ *url_value = policies.GetValue(key::kDefaultSearchProviderSearchURL);
+ if (!*url_value || !(*url_value)->GetAsString(url_string) ||
+ url_string->empty())
+ return false;
+ TemplateURLData data;
+ data.SetURL(*url_string);
+ SearchTermsData search_terms_data;
+ return TemplateURL(NULL, data).SupportsReplacementUsingTermsData(
+ search_terms_data);
+}
+
+void DefaultSearchPolicyHandler::EnsureStringPrefExists(
+ PrefValueMap* prefs,
+ const std::string& path) {
+ std::string value;
+ if (!prefs->GetString(path, &value))
+ prefs->SetString(path, value);
+}
+
+void DefaultSearchPolicyHandler::EnsureListPrefExists(
+ PrefValueMap* prefs,
+ const std::string& path) {
+ base::Value* value;
+ base::ListValue* list_value;
+ if (!prefs->GetValue(path, &value) || !value->GetAsList(&list_value))
+ prefs->SetValue(path, new ListValue());
+}
+
+} // namespace policy
diff --git a/chrome/browser/search_engines/default_search_policy_handler.h b/chrome/browser/search_engines/default_search_policy_handler.h
new file mode 100644
index 0000000000..c0fe7151de
--- /dev/null
+++ b/chrome/browser/search_engines/default_search_policy_handler.h
@@ -0,0 +1,79 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SEARCH_ENGINES_DEFAULT_SEARCH_POLICY_HANDLER_H_
+#define CHROME_BROWSER_SEARCH_ENGINES_DEFAULT_SEARCH_POLICY_HANDLER_H_
+
+#include <vector>
+
+#include "chrome/browser/policy/configuration_policy_handler.h"
+
+namespace policy {
+
+// ConfigurationPolicyHandler for the DefaultSearchEncodings policy.
+class DefaultSearchEncodingsPolicyHandler
+ : public TypeCheckingPolicyHandler {
+ public:
+ DefaultSearchEncodingsPolicyHandler();
+ virtual ~DefaultSearchEncodingsPolicyHandler();
+
+ // ConfigurationPolicyHandler methods:
+ virtual void ApplyPolicySettings(const PolicyMap& policies,
+ PrefValueMap* prefs) OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DefaultSearchEncodingsPolicyHandler);
+};
+
+// ConfigurationPolicyHandler for the default search policies.
+class DefaultSearchPolicyHandler : public ConfigurationPolicyHandler {
+ public:
+ DefaultSearchPolicyHandler();
+ virtual ~DefaultSearchPolicyHandler();
+
+ // ConfigurationPolicyHandler methods:
+ virtual bool CheckPolicySettings(const PolicyMap& policies,
+ PolicyErrorMap* errors) OVERRIDE;
+ virtual void ApplyPolicySettings(const PolicyMap& policies,
+ PrefValueMap* prefs) OVERRIDE;
+
+ private:
+ // Calls |CheckPolicySettings()| on each of the handlers in |handlers_|
+ // and returns whether all of the calls succeeded.
+ bool CheckIndividualPolicies(const PolicyMap& policies,
+ PolicyErrorMap* errors);
+
+ // Returns whether there is a value for |policy_name| in |policies|.
+ bool HasDefaultSearchPolicy(const PolicyMap& policies,
+ const char* policy_name);
+
+ // Returns whether any default search policies are specified in |policies|.
+ bool AnyDefaultSearchPoliciesSpecified(const PolicyMap& policies);
+
+ // Returns whether the default search provider is disabled.
+ bool DefaultSearchProviderIsDisabled(const PolicyMap& policies);
+
+ // Returns whether the default search URL is set and valid. On success, both
+ // outparams (which must be non-NULL) are filled with the search URL.
+ bool DefaultSearchURLIsValid(const PolicyMap& policies,
+ const Value** url_value,
+ std::string* url_string);
+
+ // Make sure that the |path| is present in |prefs_|. If not, set it to
+ // a blank string.
+ void EnsureStringPrefExists(PrefValueMap* prefs, const std::string& path);
+
+ // Make sure that the |path| is present in |prefs_| and is a ListValue. If
+ // not, set it to an empty list.
+ void EnsureListPrefExists(PrefValueMap* prefs, const std::string& path);
+
+ // The ConfigurationPolicyHandler handlers for each default search policy.
+ std::vector<TypeCheckingPolicyHandler*> handlers_;
+
+ DISALLOW_COPY_AND_ASSIGN(DefaultSearchPolicyHandler);
+};
+
+} // namespace policy
+
+#endif // CHROME_BROWSER_SEARCH_ENGINES_DEFAULT_SEARCH_POLICY_HANDLER_H_
diff --git a/chrome/browser/search_engines/default_search_policy_handler_unittest.cc b/chrome/browser/search_engines/default_search_policy_handler_unittest.cc
new file mode 100644
index 0000000000..ca880432fb
--- /dev/null
+++ b/chrome/browser/search_engines/default_search_policy_handler_unittest.cc
@@ -0,0 +1,294 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/policy/configuration_policy_pref_store.h"
+#include "chrome/browser/policy/configuration_policy_pref_store_unittest.h"
+#include "chrome/browser/search_engines/default_search_policy_handler.h"
+#include "chrome/common/pref_names.h"
+#include "policy/policy_constants.h"
+
+namespace policy {
+
+class DefaultSearchPolicyHandlerTest
+ : public ConfigurationPolicyPrefStoreTest {
+ public:
+ DefaultSearchPolicyHandlerTest() {
+ default_alternate_urls_.AppendString(
+ "http://www.google.com/#q={searchTerms}");
+ default_alternate_urls_.AppendString(
+ "http://www.google.com/search#q={searchTerms}");
+ }
+
+ protected:
+ static const char kSearchURL[];
+ static const char kSuggestURL[];
+ static const char kIconURL[];
+ static const char kName[];
+ static const char kKeyword[];
+ static const char kReplacementKey[];
+ static const char kImageURL[];
+ static const char kImageParams[];
+ static const char kNewTabURL[];
+
+ // Build a default search policy by setting search-related keys in |policy| to
+ // reasonable values. You can update any of the keys after calling this
+ // method.
+ void BuildDefaultSearchPolicy(PolicyMap* policy);
+
+ base::ListValue default_alternate_urls_;
+};
+
+const char DefaultSearchPolicyHandlerTest::kSearchURL[] =
+ "http://test.com/search?t={searchTerms}";
+const char DefaultSearchPolicyHandlerTest::kSuggestURL[] =
+ "http://test.com/sugg?={searchTerms}";
+const char DefaultSearchPolicyHandlerTest::kIconURL[] =
+ "http://test.com/icon.jpg";
+const char DefaultSearchPolicyHandlerTest::kName[] =
+ "MyName";
+const char DefaultSearchPolicyHandlerTest::kKeyword[] =
+ "MyKeyword";
+const char DefaultSearchPolicyHandlerTest::kReplacementKey[] =
+ "espv";
+const char DefaultSearchPolicyHandlerTest::kImageURL[] =
+ "http://test.com/searchbyimage/upload";
+const char DefaultSearchPolicyHandlerTest::kImageParams[] =
+ "image_content=content,image_url=http://test.com/test.png";
+const char DefaultSearchPolicyHandlerTest::kNewTabURL[] =
+ "http://test.com/newtab";
+
+void DefaultSearchPolicyHandlerTest::
+ BuildDefaultSearchPolicy(PolicyMap* policy) {
+ base::ListValue* encodings = new base::ListValue();
+ encodings->AppendString("UTF-16");
+ encodings->AppendString("UTF-8");
+ policy->Set(key::kDefaultSearchProviderEnabled, POLICY_LEVEL_MANDATORY,
+ POLICY_SCOPE_USER, base::Value::CreateBooleanValue(true), NULL);
+ policy->Set(key::kDefaultSearchProviderSearchURL, POLICY_LEVEL_MANDATORY,
+ POLICY_SCOPE_USER, base::Value::CreateStringValue(kSearchURL),
+ NULL);
+ policy->Set(key::kDefaultSearchProviderName, POLICY_LEVEL_MANDATORY,
+ POLICY_SCOPE_USER, base::Value::CreateStringValue(kName), NULL);
+ policy->Set(key::kDefaultSearchProviderKeyword, POLICY_LEVEL_MANDATORY,
+ POLICY_SCOPE_USER, base::Value::CreateStringValue(kKeyword),
+ NULL);
+ policy->Set(key::kDefaultSearchProviderSuggestURL, POLICY_LEVEL_MANDATORY,
+ POLICY_SCOPE_USER, base::Value::CreateStringValue(kSuggestURL),
+ NULL);
+ policy->Set(key::kDefaultSearchProviderIconURL, POLICY_LEVEL_MANDATORY,
+ POLICY_SCOPE_USER, base::Value::CreateStringValue(kIconURL),
+ NULL);
+ policy->Set(key::kDefaultSearchProviderEncodings, POLICY_LEVEL_MANDATORY,
+ POLICY_SCOPE_USER, encodings, NULL);
+ policy->Set(key::kDefaultSearchProviderAlternateURLs, POLICY_LEVEL_MANDATORY,
+ POLICY_SCOPE_USER, default_alternate_urls_.DeepCopy(), NULL);
+ policy->Set(key::kDefaultSearchProviderSearchTermsReplacementKey,
+ POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+ base::Value::CreateStringValue(kReplacementKey), NULL);
+ policy->Set(key::kDefaultSearchProviderImageURL,
+ POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+ base::Value::CreateStringValue(kImageURL), NULL);
+ policy->Set(key::kDefaultSearchProviderImageURLPostParams,
+ POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+ base::Value::CreateStringValue(kImageParams), NULL);
+ policy->Set(key::kDefaultSearchProviderNewTabURL,
+ POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+ base::Value::CreateStringValue(kNewTabURL), NULL);
+}
+
+// Checks that if the policy for default search is valid, i.e. there's a
+// search URL, that all the elements have been given proper defaults.
+TEST_F(DefaultSearchPolicyHandlerTest, MinimallyDefined) {
+ PolicyMap policy;
+ policy.Set(key::kDefaultSearchProviderEnabled, POLICY_LEVEL_MANDATORY,
+ POLICY_SCOPE_USER, base::Value::CreateBooleanValue(true), NULL);
+ policy.Set(key::kDefaultSearchProviderSearchURL, POLICY_LEVEL_MANDATORY,
+ POLICY_SCOPE_USER, base::Value::CreateStringValue(kSearchURL),
+ NULL);
+ UpdateProviderPolicy(policy);
+
+ const base::Value* value = NULL;
+ EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderSearchURL, &value));
+ EXPECT_TRUE(base::StringValue(kSearchURL).Equals(value));
+
+ EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderName, &value));
+ EXPECT_TRUE(base::StringValue("test.com").Equals(value));
+
+ EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderKeyword, &value));
+ EXPECT_TRUE(base::StringValue("test.com").Equals(value));
+
+ EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderSuggestURL,
+ &value));
+ EXPECT_TRUE(base::StringValue(std::string()).Equals(value));
+
+ EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderIconURL, &value));
+ EXPECT_TRUE(base::StringValue(std::string()).Equals(value));
+
+ EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderEncodings, &value));
+ EXPECT_TRUE(base::StringValue(std::string()).Equals(value));
+
+ EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderInstantURL,
+ &value));
+ EXPECT_TRUE(base::StringValue(std::string()).Equals(value));
+
+ EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderAlternateURLs,
+ &value));
+ EXPECT_TRUE(base::ListValue().Equals(value));
+
+ EXPECT_TRUE(
+ store_->GetValue(prefs::kDefaultSearchProviderSearchTermsReplacementKey,
+ &value));
+ EXPECT_TRUE(base::StringValue(std::string()).Equals(value));
+
+ EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderImageURL, &value));
+ EXPECT_TRUE(base::StringValue(std::string()).Equals(value));
+
+ EXPECT_TRUE(store_->GetValue(
+ prefs::kDefaultSearchProviderSearchURLPostParams, &value));
+ EXPECT_TRUE(base::StringValue(std::string()).Equals(value));
+
+ EXPECT_TRUE(store_->GetValue(
+ prefs::kDefaultSearchProviderSuggestURLPostParams, &value));
+ EXPECT_TRUE(base::StringValue(std::string()).Equals(value));
+
+ EXPECT_TRUE(store_->GetValue(
+ prefs::kDefaultSearchProviderInstantURLPostParams, &value));
+ EXPECT_TRUE(base::StringValue(std::string()).Equals(value));
+
+ EXPECT_TRUE(store_->GetValue(
+ prefs::kDefaultSearchProviderImageURLPostParams, &value));
+ EXPECT_TRUE(base::StringValue(std::string()).Equals(value));
+
+ EXPECT_TRUE(store_->GetValue(
+ prefs::kDefaultSearchProviderNewTabURL, &value));
+ EXPECT_TRUE(base::StringValue(std::string()).Equals(value));
+}
+
+// Checks that for a fully defined search policy, all elements have been
+// read properly.
+TEST_F(DefaultSearchPolicyHandlerTest, FullyDefined) {
+ PolicyMap policy;
+ BuildDefaultSearchPolicy(&policy);
+ UpdateProviderPolicy(policy);
+
+ const base::Value* value = NULL;
+ EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderSearchURL, &value));
+ EXPECT_TRUE(base::StringValue(kSearchURL).Equals(value));
+
+ EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderName, &value));
+ EXPECT_TRUE(base::StringValue(kName).Equals(value));
+
+ EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderKeyword, &value));
+ EXPECT_TRUE(base::StringValue(kKeyword).Equals(value));
+
+ EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderSuggestURL,
+ &value));
+ EXPECT_TRUE(base::StringValue(kSuggestURL).Equals(value));
+
+ EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderIconURL, &value));
+ EXPECT_TRUE(base::StringValue(kIconURL).Equals(value));
+
+ EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderEncodings, &value));
+ EXPECT_TRUE(base::StringValue("UTF-16;UTF-8").Equals(value));
+
+ EXPECT_TRUE(store_->GetValue(
+ prefs::kDefaultSearchProviderAlternateURLs, &value));
+ EXPECT_TRUE(default_alternate_urls_.Equals(value));
+
+ EXPECT_TRUE(
+ store_->GetValue(prefs::kDefaultSearchProviderSearchTermsReplacementKey,
+ &value));
+ EXPECT_TRUE(base::StringValue(kReplacementKey).Equals(value));
+
+ EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderImageURL, &value));
+ EXPECT_TRUE(base::StringValue(std::string(kImageURL)).Equals(value));
+
+ EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderImageURLPostParams,
+ &value));
+ EXPECT_TRUE(base::StringValue(std::string(kImageParams)).Equals(value));
+
+ EXPECT_TRUE(store_->GetValue(
+ prefs::kDefaultSearchProviderSearchURLPostParams, &value));
+ EXPECT_TRUE(base::StringValue(std::string()).Equals(value));
+
+ EXPECT_TRUE(store_->GetValue(
+ prefs::kDefaultSearchProviderSuggestURLPostParams, &value));
+ EXPECT_TRUE(base::StringValue(std::string()).Equals(value));
+
+ EXPECT_TRUE(store_->GetValue(
+ prefs::kDefaultSearchProviderInstantURLPostParams, &value));
+ EXPECT_TRUE(base::StringValue(std::string()).Equals(value));
+}
+
+// Checks that if the default search policy is missing, that no elements of the
+// default search policy will be present.
+TEST_F(DefaultSearchPolicyHandlerTest, MissingUrl) {
+ PolicyMap policy;
+ BuildDefaultSearchPolicy(&policy);
+ policy.Erase(key::kDefaultSearchProviderSearchURL);
+ UpdateProviderPolicy(policy);
+
+ EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderSearchURL, NULL));
+ EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderName, NULL));
+ EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderKeyword, NULL));
+ EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderSuggestURL, NULL));
+ EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderIconURL, NULL));
+ EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderEncodings, NULL));
+ EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderAlternateURLs,
+ NULL));
+ EXPECT_FALSE(store_->GetValue(
+ prefs::kDefaultSearchProviderSearchTermsReplacementKey, NULL));
+ EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderImageURL, NULL));
+ EXPECT_FALSE(store_->GetValue(
+ prefs::kDefaultSearchProviderImageURLPostParams, NULL));
+ EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderInstantURL, NULL));
+ EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderNewTabURL, NULL));
+}
+
+// Checks that if the default search policy is invalid, that no elements of the
+// default search policy will be present.
+TEST_F(DefaultSearchPolicyHandlerTest, Invalid) {
+ PolicyMap policy;
+ BuildDefaultSearchPolicy(&policy);
+ const char bad_search_url[] = "http://test.com/noSearchTerms";
+ policy.Set(key::kDefaultSearchProviderSearchURL, POLICY_LEVEL_MANDATORY,
+ POLICY_SCOPE_USER,
+ base::Value::CreateStringValue(bad_search_url), NULL);
+ UpdateProviderPolicy(policy);
+
+ EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderSearchURL, NULL));
+ EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderName, NULL));
+ EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderKeyword, NULL));
+ EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderSuggestURL, NULL));
+ EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderIconURL, NULL));
+ EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderEncodings, NULL));
+ EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderAlternateURLs,
+ NULL));
+ EXPECT_FALSE(store_->GetValue(
+ prefs::kDefaultSearchProviderSearchTermsReplacementKey, NULL));
+ EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderImageURL, NULL));
+ EXPECT_FALSE(store_->GetValue(
+ prefs::kDefaultSearchProviderImageURLPostParams, NULL));
+ EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderInstantURL, NULL));
+ EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderNewTabURL, NULL));
+}
+
+// Checks that if the default search policy is invalid, that no elements of the
+// default search policy will be present.
+TEST_F(DefaultSearchPolicyHandlerTest, Disabled) {
+ PolicyMap policy;
+ policy.Set(key::kDefaultSearchProviderEnabled, POLICY_LEVEL_MANDATORY,
+ POLICY_SCOPE_USER, base::Value::CreateBooleanValue(false), NULL);
+ UpdateProviderPolicy(policy);
+
+ const base::Value* value = NULL;
+ EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderEnabled, &value));
+ base::FundamentalValue expected_enabled(false);
+ EXPECT_TRUE(base::Value::Equals(&expected_enabled, value));
+ EXPECT_TRUE(store_->GetValue(prefs::kDefaultSearchProviderSearchURL, &value));
+ base::StringValue expected_search_url((std::string()));
+ EXPECT_TRUE(base::Value::Equals(&expected_search_url, value));
+}
+
+} // namespace policy
diff --git a/chrome/browser/sessions/better_session_restore_browsertest.cc b/chrome/browser/sessions/better_session_restore_browsertest.cc
index 11ea512655..ad68c95002 100644
--- a/chrome/browser/sessions/better_session_restore_browsertest.cc
+++ b/chrome/browser/sessions/better_session_restore_browsertest.cc
@@ -9,16 +9,21 @@
#include "base/path_service.h"
#include "base/prefs/pref_service.h"
#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/background/background_mode_manager.h"
#include "chrome/browser/browser_process.h"
+#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/content_settings/cookie_settings.h"
+#include "chrome/browser/defaults.h"
#include "chrome/browser/infobars/confirm_infobar_delegate.h"
#include "chrome/browser/infobars/infobar_service.h"
+#include "chrome/browser/lifetime/application_lifetime.h"
#include "chrome/browser/prefs/session_startup_pref.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_impl.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/sessions/session_backend.h"
#include "chrome/browser/sessions/session_service_factory.h"
+#include "chrome/browser/sessions/session_service_test_helper.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_iterator.h"
@@ -41,6 +46,10 @@
#include "net/url_request/url_request_filter.h"
#include "net/url_request/url_request_test_job.h"
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_nsautorelease_pool.h"
+#endif
+
namespace {
Browser* FindOneOtherBrowserForProfile(Profile* profile,
@@ -97,6 +106,27 @@ net::URLRequestJob* URLRequestFakerForPostRequests(
true);
}
+class FakeBackgroundModeManager : public BackgroundModeManager {
+ public:
+ FakeBackgroundModeManager()
+ : BackgroundModeManager(
+ CommandLine::ForCurrentProcess(),
+ &g_browser_process->profile_manager()->GetProfileInfoCache()),
+ background_mode_active_(false) {}
+
+ void SetBackgroundModeActive(bool active) {
+ background_mode_active_ = active;
+ }
+
+ virtual bool IsBackgroundModeActive() OVERRIDE {
+ return background_mode_active_;
+ }
+
+ private:
+ bool background_mode_active_;
+
+};
+
} // namespace
class BetterSessionRestoreTest : public InProcessBrowserTest {
@@ -138,6 +168,15 @@ class BetterSessionRestoreTest : public InProcessBrowserTest {
}
protected:
+ virtual void SetUpOnMainThread() OVERRIDE {
+ SessionServiceTestHelper helper(
+ SessionServiceFactory::GetForProfile(browser()->profile()));
+ helper.SetForceBrowserNotAliveWithNoWindows(true);
+ helper.ReleaseService();
+ g_browser_process->set_background_mode_manager_for_test(
+ scoped_ptr<BackgroundModeManager>(new FakeBackgroundModeManager));
+ }
+
void StoreDataWithPage(const std::string& filename) {
StoreDataWithPage(browser(), filename);
}
@@ -184,7 +223,11 @@ class BetterSessionRestoreTest : public InProcessBrowserTest {
}
void CheckReloadedPageNotRestored() {
- CheckTitle(browser(), title_storing_);
+ CheckReloadedPageNotRestored(browser());
+ }
+
+ void CheckReloadedPageNotRestored(Browser* browser) {
+ CheckTitle(browser, title_storing_);
}
void CheckTitle(Browser* browser, const string16& expected_title) {
@@ -230,7 +273,12 @@ class BetterSessionRestoreTest : public InProcessBrowserTest {
}
void CheckFormRestored(bool text_present, bool password_present) {
- CheckReloadedPageRestored();
+ CheckFormRestored(browser(), text_present, password_present);
+ }
+
+ void CheckFormRestored(
+ Browser* browser, bool text_present, bool password_present) {
+ CheckReloadedPageRestored(browser);
if (text_present) {
EXPECT_TRUE(g_last_upload_bytes.Get().find("posted-text") !=
std::string::npos);
@@ -255,6 +303,36 @@ class BetterSessionRestoreTest : public InProcessBrowserTest {
}
}
+ void CloseBrowserSynchronously(Browser* browser) {
+ content::WindowedNotificationObserver observer(
+ chrome::NOTIFICATION_BROWSER_CLOSED,
+ content::NotificationService::AllSources());
+ browser->window()->Close();
+#if defined(OS_MACOSX)
+ // BrowserWindowController depends on the auto release pool being recycled
+ // in the message loop to delete itself, which frees the Browser object
+ // which fires this event.
+ AutoreleasePool()->Recycle();
+#endif
+ observer.Wait();
+ }
+
+ virtual Browser* QuitBrowserAndRestore(Browser* browser) {
+ Profile* profile = browser->profile();
+
+ // Close the browser.
+ chrome::StartKeepAlive();
+ CloseBrowserSynchronously(browser);
+
+ // Create a new window, which should trigger session restore.
+ ui_test_utils::BrowserAddedObserver window_observer;
+ chrome::NewEmptyWindow(profile, chrome::HOST_DESKTOP_TYPE_NATIVE);
+ Browser* new_browser = window_observer.WaitForSingleNewBrowser();
+ chrome::EndKeepAlive();
+
+ return new_browser;
+ }
+
std::string fake_server_address() {
return fake_server_address_;
}
@@ -263,6 +341,18 @@ class BetterSessionRestoreTest : public InProcessBrowserTest {
return test_path_;
}
+ void EnableBackgroundMode() {
+ static_cast<FakeBackgroundModeManager*>(
+ g_browser_process->background_mode_manager())->
+ SetBackgroundModeActive(true);
+ }
+
+ void DisableBackgroundMode() {
+ static_cast<FakeBackgroundModeManager*>(
+ g_browser_process->background_mode_manager())->
+ SetBackgroundModeActive(false);
+ }
+
private:
const std::string fake_server_address_;
const std::string test_path_;
@@ -284,6 +374,17 @@ class ContinueWhereILeftOffTest : public BetterSessionRestoreTest {
browser()->profile(), SessionStartupPref(SessionStartupPref::LAST));
}
+ protected:
+ virtual Browser* QuitBrowserAndRestore(Browser* browser) OVERRIDE {
+ content::WindowedNotificationObserver session_restore_observer(
+ chrome::NOTIFICATION_SESSION_RESTORE_DONE,
+ content::NotificationService::AllSources());
+ Browser* new_browser =
+ BetterSessionRestoreTest::QuitBrowserAndRestore(browser);
+ session_restore_observer.Wait();
+ return new_browser;
+ }
+
DISALLOW_COPY_AND_ASSIGN(ContinueWhereILeftOffTest);
};
@@ -360,6 +461,53 @@ IN_PROC_BROWSER_TEST_F(ContinueWhereILeftOffTest, PostWithPassword) {
CheckFormRestored(false, false);
}
+IN_PROC_BROWSER_TEST_F(ContinueWhereILeftOffTest, SessionCookiesBrowserClose) {
+ // Set the startup preference to "continue where I left off" and visit a page
+ // which stores a session cookie.
+ StoreDataWithPage("session_cookies.html");
+ Browser* new_browser = QuitBrowserAndRestore(browser());
+ // The browsing session will be continued; just wait for the page to reload
+ // and check the stored data.
+ CheckReloadedPageRestored(new_browser);
+}
+
+IN_PROC_BROWSER_TEST_F(ContinueWhereILeftOffTest,
+ CookiesClearedOnBrowserClose) {
+ StoreDataWithPage("cookies.html");
+ // Normally cookies are restored.
+ Browser* new_browser = QuitBrowserAndRestore(browser());
+ CheckReloadedPageRestored(new_browser);
+ // ... but not if the content setting is set to clear on exit.
+ CookieSettings::Factory::GetForProfile(new_browser->profile())->
+ SetDefaultCookieSetting(CONTENT_SETTING_SESSION_ONLY);
+ // ... unless background mode is active.
+ EnableBackgroundMode();
+ new_browser = QuitBrowserAndRestore(new_browser);
+ CheckReloadedPageRestored(new_browser);
+
+ DisableBackgroundMode();
+ new_browser = QuitBrowserAndRestore(new_browser);
+ if (browser_defaults::kBrowserAliveWithNoWindows)
+ CheckReloadedPageRestored(new_browser);
+ else
+ CheckReloadedPageNotRestored(new_browser);
+}
+
+IN_PROC_BROWSER_TEST_F(ContinueWhereILeftOffTest, PostBrowserClose) {
+ PostFormWithPage("post.html", false);
+ Browser* new_browser = QuitBrowserAndRestore(browser());
+ CheckFormRestored(new_browser, true, false);
+}
+
+IN_PROC_BROWSER_TEST_F(ContinueWhereILeftOffTest,
+ PostWithPasswordBrowserClose) {
+ PostFormWithPage("post_with_password.html", true);
+ Browser* new_browser = QuitBrowserAndRestore(browser());
+ CheckReloadedPageRestored(new_browser);
+ // The form data contained passwords, so it's removed completely.
+ CheckFormRestored(new_browser, false, false);
+}
+
class RestartTest : public BetterSessionRestoreTest {
public:
RestartTest() { }
@@ -530,3 +678,38 @@ IN_PROC_BROWSER_TEST_F(NoSessionRestoreTest, CookiesClearedOnExit) {
web_contents->GetURL().spec());
StoreDataWithPage("local_storage.html");
}
+
+IN_PROC_BROWSER_TEST_F(NoSessionRestoreTest, SessionCookiesBrowserClose) {
+ StoreDataWithPage("session_cookies.html");
+ EnableBackgroundMode();
+ Browser* new_browser = QuitBrowserAndRestore(browser());
+ NavigateAndCheckStoredData(new_browser, "session_cookies.html");
+ DisableBackgroundMode();
+ new_browser = QuitBrowserAndRestore(new_browser);
+ if (browser_defaults::kBrowserAliveWithNoWindows)
+ NavigateAndCheckStoredData(new_browser, "session_cookies.html");
+ else
+ StoreDataWithPage(new_browser, "session_cookies.html");
+}
+
+IN_PROC_BROWSER_TEST_F(NoSessionRestoreTest, CookiesClearedOnBrowserClose) {
+ StoreDataWithPage("cookies.html");
+
+ // Normally cookies are restored.
+ Browser* new_browser = QuitBrowserAndRestore(browser());
+ NavigateAndCheckStoredData(new_browser, "cookies.html");
+
+ // ... but not if the content setting is set to clear on exit.
+ CookieSettings::Factory::GetForProfile(new_browser->profile())->
+ SetDefaultCookieSetting(CONTENT_SETTING_SESSION_ONLY);
+ // ... unless background mode is active.
+ EnableBackgroundMode();
+ new_browser = QuitBrowserAndRestore(new_browser);
+ NavigateAndCheckStoredData(new_browser, "cookies.html");
+ DisableBackgroundMode();
+ new_browser = QuitBrowserAndRestore(new_browser);
+ if (browser_defaults::kBrowserAliveWithNoWindows)
+ NavigateAndCheckStoredData(new_browser, "cookies.html");
+ else
+ StoreDataWithPage(new_browser, "cookies.html");
+}
diff --git a/chrome/browser/sessions/session_data_deleter.cc b/chrome/browser/sessions/session_data_deleter.cc
new file mode 100644
index 0000000000..2378731718
--- /dev/null
+++ b/chrome/browser/sessions/session_data_deleter.cc
@@ -0,0 +1,169 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "chrome/browser/browser_shutdown.h"
+#include "chrome/browser/net/chrome_url_request_context.h"
+#include "chrome/browser/prefs/session_startup_pref.h"
+#include "chrome/browser/profiles/profile_io_data.h"
+#include "chrome/browser/ui/startup/startup_browser_creator.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/dom_storage_context.h"
+#include "content/public/browser/local_storage_usage_info.h"
+#include "content/public/browser/storage_partition.h"
+#include "net/cookies/cookie_monster.h"
+#include "net/cookies/cookie_store.h"
+#include "net/cookies/cookie_util.h"
+#include "webkit/browser/quota/special_storage_policy.h"
+
+namespace {
+
+void CookieDeleted(bool success) {
+ DCHECK(success);
+}
+
+class SessionDataDeleter
+ : public base::RefCountedThreadSafe<SessionDataDeleter> {
+ public:
+ SessionDataDeleter(quota::SpecialStoragePolicy* storage_policy,
+ bool delete_only_by_session_only_policy);
+
+ void Run(content::StoragePartition* storage_partition,
+ ProfileIOData* profile_io_data);
+
+ private:
+ friend class base::RefCountedThreadSafe<SessionDataDeleter>;
+ ~SessionDataDeleter();
+
+ // Deletes the local storage described by |usages| for origins which are
+ // session-only.
+ void ClearSessionOnlyLocalStorage(
+ content::StoragePartition* storage_partition,
+ const std::vector<content::LocalStorageUsageInfo>& usages);
+
+ // Deletes all cookies that are session only if
+ // |delete_only_by_session_only_policy_| is false. Once completed or skipped,
+ // this arranges for DeleteSessionOnlyOriginCookies to be called with a list
+ // of all remaining cookies.
+ void DeleteSessionCookiesOnIOThread(ProfileIOData* profile_io_data);
+
+ // Called when all session-only cookies have been deleted.
+ void DeleteSessionCookiesDone(int num_deleted);
+
+ // Deletes the cookies in |cookies| that are for origins which are
+ // session-only.
+ void DeleteSessionOnlyOriginCookies(const net::CookieList& cookies);
+
+ base::WeakPtr<ChromeURLRequestContext> request_context_;
+ scoped_refptr<quota::SpecialStoragePolicy> storage_policy_;
+ const bool delete_only_by_session_only_policy_;
+
+ DISALLOW_COPY_AND_ASSIGN(SessionDataDeleter);
+};
+
+SessionDataDeleter::SessionDataDeleter(
+ quota::SpecialStoragePolicy* storage_policy,
+ bool delete_only_by_session_only_policy)
+ : storage_policy_(storage_policy),
+ delete_only_by_session_only_policy_(delete_only_by_session_only_policy) {}
+
+void SessionDataDeleter::Run(content::StoragePartition* storage_partition,
+ ProfileIOData* profile_io_data) {
+ storage_partition->GetDOMStorageContext()->GetLocalStorageUsage(
+ base::Bind(&SessionDataDeleter::ClearSessionOnlyLocalStorage,
+ this,
+ storage_partition));
+ content::BrowserThread::PostTask(
+ content::BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&SessionDataDeleter::DeleteSessionCookiesOnIOThread,
+ this,
+ profile_io_data));
+}
+
+SessionDataDeleter::~SessionDataDeleter() {}
+
+void SessionDataDeleter::ClearSessionOnlyLocalStorage(
+ content::StoragePartition* storage_partition,
+ const std::vector<content::LocalStorageUsageInfo>& usages) {
+ for (std::vector<content::LocalStorageUsageInfo>::const_iterator it =
+ usages.begin();
+ it != usages.end();
+ ++it) {
+ if (storage_policy_->IsStorageSessionOnly(it->origin))
+ storage_partition->GetDOMStorageContext()->DeleteLocalStorage(it->origin);
+ }
+}
+
+void SessionDataDeleter::DeleteSessionCookiesOnIOThread(
+ ProfileIOData* profile_io_data) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+ ChromeURLRequestContext* request_context =
+ profile_io_data->GetMainRequestContext();
+ request_context_ = request_context->GetWeakPtr();
+ net::CookieMonster* cookie_monster =
+ request_context_->cookie_store()->GetCookieMonster();
+ if (delete_only_by_session_only_policy_) {
+ cookie_monster->GetAllCookiesAsync(
+ base::Bind(&SessionDataDeleter::DeleteSessionOnlyOriginCookies, this));
+ } else {
+ cookie_monster->DeleteSessionCookiesAsync(
+ base::Bind(&SessionDataDeleter::DeleteSessionCookiesDone, this));
+ }
+}
+
+void SessionDataDeleter::DeleteSessionCookiesDone(int num_deleted) {
+ ChromeURLRequestContext* request_context = request_context_.get();
+ if (!request_context)
+ return;
+
+ request_context->cookie_store()->GetCookieMonster()->GetAllCookiesAsync(
+ base::Bind(&SessionDataDeleter::DeleteSessionOnlyOriginCookies, this));
+}
+
+void SessionDataDeleter::DeleteSessionOnlyOriginCookies(
+ const net::CookieList& cookies) {
+ ChromeURLRequestContext* request_context = request_context_.get();
+ if (!request_context)
+ return;
+
+ net::CookieMonster* cookie_monster =
+ request_context->cookie_store()->GetCookieMonster();
+ for (net::CookieList::const_iterator it = cookies.begin();
+ it != cookies.end();
+ ++it) {
+ if (storage_policy_->IsStorageSessionOnly(
+ net::cookie_util::CookieOriginToURL(it->Domain(),
+ it->IsSecure()))) {
+ cookie_monster->DeleteCanonicalCookieAsync(*it,
+ base::Bind(CookieDeleted));
+ }
+ }
+}
+
+} // namespace
+
+void DeleteSessionOnlyData(Profile* profile) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ if (browser_shutdown::IsTryingToQuit())
+ return;
+
+#if defined(OS_ANDROID)
+ SessionStartupPref::Type startup_pref_type =
+ SessionStartupPref::GetDefaultStartupType();
+#else
+ SessionStartupPref::Type startup_pref_type =
+ StartupBrowserCreator::GetSessionStartupPref(
+ *CommandLine::ForCurrentProcess(), profile).type;
+#endif
+
+ scoped_refptr<SessionDataDeleter> deleter(
+ new SessionDataDeleter(profile->GetSpecialStoragePolicy(),
+ startup_pref_type == SessionStartupPref::LAST));
+ deleter->Run(
+ Profile::GetDefaultStoragePartition(profile),
+ ProfileIOData::FromResourceContext(profile->GetResourceContext()));
+}
diff --git a/chrome/browser/sessions/session_data_deleter.h b/chrome/browser/sessions/session_data_deleter.h
new file mode 100644
index 0000000000..710cd7e41e
--- /dev/null
+++ b/chrome/browser/sessions/session_data_deleter.h
@@ -0,0 +1,15 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SESSIONS_SESSION_DATA_DELETER_H_
+#define CHROME_BROWSER_SESSIONS_SESSION_DATA_DELETER_H_
+
+class Profile;
+
+// Clears cookies and local storage for origins that are session-only and clears
+// session cookies unless the startup preference is to continue the previous
+// session.
+void DeleteSessionOnlyData(Profile* profile);
+
+#endif // CHROME_BROWSER_SESSIONS_SESSION_DATA_DELETER_H_
diff --git a/chrome/browser/sessions/session_service.cc b/chrome/browser/sessions/session_service.cc
index 8af2138194..0b7aca805c 100644
--- a/chrome/browser/sessions/session_service.cc
+++ b/chrome/browser/sessions/session_service.cc
@@ -16,12 +16,16 @@
#include "base/metrics/histogram.h"
#include "base/pickle.h"
#include "base/threading/thread.h"
+#include "chrome/browser/background/background_mode_manager.h"
+#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/defaults.h"
#include "chrome/browser/extensions/tab_helper.h"
#include "chrome/browser/prefs/session_startup_pref.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sessions/session_backend.h"
#include "chrome/browser/sessions/session_command.h"
+#include "chrome/browser/sessions/session_data_deleter.h"
#include "chrome/browser/sessions/session_restore.h"
#include "chrome/browser/sessions/session_tab_helper.h"
#include "chrome/browser/sessions/session_types.h"
@@ -338,6 +342,14 @@ void SessionService::WindowClosed(const SessionID& window_id) {
else
ScheduleCommand(CreateWindowClosedCommand(window_id.id()));
}
+ // Clear session data if the last window for a profile has been closed and
+ // closing the last window would normally close Chrome, unless background mode
+ // is active.
+ if (!has_open_trackable_browsers_ &&
+ !browser_defaults::kBrowserAliveWithNoWindows &&
+ !g_browser_process->background_mode_manager()->IsBackgroundModeActive()) {
+ DeleteSessionOnlyData(profile());
+ }
}
void SessionService::SetWindowType(const SessionID& window_id,
diff --git a/chrome/browser/sessions/session_service_factory.cc b/chrome/browser/sessions/session_service_factory.cc
index 05cf198989..7e928f988d 100644
--- a/chrome/browser/sessions/session_service_factory.cc
+++ b/chrome/browser/sessions/session_service_factory.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/sessions/session_service_factory.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/sessions/session_data_deleter.h"
#include "chrome/browser/sessions/session_service.h"
#include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
@@ -33,6 +34,8 @@ SessionService* SessionServiceFactory::GetForProfileIfExisting(
// static
void SessionServiceFactory::ShutdownForProfile(Profile* profile) {
+ DeleteSessionOnlyData(profile);
+
// We're about to exit, force creation of the session service if it hasn't
// been created yet. We do this to ensure session state matches the point in
// time the user exited.
diff --git a/chrome/browser/sessions/tab_restore_browsertest.cc b/chrome/browser/sessions/tab_restore_browsertest.cc
index 31f831061d..4d6e849f82 100644
--- a/chrome/browser/sessions/tab_restore_browsertest.cc
+++ b/chrome/browser/sessions/tab_restore_browsertest.cc
@@ -26,6 +26,7 @@
#include "content/public/browser/page_navigator.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
+#include "content/public/test/browser_test_utils.h"
#include "net/base/net_util.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "third_party/WebKit/public/web/WebFindOptions.h"
@@ -70,12 +71,11 @@ class TabRestoreTest : public InProcessBrowserTest {
}
void CloseTab(int index) {
- content::WindowedNotificationObserver tab_close_observer(
- content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
- content::NotificationService::AllSources());
+ content::WebContentsDestroyedWatcher destroyed_watcher(
+ browser()->tab_strip_model()->GetWebContentsAt(index));
browser()->tab_strip_model()->CloseWebContentsAt(
index, TabStripModel::CLOSE_CREATE_HISTORICAL_TAB);
- tab_close_observer.Wait();
+ destroyed_watcher.Wait();
}
// Uses the undo-close-tab accelerator to undo a close-tab or close-window
diff --git a/chrome/browser/signin/account_reconcilor.cc b/chrome/browser/signin/account_reconcilor.cc
new file mode 100644
index 0000000000..7f27ec5950
--- /dev/null
+++ b/chrome/browser/signin/account_reconcilor.cc
@@ -0,0 +1,15 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/signin/account_reconcilor.h"
+
+#include "chrome/browser/profiles/profile.h"
+
+AccountReconcilor::AccountReconcilor(Profile* profile) : profile_(profile) {
+}
+
+AccountReconcilor::~AccountReconcilor() {}
+
+void AccountReconcilor::Shutdown() {}
+
diff --git a/chrome/browser/signin/account_reconcilor.h b/chrome/browser/signin/account_reconcilor.h
new file mode 100644
index 0000000000..b57fa9c585
--- /dev/null
+++ b/chrome/browser/signin/account_reconcilor.h
@@ -0,0 +1,30 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#ifndef CHROME_BROWSER_SIGNIN_ACCOUNT_RECONCILOR_H_
+#define CHROME_BROWSER_SIGNIN_ACCOUNT_RECONCILOR_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "components/browser_context_keyed_service/browser_context_keyed_service.h"
+
+class Profile;
+
+class AccountReconcilor : public BrowserContextKeyedService {
+ public:
+ AccountReconcilor(Profile* profile);
+ virtual ~AccountReconcilor();
+
+ // BrowserContextKeyedService implementation.
+ virtual void Shutdown() OVERRIDE;
+
+ Profile* profile() { return profile_; }
+
+ private:
+ // The profile that this reconcilor belongs to.
+ Profile* profile_;
+
+ DISALLOW_COPY_AND_ASSIGN(AccountReconcilor);
+};
+
+#endif // CHROME_BROWSER_SIGNIN_ACCOUNT_RECONCILOR_H_
diff --git a/chrome/browser/signin/account_reconcilor_factory.cc b/chrome/browser/signin/account_reconcilor_factory.cc
new file mode 100644
index 0000000000..ef250e8d12
--- /dev/null
+++ b/chrome/browser/signin/account_reconcilor_factory.cc
@@ -0,0 +1,41 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/signin/account_reconcilor_factory.h"
+
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
+#include "chrome/browser/signin/signin_manager_factory.h"
+#include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
+
+AccountReconcilorFactory::AccountReconcilorFactory()
+ : BrowserContextKeyedServiceFactory(
+ "AccountReconcilor",
+ BrowserContextDependencyManager::GetInstance()) {
+ DependsOn(ProfileOAuth2TokenServiceFactory::GetInstance());
+ DependsOn(SigninManagerFactory::GetInstance());
+}
+
+AccountReconcilorFactory::~AccountReconcilorFactory() {}
+
+// static
+AccountReconcilor* AccountReconcilorFactory::GetForProfile(
+ Profile* profile) {
+ return static_cast<AccountReconcilor*>(
+ GetInstance()->GetServiceForBrowserContext(profile, true));
+}
+
+// static
+AccountReconcilorFactory* AccountReconcilorFactory::GetInstance() {
+ return Singleton<AccountReconcilorFactory>::get();
+}
+
+BrowserContextKeyedService* AccountReconcilorFactory::BuildServiceInstanceFor(
+ content::BrowserContext* context) const {
+ return new AccountReconcilor(static_cast<Profile*>(context));
+}
+
+void AccountReconcilorFactory::RegisterProfilePrefs(
+ user_prefs::PrefRegistrySyncable* registry) {
+}
diff --git a/chrome/browser/signin/account_reconcilor_factory.h b/chrome/browser/signin/account_reconcilor_factory.h
new file mode 100644
index 0000000000..f17fdf1e80
--- /dev/null
+++ b/chrome/browser/signin/account_reconcilor_factory.h
@@ -0,0 +1,40 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SIGNIN_ACCOUNT_RECONCILOR_FACTORY_H_
+#define CHROME_BROWSER_SIGNIN_ACCOUNT_RECONCILOR_FACTORY_H_
+
+#include "base/memory/singleton.h"
+#include "chrome/browser/signin/account_reconcilor.h"
+#include "components/browser_context_keyed_service/browser_context_keyed_service_factory.h"
+
+class AccountReconcilor;
+class Profile;
+
+// Singleton that owns all AccountReconcilors and associates them with
+// Profiles. Listens for the Profile's destruction notification and cleans up.
+class AccountReconcilorFactory : public BrowserContextKeyedServiceFactory {
+ public:
+ // Returns the instance of AccountReconcilor associated with this profile
+ // (creating one if none exists). Returns NULL if this profile cannot have an
+ // AccountReconcilor (for example, if |profile| is incognito).
+ static AccountReconcilor* GetForProfile(Profile* profile);
+
+ // Returns an instance of the factory singleton.
+ static AccountReconcilorFactory* GetInstance();
+
+ private:
+ friend struct DefaultSingletonTraits<AccountReconcilorFactory>;
+
+ AccountReconcilorFactory();
+ virtual ~AccountReconcilorFactory();
+
+ // BrowserContextKeyedServiceFactory:
+ virtual BrowserContextKeyedService* BuildServiceInstanceFor(
+ content::BrowserContext* profile) const OVERRIDE;
+ virtual void RegisterProfilePrefs(
+ user_prefs::PrefRegistrySyncable* registry) OVERRIDE;
+};
+
+#endif // CHROME_BROWSER_SIGNIN_ACCOUNT_RECONCILOR_FACTORY_H_
diff --git a/chrome/browser/signin/account_reconcilor_unittest.cc b/chrome/browser/signin/account_reconcilor_unittest.cc
new file mode 100644
index 0000000000..c21acc88c9
--- /dev/null
+++ b/chrome/browser/signin/account_reconcilor_unittest.cc
@@ -0,0 +1,52 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/signin/account_reconcilor.h"
+#include "chrome/browser/signin/account_reconcilor_factory.h"
+#include "chrome/browser/signin/fake_profile_oauth2_token_service.h"
+#include "chrome/browser/signin/fake_signin_manager.h"
+#include "chrome/browser/signin/profile_oauth2_token_service.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
+#include "chrome/browser/signin/signin_manager.h"
+#include "chrome/browser/signin/signin_manager_factory.h"
+#include "chrome/test/base/testing_profile.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class AccountReconcilorTest : public testing::Test {
+ public:
+ virtual void SetUp() OVERRIDE;
+ virtual void TearDown() OVERRIDE;
+
+ TestingProfile* profile() { return profile_.get(); }
+
+private:
+ scoped_ptr<TestingProfile> profile_;
+};
+
+void AccountReconcilorTest::SetUp() {
+ TestingProfile::Builder builder;
+ builder.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(),
+ FakeProfileOAuth2TokenService::Build);
+ builder.AddTestingFactory(SigninManagerFactory::GetInstance(),
+ FakeSigninManagerBase::Build);
+ profile_ = builder.Build();
+}
+
+void AccountReconcilorTest::TearDown() {
+ // Destroy the profile before all threads are torn down.
+ profile_.reset();
+}
+
+} // namespace
+
+TEST_F(AccountReconcilorTest, Basic) {
+ AccountReconcilor* reconcilor =
+ AccountReconcilorFactory::GetForProfile(profile());
+ ASSERT_TRUE(NULL != reconcilor);
+ ASSERT_EQ(profile(), reconcilor->profile());
+}
diff --git a/chrome/browser/signin/fake_profile_oauth2_token_service.cc b/chrome/browser/signin/fake_profile_oauth2_token_service.cc
index 6c864b1557..6f783bf5f5 100644
--- a/chrome/browser/signin/fake_profile_oauth2_token_service.cc
+++ b/chrome/browser/signin/fake_profile_oauth2_token_service.cc
@@ -31,11 +31,17 @@ bool FakeProfileOAuth2TokenService::RefreshTokenIsAvailable(
void FakeProfileOAuth2TokenService::IssueRefreshToken(
const std::string& token) {
+ IssueRefreshTokenForUser("account_id", token);
+}
+
+void FakeProfileOAuth2TokenService::IssueRefreshTokenForUser(
+ const std::string& account_id,
+ const std::string& token) {
refresh_token_ = token;
if (refresh_token_.empty())
- FireRefreshTokenRevoked("account_id");
+ FireRefreshTokenRevoked(account_id);
else
- FireRefreshTokenAvailable("account_id");
+ FireRefreshTokenAvailable(account_id);
// TODO(atwilson): Maybe we should also call FireRefreshTokensLoaded() here?
}
@@ -79,6 +85,7 @@ void FakeProfileOAuth2TokenService::CompleteRequests(
const base::Time& expiration) {
std::vector<FakeProfileOAuth2TokenService::PendingRequest> requests =
GetPendingRequests();
+
// Walk the requests and notify the callbacks.
for (std::vector<PendingRequest>::iterator it = pending_requests_.begin();
it != pending_requests_.end(); ++it) {
diff --git a/chrome/browser/signin/fake_profile_oauth2_token_service.h b/chrome/browser/signin/fake_profile_oauth2_token_service.h
index e8e7dc85e6..d7e4923162 100644
--- a/chrome/browser/signin/fake_profile_oauth2_token_service.h
+++ b/chrome/browser/signin/fake_profile_oauth2_token_service.h
@@ -71,6 +71,11 @@ class FakeProfileOAuth2TokenService
// OnRefreshTokenRevoked().
void IssueRefreshToken(const std::string& token);
+ // TODO(fgorski,rogerta): Merge with UpdateCredentials when this class fully
+ // supports multiple accounts.
+ void IssueRefreshTokenForUser(const std::string& account_id,
+ const std::string& token);
+
// Gets a list of active requests (can be used by tests to validate that the
// correct request has been issued).
std::vector<PendingRequest> GetPendingRequests();
diff --git a/chrome/browser/signin/signin_browsertest.cc b/chrome/browser/signin/signin_browsertest.cc
index d3031c0dbe..f85b8bdd47 100644
--- a/chrome/browser/signin/signin_browsertest.cc
+++ b/chrome/browser/signin/signin_browsertest.cc
@@ -171,6 +171,7 @@ class BackOnNTPCommitObserver : public content::WebContentsObserver {
virtual void DidCommitProvisionalLoadForFrame(
int64 frame_id,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& url,
content::PageTransition transition_type,
diff --git a/chrome/browser/signin/signin_promo.cc b/chrome/browser/signin/signin_promo.cc
index fd64bddb1d..be3c5d625f 100644
--- a/chrome/browser/signin/signin_promo.cc
+++ b/chrome/browser/signin/signin_promo.cc
@@ -176,6 +176,17 @@ GURL GetLandingURL(const char* option, int value) {
GURL GetPromoURL(Source source, bool auto_close) {
DCHECK_NE(SOURCE_UNKNOWN, source);
+ bool enable_inline = CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableInlineSignin);
+ if (enable_inline) {
+ std::string url(chrome::kChromeUIInlineLoginURL);
+ base::StringAppendF(&url, "?%s=%d", kSignInPromoQueryKeySource, source);
+ if (auto_close)
+ base::StringAppendF(
+ &url, "&%s=1", kSignInPromoQueryKeyAutoClose);
+ return GURL(url);
+ }
+
// Build a Gaia-based URL that can be used to sign the user into chrome.
// There are required request parameters:
//
diff --git a/chrome/browser/ssl/ssl_blocking_page.cc b/chrome/browser/ssl/ssl_blocking_page.cc
index 056321f5ff..1c380a26bd 100644
--- a/chrome/browser/ssl/ssl_blocking_page.cc
+++ b/chrome/browser/ssl/ssl_blocking_page.cc
@@ -7,7 +7,9 @@
#include "base/i18n/rtl.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
+#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
+#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/history/history_service_factory.h"
@@ -29,6 +31,7 @@
#include "grit/app_locale_settings.h"
#include "grit/browser_resources.h"
#include "grit/generated_resources.h"
+#include "net/base/hash_value.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
#include "ui/base/l10n/l10n_util.h"
@@ -51,7 +54,8 @@ enum SSLBlockingPageCommands {
CMD_DONT_PROCEED,
CMD_PROCEED,
CMD_FOCUS,
- CMD_MORE
+ CMD_MORE,
+ CMD_RELOAD,
};
// Events for UMA.
@@ -198,51 +202,143 @@ SSLBlockingPage::~SSLBlockingPage() {
}
std::string SSLBlockingPage::GetHTMLContents() {
- // Let's build the html error page.
DictionaryValue strings;
- SSLErrorInfo error_info =
- SSLErrorInfo::CreateError(SSLErrorInfo::NetErrorToErrorType(cert_error_),
- ssl_info_.cert.get(),
- request_url_);
-
- int resource_id = IDR_SSL_ROAD_BLOCK_HTML;
- strings.SetString("headLine", error_info.title());
- strings.SetString("description", error_info.details());
- strings.SetString("moreInfoTitle",
- l10n_util::GetStringUTF16(IDS_CERT_ERROR_EXTRA_INFO_TITLE));
- SetExtraInfo(&strings, error_info.extra_information());
-
- strings.SetString("exit",
- l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_EXIT));
-
+ int resource_id;
if (overridable_ && !strict_enforcement_) {
- strings.SetString("title",
- l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_TITLE));
- strings.SetString("proceed",
- l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_PROCEED));
- strings.SetString("reasonForNotProceeding",
- l10n_util::GetStringUTF16(
- IDS_SSL_BLOCKING_PAGE_SHOULD_NOT_PROCEED));
+ // Let's build the overridable error page.
+ SSLErrorInfo error_info =
+ SSLErrorInfo::CreateError(
+ SSLErrorInfo::NetErrorToErrorType(cert_error_),
+ ssl_info_.cert.get(),
+ request_url_);
+
+ resource_id = IDR_SSL_ROAD_BLOCK_HTML;
+ strings.SetString("headLine", error_info.title());
+ strings.SetString("description", error_info.details());
+ strings.SetString("moreInfoTitle",
+ l10n_util::GetStringUTF16(IDS_CERT_ERROR_EXTRA_INFO_TITLE));
+ SetExtraInfo(&strings, error_info.extra_information());
+
+ strings.SetString(
+ "exit", l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_PAGE_EXIT));
+ strings.SetString(
+ "title", l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_PAGE_TITLE));
+ strings.SetString(
+ "proceed", l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_PAGE_PROCEED));
+ strings.SetString(
+ "reasonForNotProceeding", l10n_util::GetStringUTF16(
+ IDS_SSL_OVERRIDABLE_PAGE_SHOULD_NOT_PROCEED));
strings.SetString("errorType", "overridable");
+ strings.SetString("textdirection", base::i18n::IsRTL() ? "rtl" : "ltr");
} else {
- strings.SetString("title",
- l10n_util::GetStringUTF16(IDS_SSL_ERROR_PAGE_TITLE));
- if (strict_enforcement_) {
- strings.SetString("reasonForNotProceeding",
- l10n_util::GetStringUTF16(
- IDS_SSL_ERROR_PAGE_CANNOT_PROCEED));
+ // Let's build the blocking error page.
+ resource_id = IDR_SSL_BLOCKING_HTML;
+
+ // Strings that are not dependent on the URL.
+ strings.SetString(
+ "title", l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_TITLE));
+ strings.SetString(
+ "reloadMsg", l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_RELOAD));
+ strings.SetString(
+ "more", l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_MORE));
+ strings.SetString(
+ "less", l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_LESS));
+ strings.SetString(
+ "moreTitle",
+ l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_MORE_TITLE));
+ strings.SetString(
+ "techTitle",
+ l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_TECH_TITLE));
+
+ // Strings that are dependent on the URL.
+ string16 url(ASCIIToUTF16(request_url_.host()));
+ bool rtl = base::i18n::IsRTL();
+ strings.SetString("textDirection", rtl ? "rtl" : "ltr");
+ if (rtl)
+ base::i18n::WrapStringWithLTRFormatting(&url);
+ strings.SetString(
+ "headline", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_HEADLINE,
+ url.c_str()));
+ strings.SetString(
+ "message", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_BODY_TEXT,
+ url.c_str()));
+ strings.SetString(
+ "moreMessage",
+ l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_MORE_TEXT,
+ url.c_str()));
+ strings.SetString("reloadUrl", request_url_.spec());
+
+ // Strings that are dependent on the error type.
+ SSLErrorInfo::ErrorType type =
+ SSLErrorInfo::NetErrorToErrorType(cert_error_);
+ string16 errorType;
+ if (type == SSLErrorInfo::CERT_REVOKED) {
+ errorType = string16(ASCIIToUTF16("Key revocation"));
+ strings.SetString(
+ "failure",
+ l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_REVOKED));
+ } else if (type == SSLErrorInfo::CERT_INVALID) {
+ errorType = string16(ASCIIToUTF16("Malformed certificate"));
+ strings.SetString(
+ "failure",
+ l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_FORMATTED));
+ } else if (type == SSLErrorInfo::CERT_PINNED_KEY_MISSING) {
+ errorType = string16(ASCIIToUTF16("Certificate pinning failure"));
+ strings.SetString(
+ "failure",
+ l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_PINNING,
+ url.c_str()));
+ } else if (type == SSLErrorInfo::CERT_WEAK_KEY_DH) {
+ errorType = string16(ASCIIToUTF16("Weak DH public key"));
+ strings.SetString(
+ "failure",
+ l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_WEAK_DH,
+ url.c_str()));
} else {
- strings.SetString("reasonForNotProceeding", std::string());
+ // HSTS failure.
+ errorType = string16(ASCIIToUTF16("HSTS failure"));
+ strings.SetString(
+ "failure",
+ l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_HSTS, url.c_str()));
+ }
+ if (rtl)
+ base::i18n::WrapStringWithLTRFormatting(&errorType);
+ strings.SetString(
+ "errorType", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_ERROR,
+ errorType.c_str()));
+
+ // Strings that display the invalid cert.
+ string16 subject(ASCIIToUTF16(ssl_info_.cert->subject().GetDisplayName()));
+ string16 issuer(ASCIIToUTF16(ssl_info_.cert->issuer().GetDisplayName()));
+ std::string hashes;
+ for (std::vector<net::HashValue>::iterator it =
+ ssl_info_.public_key_hashes.begin();
+ it != ssl_info_.public_key_hashes.end();
+ ++it) {
+ base::StringAppendF(&hashes, "%s ", it->ToString().c_str());
}
- strings.SetString("errorType", "notoverridable");
+ string16 fingerprint(ASCIIToUTF16(hashes));
+ if (rtl) {
+ // These are always going to be LTR.
+ base::i18n::WrapStringWithLTRFormatting(&subject);
+ base::i18n::WrapStringWithLTRFormatting(&issuer);
+ base::i18n::WrapStringWithLTRFormatting(&fingerprint);
+ }
+ strings.SetString(
+ "subject", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_SUBJECT,
+ subject.c_str()));
+ strings.SetString(
+ "issuer", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_ISSUER,
+ issuer.c_str()));
+ strings.SetString(
+ "fingerprint",
+ l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_HASHES,
+ fingerprint.c_str()));
}
- strings.SetString("textdirection", base::i18n::IsRTL() ? "rtl" : "ltr");
-
base::StringPiece html(
ResourceBundle::GetSharedInstance().GetRawDataResource(
resource_id));
-
return webui::GetI18nTemplateHtml(html, &strings);
}
@@ -274,6 +370,10 @@ void SSLBlockingPage::CommandReceived(const std::string& command) {
display_start_time_ = base::TimeTicks::Now();
} else if (cmd == CMD_MORE) {
RecordSSLBlockingPageEventStats(MORE);
+ } else if (cmd == CMD_RELOAD) {
+ // The interstitial can't refresh itself.
+ content::NavigationController* controller = &web_contents_->GetController();
+ controller->Reload(true);
}
}
diff --git a/chrome/browser/ssl/ssl_browser_tests.cc b/chrome/browser/ssl/ssl_browser_tests.cc
index 991d5b9241..cba27ee6a0 100644
--- a/chrome/browser/ssl/ssl_browser_tests.cc
+++ b/chrome/browser/ssl/ssl_browser_tests.cc
@@ -75,6 +75,7 @@ class ProvisionalLoadWaiter : public content::WebContentsObserver {
virtual void DidFailProvisionalLoad(
int64 frame_id,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& validated_url,
int error_code,
diff --git a/chrome/browser/ssl/ssl_error_info.cc b/chrome/browser/ssl/ssl_error_info.cc
index d11beb80f3..ac30ed084b 100644
--- a/chrome/browser/ssl/ssl_error_info.cc
+++ b/chrome/browser/ssl/ssl_error_info.cc
@@ -198,6 +198,23 @@ SSLErrorInfo SSLErrorInfo::CreateError(ErrorType error_type,
l10n_util::GetStringUTF16(
IDS_CERT_ERROR_WEAK_KEY_EXTRA_INFO_2));
break;
+ case CERT_WEAK_KEY_DH:
+ title = l10n_util::GetStringUTF16(
+ IDS_ERRORPAGES_HEADING_WEAK_SERVER_EPHEMERAL_DH_KEY);
+ details = l10n_util::GetStringFUTF16(
+ IDS_CERT_ERROR_WEAK_KEY_DETAILS, UTF8ToUTF16(request_url.host()));
+ short_description = l10n_util::GetStringUTF16(
+ IDS_CERT_ERROR_WEAK_KEY_DESCRIPTION);
+ extra_info.push_back(
+ l10n_util::GetStringUTF16(
+ IDS_ERRORPAGES_SUMMARY_WEAK_SERVER_EPHEMERAL_DH_KEY));
+ case CERT_PINNED_KEY_MISSING:
+ title = l10n_util::GetStringUTF16(
+ IDS_ERRORPAGES_HEADING_PINNING_FAILURE);
+ details = l10n_util::GetStringUTF16(
+ IDS_ERRORPAGES_SUMMARY_PINNING_FAILURE);
+ short_description = l10n_util::GetStringUTF16(
+ IDS_ERRORPAGES_DETAILS_PINNING_FAILURE);
case UNKNOWN:
title = l10n_util::GetStringUTF16(IDS_CERT_ERROR_UNKNOWN_ERROR_TITLE);
details = l10n_util::GetStringUTF16(IDS_CERT_ERROR_UNKNOWN_ERROR_DETAILS);
@@ -236,6 +253,10 @@ SSLErrorInfo::ErrorType SSLErrorInfo::NetErrorToErrorType(int net_error) {
return CERT_WEAK_SIGNATURE_ALGORITHM;
case net::ERR_CERT_WEAK_KEY:
return CERT_WEAK_KEY;
+ case net::ERR_SSL_WEAK_SERVER_EPHEMERAL_DH_KEY:
+ return CERT_WEAK_KEY_DH;
+ case net::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN:
+ return CERT_PINNED_KEY_MISSING;
default:
NOTREACHED();
return UNKNOWN;
diff --git a/chrome/browser/ssl/ssl_error_info.h b/chrome/browser/ssl/ssl_error_info.h
index 5e29523edb..b50d225913 100644
--- a/chrome/browser/ssl/ssl_error_info.h
+++ b/chrome/browser/ssl/ssl_error_info.h
@@ -33,6 +33,8 @@ class SSLErrorInfo {
CERT_WEAK_SIGNATURE_ALGORITHM,
CERT_WEAK_KEY,
UNKNOWN,
+ CERT_WEAK_KEY_DH,
+ CERT_PINNED_KEY_MISSING,
END_OF_ENUM
};
diff --git a/chrome/browser/storage_monitor/image_capture_device.mm b/chrome/browser/storage_monitor/image_capture_device.mm
index e70be83f8d..dfbb60646f 100644
--- a/chrome/browser/storage_monitor/image_capture_device.mm
+++ b/chrome/browser/storage_monitor/image_capture_device.mm
@@ -9,23 +9,20 @@
namespace {
-void RenameFile(const base::FilePath& downloaded_filename,
- const base::FilePath& desired_filename,
- base::PlatformFileError* result) {
+base::PlatformFileError RenameFile(const base::FilePath& downloaded_filename,
+ const base::FilePath& desired_filename) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
bool success = base::ReplaceFile(downloaded_filename, desired_filename, NULL);
- *result = success ? base::PLATFORM_FILE_OK
- : base::PLATFORM_FILE_ERROR_NOT_FOUND;
+ return success ? base::PLATFORM_FILE_OK : base::PLATFORM_FILE_ERROR_NOT_FOUND;
}
void ReturnRenameResultToListener(
base::WeakPtr<ImageCaptureDeviceListener> listener,
const std::string& name,
- base::PlatformFileError* result) {
+ const base::PlatformFileError& result) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
- scoped_ptr<base::PlatformFileError> result_deleter(result);
if (listener)
- listener->DownloadedFile(name, *result);
+ listener->DownloadedFile(name, result);
}
base::Time NSDateToBaseTime(NSDate* date) {
@@ -214,12 +211,11 @@ base::FilePath PathForCameraItem(ICCameraItem* item) {
base::FilePath saveAsPath = saveDir.Append(saveAsFilename);
base::FilePath savedPath = saveDir.Append(savedFilename);
// Shared result value from file-copy closure to tell-listener closure.
- base::PlatformFileError* copyResult = new base::PlatformFileError();
- content::BrowserThread::PostTaskAndReply(
+ content::BrowserThread::PostTaskAndReplyWithResult(
content::BrowserThread::FILE,
FROM_HERE,
- base::Bind(&RenameFile, savedPath, saveAsPath, copyResult),
- base::Bind(&ReturnRenameResultToListener, listener_, name, copyResult));
+ base::Bind(&RenameFile, savedPath, saveAsPath),
+ base::Bind(&ReturnRenameResultToListener, listener_, name));
}
@end // ImageCaptureDevice
diff --git a/chrome/browser/storage_monitor/storage_monitor_chromeos_unittest.cc b/chrome/browser/storage_monitor/storage_monitor_chromeos_unittest.cc
index 2ab67a8a92..880b6f93c8 100644
--- a/chrome/browser/storage_monitor/storage_monitor_chromeos_unittest.cc
+++ b/chrome/browser/storage_monitor/storage_monitor_chromeos_unittest.cc
@@ -30,13 +30,10 @@ using content::BrowserThread;
using disks::DiskMountManager;
using testing::_;
-const char kDeviceNameWithManufacturerDetails[] = "110 KB (CompanyA, Z101)";
const char kDevice1[] = "/dev/d1";
const char kDevice1Name[] = "d1";
-const char kDevice1NameWithSizeInfo[] = "110 KB d1";
const char kDevice2[] = "/dev/disk/d2";
const char kDevice2Name[] = "d2";
-const char kDevice2NameWithSizeInfo[] = "207 KB d2";
const char kEmptyDeviceLabel[] = "";
const char kMountPointA[] = "mnt_a";
const char kMountPointB[] = "mnt_b";
diff --git a/chrome/browser/sync/profile_sync_service_android.cc b/chrome/browser/sync/profile_sync_service_android.cc
index 19f94ec92f..ec7d507513 100644
--- a/chrome/browser/sync/profile_sync_service_android.cc
+++ b/chrome/browser/sync/profile_sync_service_android.cc
@@ -46,7 +46,6 @@ using base::android::ScopedJavaLocalRef;
using content::BrowserThread;
namespace {
-const char kSyncDisabledStatus[] = "OFFLINE_DISABLED";
enum {
#define DEFINE_MODEL_TYPE_SELECTION(name,value) name = value,
diff --git a/chrome/browser/sync/profile_sync_service_preference_unittest.cc b/chrome/browser/sync/profile_sync_service_preference_unittest.cc
index 3c5dbe6749..b3683bfada 100644
--- a/chrome/browser/sync/profile_sync_service_preference_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_preference_unittest.cc
@@ -10,6 +10,7 @@
#include "base/callback.h"
#include "base/json/json_reader.h"
#include "base/json/json_string_value_serializer.h"
+#include "base/json/json_writer.h"
#include "base/location.h"
#include "base/stl_util.h"
#include "base/strings/string_piece.h"
@@ -364,6 +365,7 @@ TEST_F(ProfileSyncServicePreferenceTest, ModelAssociationCloudHasData) {
}
PreferenceValues cloud_data;
+ STLValueDeleter<PreferenceValues> cloud_data_deleter(&cloud_data);
cloud_data[prefs::kHomePage] = Value::CreateStringValue(example_url1_);
ListValue* urls_to_restore = new ListValue;
urls_to_restore->Append(Value::CreateStringValue(example_url1_));
@@ -399,7 +401,165 @@ TEST_F(ProfileSyncServicePreferenceTest, ModelAssociationCloudHasData) {
EXPECT_EQ(non_default_charset_value_, string_value);
EXPECT_EQ(non_default_charset_value_,
prefs_->GetString(prefs::kDefaultCharset));
- STLDeleteValues(&cloud_data);
+}
+
+TEST_F(ProfileSyncServicePreferenceTest,
+ ModelAssociationCloudHasOldMigratedData) {
+ ASSERT_TRUE(PrefModelAssociator::IsMigratedPreference(
+ prefs::kURLsToRestoreOnStartup));
+ ASSERT_TRUE(PrefModelAssociator::IsOldMigratedPreference(
+ prefs::kURLsToRestoreOnStartupOld));
+ prefs_->SetString(prefs::kHomePage, example_url0_);
+ {
+ ListPrefUpdate update(prefs_, prefs::kURLsToRestoreOnStartup);
+ ListValue* url_list = update.Get();
+ url_list->Append(Value::CreateStringValue(example_url0_));
+ url_list->Append(Value::CreateStringValue(example_url1_));
+ }
+
+ PreferenceValues cloud_data;
+ STLValueDeleter<PreferenceValues> cloud_data_deleter(&cloud_data);
+ cloud_data[prefs::kHomePage] = Value::CreateStringValue(example_url1_);
+ ListValue* urls_to_restore = new ListValue;
+ urls_to_restore->Append(Value::CreateStringValue(example_url1_));
+ urls_to_restore->Append(Value::CreateStringValue(example_url2_));
+ cloud_data[prefs::kURLsToRestoreOnStartupOld] = urls_to_restore;
+
+ AddPreferenceEntriesHelper helper(this, cloud_data);
+ ASSERT_TRUE(StartSyncService(helper.callback(), false));
+ ASSERT_TRUE(helper.success());
+
+ scoped_ptr<const Value> value(GetSyncedValue(prefs::kHomePage));
+ ASSERT_TRUE(value.get());
+ std::string string_value;
+ EXPECT_TRUE(value->GetAsString(&string_value));
+ EXPECT_EQ(example_url1_, string_value);
+ EXPECT_EQ(example_url1_, prefs_->GetString(prefs::kHomePage));
+
+ // Expect that the new preference data contains the merged old prefs values.
+ scoped_ptr<ListValue> expected_urls(new ListValue);
+ expected_urls->Append(Value::CreateStringValue(example_url1_));
+ expected_urls->Append(Value::CreateStringValue(example_url2_));
+ expected_urls->Append(Value::CreateStringValue(example_url0_));
+
+ value.reset(GetSyncedValue(prefs::kURLsToRestoreOnStartup));
+ ASSERT_TRUE(value.get());
+ EXPECT_TRUE(value->Equals(expected_urls.get()));
+ EXPECT_TRUE(GetPreferenceValue(prefs::kURLsToRestoreOnStartup).
+ Equals(expected_urls.get()));
+
+ // The old preference name should also contain the merged sync data.
+ expected_urls.reset(new ListValue);
+ value.reset(GetSyncedValue(prefs::kURLsToRestoreOnStartupOld));
+ ASSERT_TRUE(value.get());
+ EXPECT_TRUE(GetPreferenceValue(prefs::kURLsToRestoreOnStartupOld).
+ Equals(expected_urls.get()));
+}
+
+TEST_F(ProfileSyncServicePreferenceTest,
+ ModelAssociationCloudHasNewMigratedData) {
+ ASSERT_TRUE(PrefModelAssociator::IsMigratedPreference(
+ prefs::kURLsToRestoreOnStartup));
+ ASSERT_TRUE(PrefModelAssociator::IsOldMigratedPreference(
+ prefs::kURLsToRestoreOnStartupOld));
+ prefs_->SetString(prefs::kHomePage, example_url0_);
+ {
+ ListPrefUpdate update(prefs_, prefs::kURLsToRestoreOnStartupOld);
+ ListValue* url_list = update.Get();
+ url_list->Append(Value::CreateStringValue(example_url0_));
+ url_list->Append(Value::CreateStringValue(example_url1_));
+ }
+
+ PreferenceValues cloud_data;
+ STLValueDeleter<PreferenceValues> cloud_data_deleter(&cloud_data);
+ cloud_data[prefs::kHomePage] = Value::CreateStringValue(example_url1_);
+ ListValue* urls_to_restore = new ListValue;
+ urls_to_restore->Append(Value::CreateStringValue(example_url1_));
+ urls_to_restore->Append(Value::CreateStringValue(example_url2_));
+ cloud_data[prefs::kURLsToRestoreOnStartup] = urls_to_restore;
+
+ AddPreferenceEntriesHelper helper(this, cloud_data);
+ ASSERT_TRUE(StartSyncService(helper.callback(), false));
+ ASSERT_TRUE(helper.success());
+
+ scoped_ptr<const Value> value(GetSyncedValue(prefs::kHomePage));
+ ASSERT_TRUE(value.get());
+ std::string string_value;
+ EXPECT_TRUE(value->GetAsString(&string_value));
+ EXPECT_EQ(example_url1_, string_value);
+ EXPECT_EQ(example_url1_, prefs_->GetString(prefs::kHomePage));
+
+ // Expect that the cloud data under the new migrated preference name sticks.
+ scoped_ptr<ListValue> expected_urls(new ListValue);
+ expected_urls->Append(Value::CreateStringValue(example_url1_));
+ expected_urls->Append(Value::CreateStringValue(example_url2_));
+
+ value.reset(GetSyncedValue(prefs::kURLsToRestoreOnStartup));
+ ASSERT_TRUE(value.get());
+ EXPECT_TRUE(value->Equals(expected_urls.get()));
+ EXPECT_TRUE(GetPreferenceValue(prefs::kURLsToRestoreOnStartup).
+ Equals(expected_urls.get()));
+
+ // The old preference data should still be here, though not synced.
+ expected_urls.reset(new ListValue);
+ expected_urls->Append(Value::CreateStringValue(example_url0_));
+ expected_urls->Append(Value::CreateStringValue(example_url1_));
+
+ value.reset(GetSyncedValue(prefs::kURLsToRestoreOnStartupOld));
+ ASSERT_FALSE(value.get());
+ EXPECT_TRUE(GetPreferenceValue(prefs::kURLsToRestoreOnStartupOld).
+ Equals(expected_urls.get()));
+}
+
+TEST_F(ProfileSyncServicePreferenceTest,
+ ModelAssociationCloudAddsOldAndNewMigratedData) {
+ ASSERT_TRUE(PrefModelAssociator::IsMigratedPreference(
+ prefs::kURLsToRestoreOnStartup));
+ ASSERT_TRUE(PrefModelAssociator::IsOldMigratedPreference(
+ prefs::kURLsToRestoreOnStartupOld));
+ prefs_->SetString(prefs::kHomePage, example_url0_);
+ {
+ ListPrefUpdate update_old(prefs_, prefs::kURLsToRestoreOnStartupOld);
+ ListValue* url_list_old = update_old.Get();
+ url_list_old->Append(Value::CreateStringValue(example_url0_));
+ url_list_old->Append(Value::CreateStringValue(example_url1_));
+ ListPrefUpdate update(prefs_, prefs::kURLsToRestoreOnStartup);
+ ListValue* url_list = update.Get();
+ url_list->Append(Value::CreateStringValue(example_url1_));
+ url_list->Append(Value::CreateStringValue(example_url2_));
+ }
+
+ PreferenceValues cloud_data;
+ STLValueDeleter<PreferenceValues> cloud_data_deleter(&cloud_data);
+ cloud_data[prefs::kHomePage] = Value::CreateStringValue(example_url1_);
+
+ AddPreferenceEntriesHelper helper(this, cloud_data);
+ ASSERT_TRUE(StartSyncService(helper.callback(), false));
+ ASSERT_TRUE(helper.success());
+
+ scoped_ptr<const Value> value(GetSyncedValue(prefs::kHomePage));
+ ASSERT_TRUE(value.get());
+ std::string string_value;
+ EXPECT_TRUE(value->GetAsString(&string_value));
+ EXPECT_EQ(example_url1_, string_value);
+ EXPECT_EQ(example_url1_, prefs_->GetString(prefs::kHomePage));
+
+ // Expect that the cloud data under the new migrated preference name sticks.
+ scoped_ptr<ListValue> expected_urls(new ListValue);
+ expected_urls->Append(Value::CreateStringValue(example_url1_));
+ expected_urls->Append(Value::CreateStringValue(example_url2_));
+
+ value.reset(GetSyncedValue(prefs::kURLsToRestoreOnStartup));
+ ASSERT_TRUE(value.get());
+ EXPECT_TRUE(value->Equals(expected_urls.get()));
+ EXPECT_TRUE(GetPreferenceValue(prefs::kURLsToRestoreOnStartup).
+ Equals(expected_urls.get()));
+
+ // Should not have synced in the old startup url values.
+ value.reset(GetSyncedValue(prefs::kURLsToRestoreOnStartupOld));
+ ASSERT_FALSE(value.get());
+ EXPECT_FALSE(GetPreferenceValue(prefs::kURLsToRestoreOnStartupOld).
+ Equals(expected_urls.get()));
}
TEST_F(ProfileSyncServicePreferenceTest, FailModelAssociation) {
@@ -552,10 +712,11 @@ TEST_F(ProfileSyncServicePreferenceTest, ManagedListPreferences) {
// Set a cloud version.
PreferenceValues cloud_data;
- scoped_ptr<ListValue> urls_to_restore(new ListValue);
+ STLValueDeleter<PreferenceValues> cloud_data_deleter(&cloud_data);
+ ListValue* urls_to_restore = new ListValue;
urls_to_restore->Append(Value::CreateStringValue(example_url1_));
urls_to_restore->Append(Value::CreateStringValue(example_url2_));
- cloud_data[prefs::kURLsToRestoreOnStartup] = urls_to_restore.get();
+ cloud_data[prefs::kURLsToRestoreOnStartup] = urls_to_restore;
// Start sync and verify the synced value didn't get merged.
AddPreferenceEntriesHelper helper(this, cloud_data);
diff --git a/chrome/browser/sync/test/integration/single_client_managed_user_settings_sync_test.cc b/chrome/browser/sync/test/integration/single_client_managed_user_settings_sync_test.cc
index 51b25fd7bc..55b2e08495 100644
--- a/chrome/browser/sync/test/integration/single_client_managed_user_settings_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_managed_user_settings_sync_test.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/command_line.h"
#include "base/prefs/pref_service.h"
#include "base/values.h"
#include "chrome/browser/managed_mode/managed_user_constants.h"
@@ -12,12 +13,19 @@
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/profile_sync_service_harness.h"
#include "chrome/browser/sync/test/integration/sync_test.h"
+#include "chrome/common/chrome_switches.h"
class SingleClientManagedUserSettingsSyncTest : public SyncTest {
public:
SingleClientManagedUserSettingsSyncTest() : SyncTest(SINGLE_CLIENT) {}
virtual ~SingleClientManagedUserSettingsSyncTest() {}
+
+ // SyncTest overrides:
+ virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+ SyncTest::SetUpCommandLine(command_line);
+ command_line->AppendSwitch(switches::kNewProfileIsSupervised);
+ }
};
// TODO(pavely): Fix this test. See also: http://crbug.com/279307
@@ -26,7 +34,6 @@ IN_PROC_BROWSER_TEST_F(SingleClientManagedUserSettingsSyncTest,
ASSERT_TRUE(SetupClients());
for (int i = 0; i < num_clients(); ++i) {
Profile* profile = GetProfile(i);
- ManagedUserServiceFactory::GetForProfile(profile)->InitForTesting();
// Managed users are prohibited from signing into the browser. Currently
// that means they're also unable to sync anything, so override that for
// this test.
diff --git a/chrome/browser/sync/test/integration/sync_extension_helper.cc b/chrome/browser/sync/test/integration/sync_extension_helper.cc
index 3e1c0d4cd1..75a69e60fb 100644
--- a/chrome/browser/sync/test/integration/sync_extension_helper.cc
+++ b/chrome/browser/sync/test/integration/sync_extension_helper.cc
@@ -10,6 +10,7 @@
#include "base/values.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/extensions/pending_extension_info.h"
#include "chrome/browser/extensions/pending_extension_manager.h"
#include "chrome/browser/profiles/profile.h"
@@ -116,20 +117,20 @@ bool SyncExtensionHelper::IsExtensionEnabled(
void SyncExtensionHelper::IncognitoEnableExtension(
Profile* profile, const std::string& name) {
- profile->GetExtensionService()->SetIsIncognitoEnabled(
- extensions::id_util::GenerateId(name), true);
+ extension_util::SetIsIncognitoEnabled(extensions::id_util::GenerateId(name),
+ profile->GetExtensionService(), true);
}
void SyncExtensionHelper::IncognitoDisableExtension(
Profile* profile, const std::string& name) {
- profile->GetExtensionService()->SetIsIncognitoEnabled(
- extensions::id_util::GenerateId(name), false);
+ extension_util::SetIsIncognitoEnabled(extensions::id_util::GenerateId(name),
+ profile->GetExtensionService(), false);
}
bool SyncExtensionHelper::IsIncognitoEnabled(
Profile* profile, const std::string& name) const {
- return profile->GetExtensionService()->IsIncognitoEnabled(
- extensions::id_util::GenerateId(name));
+ return extension_util::IsIncognitoEnabled(
+ extensions::id_util::GenerateId(name), profile->GetExtensionService());
}
@@ -197,7 +198,7 @@ SyncExtensionHelper::ExtensionStateMap
ExtensionState::ENABLED :
ExtensionState::DISABLED;
extension_state_map[id].incognito_enabled =
- extension_service->IsIncognitoEnabled(id);
+ extension_util::IsIncognitoEnabled(id, extension_service);
DVLOG(2) << "Extension " << (*it)->id() << " in profile "
<< profile_debug_name << " is "
@@ -215,7 +216,7 @@ SyncExtensionHelper::ExtensionStateMap
for (id = pending_crx_ids.begin(); id != pending_crx_ids.end(); ++id) {
extension_state_map[*id].enabled_state = ExtensionState::PENDING;
extension_state_map[*id].incognito_enabled =
- extension_service->IsIncognitoEnabled(*id);
+ extension_util::IsIncognitoEnabled(*id, extension_service);
DVLOG(2) << "Extension " << *id << " in profile "
<< profile_debug_name << " is pending";
}
diff --git a/chrome/browser/sync_file_system/drive_backend/drive_backend_constants.cc b/chrome/browser/sync_file_system/drive_backend/drive_backend_constants.cc
index c373fd944b..8b76a0c698 100644
--- a/chrome/browser/sync_file_system/drive_backend/drive_backend_constants.cc
+++ b/chrome/browser/sync_file_system/drive_backend/drive_backend_constants.cc
@@ -11,6 +11,12 @@ const char kSyncRootFolderTitle[] = "Chrome Syncable FileSystem";
const base::FilePath::CharType kDatabaseName[] =
FILE_PATH_LITERAL("DriveMetadata");
+const char kDatabaseVersionKey[] = "VERSION";
+const int64 kCurrentDatabaseVersion = 3;
+const char kServiceMetadataKey[] = "SERVICE";
+const char kFileMetadataKeyPrefix[] = "FILE: ";
+const char kFileTrackerKeyPrefix[] = "TRACKER: ";
+
const int kMaxRetry = 5;
} // namespace drive_backend
diff --git a/chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h b/chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h
index a2a85718e5..de9866d8c5 100644
--- a/chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h
+++ b/chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h
@@ -13,6 +13,12 @@ namespace drive_backend {
extern const char kSyncRootFolderTitle[];
extern const base::FilePath::CharType kDatabaseName[];
+extern const char kDatabaseVersionKey[];
+extern const int64 kCurrentDatabaseVersion;
+extern const char kServiceMetadataKey[];
+extern const char kFileMetadataKeyPrefix[];
+extern const char kFileTrackerKeyPrefix[];
+
extern const int kMaxRetry;
} // namespace drive_backend
diff --git a/chrome/browser/sync_file_system/drive_backend/drive_backend_util.cc b/chrome/browser/sync_file_system/drive_backend/drive_backend_util.cc
new file mode 100644
index 0000000000..b8086da16f
--- /dev/null
+++ b/chrome/browser/sync_file_system/drive_backend/drive_backend_util.cc
@@ -0,0 +1,109 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/sync_file_system/drive_backend/drive_backend_util.h"
+
+#include <string>
+
+#include "base/logging.h"
+#include "base/memory/scoped_vector.h"
+#include "base/strings/string_number_conversions.h"
+#include "chrome/browser/drive/drive_api_util.h"
+#include "chrome/browser/google_apis/drive_api_parser.h"
+#include "chrome/browser/google_apis/gdata_wapi_parser.h"
+#include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h"
+#include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h"
+#include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
+
+namespace sync_file_system {
+namespace drive_backend {
+
+void PutServiceMetadataToBatch(const ServiceMetadata& service_metadata,
+ leveldb::WriteBatch* batch) {
+ std::string value;
+ bool success = service_metadata.SerializeToString(&value);
+ DCHECK(success);
+ batch->Put(kServiceMetadataKey, value);
+}
+
+void PutFileToBatch(const FileMetadata& file, leveldb::WriteBatch* batch) {
+ std::string value;
+ bool success = file.SerializeToString(&value);
+ DCHECK(success);
+ batch->Put(kFileMetadataKeyPrefix + file.file_id(), value);
+}
+
+void PutTrackerToBatch(const FileTracker& tracker, leveldb::WriteBatch* batch) {
+ std::string value;
+ bool success = tracker.SerializeToString(&value);
+ DCHECK(success);
+ batch->Put(kFileTrackerKeyPrefix + base::Int64ToString(tracker.tracker_id()),
+ value);
+}
+
+void PopulateFileDetailsByFileResource(
+ const google_apis::FileResource& file_resource,
+ FileDetails* details) {
+ details->clear_parent_folder_ids();
+ for (ScopedVector<google_apis::ParentReference>::const_iterator itr =
+ file_resource.parents().begin();
+ itr != file_resource.parents().end();
+ ++itr) {
+ details->add_parent_folder_ids((*itr)->file_id());
+ }
+ details->set_title(file_resource.title());
+
+ google_apis::DriveEntryKind kind = drive::util::GetKind(file_resource);
+ if (kind == google_apis::ENTRY_KIND_FILE)
+ details->set_file_kind(FILE_KIND_FILE);
+ else if (kind == google_apis::ENTRY_KIND_FOLDER)
+ details->set_file_kind(FILE_KIND_FOLDER);
+ else
+ details->set_file_kind(FILE_KIND_UNSUPPORTED);
+
+ details->set_md5(file_resource.md5_checksum());
+ details->set_etag(file_resource.etag());
+ details->set_creation_time(file_resource.created_date().ToInternalValue());
+ details->set_modification_time(
+ file_resource.modified_date().ToInternalValue());
+ details->set_deleted(false);
+}
+
+scoped_ptr<FileMetadata> CreateFileMetadataFromFileResource(
+ int64 change_id,
+ const google_apis::FileResource& resource) {
+ scoped_ptr<FileMetadata> file(new FileMetadata);
+ file->set_file_id(resource.file_id());
+
+ FileDetails* details = file->mutable_details();
+ details->set_change_id(change_id);
+
+ if (resource.labels().is_trashed()) {
+ details->set_deleted(true);
+ return file.Pass();
+ }
+
+ PopulateFileDetailsByFileResource(resource, details);
+ return file.Pass();
+}
+
+scoped_ptr<FileMetadata> CreateFileMetadataFromChangeResource(
+ const google_apis::ChangeResource& change) {
+ scoped_ptr<FileMetadata> file(new FileMetadata);
+ file->set_file_id(change.file_id());
+
+ FileDetails* details = file->mutable_details();
+ details->set_change_id(change.change_id());
+
+ if (change.is_deleted()) {
+ details->set_deleted(true);
+ return file.Pass();
+ }
+
+ PopulateFileDetailsByFileResource(*change.file(), details);
+ return file.Pass();
+}
+
+} // namespace drive_backend
+} // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/drive_backend/drive_backend_util.h b/chrome/browser/sync_file_system/drive_backend/drive_backend_util.h
new file mode 100644
index 0000000000..03ada0672e
--- /dev/null
+++ b/chrome/browser/sync_file_system/drive_backend/drive_backend_util.h
@@ -0,0 +1,44 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_DRIVE_BACKEND_UTIL_H_
+#define CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_DRIVE_BACKEND_UTIL_H_
+
+#include "base/memory/scoped_ptr.h"
+
+namespace google_apis {
+class ChangeResource;
+class FileResource;
+}
+
+namespace leveldb {
+class WriteBatch;
+}
+
+namespace sync_file_system {
+namespace drive_backend {
+
+class FileDetails;
+class FileMetadata;
+class FileTracker;
+class ServiceMetadata;
+
+void PutServiceMetadataToBatch(const ServiceMetadata& service_metadata,
+ leveldb::WriteBatch* batch);
+void PutFileToBatch(const FileMetadata& file, leveldb::WriteBatch* batch);
+void PutTrackerToBatch(const FileTracker& tracker, leveldb::WriteBatch* batch);
+
+void PopulateFileDetailsByFileResource(
+ const google_apis::FileResource& file_resource,
+ FileDetails* details);
+scoped_ptr<FileMetadata> CreateFileMetadataFromFileResource(
+ int64 change_id,
+ const google_apis::FileResource& resource);
+scoped_ptr<FileMetadata> CreateFileMetadataFromChangeResource(
+ const google_apis::ChangeResource& change);
+
+} // namespace drive_backend
+} // namespace sync_file_system
+
+#endif // CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_DRIVE_BACKEND_UTIL_H_
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database.cc b/chrome/browser/sync_file_system/drive_backend/metadata_database.cc
index 0ba2872f87..964b651e82 100644
--- a/chrome/browser/sync_file_system/drive_backend/metadata_database.cc
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_database.cc
@@ -23,6 +23,8 @@
#include "chrome/browser/drive/drive_api_util.h"
#include "chrome/browser/google_apis/drive_api_parser.h"
#include "chrome/browser/google_apis/drive_entry_kinds.h"
+#include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h"
+#include "chrome/browser/sync_file_system/drive_backend/drive_backend_util.h"
#include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h"
#include "chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util.h"
#include "chrome/browser/sync_file_system/logger.h"
@@ -34,12 +36,6 @@
namespace sync_file_system {
namespace drive_backend {
-const char kDatabaseVersionKey[] = "VERSION";
-const int64 kCurrentDatabaseVersion = 3;
-const char kServiceMetadataKey[] = "SERVICE";
-const char kFileMetadataKeyPrefix[] = "FILE: ";
-const char kFileTrackerKeyPrefix[] = "TRACKER: ";
-
struct DatabaseContents {
scoped_ptr<ServiceMetadata> service_metadata;
ScopedVector<FileMetadata> file_metadata;
@@ -86,69 +82,6 @@ base::FilePath ReverseConcatPathComponents(
return base::FilePath(result).NormalizePathSeparators();
}
-void PopulateFileDetailsByFileResource(
- const google_apis::FileResource& file_resource,
- FileDetails* details) {
- details->clear_parent_folder_ids();
- for (ScopedVector<google_apis::ParentReference>::const_iterator itr =
- file_resource.parents().begin();
- itr != file_resource.parents().end();
- ++itr) {
- details->add_parent_folder_ids((*itr)->file_id());
- }
- details->set_title(file_resource.title());
-
- google_apis::DriveEntryKind kind = drive::util::GetKind(file_resource);
- if (kind == google_apis::ENTRY_KIND_FILE)
- details->set_file_kind(FILE_KIND_FILE);
- else if (kind == google_apis::ENTRY_KIND_FOLDER)
- details->set_file_kind(FILE_KIND_FOLDER);
- else
- details->set_file_kind(FILE_KIND_UNSUPPORTED);
-
- details->set_md5(file_resource.md5_checksum());
- details->set_etag(file_resource.etag());
- details->set_creation_time(file_resource.created_date().ToInternalValue());
- details->set_modification_time(
- file_resource.modified_date().ToInternalValue());
- details->set_deleted(false);
-}
-
-scoped_ptr<FileMetadata> CreateFileMetadataFromFileResource(
- int64 change_id,
- const google_apis::FileResource& resource) {
- scoped_ptr<FileMetadata> file(new FileMetadata);
- file->set_file_id(resource.file_id());
-
- FileDetails* details = file->mutable_details();
- details->set_change_id(change_id);
-
- if (resource.labels().is_trashed()) {
- details->set_deleted(true);
- return file.Pass();
- }
-
- PopulateFileDetailsByFileResource(resource, details);
- return file.Pass();
-}
-
-scoped_ptr<FileMetadata> CreateFileMetadataFromChangeResource(
- const google_apis::ChangeResource& change) {
- scoped_ptr<FileMetadata> file(new FileMetadata);
- file->set_file_id(change.file_id());
-
- FileDetails* details = file->mutable_details();
- details->set_change_id(change.change_id());
-
- if (change.is_deleted()) {
- details->set_deleted(true);
- return file.Pass();
- }
-
- PopulateFileDetailsByFileResource(*change.file(), details);
- return file.Pass();
-}
-
void CreateInitialSyncRootTracker(
int64 tracker_id,
const google_apis::FileResource& file_resource,
@@ -207,29 +140,6 @@ void AdaptLevelDBStatusToSyncStatusCode(const SyncStatusCallback& callback,
callback.Run(LevelDBStatusToSyncStatusCode(status));
}
-void PutServiceMetadataToBatch(const ServiceMetadata& service_metadata,
- leveldb::WriteBatch* batch) {
- std::string value;
- bool success = service_metadata.SerializeToString(&value);
- DCHECK(success);
- batch->Put(kServiceMetadataKey, value);
-}
-
-void PutFileToBatch(const FileMetadata& file, leveldb::WriteBatch* batch) {
- std::string value;
- bool success = file.SerializeToString(&value);
- DCHECK(success);
- batch->Put(kFileMetadataKeyPrefix + file.file_id(), value);
-}
-
-void PutTrackerToBatch(const FileTracker& tracker, leveldb::WriteBatch* batch) {
- std::string value;
- bool success = tracker.SerializeToString(&value);
- DCHECK(success);
- batch->Put(kFileTrackerKeyPrefix + base::Int64ToString(tracker.tracker_id()),
- value);
-}
-
void PutFileDeletionToBatch(const std::string& file_id,
leveldb::WriteBatch* batch) {
batch->Delete(kFileMetadataKeyPrefix + file_id);
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database.h b/chrome/browser/sync_file_system/drive_backend/metadata_database.h
index b4f616b441..82b7e70e27 100644
--- a/chrome/browser/sync_file_system/drive_backend/metadata_database.h
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_database.h
@@ -224,6 +224,7 @@ class MetadataDatabase {
const SyncStatusCallback& callback);
private:
+ friend class RegisterAppTaskTest;
friend class SyncEngineInitializerTest;
struct DirtyTrackerComparator {
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc b/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc
index 44cc7fdadd..429ad7cafe 100644
--- a/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc
@@ -139,7 +139,7 @@ void ExpectEquivalentSets(const Container& left, const Container& right) {
class MetadataDatabaseTest : public testing::Test {
public:
MetadataDatabaseTest()
- : next_change_id_(kInitialChangeID + 1),
+ : current_change_id_(kInitialChangeID),
next_tracker_id_(kSyncRootTrackerID + 1),
next_file_id_number_(1),
next_md5_sequence_number_(1) {}
@@ -392,7 +392,7 @@ class MetadataDatabaseTest : public testing::Test {
FileMetadata* file) {
FileDetails* details = file->mutable_details();
details->set_title(new_title);
- details->set_change_id(next_change_id_++);
+ details->set_change_id(++current_change_id_);
}
void ApplyReorganizeChangeToMetadata(const std::string& new_parent,
@@ -400,14 +400,14 @@ class MetadataDatabaseTest : public testing::Test {
FileDetails* details = file->mutable_details();
details->clear_parent_folder_ids();
details->add_parent_folder_ids(new_parent);
- details->set_change_id(next_change_id_++);
+ details->set_change_id(++current_change_id_);
}
void ApplyContentChangeToMetadata(FileMetadata* file) {
FileDetails* details = file->mutable_details();
details->set_md5(
"md5_value_" + base::Int64ToString(next_md5_sequence_number_++));
- details->set_change_id(next_change_id_++);
+ details->set_change_id(++current_change_id_);
}
void PushToChangeList(scoped_ptr<google_apis::ChangeResource> change,
@@ -586,7 +586,7 @@ class MetadataDatabaseTest : public testing::Test {
scoped_ptr<MetadataDatabase> metadata_database_;
- int64 next_change_id_;
+ int64 current_change_id_;
int64 next_tracker_id_;
int64 next_file_id_number_;
int64 next_md5_sequence_number_;
diff --git a/chrome/browser/sync_file_system/drive_backend/register_app_task.cc b/chrome/browser/sync_file_system/drive_backend/register_app_task.cc
index 3a7eec19ea..fc19be33eb 100644
--- a/chrome/browser/sync_file_system/drive_backend/register_app_task.cc
+++ b/chrome/browser/sync_file_system/drive_backend/register_app_task.cc
@@ -105,7 +105,7 @@ void RegisterAppTask::DidCreateAppRootFolder(
DCHECK(entry);
scoped_ptr<google_apis::FileResource> resource(
drive::util::ConvertResourceEntryToFileResource(*entry));
- sync_context_->GetMetadataDatabase()->UpdateByFileResource(
+ metadata_database()->UpdateByFileResource(
change_id,
*resource,
base::Bind(&RegisterAppTask::DidUpdateDatabase,
diff --git a/chrome/browser/sync_file_system/drive_backend/register_app_task_unittest.cc b/chrome/browser/sync_file_system/drive_backend/register_app_task_unittest.cc
new file mode 100644
index 0000000000..327e48fb53
--- /dev/null
+++ b/chrome/browser/sync_file_system/drive_backend/register_app_task_unittest.cc
@@ -0,0 +1,319 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/sync_file_system/drive_backend/register_app_task.h"
+
+#include "base/files/scoped_temp_dir.h"
+#include "base/format_macros.h"
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/browser/drive/fake_drive_service.h"
+#include "chrome/browser/google_apis/gdata_wapi_parser.h"
+#include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h"
+#include "chrome/browser/sync_file_system/drive_backend/drive_backend_util.h"
+#include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
+#include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h"
+#include "chrome/browser/sync_file_system/drive_backend/sync_engine_context.h"
+#include "chrome/browser/sync_file_system/drive_backend_v1/fake_drive_service_helper.h"
+#include "chrome/browser/sync_file_system/sync_file_system_test_util.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/leveldatabase/src/include/leveldb/db.h"
+#include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
+
+namespace sync_file_system {
+namespace drive_backend {
+
+namespace {
+const int64 kSyncRootTrackerID = 100;
+} // namespace
+
+class RegisterAppTaskTest : public testing::Test,
+ public SyncEngineContext {
+ public:
+ RegisterAppTaskTest()
+ : next_file_id_(1000),
+ next_tracker_id_(10000) {}
+ virtual ~RegisterAppTaskTest() {}
+
+ virtual void SetUp() OVERRIDE {
+ ASSERT_TRUE(database_dir_.CreateUniqueTempDir());
+
+ fake_drive_service_.reset(new drive::FakeDriveService);
+ ASSERT_TRUE(fake_drive_service_->LoadAccountMetadataForWapi(
+ "sync_file_system/account_metadata.json"));
+ ASSERT_TRUE(fake_drive_service_->LoadResourceListForWapi(
+ "gdata/empty_feed.json"));
+
+ drive_uploader_.reset(new drive::DriveUploader(
+ fake_drive_service_.get(), base::MessageLoopProxy::current()));
+
+ fake_drive_service_helper_.reset(new FakeDriveServiceHelper(
+ fake_drive_service_.get(), drive_uploader_.get()));
+
+ ASSERT_EQ(google_apis::HTTP_CREATED,
+ fake_drive_service_helper_->AddOrphanedFolder(
+ kSyncRootFolderTitle, &sync_root_folder_id_));
+ }
+
+ virtual void TearDown() OVERRIDE {
+ metadata_database_.reset();
+ base::RunLoop().RunUntilIdle();
+ }
+
+ virtual drive::DriveServiceInterface* GetDriveService() OVERRIDE {
+ return fake_drive_service_.get();
+ }
+
+ virtual MetadataDatabase* GetMetadataDatabase() OVERRIDE {
+ return metadata_database_.get();
+ }
+
+ protected:
+ scoped_ptr<leveldb::DB> OpenLevelDB() {
+ leveldb::DB* db = NULL;
+ leveldb::Options options;
+ options.create_if_missing = true;
+ leveldb::Status status =
+ leveldb::DB::Open(options, database_dir_.path().AsUTF8Unsafe(), &db);
+ EXPECT_TRUE(status.ok());
+ return make_scoped_ptr<leveldb::DB>(db);
+ }
+
+ void SetUpInitialData(leveldb::DB* db) {
+ ServiceMetadata service_metadata;
+ service_metadata.set_largest_change_id(100);
+ service_metadata.set_sync_root_tracker_id(kSyncRootTrackerID);
+ service_metadata.set_next_tracker_id(next_tracker_id_);
+
+ FileDetails sync_root_details;
+ sync_root_details.set_title(kSyncRootFolderTitle);
+ sync_root_details.set_file_kind(FILE_KIND_FOLDER);
+ sync_root_details.set_change_id(1);
+
+ FileMetadata sync_root_metadata;
+ sync_root_metadata.set_file_id(sync_root_folder_id_);
+ *sync_root_metadata.mutable_details() = sync_root_details;
+
+ FileTracker sync_root_tracker;
+ sync_root_tracker.set_tracker_id(service_metadata.sync_root_tracker_id());
+ sync_root_tracker.set_parent_tracker_id(0);
+ sync_root_tracker.set_file_id(sync_root_metadata.file_id());
+ sync_root_tracker.set_tracker_kind(TRACKER_KIND_REGULAR);
+ *sync_root_tracker.mutable_synced_details() = sync_root_details;
+ sync_root_tracker.set_active(true);
+
+ leveldb::WriteBatch batch;
+ batch.Put(kDatabaseVersionKey,
+ base::Int64ToString(kCurrentDatabaseVersion));
+ PutServiceMetadataToBatch(service_metadata, &batch);
+ PutFileToBatch(sync_root_metadata, &batch);
+ PutTrackerToBatch(sync_root_tracker, &batch);
+ EXPECT_TRUE(db->Write(leveldb::WriteOptions(), &batch).ok());
+ }
+
+ void CreateMetadataDatabase(scoped_ptr<leveldb::DB> db) {
+ ASSERT_TRUE(db);
+ ASSERT_FALSE(metadata_database_);
+ ASSERT_EQ(SYNC_STATUS_OK,
+ MetadataDatabase::CreateForTesting(
+ db.Pass(), &metadata_database_));
+ }
+
+ SyncStatusCode RunRegisterAppTask(const std::string& app_id) {
+ RegisterAppTask task(this, app_id);
+ SyncStatusCode status = SYNC_STATUS_UNKNOWN;
+ task.Run(CreateResultReceiver(&status));
+ base::RunLoop().RunUntilIdle();
+ return status;
+ }
+
+ void SetUpRegisteredAppRoot(
+ const std::string& app_id,
+ leveldb::DB* db) {
+ FileDetails details;
+ details.set_title(app_id);
+ details.set_file_kind(FILE_KIND_FOLDER);
+ details.add_parent_folder_ids(sync_root_folder_id_);
+
+ FileMetadata metadata;
+ metadata.set_file_id(GenerateFileID());
+ *metadata.mutable_details() = details;
+
+ FileTracker tracker;
+ tracker.set_parent_tracker_id(kSyncRootTrackerID);
+ tracker.set_tracker_id(next_tracker_id_++);
+ tracker.set_file_id(metadata.file_id());
+ tracker.set_tracker_kind(TRACKER_KIND_APP_ROOT);
+ tracker.set_app_id(app_id);
+ *tracker.mutable_synced_details() = details;
+ tracker.set_active(true);
+
+ leveldb::WriteBatch batch;
+ PutFileToBatch(metadata, &batch);
+ PutTrackerToBatch(tracker, &batch);
+ EXPECT_TRUE(db->Write(leveldb::WriteOptions(), &batch).ok());
+ }
+
+ void SetUpUnregisteredAppRoot(const std::string& app_id,
+ leveldb::DB* db) {
+ FileDetails details;
+ details.set_title(app_id);
+ details.set_file_kind(FILE_KIND_FOLDER);
+ details.add_parent_folder_ids(sync_root_folder_id_);
+
+ FileMetadata metadata;
+ metadata.set_file_id(GenerateFileID());
+ *metadata.mutable_details() = details;
+
+ FileTracker tracker;
+ tracker.set_parent_tracker_id(kSyncRootTrackerID);
+ tracker.set_tracker_id(next_tracker_id_++);
+ tracker.set_file_id(metadata.file_id());
+ tracker.set_tracker_kind(TRACKER_KIND_REGULAR);
+ *tracker.mutable_synced_details() = details;
+ tracker.set_active(false);
+
+ leveldb::WriteBatch batch;
+ PutFileToBatch(metadata, &batch);
+ PutTrackerToBatch(tracker, &batch);
+ EXPECT_TRUE(db->Write(leveldb::WriteOptions(), &batch).ok());
+ }
+
+ size_t CountRegisteredAppRoot() {
+ // TODO(tzik): Add function to MetadataDatabase to list trackers by parent.
+ typedef MetadataDatabase::TrackersByTitle TrackersByTitle;
+ const TrackersByTitle& trackers_by_title =
+ metadata_database_->trackers_by_parent_and_title_[kSyncRootTrackerID];
+
+ size_t count = 0;
+ for (TrackersByTitle::const_iterator itr = trackers_by_title.begin();
+ itr != trackers_by_title.end(); ++itr) {
+ if (itr->second.has_active())
+ ++count;
+ }
+
+ return count;
+ }
+
+ bool IsAppRegistered(const std::string& app_id) {
+ TrackerSet trackers;
+ if (!metadata_database_->FindTrackersByParentAndTitle(
+ kSyncRootTrackerID, app_id, &trackers))
+ return false;
+ return trackers.has_active();
+ }
+
+ size_t CountRemoteFileInSyncRoot() {
+ ScopedVector<google_apis::ResourceEntry> files;
+ EXPECT_EQ(google_apis::HTTP_SUCCESS,
+ fake_drive_service_helper_->ListFilesInFolder(
+ sync_root_folder_id_, &files));
+ return files.size();
+ }
+
+ bool HasRemoteAppRoot(const std::string& app_id) {
+ TrackerSet files;
+ if (!metadata_database_->FindTrackersByParentAndTitle(
+ kSyncRootTrackerID, app_id, &files) ||
+ !files.has_active())
+ return false;
+
+ std::string app_root_folder_id = files.active_tracker()->file_id();
+ scoped_ptr<google_apis::ResourceEntry> entry;
+ if (google_apis::HTTP_SUCCESS !=
+ fake_drive_service_helper_->GetResourceEntry(
+ app_root_folder_id, &entry))
+ return false;
+
+ return !entry->deleted();
+ }
+
+ private:
+ std::string GenerateFileID() {
+ return base::StringPrintf("file_id_%" PRId64, next_file_id_++);
+ }
+
+ std::string sync_root_folder_id_;
+
+ int64 next_file_id_;
+ int64 next_tracker_id_;
+
+ content::TestBrowserThreadBundle browser_threads_;
+ base::ScopedTempDir database_dir_;
+
+ scoped_ptr<drive::FakeDriveService> fake_drive_service_;
+ scoped_ptr<drive::DriveUploader> drive_uploader_;
+ scoped_ptr<FakeDriveServiceHelper> fake_drive_service_helper_;
+
+ scoped_ptr<MetadataDatabase> metadata_database_;
+
+ DISALLOW_COPY_AND_ASSIGN(RegisterAppTaskTest);
+};
+
+TEST_F(RegisterAppTaskTest, AlreadyRegistered) {
+ scoped_ptr<leveldb::DB> db(OpenLevelDB());
+ ASSERT_TRUE(db);
+ SetUpInitialData(db.get());
+
+ const std::string kAppID = "app_id";
+ SetUpRegisteredAppRoot(kAppID, db.get());
+
+ CreateMetadataDatabase(db.Pass());
+ EXPECT_EQ(SYNC_STATUS_OK, RunRegisterAppTask(kAppID));
+
+ EXPECT_EQ(1u, CountRegisteredAppRoot());
+ EXPECT_TRUE(IsAppRegistered(kAppID));
+}
+
+TEST_F(RegisterAppTaskTest, CreateAppFolder) {
+ scoped_ptr<leveldb::DB> db(OpenLevelDB());
+ ASSERT_TRUE(db);
+ SetUpInitialData(db.get());
+
+ const std::string kAppID = "app_id";
+ CreateMetadataDatabase(db.Pass());
+ RunRegisterAppTask(kAppID);
+
+ EXPECT_EQ(1u, CountRegisteredAppRoot());
+ EXPECT_TRUE(IsAppRegistered(kAppID));
+
+ EXPECT_EQ(1u, CountRemoteFileInSyncRoot());
+ EXPECT_TRUE(HasRemoteAppRoot(kAppID));
+}
+
+TEST_F(RegisterAppTaskTest, RegisterExistingFolder) {
+ scoped_ptr<leveldb::DB> db(OpenLevelDB());
+ ASSERT_TRUE(db);
+ SetUpInitialData(db.get());
+
+ const std::string kAppID = "app_id";
+ SetUpUnregisteredAppRoot(kAppID, db.get());
+
+ CreateMetadataDatabase(db.Pass());
+ RunRegisterAppTask(kAppID);
+
+ EXPECT_EQ(1u, CountRegisteredAppRoot());
+ EXPECT_TRUE(IsAppRegistered(kAppID));
+}
+
+TEST_F(RegisterAppTaskTest, RegisterExistingFolder_MultipleCandidate) {
+ scoped_ptr<leveldb::DB> db(OpenLevelDB());
+ ASSERT_TRUE(db);
+ SetUpInitialData(db.get());
+
+ const std::string kAppID = "app_id";
+ SetUpUnregisteredAppRoot(kAppID, db.get());
+ SetUpUnregisteredAppRoot(kAppID, db.get());
+
+ CreateMetadataDatabase(db.Pass());
+ RunRegisterAppTask(kAppID);
+
+ EXPECT_EQ(1u, CountRegisteredAppRoot());
+ EXPECT_TRUE(IsAppRegistered(kAppID));
+}
+
+} // namespace drive_backend
+} // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/drive_backend/sync_engine_initializer_unittest.cc b/chrome/browser/sync_file_system/drive_backend/sync_engine_initializer_unittest.cc
index b4ba1403e1..4dd8a71ad6 100644
--- a/chrome/browser/sync_file_system/drive_backend/sync_engine_initializer_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend/sync_engine_initializer_unittest.cc
@@ -6,7 +6,7 @@
#include "base/bind.h"
#include "base/files/scoped_temp_dir.h"
-#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
#include "chrome/browser/drive/drive_api_util.h"
#include "chrome/browser/drive/fake_drive_service.h"
#include "chrome/browser/google_apis/drive_api_parser.h"
@@ -50,7 +50,7 @@ class SyncEngineInitializerTest : public testing::Test {
virtual void TearDown() OVERRIDE {
initializer_.reset();
metadata_database_.reset();
- base::MessageLoop::current()->RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
}
base::FilePath database_path() {
@@ -65,7 +65,7 @@ class SyncEngineInitializerTest : public testing::Test {
SyncStatusCode status = SYNC_STATUS_UNKNOWN;
initializer_->Run(CreateResultReceiver(&status));
- base::MessageLoop::current()->RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
metadata_database_ = initializer_->PassMetadataDatabase();
return status;
@@ -86,7 +86,7 @@ class SyncEngineInitializerTest : public testing::Test {
scoped_ptr<google_apis::ResourceEntry> entry;
fake_drive_service_.GetResourceEntry(file->metadata.file_id(),
CreateResultReceiver(&error, &entry));
- base::MessageLoop::current()->RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
if (entry) {
file->resource =
@@ -108,7 +108,7 @@ class SyncEngineInitializerTest : public testing::Test {
base::MessageLoopProxy::current(),
database_path(),
CreateResultReceiver(&status, &database));
- base::MessageLoop::current()->RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
if (status != SYNC_STATUS_OK)
return status;
@@ -125,7 +125,7 @@ class SyncEngineInitializerTest : public testing::Test {
sync_root,
app_root_list,
CreateResultReceiver(&status));
- base::MessageLoop::current()->RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
app_root_list.weak_clear();
@@ -140,7 +140,7 @@ class SyncEngineInitializerTest : public testing::Test {
fake_drive_service_.AddNewDirectory(
parent_folder_id, title,
CreateResultReceiver(&error, &entry));
- base::MessageLoop::current()->RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
EXPECT_EQ(google_apis::HTTP_CREATED, error);
if (!entry)
@@ -158,7 +158,7 @@ class SyncEngineInitializerTest : public testing::Test {
sync_root->parents()[i]->file_id(),
sync_root->file_id(),
CreateResultReceiver(&error));
- base::MessageLoop::current()->RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
EXPECT_EQ(google_apis::HTTP_SUCCESS, error);
}
@@ -191,7 +191,7 @@ class SyncEngineInitializerTest : public testing::Test {
fake_drive_service_.GetResourceEntry(
file_id,
CreateResultReceiver(&error, &entry));
- base::MessageLoop::current()->RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
EXPECT_EQ(google_apis::HTTP_SUCCESS, error);
return !entry->GetLinkByType(google_apis::Link::LINK_PARENT);
}
@@ -211,7 +211,7 @@ class SyncEngineInitializerTest : public testing::Test {
fake_drive_service_.AddResourceToDirectory(
new_parent_folder_id, file_id,
CreateResultReceiver(&error));
- base::MessageLoop::current()->RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
return error;
}
diff --git a/chrome/browser/sync_file_system/drive_backend_v1/drive_file_sync_service_fake_unittest.cc b/chrome/browser/sync_file_system/drive_backend_v1/drive_file_sync_service_fake_unittest.cc
index 6b7df0baf8..912bbb9478 100644
--- a/chrome/browser/sync_file_system/drive_backend_v1/drive_file_sync_service_fake_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend_v1/drive_file_sync_service_fake_unittest.cc
@@ -66,8 +66,10 @@ using drive_backend::FakeDriveServiceHelper;
namespace {
+#if !defined(OS_ANDROID)
const char kExtensionName1[] = "example1";
const char kExtensionName2[] = "example2";
+#endif
void DidInitialize(bool* done, SyncStatusCode status, bool created) {
EXPECT_FALSE(*done);
diff --git a/chrome/browser/sync_file_system/drive_backend_v1/fake_drive_service_helper.cc b/chrome/browser/sync_file_system/drive_backend_v1/fake_drive_service_helper.cc
index 93987ec950..7871f70bf4 100644
--- a/chrome/browser/sync_file_system/drive_backend_v1/fake_drive_service_helper.cc
+++ b/chrome/browser/sync_file_system/drive_backend_v1/fake_drive_service_helper.cc
@@ -7,8 +7,12 @@
#include "base/bind.h"
#include "base/file_util.h"
#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
#include "base/threading/sequenced_worker_pool.h"
+#include "chrome/browser/google_apis/drive_api_parser.h"
+#include "chrome/browser/google_apis/gdata_wapi_parser.h"
#include "chrome/browser/sync_file_system/drive_backend_v1/api_util.h"
+#include "chrome/browser/sync_file_system/sync_file_system_test_util.h"
#include "chrome/browser/sync_file_system/sync_status_code.h"
#include "content/public/test/test_browser_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -16,6 +20,7 @@
#define FPL(path) FILE_PATH_LITERAL(path)
+using google_apis::AboutResource;
using google_apis::GDataErrorCode;
using google_apis::ResourceEntry;
using google_apis::ResourceList;
@@ -25,16 +30,6 @@ namespace drive_backend {
namespace {
-void ResourceEntryResultCallback(GDataErrorCode* error_out,
- scoped_ptr<ResourceEntry>* entry_out,
- GDataErrorCode error,
- scoped_ptr<ResourceEntry> entry) {
- ASSERT_TRUE(error_out);
- ASSERT_TRUE(entry_out);
- *error_out = error;
- *entry_out = entry.Pass();
-}
-
void UploadResultCallback(GDataErrorCode* error_out,
scoped_ptr<ResourceEntry>* entry_out,
GDataErrorCode error,
@@ -46,22 +41,6 @@ void UploadResultCallback(GDataErrorCode* error_out,
*entry_out = entry.Pass();
}
-void ResourceListResultCallback(GDataErrorCode* error_out,
- scoped_ptr<ResourceList>* list_out,
- GDataErrorCode error,
- scoped_ptr<ResourceList> list) {
- ASSERT_TRUE(error_out);
- ASSERT_TRUE(list_out);
- *error_out = error;
- *list_out = list.Pass();
-}
-
-void GDataErrorResultCallback(GDataErrorCode* error_out,
- GDataErrorCode error) {
- ASSERT_TRUE(error_out);
- *error_out = error;
-}
-
void DownloadResultCallback(GDataErrorCode* error_out,
GDataErrorCode error,
const base::FilePath& local_file) {
@@ -95,8 +74,8 @@ GDataErrorCode FakeDriveServiceHelper::AddOrphanedFolder(
error = google_apis::GDATA_OTHER_ERROR;
fake_drive_service_->RemoveResourceFromDirectory(
root_folder_id, *folder_id,
- base::Bind(&GDataErrorResultCallback, &error));
- FlushMessageLoop();
+ CreateResultReceiver(&error));
+ base::RunLoop().RunUntilIdle();
if (error != google_apis::HTTP_SUCCESS)
return error;
@@ -113,8 +92,8 @@ GDataErrorCode FakeDriveServiceHelper::AddFolder(
scoped_ptr<ResourceEntry> folder;
fake_drive_service_->AddNewDirectory(
parent_folder_id, title,
- base::Bind(&ResourceEntryResultCallback, &error, &folder));
- FlushMessageLoop();
+ CreateResultReceiver(&error, &folder));
+ base::RunLoop().RunUntilIdle();
if (error == google_apis::HTTP_CREATED)
*folder_id = folder->resource_id();
@@ -136,7 +115,7 @@ GDataErrorCode FakeDriveServiceHelper::AddFile(
"application/octet-stream",
base::Bind(&UploadResultCallback, &error, &file),
google_apis::ProgressCallback());
- FlushMessageLoop();
+ base::RunLoop().RunUntilIdle();
if (error == google_apis::HTTP_SUCCESS)
*file_id = file->resource_id();
@@ -155,7 +134,7 @@ GDataErrorCode FakeDriveServiceHelper::UpdateFile(
std::string(), // etag
base::Bind(&UploadResultCallback, &error, &file),
google_apis::ProgressCallback());
- FlushMessageLoop();
+ base::RunLoop().RunUntilIdle();
return error;
}
@@ -165,8 +144,8 @@ GDataErrorCode FakeDriveServiceHelper::RemoveResource(
fake_drive_service_->DeleteResource(
file_id,
std::string(), // etag
- base::Bind(&GDataErrorResultCallback, &error));
- FlushMessageLoop();
+ CreateResultReceiver(&error));
+ base::RunLoop().RunUntilIdle();
return error;
}
@@ -176,8 +155,8 @@ GDataErrorCode FakeDriveServiceHelper::GetSyncRootFolderID(
scoped_ptr<ResourceList> resource_list;
fake_drive_service_->SearchByTitle(
APIUtil::GetSyncRootDirectoryName(), std::string(),
- base::Bind(&ResourceListResultCallback, &error, &resource_list));
- FlushMessageLoop();
+ CreateResultReceiver(&error, &resource_list));
+ base::RunLoop().RunUntilIdle();
if (error != google_apis::HTTP_SUCCESS)
return error;
@@ -200,8 +179,8 @@ GDataErrorCode FakeDriveServiceHelper::ListFilesInFolder(
scoped_ptr<ResourceList> list;
fake_drive_service_->GetResourceListInDirectory(
folder_id,
- base::Bind(&ResourceListResultCallback, &error, &list));
- FlushMessageLoop();
+ CreateResultReceiver(&error, &list));
+ base::RunLoop().RunUntilIdle();
if (error != google_apis::HTTP_SUCCESS)
return error;
@@ -216,8 +195,8 @@ GDataErrorCode FakeDriveServiceHelper::SearchByTitle(
scoped_ptr<ResourceList> list;
fake_drive_service_->SearchByTitle(
title, folder_id,
- base::Bind(&ResourceListResultCallback, &error, &list));
- FlushMessageLoop();
+ CreateResultReceiver(&error, &list));
+ base::RunLoop().RunUntilIdle();
if (error != google_apis::HTTP_SUCCESS)
return error;
@@ -230,8 +209,8 @@ GDataErrorCode FakeDriveServiceHelper::GetResourceEntry(
GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
fake_drive_service_->GetResourceEntry(
file_id,
- base::Bind(&ResourceEntryResultCallback, &error, entry));
- FlushMessageLoop();
+ CreateResultReceiver(&error, entry));
+ base::RunLoop().RunUntilIdle();
return error;
}
@@ -253,7 +232,7 @@ GDataErrorCode FakeDriveServiceHelper::ReadFile(
base::Bind(&DownloadResultCallback, &error),
google_apis::GetContentCallback(),
google_apis::ProgressCallback());
- FlushMessageLoop();
+ base::RunLoop().RunUntilIdle();
if (error != google_apis::HTTP_SUCCESS)
return error;
@@ -261,6 +240,15 @@ GDataErrorCode FakeDriveServiceHelper::ReadFile(
? google_apis::HTTP_SUCCESS : google_apis::GDATA_FILE_ERROR;
}
+GDataErrorCode FakeDriveServiceHelper::GetAboutResource(
+ scoped_ptr<AboutResource>* about_resource) {
+ GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
+ fake_drive_service_->GetAboutResource(
+ CreateResultReceiver(&error, about_resource));
+ base::RunLoop().RunUntilIdle();
+ return error;
+}
+
GDataErrorCode FakeDriveServiceHelper::CompleteListing(
scoped_ptr<ResourceList> list,
ScopedVector<ResourceEntry>* entries) {
@@ -281,8 +269,8 @@ GDataErrorCode FakeDriveServiceHelper::CompleteListing(
list.reset();
fake_drive_service_->GetRemainingFileList(
next_feed,
- base::Bind(&ResourceListResultCallback, &error, &list));
- FlushMessageLoop();
+ CreateResultReceiver(&error, &list));
+ base::RunLoop().RunUntilIdle();
if (error != google_apis::HTTP_SUCCESS)
return error;
}
@@ -303,11 +291,5 @@ base::FilePath FakeDriveServiceHelper::WriteToTempFile(
return temp_file;
}
-void FakeDriveServiceHelper::FlushMessageLoop() {
- base::MessageLoop::current()->RunUntilIdle();
- content::BrowserThread::GetBlockingPool()->FlushForTesting();
- base::MessageLoop::current()->RunUntilIdle();
-}
-
} // namespace drive_backend
} // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/drive_backend_v1/fake_drive_service_helper.h b/chrome/browser/sync_file_system/drive_backend_v1/fake_drive_service_helper.h
index 05cd927eca..7aa2af68b2 100644
--- a/chrome/browser/sync_file_system/drive_backend_v1/fake_drive_service_helper.h
+++ b/chrome/browser/sync_file_system/drive_backend_v1/fake_drive_service_helper.h
@@ -57,6 +57,8 @@ class FakeDriveServiceHelper {
google_apis::GDataErrorCode ReadFile(
const std::string& file_id,
std::string* file_content);
+ google_apis::GDataErrorCode GetAboutResource(
+ scoped_ptr<google_apis::AboutResource>* about_resource);
base::FilePath base_dir_path() { return base_dir_.path(); }
@@ -68,7 +70,6 @@ class FakeDriveServiceHelper {
void Initialize();
base::FilePath WriteToTempFile(const std::string& content);
- void FlushMessageLoop();
base::ScopedTempDir base_dir_;
base::FilePath temp_dir_;
diff --git a/chrome/browser/sync_file_system/local/sync_file_system_backend.cc b/chrome/browser/sync_file_system/local/sync_file_system_backend.cc
index 199c23398a..f85aaa8c3b 100644
--- a/chrome/browser/sync_file_system/local/sync_file_system_backend.cc
+++ b/chrome/browser/sync_file_system/local/sync_file_system_backend.cc
@@ -18,7 +18,6 @@
#include "webkit/browser/fileapi/file_stream_writer.h"
#include "webkit/browser/fileapi/file_system_context.h"
#include "webkit/browser/fileapi/file_system_operation.h"
-#include "webkit/browser/fileapi/sandbox_quota_observer.h"
#include "webkit/common/fileapi/file_system_util.h"
using content::BrowserThread;
@@ -106,14 +105,9 @@ void SyncFileSystemBackend::Initialize(fileapi::FileSystemContext* context) {
context_ = context;
fileapi::SandboxFileSystemBackendDelegate* delegate = GetDelegate();
- delegate->AddFileUpdateObserver(
- fileapi::kFileSystemTypeSyncable,
- delegate->quota_observer(),
- delegate->file_task_runner());
- delegate->AddFileUpdateObserver(
- fileapi::kFileSystemTypeSyncableForInternalSync,
- delegate->quota_observer(),
- delegate->file_task_runner());
+ delegate->RegisterQuotaUpdateObserver(fileapi::kFileSystemTypeSyncable);
+ delegate->RegisterQuotaUpdateObserver(
+ fileapi::kFileSystemTypeSyncableForInternalSync);
}
void SyncFileSystemBackend::OpenFileSystem(
diff --git a/chrome/browser/sync_file_system/local/syncable_file_system_unittest.cc b/chrome/browser/sync_file_system/local/syncable_file_system_unittest.cc
index b921319ddf..a7bff60bf0 100644
--- a/chrome/browser/sync_file_system/local/syncable_file_system_unittest.cc
+++ b/chrome/browser/sync_file_system/local/syncable_file_system_unittest.cc
@@ -11,8 +11,8 @@
#include "content/public/test/sandbox_file_system_test_helper.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/browser/fileapi/async_file_test_helper.h"
#include "webkit/browser/fileapi/file_system_context.h"
-#include "webkit/browser/fileapi/file_system_file_util.h"
#include "webkit/browser/fileapi/file_system_operation_context.h"
#include "webkit/browser/fileapi/isolated_context.h"
#include "webkit/browser/quota/quota_manager.h"
@@ -265,22 +265,12 @@ TEST_F(SyncableFileSystemTest, DisableDirectoryOperations) {
const FileSystemURL kSrcDir = other_file_system_.CreateURLFromUTF8("/a");
const FileSystemURL kSrcChild = other_file_system_.CreateURLFromUTF8("/a/b");
- bool created = false;
- scoped_ptr<FileSystemOperationContext> operation_context;
-
- operation_context.reset(other_file_system_.NewOperationContext());
- operation_context->set_allowed_bytes_growth(1024);
EXPECT_EQ(base::PLATFORM_FILE_OK,
- other_file_system_.file_util()->CreateDirectory(
- operation_context.get(),
- kSrcDir, false /* exclusive */, false /* recursive */));
-
- operation_context.reset(other_file_system_.NewOperationContext());
- operation_context->set_allowed_bytes_growth(1024);
+ fileapi::AsyncFileTestHelper::CreateDirectory(
+ other_file_system_.file_system_context(), kSrcDir));
EXPECT_EQ(base::PLATFORM_FILE_OK,
- other_file_system_.file_util()->EnsureFileExists(
- operation_context.get(), kSrcChild, &created));
- EXPECT_TRUE(created);
+ fileapi::AsyncFileTestHelper::CreateFile(
+ other_file_system_.file_system_context(), kSrcChild));
// Now try copying the directory into the syncable file system, which should
// fail if directory operation is disabled. (http://crbug.com/161442)
diff --git a/chrome/browser/sync_file_system/sync_file_system_test_util.cc b/chrome/browser/sync_file_system/sync_file_system_test_util.cc
index 407b36298a..0b31c31470 100644
--- a/chrome/browser/sync_file_system/sync_file_system_test_util.cc
+++ b/chrome/browser/sync_file_system/sync_file_system_test_util.cc
@@ -4,18 +4,10 @@
#include "chrome/browser/sync_file_system/sync_file_system_test_util.h"
-#include "base/bind.h"
-#include "base/message_loop/message_loop_proxy.h"
#include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread.h"
#include "chrome/browser/google_apis/gdata_errorcode.h"
-#include "chrome/browser/google_apis/gdata_wapi_parser.h"
-#include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
#include "chrome/browser/sync_file_system/sync_status_code.h"
-#include "content/public/browser/browser_thread.h"
#include "content/public/test/test_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
using content::BrowserThread;
@@ -45,32 +37,12 @@ void ReceiveResult1(bool* done, Arg* arg_out, Arg arg) {
*arg_out = base::internal::CallbackForward(arg);
}
-template <typename Arg1, typename Arg2>
-void ReceiveResult2(bool* done,
- Arg1* arg1_out,
- Arg2* arg2_out,
- Arg1 arg1,
- Arg2 arg2) {
- EXPECT_FALSE(*done);
- *done = true;
- *arg1_out = base::internal::CallbackForward(arg1);
- *arg2_out = base::internal::CallbackForward(arg2);
-}
-
template <typename Arg>
base::Callback<void(Arg)> CreateResultReceiver(Arg* arg_out) {
return base::Bind(&ReceiveResult1<Arg>,
base::Owned(new bool(false)), arg_out);
}
-template <typename Arg1, typename Arg2>
-base::Callback<void(Arg1, Arg2)> CreateResultReceiver(Arg1* arg1_out,
- Arg2* arg2_out) {
- return base::Bind(&ReceiveResult2<Arg1, Arg2>,
- base::Owned(new bool(false)),
- arg1_out, arg2_out);
-}
-
// Instantiate versions we know callers will need.
template base::Callback<void(SyncStatusCode)>
AssignAndQuitCallback(base::RunLoop*, SyncStatusCode*);
@@ -81,11 +53,4 @@ INSTANTIATE_RECEIVER(SyncStatusCode);
INSTANTIATE_RECEIVER(google_apis::GDataErrorCode);
#undef INSTANTIATE_RECEIVER
-#define INSTANTIATE_RECEIVER(type1, type2) \
- template base::Callback<void(type1, scoped_ptr<type2>)> \
- CreateResultReceiver(type1*, scoped_ptr<type2>*)
-INSTANTIATE_RECEIVER(SyncStatusCode, drive_backend::MetadataDatabase);
-INSTANTIATE_RECEIVER(google_apis::GDataErrorCode, google_apis::ResourceEntry);
-#undef INSTANTIATE_RECEIVER
-
} // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/sync_file_system_test_util.h b/chrome/browser/sync_file_system/sync_file_system_test_util.h
index 66c3b8a6cf..572cc32539 100644
--- a/chrome/browser/sync_file_system/sync_file_system_test_util.h
+++ b/chrome/browser/sync_file_system/sync_file_system_test_util.h
@@ -5,7 +5,9 @@
#ifndef CHROME_BROWSER_SYNC_FILE_SYSTEM_SYNC_FILE_SYSTEM_TEST_UTIL_H_
#define CHROME_BROWSER_SYNC_FILE_SYSTEM_SYNC_FILE_SYSTEM_TEST_UTIL_H_
-#include "base/callback_forward.h"
+#include "base/bind.h"
+#include "base/callback.h"
+#include "testing/gtest/include/gtest/gtest.h"
namespace base {
class RunLoop;
@@ -13,6 +15,18 @@ class RunLoop;
namespace sync_file_system {
+template <typename Arg1, typename Arg2>
+void ReceiveResult2(bool* done,
+ Arg1* arg1_out,
+ Arg2* arg2_out,
+ Arg1 arg1,
+ Arg2 arg2) {
+ EXPECT_FALSE(*done);
+ *done = true;
+ *arg1_out = base::internal::CallbackForward(arg1);
+ *arg2_out = base::internal::CallbackForward(arg2);
+}
+
template <typename R>
void AssignAndQuit(base::RunLoop* run_loop, R* result_out, R result);
@@ -24,7 +38,11 @@ base::Callback<void(Arg)> CreateResultReceiver(Arg* arg_out);
template <typename Arg1, typename Arg2>
base::Callback<void(Arg1, Arg2)> CreateResultReceiver(Arg1* arg1_out,
- Arg2* arg2_out);
+ Arg2* arg2_out) {
+ return base::Bind(&ReceiveResult2<Arg1, Arg2>,
+ base::Owned(new bool(false)),
+ arg1_out, arg2_out);
+}
} // namespace sync_file_system
diff --git a/chrome/browser/tab_contents/background_contents.cc b/chrome/browser/tab_contents/background_contents.cc
index 8d3dceca20..a6c9a58891 100644
--- a/chrome/browser/tab_contents/background_contents.cc
+++ b/chrome/browser/tab_contents/background_contents.cc
@@ -6,6 +6,7 @@
#include "chrome/browser/background/background_contents_service.h"
#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/extensions/extension_web_contents_observer.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_preferences_util.h"
#include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h"
@@ -47,6 +48,8 @@ BackgroundContents::BackgroundContents(
web_contents_.get(), extensions::VIEW_TYPE_BACKGROUND_CONTENTS);
web_contents_->SetDelegate(this);
content::WebContentsObserver::Observe(web_contents_.get());
+ extensions::ExtensionWebContentsObserver::CreateForWebContents(
+ web_contents_.get());
// Close ourselves when the application is shutting down.
registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
diff --git a/chrome/browser/tab_contents/navigation_metrics_recorder.cc b/chrome/browser/tab_contents/navigation_metrics_recorder.cc
index e1f98e458d..f1475d1edf 100644
--- a/chrome/browser/tab_contents/navigation_metrics_recorder.cc
+++ b/chrome/browser/tab_contents/navigation_metrics_recorder.cc
@@ -7,6 +7,13 @@
#include "base/metrics/histogram.h"
#include "content/public/browser/navigation_details.h"
#include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host_view.h"
+
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#include "chrome/browser/metro_utils/metro_chrome_win.h"
+#endif
DEFINE_WEB_CONTENTS_USER_DATA_KEY(NavigationMetricsRecorder);
@@ -70,3 +77,20 @@ void NavigationMetricsRecorder::DidNavigateMainFrame(
RecordMainFrameNavigation(details);
}
+void NavigationMetricsRecorder::DidStartLoading(
+ content::RenderViewHost* render_view_host) {
+#if defined(OS_WIN) && defined(USE_ASH)
+ if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
+ gfx::NativeView view = render_view_host->GetView()->GetNativeView();
+ if (view) {
+ chrome::HostDesktopType desktop =
+ chrome::GetHostDesktopTypeForNativeView(view);
+ UMA_HISTOGRAM_ENUMERATION("Win8.PageLoad",
+ chrome::GetWin8Environment(desktop),
+ chrome::WIN_8_ENVIRONMENT_MAX);
+ }
+ }
+#endif
+}
+
+
diff --git a/chrome/browser/tab_contents/navigation_metrics_recorder.h b/chrome/browser/tab_contents/navigation_metrics_recorder.h
index 6c339bf539..ca3301e83b 100644
--- a/chrome/browser/tab_contents/navigation_metrics_recorder.h
+++ b/chrome/browser/tab_contents/navigation_metrics_recorder.h
@@ -23,6 +23,9 @@ class NavigationMetricsRecorder
const content::LoadCommittedDetails& details,
const content::FrameNavigateParams& params) OVERRIDE;
+ virtual void DidStartLoading(
+ content::RenderViewHost* render_view_host) OVERRIDE;
+
DISALLOW_COPY_AND_ASSIGN(NavigationMetricsRecorder);
};
diff --git a/chrome/browser/task_manager/background_resource_provider.cc b/chrome/browser/task_manager/background_resource_provider.cc
index 6bbf757da4..9ffaece5e7 100644
--- a/chrome/browser/task_manager/background_resource_provider.cc
+++ b/chrome/browser/task_manager/background_resource_provider.cc
@@ -196,6 +196,8 @@ void BackgroundContentsResourceProvider::StartUpdating() {
content::NotificationService::AllBrowserContextsAndSources());
registrar_.Add(this, chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED,
content::NotificationService::AllBrowserContextsAndSources());
+ registrar_.Add(this, content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
+ content::NotificationService::AllBrowserContextsAndSources());
}
void BackgroundContentsResourceProvider::StopUpdating() {
@@ -212,6 +214,9 @@ void BackgroundContentsResourceProvider::StopUpdating() {
registrar_.Remove(
this, chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED,
content::NotificationService::AllBrowserContextsAndSources());
+ registrar_.Remove(
+ this, content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
+ content::NotificationService::AllBrowserContextsAndSources());
// Delete all the resources.
STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end());
@@ -223,8 +228,7 @@ void BackgroundContentsResourceProvider::AddToTaskManager(
BackgroundContents* background_contents,
const string16& application_name) {
BackgroundContentsResource* resource =
- new BackgroundContentsResource(background_contents,
- application_name);
+ new BackgroundContentsResource(background_contents, application_name);
resources_[background_contents] = resource;
task_manager_->AddResource(resource);
}
@@ -307,6 +311,20 @@ void BackgroundContentsResourceProvider::Observe(
// (applications may now be considered "foreground" that weren't before).
task_manager_->ModelChanged();
break;
+ case content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED: {
+ WebContents* web_contents = content::Source<WebContents>(source).ptr();
+ for (Resources::iterator i = resources_.begin(); i != resources_.end();
+ i++) {
+ if (i->first->web_contents() == web_contents) {
+ string16 application_name = i->second->application_name();
+ BackgroundContents* contents = i->first;
+ Remove(contents);
+ Add(contents, application_name);
+ return;
+ }
+ }
+ break;
+ }
default:
NOTREACHED() << "Unexpected notification.";
return;
diff --git a/chrome/browser/task_manager/renderer_resource.cc b/chrome/browser/task_manager/renderer_resource.cc
index cc66efb720..51d37653bc 100644
--- a/chrome/browser/task_manager/renderer_resource.cc
+++ b/chrome/browser/task_manager/renderer_resource.cc
@@ -15,8 +15,7 @@ namespace task_manager {
RendererResource::RendererResource(base::ProcessHandle process,
content::RenderViewHost* render_view_host)
- : content::RenderViewHostObserver(render_view_host),
- process_(process),
+ : process_(process),
render_view_host_(render_view_host),
pending_stats_update_(false),
fps_(0.0f),
@@ -125,11 +124,4 @@ bool RendererResource::SupportNetworkUsage() const {
return true;
}
-void RendererResource::RenderViewHostDestroyed(
- content::RenderViewHost* render_view_host) {
- // We should never get here. We should get deleted first.
- // Use this CHECK to help diagnose http://crbug.com/165138.
- CHECK(false);
-}
-
} // namespace task_manager
diff --git a/chrome/browser/task_manager/renderer_resource.h b/chrome/browser/task_manager/renderer_resource.h
index 3ca4699ea4..c588ff6c74 100644
--- a/chrome/browser/task_manager/renderer_resource.h
+++ b/chrome/browser/task_manager/renderer_resource.h
@@ -7,7 +7,6 @@
#include "base/basictypes.h"
#include "chrome/browser/task_manager/resource_provider.h"
-#include "content/public/browser/render_view_host_observer.h"
namespace content {
class RenderViewHost;
@@ -17,8 +16,7 @@ namespace task_manager {
// Base class for various types of render process resources that provides common
// functionality like stats tracking.
-class RendererResource : public Resource,
- public content::RenderViewHostObserver {
+class RendererResource : public Resource {
public:
RendererResource(base::ProcessHandle process,
content::RenderViewHost* render_view_host);
@@ -57,10 +55,6 @@ class RendererResource : public Resource,
virtual void NotifyV8HeapStats(size_t v8_memory_allocated,
size_t v8_memory_used) OVERRIDE;
- // content::RenderViewHostObserver implementation.
- virtual void RenderViewHostDestroyed(
- content::RenderViewHost* render_view_host) OVERRIDE;
-
content::RenderViewHost* render_view_host() const {
return render_view_host_;
}
diff --git a/chrome/browser/task_manager/task_manager_browsertest.cc b/chrome/browser/task_manager/task_manager_browsertest.cc
index 12686b476f..0093f38288 100644
--- a/chrome/browser/task_manager/task_manager_browsertest.cc
+++ b/chrome/browser/task_manager/task_manager_browsertest.cc
@@ -179,7 +179,7 @@ IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, MAYBE_NoticePanelChanges) {
"chrome-extension://behllobkkfkfnphdnhnkndlbkcpglgmj/french_sentence.html");
Panel* panel = PanelManager::GetInstance()->CreatePanel(
web_app::GenerateApplicationNameFromExtensionId(
- last_loaded_extension_id_),
+ last_loaded_extension_id()),
browser()->profile(),
url,
gfx::Rect(300, 400),
@@ -198,7 +198,7 @@ IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, MAYBE_NoticePanelChanges) {
TaskManagerBrowserTestUtil::WaitForWebResourceChange(2);
// Unload extension to avoid crash on Windows.
- UnloadExtension(last_loaded_extension_id_);
+ UnloadExtension(last_loaded_extension_id());
TaskManagerBrowserTestUtil::WaitForWebResourceChange(1);
}
@@ -226,7 +226,7 @@ IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, MAYBE_KillPanelExtension) {
"chrome-extension://behllobkkfkfnphdnhnkndlbkcpglgmj/french_sentence.html");
PanelManager::GetInstance()->CreatePanel(
web_app::GenerateApplicationNameFromExtensionId(
- last_loaded_extension_id_),
+ last_loaded_extension_id()),
browser()->profile(),
url,
gfx::Rect(300, 400),
@@ -276,7 +276,7 @@ IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeExtensionTabs) {
prefix, true));
// Unload extension to avoid crash on Windows.
- UnloadExtension(last_loaded_extension_id_);
+ UnloadExtension(last_loaded_extension_id());
TaskManagerBrowserTestUtil::WaitForWebResourceChange(1);
}
@@ -287,7 +287,7 @@ IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeAppTabs) {
ExtensionService* service = extensions::ExtensionSystem::Get(
browser()->profile())->extension_service();
const extensions::Extension* extension =
- service->GetExtensionById(last_loaded_extension_id_, false);
+ service->GetExtensionById(last_loaded_extension_id(), false);
// New Tab Page.
TaskManagerBrowserTestUtil::WaitForWebResourceChange(1);
@@ -309,7 +309,7 @@ IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeAppTabs) {
prefix, true));
// Unload extension to avoid crash on Windows.
- UnloadExtension(last_loaded_extension_id_);
+ UnloadExtension(last_loaded_extension_id());
TaskManagerBrowserTestUtil::WaitForWebResourceChange(1);
}
@@ -363,7 +363,7 @@ IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeHostedAppTabs) {
app_prefix, true));
// Disable extension and reload page.
- DisableExtension(last_loaded_extension_id_);
+ DisableExtension(last_loaded_extension_id());
ui_test_utils::NavigateToURL(browser(), url);
// Force the TaskManager to query the title.
diff --git a/chrome/browser/themes/theme_service.cc b/chrome/browser/themes/theme_service.cc
index bf6b9ccdd1..238824bb69 100644
--- a/chrome/browser/themes/theme_service.cc
+++ b/chrome/browser/themes/theme_service.cc
@@ -14,8 +14,6 @@
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
-#include "chrome/browser/managed_mode/managed_user_service.h"
-#include "chrome/browser/managed_mode/managed_user_service_factory.h"
#include "chrome/browser/managed_mode/managed_user_theme.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/themes/browser_theme_pack.h"
@@ -98,9 +96,6 @@ void ThemeService::Init(Profile* profile) {
DCHECK(CalledOnValidThread());
profile_ = profile;
- ManagedUserServiceFactory::GetForProfile(profile)->AddInitCallback(base::Bind(
- &ThemeService::OnManagedUserInitialized, weak_ptr_factory_.GetWeakPtr()));
-
LoadThemePrefs();
registrar_.Add(this,
@@ -578,25 +573,6 @@ void ThemeService::SetManagedUserTheme() {
SetCustomDefaultTheme(new ManagedUserTheme);
}
-void ThemeService::OnManagedUserInitialized() {
- // Currently when creating a supervised user, the ThemeService is initialized
- // before the boolean flag indicating the profile belongs to a supervised
- // user gets set. In order to get the custom managed user theme, we get a
- // callback when ManagedUserService is initialized, which happens some time
- // after the boolean flag has been set in
- // ProfileManager::InitProfileUserPrefs() and after the
- // NOTIFICATION_EXTENSIONS_READY notification is sent.
- if ((theme_supplier_.get() &&
- (theme_supplier_->get_theme_type() == CustomThemeSupplier::EXTENSION ||
- theme_supplier_->get_theme_type() ==
- CustomThemeSupplier::MANAGED_USER_THEME)) ||
- !IsManagedUser()) {
- return;
- }
-
- SetManagedUserTheme();
-}
-
void ThemeService::OnInfobarDisplayed() {
number_of_infobars_++;
}
diff --git a/chrome/browser/themes/theme_service_unittest.cc b/chrome/browser/themes/theme_service_unittest.cc
index 4b03205756..19b78f940a 100644
--- a/chrome/browser/themes/theme_service_unittest.cc
+++ b/chrome/browser/themes/theme_service_unittest.cc
@@ -26,10 +26,8 @@ namespace theme_service_internal {
class ThemeServiceTest : public ExtensionServiceTestBase {
public:
- ThemeServiceTest() {
- manager_.reset(
- new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
- }
+ ThemeServiceTest() : is_managed_(false),
+ manager_(TestingBrowserProcess::GetGlobal()) {}
virtual ~ThemeServiceTest() {}
// Moves a minimal theme to |temp_dir_path| and unpacks it from that
@@ -81,10 +79,12 @@ class ThemeServiceTest : public ExtensionServiceTestBase {
virtual void SetUp() {
ExtensionServiceTestBase::SetUp();
- InitializeEmptyExtensionService();
+ ExtensionServiceTestBase::ExtensionServiceInitParams params =
+ CreateDefaultInitParams();
+ params.profile_is_managed = is_managed_;
+ InitializeExtensionService(params);
service_->Init();
- bool success = manager_->SetUp();
- ASSERT_TRUE(success);
+ ASSERT_TRUE(manager_.SetUp());
}
const CustomThemeSupplier* get_theme_supplier(ThemeService* theme_service) {
@@ -92,11 +92,14 @@ class ThemeServiceTest : public ExtensionServiceTestBase {
}
TestingProfileManager* manager() {
- return manager_.get();
+ return &manager_;
}
+ protected:
+ bool is_managed_;
+
private:
- scoped_ptr<TestingProfileManager> manager_;
+ TestingProfileManager manager_;
};
// Installs then uninstalls a theme and makes sure that the ThemeService
@@ -226,9 +229,19 @@ TEST_F(ThemeServiceTest, ThemeUpgrade) {
ExtensionService::INCLUDE_DISABLED));
}
+class ThemeServiceManagedUserTest : public ThemeServiceTest {
+ public:
+ ThemeServiceManagedUserTest() {}
+ virtual ~ThemeServiceManagedUserTest() {}
+
+ virtual void SetUp() OVERRIDE {
+ is_managed_ = true;
+ ThemeServiceTest::SetUp();
+ }
+};
+
// Checks that managed users have their own default theme.
-TEST_F(ThemeServiceTest, ManagedUserThemeReplacesDefaultTheme) {
- ManagedUserServiceFactory::GetForProfile(profile_.get())->InitForTesting();
+TEST_F(ThemeServiceManagedUserTest, ManagedUserThemeReplacesDefaultTheme) {
ThemeService* theme_service =
ThemeServiceFactory::GetForProfile(profile_.get());
theme_service->UseDefaultTheme();
@@ -238,23 +251,10 @@ TEST_F(ThemeServiceTest, ManagedUserThemeReplacesDefaultTheme) {
CustomThemeSupplier::MANAGED_USER_THEME);
}
-TEST_F(ThemeServiceTest, ManagedUserThemeNewUser) {
- TestingProfile* profile = manager()->CreateTestingProfile("mu");
- // Simulate the current initialization behavior: first the ThemeService is
- // created, then the supervised user profile is initialized.
- ThemeService* theme_service =
- ThemeServiceFactory::GetForProfile(profile);
- ManagedUserServiceFactory::GetForProfile(profile)->InitForTesting();
- EXPECT_EQ(get_theme_supplier(theme_service)->get_theme_type(),
- CustomThemeSupplier::MANAGED_USER_THEME);
- manager()->DeleteTestingProfile("mu");
-}
-
#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
// Checks that managed users don't use the system theme even if it is the
// default. The system theme is only available on Linux.
-TEST_F(ThemeServiceTest, ManagedUserThemeReplacesNativeTheme) {
- ManagedUserServiceFactory::GetForProfile(profile_.get())->InitForTesting();
+TEST_F(ThemeServiceManagedUserTest, ManagedUserThemeReplacesNativeTheme) {
profile_->GetPrefs()->SetBoolean(prefs::kUsesSystemTheme, true);
ThemeService* theme_service =
ThemeServiceFactory::GetForProfile(profile_.get());
diff --git a/chrome/browser/ui/android/infobars/infobar_android.cc b/chrome/browser/ui/android/infobars/infobar_android.cc
index f52384e00f..2f08d849f3 100644
--- a/chrome/browser/ui/android/infobars/infobar_android.cc
+++ b/chrome/browser/ui/android/infobars/infobar_android.cc
@@ -67,12 +67,7 @@ void InfoBarAndroid::OnButtonClicked(JNIEnv* env,
void InfoBarAndroid::OnCloseButtonClicked(JNIEnv* env, jobject obj) {
delegate_->InfoBarDismissed();
-}
-
-void InfoBarAndroid::OnInfoBarClosed(JNIEnv* env, jobject obj) {
- java_info_bar_.Reset(); // So we don't notify Java.
- if (owner())
- RemoveSelf();
+ RemoveSelf();
}
void InfoBarAndroid::CloseJavaInfoBar() {
diff --git a/chrome/browser/ui/android/infobars/infobar_android.h b/chrome/browser/ui/android/infobars/infobar_android.h
index 0fe85fc1cc..654f480f38 100644
--- a/chrome/browser/ui/android/infobars/infobar_android.h
+++ b/chrome/browser/ui/android/infobars/infobar_android.h
@@ -52,8 +52,6 @@ class InfoBarAndroid : public InfoBar {
jstring action_value);
void OnCloseButtonClicked(JNIEnv* env, jobject obj);
- void OnInfoBarClosed(JNIEnv* env, jobject obj);
-
void CloseJavaInfoBar();
// Maps from a Chromium ID (IDR_TRANSLATE) to a enum value that Java code can
diff --git a/chrome/browser/ui/android/infobars/translate_infobar.cc b/chrome/browser/ui/android/infobars/translate_infobar.cc
index 516da32f56..a8cd9596b9 100644
--- a/chrome/browser/ui/android/infobars/translate_infobar.cc
+++ b/chrome/browser/ui/android/infobars/translate_infobar.cc
@@ -59,8 +59,6 @@ void TranslateInfoBar::ProcessButton(
return; // We're closing; don't call anything, it might access the owner.
if (action == InfoBarAndroid::ACTION_TRANSLATE) {
- // Do not close the infobar upon translate since it will be replaced by a
- // different one which will close this current infobar.
delegate_->Translate();
return;
}
diff --git a/chrome/browser/ui/android/tab_model/tab_model.h b/chrome/browser/ui/android/tab_model/tab_model.h
index e8a5e6c8eb..129164afdb 100644
--- a/chrome/browser/ui/android/tab_model/tab_model.h
+++ b/chrome/browser/ui/android/tab_model/tab_model.h
@@ -47,6 +47,9 @@ class TabModel : public content::NotificationObserver,
virtual content::WebContents* GetWebContentsAt(int index) const = 0;
virtual TabAndroid* GetTabAt(int index) const = 0;
+ virtual void SetActiveIndex(int index) = 0;
+ virtual void CloseTabAt(int index) = 0;
+
// Used for restoring tabs from synced foreign sessions.
virtual void CreateTab(content::WebContents* web_contents) = 0;
diff --git a/chrome/browser/ui/android/tab_model/tab_model_unittest.cc b/chrome/browser/ui/android/tab_model/tab_model_unittest.cc
index 3feaf0fc66..bcddf79731 100644
--- a/chrome/browser/ui/android/tab_model/tab_model_unittest.cc
+++ b/chrome/browser/ui/android/tab_model/tab_model_unittest.cc
@@ -43,7 +43,8 @@ class TestTabModel : public TabModel {
virtual TabAndroid* GetTabAt(int index) const OVERRIDE {
return NULL;
}
-
+ virtual void SetActiveIndex(int index) OVERRIDE {}
+ virtual void CloseTabAt(int index) OVERRIDE {}
};
TEST_F(TabModelTest, TestProfileHandling) {
diff --git a/chrome/browser/ui/app_list/app_context_menu.cc b/chrome/browser/ui/app_list/app_context_menu.cc
index 8d9c9c2bbb..ac5ce9e368 100644
--- a/chrome/browser/ui/app_list/app_context_menu.cc
+++ b/chrome/browser/ui/app_list/app_context_menu.cc
@@ -66,7 +66,7 @@ class ExtensionUninstaller : public ExtensionUninstallDialog::Delegate {
void Run() {
const Extension* extension =
extensions::ExtensionSystem::Get(profile_)->extension_service()->
- GetExtensionById(app_id_, true);
+ GetInstalledExtension(app_id_);
if (!extension) {
CleanUp();
return;
@@ -189,7 +189,7 @@ ui::MenuModel* AppContextMenu::GetMenuModel() {
IDS_APP_LIST_CONTEXT_MENU_PIN);
}
- if (controller_->CanDoCreateShortcutsFlow(is_platform_app_)) {
+ if (controller_->CanDoCreateShortcutsFlow()) {
menu_model_->AddItemWithStringId(CREATE_SHORTCUTS,
IDS_NEW_TAB_APP_CREATE_SHORTCUT);
}
diff --git a/chrome/browser/ui/app_list/app_list_controller_delegate.cc b/chrome/browser/ui/app_list/app_list_controller_delegate.cc
index ec1332d184..9daf2f8c68 100644
--- a/chrome/browser/ui/app_list/app_list_controller_delegate.cc
+++ b/chrome/browser/ui/app_list/app_list_controller_delegate.cc
@@ -6,7 +6,10 @@
#include "base/logging.h"
#include "chrome/browser/browser_process.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/browser_dialogs.h"
#include "chrome/common/extensions/extension_constants.h"
#include "ui/gfx/image/image_skia.h"
@@ -26,9 +29,30 @@ void AppListControllerDelegate::PinApp(const std::string& extension_id) {}
void AppListControllerDelegate::UnpinApp(const std::string& extension_id) {}
+bool AppListControllerDelegate::CanDoCreateShortcutsFlow() {
+ return false;
+}
+
void AppListControllerDelegate::DoCreateShortcutsFlow(
Profile* profile,
- const std::string& extension_id) {}
+ const std::string& extension_id) {
+ DCHECK(CanDoCreateShortcutsFlow());
+ ExtensionService* service =
+ extensions::ExtensionSystem::Get(profile)->extension_service();
+ DCHECK(service);
+ const extensions::Extension* extension = service->GetInstalledExtension(
+ extension_id);
+ DCHECK(extension);
+
+ gfx::NativeWindow parent_window = GetAppListWindow();
+ if (!parent_window)
+ return;
+ OnShowExtensionPrompt();
+ chrome::ShowCreateChromeAppShortcutsDialog(
+ parent_window, profile, extension,
+ base::Bind(&AppListControllerDelegate::OnCloseExtensionPrompt,
+ base::Unretained(this)));
+}
void AppListControllerDelegate::CreateNewWindow(Profile* profile,
bool incognito) {
diff --git a/chrome/browser/ui/app_list/app_list_controller_delegate.h b/chrome/browser/ui/app_list/app_list_controller_delegate.h
index 4b8ed1dc14..04d04a85b3 100644
--- a/chrome/browser/ui/app_list/app_list_controller_delegate.h
+++ b/chrome/browser/ui/app_list/app_list_controller_delegate.h
@@ -67,9 +67,11 @@ class AppListControllerDelegate {
virtual void OnCloseExtensionPrompt() {}
// Whether the controller supports a Create Shortcuts flow.
- virtual bool CanDoCreateShortcutsFlow(bool is_platform_app) = 0;
- virtual void DoCreateShortcutsFlow(Profile* profile,
- const std::string& extension_id);
+ virtual bool CanDoCreateShortcutsFlow();
+
+ // Show the dialog to create shortcuts. Call only if
+ // CanDoCreateShortcutsFlow() returns true.
+ void DoCreateShortcutsFlow(Profile* profile, const std::string& extension_id);
// Handle the "create window" context menu items of Chrome App.
// |incognito| is true to create an incognito window.
diff --git a/chrome/browser/ui/app_list/app_list_service_impl.cc b/chrome/browser/ui/app_list/app_list_service_impl.cc
index 006138fd5a..90fc03b306 100644
--- a/chrome/browser/ui/app_list/app_list_service_impl.cc
+++ b/chrome/browser/ui/app_list/app_list_service_impl.cc
@@ -281,7 +281,7 @@ void AppListServiceImpl::HandleCommandLineFlags(Profile* initial_profile) {
if (command_line_.HasSwitch(switches::kEnableAppList))
EnableAppList(initial_profile);
- if (command_line_.HasSwitch(switches::kDisableAppList))
+ if (command_line_.HasSwitch(switches::kResetAppListInstallState))
local_state_->SetBoolean(prefs::kAppLauncherHasBeenEnabled, false);
}
diff --git a/chrome/browser/ui/app_list/app_list_service_mac.mm b/chrome/browser/ui/app_list/app_list_service_mac.mm
index 4dcaf16961..193a93d124 100644
--- a/chrome/browser/ui/app_list/app_list_service_mac.mm
+++ b/chrome/browser/ui/app_list/app_list_service_mac.mm
@@ -89,10 +89,7 @@ class AppListControllerDelegateCocoa : public AppListControllerDelegate {
virtual void DismissView() OVERRIDE;
virtual gfx::NativeWindow GetAppListWindow() OVERRIDE;
virtual Pinnable GetPinnable() OVERRIDE;
- virtual bool CanDoCreateShortcutsFlow(bool is_platform_app) OVERRIDE;
virtual void CreateNewWindow(Profile* profile, bool incognito) OVERRIDE;
- virtual void DoCreateShortcutsFlow(Profile* profile,
- const std::string& extension_id) OVERRIDE;
virtual void ActivateApp(Profile* profile,
const extensions::Extension* extension,
AppListSource source,
@@ -216,24 +213,6 @@ AppListControllerDelegate::Pinnable
return NO_PIN;
}
-bool AppListControllerDelegateCocoa::CanDoCreateShortcutsFlow(
- bool is_platform_app) {
- return false;
-}
-
-void AppListControllerDelegateCocoa::DoCreateShortcutsFlow(
- Profile* profile, const std::string& extension_id) {
- ExtensionService* service =
- extensions::ExtensionSystem::Get(profile)->extension_service();
- DCHECK(service);
- const extensions::Extension* extension =
- service->GetInstalledExtension(extension_id);
- DCHECK(extension);
-
- web_app::UpdateShortcutInfoAndIconForApp(
- *extension, profile, base::Bind(&CreateShortcutsInDefaultLocation));
-}
-
void AppListControllerDelegateCocoa::CreateNewWindow(
Profile* profile, bool incognito) {
Profile* window_profile = incognito ?
@@ -454,7 +433,9 @@ void AppListServiceMac::CreateForProfile(Profile* requested_profile) {
}
scoped_ptr<app_list::AppListViewDelegate> delegate(
- new AppListViewDelegate(new AppListControllerDelegateCocoa(), profile()));
+ new AppListViewDelegate(
+ scoped_ptr<AppListControllerDelegate>(
+ new AppListControllerDelegateCocoa()), profile()));
[[window_controller_ appListViewController] setDelegate:delegate.Pass()];
}
diff --git a/chrome/browser/ui/app_list/app_list_service_unittest.cc b/chrome/browser/ui/app_list/app_list_service_unittest.cc
index 570b1d5712..9ad7aeec0c 100644
--- a/chrome/browser/ui/app_list/app_list_service_unittest.cc
+++ b/chrome/browser/ui/app_list/app_list_service_unittest.cc
@@ -168,7 +168,7 @@ TEST_F(AppListServiceUnitTest, EnableViaCommandLineFlag) {
TEST_F(AppListServiceUnitTest, DisableViaCommandLineFlag) {
CommandLine command_line(CommandLine::NO_PROGRAM);
- command_line.AppendSwitch(switches::kDisableAppList);
+ command_line.AppendSwitch(switches::kResetAppListInstallState);
SetupWithCommandLine(command_line);
service_->HandleCommandLineFlags(profile1_.get());
EXPECT_FALSE(local_state_->GetBoolean(prefs::kAppLauncherHasBeenEnabled));
diff --git a/chrome/browser/ui/app_list/app_list_view_delegate.cc b/chrome/browser/ui/app_list/app_list_view_delegate.cc
index 0a5202d0cf..89d54fe7b2 100644
--- a/chrome/browser/ui/app_list/app_list_view_delegate.cc
+++ b/chrome/browser/ui/app_list/app_list_view_delegate.cc
@@ -76,9 +76,10 @@ void PopulateUsers(const ProfileInfoCache& profile_info,
} // namespace
-AppListViewDelegate::AppListViewDelegate(AppListControllerDelegate* controller,
- Profile* profile)
- : controller_(controller),
+AppListViewDelegate::AppListViewDelegate(
+ scoped_ptr<AppListControllerDelegate> controller,
+ Profile* profile)
+ : controller_(controller.Pass()),
profile_(profile),
model_(NULL) {
CHECK(controller_);
diff --git a/chrome/browser/ui/app_list/app_list_view_delegate.h b/chrome/browser/ui/app_list/app_list_view_delegate.h
index d7ab3cf928..0a2584fff1 100644
--- a/chrome/browser/ui/app_list/app_list_view_delegate.h
+++ b/chrome/browser/ui/app_list/app_list_view_delegate.h
@@ -47,7 +47,8 @@ class AppListViewDelegate : public app_list::AppListViewDelegate,
public ProfileInfoCacheObserver {
public:
// The delegate will take ownership of the controller.
- AppListViewDelegate(AppListControllerDelegate* controller, Profile* profile);
+ AppListViewDelegate(scoped_ptr<AppListControllerDelegate> controller,
+ Profile* profile);
virtual ~AppListViewDelegate();
private:
diff --git a/chrome/browser/ui/app_list/extension_app_item.cc b/chrome/browser/ui/app_list/extension_app_item.cc
index 07b0c60708..6d1f9aa9e6 100644
--- a/chrome/browser/ui/app_list/extension_app_item.cc
+++ b/chrome/browser/ui/app_list/extension_app_item.cc
@@ -144,6 +144,35 @@ void ExtensionAppItem::UpdateIcon() {
SetIcon(icon, !HasOverlay());
}
+void ExtensionAppItem::Move(const ExtensionAppItem* prev,
+ const ExtensionAppItem* next) {
+ if (!prev && !next)
+ return; // No reordering necessary
+
+ ExtensionService* service =
+ extensions::ExtensionSystem::Get(profile_)->extension_service();
+ ExtensionSorting* sorting = service->extension_prefs()->extension_sorting();
+
+ syncer::StringOrdinal page;
+ std::string prev_id, next_id;
+ if (!prev) {
+ next_id = next->extension_id();
+ page = sorting->GetPageOrdinal(next_id);
+ } else if (!next) {
+ prev_id = prev->extension_id();
+ page = sorting->GetPageOrdinal(prev_id);
+ } else {
+ prev_id = prev->extension_id();
+ page = sorting->GetPageOrdinal(prev_id);
+ // Only set |next_id| if on the same page, otherwise just insert after prev.
+ if (page.Equals(sorting->GetPageOrdinal(next->extension_id())))
+ next_id = next->extension_id();
+ }
+ service->extension_prefs()->SetAppDraggedByUser(extension_id_);
+ sorting->SetPageOrdinal(extension_id_, page);
+ service->OnExtensionMoved(extension_id_, prev_id, next_id);
+}
+
const Extension* ExtensionAppItem::GetExtension() const {
const ExtensionService* service =
extensions::ExtensionSystem::Get(profile_)->extension_service();
diff --git a/chrome/browser/ui/app_list/extension_app_item.h b/chrome/browser/ui/app_list/extension_app_item.h
index 3d4224f1a1..eb56f42b32 100644
--- a/chrome/browser/ui/app_list/extension_app_item.h
+++ b/chrome/browser/ui/app_list/extension_app_item.h
@@ -48,6 +48,11 @@ class ExtensionAppItem : public app_list::AppListItemModel,
// it gray.
void UpdateIcon();
+ // Update page and app launcher ordinals to put the app in between |prev| and
+ // |next|. Note that |prev| and |next| could be NULL when the app is put at
+ // the beginning or at the end.
+ void Move(const ExtensionAppItem* prev, const ExtensionAppItem* next);
+
const std::string& extension_id() const { return extension_id_; }
static const char kAppType[];
diff --git a/chrome/browser/ui/app_list/extension_app_model_builder.cc b/chrome/browser/ui/app_list/extension_app_model_builder.cc
index 767bb7b7f2..1f17f6d6d6 100644
--- a/chrome/browser/ui/app_list/extension_app_model_builder.cc
+++ b/chrome/browser/ui/app_list/extension_app_model_builder.cc
@@ -48,11 +48,13 @@ ExtensionAppModelBuilder::ExtensionAppModelBuilder(
model_(model),
highlighted_app_pending_(false),
tracker_(NULL) {
+ model_->apps()->AddObserver(this);
SwitchProfile(profile); // Builds the model.
}
ExtensionAppModelBuilder::~ExtensionAppModelBuilder() {
OnShutdown();
+ model_->apps()->RemoveObserver(this);
}
void ExtensionAppModelBuilder::OnBeginExtensionInstall(
@@ -239,3 +241,40 @@ void ExtensionAppModelBuilder::UpdateHighlight() {
item->SetHighlighted(true);
highlighted_app_pending_ = false;
}
+
+void ExtensionAppModelBuilder::ListItemsAdded(size_t start, size_t count) {
+}
+
+void ExtensionAppModelBuilder::ListItemsRemoved(size_t start, size_t count) {
+}
+
+void ExtensionAppModelBuilder::ListItemMoved(size_t index,
+ size_t target_index) {
+ app_list::AppListModel::Apps* app_list = model_->apps();
+ app_list::AppListItemModel* item = app_list->GetItemAt(target_index);
+ if (item->GetAppType() != ExtensionAppItem::kAppType)
+ return;
+
+ ExtensionAppItem* prev = NULL;
+ for (size_t idx = target_index; idx > 1; --idx) {
+ app_list::AppListItemModel* item = app_list->GetItemAt(idx - 1);
+ if (item->GetAppType() == ExtensionAppItem::kAppType) {
+ prev = static_cast<ExtensionAppItem*>(item);
+ break;
+ }
+ }
+ ExtensionAppItem* next = NULL;
+ for (size_t idx = target_index; idx < app_list->item_count() - 1; ++idx) {
+ app_list::AppListItemModel* item = app_list->GetItemAt(idx + 1);
+ if (item->GetAppType() == ExtensionAppItem::kAppType) {
+ next = static_cast<ExtensionAppItem*>(item);
+ break;
+ }
+ }
+ if (prev || next)
+ static_cast<ExtensionAppItem*>(item)->Move(prev, next);
+}
+
+void ExtensionAppModelBuilder::ListItemsChanged(size_t start, size_t count) {
+ NOTREACHED();
+}
diff --git a/chrome/browser/ui/app_list/extension_app_model_builder.h b/chrome/browser/ui/app_list/extension_app_model_builder.h
index 9278d05299..50cfb9e414 100644
--- a/chrome/browser/ui/app_list/extension_app_model_builder.h
+++ b/chrome/browser/ui/app_list/extension_app_model_builder.h
@@ -29,7 +29,8 @@ class ImageSkia;
// This class populates and maintains the given |model| with information from
// |profile|.
-class ExtensionAppModelBuilder : public extensions::InstallObserver {
+class ExtensionAppModelBuilder : public extensions::InstallObserver,
+ public ui::ListModelObserver {
public:
ExtensionAppModelBuilder(Profile* profile,
app_list::AppListModel* model,
@@ -42,16 +43,14 @@ class ExtensionAppModelBuilder : public extensions::InstallObserver {
private:
typedef std::vector<ExtensionAppItem*> ExtensionAppList;
- // Overridden from extensions::InstallObserver:
+ // extensions::InstallObserver
virtual void OnBeginExtensionInstall(const std::string& extension_id,
const std::string& extension_name,
const gfx::ImageSkia& installing_icon,
bool is_app,
bool is_platform_app) OVERRIDE;
-
virtual void OnDownloadProgress(const std::string& extension_id,
int percent_downloaded) OVERRIDE;
-
virtual void OnInstallFailure(const std::string& extension_id) OVERRIDE;
virtual void OnExtensionInstalled(
const extensions::Extension* extension) OVERRIDE {}
@@ -66,6 +65,12 @@ class ExtensionAppModelBuilder : public extensions::InstallObserver {
const std::string& extension_id) OVERRIDE;
virtual void OnShutdown() OVERRIDE;
+ // ui::ListModelObserver
+ virtual void ListItemsAdded(size_t start, size_t count) OVERRIDE;
+ virtual void ListItemsRemoved(size_t start, size_t count) OVERRIDE;
+ virtual void ListItemMoved(size_t index, size_t target_index) OVERRIDE;
+ virtual void ListItemsChanged(size_t start, size_t count) OVERRIDE;
+
// Adds apps in |extensions| to |apps|.
void AddApps(const ExtensionSet* extensions, ExtensionAppList* apps);
diff --git a/chrome/browser/ui/app_list/search/app_search_provider.cc b/chrome/browser/ui/app_list/search/app_search_provider.cc
index ceba03f9c4..c7fc5f0ddf 100644
--- a/chrome/browser/ui/app_list/search/app_search_provider.cc
+++ b/chrome/browser/ui/app_list/search/app_search_provider.cc
@@ -10,6 +10,7 @@
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system_factory.h"
+#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/app_list/search/app_result.h"
#include "chrome/browser/ui/app_list/search/tokenized_string.h"
@@ -82,7 +83,7 @@ void AppSearchProvider::AddApps(const ExtensionSet* extensions,
continue;
if (profile_->IsOffTheRecord() &&
- !service->CanLoadInIncognito(app))
+ !extension_util::CanLoadInIncognito(app, service))
continue;
apps_.push_back(new App(app));
}
diff --git a/chrome/browser/ui/app_list/search/app_search_provider_unittest.cc b/chrome/browser/ui/app_list/search/app_search_provider_unittest.cc
index fe8f22c154..ab44c2d9fc 100644
--- a/chrome/browser/ui/app_list/search/app_search_provider_unittest.cc
+++ b/chrome/browser/ui/app_list/search/app_search_provider_unittest.cc
@@ -19,7 +19,6 @@ namespace test {
const char kHostedAppId[] = "dceacbkfkmllgmjmbhgkpjegnodmildf";
const char kPackagedApp1Id[] = "emfkafnhnpcmabnnkckkchdilgeoekbo";
-const char kPackagedApp2Id[] = "jlklkagmeajbjiobondfhiekepofmljl";
class AppSearchProviderTest : public ExtensionServiceTestBase {
public:
diff --git a/chrome/browser/ui/app_list/search/common/dictionary_data_store.cc b/chrome/browser/ui/app_list/search/common/dictionary_data_store.cc
new file mode 100644
index 0000000000..fd50e8d51d
--- /dev/null
+++ b/chrome/browser/ui/app_list/search/common/dictionary_data_store.cc
@@ -0,0 +1,92 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/app_list/search/common/dictionary_data_store.h"
+
+#include "base/callback.h"
+#include "base/json/json_file_value_serializer.h"
+#include "base/json/json_string_value_serializer.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/task_runner_util.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "base/values.h"
+#include "content/public/browser/browser_thread.h"
+
+using content::BrowserThread;
+
+namespace app_list {
+
+DictionaryDataStore::DictionaryDataStore(const base::FilePath& data_file)
+ : data_file_(data_file) {
+ std::string token("app-launcher-data-store");
+ token.append(data_file.AsUTF8Unsafe());
+
+ // Uses a SKIP_ON_SHUTDOWN file task runner because losing a couple
+ // associations is better than blocking shutdown.
+ base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool();
+ file_task_runner_ = pool->GetSequencedTaskRunnerWithShutdownBehavior(
+ pool->GetNamedSequenceToken(token),
+ base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+ writer_.reset(
+ new base::ImportantFileWriter(data_file, file_task_runner_.get()));
+
+ cached_dict_.reset(new base::DictionaryValue);
+}
+
+DictionaryDataStore::~DictionaryDataStore() {
+ Flush(OnFlushedCallback());
+}
+
+void DictionaryDataStore::Flush(const OnFlushedCallback& on_flushed) {
+ if (writer_->HasPendingWrite())
+ writer_->DoScheduledWrite();
+
+ if (on_flushed.is_null())
+ return;
+
+ file_task_runner_->PostTaskAndReply(
+ FROM_HERE, base::Bind(&base::DoNothing), on_flushed);
+}
+
+void DictionaryDataStore::Load(
+ const DictionaryDataStore::OnLoadedCallback& on_loaded) {
+ base::PostTaskAndReplyWithResult(
+ file_task_runner_.get(),
+ FROM_HERE,
+ base::Bind(&DictionaryDataStore::LoadOnBlockingPool, this),
+ on_loaded);
+}
+
+void DictionaryDataStore::ScheduleWrite() {
+ writer_->ScheduleWrite(this);
+}
+
+scoped_ptr<base::DictionaryValue> DictionaryDataStore::LoadOnBlockingPool() {
+ DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
+
+ int error_code = JSONFileValueSerializer::JSON_NO_ERROR;
+ std::string error_message;
+ JSONFileValueSerializer serializer(data_file_);
+ base::Value* value = serializer.Deserialize(&error_code, &error_message);
+ base::DictionaryValue* dict_value = NULL;
+ if (error_code != JSONFileValueSerializer::JSON_NO_ERROR ||
+ !value ||
+ !value->GetAsDictionary(&dict_value) ||
+ !dict_value) {
+ return scoped_ptr<base::DictionaryValue>();
+ }
+
+ base::DictionaryValue* return_dict = dict_value->DeepCopy();
+ cached_dict_.reset(dict_value);
+ return make_scoped_ptr(return_dict).Pass();
+}
+
+bool DictionaryDataStore::SerializeData(std::string* data) {
+ JSONStringValueSerializer serializer(data);
+ serializer.set_pretty_print(true);
+ return serializer.Serialize(*cached_dict_.get());
+}
+
+} // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/common/dictionary_data_store.h b/chrome/browser/ui/app_list/search/common/dictionary_data_store.h
new file mode 100644
index 0000000000..dac2f61fcb
--- /dev/null
+++ b/chrome/browser/ui/app_list/search/common/dictionary_data_store.h
@@ -0,0 +1,74 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_APP_LIST_SEARCH_COMMON_DICTIONARY_DATA_STORE_H_
+#define CHROME_BROWSER_UI_APP_LIST_SEARCH_COMMON_DICTIONARY_DATA_STORE_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/callback_forward.h"
+#include "base/files/file_path.h"
+#include "base/files/important_file_writer.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+
+namespace base {
+class DictionaryValue;
+class SequencedTaskRunner;
+}
+
+namespace app_list {
+
+// A simple JSON store to persist a dictionary.
+class DictionaryDataStore
+ : public base::RefCountedThreadSafe<DictionaryDataStore>,
+ public base::ImportantFileWriter::DataSerializer {
+ public:
+ typedef base::Callback<void(
+ scoped_ptr<base::DictionaryValue>)> OnLoadedCallback;
+ typedef base::Closure OnFlushedCallback;
+
+ explicit DictionaryDataStore(const base::FilePath& data_file);
+
+ // Flushes pending writes.
+ void Flush(const OnFlushedCallback& on_flushed);
+
+ // Reads the persisted data from disk asynchronously. |on_read| is called
+ // with the loaded and parsed data. If there is an error, |on_read| is called
+ // without data.
+ void Load(const OnLoadedCallback& on_loaded);
+
+ // Schedule a job to persist the cached dictionary.
+ void ScheduleWrite();
+
+ // Used to get a pointer to the cached dictionary. Changes to this dictionary
+ // will not be persisted unless ScheduleWrite() is called.
+ base::DictionaryValue* cached_dict() { return cached_dict_.get(); }
+
+ private:
+ friend class base::RefCountedThreadSafe<DictionaryDataStore>;
+
+ virtual ~DictionaryDataStore();
+
+ // Reads data from backing file.
+ scoped_ptr<base::DictionaryValue> LoadOnBlockingPool();
+
+ // ImportantFileWriter::DataSerializer overrides:
+ virtual bool SerializeData(std::string* data) OVERRIDE;
+
+ base::FilePath data_file_;
+ scoped_refptr<base::SequencedTaskRunner> file_task_runner_;
+ scoped_ptr<base::ImportantFileWriter> writer_;
+
+ // Cached JSON dictionary to serve read and incremental change calls.
+ scoped_ptr<base::DictionaryValue> cached_dict_;
+
+ DISALLOW_COPY_AND_ASSIGN(DictionaryDataStore);
+};
+
+} // namespace app_list
+
+#endif // CHROME_BROWSER_UI_APP_LIST_SEARCH_COMMON_DICTIONARY_DATA_STORE_H_
diff --git a/chrome/browser/ui/app_list/search/history_data_store.cc b/chrome/browser/ui/app_list/search/history_data_store.cc
index b52598fba9..c8ea497e91 100644
--- a/chrome/browser/ui/app_list/search/history_data_store.cc
+++ b/chrome/browser/ui/app_list/search/history_data_store.cc
@@ -60,15 +60,17 @@ void GetSecondary(const base::ListValue* list,
// ...
// }
// }
-scoped_ptr<HistoryData::Associations> Parse(const base::DictionaryValue& dict) {
+scoped_ptr<HistoryData::Associations> Parse(
+ scoped_ptr<base::DictionaryValue> dict) {
std::string version;
- if (!dict.GetStringWithoutPathExpansion(kKeyVersion, &version) ||
+ if (!dict->GetStringWithoutPathExpansion(kKeyVersion, &version) ||
version != kCurrentVersion) {
return scoped_ptr<HistoryData::Associations>();
}
const base::DictionaryValue* assoc_dict = NULL;
- if (!dict.GetDictionaryWithoutPathExpansion(kKeyAssociations, &assoc_dict) ||
+ if (!dict->GetDictionaryWithoutPathExpansion(kKeyAssociations,
+ &assoc_dict) ||
!assoc_dict) {
return scoped_ptr<HistoryData::Associations>();
}
@@ -107,52 +109,29 @@ scoped_ptr<HistoryData::Associations> Parse(const base::DictionaryValue& dict) {
return data.Pass();
}
-// An empty callback used to ensure file tasks are cleared.
-void EmptyCallback() {}
-
} // namespace
HistoryDataStore::HistoryDataStore(const base::FilePath& data_file)
- : data_file_(data_file) {
- std::string token("app-launcher-history-data-store");
- token.append(data_file.AsUTF8Unsafe());
-
- // Uses a SKIP_ON_SHUTDOWN file task runner because losing a couple
- // associations is better than blocking shutdown.
- base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool();
- file_task_runner_ = pool->GetSequencedTaskRunnerWithShutdownBehavior(
- pool->GetNamedSequenceToken(token),
- base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
- writer_.reset(
- new base::ImportantFileWriter(data_file, file_task_runner_.get()));
-
- cached_json_.reset(new base::DictionaryValue);
- cached_json_->SetString(kKeyVersion, kCurrentVersion);
- cached_json_->Set(kKeyAssociations, new base::DictionaryValue);
+ : data_store_(new DictionaryDataStore(data_file)) {
+ base::DictionaryValue* dict = data_store_->cached_dict();
+ DCHECK(dict);
+ dict->SetString(kKeyVersion, kCurrentVersion);
+ dict->Set(kKeyAssociations, new base::DictionaryValue);
}
HistoryDataStore::~HistoryDataStore() {
- Flush(OnFlushedCallback());
}
-void HistoryDataStore::Flush(const OnFlushedCallback& on_flushed) {
- if (writer_->HasPendingWrite())
- writer_->DoScheduledWrite();
-
- if (on_flushed.is_null())
- return;
-
- file_task_runner_->PostTaskAndReply(
- FROM_HERE, base::Bind(&EmptyCallback), on_flushed);
+void HistoryDataStore::Flush(
+ const DictionaryDataStore::OnFlushedCallback& on_flushed) {
+ data_store_->Flush(on_flushed);
}
void HistoryDataStore::Load(
const HistoryDataStore::OnLoadedCallback& on_loaded) {
- base::PostTaskAndReplyWithResult(
- file_task_runner_.get(),
- FROM_HERE,
- base::Bind(&HistoryDataStore::LoadOnBlockingPool, this),
- on_loaded);
+ data_store_->Load(base::Bind(&HistoryDataStore::OnDictionaryLoadedCallback,
+ this,
+ on_loaded));
}
void HistoryDataStore::SetPrimary(const std::string& query,
@@ -160,7 +139,7 @@ void HistoryDataStore::SetPrimary(const std::string& query,
base::DictionaryValue* entry_dict = GetEntryDict(query);
entry_dict->SetWithoutPathExpansion(kKeyPrimary,
new base::StringValue(result));
- writer_->ScheduleWrite(this);
+ data_store_->ScheduleWrite();
}
void HistoryDataStore::SetSecondary(
@@ -172,7 +151,7 @@ void HistoryDataStore::SetSecondary(
base::DictionaryValue* entry_dict = GetEntryDict(query);
entry_dict->SetWithoutPathExpansion(kKeySecondary, results_list.release());
- writer_->ScheduleWrite(this);
+ data_store_->ScheduleWrite();
}
void HistoryDataStore::SetUpdateTime(const std::string& query,
@@ -181,18 +160,21 @@ void HistoryDataStore::SetUpdateTime(const std::string& query,
entry_dict->SetWithoutPathExpansion(kKeyUpdateTime,
new base::StringValue(base::Int64ToString(
update_time.ToInternalValue())));
- writer_->ScheduleWrite(this);
+ data_store_->ScheduleWrite();
}
void HistoryDataStore::Delete(const std::string& query) {
base::DictionaryValue* assoc_dict = GetAssociationDict();
assoc_dict->RemoveWithoutPathExpansion(query, NULL);
- writer_->ScheduleWrite(this);
+ data_store_->ScheduleWrite();
}
base::DictionaryValue* HistoryDataStore::GetAssociationDict() {
+ base::DictionaryValue* cached_dict = data_store_->cached_dict();
+ DCHECK(cached_dict);
+
base::DictionaryValue* assoc_dict = NULL;
- CHECK(cached_json_->GetDictionary(kKeyAssociations, &assoc_dict) &&
+ CHECK(cached_dict->GetDictionary(kKeyAssociations, &assoc_dict) &&
assoc_dict);
return assoc_dict;
@@ -212,29 +194,13 @@ base::DictionaryValue* HistoryDataStore::GetEntryDict(
return entry_dict;
}
-scoped_ptr<HistoryData::Associations> HistoryDataStore::LoadOnBlockingPool() {
- DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
-
- int error_code = JSONFileValueSerializer::JSON_NO_ERROR;
- std::string error_message;
- JSONFileValueSerializer serializer(data_file_);
- base::Value* value = serializer.Deserialize(&error_code, &error_message);
- base::DictionaryValue* dict_value = NULL;
- if (error_code != JSONFileValueSerializer::JSON_NO_ERROR ||
- !value ||
- !value->GetAsDictionary(&dict_value) ||
- !dict_value) {
- return scoped_ptr<HistoryData::Associations>();
+void HistoryDataStore::OnDictionaryLoadedCallback(
+ OnLoadedCallback callback, scoped_ptr<base::DictionaryValue> dict) {
+ if (!dict) {
+ callback.Run(scoped_ptr<HistoryData::Associations>());
+ } else {
+ callback.Run(Parse(dict.Pass()).Pass());
}
-
- cached_json_.reset(dict_value);
- return Parse(*dict_value).Pass();
-}
-
-bool HistoryDataStore::SerializeData(std::string* data) {
- JSONStringValueSerializer serializer(data);
- serializer.set_pretty_print(true);
- return serializer.Serialize(*cached_json_.get());
}
} // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/history_data_store.h b/chrome/browser/ui/app_list/search/history_data_store.h
index 2df529e0d1..56d8571091 100644
--- a/chrome/browser/ui/app_list/search/history_data_store.h
+++ b/chrome/browser/ui/app_list/search/history_data_store.h
@@ -14,6 +14,7 @@
#include "base/files/important_file_writer.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/ui/app_list/search/common/dictionary_data_store.h"
#include "chrome/browser/ui/app_list/search/history_data.h"
namespace base {
@@ -28,18 +29,16 @@ class HistoryDataStoreTest;
}
// A simple json store to persist HistoryData.
-class HistoryDataStore : public base::RefCountedThreadSafe<HistoryDataStore>,
- public base::ImportantFileWriter::DataSerializer {
+class HistoryDataStore : public base::RefCountedThreadSafe<HistoryDataStore> {
public:
typedef base::Callback<void(scoped_ptr<HistoryData::Associations>)>
OnLoadedCallback;
- typedef base::Closure OnFlushedCallback;
explicit HistoryDataStore(const base::FilePath& data_file);
// Flushes pending writes. |on_flushed| is invoked when disk write is
// finished.
- void Flush(const OnFlushedCallback& on_flushed);
+ void Flush(const DictionaryDataStore::OnFlushedCallback& on_flushed);
// Reads the persisted data from disk asynchronously. |on_read| is called
// with the loaded and parsed data. If there is an error, |on_read| is called
@@ -65,18 +64,10 @@ class HistoryDataStore : public base::RefCountedThreadSafe<HistoryDataStore>,
// Gets entry dictionary for given |query|. Creates one if necessary.
base::DictionaryValue* GetEntryDict(const std::string& query);
- // Reads data from backing file.
- scoped_ptr<HistoryData::Associations> LoadOnBlockingPool();
+ void OnDictionaryLoadedCallback(OnLoadedCallback callback,
+ scoped_ptr<base::DictionaryValue> dict);
- // ImportantFileWriter::DataSerializer overrides:
- virtual bool SerializeData(std::string* data) OVERRIDE;
-
- base::FilePath data_file_;
- scoped_refptr<base::SequencedTaskRunner> file_task_runner_;
- scoped_ptr<base::ImportantFileWriter> writer_;
-
- // Cached json dictionary to serve read and incremental change calls.
- scoped_ptr<base::DictionaryValue> cached_json_;
+ scoped_refptr<DictionaryDataStore> data_store_;
DISALLOW_COPY_AND_ASSIGN(HistoryDataStore);
};
diff --git a/chrome/browser/ui/app_list/search/history_data_store_unittest.cc b/chrome/browser/ui/app_list/search/history_data_store_unittest.cc
index 123faa291c..3d71554875 100644
--- a/chrome/browser/ui/app_list/search/history_data_store_unittest.cc
+++ b/chrome/browser/ui/app_list/search/history_data_store_unittest.cc
@@ -59,7 +59,7 @@ class HistoryDataStoreTest : public testing::Test {
}
void Flush() {
- store_->Flush(HistoryDataStore::OnFlushedCallback());
+ store_->Flush(DictionaryDataStore::OnFlushedCallback());
}
void Load() {
diff --git a/chrome/browser/ui/app_list/search/people/people_result.cc b/chrome/browser/ui/app_list/search/people/people_result.cc
index c80a39634d..03f37472b3 100644
--- a/chrome/browser/ui/app_list/search/people/people_result.cc
+++ b/chrome/browser/ui/app_list/search/people/people_result.cc
@@ -35,7 +35,12 @@ const int kIconSize = 32;
const char kImageSizePath[] = "s32-p/";
const char kEmailUrlPrefix[] = "mailto:";
-const char kHangoutsExtensionId[] = "eigpckmcflhchknfhifenfgmjncfgcak";
+const char* const kHangoutsExtensionIds[] = {
+ "nckgahadagoaajjgafhacjanaoiihapd",
+ "ljclpkphhpbpinifbeabbhlfddcpfdde",
+ "ppleadejekpmccmnpjdimmlfljlkdfej",
+ "eggnbpckecmjlblplehfpjjdhhidfdoj"
+};
// Add a query parameter to specify the size to fetch the image in. The
// original profile image can be of an arbitrary size, we ask the server to
@@ -59,7 +64,7 @@ PeopleResult::PeopleResult(Profile* profile, scoped_ptr<Person> person)
set_relevance(person_->interaction_rank);
set_details(UTF8ToUTF16(person_->email));
- is_chat_available_ = IsChatAvailable();
+ RefreshHangoutsExtensionId();
SetDefaultActions();
image_ = gfx::ImageSkia(
@@ -82,7 +87,7 @@ void PeopleResult::Open(int event_flags) {
}
void PeopleResult::InvokeAction(int action_index, int event_flags) {
- if (!is_chat_available_) {
+ if (hangouts_extension_id_.empty()) {
// If the hangouts app is not available, the only option we are showing
// to the user is 'Send Email'.
SendEmail();
@@ -119,7 +124,7 @@ void PeopleResult::SetDefaultActions() {
Actions actions;
ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
- if (is_chat_available_) {
+ if (!hangouts_extension_id_.empty()) {
actions.push_back(Action(
*bundle.GetImageSkiaNamed(IDR_PEOPLE_SEARCH_ACTION_CHAT),
*bundle.GetImageSkiaNamed(IDR_PEOPLE_SEARCH_ACTION_CHAT_HOVER),
@@ -158,7 +163,7 @@ void PeopleResult::OpenChat() {
// See crbug.com/306672
extensions::ExtensionSystem::Get(
profile_)->event_router()->DispatchEventToExtension(
- kHangoutsExtensionId, event.Pass());
+ hangouts_extension_id_, event.Pass());
}
void PeopleResult::SendEmail() {
@@ -170,12 +175,18 @@ void PeopleResult::SendEmail() {
chrome::Navigate(&params);
}
-bool PeopleResult::IsChatAvailable() {
+void PeopleResult::RefreshHangoutsExtensionId() {
// TODO(rkc): Change this once we remove the hangoutsPrivate API.
// See crbug.com/306672
- return extensions::ExtensionSystem::Get(
- profile_)->event_router()->ExtensionHasEventListener(
- kHangoutsExtensionId, OnHangoutRequested::kEventName);
+ for (size_t i = 0; i < arraysize(kHangoutsExtensionIds); ++i) {
+ if (extensions::ExtensionSystem::Get(
+ profile_)->event_router()->ExtensionHasEventListener(
+ kHangoutsExtensionIds[i], OnHangoutRequested::kEventName)) {
+ hangouts_extension_id_ = kHangoutsExtensionIds[i];
+ return;
+ }
+ }
+ hangouts_extension_id_.clear();
}
ChromeSearchResultType PeopleResult::GetType() {
diff --git a/chrome/browser/ui/app_list/search/people/people_result.h b/chrome/browser/ui/app_list/search/people/people_result.h
index d49853d168..2381f98025 100644
--- a/chrome/browser/ui/app_list/search/people/people_result.h
+++ b/chrome/browser/ui/app_list/search/people/people_result.h
@@ -35,7 +35,12 @@ class PeopleResult : public ChromeSearchResult {
void OpenChat();
void SendEmail();
- bool IsChatAvailable();
+ // Check if we have any variant of the hangouts extension installed and
+ // waiting on the onHangoutRequested event (the hangouts extension can have
+ // a total of four possible id's, depending on which release type of it is
+ // installed). If so, set the hangouts_extension_id_ to the id of the
+ // extension that is waiting, or set it to an empty string if not.
+ void RefreshHangoutsExtensionId();
Profile* profile_;
scoped_ptr<Person> person_;
@@ -43,9 +48,8 @@ class PeopleResult : public ChromeSearchResult {
gfx::ImageSkia image_;
base::WeakPtrFactory<PeopleResult> weak_factory_;
- // Caches whether or not the hangouts app is available for us to
- // send chat/video reqeusts to.
- bool is_chat_available_;
+ // Caches the id of the hangouts extension.
+ std::string hangouts_extension_id_;
DISALLOW_COPY_AND_ASSIGN(PeopleResult);
};
diff --git a/chrome/browser/ui/ash/app_list/app_list_controller_ash.cc b/chrome/browser/ui/ash/app_list/app_list_controller_ash.cc
index fdf01dd1a0..54b4a51575 100644
--- a/chrome/browser/ui/ash/app_list/app_list_controller_ash.cc
+++ b/chrome/browser/ui/ash/app_list/app_list_controller_ash.cc
@@ -41,11 +41,6 @@ AppListControllerDelegate::Pinnable
PIN_FIXED;
}
-bool AppListControllerDelegateAsh::CanDoCreateShortcutsFlow(
- bool is_platform_app) {
- return false;
-}
-
void AppListControllerDelegateAsh::CreateNewWindow(Profile* profile,
bool incognito) {
if (incognito)
diff --git a/chrome/browser/ui/ash/app_list/app_list_controller_ash.h b/chrome/browser/ui/ash/app_list/app_list_controller_ash.h
index 60005f509a..bf4c295a54 100644
--- a/chrome/browser/ui/ash/app_list/app_list_controller_ash.h
+++ b/chrome/browser/ui/ash/app_list/app_list_controller_ash.h
@@ -23,7 +23,6 @@ class AppListControllerDelegateAsh : public AppListControllerDelegate {
virtual void PinApp(const std::string& extension_id) OVERRIDE;
virtual void UnpinApp(const std::string& extension_id) OVERRIDE;
virtual Pinnable GetPinnable() OVERRIDE;
- virtual bool CanDoCreateShortcutsFlow(bool is_platform_app) OVERRIDE;
virtual void CreateNewWindow(Profile* profile, bool incognito) OVERRIDE;
virtual void ActivateApp(Profile* profile,
const extensions::Extension* extension,
diff --git a/chrome/browser/ui/ash/ash_keyboard_controller_proxy.cc b/chrome/browser/ui/ash/ash_keyboard_controller_proxy.cc
index 2b5c833b9c..9c986f6ae9 100644
--- a/chrome/browser/ui/ash/ash_keyboard_controller_proxy.cc
+++ b/chrome/browser/ui/ash/ash_keyboard_controller_proxy.cc
@@ -9,6 +9,7 @@
#include "chrome/browser/extensions/extension_function_dispatcher.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/extension_web_contents_observer.h"
#include "chrome/browser/extensions/event_names.h"
#include "chrome/browser/extensions/event_router.h"
#include "chrome/browser/media/media_capture_devices_dispatcher.h"
@@ -114,6 +115,7 @@ void AshKeyboardControllerProxy::SetupWebContents(
new ExtensionFunctionDispatcher(ProfileManager::GetDefaultProfile(),
this));
extensions::SetViewType(contents, extensions::VIEW_TYPE_VIRTUAL_KEYBOARD);
+ extensions::ExtensionWebContentsObserver::CreateForWebContents(contents);
Observe(contents);
}
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.cc b/chrome/browser/ui/ash/chrome_shell_delegate.cc
index f0543bcd06..c94e533de7 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate.cc
+++ b/chrome/browser/ui/ash/chrome_shell_delegate.cc
@@ -200,21 +200,6 @@ void ChromeShellDelegate::ToggleFullscreen() {
}
}
-void ChromeShellDelegate::ToggleMaximized() {
- // Only toggle if the user has a window open.
- aura::Window* window = ash::wm::GetActiveWindow();
- if (!window)
- return;
-
- ash::wm::WindowState* window_state = ash::wm::GetWindowState(window);
- // Get out of fullscreen when in fullscreen mode.
- if (window_state->IsFullscreen()) {
- ToggleFullscreen();
- return;
- }
- window_state->ToggleMaximized();
-}
-
void ChromeShellDelegate::RestoreTab() {
if (tab_restore_helper_.get()) {
DCHECK(!tab_restore_helper_->tab_restore_service()->IsLoaded());
@@ -254,7 +239,9 @@ app_list::AppListViewDelegate*
// Shell will own the created delegate, and the delegate will own
// the controller.
Profile* profile = ProfileManager::GetDefaultProfileOrOffTheRecord();
- return new AppListViewDelegate(new AppListControllerDelegateAsh(), profile);
+ return new AppListViewDelegate(
+ scoped_ptr<AppListControllerDelegate>(new AppListControllerDelegateAsh()),
+ profile);
}
ash::LauncherDelegate* ChromeShellDelegate::CreateLauncherDelegate(
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.h b/chrome/browser/ui/ash/chrome_shell_delegate.h
index 0675acdb36..804d1c0770 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate.h
+++ b/chrome/browser/ui/ash/chrome_shell_delegate.h
@@ -45,7 +45,6 @@ class ChromeShellDelegate : public ash::ShellDelegate,
virtual void NewTab() OVERRIDE;
virtual void NewWindow(bool is_incognito) OVERRIDE;
virtual void ToggleFullscreen() OVERRIDE;
- virtual void ToggleMaximized() OVERRIDE;
virtual void OpenFileManager() OVERRIDE;
virtual void OpenCrosh() OVERRIDE;
virtual void RestoreTab() OVERRIDE;
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate_browsertest.cc b/chrome/browser/ui/ash/chrome_shell_delegate_browsertest.cc
index 892021730a..1caabc8501 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate_browsertest.cc
+++ b/chrome/browser/ui/ash/chrome_shell_delegate_browsertest.cc
@@ -6,6 +6,7 @@
#include "apps/shell_window.h"
#include "apps/ui/native_app_window.h"
+#include "ash/accelerators/accelerator_commands.h"
#include "ash/ash_switches.h"
#include "ash/shell.h"
#include "ash/shell_delegate.h"
@@ -39,6 +40,9 @@ bool IsInImmersiveFullscreen(BrowserWindow* browser_window) {
typedef InProcessBrowserTest ChromeShellDelegateBrowserTest;
+// TODO(oshima): Move these tests to ash once ToggleFullscreen is moved
+// to ash. crbug.com/309837.
+
// Confirm that toggling window miximized works properly
IN_PROC_BROWSER_TEST_F(ChromeShellDelegateBrowserTest, ToggleMaximized) {
ash::ShellDelegate* shell_delegate = ash::Shell::GetInstance()->delegate();
@@ -46,23 +50,23 @@ IN_PROC_BROWSER_TEST_F(ChromeShellDelegateBrowserTest, ToggleMaximized) {
ash::wm::WindowState* window_state = ash::wm::GetActiveWindowState();
ASSERT_TRUE(window_state);
- // When not in fullscreen, ShellDelegate::ToggleMaximized toggles Maximized.
+ // When not in fullscreen, accelerators::ToggleMaximized toggles Maximized.
EXPECT_FALSE(window_state->IsMaximized());
- shell_delegate->ToggleMaximized();
+ ash::accelerators::ToggleMaximized();
EXPECT_TRUE(window_state->IsMaximized());
- shell_delegate->ToggleMaximized();
+ ash::accelerators::ToggleMaximized();
EXPECT_FALSE(window_state->IsMaximized());
- // When in fullscreen ShellDelegate::ToggleMaximized gets out of fullscreen.
+ // When in fullscreen accelerators::ToggleMaximized gets out of fullscreen.
EXPECT_FALSE(window_state->IsFullscreen());
Browser* browser = chrome::FindBrowserWithWindow(window_state->window());
ASSERT_TRUE(browser);
chrome::ToggleFullscreenMode(browser);
EXPECT_TRUE(window_state->IsFullscreen());
- shell_delegate->ToggleMaximized();
+ ash::accelerators::ToggleMaximized();
EXPECT_FALSE(window_state->IsFullscreen());
EXPECT_FALSE(window_state->IsMaximized());
- shell_delegate->ToggleMaximized();
+ ash::accelerators::ToggleMaximized();
EXPECT_FALSE(window_state->IsFullscreen());
EXPECT_TRUE(window_state->IsMaximized());
}
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc b/chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc
index 0c37d2a6f3..2c5be45818 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc
+++ b/chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc
@@ -89,7 +89,11 @@ void ChromeShellDelegate::OpenFileManager() {
service->GetInstalledExtension(kFileManagerAppId);
// event_flags = 0 means this invokes the same behavior as the launcher
// item is clicked without any keyboard modifiers.
- OpenApplication(AppLaunchParams(profile, extension, 0 /* event_flags */));
+ OpenApplication(AppLaunchParams(
+ profile,
+ extension,
+ 0 /* event_flags */,
+ chrome::HOST_DESKTOP_TYPE_ASH));
} else {
// Activate the existing window.
list.front()->GetBaseWindow()->Activate();
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
index 4b7937b0f1..780c3b529d 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
@@ -573,7 +573,11 @@ void ChromeLauncherController::LaunchApp(const std::string& app_id,
return;
}
- AppLaunchParams params(GetProfileForNewWindows(), extension, event_flags);
+ AppLaunchParams params(
+ GetProfileForNewWindows(),
+ extension,
+ event_flags,
+ chrome::HOST_DESKTOP_TYPE_ASH);
if (source != ash::LAUNCH_FROM_UNKNOWN &&
app_id == extension_misc::kWebStoreAppId) {
// Get the corresponding source string.
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
index 99d30de2b2..c9f37ca00a 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
@@ -12,11 +12,11 @@
#include "ash/launcher/launcher.h"
#include "ash/launcher/launcher_button.h"
#include "ash/launcher/launcher_model.h"
-#include "ash/launcher/launcher_view.h"
#include "ash/shelf/shelf_util.h"
+#include "ash/shelf/shelf_view.h"
#include "ash/shell.h"
#include "ash/test/launcher_test_api.h"
-#include "ash/test/launcher_view_test_api.h"
+#include "ash/test/shelf_view_test_api.h"
#include "ash/test/shell_test_api.h"
#include "ash/wm/window_state.h"
#include "ash/wm/window_util.h"
@@ -50,6 +50,7 @@
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/web_contents.h"
+#include "content/public/test/browser_test_utils.h"
#include "extensions/common/switches.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/app_list/views/apps_grid_view.h"
@@ -219,7 +220,7 @@ class LauncherAppBrowserTest : public ExtensionBrowserTest {
ExtensionService* service = extensions::ExtensionSystem::Get(
profile())->extension_service();
const Extension* extension =
- service->GetExtensionById(last_loaded_extension_id_, false);
+ service->GetExtensionById(last_loaded_extension_id(), false);
EXPECT_TRUE(extension);
OpenApplication(AppLaunchParams(profile(),
@@ -236,7 +237,7 @@ class LauncherAppBrowserTest : public ExtensionBrowserTest {
// First get app_id.
const Extension* extension =
- service->GetExtensionById(last_loaded_extension_id_, false);
+ service->GetExtensionById(last_loaded_extension_id(), false);
const std::string app_id = extension->id();
// Then create a shortcut.
@@ -277,7 +278,7 @@ class LauncherAppBrowserTest : public ExtensionBrowserTest {
// Try to rip off |item_index|.
void RipOffItemIndex(int index,
aura::test::EventGenerator* generator,
- ash::test::LauncherViewTestAPI* test,
+ ash::test::ShelfViewTestAPI* test,
RipOffCommand command) {
ash::internal::LauncherButton* button = test->GetButton(index);
gfx::Point start_point = button->GetBoundsInScreen().CenterPoint();
@@ -848,11 +849,9 @@ IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, LaunchPinned) {
EXPECT_EQ(++tab_count, tab_strip->count());
EXPECT_EQ(ash::STATUS_ACTIVE, (*model_->ItemByID(shortcut_id)).status);
WebContents* tab = tab_strip->GetActiveWebContents();
- content::WindowedNotificationObserver close_observer(
- content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
- content::Source<WebContents>(tab));
+ content::WebContentsDestroyedWatcher destroyed_watcher(tab);
browser()->tab_strip_model()->CloseSelectedTabs();
- close_observer.Wait();
+ destroyed_watcher.Wait();
EXPECT_EQ(--tab_count, tab_strip->count());
EXPECT_EQ(ash::STATUS_CLOSED, (*model_->ItemByID(shortcut_id)).status);
}
@@ -867,11 +866,9 @@ IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, LaunchUnpinned) {
ash::LauncherID shortcut_id = CreateShortcut("app1");
EXPECT_EQ(ash::STATUS_ACTIVE, (*model_->ItemByID(shortcut_id)).status);
WebContents* tab = tab_strip->GetActiveWebContents();
- content::WindowedNotificationObserver close_observer(
- content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
- content::Source<WebContents>(tab));
+ content::WebContentsDestroyedWatcher destroyed_watcher(tab);
browser()->tab_strip_model()->CloseSelectedTabs();
- close_observer.Wait();
+ destroyed_watcher.Wait();
EXPECT_EQ(--tab_count, tab_strip->count());
EXPECT_EQ(ash::STATUS_CLOSED, (*model_->ItemByID(shortcut_id)).status);
}
@@ -884,7 +881,7 @@ IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, LaunchInBackground) {
LoadAndLaunchExtension("app1", extension_misc::LAUNCH_TAB,
NEW_BACKGROUND_TAB);
EXPECT_EQ(++tab_count, tab_strip->count());
- ChromeLauncherController::instance()->LaunchApp(last_loaded_extension_id_,
+ ChromeLauncherController::instance()->LaunchApp(last_loaded_extension_id(),
ash::LAUNCH_FROM_UNKNOWN,
0);
}
@@ -1548,8 +1545,8 @@ IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, DragAndDrop) {
// Get a number of interfaces we need.
aura::test::EventGenerator generator(
ash::Shell::GetPrimaryRootWindow(), gfx::Point());
- ash::test::LauncherViewTestAPI test(
- ash::test::LauncherTestAPI(launcher_).launcher_view());
+ ash::test::ShelfViewTestAPI test(
+ ash::test::LauncherTestAPI(launcher_).shelf_view());
AppListService* service = AppListService::Get();
// There should be two items in our launcher by this time.
@@ -1558,7 +1555,7 @@ IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, DragAndDrop) {
// Open the app list menu and check that the drag and drop host was set.
gfx::Rect app_list_bounds =
- test.launcher_view()->GetAppListButtonView()->GetBoundsInScreen();
+ test.shelf_view()->GetAppListButtonView()->GetBoundsInScreen();
generator.MoveMouseTo(app_list_bounds.CenterPoint().x(),
app_list_bounds.CenterPoint().y());
base::MessageLoop::current()->RunUntilIdle();
@@ -1590,7 +1587,7 @@ IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, DragAndDrop) {
// Drag the item into the launcher and check that a new item gets created.
const views::ViewModel* vm_launcher =
- test.launcher_view()->view_model_for_test();
+ test.shelf_view()->view_model_for_test();
views::View* launcher1 = vm_launcher->view_at(1);
gfx::Rect bounds_launcher_1 = launcher1->GetBoundsInScreen();
generator.MoveMouseTo(bounds_launcher_1.CenterPoint().x(),
@@ -1667,8 +1664,8 @@ IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, DragAndDrop) {
IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, DragOffShelf) {
aura::test::EventGenerator generator(
ash::Shell::GetPrimaryRootWindow(), gfx::Point());
- ash::test::LauncherViewTestAPI test(
- ash::test::LauncherTestAPI(launcher_).launcher_view());
+ ash::test::ShelfViewTestAPI test(
+ ash::test::LauncherTestAPI(launcher_).shelf_view());
// Create a known application and check that we have 3 items in the launcher.
CreateShortcut("app1");
@@ -1765,8 +1762,8 @@ IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, ClickItem) {
// Get a number of interfaces we need.
aura::test::EventGenerator generator(
ash::Shell::GetPrimaryRootWindow(), gfx::Point());
- ash::test::LauncherViewTestAPI test(
- ash::test::LauncherTestAPI(launcher_).launcher_view());
+ ash::test::ShelfViewTestAPI test(
+ ash::test::LauncherTestAPI(launcher_).shelf_view());
AppListService* service = AppListService::Get();
// There should be two items in our launcher by this time.
EXPECT_EQ(2, model_->item_count());
@@ -1774,7 +1771,7 @@ IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, ClickItem) {
// Open the app list menu and check that the drag and drop host was set.
gfx::Rect app_list_bounds =
- test.launcher_view()->GetAppListButtonView()->GetBoundsInScreen();
+ test.shelf_view()->GetAppListButtonView()->GetBoundsInScreen();
generator.MoveMouseTo(app_list_bounds.CenterPoint().x(),
app_list_bounds.CenterPoint().y());
generator.ClickLeftButton();
@@ -1866,8 +1863,8 @@ IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, OverflowBubble) {
// No overflow yet.
EXPECT_FALSE(launcher_->IsShowingOverflowBubble());
- ash::test::LauncherViewTestAPI test(
- ash::test::LauncherTestAPI(launcher_).launcher_view());
+ ash::test::ShelfViewTestAPI test(
+ ash::test::LauncherTestAPI(launcher_).shelf_view());
int items_added = 0;
while (!test.IsOverflowButtonVisible()) {
diff --git a/chrome/browser/ui/ash/multi_user_window_manager.cc b/chrome/browser/ui/ash/multi_user_window_manager.cc
index a26c92f670..0a58841505 100644
--- a/chrome/browser/ui/ash/multi_user_window_manager.cc
+++ b/chrome/browser/ui/ash/multi_user_window_manager.cc
@@ -28,13 +28,6 @@
namespace {
chrome::MultiUserWindowManager* g_instance = NULL;
-
-// Get the user id from a given profile.
-std::string GetUserIDFromProfile(Profile* profile) {
- return gaia::CanonicalizeEmail(gaia::SanitizeEmail(
- profile->GetOriginalProfile()->GetProfileName()));
-}
-
} // namespace
namespace chrome {
@@ -84,6 +77,12 @@ void MultiUserWindowManager::DeleteInstance() {
g_instance = NULL;
}
+// static
+std::string MultiUserWindowManager::GetUserIDFromProfile(Profile* profile) {
+ return gaia::CanonicalizeEmail(gaia::SanitizeEmail(
+ profile->GetOriginalProfile()->GetProfileName()));
+}
+
void MultiUserWindowManager::SetWindowOwner(aura::Window* window,
const std::string& user_id) {
// Make sure the window is valid and there was no owner yet.
diff --git a/chrome/browser/ui/ash/multi_user_window_manager.h b/chrome/browser/ui/ash/multi_user_window_manager.h
index bff9762e26..fea8fd0cbe 100644
--- a/chrome/browser/ui/ash/multi_user_window_manager.h
+++ b/chrome/browser/ui/ash/multi_user_window_manager.h
@@ -62,6 +62,9 @@ class MultiUserWindowManager : public ash::SessionStateObserver,
// Removes the instance.
static void DeleteInstance();
+ // Get the user id from a given profile.
+ static std::string GetUserIDFromProfile(Profile* profile);
+
// Assigns an owner to a passed window. Note that this window's parent should
// be a direct child of the root window.
// A user switch will automatically change the visibility - and - if the
diff --git a/chrome/browser/ui/ash/multi_user_window_manager_unittest.cc b/chrome/browser/ui/ash/multi_user_window_manager_unittest.cc
index d400c7bca6..02c60363cc 100644
--- a/chrome/browser/ui/ash/multi_user_window_manager_unittest.cc
+++ b/chrome/browser/ui/ash/multi_user_window_manager_unittest.cc
@@ -20,9 +20,6 @@
namespace ash {
namespace test {
-// This many test windows will get created.
-const int kNumberOfTestWindows = 5;
-
// A test class for preparing the chrome::MultiUserWindowManager. It creates
// various windows and instantiates the chrome::MultiUserWindowManager.
class MultiUserWindowManagerTest : public AshTestBase {
diff --git a/chrome/browser/ui/ash/session_state_delegate_chromeos.cc b/chrome/browser/ui/ash/session_state_delegate_chromeos.cc
index b4a7ccddf7..e1ff42ba58 100644
--- a/chrome/browser/ui/ash/session_state_delegate_chromeos.cc
+++ b/chrome/browser/ui/ash/session_state_delegate_chromeos.cc
@@ -90,6 +90,14 @@ const std::string SessionStateDelegateChromeos::GetUserEmail(
GetLRULoggedInUsers()[index]->display_email();
}
+const std::string SessionStateDelegateChromeos::GetUserID(
+ ash::MultiProfileIndex index) const {
+ DCHECK_LT(index, NumberOfLoggedInUsers());
+ return gaia::CanonicalizeEmail(gaia::SanitizeEmail(
+ chromeos::UserManager::Get()->
+ GetLRULoggedInUsers()[index]->email()));
+}
+
const gfx::ImageSkia& SessionStateDelegateChromeos::GetUserImage(
ash::MultiProfileIndex index) const {
DCHECK_LT(index, NumberOfLoggedInUsers());
@@ -107,11 +115,11 @@ void SessionStateDelegateChromeos::GetLoggedInUsers(ash::UserIdList* users) {
}
void SessionStateDelegateChromeos::SwitchActiveUser(
- const std::string& user_email) {
+ const std::string& user_id) {
// Disallow switching to an already active user since that might crash.
- // Transform the |user_email| into a |user_id| for comparison & switching.
- std::string user_id =
- gaia::CanonicalizeEmail(gaia::SanitizeEmail(user_email));
+ // Also check that we got a user id and not an email address.
+ DCHECK_EQ(user_id,
+ gaia::CanonicalizeEmail(gaia::SanitizeEmail(user_id)));
if (user_id == chromeos::UserManager::Get()->GetActiveUser()->email())
return;
chromeos::UserManager::Get()->SwitchActiveUser(user_id);
diff --git a/chrome/browser/ui/ash/session_state_delegate_chromeos.h b/chrome/browser/ui/ash/session_state_delegate_chromeos.h
index 69936a42f1..24a7964113 100644
--- a/chrome/browser/ui/ash/session_state_delegate_chromeos.h
+++ b/chrome/browser/ui/ash/session_state_delegate_chromeos.h
@@ -36,10 +36,12 @@ class SessionStateDelegateChromeos
ash::MultiProfileIndex index) const OVERRIDE;
virtual const std::string GetUserEmail(
ash::MultiProfileIndex index) const OVERRIDE;
+ virtual const std::string GetUserID(
+ ash::MultiProfileIndex index) const OVERRIDE;
virtual const gfx::ImageSkia& GetUserImage(
ash::MultiProfileIndex index) const OVERRIDE;
virtual void GetLoggedInUsers(ash::UserIdList* users) OVERRIDE;
- virtual void SwitchActiveUser(const std::string& user_email) OVERRIDE;
+ virtual void SwitchActiveUser(const std::string& user_id) OVERRIDE;
virtual void SwitchActiveUserToNext() OVERRIDE;
virtual void AddSessionStateObserver(
ash::SessionStateObserver* observer) OVERRIDE;
diff --git a/chrome/browser/ui/ash/session_state_delegate_views.cc b/chrome/browser/ui/ash/session_state_delegate_views.cc
index 9933890a18..2998204199 100644
--- a/chrome/browser/ui/ash/session_state_delegate_views.cc
+++ b/chrome/browser/ui/ash/session_state_delegate_views.cc
@@ -66,6 +66,12 @@ const std::string SessionStateDelegate::GetUserEmail(
return "";
}
+const std::string SessionStateDelegate::GetUserID(
+ ash::MultiProfileIndex index) const {
+ NOTIMPLEMENTED();
+ return "";
+}
+
const gfx::ImageSkia& SessionStateDelegate::GetUserImage(
ash::MultiProfileIndex index) const {
NOTIMPLEMENTED();
@@ -77,7 +83,7 @@ void SessionStateDelegate::GetLoggedInUsers(ash::UserIdList* users) {
NOTIMPLEMENTED();
}
-void SessionStateDelegate::SwitchActiveUser(const std::string& user_email) {
+void SessionStateDelegate::SwitchActiveUser(const std::string& user_id) {
NOTIMPLEMENTED();
}
diff --git a/chrome/browser/ui/ash/session_state_delegate_views.h b/chrome/browser/ui/ash/session_state_delegate_views.h
index 482d5d1997..238c1b487a 100644
--- a/chrome/browser/ui/ash/session_state_delegate_views.h
+++ b/chrome/browser/ui/ash/session_state_delegate_views.h
@@ -33,10 +33,12 @@ class SessionStateDelegate : public ash::SessionStateDelegate {
ash::MultiProfileIndex index) const OVERRIDE;
virtual const std::string GetUserEmail(
ash::MultiProfileIndex index) const OVERRIDE;
+ virtual const std::string GetUserID(
+ ash::MultiProfileIndex index) const OVERRIDE;
virtual const gfx::ImageSkia& GetUserImage(
ash::MultiProfileIndex index) const OVERRIDE;
virtual void GetLoggedInUsers(ash::UserIdList* users) OVERRIDE;
- virtual void SwitchActiveUser(const std::string& user_email) OVERRIDE;
+ virtual void SwitchActiveUser(const std::string& user_id) OVERRIDE;
virtual void SwitchActiveUserToNext() OVERRIDE;
virtual void AddSessionStateObserver(
ash::SessionStateObserver* observer) OVERRIDE;
diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_browsertest.cc b/chrome/browser/ui/autofill/autofill_dialog_controller_browsertest.cc
index 2fbc3d7ce6..36bfd41b82 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_controller_browsertest.cc
+++ b/chrome/browser/ui/autofill/autofill_dialog_controller_browsertest.cc
@@ -15,11 +15,13 @@
#include "chrome/browser/ui/autofill/autofill_dialog_view.h"
#include "chrome/browser/ui/autofill/data_model_wrapper.h"
#include "chrome/browser/ui/autofill/tab_autofill_manager_delegate.h"
+#include "chrome/browser/ui/autofill/test_generated_credit_card_bubble_controller.h"
#include "chrome/browser/ui/autofill/testable_autofill_dialog_view.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
+#include "components/autofill/content/browser/risk/proto/fingerprint.pb.h"
#include "components/autofill/content/browser/wallet/mock_wallet_client.h"
#include "components/autofill/content/browser/wallet/wallet_test_util.h"
#include "components/autofill/core/browser/autofill_common_test.h"
@@ -42,6 +44,8 @@ namespace autofill {
namespace {
+using testing::_;
+
void MockCallback(const FormStructure*) {}
class MockAutofillMetrics : public AutofillMetrics {
@@ -74,10 +78,11 @@ class MockAutofillMetrics : public AutofillMetrics {
class TestAutofillDialogController : public AutofillDialogControllerImpl {
public:
- TestAutofillDialogController(content::WebContents* contents,
- const FormData& form_data,
- const AutofillMetrics& metric_logger,
- scoped_refptr<content::MessageLoopRunner> runner)
+ TestAutofillDialogController(
+ content::WebContents* contents,
+ const FormData& form_data,
+ const AutofillMetrics& metric_logger,
+ scoped_refptr<content::MessageLoopRunner> runner)
: AutofillDialogControllerImpl(contents,
form_data,
form_data.origin,
@@ -121,10 +126,16 @@ class TestAutofillDialogController : public AutofillDialogControllerImpl {
return false;
}
+ void ForceFinishSubmit() {
+ DoFinishSubmit();
+ }
+
// Increase visibility for testing.
using AutofillDialogControllerImpl::view;
using AutofillDialogControllerImpl::input_showing_popup;
+ MOCK_METHOD0(LoadRiskFingerprintData, void());
+
virtual std::vector<DialogNotification> CurrentNotifications() OVERRIDE {
return notifications_;
}
@@ -139,6 +150,8 @@ class TestAutofillDialogController : public AutofillDialogControllerImpl {
using AutofillDialogControllerImpl::IsEditingExistingData;
using AutofillDialogControllerImpl::IsManuallyEditingSection;
+ using AutofillDialogControllerImpl::IsSubmitPausedOn;
+ using AutofillDialogControllerImpl::OnDidLoadRiskFingerprintData;
void set_use_validation(bool use_validation) {
use_validation_ = use_validation;
@@ -148,6 +161,10 @@ class TestAutofillDialogController : public AutofillDialogControllerImpl {
return weak_ptr_factory_.GetWeakPtr();
}
+ wallet::MockWalletClient* GetTestingWalletClient() {
+ return &mock_wallet_client_;
+ }
+
protected:
virtual PersonalDataManager* GetManager() OVERRIDE {
return &test_manager_;
@@ -212,6 +229,11 @@ class AutofillDialogControllerTest : public InProcessBrowserTest {
field.autocomplete_attribute = "shipping tel";
form.fields.push_back(field);
+ test_generated_bubble_controller_ =
+ new testing::NiceMock<TestGeneratedCreditCardBubbleController>(
+ GetActiveWebContents());
+ ASSERT_TRUE(test_generated_bubble_controller_->IsInstalled());
+
message_loop_runner_ = new content::MessageLoopRunner;
controller_ = new TestAutofillDialogController(
GetActiveWebContents(),
@@ -303,15 +325,23 @@ class AutofillDialogControllerTest : public InProcessBrowserTest {
WaitForWebDB();
}
+ TestGeneratedCreditCardBubbleController* test_generated_bubble_controller() {
+ return test_generated_bubble_controller_;
+ }
+
private:
void WaitForWebDB() {
content::RunAllPendingInMessageLoop(content::BrowserThread::DB);
}
- MockAutofillMetrics metric_logger_;
+ testing::NiceMock<MockAutofillMetrics> metric_logger_;
TestAutofillDialogController* controller_; // Weak reference.
scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
scoped_ptr<content::DOMMessageQueue> dom_message_queue_;
+
+ // Weak; owned by the active web contents.
+ TestGeneratedCreditCardBubbleController* test_generated_bubble_controller_;
+
DISALLOW_COPY_AND_ASSIGN(AutofillDialogControllerTest);
};
@@ -583,49 +613,6 @@ IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, ShouldShowErrorBubble) {
EXPECT_TRUE(controller()->ShouldShowErrorBubble());
}
-// Tests that credit card number is disabled while editing a Wallet instrument.
-IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, WalletCreditCardDisabled) {
- std::vector<std::string> usernames;
- usernames.push_back("user@example.com");
- controller()->OnUserNameFetchSuccess(usernames);
- controller()->OnDidFetchWalletCookieValue(std::string());
-
- scoped_ptr<wallet::WalletItems> wallet_items =
- wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
- // An expired card will be forced into edit mode.
- wallet_items->AddInstrument(wallet::GetTestMaskedInstrumentWithDetails(
- "instrument_id",
- wallet::GetTestAddress(),
- wallet::WalletItems::MaskedInstrument::VISA,
- wallet::WalletItems::MaskedInstrument::EXPIRED));
- controller()->OnDidGetWalletItems(wallet_items.Pass());
-
- const DetailInputs& edit_inputs =
- controller()->RequestedFieldsForSection(SECTION_CC_BILLING);
- size_t i;
- for (i = 0; i < edit_inputs.size(); ++i) {
- if (edit_inputs[i].type == CREDIT_CARD_NUMBER) {
- EXPECT_FALSE(edit_inputs[i].editable);
- break;
- }
- }
- ASSERT_LT(i, edit_inputs.size());
-
- // Select "Add new billing info..." while using Wallet.
- ui::MenuModel* model = controller()->MenuModelForSection(SECTION_CC_BILLING);
- model->ActivatedAt(model->GetItemCount() - 2);
-
- const DetailInputs& add_inputs =
- controller()->RequestedFieldsForSection(SECTION_CC_BILLING);
- for (i = 0; i < add_inputs.size(); ++i) {
- if (add_inputs[i].type == CREDIT_CARD_NUMBER) {
- EXPECT_TRUE(add_inputs[i].editable);
- break;
- }
- }
- ASSERT_LT(i, add_inputs.size());
-}
-
// Ensure that expired cards trigger invalid suggestions.
IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, ExpiredCard) {
CreditCard verified_card(test::GetCreditCard());
@@ -819,4 +806,58 @@ IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, MAYBE_PreservedSections) {
}
#endif // defined(TOOLKIT_VIEWS) || defined(OS_MACOSX)
+// TODO(groby): figure out if the CVC challenge code actually works on Mac.
+#if !defined(OS_MACOSX)
+IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest,
+ GeneratedCardLastFourAfterVerifyCvv) {
+ std::vector<std::string> usernames;
+ usernames.push_back("user@example.com");
+ controller()->OnUserNameFetchSuccess(usernames);
+ controller()->OnDidFetchWalletCookieValue(std::string());
+
+ scoped_ptr<wallet::WalletItems> wallet_items =
+ wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
+ wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
+ wallet_items->AddAddress(wallet::GetTestShippingAddress());
+
+ base::string16 last_four =
+ wallet_items->instruments()[0]->TypeAndLastFourDigits();
+ controller()->OnDidGetWalletItems(wallet_items.Pass());
+
+ EXPECT_CALL(*controller(), LoadRiskFingerprintData());
+ controller()->OnAccept();
+
+ EXPECT_CALL(*controller()->GetTestingWalletClient(), GetFullWallet(_));
+ scoped_ptr<risk::Fingerprint> fingerprint(new risk::Fingerprint());
+ fingerprint->mutable_machine_characteristics()->mutable_screen_size()->
+ set_width(1024);
+ controller()->OnDidLoadRiskFingerprintData(fingerprint.Pass());
+
+ controller()->OnDidGetFullWallet(
+ wallet::GetTestFullWalletWithRequiredActions(
+ std::vector<wallet::RequiredAction>(1, wallet::VERIFY_CVV)));
+
+ ASSERT_TRUE(controller()->IsSubmitPausedOn(wallet::VERIFY_CVV));
+
+ std::string fake_cvc("123");
+ TestableAutofillDialogView* test_view = controller()->GetTestableView();
+ test_view->SetTextContentsOfSuggestionInput(SECTION_CC_BILLING,
+ ASCIIToUTF16(fake_cvc));
+
+ EXPECT_CALL(*controller()->GetTestingWalletClient(),
+ AuthenticateInstrument(_, fake_cvc));
+ controller()->OnAccept();
+
+ EXPECT_CALL(*controller()->GetTestingWalletClient(), GetFullWallet(_));
+ controller()->OnDidAuthenticateInstrument(true);
+ controller()->OnDidGetFullWallet(wallet::GetTestFullWallet());
+ controller()->ForceFinishSubmit();
+
+ RunMessageLoop();
+
+ EXPECT_EQ(1, test_generated_bubble_controller()->bubbles_shown());
+ EXPECT_EQ(last_four, test_generated_bubble_controller()->backing_card_name());
+}
+#endif // !defined(OS_MACOSX)
+
} // namespace autofill
diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
index ff9d063cf7..384a8d7f09 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
+++ b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
@@ -249,7 +249,6 @@ string16 GetValueForType(const DetailOutputMap& output,
if (it->first->type == type)
return it->second;
}
- NOTREACHED();
return string16();
}
@@ -935,11 +934,6 @@ bool AutofillDialogControllerImpl::SectionIsActive(DialogSection section)
return section != SECTION_CC_BILLING;
}
-bool AutofillDialogControllerImpl::IsSubmitPausedOn(
- wallet::RequiredAction required_action) const {
- return full_wallet_ && full_wallet_->HasRequiredAction(required_action);
-}
-
void AutofillDialogControllerImpl::GetWalletItems() {
ScopedViewUpdates updates(view_.get());
@@ -1151,10 +1145,6 @@ void AutofillDialogControllerImpl::ShowEditUiIfBadSuggestion(
DetailInputs* inputs = MutableRequestedFieldsForSection(section);
if (wrapper && IsEditingExistingData(section))
wrapper->FillInputs(inputs);
-
- for (DetailInputs::iterator it = inputs->begin(); it != inputs->end(); ++it) {
- it->editable = InputIsEditable(*it, section);
- }
}
bool AutofillDialogControllerImpl::InputWasEdited(ServerFieldType type,
@@ -1561,31 +1551,6 @@ gfx::Image AutofillDialogControllerImpl::ExtraSuggestionIconForSection(
model->GetInfo(AutofillType(CREDIT_CARD_TYPE)));
}
-// TODO(groby): Remove this deprecated method after Mac starts using
-// IconsForFields. http://crbug.com/292876
-gfx::Image AutofillDialogControllerImpl::IconForField(
- ServerFieldType type, const string16& user_input) const {
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- if (type == CREDIT_CARD_VERIFICATION_CODE)
- return rb.GetImageNamed(IDR_CREDIT_CARD_CVC_HINT);
-
- if (type == CREDIT_CARD_NUMBER) {
- const int input_card_idr = CreditCard::IconResourceId(
- CreditCard::GetCreditCardType(user_input));
- if (input_card_idr != IDR_AUTOFILL_CC_GENERIC)
- return rb.GetImageNamed(input_card_idr);
-
- // When the credit card type is unknown, no image should be shown. However,
- // to simplify the view code on Mac, save space for the credit card image by
- // returning a transparent image of the appropriate size.
- gfx::ImageSkia image = *rb.GetImageSkiaNamed(input_card_idr);
- return
- gfx::Image(gfx::ImageSkiaOperations::CreateTransparentImage(image, 0));
- }
-
- return gfx::Image();
-}
-
FieldIconMap AutofillDialogControllerImpl::IconsForFields(
const FieldValueMap& user_inputs) const {
FieldIconMap result;
@@ -1622,6 +1587,41 @@ string16 AutofillDialogControllerImpl::TooltipForField(ServerFieldType type)
return string16();
}
+bool AutofillDialogControllerImpl::InputIsEditable(
+ const DetailInput& input,
+ DialogSection section) {
+ if (section != SECTION_CC_BILLING)
+ return true;
+
+ if (input.type == CREDIT_CARD_NUMBER)
+ return !IsEditingExistingData(section);
+
+ // For CVC, only require (allow) input if the user has edited some other
+ // aspect of the card.
+ if (input.type == CREDIT_CARD_VERIFICATION_CODE &&
+ IsEditingExistingData(section)) {
+ DetailOutputMap output;
+ view_->GetUserInput(section, &output);
+ WalletInstrumentWrapper wrapper(ActiveInstrument());
+
+ for (DetailOutputMap::iterator iter = output.begin(); iter != output.end();
+ ++iter) {
+ if (iter->first->type == input.type)
+ continue;
+
+ AutofillType type(iter->first->type);
+ if (type.group() == CREDIT_CARD &&
+ iter->second != wrapper.GetInfo(type)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ return true;
+}
+
// TODO(groby): Add more tests.
string16 AutofillDialogControllerImpl::InputValidityMessage(
DialogSection section,
@@ -2052,8 +2052,26 @@ bool AutofillDialogControllerImpl::OnAccept() {
// This must come before SetIsSubmitting().
if (IsPayingWithWallet()) {
- submitted_cardholder_name_ =
- GetValueFromSection(SECTION_CC_BILLING, NAME_FULL);
+ // In the VERIFY_CVV case, hold onto the previously submitted cardholder
+ // name.
+ if (!IsSubmitPausedOn(wallet::VERIFY_CVV)) {
+ submitted_cardholder_name_ =
+ GetValueFromSection(SECTION_CC_BILLING, NAME_BILLING_FULL);
+
+ // Snag the last four digits of the backing card now as it could be wiped
+ // out if a CVC challenge happens.
+ if (ActiveInstrument()) {
+ backing_card_last_four_ = ActiveInstrument()->TypeAndLastFourDigits();
+ } else {
+ DetailOutputMap output;
+ view_->GetUserInput(SECTION_CC_BILLING, &output);
+ CreditCard card;
+ GetBillingInfoFromOutputs(output, &card, NULL, NULL);
+ backing_card_last_four_ = card.TypeAndLastFourDigits();
+ }
+ }
+ DCHECK(!submitted_cardholder_name_.empty());
+ DCHECK(!backing_card_last_four_.empty());
}
SetIsSubmitting(true);
@@ -2258,21 +2276,20 @@ void AutofillDialogControllerImpl::OnDidGetFullWallet(
choose_another_instrument_or_address_ = true;
SetIsSubmitting(false);
GetWalletItems();
- view_->UpdateNotificationArea();
- view_->UpdateButtonStrip();
- view_->UpdateOverlay();
break;
case wallet::VERIFY_CVV:
SuggestionsUpdated();
- view_->UpdateButtonStrip();
- view_->UpdateNotificationArea();
break;
default:
DisableWallet(wallet::WalletClient::UNKNOWN_ERROR);
- break;
+ return;
}
+
+ view_->UpdateNotificationArea();
+ view_->UpdateButtonStrip();
+ view_->UpdateOverlay();
}
void AutofillDialogControllerImpl::OnPassiveSigninSuccess(
@@ -2434,6 +2451,11 @@ bool AutofillDialogControllerImpl::TransmissionWillBeSecure() const {
return source_url_.SchemeIs(content::kHttpsScheme);
}
+bool AutofillDialogControllerImpl::IsSubmitPausedOn(
+ wallet::RequiredAction required_action) const {
+ return full_wallet_ && full_wallet_->HasRequiredAction(required_action);
+}
+
void AutofillDialogControllerImpl::ShowNewCreditCardBubble(
scoped_ptr<CreditCard> new_card,
scoped_ptr<AutofillProfile> billing_profile) {
@@ -2884,13 +2906,7 @@ string16 AutofillDialogControllerImpl::GetValueFromSection(
DetailOutputMap output;
view_->GetUserInput(section, &output);
- for (DetailOutputMap::iterator iter = output.begin(); iter != output.end();
- ++iter) {
- if (iter->first->type == type)
- return iter->second;
- }
-
- return string16();
+ return GetValueForType(output, type);
}
SuggestionsMenuModel* AutofillDialogControllerImpl::
@@ -2985,18 +3001,6 @@ base::string16 AutofillDialogControllerImpl::CreditCardNumberValidityMessage(
return base::string16();
}
-bool AutofillDialogControllerImpl::InputIsEditable(
- const DetailInput& input,
- DialogSection section) const {
- if (input.type != CREDIT_CARD_NUMBER || !IsPayingWithWallet())
- return true;
-
- if (IsEditingExistingData(section))
- return false;
-
- return true;
-}
-
bool AutofillDialogControllerImpl::AllSectionsAreValid() {
for (size_t section = SECTION_MIN; section <= SECTION_MAX; ++section) {
if (!SectionIsValid(static_cast<DialogSection>(section)))
@@ -3479,21 +3483,11 @@ void AutofillDialogControllerImpl::MaybeShowCreditCardBubble() {
if (!full_wallet_ || !full_wallet_->billing_address())
return;
- base::string16 backing_last_four;
- if (ActiveInstrument()) {
- backing_last_four = ActiveInstrument()->TypeAndLastFourDigits();
- } else {
- DetailOutputMap output;
- view_->GetUserInput(SECTION_CC_BILLING, &output);
- CreditCard card;
- GetBillingInfoFromOutputs(output, &card, NULL, NULL);
- backing_last_four = card.TypeAndLastFourDigits();
- }
#if !defined(OS_ANDROID)
GeneratedCreditCardBubbleController::Show(
web_contents(),
full_wallet_->TypeAndLastFourDigits(),
- backing_last_four);
+ backing_card_last_four_);
#endif
}
diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h
index ff432b2fb0..b320ed4bbf 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h
+++ b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h
@@ -131,14 +131,12 @@ class AutofillDialogControllerImpl : public AutofillDialogViewDelegate,
virtual string16 LabelForSection(DialogSection section) const OVERRIDE;
virtual SuggestionState SuggestionStateForSection(
DialogSection section) OVERRIDE;
- // TODO(groby): Remove this deprecated method after Mac starts using
- // IconsForFields. http://crbug.com/292876
- virtual gfx::Image IconForField(ServerFieldType type,
- const string16& user_input) const OVERRIDE;
virtual FieldIconMap IconsForFields(const FieldValueMap& user_inputs)
const OVERRIDE;
virtual bool FieldControlsIcons(ServerFieldType type) const OVERRIDE;
virtual string16 TooltipForField(ServerFieldType type) const OVERRIDE;
+ virtual bool InputIsEditable(const DetailInput& input, DialogSection section)
+ OVERRIDE;
virtual string16 InputValidityMessage(DialogSection section,
ServerFieldType type,
const string16& value) OVERRIDE;
@@ -285,6 +283,9 @@ class AutofillDialogControllerImpl : public AutofillDialogViewDelegate,
// to the requesting site.
virtual bool TransmissionWillBeSecure() const;
+ // Whether submission is currently waiting for |action| to be handled.
+ bool IsSubmitPausedOn(wallet::RequiredAction action) const;
+
// Shows a new credit card saved bubble and passes ownership of |new_card| and
// |billing_profile| to the bubble. Exposed for testing.
virtual void ShowNewCreditCardBubble(
@@ -463,9 +464,6 @@ class AutofillDialogControllerImpl : public AutofillDialogViewDelegate,
base::string16 CreditCardNumberValidityMessage(
const base::string16& number) const;
- // Whether a particular DetailInput in |section| should be edited or not.
- bool InputIsEditable(const DetailInput& input, DialogSection section) const;
-
// Whether all of the input fields currently showing in the dialog have valid
// contents. This validates only by checking "sure" messages, i.e. messages
// that would have been displayed to the user during editing, as opposed to
@@ -521,9 +519,6 @@ class AutofillDialogControllerImpl : public AutofillDialogViewDelegate,
void HandleSaveOrUpdateRequiredActions(
const std::vector<wallet::RequiredAction>& required_actions);
- // Whether submission is currently waiting for |action| to be handled.
- bool IsSubmitPausedOn(wallet::RequiredAction action) const;
-
// Shows a card generation overlay if necessary, then calls DoFinishSubmit.
void FinishSubmit();
@@ -733,6 +728,10 @@ class AutofillDialogControllerImpl : public AutofillDialogViewDelegate,
// saved. Never populated while incognito (as nothing's actually saved).
scoped_ptr<CreditCard> newly_saved_card_;
+ // The last four digits of the backing card used for the current run of the
+ // dialog. Only applies to Wallet and is populated on submit.
+ base::string16 backing_card_last_four_;
+
// The timer that delays enabling submit button for a short period of time on
// startup.
base::OneShotTimer<AutofillDialogControllerImpl> submit_button_delay_timer_;
diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc b/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc
index 799d7a2564..f0c23422dd 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc
+++ b/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc
@@ -12,13 +12,14 @@
#include "base/prefs/pref_service.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
#include "base/strings/utf_string_conversions.h"
#include "base/tuple.h"
#include "chrome/browser/ui/autofill/autofill_dialog_controller_impl.h"
#include "chrome/browser/ui/autofill/autofill_dialog_view.h"
#include "chrome/browser/ui/autofill/generated_credit_card_bubble_controller.h"
#include "chrome/browser/ui/autofill/mock_new_credit_card_bubble_controller.h"
-#include "chrome/browser/ui/autofill/test_generated_credit_card_bubble_view.h"
+#include "chrome/browser/ui/autofill/test_generated_credit_card_bubble_controller.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/render_messages.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
@@ -45,12 +46,12 @@
#include "ui/base/win/scoped_ole_initializer.h"
#endif
-using testing::_;
-
namespace autofill {
namespace {
+using testing::_;
+
const char kFakeEmail[] = "user@example.com";
const char kFakeFingerprintEncoded[] = "CgVaAwiACA==";
const char kEditedBillingAddress[] = "123 edited billing address";
@@ -113,14 +114,6 @@ scoped_ptr<wallet::WalletItems> CompleteAndValidWalletItems() {
return items.Pass();
}
-scoped_ptr<wallet::FullWallet> CreateFullWallet(const char* required_action) {
- base::DictionaryValue dict;
- scoped_ptr<base::ListValue> list(new base::ListValue());
- list->AppendString(required_action);
- dict.Set("required_action", list.release());
- return wallet::FullWallet::CreateFullWallet(dict);
-}
-
scoped_ptr<risk::Fingerprint> GetFakeFingerprint() {
scoped_ptr<risk::Fingerprint> fingerprint(new risk::Fingerprint());
// Add some data to the proto, else the encoded content is empty.
@@ -321,6 +314,7 @@ class TestAutofillDialogController
MOCK_METHOD0(LoadRiskFingerprintData, void());
using AutofillDialogControllerImpl::OnDidLoadRiskFingerprintData;
using AutofillDialogControllerImpl::IsEditingExistingData;
+ using AutofillDialogControllerImpl::IsSubmitPausedOn;
protected:
virtual PersonalDataManager* GetManager() OVERRIDE {
@@ -373,34 +367,6 @@ class TestAutofillDialogController
DISALLOW_COPY_AND_ASSIGN(TestAutofillDialogController);
};
-class TestGeneratedCreditCardBubbleController :
- public GeneratedCreditCardBubbleController {
- public:
- explicit TestGeneratedCreditCardBubbleController(
- content::WebContents* contents)
- : GeneratedCreditCardBubbleController(contents) {
- contents->SetUserData(UserDataKey(), this);
- CHECK_EQ(contents->GetUserData(UserDataKey()), this);
- }
-
- virtual ~TestGeneratedCreditCardBubbleController() {}
-
- MOCK_METHOD2(SetupAndShow, void(const base::string16& backing_card_name,
- const base::string16& fronting_card_name));
-
- protected:
- virtual base::WeakPtr<GeneratedCreditCardBubbleView> CreateBubble() OVERRIDE {
- return TestGeneratedCreditCardBubbleView::Create(GetWeakPtr());
- }
-
- virtual bool CanShow() const OVERRIDE {
- return true;
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(TestGeneratedCreditCardBubbleController);
-};
-
class AutofillDialogControllerTest : public ChromeRenderViewHostTestHarness {
protected:
AutofillDialogControllerTest(): form_structure_(NULL) {}
@@ -424,6 +390,8 @@ class AutofillDialogControllerTest : public ChromeRenderViewHostTestHarness {
test_generated_bubble_controller_ =
new testing::NiceMock<TestGeneratedCreditCardBubbleController>(
web_contents());
+ ASSERT_TRUE(test_generated_bubble_controller_->IsInstalled());
+
mock_new_card_bubble_controller_.reset(
new MockNewCreditCardBubbleController);
@@ -469,6 +437,7 @@ class AutofillDialogControllerTest : public ChromeRenderViewHostTestHarness {
controller()->OnDidGetWalletItems(CompleteAndValidWalletItems());
}
+ // Fills the inputs in SECTION_CC with data.
void FillCreditCardInputs() {
DetailOutputMap cc_outputs;
const DetailInputs& cc_inputs =
@@ -480,6 +449,24 @@ class AutofillDialogControllerTest : public ChromeRenderViewHostTestHarness {
controller()->GetView()->SetUserInput(SECTION_CC, cc_outputs);
}
+ // Fills the inputs in SECTION_CC_BILLING with valid data.
+ void FillCCBillingInputs() {
+ DetailOutputMap outputs;
+ const DetailInputs& inputs =
+ controller()->RequestedFieldsForSection(SECTION_CC_BILLING);
+ AutofillProfile full_profile(test::GetVerifiedProfile());
+ CreditCard full_card(test::GetCreditCard());
+ for (size_t i = 0; i < inputs.size(); ++i) {
+ const DetailInput& input = inputs[i];
+ outputs[&input] = full_profile.GetInfo(AutofillType(input.type),
+ "en-US");
+
+ if (outputs[&input].empty())
+ outputs[&input] = full_card.GetInfo(AutofillType(input.type), "en-US");
+ }
+ controller()->GetView()->SetUserInput(SECTION_CC_BILLING, outputs);
+ }
+
// Activates the 'Add new foo' option from the |section|'s suggestions
// dropdown and fills the |section|'s inputs with the data from the
// |data_model|. If |section| is SECTION_CC, also fills in '123' for the CVC.
@@ -993,7 +980,7 @@ TEST_F(AutofillDialogControllerTest, NewAutofillProfileIsDefault) {
TEST_F(AutofillDialogControllerTest, AutofillProfileVariants) {
SwitchToAutofill();
- EXPECT_CALL(*controller()->GetView(), ModelChanged()).Times(1);
+ EXPECT_CALL(*controller()->GetView(), ModelChanged());
ui::MenuModel* shipping_model =
controller()->MenuModelForSection(SECTION_SHIPPING);
ASSERT_TRUE(!!shipping_model);
@@ -1235,10 +1222,9 @@ TEST_F(AutofillDialogControllerTest, BillingVsShippingPhoneNumber) {
TEST_F(AutofillDialogControllerTest, AcceptLegalDocuments) {
EXPECT_CALL(*controller()->GetTestingWalletClient(),
- AcceptLegalDocuments(_, _)).Times(1);
- EXPECT_CALL(*controller()->GetTestingWalletClient(),
- GetFullWallet(_)).Times(1);
- EXPECT_CALL(*controller(), LoadRiskFingerprintData()).Times(1);
+ AcceptLegalDocuments(_, _));
+ EXPECT_CALL(*controller()->GetTestingWalletClient(), GetFullWallet(_));
+ EXPECT_CALL(*controller(), LoadRiskFingerprintData());
scoped_ptr<wallet::WalletItems> wallet_items = CompleteAndValidWalletItems();
wallet_items->AddLegalDocument(wallet::GetTestLegalDocument());
@@ -1345,10 +1331,9 @@ TEST_F(AutofillDialogControllerTest, SelectInstrument) {
}
TEST_F(AutofillDialogControllerTest, SaveAddress) {
- EXPECT_CALL(*controller()->GetView(), ModelChanged()).Times(1);
+ EXPECT_CALL(*controller()->GetView(), ModelChanged());
EXPECT_CALL(*controller()->GetTestingWalletClient(),
- SaveToWalletMock(testing::IsNull(),
- testing::NotNull())).Times(1);
+ SaveToWalletMock(testing::IsNull(), testing::NotNull()));
scoped_ptr<wallet::WalletItems> wallet_items =
wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
@@ -1368,11 +1353,11 @@ TEST_F(AutofillDialogControllerTest, SaveAddress) {
}
TEST_F(AutofillDialogControllerTest, SaveInstrument) {
- EXPECT_CALL(*controller()->GetView(), ModelChanged()).Times(1);
+ EXPECT_CALL(*controller()->GetView(), ModelChanged());
EXPECT_CALL(*controller()->GetTestingWalletClient(),
- SaveToWalletMock(testing::NotNull(),
- testing::IsNull())).Times(1);
+ SaveToWalletMock(testing::NotNull(), testing::IsNull()));
+ FillCCBillingInputs();
scoped_ptr<wallet::WalletItems> wallet_items =
wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
wallet_items->AddAddress(wallet::GetTestShippingAddress());
@@ -1380,11 +1365,11 @@ TEST_F(AutofillDialogControllerTest, SaveInstrument) {
}
TEST_F(AutofillDialogControllerTest, SaveInstrumentWithInvalidInstruments) {
- EXPECT_CALL(*controller()->GetView(), ModelChanged()).Times(1);
+ EXPECT_CALL(*controller()->GetView(), ModelChanged());
EXPECT_CALL(*controller()->GetTestingWalletClient(),
- SaveToWalletMock(testing::NotNull(),
- testing::IsNull())).Times(1);
+ SaveToWalletMock(testing::NotNull(), testing::IsNull()));
+ FillCCBillingInputs();
scoped_ptr<wallet::WalletItems> wallet_items =
wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
wallet_items->AddAddress(wallet::GetTestShippingAddress());
@@ -1394,12 +1379,12 @@ TEST_F(AutofillDialogControllerTest, SaveInstrumentWithInvalidInstruments) {
TEST_F(AutofillDialogControllerTest, SaveInstrumentAndAddress) {
EXPECT_CALL(*controller()->GetTestingWalletClient(),
- SaveToWalletMock(testing::NotNull(),
- testing::NotNull())).Times(1);
+ SaveToWalletMock(testing::NotNull(), testing::NotNull()));
- controller()->OnDidGetWalletItems(
- wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED));
- AcceptAndLoadFakeFingerprint();
+ FillCCBillingInputs();
+ scoped_ptr<wallet::WalletItems> wallet_items =
+ wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
+ SubmitWithWalletItems(wallet_items.Pass());
}
MATCHER(IsUpdatingExistingData, "updating existing Wallet data") {
@@ -1414,8 +1399,7 @@ MATCHER(UsesLocalBillingAddress, "uses the local billing address") {
// matched shipping address, then a shipping address should be added.
TEST_F(AutofillDialogControllerTest, BillingForShipping) {
EXPECT_CALL(*controller()->GetTestingWalletClient(),
- SaveToWalletMock(testing::IsNull(),
- testing::NotNull())).Times(1);
+ SaveToWalletMock(testing::IsNull(), testing::NotNull()));
controller()->OnDidGetWalletItems(CompleteAndValidWalletItems());
// Select "Same as billing" in the address menu.
@@ -1482,8 +1466,7 @@ TEST_F(AutofillDialogControllerTest, SaveInstrumentSameAsBilling) {
controller()->OnAccept();
EXPECT_CALL(*controller()->GetTestingWalletClient(),
- SaveToWalletMock(testing::NotNull(),
- UsesLocalBillingAddress())).Times(1);
+ SaveToWalletMock(testing::NotNull(), UsesLocalBillingAddress()));
AcceptAndLoadFakeFingerprint();
}
@@ -1491,7 +1474,7 @@ TEST_F(AutofillDialogControllerTest, CancelNoSave) {
EXPECT_CALL(*controller()->GetTestingWalletClient(),
SaveToWalletMock(_, _)).Times(0);
- EXPECT_CALL(*controller()->GetView(), ModelChanged()).Times(1);
+ EXPECT_CALL(*controller()->GetView(), ModelChanged());
controller()->OnDidGetWalletItems(
wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED));
@@ -1570,10 +1553,9 @@ TEST_F(AutofillDialogControllerTest, AddAutofillProfile) {
}
TEST_F(AutofillDialogControllerTest, VerifyCvv) {
+ EXPECT_CALL(*controller()->GetTestingWalletClient(), GetFullWallet(_));
EXPECT_CALL(*controller()->GetTestingWalletClient(),
- GetFullWallet(_)).Times(1);
- EXPECT_CALL(*controller()->GetTestingWalletClient(),
- AuthenticateInstrument(_, _)).Times(1);
+ AuthenticateInstrument(_, _));
SubmitWithWalletItems(CompleteAndValidWalletItems());
@@ -1587,7 +1569,10 @@ TEST_F(AutofillDialogControllerTest, VerifyCvv) {
controller()->SuggestionStateForSection(SECTION_CC_BILLING);
EXPECT_TRUE(suggestion_state.extra_text.empty());
- controller()->OnDidGetFullWallet(CreateFullWallet("verify_cvv"));
+ controller()->OnDidGetFullWallet(
+ wallet::GetTestFullWalletWithRequiredActions(
+ std::vector<wallet::RequiredAction>(1, wallet::VERIFY_CVV)));
+ ASSERT_TRUE(controller()->IsSubmitPausedOn(wallet::VERIFY_CVV));
EXPECT_FALSE(
NotificationsOfType(DialogNotification::REQUIRED_ACTION).empty());
@@ -1606,8 +1591,7 @@ TEST_F(AutofillDialogControllerTest, VerifyCvv) {
}
TEST_F(AutofillDialogControllerTest, ErrorDuringSubmit) {
- EXPECT_CALL(*controller()->GetTestingWalletClient(),
- GetFullWallet(_)).Times(1);
+ EXPECT_CALL(*controller()->GetTestingWalletClient(), GetFullWallet(_));
SubmitWithWalletItems(CompleteAndValidWalletItems());
@@ -1621,11 +1605,12 @@ TEST_F(AutofillDialogControllerTest, ErrorDuringSubmit) {
}
TEST_F(AutofillDialogControllerTest, ErrorDuringVerifyCvv) {
- EXPECT_CALL(*controller()->GetTestingWalletClient(),
- GetFullWallet(_)).Times(1);
+ EXPECT_CALL(*controller()->GetTestingWalletClient(), GetFullWallet(_));
SubmitWithWalletItems(CompleteAndValidWalletItems());
- controller()->OnDidGetFullWallet(CreateFullWallet("verify_cvv"));
+ controller()->OnDidGetFullWallet(
+ wallet::GetTestFullWalletWithRequiredActions(
+ std::vector<wallet::RequiredAction>(1, wallet::VERIFY_CVV)));
ASSERT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
ASSERT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_CANCEL));
@@ -1654,7 +1639,7 @@ TEST_F(AutofillDialogControllerTest, WalletServerSideValidation) {
wallet::FormFieldError(wallet::FormFieldError::INVALID_POSTAL_CODE,
wallet::FormFieldError::SHIPPING_ADDRESS));
- EXPECT_CALL(*controller()->GetView(), UpdateForErrors()).Times(1);
+ EXPECT_CALL(*controller()->GetView(), UpdateForErrors());
controller()->OnDidSaveToWallet(std::string(),
std::string(),
required_actions,
@@ -1918,7 +1903,7 @@ TEST_F(AutofillDialogControllerTest, SaveDetailsInChrome) {
TEST_F(AutofillDialogControllerTest, UpgradeMinimalAddress) {
// A minimal address being selected should trigger error validation in the
// view. Called once for each incomplete suggestion.
- EXPECT_CALL(*controller()->GetView(), UpdateForErrors()).Times(1);
+ EXPECT_CALL(*controller()->GetView(), UpdateForErrors());
scoped_ptr<wallet::WalletItems> wallet_items =
wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
@@ -1939,8 +1924,7 @@ TEST_F(AutofillDialogControllerTest, UpgradeMinimalAddress) {
TEST_F(AutofillDialogControllerTest, RiskNeverLoadsWithPendingLegalDocuments) {
EXPECT_CALL(*controller(), LoadRiskFingerprintData()).Times(0);
- scoped_ptr<wallet::WalletItems> wallet_items =
- wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
+ scoped_ptr<wallet::WalletItems> wallet_items = CompleteAndValidWalletItems();
wallet_items->AddLegalDocument(wallet::GetTestLegalDocument());
controller()->OnDidGetWalletItems(wallet_items.Pass());
controller()->OnAccept();
@@ -1949,13 +1933,12 @@ TEST_F(AutofillDialogControllerTest, RiskNeverLoadsWithPendingLegalDocuments) {
TEST_F(AutofillDialogControllerTest, RiskLoadsAfterAcceptingLegalDocuments) {
EXPECT_CALL(*controller(), LoadRiskFingerprintData()).Times(0);
- scoped_ptr<wallet::WalletItems> wallet_items =
- wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
+ scoped_ptr<wallet::WalletItems> wallet_items = CompleteAndValidWalletItems();
wallet_items->AddLegalDocument(wallet::GetTestLegalDocument());
controller()->OnDidGetWalletItems(wallet_items.Pass());
testing::Mock::VerifyAndClear(controller());
- EXPECT_CALL(*controller(), LoadRiskFingerprintData()).Times(1);
+ EXPECT_CALL(*controller(), LoadRiskFingerprintData());
controller()->OnAccept();
@@ -2037,8 +2020,7 @@ TEST_F(AutofillDialogControllerTest, ShippingSectionCanBeHiddenForWallet) {
EXPECT_FALSE(controller()->SectionIsActive(SECTION_SHIPPING));
EXPECT_FALSE(controller()->IsShippingAddressRequired());
- EXPECT_CALL(*controller()->GetTestingWalletClient(),
- GetFullWallet(_)).Times(1);
+ EXPECT_CALL(*controller()->GetTestingWalletClient(), GetFullWallet(_));
scoped_ptr<wallet::WalletItems> wallet_items =
wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
@@ -2117,10 +2099,11 @@ TEST_F(AutofillDialogControllerTest, ChooseAnotherInstrumentOrAddress) {
EXPECT_EQ(0U, NotificationsOfType(
DialogNotification::REQUIRED_ACTION).size());
- EXPECT_CALL(*controller()->GetTestingWalletClient(),
- GetWalletItems()).Times(1);
+ EXPECT_CALL(*controller()->GetTestingWalletClient(), GetWalletItems());
controller()->OnDidGetFullWallet(
- CreateFullWallet("choose_another_instrument_or_address"));
+ wallet::GetTestFullWalletWithRequiredActions(
+ std::vector<wallet::RequiredAction>(
+ 1, wallet::CHOOSE_ANOTHER_INSTRUMENT_OR_ADDRESS)));
EXPECT_EQ(1U, NotificationsOfType(
DialogNotification::REQUIRED_ACTION).size());
controller()->OnDidGetWalletItems(CompleteAndValidWalletItems());
@@ -2131,25 +2114,23 @@ TEST_F(AutofillDialogControllerTest, ChooseAnotherInstrumentOrAddress) {
}
TEST_F(AutofillDialogControllerTest, NewCardBubbleShown) {
- EXPECT_CALL(*test_generated_bubble_controller(), SetupAndShow(_, _)).Times(0);
-
SwitchToAutofill();
FillCreditCardInputs();
controller()->OnAccept();
controller()->ViewClosed();
EXPECT_EQ(1, mock_new_card_bubble_controller()->bubbles_shown());
+ EXPECT_EQ(0, test_generated_bubble_controller()->bubbles_shown());
}
TEST_F(AutofillDialogControllerTest, GeneratedCardBubbleShown) {
- EXPECT_CALL(*test_generated_bubble_controller(), SetupAndShow(_, _)).Times(1);
-
SubmitWithWalletItems(CompleteAndValidWalletItems());
controller()->OnDidGetFullWallet(wallet::GetTestFullWallet());
controller()->ForceFinishSubmit();
controller()->ViewClosed();
EXPECT_EQ(0, mock_new_card_bubble_controller()->bubbles_shown());
+ EXPECT_EQ(1, test_generated_bubble_controller()->bubbles_shown());
}
// Verify that new Wallet data is fetched when the user switches away from the
@@ -2457,7 +2438,7 @@ TEST_F(AutofillDialogControllerTest, SaveCreditCardIncludesName_WithBilling) {
TestPersonalDataManager* test_pdm = controller()->GetTestingManager();
AutofillProfile test_profile(test::GetVerifiedProfile());
- EXPECT_CALL(*controller()->GetView(), ModelChanged()).Times(1);
+ EXPECT_CALL(*controller()->GetView(), ModelChanged());
test_pdm->AddTestingProfile(&test_profile);
ASSERT_TRUE(controller()->MenuModelForSection(SECTION_BILLING));
@@ -2474,4 +2455,78 @@ TEST_F(AutofillDialogControllerTest, SaveCreditCardIncludesName_WithBilling) {
controller()->ViewClosed();
}
+TEST_F(AutofillDialogControllerTest, InputEditability) {
+ // Empty wallet items: all fields are editable.
+ scoped_ptr<wallet::WalletItems> items =
+ wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
+ controller()->OnDidGetWalletItems(items.Pass());
+
+ DialogSection sections[] = { SECTION_CC_BILLING, SECTION_SHIPPING };
+ for (size_t i = 0; i < arraysize(sections); ++i) {
+ const DetailInputs& inputs =
+ controller()->RequestedFieldsForSection(sections[i]);
+ for (size_t j = 0; j < inputs.size(); ++j) {
+ EXPECT_TRUE(controller()->InputIsEditable(inputs[j], sections[i]));
+ }
+ }
+
+ // Expired instrument: CC number + CVV are not editable.
+ items = wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
+ scoped_ptr<wallet::WalletItems::MaskedInstrument> expired_instrument =
+ wallet::GetTestMaskedInstrumentExpired();
+ items->AddInstrument(expired_instrument.Pass());
+ controller()->OnDidGetWalletItems(items.Pass());
+ EXPECT_TRUE(controller()->IsEditingExistingData(SECTION_CC_BILLING));
+
+ const DetailInputs& inputs =
+ controller()->RequestedFieldsForSection(SECTION_CC_BILLING);
+ DetailOutputMap outputs;
+ CopyInitialValues(inputs, &outputs);
+ controller()->GetView()->SetUserInput(SECTION_CC_BILLING, outputs);
+
+ for (size_t i = 0; i < arraysize(sections); ++i) {
+ const DetailInputs& inputs =
+ controller()->RequestedFieldsForSection(sections[i]);
+ for (size_t j = 0; j < inputs.size(); ++j) {
+ if (inputs[j].type == CREDIT_CARD_NUMBER ||
+ inputs[j].type == CREDIT_CARD_VERIFICATION_CODE) {
+ EXPECT_FALSE(controller()->InputIsEditable(inputs[j], sections[i]));
+ } else {
+ EXPECT_TRUE(controller()->InputIsEditable(inputs[j], sections[i]));
+ }
+ }
+ }
+
+ // User changes the billing address; same story.
+ SetOutputValue(inputs, ADDRESS_BILLING_ZIP, ASCIIToUTF16("77025"), &outputs);
+ controller()->GetView()->SetUserInput(SECTION_CC_BILLING, outputs);
+ for (size_t i = 0; i < arraysize(sections); ++i) {
+ const DetailInputs& inputs =
+ controller()->RequestedFieldsForSection(sections[i]);
+ for (size_t j = 0; j < inputs.size(); ++j) {
+ if (inputs[j].type == CREDIT_CARD_NUMBER ||
+ inputs[j].type == CREDIT_CARD_VERIFICATION_CODE) {
+ EXPECT_FALSE(controller()->InputIsEditable(inputs[j], sections[i]));
+ } else {
+ EXPECT_TRUE(controller()->InputIsEditable(inputs[j], sections[i]));
+ }
+ }
+ }
+
+ // User changes a detail of the CC itself (expiration date), CVV is now
+ // editable (and mandatory).
+ SetOutputValue(inputs, CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("06"), &outputs);
+ controller()->GetView()->SetUserInput(SECTION_CC_BILLING, outputs);
+ for (size_t i = 0; i < arraysize(sections); ++i) {
+ const DetailInputs& inputs =
+ controller()->RequestedFieldsForSection(sections[i]);
+ for (size_t j = 0; j < inputs.size(); ++j) {
+ if (inputs[j].type == CREDIT_CARD_NUMBER)
+ EXPECT_FALSE(controller()->InputIsEditable(inputs[j], sections[i]));
+ else
+ EXPECT_TRUE(controller()->InputIsEditable(inputs[j], sections[i]));
+ }
+ }
+}
+
} // namespace autofill
diff --git a/chrome/browser/ui/autofill/autofill_dialog_types.h b/chrome/browser/ui/autofill/autofill_dialog_types.h
index a31b647885..a06f5b0cf0 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_types.h
+++ b/chrome/browser/ui/autofill/autofill_dialog_types.h
@@ -45,10 +45,6 @@ struct DetailInput {
// When non-empty, indicates the starting value for this input. This will be
// used when the user is editing existing data.
string16 initial_value;
-
- // Whether the input is able to be edited (e.g. text changed in textfields,
- // index changed in comboboxes).
- bool editable;
};
// Determines whether |input| and |field| match.
diff --git a/chrome/browser/ui/autofill/autofill_dialog_view_delegate.h b/chrome/browser/ui/autofill/autofill_dialog_view_delegate.h
index bcb33c65d9..eee85b9d99 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_view_delegate.h
+++ b/chrome/browser/ui/autofill/autofill_dialog_view_delegate.h
@@ -119,11 +119,6 @@ class AutofillDialogViewDelegate {
// Returns the current state of suggestions for |section|.
virtual SuggestionState SuggestionStateForSection(DialogSection section) = 0;
- // TODO(groby): Remove this deprecated method after Mac starts using
- // IconsForFields. http://crbug.com/292876
- virtual gfx::Image IconForField(ServerFieldType type,
- const string16& user_input) const = 0;
-
// Returns the icons to be displayed along with the given |user_inputs| in a
// section.
virtual FieldIconMap IconsForFields(
@@ -136,6 +131,10 @@ class AutofillDialogViewDelegate {
// Returns a tooltip for the given field, or an empty string if none exists.
virtual string16 TooltipForField(ServerFieldType type) const = 0;
+ // Whether a particular DetailInput in |section| should be edited or not.
+ virtual bool InputIsEditable(const DetailInput& input,
+ DialogSection section) = 0;
+
// Decides whether input of |value| is valid for a field of type |type|. If
// valid, the returned string will be empty. Otherwise it will contain an
// error message.
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
index 3599ca469b..c7c1751dc4 100644
--- a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
+++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
@@ -30,9 +30,6 @@ namespace {
// Used to indicate that no line is currently selected by the user.
const int kNoSelection = -1;
-// Size difference between name and subtext in pixels.
-const int kLabelFontSizeDelta = -2;
-
// The vertical height of each row in pixels.
const size_t kRowHeight = 24;
@@ -40,6 +37,9 @@ const size_t kRowHeight = 24;
const size_t kSeparatorHeight = 1;
#if !defined(OS_ANDROID)
+// Size difference between name and subtext in pixels.
+const int kLabelFontSizeDelta = -2;
+
const size_t kNamePadding = AutofillPopupView::kNamePadding;
const size_t kIconPadding = AutofillPopupView::kIconPadding;
const size_t kEndPadding = AutofillPopupView::kEndPadding;
diff --git a/chrome/browser/ui/autofill/generated_credit_card_bubble_controller.h b/chrome/browser/ui/autofill/generated_credit_card_bubble_controller.h
index bdb1614de8..4b3ee00dc6 100644
--- a/chrome/browser/ui/autofill/generated_credit_card_bubble_controller.h
+++ b/chrome/browser/ui/autofill/generated_credit_card_bubble_controller.h
@@ -116,11 +116,15 @@ class GeneratedCreditCardBubbleController
// will show in the omnibox.
bool ShouldDisplayBubbleInitially() const;
+ // Exposed for testing.
+ base::string16 fronting_card_name() const { return fronting_card_name_; }
+ base::string16 backing_card_name() const { return backing_card_name_; }
+
// Generates the correct bubble text and text highlighting ranges and shows a
// bubble to educate the user about generated (fronting) cards and how they
// are used to bill their original (backing) card. Exposed for testing.
- virtual void SetupAndShow(const base::string16& backing_card_name,
- const base::string16& fronting_card_name);
+ virtual void SetupAndShow(const base::string16& fronting_card_name,
+ const base::string16& backing_card_name);
private:
friend class
diff --git a/chrome/browser/ui/autofill/generated_credit_card_bubble_controller_unittest.cc b/chrome/browser/ui/autofill/generated_credit_card_bubble_controller_unittest.cc
index e8370bcd81..42f9f50904 100644
--- a/chrome/browser/ui/autofill/generated_credit_card_bubble_controller_unittest.cc
+++ b/chrome/browser/ui/autofill/generated_credit_card_bubble_controller_unittest.cc
@@ -10,6 +10,7 @@
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/ui/autofill/generated_credit_card_bubble_controller.h"
+#include "chrome/browser/ui/autofill/test_generated_credit_card_bubble_controller.h"
#include "chrome/browser/ui/autofill/test_generated_credit_card_bubble_view.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_profile.h"
@@ -42,39 +43,6 @@ base::string16 RangeOfString(const base::string16& string,
return string.substr(range.start(), range.end() - range.start());
}
-class TestGeneratedCreditCardBubbleController
- : public GeneratedCreditCardBubbleController {
- public:
- explicit TestGeneratedCreditCardBubbleController(
- content::WebContents* contents)
- : GeneratedCreditCardBubbleController(contents) {
- contents->SetUserData(UserDataKey(), this);
- }
-
- virtual ~TestGeneratedCreditCardBubbleController() {}
-
- bool IsInstalled() const {
- return web_contents()->GetUserData(UserDataKey()) == this;
- }
-
- TestGeneratedCreditCardBubbleView* GetTestingBubble() {
- return static_cast<TestGeneratedCreditCardBubbleView*>(
- GeneratedCreditCardBubbleController::bubble().get());
- }
-
- protected:
- virtual base::WeakPtr<GeneratedCreditCardBubbleView> CreateBubble() OVERRIDE {
- return TestGeneratedCreditCardBubbleView::Create(GetWeakPtr());
- }
-
- virtual bool CanShow() const OVERRIDE {
- return true;
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(TestGeneratedCreditCardBubbleController);
-};
-
class GeneratedCreditCardBubbleControllerTest : public testing::Test {
public:
GeneratedCreditCardBubbleControllerTest()
diff --git a/chrome/browser/ui/autofill/mock_autofill_dialog_view_delegate.cc b/chrome/browser/ui/autofill/mock_autofill_dialog_view_delegate.cc
index e9b4f5c2e3..57e6093080 100644
--- a/chrome/browser/ui/autofill/mock_autofill_dialog_view_delegate.cc
+++ b/chrome/browser/ui/autofill/mock_autofill_dialog_view_delegate.cc
@@ -29,6 +29,9 @@ MockAutofillDialogViewDelegate::MockAutofillDialogViewDelegate() {
gfx::Image(),
string16(),
gfx::Image()));
+ DefaultValue<FieldIconMap>::Set(FieldIconMap());
+ DefaultValue<std::vector<DialogNotification> >::Set(
+ std::vector<DialogNotification>());
// SECTION_CC *must* have a CREDIT_CARD_VERIFICATION_CODE field.
const DetailInput kCreditCardInputs[] = {
@@ -49,6 +52,11 @@ MockAutofillDialogViewDelegate::MockAutofillDialogViewDelegate() {
.WillByDefault(Return(false));
}
+void MockAutofillDialogViewDelegate::SetWebContents(
+ content::WebContents* contents) {
+ testing::DefaultValue<content::WebContents*>::Set(contents);
+}
+
MockAutofillDialogViewDelegate::~MockAutofillDialogViewDelegate() {
using testing::DefaultValue;
@@ -57,6 +65,9 @@ MockAutofillDialogViewDelegate::~MockAutofillDialogViewDelegate() {
DefaultValue<ValidityMessages>::Clear();
DefaultValue<string16>::Clear();
DefaultValue<const DetailInputs&>::Clear();
+ DefaultValue<FieldIconMap>::Clear();
+ DefaultValue<std::vector<DialogNotification> >::Clear();
+ DefaultValue<content::WebContents*>::Clear();
}
} // namespace autofill
diff --git a/chrome/browser/ui/autofill/mock_autofill_dialog_view_delegate.h b/chrome/browser/ui/autofill/mock_autofill_dialog_view_delegate.h
index 99ccfc5e0a..3eb153d05f 100644
--- a/chrome/browser/ui/autofill/mock_autofill_dialog_view_delegate.h
+++ b/chrome/browser/ui/autofill/mock_autofill_dialog_view_delegate.h
@@ -49,23 +49,21 @@ class MockAutofillDialogViewDelegate : public AutofillDialogViewDelegate {
MOCK_METHOD1(SuggestionStateForSection, SuggestionState(DialogSection));
MOCK_METHOD1(EditClickedForSection, void(DialogSection section));
MOCK_METHOD1(EditCancelledForSection, void(DialogSection section));
- // TODO(groby): Remove this deprecated method after Mac starts using
- // IconsForFields. http://crbug.com/292876
- MOCK_CONST_METHOD2(IconForField,
- gfx::Image(ServerFieldType, const string16&));
MOCK_CONST_METHOD1(IconsForFields, FieldIconMap(const FieldValueMap&));
MOCK_CONST_METHOD1(FieldControlsIcons, bool(ServerFieldType));
MOCK_CONST_METHOD1(TooltipForField, base::string16(ServerFieldType));
+ MOCK_METHOD2(InputIsEditable, bool(const DetailInput& input,
+ DialogSection section));
MOCK_METHOD3(InputValidityMessage,
string16(DialogSection, ServerFieldType, const string16&));
MOCK_METHOD2(InputsAreValid, ValidityMessages(DialogSection,
const DetailOutputMap&));
- MOCK_METHOD6(UserEditedOrActivatedInput,void(DialogSection,
- const DetailInput*,
- gfx::NativeView,
- const gfx::Rect&,
- const string16&,
- bool was_edit));
+ MOCK_METHOD6(UserEditedOrActivatedInput, void(DialogSection,
+ const DetailInput*,
+ gfx::NativeView,
+ const gfx::Rect&,
+ const string16&,
+ bool was_edit));
MOCK_METHOD1(HandleKeyPressEventInInput,
bool(const content::NativeWebKeyboardEvent& event));
MOCK_METHOD0(FocusMoved, void());
@@ -83,6 +81,9 @@ class MockAutofillDialogViewDelegate : public AutofillDialogViewDelegate {
MOCK_METHOD0(profile, Profile*());
MOCK_METHOD0(GetWebContents, content::WebContents*());
+ // Set which web contents initiated showing the dialog.
+ void SetWebContents(content::WebContents* contents);
+
private:
DetailInputs default_inputs_;
DetailInputs cc_default_inputs_; // Default inputs for SECTION_CC.
diff --git a/chrome/browser/ui/autofill/test_generated_credit_card_bubble_controller.cc b/chrome/browser/ui/autofill/test_generated_credit_card_bubble_controller.cc
new file mode 100644
index 0000000000..9c4b4f7152
--- /dev/null
+++ b/chrome/browser/ui/autofill/test_generated_credit_card_bubble_controller.cc
@@ -0,0 +1,50 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/autofill/test_generated_credit_card_bubble_controller.h"
+
+#include "chrome/browser/ui/autofill/test_generated_credit_card_bubble_view.h"
+#include "content/public/browser/web_contents.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace autofill {
+
+TestGeneratedCreditCardBubbleController::
+ TestGeneratedCreditCardBubbleController(content::WebContents* contents)
+ : GeneratedCreditCardBubbleController(contents),
+ bubbles_shown_(0) {
+ contents->SetUserData(UserDataKey(), this);
+}
+
+TestGeneratedCreditCardBubbleController::
+ ~TestGeneratedCreditCardBubbleController() {}
+
+bool TestGeneratedCreditCardBubbleController::IsInstalled() const {
+ return web_contents()->GetUserData(UserDataKey()) == this;
+}
+
+TestGeneratedCreditCardBubbleView* TestGeneratedCreditCardBubbleController::
+ GetTestingBubble() {
+ return static_cast<TestGeneratedCreditCardBubbleView*>(
+ GeneratedCreditCardBubbleController::bubble().get());
+}
+
+base::WeakPtr<GeneratedCreditCardBubbleView>
+ TestGeneratedCreditCardBubbleController::CreateBubble() {
+ return TestGeneratedCreditCardBubbleView::Create(GetWeakPtr());
+}
+
+bool TestGeneratedCreditCardBubbleController::CanShow() const {
+ return true;
+}
+
+void TestGeneratedCreditCardBubbleController::SetupAndShow(
+ const base::string16& fronting_card_name,
+ const base::string16& backing_card_name) {
+ GeneratedCreditCardBubbleController::SetupAndShow(fronting_card_name,
+ backing_card_name);
+ ++bubbles_shown_;
+}
+
+} // namespace autofill
diff --git a/chrome/browser/ui/autofill/test_generated_credit_card_bubble_controller.h b/chrome/browser/ui/autofill/test_generated_credit_card_bubble_controller.h
new file mode 100644
index 0000000000..eef69f442b
--- /dev/null
+++ b/chrome/browser/ui/autofill/test_generated_credit_card_bubble_controller.h
@@ -0,0 +1,51 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_AUTOFILL_TEST_GENERATED_CREDIT_CARD_BUBBLE_CONTROLLER_H_
+#define CHROME_BROWSER_UI_AUTOFILL_TEST_GENERATED_CREDIT_CARD_BUBBLE_CONTROLLER_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "chrome/browser/ui/autofill/generated_credit_card_bubble_controller.h"
+
+namespace autofill {
+
+class TestGeneratedCreditCardBubbleView;
+
+class TestGeneratedCreditCardBubbleController
+ : public GeneratedCreditCardBubbleController {
+ public:
+ explicit TestGeneratedCreditCardBubbleController(
+ content::WebContents* contents);
+ virtual ~TestGeneratedCreditCardBubbleController();
+
+ // Whether this controller is installed on |web_contents()|.
+ bool IsInstalled() const;
+
+ // Get an invisible, dumb, test-only bubble.
+ TestGeneratedCreditCardBubbleView* GetTestingBubble();
+
+ // Made public for testing.
+ using GeneratedCreditCardBubbleController::fronting_card_name;
+ using GeneratedCreditCardBubbleController::backing_card_name;
+
+ int bubbles_shown() const { return bubbles_shown_; }
+
+ protected:
+ // GeneratedCreditCardBubbleController:
+ virtual base::WeakPtr<GeneratedCreditCardBubbleView> CreateBubble() OVERRIDE;
+ virtual bool CanShow() const OVERRIDE;
+ virtual void SetupAndShow(const base::string16& fronting_card_name,
+ const base::string16& backing_card_name) OVERRIDE;
+
+ private:
+ // How many bubbles have been shown via this controller.
+ int bubbles_shown_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestGeneratedCreditCardBubbleController);
+};
+
+} // namespace autofill
+
+#endif // CHROME_BROWSER_UI_AUTOFILL_TEST_GENERATED_CREDIT_CARD_BUBBLE_CONTROLLER_H_
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index 799f03cceb..e56c71d2a3 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -697,7 +697,8 @@ Browser::DownloadClosePreventionType Browser::OkToCloseWithInProgressDownloads(
if (!g_browser_process->profile_manager())
return DOWNLOAD_CLOSE_OK;
- int total_download_count = DownloadService::DownloadCountAllProfiles();
+ int total_download_count =
+ DownloadService::NonMaliciousDownloadCountAllProfiles();
if (total_download_count == 0)
return DOWNLOAD_CLOSE_OK; // No downloads; can definitely close.
@@ -731,9 +732,9 @@ Browser::DownloadClosePreventionType Browser::OkToCloseWithInProgressDownloads(
DownloadService* download_service =
DownloadServiceFactory::GetForBrowserContext(profile());
if ((profile_window_count == 0) &&
- (download_service->DownloadCount() > 0) &&
+ (download_service->NonMaliciousDownloadCount() > 0) &&
profile()->IsOffTheRecord()) {
- *num_downloads_blocking = download_service->DownloadCount();
+ *num_downloads_blocking = download_service->NonMaliciousDownloadCount();
return DOWNLOAD_CLOSE_LAST_WINDOW_IN_INCOGNITO_PROFILE;
}
diff --git a/chrome/browser/ui/browser_close_browsertest.cc b/chrome/browser/ui/browser_close_browsertest.cc
index 4f2b145036..cbc544c5bf 100644
--- a/chrome/browser/ui/browser_close_browsertest.cc
+++ b/chrome/browser/ui/browser_close_browsertest.cc
@@ -255,6 +255,8 @@ class BrowserCloseTest : public InProcessBrowserTest {
// an assertion has failed and the test should be aborted.
bool ExecuteDownloadCloseCheckCase(size_t i) {
const DownloadsCloseCheckCase& check_case(download_close_check_cases[i]);
+ SCOPED_TRACE(testing::Message() << "Case" << i
+ << ": " << check_case.DebugString());
// Test invariant: so that we don't actually try and close the browser,
// we always enter the function with a single browser window open on the
@@ -270,18 +272,14 @@ class BrowserCloseTest : public InProcessBrowserTest {
return false;
Browser* entry_browser = FirstUnclosedBrowser();
- EXPECT_EQ(first_profile_, entry_browser->profile())
- << "Case" << i
- << ": " << check_case.DebugString();
+ EXPECT_EQ(first_profile_, entry_browser->profile());
if (first_profile_ != entry_browser->profile())
return false;
- int total_download_count = DownloadService::DownloadCountAllProfiles();
- EXPECT_EQ(0, total_download_count)
- << "Case " << i
- << ": " << check_case.DebugString();
+ int total_download_count =
+ DownloadService::NonMaliciousDownloadCountAllProfiles();
+ EXPECT_EQ(0, total_download_count);
if (0 != total_download_count)
return false;
-
Profile* first_profile_incognito = first_profile_->GetOffTheRecordProfile();
Profile* second_profile_incognito =
second_profile_->GetOffTheRecordProfile();
@@ -356,12 +354,9 @@ class BrowserCloseTest : public InProcessBrowserTest {
Browser::DownloadClosePreventionType type =
browser_to_probe->OkToCloseWithInProgressDownloads(
&num_downloads_blocking);
- EXPECT_EQ(check_case.type, type) << "Case " << i
- << ": " << check_case.DebugString();
+ EXPECT_EQ(check_case.type, type);
if (type != Browser::DOWNLOAD_CLOSE_OK)
- EXPECT_EQ(check_case.num_blocking, num_downloads_blocking)
- << "Case " << i
- << ": " << check_case.DebugString();
+ EXPECT_EQ(check_case.num_blocking, num_downloads_blocking);
// Release all the downloads.
CompleteAllDownloads(browser_to_probe);
diff --git a/chrome/browser/ui/browser_command_controller.cc b/chrome/browser/ui/browser_command_controller.cc
index 2afe9bec2f..ff9cdefba8 100644
--- a/chrome/browser/ui/browser_command_controller.cc
+++ b/chrome/browser/ui/browser_command_controller.cc
@@ -28,6 +28,7 @@
#include "chrome/browser/ui/chrome_pages.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/tabs/tab_strip_model_utils.h"
+#include "chrome/browser/ui/webui/inspect_ui.h"
#include "chrome/common/content_restriction.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/profiling.h"
@@ -55,6 +56,12 @@
#include "chrome/browser/ui/ash/ash_util.h"
#endif
+#if defined(OS_CHROMEOS)
+#include "ash/session_state_delegate.h"
+#include "ash/shell.h"
+#include "chrome/browser/ui/ash/multi_user_window_manager.h"
+#endif
+
using content::NavigationEntry;
using content::NavigationController;
using content::WebContents;
@@ -452,6 +459,21 @@ void BrowserCommandController::ExecuteCommandWithDisposition(
// mechanism to pass accelerators back into Ash. http://crbug.com/285308
#endif
+#if defined(OS_CHROMEOS)
+ case IDC_VISIT_DESKTOP_OF_LRU_USER_2:
+ case IDC_VISIT_DESKTOP_OF_LRU_USER_3: {
+ // When running the multi user mode on Chrome OS, windows can "visit"
+ // another user's desktop.
+ const std::string& user_id =
+ ash::Shell::GetInstance()->session_state_delegate()->GetUserID(
+ IDC_VISIT_DESKTOP_OF_LRU_USER_2 == id ? 1 : 2);
+ chrome::MultiUserWindowManager::GetInstance()->ShowWindowForUser(
+ browser_->window()->GetNativeWindow(),
+ user_id);
+ break;
+ }
+#endif
+
#if defined(OS_WIN)
// Windows 8 specific commands.
case IDC_METRO_SNAP_ENABLE:
@@ -629,6 +651,9 @@ void BrowserCommandController::ExecuteCommandWithDisposition(
case IDC_DEV_TOOLS_CONSOLE:
ToggleDevToolsWindow(browser_, DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE);
break;
+ case IDC_DEV_TOOLS_DEVICES:
+ InspectUI::InspectDevices(browser_);
+ break;
case IDC_DEV_TOOLS_INSPECT:
ToggleDevToolsWindow(browser_, DEVTOOLS_TOGGLE_ACTION_INSPECT);
break;
@@ -845,6 +870,10 @@ void BrowserCommandController::InitCommandState() {
#if defined(USE_ASH)
command_updater_.UpdateCommandEnabled(IDC_MINIMIZE_WINDOW, true);
#endif
+#if defined(OS_CHROMEOS)
+ command_updater_.UpdateCommandEnabled(IDC_VISIT_DESKTOP_OF_LRU_USER_2, true);
+ command_updater_.UpdateCommandEnabled(IDC_VISIT_DESKTOP_OF_LRU_USER_3, true);
+#endif
// Page-related commands
command_updater_.UpdateCommandEnabled(IDC_EMAIL_PAGE_LOCATION, true);
@@ -1079,6 +1108,8 @@ void BrowserCommandController::UpdateCommandsForDevTools() {
dev_tools_enabled);
command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS_CONSOLE,
dev_tools_enabled);
+ command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS_DEVICES,
+ dev_tools_enabled);
command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS_INSPECT,
dev_tools_enabled);
command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS_TOGGLE,
diff --git a/chrome/browser/ui/browser_dialogs.h b/chrome/browser/ui/browser_dialogs.h
index c3ad4004fc..72af390f99 100644
--- a/chrome/browser/ui/browser_dialogs.h
+++ b/chrome/browser/ui/browser_dialogs.h
@@ -77,6 +77,14 @@ void ShowCreateWebAppShortcutsDialog(gfx::NativeWindow parent_window,
content::WebContents* web_contents);
#endif
+// Shows the create chrome app shortcut dialog box.
+// On Mac, this creates a shortcut without prompting.
+// |close_callback| may be null.
+void ShowCreateChromeAppShortcutsDialog(gfx::NativeWindow parent_window,
+ Profile* profile,
+ const extensions::Extension* app,
+ const base::Closure& close_callback);
+
// Shows a color chooser that reports to the given WebContents.
content::ColorChooser* ShowColorChooser(content::WebContents* web_contents,
SkColor initial_color);
diff --git a/chrome/browser/ui/browser_focus_uitest.cc b/chrome/browser/ui/browser_focus_uitest.cc
index 869f43d047..4a6f59dc98 100644
--- a/chrome/browser/ui/browser_focus_uitest.cc
+++ b/chrome/browser/ui/browser_focus_uitest.cc
@@ -871,6 +871,19 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, DISABLED_FocusOnReloadCrashedTab) {
ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
}
+// Tests that focus goes to frame after crashed tab.
+// TODO(shrikant): Find out where the focus should be deterministically.
+// Currently focused_view after crash seem to be non null in debug mode
+// (invalidated pointer 0xcccccc).
+IN_PROC_BROWSER_TEST_F(BrowserFocusTest, DISABLED_FocusAfterCrashedTab) {
+ ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
+ content::CrashTab(browser()->tab_strip_model()->GetActiveWebContents());
+
+ ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
+}
+
// Tests that when a new tab is opened from the omnibox, the focus is moved from
// the omnibox for the current tab.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest,
diff --git a/chrome/browser/ui/browser_navigator.cc b/chrome/browser/ui/browser_navigator.cc
index 4c25a8edcb..7726b996d8 100644
--- a/chrome/browser/ui/browser_navigator.cc
+++ b/chrome/browser/ui/browser_navigator.cc
@@ -354,14 +354,16 @@ content::WebContents* CreateTargetContents(const chrome::NavigateParams& params,
return target_contents;
}
-// If a prerendered page exists for |url|, replace the page at |target_contents|
-// with it.
-bool SwapInPrerender(WebContents* target_contents, const GURL& url) {
+// If a prerendered page exists for |url|, replace the page at
+// |params->target_contents| with it and update to point to the swapped-in
+// WebContents.
+bool SwapInPrerender(const GURL& url, chrome::NavigateParams* params) {
prerender::PrerenderManager* prerender_manager =
prerender::PrerenderManagerFactory::GetForProfile(
- Profile::FromBrowserContext(target_contents->GetBrowserContext()));
+ Profile::FromBrowserContext(
+ params->target_contents->GetBrowserContext()));
return prerender_manager &&
- prerender_manager->MaybeUsePrerenderedPage(target_contents, url);
+ prerender_manager->MaybeUsePrerenderedPage(url, params);
}
bool SwapInInstantNTP(chrome::NavigateParams* params,
@@ -540,8 +542,8 @@ void Navigate(NavigateParams* params) {
// Check if this is a singleton tab that already exists
int singleton_index = chrome::GetIndexOfSingletonTab(params);
- // Did we use Instant's NTP contents?
- bool swapped_in_instant = false;
+ // Did we use Instant's NTP contents or a prerender?
+ bool swapped_in = false;
// If no target WebContents was specified, we need to construct one if
// we are supposed to target a new tab; unless it's a singleton that already
@@ -557,8 +559,8 @@ void Navigate(NavigateParams* params) {
}
if (params->disposition != CURRENT_TAB) {
- swapped_in_instant = SwapInInstantNTP(params, url, NULL);
- if (!swapped_in_instant)
+ swapped_in = SwapInInstantNTP(params, url, NULL);
+ if (!swapped_in)
params->target_contents = CreateTargetContents(*params, url);
// This function takes ownership of |params->target_contents| until it
@@ -568,20 +570,21 @@ void Navigate(NavigateParams* params) {
// ... otherwise if we're loading in the current tab, the target is the
// same as the source.
DCHECK(params->source_contents);
- swapped_in_instant = SwapInInstantNTP(params, url,
- params->source_contents);
- if (!swapped_in_instant)
+ swapped_in = SwapInInstantNTP(params, url, params->source_contents);
+ if (!swapped_in)
params->target_contents = params->source_contents;
DCHECK(params->target_contents);
+ // Prerender expects |params->target_contents| to be attached to a browser
+ // window, so only call for CURRENT_TAB navigations. (Others are currently
+ // unsupported because of session storage namespaces anyway.)
+ if (!swapped_in)
+ swapped_in = SwapInPrerender(url, params);
}
if (user_initiated)
params->target_contents->UserGestureDone();
- if (!swapped_in_instant) {
- if (SwapInPrerender(params->target_contents, url))
- return;
-
+ if (!swapped_in) {
// Try to handle non-navigational URLs that popup dialogs and such, these
// should not actually navigate.
if (!HandleNonNavigationAboutURL(url)) {
@@ -607,7 +610,7 @@ void Navigate(NavigateParams* params) {
params->source_contents->GetView()->Focus();
if (params->source_contents == params->target_contents ||
- (swapped_in_instant && params->disposition == CURRENT_TAB)) {
+ (swapped_in && params->disposition == CURRENT_TAB)) {
// The navigation occurred in the source tab.
params->browser->UpdateUIForNavigationInTab(params->target_contents,
params->transition,
diff --git a/chrome/browser/ui/browser_tab_contents.cc b/chrome/browser/ui/browser_tab_contents.cc
index 95e26752d7..246302db0f 100644
--- a/chrome/browser/ui/browser_tab_contents.cc
+++ b/chrome/browser/ui/browser_tab_contents.cc
@@ -8,6 +8,7 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/content_settings/tab_specific_content_settings.h"
#include "chrome/browser/extensions/api/web_navigation/web_navigation_api.h"
+#include "chrome/browser/extensions/extension_web_contents_observer.h"
#include "chrome/browser/extensions/tab_helper.h"
#include "chrome/browser/external_protocol/external_protocol_observer.h"
#include "chrome/browser/favicon/favicon_tab_helper.h"
@@ -129,6 +130,7 @@ void BrowserTabContents::AttachTabHelpers(WebContents* web_contents) {
chrome_browser_net::PredictorTabHelper::CreateForWebContents(web_contents);
WebContentsModalDialogManager::CreateForWebContents(web_contents);
CoreTabHelper::CreateForWebContents(web_contents);
+ extensions::ExtensionWebContentsObserver::CreateForWebContents(web_contents);
extensions::TabHelper::CreateForWebContents(web_contents);
extensions::WebNavigationTabObserver::CreateForWebContents(web_contents);
ExternalProtocolObserver::CreateForWebContents(web_contents);
diff --git a/chrome/browser/ui/browser_window.h b/chrome/browser/ui/browser_window.h
index 2acfbf68c0..7811ace7de 100644
--- a/chrome/browser/ui/browser_window.h
+++ b/chrome/browser/ui/browser_window.h
@@ -296,10 +296,6 @@ class BrowserWindow : public ui::BaseWindow {
virtual void HandleKeyboardEvent(
const content::NativeWebKeyboardEvent& event) = 0;
- // Shows the create chrome app shortcut dialog box.
- virtual void ShowCreateChromeAppShortcutsDialog(Profile* profile,
- const extensions::Extension* app) = 0;
-
// Clipboard commands applied to the whole browser window.
virtual void Cut() = 0;
virtual void Copy() = 0;
diff --git a/chrome/browser/ui/chrome_pages.cc b/chrome/browser/ui/chrome_pages.cc
index a42b5e2940..1fe3475592 100644
--- a/chrome/browser/ui/chrome_pages.cc
+++ b/chrome/browser/ui/chrome_pages.cc
@@ -141,7 +141,8 @@ void ShowHelp(Browser* browser, HelpSource source) {
Profile* profile = ProfileManager::GetDefaultProfileOrOffTheRecord();
const extensions::Extension* extension = profile->GetExtensionService()->
GetInstalledExtension(genius_app::kGeniusAppId);
- OpenApplication(AppLaunchParams(profile, extension, 0));
+ OpenApplication(
+ AppLaunchParams(profile, extension, 0, browser->host_desktop_type()));
return;
}
#endif
diff --git a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.h b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.h
index b616cb50e0..18ff948163 100644
--- a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.h
+++ b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.h
@@ -127,17 +127,18 @@ class NativeAppWindowCocoa : public apps::NativeAppWindow,
virtual bool IsFrameless() const OVERRIDE;
virtual gfx::Insets GetFrameInsets() const OVERRIDE;
virtual bool IsVisible() const OVERRIDE;
-
- // WebContentsObserver implementation.
- virtual void RenderViewHostChanged(
- content::RenderViewHost* old_host,
- content::RenderViewHost* new_host) OVERRIDE;
-
// These are used to simulate Mac-style hide/show. Since windows can be hidden
// and shown using the app.window API, this sets is_hidden_with_app_ to
// differentiate the reason a window was hidden.
virtual void ShowWithApp() OVERRIDE;
virtual void HideWithApp() OVERRIDE;
+ // Calls setContent[Min|Max]Size with the current size constraints.
+ virtual void UpdateWindowMinMaxSize() OVERRIDE;
+
+ // WebContentsObserver implementation.
+ virtual void RenderViewHostChanged(
+ content::RenderViewHost* old_host,
+ content::RenderViewHost* new_host) OVERRIDE;
virtual void SetAlwaysOnTop(bool always_on_top) OVERRIDE;
@@ -198,8 +199,6 @@ class NativeAppWindowCocoa : public apps::NativeAppWindow,
bool is_fullscreen_;
NSRect restored_bounds_;
- gfx::Size min_size_;
- gfx::Size max_size_;
bool shows_resize_controls_;
bool shows_fullscreen_controls_;
diff --git a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.mm b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.mm
index 4cebcd9907..1e803aff39 100644
--- a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.mm
+++ b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.mm
@@ -62,14 +62,6 @@ enum {
namespace {
-// When gfx::Size is used as a min/max size, a zero represents an unbounded
-// component. This method checks whether either component is specified.
-// Note we can't use gfx::Size::IsEmpty as it returns true if either width or
-// height is zero.
-bool IsBoundedSize(const gfx::Size& size) {
- return size.width() != 0 || size.height() != 0;
-}
-
void SetFullScreenCollectionBehavior(NSWindow* window, bool allow_fullscreen) {
NSWindowCollectionBehavior behavior = [window collectionBehavior];
if (allow_fullscreen)
@@ -316,26 +308,18 @@ NativeAppWindowCocoa::NativeAppWindowCocoa(
window_class = [ShellFramelessNSWindow class];
}
- min_size_ = params.minimum_size;
- max_size_ = params.maximum_size;
- shows_resize_controls_ = params.resizable &&
- (min_size_.IsEmpty() || max_size_.IsEmpty() || min_size_ != max_size_);
- shows_fullscreen_controls_ = params.resizable && !IsBoundedSize(max_size_);
+ ShellWindow::SizeConstraints size_constraints =
+ shell_window_->size_constraints();
+ shows_resize_controls_ =
+ params.resizable && !size_constraints.HasFixedSize();
+ shows_fullscreen_controls_ =
+ params.resizable && !size_constraints.HasMaximumSize();
window.reset([[window_class alloc]
initWithContentRect:cocoa_bounds
styleMask:GetWindowStyleMask()
backing:NSBackingStoreBuffered
defer:NO]);
[window setTitle:base::SysUTF8ToNSString(extension()->name())];
- if (IsBoundedSize(min_size_)) {
- [window setContentMinSize:
- NSMakeSize(min_size_.width(), min_size_.height())];
- }
- if (IsBoundedSize(max_size_)) {
- CGFloat max_width = max_size_.width() ? max_size_.width() : CGFLOAT_MAX;
- CGFloat max_height = max_size_.height() ? max_size_.height() : CGFLOAT_MAX;
- [window setContentMaxSize:NSMakeSize(max_width, max_height)];
- }
if (base::mac::IsOSSnowLeopard() &&
[window respondsToSelector:@selector(setBottomCornerRounded:)])
@@ -367,6 +351,7 @@ NativeAppWindowCocoa::NativeAppWindowCocoa(
[[window_controller_ window] setDelegate:window_controller_];
[window_controller_ setAppWindow:this];
+ UpdateWindowMinMaxSize();
extension_keybinding_registry_.reset(new ExtensionKeybindingRegistryCocoa(
shell_window_->profile(),
@@ -1027,3 +1012,16 @@ void NativeAppWindowCocoa::UpdateRestoredBounds() {
if (IsRestored(*this))
restored_bounds_ = [window() frame];
}
+
+void NativeAppWindowCocoa::UpdateWindowMinMaxSize() {
+ gfx::Size min_size = shell_window_->size_constraints().GetMinimumSize();
+ [window() setContentMinSize:NSMakeSize(min_size.width(), min_size.height())];
+
+ gfx::Size max_size = shell_window_->size_constraints().GetMinimumSize();
+ const int kUnboundedSize = ShellWindow::SizeConstraints::kUnboundedSize;
+ CGFloat max_width = max_size.width() == kUnboundedSize ?
+ CGFLOAT_MAX : max_size.width();
+ CGFloat max_height = max_size.height() == kUnboundedSize ?
+ CGFLOAT_MAX : max_size.height();
+ [window() setContentMaxSize:NSMakeSize(max_width, max_height)];
+}
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_account_chooser.h b/chrome/browser/ui/cocoa/autofill/autofill_account_chooser.h
index 42f2cd9b35..75a50a7201 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_account_chooser.h
+++ b/chrome/browser/ui/cocoa/autofill/autofill_account_chooser.h
@@ -26,6 +26,7 @@ namespace autofill {
- (id)initWithFrame:(NSRect)frame
delegate:(autofill::AutofillDialogViewDelegate*)delegate;
- (void)update;
+- (void)performLayout;
@end
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_account_chooser.mm b/chrome/browser/ui/cocoa/autofill/autofill_account_chooser.mm
index 9294d30e22..fb2f8d2ba6 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_account_chooser.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_account_chooser.mm
@@ -121,7 +121,7 @@ void AddMenuItem(NSMenu *menu, id target, SEL selector, NSString* title,
self,
@selector(optionsMenuChanged:),
base::SysUTF16ToNSString(model->GetLabelAt(i)),
- model->GetCommandIdAt(i),
+ i,
model->IsEnabledAt(i),
model->IsItemCheckedAt(i));
}
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.h b/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.h
index 4cded2c499..78ce04bd43 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.h
+++ b/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.h
@@ -151,6 +151,7 @@ class AutofillDialogCocoa : public AutofillDialogView,
- (void)hideSignIn;
- (void)modelChanged;
- (void)updateErrorBubble;
+- (void)onSignInResize:(NSSize)size;
@end
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm b/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm
index 640f46dd4a..763f5b3f6b 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm
@@ -29,6 +29,13 @@
#include "ui/gfx/platform_font.h"
const CGFloat kAccountChooserHeight = 20.0;
+const CGFloat kMinimumContentsHeight = 101;
+
+// Height of all decorations & paddings on main dialog together.
+const CGFloat kDecorationHeight = kAccountChooserHeight +
+ autofill::kDetailTopPadding +
+ chrome_style::kClientBottomPadding +
+ chrome_style::kTitleTopPadding;
namespace autofill {
@@ -158,7 +165,8 @@ TestableAutofillDialogView* AutofillDialogCocoa::GetTestableView() {
}
void AutofillDialogCocoa::OnSignInResize(const gfx::Size& pref_size) {
- // TODO(groby): Implement Mac support for this.
+ [sheet_delegate_ onSignInResize:
+ NSMakeSize(pref_size.width(), pref_size.height())];
}
void AutofillDialogCocoa::SubmitForTesting() {
@@ -235,6 +243,12 @@ void AutofillDialogCocoa::OnConstrainedWindowClosed(
@interface AutofillDialogWindowController ()
+// Compute maximum allowed height for the dialog.
+- (CGFloat)maxHeight;
+
+// Update size constraints on sign-in container.
+- (void)updateSignInSizeConstraints;
+
// Notification that the WebContent's view frame has changed.
- (void)onContentViewFrameDidChange:(NSNotification*)notification;
@@ -338,8 +352,30 @@ void AutofillDialogCocoa::OnConstrainedWindowClosed(
[super dealloc];
}
+- (CGFloat)maxHeight {
+ NSRect dialogFrameRect = [[self window] frame];
+ NSRect browserFrameRect =
+ [webContents_->GetView()->GetTopLevelNativeWindow() frame];
+ dialogFrameRect.size.height =
+ NSMaxY(dialogFrameRect) - NSMinY(browserFrameRect);
+ dialogFrameRect = [[self window] contentRectForFrameRect:dialogFrameRect];
+ return NSHeight(dialogFrameRect);
+}
+
+- (void)updateSignInSizeConstraints {
+ // Adjust for the size of all decorations and paddings outside main content.
+ CGFloat minHeight = kMinimumContentsHeight - kDecorationHeight;
+ CGFloat maxHeight = std::max([self maxHeight] - kDecorationHeight, minHeight);
+ CGFloat width = NSWidth([[[self window] contentView] frame]);
+
+ [signInContainer_ constrainSizeToMinimum:NSMakeSize(width, minHeight)
+ maximum:NSMakeSize(width, maxHeight)];
+}
+
- (void)onContentViewFrameDidChange:(NSNotification*)notification {
- [self requestRelayout];
+ [self updateSignInSizeConstraints];
+ if ([[signInContainer_ view] isHidden])
+ [self requestRelayout];
}
- (void)cancelRelayout {
@@ -355,26 +391,21 @@ void AutofillDialogCocoa::OnConstrainedWindowClosed(
- (NSSize)preferredSize {
NSSize contentSize;
- // TODO(groby): Currently, keep size identical to main container.
- // Change to allow autoresize of web contents.
- contentSize = [mainContainer_ preferredSize];
+ // Overall size is determined by either main container or sign in view.
+ if (![[mainContainer_ view] isHidden])
+ contentSize = [mainContainer_ preferredSize];
+ else
+ contentSize = [signInContainer_ preferredSize];
+
+ // Always make room for the header.
NSSize headerSize = NSMakeSize(contentSize.width, kAccountChooserHeight);
- NSSize size = NSMakeSize(
- std::max(contentSize.width, headerSize.width),
- contentSize.height + headerSize.height + autofill::kDetailTopPadding);
- size.height += chrome_style::kClientBottomPadding +
- chrome_style::kTitleTopPadding;
+ NSSize size = contentSize;
+ size.height += kDecorationHeight;
// Show as much of the main view as is possible without going past the
// bottom of the browser window.
- NSRect dialogFrameRect = [[self window] frame];
- NSRect browserFrameRect =
- [webContents_->GetView()->GetTopLevelNativeWindow() frame];
- dialogFrameRect.size.height =
- NSMaxY(dialogFrameRect) - NSMinY(browserFrameRect);
- dialogFrameRect = [[self window] contentRectForFrameRect:dialogFrameRect];
- size.height = std::min(NSHeight(dialogFrameRect), size.height);
+ size.height = std::min(size.height, [self maxHeight]);
if (![[overlayController_ view] isHidden]) {
CGFloat height = [overlayController_ heightForWidth:size.width];
@@ -420,6 +451,7 @@ void AutofillDialogCocoa::OnConstrainedWindowClosed(
[titleTextField_ setFrame:titleRect];
[accountChooser_ setFrame:headerRect];
+ [accountChooser_ performLayout];
if ([[signInContainer_ view] isHidden]) {
[[mainContainer_ view] setFrame:mainRect];
[mainContainer_ performLayout];
@@ -523,6 +555,7 @@ void AutofillDialogCocoa::OnConstrainedWindowClosed(
}
- (content::NavigationController*)showSignIn {
+ [self updateSignInSizeConstraints];
[signInContainer_ loadSignInPage];
[[mainContainer_ view] setHidden:YES];
[[signInContainer_ view] setHidden:NO];
@@ -554,6 +587,11 @@ void AutofillDialogCocoa::OnConstrainedWindowClosed(
[mainContainer_ updateErrorBubble];
}
+- (void)onSignInResize:(NSSize)size {
+ [signInContainer_ setPreferredSize:size];
+ [self requestRelayout];
+}
+
@end
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_overlay_controller.mm b/chrome/browser/ui/cocoa/autofill/autofill_overlay_controller.mm
index 8b3ac3ed3b..12a984cea2 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_overlay_controller.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_overlay_controller.mm
@@ -96,7 +96,12 @@ SkColor kSubtleBorderColor = 0xffdfdfdf;
[label_ setFont:message.font.GetNativeFont()];
[label_ setStringValue:base::SysUTF16ToNSString(message.text)];
[label_ setTextColor:gfx::SkColorToCalibratedNSColor(message.text_color)];
- [label_ sizeToFit];
+
+ // Resize only height, preserve width. This guarantees text stays centered in
+ // the dialog.
+ NSSize labelSize = [label_ frame].size;
+ labelSize.height = [[label_ cell] cellSize].height;
+ [label_ setFrameSize:labelSize];
[self setHidden:message.text.empty()];
}
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_section_container.mm b/chrome/browser/ui/cocoa/autofill/autofill_section_container.mm
index 17c03c2e58..59343e0d28 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_section_container.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_section_container.mm
@@ -125,6 +125,9 @@ bool CompareInputRows(const autofill::DetailInput* input1,
// Create a view with all inputs requested by |delegate_|. Autoreleased.
- (LayoutView*)makeInputControls;
+// Refresh all field icons based on |delegate_| status.
+- (void)updateFieldIcons;
+
@end
@implementation AutofillSectionContainer
@@ -413,11 +416,9 @@ bool CompareInputRows(const autofill::DetailInput* input1,
[self validateFor:autofill::VALIDATE_EDIT];
}
- // Update the icon for the textfield.
- gfx::Image icon = delegate_->IconForField(type, fieldValue);
- if (!icon.IsEmpty()) {
- [[textfield cell] setIcon:icon.ToNSImage()];
- }
+ // Update the icon if necessary.
+ if (delegate_->FieldControlsIcons(type))
+ [self updateFieldIcons];
}
- (autofill::ServerFieldType)fieldTypeForControl:(NSControl*)control {
@@ -472,23 +473,17 @@ bool CompareInputRows(const autofill::DetailInput* input1,
NSControl<AutofillInputField>* field = [inputs_ viewWithTag:iter->type];
DCHECK(field);
- [field setEnabled:iter->editable];
+ // TODO(groby): We need to account for the fact editability state can change
+ // after any input in the same section is edited by the user.
+ [field setEnabled:delegate_->InputIsEditable(*iter, section_)];
if (shouldClobber || [field isDefault]) {
[field setFieldValue:base::SysUTF16ToNSString(iter->initial_value)];
- AutofillTextField* textField =
- base::mac::ObjCCast<AutofillTextField>(field);
- if (textField) {
- gfx::Image icon =
- delegate_->IconForField(iter->type, iter->initial_value);
- if (!icon.IsEmpty()) {
- [[textField cell] setIcon:icon.ToNSImage()];
- }
- }
}
if (shouldClobber)
[field setValidityMessage:@""];
}
+ [self updateFieldIcons];
[self modelChanged];
}
@@ -573,9 +568,6 @@ bool CompareInputRows(const autofill::DetailInput* input1,
[[AutofillTextField alloc] init]);
[[field cell] setPlaceholderString:
l10n_util::GetNSStringWithFixup(input.placeholder_text_rid)];
- [[field cell] setIcon:
- delegate_->IconForField(
- input.type, input.initial_value).AsNSImage()];
[field setDefaultValue:@""];
control.reset(field.release());
}
@@ -591,9 +583,29 @@ bool CompareInputRows(const autofill::DetailInput* input1,
layout->AddView(control);
}
+ [self updateFieldIcons];
return view.autorelease();
}
+- (void)updateFieldIcons {
+ autofill::FieldValueMap fieldValues;
+ for (NSControl<AutofillInputField>* input in [inputs_ subviews]) {
+ DCHECK([input isKindOfClass:[NSControl class]]);
+ DCHECK([input conformsToProtocol:@protocol(AutofillInputField)]);
+ autofill::ServerFieldType fieldType = [self fieldTypeForControl:input];
+ NSString* value = [input fieldValue];
+ fieldValues[fieldType] = base::SysNSStringToUTF16(value);
+ }
+
+ autofill::FieldIconMap fieldIcons = delegate_->IconsForFields(fieldValues);
+ for (autofill::FieldIconMap::const_iterator iter = fieldIcons.begin();
+ iter!= fieldIcons.end(); ++iter) {
+ AutofillTextField* textfield = base::mac::ObjCCastStrict<AutofillTextField>(
+ [inputs_ viewWithTag:iter->first]);
+ [[textfield cell] setIcon:iter->second.ToNSImage()];
+ }
+}
+
@end
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_sign_in_container.h b/chrome/browser/ui/cocoa/autofill/autofill_sign_in_container.h
index d16cc7e0e2..0279c2087c 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_sign_in_container.h
+++ b/chrome/browser/ui/cocoa/autofill/autofill_sign_in_container.h
@@ -25,11 +25,18 @@ class NavigationController;
autofill::AutofillDialogCocoa* dialog_; // Not owned.
scoped_ptr<content::WebContents> webContents_;
scoped_ptr<autofill::AutofillDialogSignInDelegate> signInDelegate_;
+
+ NSSize maxSize_;
+ NSSize minSize_;
+ NSSize preferredSize_;
}
+@property(assign, nonatomic) NSSize preferredSize;
+
- (id)initWithDialog:(autofill::AutofillDialogCocoa*)dialog;
- (void)loadSignInPage;
- (content::NavigationController*)navigationController;
+- (void)constrainSizeToMinimum:(NSSize)minSize maximum:(NSSize)maximum;
@end
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_sign_in_container.mm b/chrome/browser/ui/cocoa/autofill/autofill_sign_in_container.mm
index 05cb12e7c3..02c1b4d5fe 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_sign_in_container.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_sign_in_container.mm
@@ -16,6 +16,8 @@
@implementation AutofillSignInContainer
+@synthesize preferredSize = preferredSize_;
+
- (id)initWithDialog:(autofill::AutofillDialogCocoa*)dialog {
if (self = [super init]) {
dialog_ = dialog;
@@ -33,12 +35,18 @@
- (void)loadSignInPage {
DCHECK(webContents_.get());
+
+ // Prevent accidentaly empty |maxSize_|.
+ if (NSEqualSizes(NSMakeSize(0, 0), maxSize_)) {
+ maxSize_ = [[[self view] window] frame].size;
+ }
+
signInDelegate_.reset(
new autofill::AutofillDialogSignInDelegate(
dialog_, webContents_.get(),
dialog_->delegate()->GetWebContents()->GetDelegate(),
- // TODO(groby): Implement proper minimum and maximum sizing on Mac.
- dialog_->GetSize(), dialog_->GetSize()));
+ gfx::Size(NSSizeToCGSize(minSize_)),
+ gfx::Size(NSSizeToCGSize(maxSize_))));
webContents_->GetController().LoadURL(
autofill::wallet::GetSignInUrl(),
content::Referrer(),
@@ -50,4 +58,25 @@
return &webContents_->GetController();
}
+- (void)constrainSizeToMinimum:(NSSize)minSize maximum:(NSSize)maxSize {
+ minSize_ = minSize;
+ maxSize_ = maxSize;
+
+ // Notify the web contents of its new auto-resize limits.
+ if (signInDelegate_ && ![[self view] isHidden]) {
+ signInDelegate_->UpdateLimitsAndEnableAutoResize(
+ gfx::Size(NSSizeToCGSize(minSize_)),
+ gfx::Size(NSSizeToCGSize(maxSize_)));
+ }
+}
+
+- (void)setPreferredSize:(NSSize)size {
+ preferredSize_ = size;
+
+ // Always request re-layout if preferredSize changes.
+ id delegate = [[[self view] window] windowController];
+ if ([delegate respondsToSelector:@selector(requestRelayout)])
+ [delegate performSelector:@selector(requestRelayout)];
+}
+
@end
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_textfield.mm b/chrome/browser/ui/cocoa/autofill/autofill_textfield.mm
index cf8658ae2b..32df150eb1 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_textfield.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_textfield.mm
@@ -79,7 +79,6 @@ const CGFloat kGap = 6.0; // gap between icon and text.
- (void)setValidityMessage:(NSString*)validityMessage {
validityMessage_.reset([validityMessage copy]);
[[self cell] setInvalid:[self invalid]];
- [self setNeedsDisplay:YES];
}
- (BOOL)invalid {
@@ -93,12 +92,18 @@ const CGFloat kGap = 6.0; // gap between icon and text.
@synthesize invalid = invalid_;
@synthesize defaultValue = defaultValue_;
+- (void)setInvalid:(BOOL)invalid {
+ invalid_ = invalid;
+ [[self controlView] setNeedsDisplay:YES];
+}
+
- (NSImage*) icon{
return icon_;
}
- (void)setIcon:(NSImage*) icon {
icon_.reset([icon retain]);
+ [[self controlView] setNeedsDisplay:YES];
}
- (NSString*)fieldValue {
diff --git a/chrome/browser/ui/cocoa/browser/avatar_button_controller_unittest.mm b/chrome/browser/ui/cocoa/browser/avatar_button_controller_unittest.mm
index bae78026db..a014160d25 100644
--- a/chrome/browser/ui/cocoa/browser/avatar_button_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/browser/avatar_button_controller_unittest.mm
@@ -5,19 +5,26 @@
#import "chrome/browser/ui/cocoa/browser/avatar_button_controller.h"
#include "base/mac/scoped_nsobject.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
+#include "chrome/browser/bookmarks/bookmark_test_helpers.h"
#include "chrome/browser/managed_mode/managed_user_service.h"
#include "chrome/browser/managed_mode/managed_user_service_factory.h"
+#include "chrome/browser/prefs/pref_service_syncable.h"
+#include "chrome/browser/search_engines/template_url_service_factory.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_window.h"
#import "chrome/browser/ui/cocoa/browser/avatar_menu_bubble_controller.h"
#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
#include "chrome/browser/ui/cocoa/info_bubble_window.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_profile.h"
class AvatarButtonControllerTest : public CocoaProfileTest {
public:
- virtual void SetUp() {
+ virtual void SetUp() OVERRIDE {
CocoaProfileTest::SetUp();
ASSERT_TRUE(browser());
@@ -26,7 +33,7 @@ class AvatarButtonControllerTest : public CocoaProfileTest {
[[controller_ view] setHidden:YES];
}
- virtual void TearDown() {
+ virtual void TearDown() OVERRIDE {
browser()->window()->Close();
CocoaProfileTest::TearDown();
}
@@ -82,18 +89,31 @@ TEST_F(AvatarButtonControllerTest, DoubleOpen) {
}
TEST_F(AvatarButtonControllerTest, ManagedUserLabel) {
- // Create a second profile to enable the avatar menu.
- testing_profile_manager()->CreateTestingProfile("p2");
-
+ DCHECK(!profile()->IsManaged());
EXPECT_FALSE([controller() labelButtonView]);
- // Transform the first profile to a managed user profile.
- ManagedUserServiceFactory::GetForProfile(profile())->InitForTesting();
-
+ // Create a second, managed profile to enable the avatar menu.
+ std::string name = "p2";
+ TestingProfile* profile = testing_profile_manager()->CreateTestingProfile(
+ name, scoped_ptr<PrefServiceSyncable>(), ASCIIToUTF16(name), 0, "asdf");
+ EXPECT_TRUE(profile->IsManaged());
+
+ // http://crbug.com/39725
+ TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
+ profile, &TemplateURLServiceFactory::BuildInstanceFor);
+ AutocompleteClassifierFactory::GetInstance()->SetTestingFactoryAndUse(
+ profile, &AutocompleteClassifierFactory::BuildInstanceFor);
+ profile->CreateBookmarkModel(true);
+ test::WaitForBookmarkModelToLoad(profile);
+
+ Browser* browser =
+ new Browser(Browser::CreateParams(profile, chrome::GetActiveDesktop()));
// Build a new controller to check if it is initialized correctly for a
// managed user profile.
base::scoped_nsobject<AvatarButtonController> controller(
- [[AvatarButtonController alloc] initWithBrowser:browser()]);
+ [[AvatarButtonController alloc] initWithBrowser:browser]);
EXPECT_TRUE([controller labelButtonView]);
+
+ browser->window()->Close();
}
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa.h b/chrome/browser/ui/cocoa/browser_window_cocoa.h
index db7c621f8b..0370bc0090 100644
--- a/chrome/browser/ui/cocoa/browser_window_cocoa.h
+++ b/chrome/browser/ui/cocoa/browser_window_cocoa.h
@@ -127,9 +127,6 @@ class BrowserWindowCocoa :
bool* is_keyboard_shortcut) OVERRIDE;
virtual void HandleKeyboardEvent(
const content::NativeWebKeyboardEvent& event) OVERRIDE;
- virtual void ShowCreateChromeAppShortcutsDialog(
- Profile* profile,
- const extensions::Extension* app) OVERRIDE;
virtual void Cut() OVERRIDE;
virtual void Copy() OVERRIDE;
virtual void Paste() OVERRIDE;
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa.mm b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
index d3e9ac8a27..230ba44f46 100644
--- a/chrome/browser/ui/cocoa/browser_window_cocoa.mm
+++ b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
@@ -44,7 +44,6 @@
#import "chrome/browser/ui/cocoa/website_settings_bubble_controller.h"
#include "chrome/browser/ui/search/search_model.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/browser/ui/web_applications/web_app_ui.h"
#include "chrome/browser/web_applications/web_app.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
@@ -104,13 +103,6 @@ NSPoint GetPointForBubble(content::WebContents* web_contents,
return point;
}
-void CreateShortcuts(const ShellIntegration::ShortcutInfo& shortcut_info) {
- // creation_locations will be ignored by CreatePlatformShortcuts on Mac.
- ShellIntegration::ShortcutLocations creation_locations;
- web_app::CreateShortcuts(shortcut_info, creation_locations,
- web_app::SHORTCUT_CREATION_BY_USER);
-}
-
} // namespace
BrowserWindowCocoa::BrowserWindowCocoa(Browser* browser,
@@ -598,14 +590,6 @@ void BrowserWindowCocoa::HandleKeyboardEvent(
[BrowserWindowUtils handleKeyboardEvent:event.os_event inWindow:window()];
}
-void BrowserWindowCocoa::ShowCreateChromeAppShortcutsDialog(
- Profile* profile, const extensions::Extension* app) {
- // Normally we would show a dialog, but since we always create the app
- // shortcut in /Applications there are no options for the user to choose.
- web_app::UpdateShortcutInfoAndIconForApp(*app, profile,
- base::Bind(&CreateShortcuts));
-}
-
void BrowserWindowCocoa::Cut() {
[NSApp sendAction:@selector(cut:) to:nil from:nil];
}
diff --git a/chrome/browser/ui/cocoa/download/download_item_controller.mm b/chrome/browser/ui/cocoa/download/download_item_controller.mm
index 1c7d29561c..8981e4084d 100644
--- a/chrome/browser/ui/cocoa/download/download_item_controller.mm
+++ b/chrome/browser/ui/cocoa/download/download_item_controller.mm
@@ -172,7 +172,7 @@ class DownloadShelfContextMenuMac : public DownloadShelfContextMenu {
*font_list_, kTextWidth));
confirmButtonTitle =
base::SysUTF16ToNSString(downloadModel->GetWarningConfirmButtonText());
- if (downloadModel->IsMalicious())
+ if (downloadModel->MightBeMalicious())
alertIcon = rb.GetNativeImageNamed(IDR_SAFEBROWSING_WARNING).ToNSImage();
else
alertIcon = rb.GetNativeImageNamed(IDR_WARNING).ToNSImage();
diff --git a/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm b/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm
index a17f3d8cde..92daa8e133 100644
--- a/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm
+++ b/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm
@@ -15,6 +15,7 @@
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/extensions/extension_toolbar_model.h"
+#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sessions/session_tab_helper.h"
#include "chrome/browser/ui/browser.h"
@@ -137,8 +138,11 @@ const CGFloat kBrowserActionBubbleYOffset = 3.0;
toIndex:(NSUInteger)index
animate:(BOOL)animate;
-// Handles when the given BrowserActionButton object is clicked.
-- (void)browserActionClicked:(BrowserActionButton*)button;
+// Handles when the given BrowserActionButton object is clicked and whether
+// it should grant tab permissions. API-simulated clicks should not grant.
+- (BOOL)browserActionClicked:(BrowserActionButton*)button
+ shouldGrant:(BOOL)shouldGrant;
+- (BOOL)browserActionClicked:(BrowserActionButton*)button;
// Returns whether the given extension should be displayed. Only displays
// incognito-enabled extensions in incognito mode. Otherwise returns YES.
@@ -238,6 +242,17 @@ class ExtensionServiceObserverBridge : public content::NotificationObserver,
[owner_ resizeContainerAndAnimate:NO];
}
+ virtual bool BrowserActionShowPopup(const Extension* extension) OVERRIDE {
+ // Do not override other popups and only show in active window.
+ ExtensionPopupController* popup = [ExtensionPopupController popup];
+ if (popup || !browser_->window()->IsActive())
+ return false;
+
+ BrowserActionButton* button = [owner_ buttonForExtension:extension];
+ return button && [owner_ browserActionClicked:button
+ shouldGrant:NO];
+ }
+
private:
// The object we need to inform when we get a notification. Weak. Owns us.
BrowserActionsController* owner_;
@@ -739,10 +754,12 @@ class ExtensionServiceObserverBridge : public content::NotificationObserver,
}
}
-- (void)browserActionClicked:(BrowserActionButton*)button {
+- (BOOL)browserActionClicked:(BrowserActionButton*)button
+ shouldGrant:(BOOL)shouldGrant {
const Extension* extension = [button extension];
GURL popupUrl;
- switch (toolbarModel_->ExecuteBrowserAction(extension, browser_, &popupUrl)) {
+ switch (toolbarModel_->ExecuteBrowserAction(extension, browser_, &popupUrl,
+ shouldGrant)) {
case ExtensionToolbarModel::ACTION_NONE:
break;
case ExtensionToolbarModel::ACTION_SHOW_POPUP: {
@@ -752,17 +769,24 @@ class ExtensionServiceObserverBridge : public content::NotificationObserver,
anchoredAt:arrowPoint
arrowLocation:info_bubble::kTopRight
devMode:NO];
- break;
+ return YES;
}
}
+ return NO;
+}
+
+- (BOOL)browserActionClicked:(BrowserActionButton*)button {
+ return [self browserActionClicked:button
+ shouldGrant:YES];
}
- (BOOL)shouldDisplayBrowserAction:(const Extension*)extension {
// Only display incognito-enabled extensions while in incognito mode.
return
(!profile_->IsOffTheRecord() ||
- extensions::ExtensionSystem::Get(profile_)->extension_service()->
- IsIncognitoEnabled(extension->id()));
+ extension_util::IsIncognitoEnabled(
+ extension->id(),
+ extensions::ExtensionSystem::Get(profile_)->extension_service()));
}
- (void)showChevronIfNecessaryInFrame:(NSRect)frame animate:(BOOL)animate {
diff --git a/chrome/browser/ui/cocoa/first_run_dialog.mm b/chrome/browser/ui/cocoa/first_run_dialog.mm
index 2ffa267f43..4117e62506 100644
--- a/chrome/browser/ui/cocoa/first_run_dialog.mm
+++ b/chrome/browser/ui/cocoa/first_run_dialog.mm
@@ -29,7 +29,7 @@
#include "chrome/browser/browser_process.h"
#include "chrome/common/pref_names.h"
#include "chrome/installer/util/google_update_settings.h"
-#import "components/breakpad/breakpad_mac.h"
+#import "components/breakpad/app/breakpad_mac.h"
#endif
@interface FirstRunDialogController (PrivateMethods)
diff --git a/chrome/browser/ui/cocoa/infobars/infobar_cocoa.h b/chrome/browser/ui/cocoa/infobars/infobar_cocoa.h
index e8f1a83d54..7419f31bc0 100644
--- a/chrome/browser/ui/cocoa/infobars/infobar_cocoa.h
+++ b/chrome/browser/ui/cocoa/infobars/infobar_cocoa.h
@@ -6,6 +6,7 @@
#define CHROME_BROWSER_UI_COCOA_INFOBARS_INFOBAR_COCOA_H_
#include "base/mac/scoped_nsobject.h"
+#include "base/memory/weak_ptr.h"
#include "chrome/browser/infobars/infobar.h"
@class InfoBarController;
@@ -28,10 +29,15 @@ class InfoBarCocoa : public InfoBar {
void RemoveSelfCocoa();
InfoBarService* OwnerCocoa();
+ base::WeakPtr<InfoBarCocoa> GetWeakPtr();
+
private:
// The Objective-C class that contains most of the info bar logic.
base::scoped_nsobject<InfoBarController> controller_;
+ // Used to vend the link back to this for |controller_|.
+ base::WeakPtrFactory<InfoBarCocoa> weak_ptr_factory_;
+
DISALLOW_COPY_AND_ASSIGN(InfoBarCocoa);
};
diff --git a/chrome/browser/ui/cocoa/infobars/infobar_cocoa.mm b/chrome/browser/ui/cocoa/infobars/infobar_cocoa.mm
index c015171d91..398cd5fe39 100644
--- a/chrome/browser/ui/cocoa/infobars/infobar_cocoa.mm
+++ b/chrome/browser/ui/cocoa/infobars/infobar_cocoa.mm
@@ -12,7 +12,8 @@ const int InfoBar::kMaximumArrowTargetHalfWidth = 14;
const int InfoBar::kDefaultBarTargetHeight = 36;
InfoBarCocoa::InfoBarCocoa(InfoBarService* owner, InfoBarDelegate* delegate)
- : InfoBar(owner, delegate) {
+ : InfoBar(owner, delegate),
+ weak_ptr_factory_(this) {
}
InfoBarCocoa::~InfoBarCocoa() {
@@ -25,3 +26,7 @@ void InfoBarCocoa::RemoveSelfCocoa() {
InfoBarService* InfoBarCocoa::OwnerCocoa() {
return owner();
}
+
+base::WeakPtr<InfoBarCocoa> InfoBarCocoa::GetWeakPtr() {
+ return weak_ptr_factory_.GetWeakPtr();
+}
diff --git a/chrome/browser/ui/cocoa/infobars/infobar_container_controller.mm b/chrome/browser/ui/cocoa/infobars/infobar_container_controller.mm
index f6110909f5..ffaa38c83d 100644
--- a/chrome/browser/ui/cocoa/infobars/infobar_container_controller.mm
+++ b/chrome/browser/ui/cocoa/infobars/infobar_container_controller.mm
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#import "chrome/browser/ui/cocoa/infobars/infobar_container_controller.h"
+
#include "base/logging.h"
#include "base/mac/mac_util.h"
#include "base/message_loop/message_loop.h"
@@ -12,7 +14,6 @@
#import "chrome/browser/ui/cocoa/browser_window_controller.h"
#import "chrome/browser/ui/cocoa/infobars/infobar_cocoa.h"
#import "chrome/browser/ui/cocoa/infobars/infobar_container_cocoa.h"
-#import "chrome/browser/ui/cocoa/infobars/infobar_container_controller.h"
#import "chrome/browser/ui/cocoa/infobars/infobar_controller.h"
#import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
#import "chrome/browser/ui/cocoa/view_id_util.h"
@@ -99,8 +100,10 @@
}
- (void)removeInfoBar:(InfoBarCocoa*)infobar {
- [infobar->controller() infobarWillClose];
- [self removeController:infobar->controller()];
+ InfoBarController* controller = infobar->controller();
+ [controller infobarWillClose];
+ infobar->set_controller(nil);
+ [self removeController:controller];
base::MessageLoop::current()->DeleteSoon(FROM_HERE, infobar);
}
diff --git a/chrome/browser/ui/cocoa/infobars/infobar_controller.h b/chrome/browser/ui/cocoa/infobars/infobar_controller.h
index 5948169600..0699d372dc 100644
--- a/chrome/browser/ui/cocoa/infobars/infobar_controller.h
+++ b/chrome/browser/ui/cocoa/infobars/infobar_controller.h
@@ -5,6 +5,7 @@
#import <Cocoa/Cocoa.h>
#include "base/mac/scoped_nsobject.h"
+#include "base/memory/weak_ptr.h"
@protocol InfoBarContainerControllerBase;
class InfoBarCocoa;
@@ -19,7 +20,7 @@ class InfoBarService;
@interface InfoBarController : NSViewController<NSTextViewDelegate> {
@private
id<InfoBarContainerControllerBase> containerController_; // weak, owns us
- InfoBarCocoa* infobar_; // weak, owns us
+ base::WeakPtr<InfoBarCocoa> infobar_;
@protected
IBOutlet InfoBarGradientView* infoBarView_;
@@ -41,7 +42,7 @@ class InfoBarService;
@property(nonatomic, readonly) InfoBarDelegate* delegate;
@property(nonatomic, readonly) InfoBarCocoa* infobar;
-// Initializes a new InfoBarController.
+// Initializes a new InfoBarController and takes a WeakPtr to |infobar|.
- (id)initWithInfoBar:(InfoBarCocoa*)infobar;
// Returns YES if the infobar is owned. If this is NO, it is not safe to call
diff --git a/chrome/browser/ui/cocoa/infobars/infobar_controller.mm b/chrome/browser/ui/cocoa/infobars/infobar_controller.mm
index 3a7d0d564f..1385f81d21 100644
--- a/chrome/browser/ui/cocoa/infobars/infobar_controller.mm
+++ b/chrome/browser/ui/cocoa/infobars/infobar_controller.mm
@@ -29,13 +29,12 @@
@implementation InfoBarController
@synthesize containerController = containerController_;
-@synthesize infobar = infobar_;
- (id)initWithInfoBar:(InfoBarCocoa*)infobar {
if ((self = [super initWithNibName:@"InfoBar"
bundle:base::mac::FrameworkBundle()])) {
DCHECK(infobar);
- infobar_ = infobar;
+ infobar_ = infobar->GetWeakPtr();
}
return self;
}
@@ -79,6 +78,10 @@
[super dealloc];
}
+- (InfoBarCocoa*)infobar {
+ return infobar_.get();
+}
+
// Called when someone clicks on the embedded link.
- (BOOL)textView:(NSTextView*)textView
clickedOnLink:(id)link
@@ -89,7 +92,7 @@
}
- (BOOL)isOwned {
- return infobar_->OwnerCocoa() != NULL;
+ return infobar_ && infobar_->OwnerCocoa() != NULL;
}
// Called when someone clicks on the ok button.
diff --git a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
index 6d77910ad7..e0efa58bbc 100644
--- a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
+++ b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
@@ -925,7 +925,7 @@ void ContentSettingMediaStreamBubbleModel::SetMediaMenus() {
if (!cameras.empty()) {
std::string preferred_camera;
if (requested_camera.empty()) {
- preferred_camera = prefs->GetString(prefs::kDefaultAudioCaptureDevice);
+ preferred_camera = prefs->GetString(prefs::kDefaultVideoCaptureDevice);
camera_menu.disabled = false;
} else {
// Disable the menu since the website is managing the camera devices
diff --git a/chrome/browser/ui/extensions/application_launch.cc b/chrome/browser/ui/extensions/application_launch.cc
index d3eceb7860..d68404f0d3 100644
--- a/chrome/browser/ui/extensions/application_launch.cc
+++ b/chrome/browser/ui/extensions/application_launch.cc
@@ -27,7 +27,6 @@
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/extensions/extension_enable_flow.h"
#include "chrome/browser/ui/extensions/extension_enable_flow_delegate.h"
-#include "chrome/browser/ui/host_desktop.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/web_applications/web_app.h"
#include "chrome/common/chrome_switches.h"
@@ -59,6 +58,60 @@ using extensions::ExtensionPrefs;
namespace {
+// Attempts to launch a packaged app, prompting the user to enable it if
+// necessary. If a prompt is required it will be shown inside the AppList.
+// This class manages its own lifetime.
+class EnableViaAppListFlow : public ExtensionEnableFlowDelegate {
+ public:
+ EnableViaAppListFlow(ExtensionService* service,
+ Profile* profile,
+ const std::string& extension_id,
+ const base::Closure& callback)
+ : service_(service),
+ profile_(profile),
+ extension_id_(extension_id),
+ callback_(callback) {
+ }
+
+ virtual ~EnableViaAppListFlow() {
+ }
+
+ void Run() {
+ DCHECK(!service_->IsExtensionEnabled(extension_id_));
+ flow_.reset(new ExtensionEnableFlow(profile_, extension_id_, this));
+ flow_->StartForCurrentlyNonexistentWindow(
+ base::Bind(&EnableViaAppListFlow::ShowAppList, base::Unretained(this)));
+ }
+
+ private:
+ gfx::NativeWindow ShowAppList() {
+ AppListService::Get()->Show();
+ return AppListService::Get()->GetAppListWindow();
+ }
+
+ // ExtensionEnableFlowDelegate overrides.
+ virtual void ExtensionEnableFlowFinished() OVERRIDE {
+ const Extension* extension =
+ service_->GetExtensionById(extension_id_, false);
+ if (!extension)
+ return;
+ callback_.Run();
+ delete this;
+ }
+
+ virtual void ExtensionEnableFlowAborted(bool user_initiated) OVERRIDE {
+ delete this;
+ }
+
+ ExtensionService* service_;
+ Profile* profile_;
+ std::string extension_id_;
+ base::Closure callback_;
+ scoped_ptr<ExtensionEnableFlow> flow_;
+
+ DISALLOW_COPY_AND_ASSIGN(EnableViaAppListFlow);
+};
+
// Get the launch URL for a given extension, with optional override/fallback.
// |override_url|, if non-empty, will be preferred over the extension's
// launch url.
@@ -115,55 +168,44 @@ ui::WindowShowState DetermineWindowShowState(
return ui::SHOW_STATE_DEFAULT;
}
-WebContents* OpenApplicationWindow(
- Profile* profile,
- const Extension* extension,
- extension_misc::LaunchContainer container,
- const GURL& url_input,
- Browser** app_browser,
- const gfx::Rect& override_bounds) {
+WebContents* OpenApplicationWindow(const AppLaunchParams& params) {
+ Profile* const profile = params.profile;
+ const extensions::Extension* const extension = params.extension;
+ const GURL url_input = params.override_url;
+
DCHECK(!url_input.is_empty() || extension);
GURL url = UrlForExtension(extension, url_input);
+ Browser::CreateParams browser_params(
+ Browser::TYPE_POPUP, profile, params.desktop_type);
- std::string app_name;
- app_name = extension ?
+ browser_params.app_name = extension ?
web_app::GenerateApplicationNameFromExtensionId(extension->id()) :
web_app::GenerateApplicationNameFromURL(url);
- Browser::Type type = Browser::TYPE_POPUP;
-
- gfx::Rect window_bounds;
- if (extension) {
- window_bounds.set_width(
+ if (!params.override_bounds.IsEmpty()) {
+ browser_params.initial_bounds = params.override_bounds;
+ } else if (extension) {
+ browser_params.initial_bounds.set_width(
extensions::AppLaunchInfo::GetLaunchWidth(extension));
- window_bounds.set_height(
+ browser_params.initial_bounds.set_height(
extensions::AppLaunchInfo::GetLaunchHeight(extension));
}
- if (!override_bounds.IsEmpty())
- window_bounds = override_bounds;
- Browser::CreateParams params(type, profile, chrome::GetActiveDesktop());
- params.app_name = app_name;
- params.initial_bounds = window_bounds;
- params.initial_show_state = DetermineWindowShowState(profile,
- container,
- extension);
+ browser_params.initial_show_state = DetermineWindowShowState(profile,
+ params.container,
+ extension);
Browser* browser = NULL;
#if defined(OS_WIN)
// On Windows 8's single window Metro mode we don't allow multiple Chrome
// windows to be created. We instead attempt to reuse an existing Browser
// window.
- if (win8::IsSingleWindowMetroMode()) {
- browser = chrome::FindBrowserWithProfile(
- profile, chrome::HOST_DESKTOP_TYPE_NATIVE);
- }
+ if (win8::IsSingleWindowMetroMode())
+ browser = chrome::FindBrowserWithProfile(profile, params.desktop_type);
+
#endif
if (!browser)
- browser = new Browser(params);
-
- if (app_browser)
- *app_browser = browser;
+ browser = new Browser(browser_params);
WebContents* web_contents = chrome::AddSelectedTabWithURL(
browser, url, content::PAGE_TRANSITION_AUTO_TOPLEVEL);
@@ -178,19 +220,20 @@ WebContents* OpenApplicationWindow(
return web_contents;
}
-WebContents* OpenApplicationTab(Profile* profile,
- const Extension* extension,
- const GURL& override_url,
- WindowOpenDisposition disposition) {
+WebContents* OpenApplicationTab(const AppLaunchParams& launch_params) {
+ Profile* const profile = launch_params.profile;
+ const extensions::Extension* extension = launch_params.extension;
+ WindowOpenDisposition disposition = launch_params.disposition;
+
Browser* browser = chrome::FindTabbedBrowser(profile,
false,
- chrome::GetActiveDesktop());
+ launch_params.desktop_type);
WebContents* contents = NULL;
if (!browser) {
// No browser for this profile, need to open a new one.
browser = new Browser(Browser::CreateParams(Browser::TYPE_TABBED,
profile,
- chrome::GetActiveDesktop()));
+ launch_params.desktop_type));
browser->window()->Show();
// There's no current tab in this browser window, so add a new one.
disposition = NEW_FOREGROUND_TAB;
@@ -214,7 +257,7 @@ WebContents* OpenApplicationTab(Profile* profile,
if (launch_type == ExtensionPrefs::LAUNCH_PINNED)
add_type |= TabStripModel::ADD_PINNED;
- GURL extension_url = UrlForExtension(extension, override_url);
+ GURL extension_url = UrlForExtension(extension, launch_params.override_url);
chrome::NavigateParams params(browser, extension_url,
content::PAGE_TRANSITION_AUTO_TOPLEVEL);
params.tabstrip_add_types = add_type;
@@ -271,72 +314,17 @@ WebContents* OpenApplicationTab(Profile* profile,
return contents;
}
-// Attempts to launch a packaged app, prompting the user to enable it if
-// necessary. If a prompt is required it will be shown inside the AppList.
-// This class manages its own lifetime.
-class EnableViaAppListFlow : public ExtensionEnableFlowDelegate {
- public:
- EnableViaAppListFlow(ExtensionService* service,
- Profile* profile,
- const std::string& extension_id,
- const base::Closure& callback)
- : service_(service),
- profile_(profile),
- extension_id_(extension_id),
- callback_(callback) {
- }
-
- virtual ~EnableViaAppListFlow() {
- }
-
- void Run() {
- DCHECK(!service_->IsExtensionEnabled(extension_id_));
- flow_.reset(new ExtensionEnableFlow(profile_, extension_id_, this));
- flow_->StartForCurrentlyNonexistentWindow(
- base::Bind(&EnableViaAppListFlow::ShowAppList, base::Unretained(this)));
- }
-
- private:
- gfx::NativeWindow ShowAppList() {
- AppListService::Get()->Show();
- return AppListService::Get()->GetAppListWindow();
- }
-
- // ExtensionEnableFlowDelegate overrides.
- virtual void ExtensionEnableFlowFinished() OVERRIDE {
- const Extension* extension =
- service_->GetExtensionById(extension_id_, false);
- if (!extension)
- return;
- callback_.Run();
- delete this;
- }
-
- virtual void ExtensionEnableFlowAborted(bool user_initiated) OVERRIDE {
- delete this;
- }
-
- ExtensionService* service_;
- Profile* profile_;
- std::string extension_id_;
- base::Closure callback_;
- scoped_ptr<ExtensionEnableFlow> flow_;
-
- DISALLOW_COPY_AND_ASSIGN(EnableViaAppListFlow);
-};
-
WebContents* OpenEnabledApplication(const AppLaunchParams& params) {
Profile* profile = params.profile;
const extensions::Extension* extension = params.extension;
- extension_misc::LaunchContainer container = params.container;
- const GURL& override_url = params.override_url;
- const gfx::Rect& override_bounds = params.override_bounds;
+
WebContents* tab = NULL;
ExtensionPrefs* prefs = extensions::ExtensionSystem::Get(profile)->
extension_service()->extension_prefs();
prefs->SetActiveBit(extension->id(), true);
- UMA_HISTOGRAM_ENUMERATION("Extensions.AppLaunchContainer", container, 100);
+ UMA_HISTOGRAM_ENUMERATION(
+ "Extensions.AppLaunchContainer", params.container, 100);
if (extension->is_platform_app()) {
#if !defined(OS_CHROMEOS)
@@ -352,9 +340,10 @@ WebContents* OpenEnabledApplication(const AppLaunchParams& params) {
if (!field_trial_value.empty()) {
GURL gurl(l10n_util::GetStringFUTF8(IDS_APP_LAUNCH_NOT_SIGNED_IN_LINK,
UTF8ToUTF16(extension->id())));
- chrome::NavigateParams params(profile, gurl,
- content::PAGE_TRANSITION_LINK);
- chrome::Navigate(&params);
+ chrome::NavigateParams navigate_params(profile, gurl,
+ content::PAGE_TRANSITION_LINK);
+ navigate_params.host_desktop_type = params.desktop_type;
+ chrome::Navigate(&navigate_params);
return NULL;
}
}
@@ -369,19 +358,17 @@ WebContents* OpenEnabledApplication(const AppLaunchParams& params) {
// the onLaunched event.
prefs->SetLastLaunchTime(extension->id(), base::Time::Now());
- switch (container) {
+ switch (params.container) {
case extension_misc::LAUNCH_NONE: {
NOTREACHED();
break;
}
case extension_misc::LAUNCH_PANEL:
case extension_misc::LAUNCH_WINDOW:
- tab = OpenApplicationWindow(profile, extension, container,
- override_url, NULL, override_bounds);
+ tab = OpenApplicationWindow(params);
break;
case extension_misc::LAUNCH_TAB: {
- tab = OpenApplicationTab(profile, extension, override_url,
- params.disposition);
+ tab = OpenApplicationTab(params);
break;
}
default:
@@ -401,6 +388,7 @@ AppLaunchParams::AppLaunchParams(Profile* profile,
extension(extension),
container(container),
disposition(disposition),
+ desktop_type(chrome::GetActiveDesktop()),
override_url(),
override_bounds(),
command_line(NULL) {}
@@ -412,6 +400,7 @@ AppLaunchParams::AppLaunchParams(Profile* profile,
extension(extension),
container(extension_misc::LAUNCH_NONE),
disposition(disposition),
+ desktop_type(chrome::GetActiveDesktop()),
override_url(),
override_bounds(),
command_line(NULL) {
@@ -427,11 +416,13 @@ AppLaunchParams::AppLaunchParams(Profile* profile,
AppLaunchParams::AppLaunchParams(Profile* profile,
const extensions::Extension* extension,
- int event_flags)
+ int event_flags,
+ chrome::HostDesktopType desktop_type)
: profile(profile),
extension(extension),
container(extension_misc::LAUNCH_NONE),
disposition(ui::DispositionFromEventFlags(event_flags)),
+ desktop_type(desktop_type),
override_url(),
override_bounds(),
command_line(NULL) {
@@ -475,14 +466,15 @@ void OpenApplicationWithReenablePrompt(const AppLaunchParams& params) {
WebContents* OpenAppShortcutWindow(Profile* profile,
const GURL& url,
const gfx::Rect& override_bounds) {
- Browser* app_browser;
- WebContents* tab = OpenApplicationWindow(
+ AppLaunchParams launch_params(
profile,
NULL, // this is a URL app. No extension.
extension_misc::LAUNCH_WINDOW,
- url,
- &app_browser,
- override_bounds);
+ NEW_WINDOW);
+ launch_params.override_url = url;
+ launch_params.override_bounds = override_bounds;
+
+ WebContents* tab = OpenApplicationWindow(launch_params);
if (!tab)
return NULL;
diff --git a/chrome/browser/ui/extensions/application_launch.h b/chrome/browser/ui/extensions/application_launch.h
index 63d30b8fbd..69c5d67262 100644
--- a/chrome/browser/ui/extensions/application_launch.h
+++ b/chrome/browser/ui/extensions/application_launch.h
@@ -6,6 +6,7 @@
#define CHROME_BROWSER_UI_EXTENSIONS_APPLICATION_LAUNCH_H_
#include "base/files/file_path.h"
+#include "chrome/browser/ui/host_desktop.h"
#include "chrome/common/extensions/extension_constants.h"
#include "ui/base/window_open_disposition.h"
#include "ui/gfx/rect.h"
@@ -37,10 +38,13 @@ struct AppLaunchParams {
WindowOpenDisposition disposition);
// Helper to create AppLaunchParams using event flags that allows user to
- // override the user-configured container using modifier keys.
+ // override the user-configured container using modifier keys, falling back to
+ // ExtensionPrefs::GetLaunchContainer() with no modifiers. |desktop_type|
+ // indicates the desktop upon which to launch (Ash or Native).
AppLaunchParams(Profile* profile,
const extensions::Extension* extension,
- int event_flags);
+ int event_flags,
+ chrome::HostDesktopType desktop_type);
// The profile to load the application from.
Profile* profile;
@@ -54,6 +58,9 @@ struct AppLaunchParams {
// If container is TAB, this field controls how the tab is opened.
WindowOpenDisposition disposition;
+ // The desktop type to launch on. Uses GetActiveDesktop() if unspecified.
+ chrome::HostDesktopType desktop_type;
+
// If non-empty, use override_url in place of the application's launch url.
GURL override_url;
diff --git a/chrome/browser/ui/gtk/apps/native_app_window_gtk.cc b/chrome/browser/ui/gtk/apps/native_app_window_gtk.cc
index c9b429de1c..0600574386 100644
--- a/chrome/browser/ui/gtk/apps/native_app_window_gtk.cc
+++ b/chrome/browser/ui/gtk/apps/native_app_window_gtk.cc
@@ -95,29 +95,7 @@ NativeAppWindowGtk::NativeAppWindowGtk(ShellWindow* shell_window,
if (always_on_top_)
gtk_window_set_keep_above(window_, TRUE);
- int min_width = params.minimum_size.width();
- int min_height = params.minimum_size.height();
- int max_width = params.maximum_size.width();
- int max_height = params.maximum_size.height();
- GdkGeometry hints;
- int hints_mask = 0;
- if (min_width || min_height) {
- hints.min_height = min_height;
- hints.min_width = min_width;
- hints_mask |= GDK_HINT_MIN_SIZE;
- }
- if (max_width || max_height) {
- hints.max_height = max_height ? max_height : G_MAXINT;
- hints.max_width = max_width ? max_width : G_MAXINT;
- hints_mask |= GDK_HINT_MAX_SIZE;
- }
- if (hints_mask) {
- gtk_window_set_geometry_hints(
- window_,
- GTK_WIDGET(window_),
- &hints,
- static_cast<GdkWindowHints>(hints_mask));
- }
+ UpdateWindowMinMaxSize();
// In some (older) versions of compiz, raising top-level windows when they
// are partially off-screen causes them to get snapped back on screen, not
@@ -675,3 +653,30 @@ bool NativeAppWindowGtk::IsVisible() const {
void NativeAppWindowGtk::HideWithApp() {}
void NativeAppWindowGtk::ShowWithApp() {}
+
+void NativeAppWindowGtk::UpdateWindowMinMaxSize() {
+ GdkGeometry hints;
+ int hints_mask = 0;
+ if (shell_window_->size_constraints().HasMinimumSize()) {
+ gfx::Size min_size = shell_window_->size_constraints().GetMinimumSize();
+ hints.min_height = min_size.height();
+ hints.min_width = min_size.width();
+ hints_mask |= GDK_HINT_MIN_SIZE;
+ }
+ if (shell_window_->size_constraints().HasMaximumSize()) {
+ gfx::Size max_size = shell_window_->size_constraints().GetMaximumSize();
+ const int kUnboundedSize = ShellWindow::SizeConstraints::kUnboundedSize;
+ hints.max_height = max_size.height() == kUnboundedSize ?
+ G_MAXINT : max_size.height();
+ hints.max_width = max_size.width() == kUnboundedSize ?
+ G_MAXINT : max_size.width();
+ hints_mask |= GDK_HINT_MAX_SIZE;
+ }
+ if (hints_mask) {
+ gtk_window_set_geometry_hints(
+ window_,
+ GTK_WIDGET(window_),
+ &hints,
+ static_cast<GdkWindowHints>(hints_mask));
+ }
+}
diff --git a/chrome/browser/ui/gtk/apps/native_app_window_gtk.h b/chrome/browser/ui/gtk/apps/native_app_window_gtk.h
index 462256ee17..8ba631709e 100644
--- a/chrome/browser/ui/gtk/apps/native_app_window_gtk.h
+++ b/chrome/browser/ui/gtk/apps/native_app_window_gtk.h
@@ -83,6 +83,8 @@ class NativeAppWindowGtk : public apps::NativeAppWindow,
virtual bool IsVisible() const OVERRIDE;
virtual void HideWithApp() OVERRIDE;
virtual void ShowWithApp() OVERRIDE;
+ // Calls gtk_window_set_geometry_hints with the current size constraints.
+ virtual void UpdateWindowMinMaxSize() OVERRIDE;
// web_modal::WebContentsModalDialogHost implementation.
virtual gfx::NativeView GetHostView() const OVERRIDE;
diff --git a/chrome/browser/ui/gtk/browser_actions_toolbar_gtk.cc b/chrome/browser/ui/gtk/browser_actions_toolbar_gtk.cc
index 34f300ac07..7f6049e685 100644
--- a/chrome/browser/ui/gtk/browser_actions_toolbar_gtk.cc
+++ b/chrome/browser/ui/gtk/browser_actions_toolbar_gtk.cc
@@ -7,6 +7,7 @@
#include <gtk/gtk.h>
#include <algorithm>
+#include <utility>
#include <vector>
#include "base/bind.h"
@@ -21,6 +22,7 @@
#include "chrome/browser/extensions/extension_context_menu_model.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sessions/session_tab_helper.h"
#include "chrome/browser/ui/browser.h"
@@ -252,21 +254,25 @@ class BrowserActionButton : public content::NotificationObserver,
}
private:
- // Activate the browser action.
- void Activate(GtkWidget* widget) {
+ // Activate the browser action. Returns true if a popup was shown. Showing the
+ // popup will grant tab permissions if |should_grant| is true. Popup's shown
+ // via an API should not grant permissions.
+ bool Activate(GtkWidget* widget, bool should_grant) {
ExtensionToolbarModel* model = toolbar_->model();
const Extension* extension = extension_;
Browser* browser = toolbar_->browser();
GURL popup_url;
- switch (model->ExecuteBrowserAction(extension, browser, &popup_url)) {
+ switch (model->ExecuteBrowserAction(
+ extension, browser, &popup_url, should_grant)) {
case ExtensionToolbarModel::ACTION_NONE:
break;
case ExtensionToolbarModel::ACTION_SHOW_POPUP:
ExtensionPopupGtk::Show(popup_url, browser, widget,
ExtensionPopupGtk::SHOW);
- break;
+ return true;
}
+ return false;
}
// MenuGtk::Delegate implementation.
@@ -323,7 +329,7 @@ class BrowserActionButton : public content::NotificationObserver,
static void OnClicked(GtkWidget* widget, BrowserActionButton* button) {
if (button->enabled_)
- button->Activate(widget);
+ button->Activate(widget, true);
}
static gboolean OnExposeEvent(GtkWidget* widget,
@@ -364,7 +370,7 @@ class BrowserActionButton : public content::NotificationObserver,
// The anchor might be in the overflow menu. Then we point to the chevron.
if (!gtk_widget_get_visible(anchor))
anchor = button->toolbar_->chevron();
- button->Activate(anchor);
+ button->Activate(anchor, true);
return TRUE;
}
@@ -669,14 +675,17 @@ void BrowserActionsToolbarGtk::CreateButtonForExtension(
UpdateVisibility();
}
-GtkWidget* BrowserActionsToolbarGtk::GetBrowserActionWidget(
+BrowserActionButton* BrowserActionsToolbarGtk::GetBrowserActionButton(
const Extension* extension) {
ExtensionButtonMap::iterator it = extension_button_map_.find(
extension->id());
- if (it == extension_button_map_.end())
- return NULL;
+ return it == extension_button_map_.end() ? NULL : it->second.get();
+}
- return it->second.get()->widget();
+GtkWidget* BrowserActionsToolbarGtk::GetBrowserActionWidget(
+ const Extension* extension) {
+ BrowserActionButton* button = GetBrowserActionButton(extension);
+ return button == NULL ? NULL : button->widget();
}
void BrowserActionsToolbarGtk::RemoveButtonForExtension(
@@ -694,8 +703,9 @@ bool BrowserActionsToolbarGtk::ShouldDisplayBrowserAction(
const Extension* extension) {
// Only display incognito-enabled extensions while in incognito mode.
return (!profile_->IsOffTheRecord() ||
- extensions::ExtensionSystem::Get(profile_)->extension_service()->
- IsIncognitoEnabled(extension->id()));
+ extension_util:: IsIncognitoEnabled(
+ extension->id(),
+ extensions::ExtensionSystem::Get(profile_)->extension_service()));
}
void BrowserActionsToolbarGtk::HidePopup() {
@@ -768,6 +778,24 @@ void BrowserActionsToolbarGtk::BrowserActionMoved(const Extension* extension,
gtk_box_reorder_child(GTK_BOX(button_hbox_.get()), button_widget, index);
}
+bool BrowserActionsToolbarGtk::BrowserActionShowPopup(
+ const Extension* extension) {
+ // Do not override other popups and only show in active window.
+ if (ExtensionPopupGtk::get_current_extension_popup() ||
+ !browser_->window()->IsActive()) {
+ return false;
+ }
+
+ BrowserActionButton* button = GetBrowserActionButton(extension);
+ if (button == NULL || button->widget() == NULL)
+ return false;
+
+ GtkWidget* anchor = button->widget();
+ if (!gtk_widget_get_visible(anchor))
+ anchor = button->toolbar_->chevron();
+ return button->Activate(anchor, false);
+}
+
void BrowserActionsToolbarGtk::ModelLoaded() {
SetContainerWidth();
}
@@ -807,7 +835,8 @@ void BrowserActionsToolbarGtk::ExecuteCommand(int command_id, int event_flags) {
const Extension* extension = model_->toolbar_items()[command_id].get();
GURL popup_url;
- switch (model_->ExecuteBrowserAction(extension, browser(), &popup_url)) {
+ switch (model_->ExecuteBrowserAction(
+ extension, browser(), &popup_url, true)) {
case ExtensionToolbarModel::ACTION_NONE:
break;
case ExtensionToolbarModel::ACTION_SHOW_POPUP:
@@ -1077,13 +1106,13 @@ gboolean BrowserActionsToolbarGtk::OnOverflowMenuButtonPress(
item_index = model_->IncognitoIndexToOriginal(item_index);
const Extension* extension = model_->toolbar_items()[item_index].get();
- ExtensionButtonMap::iterator it = extension_button_map_.find(extension->id());
- if (it == extension_button_map_.end()) {
+ BrowserActionButton* button = GetBrowserActionButton(extension);
+ if (button == NULL) {
NOTREACHED();
return FALSE;
}
- MenuGtk* menu = it->second.get()->GetContextMenu();
+ MenuGtk* menu = button->GetContextMenu();
if (!menu)
return FALSE;
diff --git a/chrome/browser/ui/gtk/browser_actions_toolbar_gtk.h b/chrome/browser/ui/gtk/browser_actions_toolbar_gtk.h
index 8cb03c79e5..cb4209b930 100644
--- a/chrome/browser/ui/gtk/browser_actions_toolbar_gtk.h
+++ b/chrome/browser/ui/gtk/browser_actions_toolbar_gtk.h
@@ -52,6 +52,8 @@ class BrowserActionsToolbarGtk : public ExtensionToolbarModel::Observer,
// |extension|. Used in positioning the ExtensionInstalledBubble for
// BrowserActions.
GtkWidget* GetBrowserActionWidget(const extensions::Extension* extension);
+ BrowserActionButton* GetBrowserActionButton(
+ const extensions::Extension* extension);
int button_count() { return extension_button_map_.size(); }
@@ -118,6 +120,8 @@ class BrowserActionsToolbarGtk : public ExtensionToolbarModel::Observer,
const extensions::Extension* extension) OVERRIDE;
virtual void BrowserActionMoved(const extensions::Extension* extension,
int index) OVERRIDE;
+ virtual bool BrowserActionShowPopup(
+ const extensions::Extension* extension) OVERRIDE;
virtual void ModelLoaded() OVERRIDE;
// gfx::AnimationDelegate implementation.
diff --git a/chrome/browser/ui/gtk/browser_window_gtk.cc b/chrome/browser/ui/gtk/browser_window_gtk.cc
index e108d45489..e17c22b839 100644
--- a/chrome/browser/ui/gtk/browser_window_gtk.cc
+++ b/chrome/browser/ui/gtk/browser_window_gtk.cc
@@ -1173,11 +1173,6 @@ void BrowserWindowGtk::HandleKeyboardEvent(
gtk_window_activate_key(window_, os_event);
}
-void BrowserWindowGtk::ShowCreateChromeAppShortcutsDialog(
- Profile* profile, const extensions::Extension* app) {
- CreateChromeApplicationShortcutsDialogGtk::Show(window_, profile, app);
-}
-
void BrowserWindowGtk::Cut() {
gtk_window_util::DoCut(
window_, browser_->tab_strip_model()->GetActiveWebContents());
diff --git a/chrome/browser/ui/gtk/browser_window_gtk.h b/chrome/browser/ui/gtk/browser_window_gtk.h
index 5ad7b58fa2..9aeac84acd 100644
--- a/chrome/browser/ui/gtk/browser_window_gtk.h
+++ b/chrome/browser/ui/gtk/browser_window_gtk.h
@@ -162,9 +162,6 @@ class BrowserWindowGtk
bool* is_keyboard_shortcut) OVERRIDE;
virtual void HandleKeyboardEvent(
const content::NativeWebKeyboardEvent& event) OVERRIDE;
- virtual void ShowCreateChromeAppShortcutsDialog(
- Profile* profile,
- const extensions::Extension* app) OVERRIDE;
virtual void Cut() OVERRIDE;
virtual void Copy() OVERRIDE;
virtual void Paste() OVERRIDE;
diff --git a/chrome/browser/ui/gtk/create_application_shortcuts_dialog_gtk.cc b/chrome/browser/ui/gtk/create_application_shortcuts_dialog_gtk.cc
index c3035cfdbc..b2e14a9619 100644
--- a/chrome/browser/ui/gtk/create_application_shortcuts_dialog_gtk.cc
+++ b/chrome/browser/ui/gtk/create_application_shortcuts_dialog_gtk.cc
@@ -56,14 +56,16 @@ void ShowCreateWebAppShortcutsDialog(gfx::NativeWindow parent_window,
new CreateWebApplicationShortcutsDialogGtk(parent_window, web_contents);
}
-} // namespace chrome
-
-void CreateChromeApplicationShortcutsDialogGtk::Show(GtkWindow* parent,
- Profile* profile,
- const Extension* app) {
- new CreateChromeApplicationShortcutsDialogGtk(parent, profile, app);
+void ShowCreateChromeAppShortcutsDialog(
+ gfx::NativeWindow parent_window,
+ Profile* profile,
+ const extensions::Extension* app,
+ const base::Closure& close_callback) {
+ new CreateChromeApplicationShortcutsDialogGtk(parent_window, profile, app,
+ close_callback);
}
+} // namespace chrome
CreateApplicationShortcutsDialogGtk::CreateApplicationShortcutsDialogGtk(
GtkWindow* parent)
@@ -314,10 +316,12 @@ CreateChromeApplicationShortcutsDialogGtk::
CreateChromeApplicationShortcutsDialogGtk(
GtkWindow* parent,
Profile* profile,
- const Extension* app)
- : CreateApplicationShortcutsDialogGtk(parent),
- app_(app),
- profile_path_(profile->GetPath()) {
+ const Extension* app,
+ const base::Closure& close_callback)
+ : CreateApplicationShortcutsDialogGtk(parent),
+ app_(app),
+ profile_path_(profile->GetPath()),
+ close_callback_(close_callback) {
// Place Chrome app shortcuts in the "Chrome Apps" submenu.
shortcut_menu_subdir_ = web_app::GetAppShortcutsSubdirName();
@@ -330,6 +334,12 @@ CreateChromeApplicationShortcutsDialogGtk::
this));
}
+CreateChromeApplicationShortcutsDialogGtk::
+ ~CreateChromeApplicationShortcutsDialogGtk() {
+ if (!close_callback_.is_null())
+ close_callback_.Run();
+}
+
// Called when the app's ShortcutInfo (with icon) is loaded.
void CreateChromeApplicationShortcutsDialogGtk::OnShortcutInfoLoaded(
const ShellIntegration::ShortcutInfo& shortcut_info) {
diff --git a/chrome/browser/ui/gtk/create_application_shortcuts_dialog_gtk.h b/chrome/browser/ui/gtk/create_application_shortcuts_dialog_gtk.h
index 1491b09b19..434bdf3648 100644
--- a/chrome/browser/ui/gtk/create_application_shortcuts_dialog_gtk.h
+++ b/chrome/browser/ui/gtk/create_application_shortcuts_dialog_gtk.h
@@ -112,17 +112,14 @@ class CreateWebApplicationShortcutsDialogGtk
class CreateChromeApplicationShortcutsDialogGtk
: public CreateApplicationShortcutsDialogGtk {
public:
- // Displays the dialog box to create application shortcuts for |app|.
- static void Show(GtkWindow* parent, Profile* profile,
- const extensions::Extension* app);
-
- CreateChromeApplicationShortcutsDialogGtk(GtkWindow* parent,
- Profile* profile,
- const extensions::Extension* app);
-
+ CreateChromeApplicationShortcutsDialogGtk(
+ GtkWindow* parent,
+ Profile* profile,
+ const extensions::Extension* app,
+ const base::Closure& close_callback);
protected:
- virtual ~CreateChromeApplicationShortcutsDialogGtk() {}
+ virtual ~CreateChromeApplicationShortcutsDialogGtk();
virtual void CreateDesktopShortcut(
const ShellIntegration::ShortcutInfo& shortcut_info,
@@ -132,9 +129,9 @@ class CreateChromeApplicationShortcutsDialogGtk
void OnShortcutInfoLoaded(
const ShellIntegration::ShortcutInfo& shortcut_info);
- private:
const extensions::Extension* app_;
base::FilePath profile_path_;
+ base::Closure close_callback_;
DISALLOW_COPY_AND_ASSIGN(CreateChromeApplicationShortcutsDialogGtk);
};
diff --git a/chrome/browser/ui/gtk/download/download_item_gtk.cc b/chrome/browser/ui/gtk/download/download_item_gtk.cc
index 34f1f2fda8..6a9e194dd4 100644
--- a/chrome/browser/ui/gtk/download/download_item_gtk.cc
+++ b/chrome/browser/ui/gtk/download/download_item_gtk.cc
@@ -237,13 +237,15 @@ DownloadItemGtk::DownloadItemGtk(DownloadShelfGtk* parent_shelf,
gtk_util::CenterWidgetInHBox(dangerous_hbox_.get(), dangerous_decline,
false, 0);
- // Create the ok button.
- GtkWidget* dangerous_accept = gtk_button_new_with_label(
- UTF16ToUTF8(download_model_.GetWarningConfirmButtonText()).c_str());
- g_signal_connect(dangerous_accept, "clicked",
- G_CALLBACK(OnDangerousAcceptThunk), this);
- gtk_util::CenterWidgetInHBox(dangerous_hbox_.get(), dangerous_accept, false,
- 0);
+ // Create the ok button, if this is the kind that can be bypassed.
+ if (!download_model_.IsMalicious()) {
+ GtkWidget* dangerous_accept = gtk_button_new_with_label(
+ UTF16ToUTF8(download_model_.GetWarningConfirmButtonText()).c_str());
+ g_signal_connect(dangerous_accept, "clicked",
+ G_CALLBACK(OnDangerousAcceptThunk), this);
+ gtk_util::CenterWidgetInHBox(
+ dangerous_hbox_.get(), dangerous_accept, false, 0);
+ }
// Put it in an alignment so that padding will be added on the left and
// right.
@@ -630,15 +632,16 @@ void DownloadItemGtk::UpdateDangerWarning() {
void DownloadItemGtk::UpdateDangerIcon() {
if (theme_service_->UsingNativeTheme()) {
- const char* stock = download_model_.IsMalicious() ?
+ const char* stock = download_model_.MightBeMalicious() ?
GTK_STOCK_DIALOG_ERROR : GTK_STOCK_DIALOG_WARNING;
gtk_image_set_from_stock(
GTK_IMAGE(dangerous_image_), stock, GTK_ICON_SIZE_SMALL_TOOLBAR);
} else {
// Set the warning icon.
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- int pixbuf_id = download_model_.IsMalicious() ? IDR_SAFEBROWSING_WARNING
- : IDR_WARNING;
+ int pixbuf_id =
+ download_model_.MightBeMalicious() ? IDR_SAFEBROWSING_WARNING
+ : IDR_WARNING;
gtk_image_set_from_pixbuf(GTK_IMAGE(dangerous_image_),
rb.GetNativeImageNamed(pixbuf_id).ToGdkPixbuf());
}
diff --git a/chrome/browser/ui/gtk/first_run_dialog.cc b/chrome/browser/ui/gtk/first_run_dialog.cc
index eca4ef29af..8480f31216 100644
--- a/chrome/browser/ui/gtk/first_run_dialog.cc
+++ b/chrome/browser/ui/gtk/first_run_dialog.cc
@@ -10,7 +10,6 @@
#include "base/i18n/rtl.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/utf_string_conversions.h"
-#include "chrome/app/breakpad_linux.h"
#include "chrome/browser/first_run/first_run_dialog.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/process_singleton.h"
@@ -20,6 +19,7 @@
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "chrome/installer/util/google_update_settings.h"
+#include "components/breakpad/app/breakpad_linux.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
@@ -164,7 +164,7 @@ void FirstRunDialog::OnResponseDialog(GtkWidget* widget, int response) {
if (report_crashes_ &&
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(report_crashes_))) {
if (GoogleUpdateSettings::SetCollectStatsConsent(true))
- InitCrashReporter();
+ breakpad::InitCrashReporter();
} else {
GoogleUpdateSettings::SetCollectStatsConsent(false);
}
diff --git a/chrome/browser/ui/gtk/global_menu_bar.cc b/chrome/browser/ui/gtk/global_menu_bar.cc
index e10164a904..10336fb4cb 100644
--- a/chrome/browser/ui/gtk/global_menu_bar.cc
+++ b/chrome/browser/ui/gtk/global_menu_bar.cc
@@ -133,6 +133,7 @@ GlobalMenuBarCommand tools_menu[] = {
{ IDS_VIEW_SOURCE, IDC_VIEW_SOURCE },
{ IDS_DEV_TOOLS, IDC_DEV_TOOLS },
{ IDS_DEV_TOOLS_CONSOLE, IDC_DEV_TOOLS_CONSOLE },
+ { IDS_DEV_TOOLS_DEVICES, IDC_DEV_TOOLS_DEVICES },
{ MENU_END, MENU_END }
};
diff --git a/chrome/browser/ui/panels/panel_host.cc b/chrome/browser/ui/panels/panel_host.cc
index 66ce28164a..73dd5a21a8 100644
--- a/chrome/browser/ui/panels/panel_host.cc
+++ b/chrome/browser/ui/panels/panel_host.cc
@@ -9,6 +9,7 @@
#include "base/message_loop/message_loop.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/chrome_page_zoom.h"
+#include "chrome/browser/extensions/extension_web_contents_observer.h"
#include "chrome/browser/extensions/window_controller.h"
#include "chrome/browser/favicon/favicon_tab_helper.h"
#include "chrome/browser/profiles/profile.h"
@@ -63,6 +64,8 @@ void PanelHost::Init(const GURL& url) {
FaviconTabHelper::CreateForWebContents(web_contents_.get());
PrefsTabHelper::CreateForWebContents(web_contents_.get());
+ extensions::ExtensionWebContentsObserver::CreateForWebContents(
+ web_contents_.get());
web_contents_->GetController().LoadURL(
url, content::Referrer(), content::PAGE_TRANSITION_LINK, std::string());
diff --git a/chrome/browser/ui/prefs/prefs_tab_helper.cc b/chrome/browser/ui/prefs/prefs_tab_helper.cc
index db0b657a22..7e1691453c 100644
--- a/chrome/browser/ui/prefs/prefs_tab_helper.cc
+++ b/chrome/browser/ui/prefs/prefs_tab_helper.cc
@@ -42,78 +42,6 @@ DEFINE_WEB_CONTENTS_USER_DATA_KEY(PrefsTabHelper);
namespace {
-// Registers prefs only used for migration.
-void RegisterPrefsToMigrate(user_prefs::PrefRegistrySyncable* prefs) {
- prefs->RegisterLocalizedStringPref(
- prefs::kWebKitOldStandardFontFamily,
- IDS_STANDARD_FONT_FAMILY,
- user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
- prefs->RegisterLocalizedStringPref(
- prefs::kWebKitOldFixedFontFamily,
- IDS_FIXED_FONT_FAMILY,
- user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
- prefs->RegisterLocalizedStringPref(
- prefs::kWebKitOldSerifFontFamily,
- IDS_SERIF_FONT_FAMILY,
- user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
- prefs->RegisterLocalizedStringPref(
- prefs::kWebKitOldSansSerifFontFamily,
- IDS_SANS_SERIF_FONT_FAMILY,
- user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
- prefs->RegisterLocalizedStringPref(
- prefs::kWebKitOldCursiveFontFamily,
- IDS_CURSIVE_FONT_FAMILY,
- user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
- prefs->RegisterLocalizedStringPref(
- prefs::kWebKitOldFantasyFontFamily,
- IDS_FANTASY_FONT_FAMILY,
- user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
- prefs->RegisterLocalizedStringPref(
- prefs::kGlobalDefaultCharset,
- IDS_DEFAULT_ENCODING,
- user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
- prefs->RegisterLocalizedIntegerPref(
- prefs::kWebKitGlobalDefaultFontSize,
- IDS_DEFAULT_FONT_SIZE,
- user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
- prefs->RegisterLocalizedIntegerPref(
- prefs::kWebKitGlobalDefaultFixedFontSize,
- IDS_DEFAULT_FIXED_FONT_SIZE,
- user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
- prefs->RegisterLocalizedIntegerPref(
- prefs::kWebKitGlobalMinimumFontSize,
- IDS_MINIMUM_FONT_SIZE,
- user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
- prefs->RegisterLocalizedIntegerPref(
- prefs::kWebKitGlobalMinimumLogicalFontSize,
- IDS_MINIMUM_LOGICAL_FONT_SIZE,
- user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
- prefs->RegisterLocalizedStringPref(
- prefs::kWebKitGlobalStandardFontFamily,
- IDS_STANDARD_FONT_FAMILY,
- user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
- prefs->RegisterLocalizedStringPref(
- prefs::kWebKitGlobalFixedFontFamily,
- IDS_FIXED_FONT_FAMILY,
- user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
- prefs->RegisterLocalizedStringPref(
- prefs::kWebKitGlobalSerifFontFamily,
- IDS_SERIF_FONT_FAMILY,
- user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
- prefs->RegisterLocalizedStringPref(
- prefs::kWebKitGlobalSansSerifFontFamily,
- IDS_SANS_SERIF_FONT_FAMILY,
- user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
- prefs->RegisterLocalizedStringPref(
- prefs::kWebKitGlobalCursiveFontFamily,
- IDS_CURSIVE_FONT_FAMILY,
- user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
- prefs->RegisterLocalizedStringPref(
- prefs::kWebKitGlobalFantasyFontFamily,
- IDS_FANTASY_FONT_FAMILY,
- user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
-}
-
// The list of prefs we want to observe.
const char* kPrefsToObserve[] = {
prefs::kDefaultCharset,
@@ -138,12 +66,16 @@ const char* kPrefsToObserve[] = {
const int kPrefsToObserveLength = arraysize(kPrefsToObserve);
+#if !defined(OS_ANDROID)
// Registers a preference under the path |pref_name| for each script used for
// per-script font prefs.
// For example, for WEBKIT_WEBPREFS_FONTS_SERIF ("fonts.serif"):
// "fonts.serif.Arab", "fonts.serif.Hang", etc. are registered.
// |fonts_with_defaults| contains all |pref_names| already registered since they
// have a specified default value.
+// On Android there are no default values for these properties and there is no
+// way to set them (because extensions are not supported so the Font Settings
+// API cannot be used), so we can avoid registering them altogether.
void RegisterFontFamilyPrefs(user_prefs::PrefRegistrySyncable* registry,
const std::set<std::string>& fonts_with_defaults) {
@@ -177,7 +109,6 @@ ALL_FONT_SCRIPTS(WEBKIT_WEBPREFS_FONTS_STANDARD)
}
}
-#if !defined(OS_ANDROID)
// Registers |obs| to observe per-script font prefs under the path |map_name|.
// On android, there's no exposed way to change these prefs, so we can save
// ~715KB of heap and some startup cycles by avoiding observing these prefs
@@ -330,60 +261,6 @@ UScriptCode GetScriptOfBrowserLocale() {
return GetScriptForFontPrefMatching(code);
}
-const struct {
- const char* from;
- const char* to;
-} kPrefNamesToMigrate[] = {
- // Migrate prefs like "webkit.webprefs.standard_font_family" to
- // "webkit.webprefs.fonts.standard.Zyyy". This moves the formerly
- // "non-per-script" font prefs into the per-script font pref maps, as the
- // entry for the "Common" script (Zyyy is the ISO 15924 script code for the
- // Common script). The |from| prefs will exist if the migration to global
- // prefs (for the per-tab pref mechanism, which has since been removed) never
- // occurred.
- { prefs::kWebKitOldCursiveFontFamily,
- prefs::kWebKitCursiveFontFamily },
- { prefs::kWebKitOldFantasyFontFamily,
- prefs::kWebKitFantasyFontFamily },
- { prefs::kWebKitOldFixedFontFamily,
- prefs::kWebKitFixedFontFamily },
- { prefs::kWebKitOldSansSerifFontFamily,
- prefs::kWebKitSansSerifFontFamily },
- { prefs::kWebKitOldSerifFontFamily,
- prefs::kWebKitSerifFontFamily },
- { prefs::kWebKitOldStandardFontFamily,
- prefs::kWebKitStandardFontFamily },
-
- // Migrate "global" prefs. These will exist if the migration to global prefs
- // (for the per-tab pref mechanism, which has since been removed) occurred.
- // In addition, this moves the formerly "non-per-script" font prefs into the
- // per-script font pref maps, as above.
- { prefs::kGlobalDefaultCharset,
- prefs::kDefaultCharset },
- { prefs::kWebKitGlobalDefaultFixedFontSize,
- prefs::kWebKitDefaultFixedFontSize },
- { prefs::kWebKitGlobalDefaultFontSize,
- prefs::kWebKitDefaultFontSize },
- { prefs::kWebKitGlobalMinimumFontSize,
- prefs::kWebKitMinimumFontSize },
- { prefs::kWebKitGlobalMinimumLogicalFontSize,
- prefs::kWebKitMinimumLogicalFontSize },
- { prefs::kWebKitGlobalCursiveFontFamily,
- prefs::kWebKitCursiveFontFamily },
- { prefs::kWebKitGlobalFantasyFontFamily,
- prefs::kWebKitFantasyFontFamily },
- { prefs::kWebKitGlobalFixedFontFamily,
- prefs::kWebKitFixedFontFamily },
- { prefs::kWebKitGlobalSansSerifFontFamily,
- prefs::kWebKitSansSerifFontFamily },
- { prefs::kWebKitGlobalSerifFontFamily,
- prefs::kWebKitSerifFontFamily },
- { prefs::kWebKitGlobalStandardFontFamily,
- prefs::kWebKitStandardFontFamily }
-};
-
-const int kPrefsToMigrateLength = ARRAYSIZE_UNSAFE(kPrefNamesToMigrate);
-
// Sets a font family pref in |prefs| to |pref_value|.
void OverrideFontFamily(WebPreferences* prefs,
const std::string& generic_family,
@@ -564,7 +441,11 @@ void PrefsTabHelper::RegisterProfilePrefs(
#if defined(OS_ANDROID)
registry->RegisterDoublePref(
prefs::kWebKitFontScaleFactor,
- pref_defaults.font_scale_factor,
+ 1.0,
+ user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+ registry->RegisterBooleanPref(
+ prefs::kWebKitFontScaleFactorQuirk,
+ true,
user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
registry->RegisterBooleanPref(
prefs::kWebKitForceEnableZoom,
@@ -612,8 +493,10 @@ void PrefsTabHelper::RegisterProfilePrefs(
}
}
- // Register font prefs that don't have defaults.
+ // Register per-script font prefs that don't have defaults.
+#if !defined(OS_ANDROID)
RegisterFontFamilyPrefs(registry, fonts_with_defaults);
+#endif
registry->RegisterLocalizedIntegerPref(
prefs::kWebKitDefaultFontSize,
@@ -643,19 +526,6 @@ void PrefsTabHelper::RegisterProfilePrefs(
prefs::kRecentlySelectedEncoding,
std::string(),
user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
-
- RegisterPrefsToMigrate(registry);
-}
-
-void PrefsTabHelper::MigrateUserPrefs(PrefService* prefs) {
- for (int i = 0; i < kPrefsToMigrateLength; ++i) {
- const PrefService::Preference* pref =
- prefs->FindPreference(kPrefNamesToMigrate[i].from);
- if (pref && !pref->IsDefaultValue()) {
- prefs->Set(kPrefNamesToMigrate[i].to, *pref->GetValue());
- prefs->ClearPref(kPrefNamesToMigrate[i].from);
- }
- }
}
void PrefsTabHelper::Observe(int type,
diff --git a/chrome/browser/ui/prefs/prefs_tab_helper.h b/chrome/browser/ui/prefs/prefs_tab_helper.h
index 42ffd36289..055a2f1056 100644
--- a/chrome/browser/ui/prefs/prefs_tab_helper.h
+++ b/chrome/browser/ui/prefs/prefs_tab_helper.h
@@ -33,7 +33,6 @@ class PrefsTabHelper : public content::NotificationObserver,
static void InitIncognitoUserPrefStore(OverlayUserPrefStore* pref_store);
static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
- static void MigrateUserPrefs(PrefService* prefs);
protected:
// Update the RenderView's WebPreferences. Exposed as protected for testing.
diff --git a/chrome/browser/ui/prefs/prefs_tab_helper_browsertest.cc b/chrome/browser/ui/prefs/prefs_tab_helper_browsertest.cc
index d6cd780695..bb82f51a3c 100644
--- a/chrome/browser/ui/prefs/prefs_tab_helper_browsertest.cc
+++ b/chrome/browser/ui/prefs/prefs_tab_helper_browsertest.cc
@@ -20,7 +20,7 @@ class PrefsTabHelperBrowserTest : public InProcessBrowserTest {
PathService::Get(chrome::DIR_TEST_DATA, &test_data_directory);
return test_data_directory
.AppendASCII("profiles")
- .AppendASCII("webkit_global_migration")
+ .AppendASCII("web_prefs")
.AppendASCII("Default")
.Append(chrome::kPreferencesFilename);
}
@@ -34,15 +34,15 @@ class PrefsTabHelperBrowserTest : public InProcessBrowserTest {
LOG(ERROR) << "Can't create " << default_profile.MaybeAsASCII();
return false;
}
- base::FilePath non_global_pref_file = GetPreferencesFilePath();
- if (!base::PathExists(non_global_pref_file)) {
- LOG(ERROR) << "Doesn't exist " << non_global_pref_file.MaybeAsASCII();
+ base::FilePath pref_file = GetPreferencesFilePath();
+ if (!base::PathExists(pref_file)) {
+ LOG(ERROR) << "Doesn't exist " << pref_file.MaybeAsASCII();
return false;
}
base::FilePath default_pref_file =
default_profile.Append(chrome::kPreferencesFilename);
- if (!base::CopyFile(non_global_pref_file, default_pref_file)) {
- LOG(ERROR) << "Copy error from " << non_global_pref_file.MaybeAsASCII()
+ if (!base::CopyFile(pref_file, default_pref_file)) {
+ LOG(ERROR) << "Copy error from " << pref_file.MaybeAsASCII()
<< " to " << default_pref_file.MaybeAsASCII();
return false;
}
@@ -57,132 +57,24 @@ class PrefsTabHelperBrowserTest : public InProcessBrowserTest {
}
};
-// This tests migration like:
-// webkit.webprefs.standard_font_family -> webkit.webprefs.fonts.standard.Zyyy
-// This migration moves the formerly "non-per-script" font prefs into the
-// per-script font maps, as the entry for "Common" script (Zyyy is the ISO 15924
-// script code for the Common script).
-//
-// In addition, it tests that the former migration of
-// webkit.webprefs.blahblah -> webkit.webprefs.global.blahblah
-// no longer occurs.
-IN_PROC_BROWSER_TEST_F(PrefsTabHelperBrowserTest, PrefsAreMigratedToFontMap) {
+// Tests that a sampling of web prefs are registered and ones with values in the
+// test user preferences file take on those values.
+IN_PROC_BROWSER_TEST_F(PrefsTabHelperBrowserTest, WebPrefs) {
PrefService* prefs = browser()->profile()->GetPrefs();
EXPECT_TRUE(prefs->FindPreference(
- prefs::kGlobalDefaultCharset)->IsDefaultValue());
+ prefs::kWebKitCursiveFontFamily)->IsDefaultValue());
EXPECT_TRUE(prefs->FindPreference(
- prefs::kWebKitGlobalDefaultFontSize)->IsDefaultValue());
+ prefs::kWebKitSerifFontFamily)->IsDefaultValue());
EXPECT_TRUE(prefs->FindPreference(
- prefs::kWebKitGlobalDefaultFixedFontSize)->IsDefaultValue());
- EXPECT_TRUE(prefs->FindPreference(
- prefs::kWebKitGlobalMinimumFontSize)->IsDefaultValue());
- EXPECT_TRUE(prefs->FindPreference(
- prefs::kWebKitGlobalMinimumLogicalFontSize)->IsDefaultValue());
- EXPECT_TRUE(prefs->FindPreference(
- prefs::kWebKitOldCursiveFontFamily)->IsDefaultValue());
- EXPECT_TRUE(prefs->FindPreference(
- prefs::kWebKitOldFantasyFontFamily)->IsDefaultValue());
- EXPECT_TRUE(prefs->FindPreference(
- prefs::kWebKitOldFixedFontFamily)->IsDefaultValue());
- EXPECT_TRUE(prefs->FindPreference(
- prefs::kWebKitOldSansSerifFontFamily)->IsDefaultValue());
- EXPECT_TRUE(prefs->FindPreference(
- prefs::kWebKitOldSerifFontFamily)->IsDefaultValue());
- EXPECT_TRUE(prefs->FindPreference(
- prefs::kWebKitOldStandardFontFamily)->IsDefaultValue());
+ prefs::kWebKitSerifFontFamilyJapanese)->IsDefaultValue());
EXPECT_EQ("ISO-8859-1", prefs->GetString(prefs::kDefaultCharset));
- EXPECT_EQ(42, prefs->GetInteger(prefs::kWebKitDefaultFontSize));
- EXPECT_EQ(42, prefs->GetInteger(prefs::kWebKitDefaultFixedFontSize));
- EXPECT_EQ(42, prefs->GetInteger(prefs::kWebKitMinimumFontSize));
- EXPECT_EQ(42, prefs->GetInteger(prefs::kWebKitMinimumLogicalFontSize));
- EXPECT_EQ("CursiveFontFamily",
- prefs->GetString(prefs::kWebKitCursiveFontFamily));
- EXPECT_EQ("FantasyFontFamily",
- prefs->GetString(prefs::kWebKitFantasyFontFamily));
- // PictographFontFamily was added after the migration, so it never exists
- // in the old format (and consequently isn't in the test Preferences file).
- // So it doesn't need to be tested here.
- EXPECT_EQ("FixedFontFamily",
- prefs->GetString(prefs::kWebKitFixedFontFamily));
- EXPECT_EQ("SansSerifFontFamily",
- prefs->GetString(prefs::kWebKitSansSerifFontFamily));
- EXPECT_EQ("SerifFontFamily",
- prefs->GetString(prefs::kWebKitSerifFontFamily));
- EXPECT_EQ("StandardFontFamily",
- prefs->GetString(prefs::kWebKitStandardFontFamily));
+ EXPECT_EQ(16, prefs->GetInteger(prefs::kWebKitDefaultFontSize));
+ EXPECT_EQ("Nanum Gothic",
+ prefs->GetString(prefs::kWebKitStandardFontFamilyKorean));
+ EXPECT_EQ("Tinos", prefs->GetString(prefs::kWebKitStandardFontFamily));
+ EXPECT_EQ("DejaVu Sans", prefs->GetString(prefs::kWebKitSansSerifFontFamily));
};
-class PrefsTabHelperBrowserTest2 : public PrefsTabHelperBrowserTest {
- protected:
- virtual base::FilePath GetPreferencesFilePath() OVERRIDE {
- base::FilePath test_data_directory;
- PathService::Get(chrome::DIR_TEST_DATA, &test_data_directory);
- return test_data_directory
- .AppendASCII("profiles")
- .AppendASCII("webkit_global_reverse_migration")
- .AppendASCII("Default")
- .Append(chrome::kPreferencesFilename);
- }
-};
-// This tests migration like:
-// webkit.webprefs.global.blahblah -> webkit.webprefs.blahblah
-// This undoes the migration to "global" names (originally done for the per-tab
-// pref mechanism, which has since been removed).
-//
-// In addition it tests the migration for font families:
-// webkit.webprefs.global.standard_font_family ->
-// webkit.webprefs.fonts.standard.Zyyy
-// This moves the formerly "non-per-script" font prefs into the per-script font
-// maps, as described in the comment for PrefsAreMigratedToFontMap.
-IN_PROC_BROWSER_TEST_F(PrefsTabHelperBrowserTest2, GlobalPrefsAreMigrated) {
- PrefService* prefs = browser()->profile()->GetPrefs();
-
- EXPECT_TRUE(prefs->FindPreference(
- prefs::kGlobalDefaultCharset)->IsDefaultValue());
- EXPECT_TRUE(prefs->FindPreference(
- prefs::kWebKitGlobalDefaultFontSize)->IsDefaultValue());
- EXPECT_TRUE(prefs->FindPreference(
- prefs::kWebKitGlobalDefaultFixedFontSize)->IsDefaultValue());
- EXPECT_TRUE(prefs->FindPreference(
- prefs::kWebKitGlobalMinimumFontSize)->IsDefaultValue());
- EXPECT_TRUE(prefs->FindPreference(
- prefs::kWebKitGlobalMinimumLogicalFontSize)->IsDefaultValue());
- EXPECT_TRUE(prefs->FindPreference(
- prefs::kWebKitGlobalCursiveFontFamily)->IsDefaultValue());
- EXPECT_TRUE(prefs->FindPreference(
- prefs::kWebKitGlobalFantasyFontFamily)->IsDefaultValue());
- EXPECT_TRUE(prefs->FindPreference(
- prefs::kWebKitGlobalFixedFontFamily)->IsDefaultValue());
- EXPECT_TRUE(prefs->FindPreference(
- prefs::kWebKitGlobalSansSerifFontFamily)->IsDefaultValue());
- EXPECT_TRUE(prefs->FindPreference(
- prefs::kWebKitGlobalSerifFontFamily)->IsDefaultValue());
- EXPECT_TRUE(prefs->FindPreference(
- prefs::kWebKitGlobalStandardFontFamily)->IsDefaultValue());
-
- EXPECT_EQ("ISO-8859-1", prefs->GetString(prefs::kDefaultCharset));
- EXPECT_EQ(42, prefs->GetInteger(prefs::kWebKitDefaultFontSize));
- EXPECT_EQ(42,
- prefs->GetInteger(prefs::kWebKitDefaultFixedFontSize));
- EXPECT_EQ(42, prefs->GetInteger(prefs::kWebKitMinimumFontSize));
- EXPECT_EQ(42,
- prefs->GetInteger(prefs::kWebKitMinimumLogicalFontSize));
- EXPECT_EQ("CursiveFontFamily",
- prefs->GetString(prefs::kWebKitCursiveFontFamily));
- EXPECT_EQ("FantasyFontFamily",
- prefs->GetString(prefs::kWebKitFantasyFontFamily));
- // PictographFontFamily was added after the migration, so it never exists
- // in the old format (and consequently isn't in the test Preferences file).
- // So it doesn't need to be tested here.
- EXPECT_EQ("FixedFontFamily",
- prefs->GetString(prefs::kWebKitFixedFontFamily));
- EXPECT_EQ("SansSerifFontFamily",
- prefs->GetString(prefs::kWebKitSansSerifFontFamily));
- EXPECT_EQ("SerifFontFamily",
- prefs->GetString(prefs::kWebKitSerifFontFamily));
- EXPECT_EQ("StandardFontFamily",
- prefs->GetString(prefs::kWebKitStandardFontFamily));
-};
diff --git a/chrome/browser/ui/search/instant_page.cc b/chrome/browser/ui/search/instant_page.cc
index fb7422b8a8..1732a3c7ed 100644
--- a/chrome/browser/ui/search/instant_page.cc
+++ b/chrome/browser/ui/search/instant_page.cc
@@ -94,6 +94,7 @@ bool InstantPage::OnMessageReceived(const IPC::Message& message) {
void InstantPage::DidCommitProvisionalLoadForFrame(
int64 /* frame_id */,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& url,
content::PageTransition /* transition_type */,
@@ -114,6 +115,7 @@ void InstantPage::DidNavigateMainFrame(
void InstantPage::DidFailProvisionalLoad(
int64 /* frame_id */,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& /* validated_url */,
int /* error_code */,
diff --git a/chrome/browser/ui/search/instant_page.h b/chrome/browser/ui/search/instant_page.h
index 47cea9f0d7..cb85102405 100644
--- a/chrome/browser/ui/search/instant_page.h
+++ b/chrome/browser/ui/search/instant_page.h
@@ -132,6 +132,7 @@ class InstantPage : public content::WebContentsObserver,
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
virtual void DidCommitProvisionalLoadForFrame(
int64 frame_id,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& url,
content::PageTransition transition_type,
@@ -141,6 +142,7 @@ class InstantPage : public content::WebContentsObserver,
const content::FrameNavigateParams& params) OVERRIDE;
virtual void DidFailProvisionalLoad(
int64 frame_id,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& validated_url,
int error_code,
diff --git a/chrome/browser/ui/search/search_ipc_router.cc b/chrome/browser/ui/search/search_ipc_router.cc
index 666e3d467e..064fb27503 100644
--- a/chrome/browser/ui/search/search_ipc_router.cc
+++ b/chrome/browser/ui/search/search_ipc_router.cc
@@ -5,7 +5,6 @@
#include "chrome/browser/ui/search/search_ipc_router.h"
#include "chrome/browser/search/search.h"
-#include "chrome/browser/ui/search/search_tab_helper.h"
#include "chrome/common/render_messages.h"
#include "content/public/browser/web_contents.h"
@@ -106,8 +105,11 @@ void SearchIPCRouter::OnInstantSupportDetermined(int page_id,
void SearchIPCRouter::OnVoiceSearchSupportDetermined(
int page_id,
bool supports_voice_search) const {
- if (!web_contents()->IsActiveEntry(page_id) ||
- !policy_->ShouldProcessSetVoiceSearchSupport())
+ if (!web_contents()->IsActiveEntry(page_id))
+ return;
+
+ delegate_->OnInstantSupportDetermined(true);
+ if (!policy_->ShouldProcessSetVoiceSearchSupport())
return;
delegate_->OnSetVoiceSearchSupport(supports_voice_search);
@@ -118,7 +120,7 @@ void SearchIPCRouter::OnFocusOmnibox(int page_id,
if (!web_contents()->IsActiveEntry(page_id))
return;
- SearchTabHelper::FromWebContents(web_contents())->InstantSupportChanged(true);
+ delegate_->OnInstantSupportDetermined(true);
if (!policy_->ShouldProcessFocusOmnibox())
return;
@@ -130,7 +132,7 @@ void SearchIPCRouter::OnDeleteMostVisitedItem(int page_id,
if (!web_contents()->IsActiveEntry(page_id))
return;
- SearchTabHelper::FromWebContents(web_contents())->InstantSupportChanged(true);
+ delegate_->OnInstantSupportDetermined(true);
if (!policy_->ShouldProcessDeleteMostVisitedItem())
return;
@@ -142,7 +144,7 @@ void SearchIPCRouter::OnUndoMostVisitedDeletion(int page_id,
if (!web_contents()->IsActiveEntry(page_id))
return;
- SearchTabHelper::FromWebContents(web_contents())->InstantSupportChanged(true);
+ delegate_->OnInstantSupportDetermined(true);
if (!policy_->ShouldProcessUndoMostVisitedDeletion())
return;
@@ -153,7 +155,7 @@ void SearchIPCRouter::OnUndoAllMostVisitedDeletions(int page_id) const {
if (!web_contents()->IsActiveEntry(page_id))
return;
- SearchTabHelper::FromWebContents(web_contents())->InstantSupportChanged(true);
+ delegate_->OnInstantSupportDetermined(true);
if (!policy_->ShouldProcessUndoAllMostVisitedDeletions())
return;
@@ -161,8 +163,11 @@ void SearchIPCRouter::OnUndoAllMostVisitedDeletions(int page_id) const {
}
void SearchIPCRouter::OnLogEvent(int page_id, NTPLoggingEventType event) const {
- if (!web_contents()->IsActiveEntry(page_id) ||
- !policy_->ShouldProcessLogEvent())
+ if (!web_contents()->IsActiveEntry(page_id))
+ return;
+
+ delegate_->OnInstantSupportDetermined(true);
+ if (!policy_->ShouldProcessLogEvent())
return;
delegate_->OnLogEvent(event);
diff --git a/chrome/browser/ui/search/search_tab_helper.cc b/chrome/browser/ui/search/search_tab_helper.cc
index 059090fcfc..495cb0667e 100644
--- a/chrome/browser/ui/search/search_tab_helper.cc
+++ b/chrome/browser/ui/search/search_tab_helper.cc
@@ -298,6 +298,7 @@ void SearchTabHelper::DidNavigateMainFrame(
void SearchTabHelper::DidFailProvisionalLoad(
int64 /* frame_id */,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& /* validated_url */,
int /* error_code */,
diff --git a/chrome/browser/ui/search/search_tab_helper.h b/chrome/browser/ui/search/search_tab_helper.h
index 876c032848..64e6921ef8 100644
--- a/chrome/browser/ui/search/search_tab_helper.h
+++ b/chrome/browser/ui/search/search_tab_helper.h
@@ -173,6 +173,7 @@ class SearchTabHelper : public content::NotificationObserver,
const content::FrameNavigateParams& params) OVERRIDE;
virtual void DidFailProvisionalLoad(
int64 frame_id,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& validated_url,
int error_code,
diff --git a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
index d76ca8de49..60d73d755a 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
@@ -109,7 +109,7 @@ class StartupBrowserCreatorTest : public ExtensionBrowserTest {
ExtensionService* service = extensions::ExtensionSystem::Get(
browser()->profile())->extension_service();
*out_app_extension = service->GetExtensionById(
- last_loaded_extension_id_, false);
+ last_loaded_extension_id(), false);
ASSERT_TRUE(*out_app_extension);
// Code that opens a new browser assumes we start with exactly one.
@@ -960,16 +960,12 @@ class ManagedModeBrowserCreatorTest : public InProcessBrowserTest {
virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
InProcessBrowserTest::SetUpCommandLine(command_line);
command_line->AppendSwitch(switches::kEnableManagedUsers);
+ command_line->AppendSwitch(switches::kNewProfileIsSupervised);
}
};
IN_PROC_BROWSER_TEST_F(ManagedModeBrowserCreatorTest,
StartupManagedModeProfile) {
- // Make this a managed profile.
- ManagedUserService* managed_user_service =
- ManagedUserServiceFactory::GetForProfile(browser()->profile());
- managed_user_service->InitForTesting();
-
StartupBrowserCreator browser_creator;
// Do a simple non-process-startup browser launch.
diff --git a/chrome/browser/ui/sync/one_click_signin_helper.cc b/chrome/browser/ui/sync/one_click_signin_helper.cc
index 8ab55dc038..7bd2e7d0ef 100644
--- a/chrome/browser/ui/sync/one_click_signin_helper.cc
+++ b/chrome/browser/ui/sync/one_click_signin_helper.cc
@@ -536,6 +536,7 @@ class CurrentHistoryCleaner : public content::WebContentsObserver {
virtual void WebContentsDestroyed(content::WebContents* contents) OVERRIDE;
virtual void DidCommitProvisionalLoadForFrame(
int64 frame_id,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& url,
content::PageTransition transition_type,
@@ -559,6 +560,7 @@ CurrentHistoryCleaner::~CurrentHistoryCleaner() {
void CurrentHistoryCleaner::DidCommitProvisionalLoadForFrame(
int64 frame_id,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& url,
content::PageTransition transition_type,
diff --git a/chrome/browser/ui/tab_contents/core_tab_helper.cc b/chrome/browser/ui/tab_contents/core_tab_helper.cc
index 169e23a661..f5431398df 100644
--- a/chrome/browser/ui/tab_contents/core_tab_helper.cc
+++ b/chrome/browser/ui/tab_contents/core_tab_helper.cc
@@ -4,19 +4,36 @@
#include "chrome/browser/ui/tab_contents/core_tab_helper.h"
+#include <string>
+#include <vector>
+
#include "base/command_line.h"
#include "base/metrics/histogram.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/web_cache_manager.h"
+#include "chrome/browser/search_engines/search_terms_data.h"
+#include "chrome/browser/search_engines/template_url.h"
+#include "chrome/browser/search_engines/template_url_service.h"
+#include "chrome/browser/search_engines/template_url_service_factory.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_command_controller.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/render_messages.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
-#include "net/base/load_states.h"
#include "grit/generated_resources.h"
+#include "net/base/load_states.h"
+#include "net/http/http_request_headers.h"
+#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/codec/jpeg_codec.h"
+
+#if defined(OS_WIN)
+#include "base/win/win_util.h"
+#endif
using content::WebContents;
@@ -165,7 +182,6 @@ void CoreTabHelper::WebContentsDestroyed(WebContents* web_contents) {
UMA_HISTOGRAM_TIMES("Tab.Close.UnloadTime", now - unload_start_time);
}
}
-
}
void CoreTabHelper::BeforeUnloadFired(const base::TimeTicks& proceed_time) {
@@ -175,3 +191,83 @@ void CoreTabHelper::BeforeUnloadFired(const base::TimeTicks& proceed_time) {
void CoreTabHelper::BeforeUnloadDialogCancelled() {
OnCloseCanceled();
}
+
+bool CoreTabHelper::OnMessageReceived(const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(CoreTabHelper, message)
+ IPC_MESSAGE_HANDLER(ChromeViewHostMsg_FocusedNodeTouched,
+ OnFocusedNodeTouched)
+ IPC_MESSAGE_HANDLER(ChromeViewHostMsg_RequestThumbnailForContextNode_ACK,
+ OnRequestThumbnailForContextNodeACK)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void CoreTabHelper::OnFocusedNodeTouched(bool editable) {
+#if defined(OS_WIN) && defined(USE_AURA)
+ if (editable) {
+ base::win::DisplayVirtualKeyboard();
+ } else {
+ base::win::DismissVirtualKeyboard();
+ }
+#endif // OS_WIN && USE_AURA
+}
+
+// Handles the image thumbnail for the context node, composes a image search
+// request based on the received thumbnail and opens the request in a new tab.
+void CoreTabHelper::OnRequestThumbnailForContextNodeACK(
+ const SkBitmap& bitmap,
+ const gfx::Size& original_size) {
+ if (bitmap.isNull())
+ return;
+ Profile* profile =
+ Profile::FromBrowserContext(web_contents()->GetBrowserContext());
+
+ TemplateURLService* template_url_service =
+ TemplateURLServiceFactory::GetForProfile(profile);
+ if (!template_url_service)
+ return;
+ const TemplateURL* const default_provider =
+ template_url_service->GetDefaultSearchProvider();
+ if (!default_provider)
+ return;
+
+ const int kDefaultQualityForImageSearch = 90;
+ std::vector<unsigned char> data;
+ if (!gfx::JPEGCodec::Encode(
+ reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)),
+ gfx::JPEGCodec::FORMAT_SkBitmap, bitmap.width(), bitmap.height(),
+ static_cast<int>(bitmap.rowBytes()), kDefaultQualityForImageSearch,
+ &data))
+ return;
+
+ TemplateURLRef::SearchTermsArgs search_args =
+ TemplateURLRef::SearchTermsArgs(base::string16());
+ search_args.image_thumbnail_content = std::string(data.begin(), data.end());
+ // TODO(jnd): Add a method in WebContentsViewDelegate to get the image URL
+ // from the ContextMenuParams which creates current context menu.
+ search_args.image_url = GURL();
+ search_args.image_original_size = original_size;
+ TemplateURLRef::PostContent post_content;
+ GURL result(default_provider->image_url_ref().ReplaceSearchTerms(
+ search_args, &post_content));
+ if (!result.is_valid())
+ return;
+
+ content::OpenURLParams open_url_params(
+ result, content::Referrer(), NEW_FOREGROUND_TAB,
+ content::PAGE_TRANSITION_LINK, false);
+ const std::string& content_type = post_content.first;
+ std::string* post_data = &post_content.second;
+ if (!post_data->empty()) {
+ DCHECK(!content_type.empty());
+ open_url_params.uses_post = true;
+ open_url_params.browser_initiated_post_data =
+ base::RefCountedString::TakeString(post_data);
+ open_url_params.extra_headers += base::StringPrintf(
+ "%s: %s\r\n", net::HttpRequestHeaders::kContentType,
+ content_type.c_str());
+ }
+ web_contents()->OpenURL(open_url_params);
+}
diff --git a/chrome/browser/ui/tab_contents/core_tab_helper.h b/chrome/browser/ui/tab_contents/core_tab_helper.h
index 7f0ffe368a..bb57f4ee53 100644
--- a/chrome/browser/ui/tab_contents/core_tab_helper.h
+++ b/chrome/browser/ui/tab_contents/core_tab_helper.h
@@ -63,6 +63,11 @@ class CoreTabHelper : public content::WebContentsObserver,
content::WebContents* web_contents) OVERRIDE;
virtual void BeforeUnloadFired(const base::TimeTicks& proceed_time) OVERRIDE;
virtual void BeforeUnloadDialogCancelled() OVERRIDE;
+ virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+
+ void OnFocusedNodeTouched(bool editable);
+ void OnRequestThumbnailForContextNodeACK(const SkBitmap& bitmap,
+ const gfx::Size& original_size);
// Delegate for notifying our owner about stuff. Not owned by us.
CoreTabHelperDelegate* delegate_;
diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc
index f590dad484..91042c7a0a 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -277,6 +277,9 @@ void TabStripModel::AppendWebContents(WebContents* contents,
void TabStripModel::InsertWebContentsAt(int index,
WebContents* contents,
int add_types) {
+ // TODO(sky): nuke, used in isolating 297118.
+ CHECK(!contents->IsBeingDestroyed());
+
delegate_->WillAddWebContents(contents);
bool active = add_types & ADD_ACTIVE;
diff --git a/chrome/browser/ui/toolbar/wrench_menu_model.cc b/chrome/browser/ui/toolbar/wrench_menu_model.cc
index 19571ab8f7..c24ba59564 100644
--- a/chrome/browser/ui/toolbar/wrench_menu_model.cc
+++ b/chrome/browser/ui/toolbar/wrench_menu_model.cc
@@ -217,6 +217,7 @@ void ToolsMenuModel::Build(Browser* browser) {
AddItemWithStringId(IDC_VIEW_SOURCE, IDS_VIEW_SOURCE);
AddItemWithStringId(IDC_DEV_TOOLS, IDS_DEV_TOOLS);
AddItemWithStringId(IDC_DEV_TOOLS_CONSOLE, IDS_DEV_TOOLS_CONSOLE);
+ AddItemWithStringId(IDC_DEV_TOOLS_DEVICES, IDS_DEV_TOOLS_DEVICES);
#if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC)
AddSeparator(ui::NORMAL_SEPARATOR);
diff --git a/chrome/browser/ui/translate/language_combobox_model.cc b/chrome/browser/ui/translate/language_combobox_model.cc
new file mode 100644
index 0000000000..031998addd
--- /dev/null
+++ b/chrome/browser/ui/translate/language_combobox_model.cc
@@ -0,0 +1,33 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/translate/language_combobox_model.h"
+
+#include "chrome/browser/ui/translate/translate_bubble_model.h"
+
+LanguageComboboxModel::LanguageComboboxModel(
+ int default_index,
+ TranslateBubbleModel* model)
+ : default_index_(default_index),
+ model_(model) {
+}
+
+LanguageComboboxModel::~LanguageComboboxModel() {
+}
+
+int LanguageComboboxModel::GetItemCount() const {
+ return model_->GetNumberOfLanguages();
+}
+
+string16 LanguageComboboxModel::GetItemAt(int index) {
+ return model_->GetLanguageNameAt(index);
+}
+
+bool LanguageComboboxModel::IsItemSeparatorAt(int index) {
+ return false;
+}
+
+int LanguageComboboxModel::GetDefaultIndex() const {
+ return default_index_;
+}
diff --git a/chrome/browser/ui/translate/language_combobox_model.h b/chrome/browser/ui/translate/language_combobox_model.h
new file mode 100644
index 0000000000..4af7a69dbf
--- /dev/null
+++ b/chrome/browser/ui/translate/language_combobox_model.h
@@ -0,0 +1,37 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_TRANSLATE_LANGUAGE_COMBOBOX_MODEL_H_
+#define CHROME_BROWSER_UI_TRANSLATE_LANGUAGE_COMBOBOX_MODEL_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string16.h"
+#include "ui/base/models/combobox_model.h"
+
+class TranslateBubbleModel;
+
+// The model for the combobox to select a language. This is used for Translate
+// user interface to select language.
+class LanguageComboboxModel : public ui::ComboboxModel {
+ public:
+ LanguageComboboxModel(int default_index,
+ TranslateBubbleModel* model);
+ virtual ~LanguageComboboxModel();
+
+ // Overridden from ui::ComboboxModel:
+ virtual int GetItemCount() const OVERRIDE;
+ virtual string16 GetItemAt(int index) OVERRIDE;
+ virtual bool IsItemSeparatorAt(int index) OVERRIDE;
+ virtual int GetDefaultIndex() const OVERRIDE;
+
+ private:
+ const int default_index_;
+ TranslateBubbleModel* model_;
+
+ DISALLOW_COPY_AND_ASSIGN(LanguageComboboxModel);
+};
+
+#endif // CHROME_BROWSER_UI_TRANSLATE_LANGUAGE_COMBOBOX_MODEL_H_
diff --git a/chrome/browser/ui/translate/translate_bubble_model.h b/chrome/browser/ui/translate/translate_bubble_model.h
new file mode 100644
index 0000000000..af12a910b3
--- /dev/null
+++ b/chrome/browser/ui/translate/translate_bubble_model.h
@@ -0,0 +1,89 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_TRANSLATE_TRANSLATE_BUBBLE_MODEL_H_
+#define CHROME_BROWSER_UI_TRANSLATE_TRANSLATE_BUBBLE_MODEL_H_
+
+#include <string>
+
+#include "base/strings/string16.h"
+
+// The model for the Translate bubble UX. This manages the user's manipulation
+// of the bubble and offers the data to show on the bubble.
+class TranslateBubbleModel {
+ public:
+ enum ViewState {
+ // The view state before translating.
+ VIEW_STATE_BEFORE_TRANSLATE,
+
+ // The view state during translating.
+ VIEW_STATE_TRANSLATING,
+
+ // The view state after translating.
+ VIEW_STATE_AFTER_TRANSLATE,
+
+ // The view state when an error of Translate happens.
+ VIEW_STATE_ERROR,
+
+ // The view state when the detailed settings is shown. This view appears
+ // when the user click a link 'Advanced' on other views.
+ VIEW_STATE_ADVANCED,
+ };
+
+ virtual ~TranslateBubbleModel() {}
+
+ // Returns the current view state.
+ virtual ViewState GetViewState() const = 0;
+
+ // Transitions the view state.
+ virtual void SetViewState(ViewState view_state) = 0;
+
+ // Goes back from the 'Advanced' view state.
+ virtual void GoBackFromAdvanced() = 0;
+
+ // Returns the number of languages supported.
+ virtual int GetNumberOfLanguages() const = 0;
+
+ // Returns the displayable name for the language at |index|.
+ virtual string16 GetLanguageNameAt(int index) const = 0;
+
+ // Returns the original language index.
+ virtual int GetOriginalLanguageIndex() const = 0;
+
+ // Sets the original language index.
+ virtual void SetOriginalLanguageIndex(int index) = 0;
+
+ // Returns the target language index.
+ virtual int GetTargetLanguageIndex() const = 0;
+
+ // Sets the target language index.
+ virtual void SetTargetLanguageIndex(int index) = 0;
+
+ // Sets the value if the user doesn't want to have the page translated in the
+ // current page's language.
+ virtual void SetNeverTranslateLanguage(bool value) = 0;
+
+ // Sets the value if the user doesn't want to have the page translated the
+ // current page's domain.
+ virtual void SetNeverTranslateSite(bool value) = 0;
+
+ // Returns true if the webpage in the current original language should be
+ // translated into the current target language automatically.
+ virtual bool ShouldAlwaysTranslate() const = 0;
+
+ // Sets the value if the webpage in the current original language should be
+ // translated into the current target language automatically.
+ virtual void SetAlwaysTranslate(bool value) = 0;
+
+ // Starts translating the current page.
+ virtual void Translate() = 0;
+
+ // Reverts translation.
+ virtual void RevertTranslation() = 0;
+
+ // Processes when the user declines translation.
+ virtual void TranslationDeclined() = 0;
+};
+
+#endif // CHROME_BROWSER_UI_TRANSLATE_TRANSLATE_BUBBLE_MODEL_H_
diff --git a/chrome/browser/ui/translate/translate_bubble_model_impl.cc b/chrome/browser/ui/translate/translate_bubble_model_impl.cc
new file mode 100644
index 0000000000..7bf27172b3
--- /dev/null
+++ b/chrome/browser/ui/translate/translate_bubble_model_impl.cc
@@ -0,0 +1,82 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/translate/translate_bubble_model_impl.h"
+
+#include "chrome/browser/translate/translate_ui_delegate.h"
+
+TranslateBubbleModelImpl::TranslateBubbleModelImpl(
+ TranslateBubbleModel::ViewState view_type,
+ scoped_ptr<TranslateUIDelegate> ui_delegate)
+ : ui_delegate_(ui_delegate.Pass()),
+ view_state_transition_(view_type) {
+}
+
+TranslateBubbleModelImpl::~TranslateBubbleModelImpl() {
+}
+
+TranslateBubbleModel::ViewState TranslateBubbleModelImpl::GetViewState() const {
+ return view_state_transition_.view_state();
+}
+
+void TranslateBubbleModelImpl::SetViewState(
+ TranslateBubbleModel::ViewState view_state) {
+ view_state_transition_.SetViewState(view_state);
+}
+
+void TranslateBubbleModelImpl::GoBackFromAdvanced() {
+ view_state_transition_.GoBackFromAdvanced();
+}
+
+int TranslateBubbleModelImpl::GetNumberOfLanguages() const {
+ return ui_delegate_->GetNumberOfLanguages();
+}
+
+string16 TranslateBubbleModelImpl::GetLanguageNameAt(int index) const {
+ return ui_delegate_->GetLanguageNameAt(index);
+}
+
+int TranslateBubbleModelImpl::GetOriginalLanguageIndex() const {
+ return ui_delegate_->GetOriginalLanguageIndex();
+}
+
+void TranslateBubbleModelImpl::SetOriginalLanguageIndex(int index) {
+ ui_delegate_->SetOriginalLanguageIndex(index);
+}
+
+int TranslateBubbleModelImpl::GetTargetLanguageIndex() const {
+ return ui_delegate_->GetTargetLanguageIndex();
+}
+
+void TranslateBubbleModelImpl::SetTargetLanguageIndex(int index) {
+ ui_delegate_->SetTargetLanguageIndex(index);
+}
+
+void TranslateBubbleModelImpl::SetNeverTranslateLanguage(bool value) {
+ ui_delegate_->SetLanguageBlocked(value);
+}
+
+void TranslateBubbleModelImpl::SetNeverTranslateSite(bool value) {
+ ui_delegate_->SetSiteBlacklist(value);
+}
+
+bool TranslateBubbleModelImpl::ShouldAlwaysTranslate() const {
+ return ui_delegate_->ShouldAlwaysTranslate();
+}
+
+void TranslateBubbleModelImpl::SetAlwaysTranslate(bool value) {
+ ui_delegate_->SetAlwaysTranslate(value);
+}
+
+void TranslateBubbleModelImpl::Translate() {
+ ui_delegate_->Translate();
+}
+
+void TranslateBubbleModelImpl::RevertTranslation() {
+ ui_delegate_->RevertTranslation();
+}
+
+void TranslateBubbleModelImpl::TranslationDeclined() {
+ ui_delegate_->TranslationDeclined();
+}
diff --git a/chrome/browser/ui/translate/translate_bubble_model_impl.h b/chrome/browser/ui/translate/translate_bubble_model_impl.h
new file mode 100644
index 0000000000..94c78ad73b
--- /dev/null
+++ b/chrome/browser/ui/translate/translate_bubble_model_impl.h
@@ -0,0 +1,48 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_TRANSLATE_TRANSLATE_BUBBLE_MODEL_IMPL_H_
+#define CHROME_BROWSER_UI_TRANSLATE_TRANSLATE_BUBBLE_MODEL_IMPL_H_
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/ui/translate/translate_bubble_model.h"
+#include "chrome/browser/ui/translate/translate_bubble_view_state_transition.h"
+
+class TranslateUIDelegate;
+
+// The standard implementation of TranslateBubbleModel.
+class TranslateBubbleModelImpl : public TranslateBubbleModel {
+ public:
+ TranslateBubbleModelImpl(TranslateBubbleModel::ViewState view_type,
+ scoped_ptr<TranslateUIDelegate> ui_delegate);
+ virtual ~TranslateBubbleModelImpl();
+
+ // TranslateBubbleModel methods.
+ virtual TranslateBubbleModel::ViewState GetViewState() const OVERRIDE;
+ virtual void SetViewState(TranslateBubbleModel::ViewState view_state)
+ OVERRIDE;
+ virtual void GoBackFromAdvanced() OVERRIDE;
+ virtual int GetNumberOfLanguages() const OVERRIDE;
+ virtual string16 GetLanguageNameAt(int index) const OVERRIDE;
+ virtual int GetOriginalLanguageIndex() const OVERRIDE;
+ virtual void SetOriginalLanguageIndex(int index) OVERRIDE;
+ virtual int GetTargetLanguageIndex() const OVERRIDE;
+ virtual void SetTargetLanguageIndex(int index) OVERRIDE;
+ virtual void SetNeverTranslateLanguage(bool value) OVERRIDE;
+ virtual void SetNeverTranslateSite(bool value) OVERRIDE;
+ virtual bool ShouldAlwaysTranslate() const OVERRIDE;
+ virtual void SetAlwaysTranslate(bool value) OVERRIDE;
+ virtual void Translate() OVERRIDE;
+ virtual void RevertTranslation() OVERRIDE;
+ virtual void TranslationDeclined() OVERRIDE;
+
+ private:
+ scoped_ptr<TranslateUIDelegate> ui_delegate_;
+ TranslateBubbleViewStateTransition view_state_transition_;
+
+ DISALLOW_COPY_AND_ASSIGN(TranslateBubbleModelImpl);
+};
+
+#endif // CHROME_BROWSER_UI_TRANSLATE_TRANSLATE_BUBBLE_MODEL_IMPL_H_
diff --git a/chrome/browser/ui/translate/translate_bubble_view_state_transition.cc b/chrome/browser/ui/translate/translate_bubble_view_state_transition.cc
new file mode 100644
index 0000000000..9a7134b76c
--- /dev/null
+++ b/chrome/browser/ui/translate/translate_bubble_view_state_transition.cc
@@ -0,0 +1,27 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/translate/translate_bubble_view_state_transition.h"
+
+#include "base/logging.h"
+
+TranslateBubbleViewStateTransition::TranslateBubbleViewStateTransition(
+ TranslateBubbleModel::ViewState view_state)
+ : view_state_(view_state),
+ view_state_before_advanced_view_(view_state) {
+ // The initial view type must not be 'Advanced'.
+ DCHECK_NE(TranslateBubbleModel::VIEW_STATE_ADVANCED, view_state_);
+}
+
+void TranslateBubbleViewStateTransition::SetViewState(
+ TranslateBubbleModel::ViewState view_state) {
+ view_state_ = view_state;
+ if (view_state != TranslateBubbleModel::VIEW_STATE_ADVANCED)
+ view_state_before_advanced_view_ = view_state;
+}
+
+void TranslateBubbleViewStateTransition::GoBackFromAdvanced() {
+ DCHECK(view_state_ == TranslateBubbleModel::VIEW_STATE_ADVANCED);
+ SetViewState(view_state_before_advanced_view_);
+}
diff --git a/chrome/browser/ui/translate/translate_bubble_view_state_transition.h b/chrome/browser/ui/translate/translate_bubble_view_state_transition.h
new file mode 100644
index 0000000000..ad6c76838c
--- /dev/null
+++ b/chrome/browser/ui/translate/translate_bubble_view_state_transition.h
@@ -0,0 +1,39 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_TRANSLATE_TRANSLATE_BUBBLE_VIEW_STATE_TRANSITION_H_
+#define CHROME_BROWSER_UI_TRANSLATE_TRANSLATE_BUBBLE_VIEW_STATE_TRANSITION_H_
+
+#include "base/basictypes.h"
+#include "chrome/browser/ui/translate/translate_bubble_model.h"
+
+// The class which manages the transition of the view state of the Translate
+// bubble.
+class TranslateBubbleViewStateTransition {
+ public:
+ explicit TranslateBubbleViewStateTransition(
+ TranslateBubbleModel::ViewState view_state);
+
+ TranslateBubbleModel::ViewState view_state() const { return view_state_; }
+
+ // Transitions the view state.
+ void SetViewState(TranslateBubbleModel::ViewState view_state);
+
+ // Goes back from the 'Advanced' view state.
+ void GoBackFromAdvanced();
+
+ private:
+ // The current view type.
+ TranslateBubbleModel::ViewState view_state_;
+
+ // The view type. When the current view type is not 'Advanced' view, this is
+ // equivalent to |view_state_|. Otherwise, this is the previous view type
+ // before the user opens the 'Advanced' view. This is used to navigate when
+ // pressing 'Cancel' button on the 'Advanced' view.
+ TranslateBubbleModel::ViewState view_state_before_advanced_view_;
+
+ DISALLOW_COPY_AND_ASSIGN(TranslateBubbleViewStateTransition);
+};
+
+#endif // CHROME_BROWSER_UI_TRANSLATE_TRANSLATE_BUBBLE_VIEW_STATE_TRANSITION_H_
diff --git a/chrome/browser/ui/view_ids.h b/chrome/browser/ui/view_ids.h
index 3d0fcb8869..81e035ec96 100644
--- a/chrome/browser/ui/view_ids.h
+++ b/chrome/browser/ui/view_ids.h
@@ -24,6 +24,7 @@ enum ViewID {
VIEW_ID_WINDOW_TITLE,
VIEW_ID_AVATAR_LABEL,
VIEW_ID_AVATAR_BUTTON,
+ VIEW_ID_NEW_AVATAR_BUTTON,
// Tabs within a window/tab strip, counting from the left.
VIEW_ID_TAB_0,
diff --git a/chrome/browser/ui/views/app_list/win/app_list_controller_delegate_win.cc b/chrome/browser/ui/views/app_list/win/app_list_controller_delegate_win.cc
index 74ebecaf29..ca4458ea68 100644
--- a/chrome/browser/ui/views/app_list/win/app_list_controller_delegate_win.cc
+++ b/chrome/browser/ui/views/app_list/win/app_list_controller_delegate_win.cc
@@ -4,13 +4,11 @@
#include "chrome/browser/ui/views/app_list/win/app_list_controller_delegate_win.h"
-#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/ui/app_list/app_list_icon_win.h"
#include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/browser_dialogs.h"
#include "chrome/browser/ui/extensions/application_launch.h"
#include "chrome/browser/ui/views/app_list/win/app_list_service_win.h"
-#include "chrome/browser/ui/views/browser_dialogs.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
#include "net/base/url_util.h"
@@ -60,31 +58,10 @@ void AppListControllerDelegateWin::OnCloseExtensionPrompt() {
service_->set_can_close(true);
}
-bool AppListControllerDelegateWin::CanDoCreateShortcutsFlow(
- bool is_platform_app) {
+bool AppListControllerDelegateWin::CanDoCreateShortcutsFlow() {
return true;
}
-void AppListControllerDelegateWin::DoCreateShortcutsFlow(
- Profile* profile,
- const std::string& extension_id) {
- ExtensionService* service =
- extensions::ExtensionSystem::Get(profile)->extension_service();
- DCHECK(service);
- const extensions::Extension* extension = service->GetInstalledExtension(
- extension_id);
- DCHECK(extension);
-
- gfx::NativeWindow parent_hwnd = GetAppListWindow();
- if (!parent_hwnd)
- return;
- OnShowExtensionPrompt();
- chrome::ShowCreateChromeAppShortcutsDialog(
- parent_hwnd, profile, extension,
- base::Bind(&AppListControllerDelegateWin::OnCloseExtensionPrompt,
- base::Unretained(this)));
-}
-
void AppListControllerDelegateWin::CreateNewWindow(Profile* profile,
bool incognito) {
Profile* window_profile = incognito ?
@@ -108,6 +85,7 @@ void AppListControllerDelegateWin::LaunchApp(
AppListServiceImpl::RecordAppListAppLaunch();
AppLaunchParams params(profile, extension, NEW_FOREGROUND_TAB);
+ params.desktop_type = chrome::HOST_DESKTOP_TYPE_NATIVE;
if (source != LAUNCH_FROM_UNKNOWN &&
extension->id() == extension_misc::kWebStoreAppId) {
diff --git a/chrome/browser/ui/views/app_list/win/app_list_controller_delegate_win.h b/chrome/browser/ui/views/app_list/win/app_list_controller_delegate_win.h
index 869ca282d4..9e3ffcca56 100644
--- a/chrome/browser/ui/views/app_list/win/app_list_controller_delegate_win.h
+++ b/chrome/browser/ui/views/app_list/win/app_list_controller_delegate_win.h
@@ -31,9 +31,7 @@ class AppListControllerDelegateWin : public AppListControllerDelegate {
virtual Pinnable GetPinnable() OVERRIDE;
virtual void OnShowExtensionPrompt() OVERRIDE;
virtual void OnCloseExtensionPrompt() OVERRIDE;
- virtual bool CanDoCreateShortcutsFlow(bool is_platform_app) OVERRIDE;
- virtual void DoCreateShortcutsFlow(Profile* profile,
- const std::string& extension_id) OVERRIDE;
+ virtual bool CanDoCreateShortcutsFlow() OVERRIDE;
virtual void CreateNewWindow(Profile* profile, bool incognito) OVERRIDE;
virtual void ActivateApp(Profile* profile,
const extensions::Extension* extension,
diff --git a/chrome/browser/ui/views/app_list/win/app_list_service_win.cc b/chrome/browser/ui/views/app_list/win/app_list_service_win.cc
index d061902b2e..d02c6fa001 100644
--- a/chrome/browser/ui/views/app_list/win/app_list_service_win.cc
+++ b/chrome/browser/ui/views/app_list/win/app_list_service_win.cc
@@ -312,19 +312,22 @@ void SetWindowAttributes(HWND hwnd) {
class AppListFactoryWin : public AppListFactory {
public:
- explicit AppListFactoryWin(
- scoped_ptr<AppListControllerDelegate> delegate)
- : delegate_(delegate.Pass()) {}
- virtual ~AppListFactoryWin() {}
+ explicit AppListFactoryWin(AppListServiceWin* service)
+ : service_(service) {
+ }
+
+ virtual ~AppListFactoryWin() {
+ }
virtual AppList* CreateAppList(
Profile* profile,
const base::Closure& on_should_dismiss) OVERRIDE {
// The controller will be owned by the view delegate, and the delegate is
// owned by the app list view. The app list view manages it's own lifetime.
- // TODO(koz): Make AppListViewDelegate take a scoped_ptr.
+ scoped_ptr<AppListControllerDelegate> controller_delegate(
+ new AppListControllerDelegateWin(service_));
AppListViewDelegate* view_delegate = new AppListViewDelegate(
- delegate_.get(), profile);
+ controller_delegate.Pass(), profile);
app_list::AppListView* view = new app_list::AppListView(view_delegate);
gfx::Point cursor = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint();
view->InitAsBubbleAtFixedLocation(NULL,
@@ -339,8 +342,8 @@ class AppListFactoryWin : public AppListFactory {
private:
// PaginationModel that is shared across all views.
app_list::PaginationModel pagination_model_;
+ AppListServiceWin* service_;
- scoped_ptr<AppListControllerDelegate> delegate_;
DISALLOW_COPY_AND_ASSIGN(AppListFactoryWin);
};
@@ -355,9 +358,7 @@ AppListServiceWin* AppListServiceWin::GetInstance() {
AppListServiceWin::AppListServiceWin()
: enable_app_list_on_next_init_(false),
shower_(new AppListShower(
- scoped_ptr<AppListFactory>(
- new AppListFactoryWin(scoped_ptr<AppListControllerDelegate>(
- new AppListControllerDelegateWin(this)))),
+ scoped_ptr<AppListFactory>(new AppListFactoryWin(this)),
scoped_ptr<KeepAliveService>(new KeepAliveServiceImpl))),
weak_factory_(this) {}
diff --git a/chrome/browser/ui/views/apps/native_app_window_views.cc b/chrome/browser/ui/views/apps/native_app_window_views.cc
index c39d0424de..ff9bbd2428 100644
--- a/chrome/browser/ui/views/apps/native_app_window_views.cc
+++ b/chrome/browser/ui/views/apps/native_app_window_views.cc
@@ -131,8 +131,6 @@ NativeAppWindowViews::NativeAppWindowViews(
is_fullscreen_(false),
frameless_(create_params.frame == ShellWindow::FRAME_NONE),
transparent_background_(create_params.transparent_background),
- minimum_size_(create_params.minimum_size),
- maximum_size_(create_params.maximum_size),
resizable_(create_params.resizable),
weak_ptr_factory_(this) {
Observe(web_contents());
@@ -555,12 +553,11 @@ views::View* NativeAppWindowViews::GetInitiallyFocusedView() {
}
bool NativeAppWindowViews::CanResize() const {
- return resizable_ &&
- (maximum_size_.IsEmpty() || minimum_size_ != maximum_size_);
+ return resizable_ && !shell_window_->size_constraints().HasFixedSize();
}
bool NativeAppWindowViews::CanMaximize() const {
- return resizable_ && maximum_size_.IsEmpty() &&
+ return resizable_ && !shell_window_->size_constraints().HasMaximumSize() &&
!shell_window_->window_type_is_panel();
}
@@ -629,9 +626,7 @@ views::NonClientFrameView* NativeAppWindowViews::CreateNonClientFrameView(
return new ash::PanelFrameView(widget, frame_type);
}
if (!frameless_) {
- ash::CustomFrameViewAsh* frame = new ash::CustomFrameViewAsh();
- frame->Init(widget);
- return frame;
+ return new ash::CustomFrameViewAsh(widget);
}
}
#endif
@@ -724,11 +719,11 @@ gfx::Size NativeAppWindowViews::GetPreferredSize() {
}
gfx::Size NativeAppWindowViews::GetMinimumSize() {
- return minimum_size_;
+ return shell_window_->size_constraints().GetMinimumSize();
}
gfx::Size NativeAppWindowViews::GetMaximumSize() {
- return maximum_size_;
+ return shell_window_->size_constraints().GetMaximumSize();
}
void NativeAppWindowViews::OnFocus() {
@@ -838,3 +833,4 @@ bool NativeAppWindowViews::IsVisible() const {
void NativeAppWindowViews::HideWithApp() {}
void NativeAppWindowViews::ShowWithApp() {}
+void NativeAppWindowViews::UpdateWindowMinMaxSize() {}
diff --git a/chrome/browser/ui/views/apps/native_app_window_views.h b/chrome/browser/ui/views/apps/native_app_window_views.h
index caecca39cc..506138ce27 100644
--- a/chrome/browser/ui/views/apps/native_app_window_views.h
+++ b/chrome/browser/ui/views/apps/native_app_window_views.h
@@ -154,6 +154,7 @@ class NativeAppWindowViews : public apps::NativeAppWindow,
virtual bool IsVisible() const OVERRIDE;
virtual void HideWithApp() OVERRIDE;
virtual void ShowWithApp() OVERRIDE;
+ virtual void UpdateWindowMinMaxSize() OVERRIDE;
// web_modal::WebContentsModalDialogHost implementation.
virtual gfx::NativeView GetHostView() const OVERRIDE;
@@ -185,8 +186,6 @@ class NativeAppWindowViews : public apps::NativeAppWindow,
const bool frameless_;
const bool transparent_background_;
- gfx::Size minimum_size_;
- gfx::Size maximum_size_;
gfx::Size preferred_size_;
bool resizable_;
diff --git a/chrome/browser/ui/views/autofill/autofill_dialog_views.cc b/chrome/browser/ui/views/autofill/autofill_dialog_views.cc
index 3fba3171eb..b50c295d93 100644
--- a/chrome/browser/ui/views/autofill/autofill_dialog_views.cc
+++ b/chrome/browser/ui/views/autofill/autofill_dialog_views.cc
@@ -484,12 +484,25 @@ AutofillDialogViews::ErrorBubble::ErrorBubble(views::View* anchor,
views::View* anchor_container,
const base::string16& message)
: anchor_(anchor),
- anchor_container_(anchor_container) {
+ anchor_container_(anchor_container),
+ show_above_anchor_(
+ anchor->GetClassName() == views::Combobox::kViewClassName) {
DCHECK(anchor_container_->Contains(anchor));
-
SetAnchorView(anchor_);
- set_arrow(ShouldArrowGoOnTheRight() ? views::BubbleBorder::TOP_RIGHT :
- views::BubbleBorder::TOP_LEFT);
+
+ // TODO(dbeam): currently we assume that combobox menus always show downward
+ // (which isn't true). If the invalid combobox is low enough on the screen,
+ // its menu will actually show upward and obscure the bubble. Figure out when
+ // this might happen and adjust |show_above_anchor_| accordingly. This is not
+ // that big of deal because it rarely happens in practice.
+ if (show_above_anchor_) {
+ set_arrow(ShouldArrowGoOnTheRight() ? views::BubbleBorder::BOTTOM_RIGHT :
+ views::BubbleBorder::BOTTOM_LEFT);
+ } else {
+ set_arrow(ShouldArrowGoOnTheRight() ? views::BubbleBorder::TOP_RIGHT :
+ views::BubbleBorder::TOP_LEFT);
+ }
+
set_margins(gfx::Insets(kErrorBubbleVerticalMargin,
kErrorBubbleHorizontalMargin,
kErrorBubbleVerticalMargin,
@@ -523,7 +536,7 @@ void AutofillDialogViews::ErrorBubble::UpdatePosition() {
if (!anchor_->GetVisibleBounds().IsEmpty()) {
SizeToContents();
widget_->SetVisibilityChangedAnimationsEnabled(true);
- widget_->Show();
+ widget_->ShowInactive();
} else {
widget_->SetVisibilityChangedAnimationsEnabled(false);
widget_->Hide();
@@ -540,6 +553,10 @@ gfx::Size AutofillDialogViews::ErrorBubble::GetPreferredSize() {
gfx::Rect AutofillDialogViews::ErrorBubble::GetBubbleBounds() {
gfx::Rect bounds = views::BubbleDelegateView::GetBubbleBounds();
gfx::Rect anchor_bounds = anchor_->GetBoundsInScreen();
+
+ if (show_above_anchor_)
+ bounds.set_y(anchor_bounds.y() - GetBubbleFrameView()->height());
+
anchor_bounds.Inset(-GetBubbleFrameView()->bubble_border()->GetInsets());
bounds.set_x(ShouldArrowGoOnTheRight() ?
anchor_bounds.right() - bounds.width() - kBubbleBorderVisibleWidth :
@@ -648,6 +665,46 @@ void AutofillDialogViews::AccountChooser::OnMenuButtonClicked(
}
}
+void AutofillDialogViews::ShowDialogInMode(DialogMode dialog_mode) {
+ std::vector<views::View*> visible;
+
+ if (dialog_mode == LOADING) {
+ visible.push_back(loading_shield_);
+ } else if (dialog_mode == SIGN_IN) {
+ visible.push_back(sign_in_web_view_);
+ } else {
+ DCHECK_EQ(DETAIL_INPUT, dialog_mode);
+ visible.push_back(notification_area_);
+ visible.push_back(scrollable_area_);
+ }
+
+ for (size_t i = 0; i < visible.size(); ++i) {
+ DCHECK_GE(GetIndexOf(visible[i]), 0);
+ }
+
+ for (int i = 0; i < child_count(); ++i) {
+ views::View* child = child_at(i);
+ child->SetVisible(
+ std::find(visible.begin(), visible.end(), child) != visible.end());
+ }
+}
+
+views::View* AutofillDialogViews::GetLoadingShieldForTesting() {
+ return loading_shield_;
+}
+
+views::WebView* AutofillDialogViews::GetSignInWebViewForTesting() {
+ return sign_in_web_view_;
+}
+
+views::View* AutofillDialogViews::GetNotificationAreaForTesting() {
+ return notification_area_;
+}
+
+views::View* AutofillDialogViews::GetScrollableAreaForTesting() {
+ return scrollable_area_;
+}
+
void AutofillDialogViews::AccountChooser::LinkClicked(views::Link* source,
int event_flags) {
delegate_->SignInLinkClicked();
@@ -877,9 +934,10 @@ void AutofillDialogViews::OnWidgetClosing(views::Widget* widget) {
void AutofillDialogViews::OnWidgetBoundsChanged(views::Widget* widget,
const gfx::Rect& new_bounds) {
// Notify the web contents of its new auto-resize limits.
- if (sign_in_delegate_ && sign_in_webview_->visible())
+ if (sign_in_delegate_ && sign_in_web_view_->visible()) {
sign_in_delegate_->UpdateLimitsAndEnableAutoResize(
GetMinimumSignInViewSize(), GetMaximumSignInViewSize());
+ }
HideErrorBubble();
}
@@ -1265,7 +1323,7 @@ AutofillDialogViews::AutofillDialogViews(AutofillDialogViewDelegate* delegate)
window_(NULL),
notification_area_(NULL),
account_chooser_(NULL),
- sign_in_webview_(NULL),
+ sign_in_web_view_(NULL),
scrollable_area_(NULL),
details_container_(NULL),
loading_shield_(NULL),
@@ -1358,9 +1416,11 @@ void AutofillDialogViews::UpdateAccountChooser() {
if (show_loading) {
loading_shield_height_ = std::max(kInitialLoadingShieldHeight,
GetContentsBounds().height());
+ ShowDialogInMode(LOADING);
+ } else {
+ ShowDialogInMode(DETAIL_INPUT);
}
- loading_shield_->SetVisible(show_loading);
InvalidateLayout();
ContentsPreferredSizeChanged();
}
@@ -1398,7 +1458,6 @@ void AutofillDialogViews::UpdateButtonStrip() {
}
void AutofillDialogViews::UpdateOverlay() {
- DialogOverlayState overlay_state = delegate_->GetDialogOverlay();
overlay_view_->UpdateState();
}
@@ -1438,7 +1497,7 @@ void AutofillDialogViews::FillSection(DialogSection section,
// If the Autofill data comes from a credit card, make sure to overwrite the
// CC comboboxes (even if they already have something in them). If the
// Autofill data comes from an AutofillProfile, leave the comboboxes alone.
- if ((section == SECTION_CC || section == SECTION_CC_BILLING) &&
+ if (section == GetCreditCardSection() &&
AutofillType(originating_input.type).group() == CREDIT_CARD) {
for (ComboboxMap::const_iterator it = group->comboboxes.begin();
it != group->comboboxes.end(); ++it) {
@@ -1465,9 +1524,7 @@ void AutofillDialogViews::GetUserInput(DialogSection section,
}
base::string16 AutofillDialogViews::GetCvc() {
- DialogSection billing_section = delegate_->SectionIsActive(SECTION_CC) ?
- SECTION_CC : SECTION_CC_BILLING;
- return GroupForSection(billing_section)->suggested_info->
+ return GroupForSection(GetCreditCardSection())->suggested_info->
decorated_textfield()->text();
}
@@ -1498,20 +1555,21 @@ const content::NavigationController* AutofillDialogViews::ShowSignIn() {
sign_in_delegate_.reset(
new AutofillDialogSignInDelegate(
- this, sign_in_webview_->GetWebContents(),
+ this, sign_in_web_view_->GetWebContents(),
delegate_->GetWebContents()->GetDelegate(),
GetMinimumSignInViewSize(), GetMaximumSignInViewSize()));
- sign_in_webview_->LoadInitialURL(wallet::GetSignInUrl());
+ sign_in_web_view_->LoadInitialURL(wallet::GetSignInUrl());
+
+ ShowDialogInMode(SIGN_IN);
+ sign_in_web_view_->RequestFocus();
- sign_in_webview_->SetVisible(true);
- sign_in_webview_->RequestFocus();
UpdateButtonStrip();
ContentsPreferredSizeChanged();
- return &sign_in_webview_->web_contents()->GetController();
+ return &sign_in_web_view_->web_contents()->GetController();
}
void AutofillDialogViews::HideSignIn() {
- sign_in_webview_->SetVisible(false);
+ ShowDialogInMode(DETAIL_INPUT);
UpdateButtonStrip();
ContentsPreferredSizeChanged();
}
@@ -1530,7 +1588,7 @@ TestableAutofillDialogView* AutofillDialogViews::GetTestableView() {
}
void AutofillDialogViews::OnSignInResize(const gfx::Size& pref_size) {
- sign_in_webview_->SetPreferredSize(pref_size);
+ sign_in_web_view_->SetPreferredSize(pref_size);
ContentsPreferredSizeChanged();
}
@@ -1609,8 +1667,8 @@ gfx::Size AutofillDialogViews::GetMinimumSize() {
void AutofillDialogViews::Layout() {
const gfx::Rect content_bounds = GetContentsBounds();
- if (sign_in_webview_->visible()) {
- sign_in_webview_->SetBoundsRect(content_bounds);
+ if (sign_in_web_view_->visible()) {
+ sign_in_web_view_->SetBoundsRect(content_bounds);
return;
}
@@ -1800,6 +1858,7 @@ void AutofillDialogViews::OnDidChangeFocus(
void AutofillDialogViews::OnSelectedIndexChanged(views::Combobox* combobox) {
DetailsGroup* group = GroupForView(combobox);
ValidateGroup(*group, VALIDATE_EDIT);
+ SetEditabilityForSection(group->section);
}
void AutofillDialogViews::StyledLabelLinkClicked(const gfx::Range& range,
@@ -1852,8 +1911,8 @@ gfx::Size AutofillDialogViews::CalculatePreferredSize(bool get_minimum_size) {
// The width is always set by the scroll area.
const int width = scroll_size.width();
- if (sign_in_webview_->visible()) {
- const gfx::Size size = static_cast<views::View*>(sign_in_webview_)->
+ if (sign_in_web_view_->visible()) {
+ const gfx::Size size = static_cast<views::View*>(sign_in_web_view_)->
GetPreferredSize();
return gfx::Size(width + insets.width(), size.height() + insets.height());
}
@@ -1904,6 +1963,14 @@ gfx::Size AutofillDialogViews::GetMaximumSignInViewSize() const {
return gfx::Size(width, height);
}
+DialogSection AutofillDialogViews::GetCreditCardSection() const {
+ if (delegate_->SectionIsActive(SECTION_CC))
+ return SECTION_CC;
+
+ DCHECK(delegate_->SectionIsActive(SECTION_CC_BILLING));
+ return SECTION_CC_BILLING;
+}
+
void AutofillDialogViews::InitChildViews() {
button_strip_extra_view_ = new LayoutPropagationView();
button_strip_extra_view_->SetLayoutManager(
@@ -1936,15 +2003,15 @@ void AutofillDialogViews::InitChildViews() {
AddChildView(scrollable_area_);
loading_shield_ = new LoadingAnimationView(delegate_->SpinnerText());
- loading_shield_->SetVisible(false);
AddChildView(loading_shield_);
- sign_in_webview_ = new views::WebView(delegate_->profile());
- sign_in_webview_->SetVisible(false);
- AddChildView(sign_in_webview_);
+ sign_in_web_view_ = new views::WebView(delegate_->profile());
+ AddChildView(sign_in_web_view_);
overlay_view_ = new OverlayView(delegate_);
overlay_view_->SetVisible(false);
+
+ ShowDialogInMode(DETAIL_INPUT);
}
views::View* AutofillDialogViews::CreateDetailsContainer() {
@@ -2099,7 +2166,6 @@ void AutofillDialogViews::UpdateSectionImpl(
if (text_mapping != group->textfields.end()) {
DecoratedTextfield* decorated = text_mapping->second;
- decorated->SetEnabled(input.editable);
if (decorated->text().empty() || clobber_inputs)
decorated->SetText(iter->initial_value);
}
@@ -2107,7 +2173,6 @@ void AutofillDialogViews::UpdateSectionImpl(
ComboboxMap::iterator combo_mapping = group->comboboxes.find(&input);
if (combo_mapping != group->comboboxes.end()) {
views::Combobox* combobox = combo_mapping->second;
- combobox->SetEnabled(input.editable);
if (combobox->selected_index() == combobox->model()->GetDefaultIndex() ||
clobber_inputs) {
for (int i = 0; i < combobox->model()->GetItemCount(); ++i) {
@@ -2121,6 +2186,7 @@ void AutofillDialogViews::UpdateSectionImpl(
}
SetIconsForSection(section);
+ SetEditabilityForSection(section);
UpdateDetailsGroupState(*group);
}
@@ -2230,7 +2296,7 @@ void AutofillDialogViews::MarkInputsInvalid(
++it;
}
- if (section == SECTION_CC) {
+ if (section == GetCreditCardSection()) {
// Special case CVC as it's not part of |group->manual_input|.
const ValidityMessage& message =
messages.GetMessageOrDefault(CREDIT_CARD_VERIFICATION_CODE);
@@ -2252,14 +2318,14 @@ bool AutofillDialogViews::ValidateGroup(const DetailsGroup& group,
if (group.manual_input->visible()) {
for (TextfieldMap::const_iterator iter = group.textfields.begin();
iter != group.textfields.end(); ++iter) {
- if (!iter->first->editable)
+ if (!iter->second->editable())
continue;
detail_outputs[iter->first] = iter->second->text();
}
for (ComboboxMap::const_iterator iter = group.comboboxes.begin();
iter != group.comboboxes.end(); ++iter) {
- if (!iter->first->editable)
+ if (!iter->second->enabled())
continue;
views::Combobox* combobox = iter->second;
@@ -2267,12 +2333,14 @@ bool AutofillDialogViews::ValidateGroup(const DetailsGroup& group,
combobox->model()->GetItemAt(combobox->selected_index());
detail_outputs[iter->first] = item;
}
- } else if (group.section == SECTION_CC) {
+ } else if (group.section == GetCreditCardSection()) {
DecoratedTextfield* decorated_cvc =
group.suggested_info->decorated_textfield();
- cvc_input.reset(new DetailInput);
- cvc_input->type = CREDIT_CARD_VERIFICATION_CODE;
- detail_outputs[cvc_input.get()] = decorated_cvc->text();
+ if (decorated_cvc->visible()) {
+ cvc_input.reset(new DetailInput);
+ cvc_input->type = CREDIT_CARD_VERIFICATION_CODE;
+ detail_outputs[cvc_input.get()] = decorated_cvc->text();
+ }
}
ValidityMessages validity = delegate_->InputsAreValid(group.section,
@@ -2352,6 +2420,8 @@ void AutofillDialogViews::TextfieldEditedOrActivated(
if (delegate_->FieldControlsIcons(type))
SetIconsForSection(group->section);
+
+ SetEditabilityForSection(group->section);
}
void AutofillDialogViews::UpdateButtonStripExtraView() {
@@ -2467,6 +2537,31 @@ void AutofillDialogViews::SetIconsForSection(DialogSection section) {
}
}
+void AutofillDialogViews::SetEditabilityForSection(DialogSection section) {
+ const DetailInputs& inputs =
+ delegate_->RequestedFieldsForSection(section);
+ DetailsGroup* group = GroupForSection(section);
+
+ for (DetailInputs::const_iterator iter = inputs.begin();
+ iter != inputs.end(); ++iter) {
+ const DetailInput& input = *iter;
+ bool editable = delegate_->InputIsEditable(input, section);
+
+ TextfieldMap::iterator text_mapping = group->textfields.find(&input);
+ if (text_mapping != group->textfields.end()) {
+ DecoratedTextfield* decorated = text_mapping->second;
+ decorated->SetEditable(editable);
+ continue;
+ }
+
+ ComboboxMap::iterator combo_mapping = group->comboboxes.find(&input);
+ if (combo_mapping != group->comboboxes.end()) {
+ views::Combobox* combobox = combo_mapping->second;
+ combobox->SetEnabled(editable);
+ }
+ }
+}
+
AutofillDialogViews::DetailsGroup::DetailsGroup(DialogSection section)
: section(section),
container(NULL),
diff --git a/chrome/browser/ui/views/autofill/autofill_dialog_views.h b/chrome/browser/ui/views/autofill/autofill_dialog_views.h
index ef59102563..4f57cf44f9 100644
--- a/chrome/browser/ui/views/autofill/autofill_dialog_views.h
+++ b/chrome/browser/ui/views/autofill/autofill_dialog_views.h
@@ -167,6 +167,26 @@ class AutofillDialogViews : public AutofillDialogView,
virtual void OnMenuButtonClicked(views::View* source,
const gfx::Point& point) OVERRIDE;
+ protected:
+ // What the entire dialog should be doing (e.g. gathering info from the user,
+ // asking the user to sign in, etc.).
+ enum DialogMode {
+ DETAIL_INPUT,
+ LOADING,
+ SIGN_IN,
+ };
+
+ // Changes the function of the whole dialog. Currently this can show a loading
+ // shield, an embedded sign in web view, or the more typical detail input mode
+ // (suggestions and form inputs).
+ void ShowDialogInMode(DialogMode dialog_mode);
+
+ // Exposed for testing.
+ views::View* GetLoadingShieldForTesting();
+ views::WebView* GetSignInWebViewForTesting();
+ views::View* GetNotificationAreaForTesting();
+ views::View* GetScrollableAreaForTesting();
+
private:
// A class that creates and manages a widget for error messages.
class ErrorBubble : public views::BubbleDelegateView {
@@ -207,6 +227,9 @@ class AutofillDialogViews : public AutofillDialogView,
// right edge of |anchor_|. Must contain |anchor_|.
views::View* const anchor_container_; // Weak.
+ // Whether the bubble should be shown above the anchor (default is below).
+ const bool show_above_anchor_;
+
DISALLOW_COPY_AND_ASSIGN(ErrorBubble);
};
@@ -504,6 +527,9 @@ class AutofillDialogViews : public AutofillDialogView,
// Returns the maximum size of the sign in view for this dialog.
gfx::Size GetMaximumSignInViewSize() const;
+ // Returns which section should currently be used for credit card info.
+ DialogSection GetCreditCardSection() const;
+
void InitChildViews();
// Creates and returns a view that holds all detail sections.
@@ -519,10 +545,6 @@ class AutofillDialogViews : public AutofillDialogView,
// inputs View, and suggestion model. Relevant pointers are stored in |group|.
void CreateDetailsSection(DialogSection section);
- // Like CreateDetailsSection, but creates the combined billing/cc section,
- // which is somewhat more complicated than the others.
- void CreateBillingSection();
-
// Creates the view that holds controls for inputing or selecting data for
// a given section.
views::View* CreateInputsContainer(DialogSection section);
@@ -603,6 +625,10 @@ class AutofillDialogViews : public AutofillDialogView,
// sets the credit card and CVC icons according to the credit card number.
void SetIconsForSection(DialogSection section);
+ // Iterates over all the inputs in |section| and sets their enabled/disabled
+ // state.
+ void SetEditabilityForSection(DialogSection section);
+
// The delegate that drives this view. Weak pointer, always non-NULL.
AutofillDialogViewDelegate* const delegate_;
@@ -634,7 +660,7 @@ class AutofillDialogViews : public AutofillDialogView,
// A WebView to that navigates to a Google sign-in page to allow the user to
// sign-in.
- views::WebView* sign_in_webview_;
+ views::WebView* sign_in_web_view_;
// View that wraps |details_container_| and makes it scroll vertically.
views::ScrollView* scrollable_area_;
diff --git a/chrome/browser/ui/views/autofill/autofill_dialog_views_unittest.cc b/chrome/browser/ui/views/autofill/autofill_dialog_views_unittest.cc
new file mode 100644
index 0000000000..04087d0fd7
--- /dev/null
+++ b/chrome/browser/ui/views/autofill/autofill_dialog_views_unittest.cc
@@ -0,0 +1,186 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/autofill/autofill_dialog_views.h"
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/ui/autofill/mock_autofill_dialog_view_delegate.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/frame/test_with_browser_view.h"
+#include "components/web_modal/test_web_contents_modal_dialog_host.h"
+#include "components/web_modal/test_web_contents_modal_dialog_manager_delegate.h"
+#include "components/web_modal/web_contents_modal_dialog_manager.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/views/controls/webview/webview.h"
+#include "ui/views/widget/widget.h"
+
+namespace autofill {
+
+namespace {
+
+using web_modal::WebContentsModalDialogManager;
+
+// A views implementation of the Autofill dialog with slightly more testability.
+class TestAutofillDialogViews : public AutofillDialogViews {
+ public:
+ explicit TestAutofillDialogViews(AutofillDialogViewDelegate* delegate)
+ : AutofillDialogViews(delegate) {}
+ virtual ~TestAutofillDialogViews() {}
+
+ void ShowLoadingMode() { ShowDialogInMode(LOADING); }
+ void ShowSignInMode() { ShowDialogInMode(SIGN_IN); }
+ void ShowDetailInputMode() { ShowDialogInMode(DETAIL_INPUT); }
+
+ using AutofillDialogViews::GetLoadingShieldForTesting;
+ using AutofillDialogViews::GetSignInWebViewForTesting;
+ using AutofillDialogViews::GetNotificationAreaForTesting;
+ using AutofillDialogViews::GetScrollableAreaForTesting;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestAutofillDialogViews);
+};
+
+} // namespace
+
+class AutofillDialogViewsTest : public TestWithBrowserView {
+ public:
+ AutofillDialogViewsTest() {}
+ virtual ~AutofillDialogViewsTest() {}
+
+ // TestWithBrowserView:
+ virtual void SetUp() OVERRIDE {
+ TestWithBrowserView::SetUp();
+
+ AddTab(browser(), GURL());
+ TabStripModel* tab_strip_model = browser()->tab_strip_model();
+ content::WebContents* contents = tab_strip_model->GetWebContentsAt(0);
+ ASSERT_TRUE(contents);
+ view_delegate_.SetWebContents(contents);
+
+ BrowserView* browser_view =
+ BrowserView::GetBrowserViewForBrowser(browser());
+ dialog_host_.reset(new web_modal::TestWebContentsModalDialogHost(
+ browser_view->GetWidget()->GetNativeView()));
+ dialog_delegate_.set_web_contents_modal_dialog_host(dialog_host_.get());
+
+ WebContentsModalDialogManager* dialog_manager =
+ WebContentsModalDialogManager::FromWebContents(contents);
+ ASSERT_TRUE(dialog_manager);
+ dialog_manager->SetDelegate(&dialog_delegate_);
+
+ dialog_.reset(new TestAutofillDialogViews(&view_delegate_));
+ dialog_->Show();
+ }
+
+ virtual void TearDown() OVERRIDE {
+ dialog_->GetWidget()->CloseNow();
+
+ TestWithBrowserView::TearDown();
+ }
+
+ TestAutofillDialogViews* dialog() { return dialog_.get(); }
+
+ protected:
+ // Allows each main section (e.g. loading shield, sign in web view,
+ // notification area, and scrollable area) to get focus. Used in focus-related
+ // tests.
+ void SetSectionsFocusable() {
+ dialog()->GetLoadingShieldForTesting()->set_focusable(true);
+ // The sign in web view has a different implementation of IsFocusable().
+ dialog()->GetNotificationAreaForTesting()->set_focusable(true);
+ dialog()->GetScrollableAreaForTesting()->set_focusable(true);
+ }
+
+ private:
+ // Fake dialog delegate and host to isolate test behavior.
+ web_modal::TestWebContentsModalDialogManagerDelegate dialog_delegate_;
+ scoped_ptr<web_modal::TestWebContentsModalDialogHost> dialog_host_;
+
+ // Mock view delegate as this file only tests the view.
+ testing::NiceMock<MockAutofillDialogViewDelegate> view_delegate_;
+
+ scoped_ptr<TestAutofillDialogViews> dialog_;
+};
+
+TEST_F(AutofillDialogViewsTest, ShowLoadingMode) {
+ SetSectionsFocusable();
+
+ dialog()->ShowLoadingMode();
+
+ views::View* loading_shield = dialog()->GetLoadingShieldForTesting();
+ EXPECT_TRUE(loading_shield->visible());
+ EXPECT_TRUE(loading_shield->IsFocusable());
+
+ loading_shield->RequestFocus();
+ EXPECT_TRUE(loading_shield->HasFocus());
+
+ views::View* sign_in_web_view = dialog()->GetSignInWebViewForTesting();
+ EXPECT_FALSE(sign_in_web_view->visible());
+ EXPECT_FALSE(sign_in_web_view->IsFocusable());
+
+ views::View* notification_area = dialog()->GetNotificationAreaForTesting();
+ EXPECT_FALSE(notification_area->visible());
+ EXPECT_FALSE(notification_area->IsFocusable());
+
+ views::View* scrollable_area = dialog()->GetScrollableAreaForTesting();
+ EXPECT_FALSE(scrollable_area->visible());
+ EXPECT_FALSE(scrollable_area->IsFocusable());
+}
+
+TEST_F(AutofillDialogViewsTest, ShowSignInMode) {
+ SetSectionsFocusable();
+
+ dialog()->ShowSignInMode();
+
+ views::View* loading_shield = dialog()->GetLoadingShieldForTesting();
+ EXPECT_FALSE(loading_shield->visible());
+ EXPECT_FALSE(loading_shield->IsFocusable());
+
+ views::View* sign_in_web_view = dialog()->GetSignInWebViewForTesting();
+ EXPECT_TRUE(sign_in_web_view->visible());
+ // NOTE: |sign_in_web_view| is not focusable until a web contents is created.
+ // TODO(dbeam): figure out how to create a web contents on the right thread.
+
+ views::View* notification_area = dialog()->GetNotificationAreaForTesting();
+ EXPECT_FALSE(notification_area->visible());
+ EXPECT_FALSE(notification_area->IsFocusable());
+
+ views::View* scrollable_area = dialog()->GetScrollableAreaForTesting();
+ EXPECT_FALSE(scrollable_area->visible());
+ EXPECT_FALSE(scrollable_area->IsFocusable());
+}
+
+TEST_F(AutofillDialogViewsTest, ShowDetailInputMode) {
+ SetSectionsFocusable();
+
+ dialog()->ShowDetailInputMode();
+
+ views::View* loading_shield = dialog()->GetLoadingShieldForTesting();
+ EXPECT_FALSE(loading_shield->visible());
+ EXPECT_FALSE(loading_shield->IsFocusable());
+
+ views::View* sign_in_web_view = dialog()->GetSignInWebViewForTesting();
+ EXPECT_FALSE(sign_in_web_view->visible());
+ EXPECT_FALSE(sign_in_web_view->IsFocusable());
+
+ views::View* notification_area = dialog()->GetNotificationAreaForTesting();
+ EXPECT_TRUE(notification_area->visible());
+ EXPECT_TRUE(notification_area->IsFocusable());
+
+ views::View* scrollable_area = dialog()->GetScrollableAreaForTesting();
+ EXPECT_TRUE(scrollable_area->visible());
+ EXPECT_TRUE(scrollable_area->IsFocusable());
+
+ notification_area->RequestFocus();
+ EXPECT_TRUE(notification_area->HasFocus());
+
+ scrollable_area->RequestFocus();
+ EXPECT_TRUE(scrollable_area->HasFocus());
+}
+
+} // namespace autofill
diff --git a/chrome/browser/ui/views/autofill/decorated_textfield.cc b/chrome/browser/ui/views/autofill/decorated_textfield.cc
index 02bf92d9ef..d4c0fa34f9 100644
--- a/chrome/browser/ui/views/autofill/decorated_textfield.cc
+++ b/chrome/browser/ui/views/autofill/decorated_textfield.cc
@@ -31,9 +31,9 @@ DecoratedTextfield::DecoratedTextfield(
const base::string16& placeholder,
views::TextfieldController* controller)
: border_(new views::FocusableBorder()),
- invalid_(false) {
- set_background(
- views::Background::CreateSolidBackground(GetBackgroundColor()));
+ invalid_(false),
+ editable_(true) {
+ UpdateBackground();
set_border(border_);
// Removes the border from |native_wrapper_|.
@@ -49,6 +49,9 @@ DecoratedTextfield::~DecoratedTextfield() {}
void DecoratedTextfield::SetInvalid(bool invalid) {
invalid_ = invalid;
+ if (!editable_)
+ return;
+
if (invalid)
border_->SetColor(kWarningColor);
else
@@ -56,6 +59,24 @@ void DecoratedTextfield::SetInvalid(bool invalid) {
SchedulePaint();
}
+void DecoratedTextfield::SetEditable(bool editable) {
+ if (editable_ == editable)
+ return;
+
+ editable_ = editable;
+ if (editable) {
+ SetInvalid(invalid_);
+ UseDefaultBackgroundColor();
+ } else {
+ border_->SetColor(SK_ColorTRANSPARENT);
+ SetBackgroundColor(SK_ColorTRANSPARENT);
+ }
+
+ UpdateBackground();
+ SetEnabled(editable);
+ IconChanged();
+}
+
void DecoratedTextfield::SetIcon(const gfx::Image& icon) {
if (!icon_view_ && icon.IsEmpty())
return;
@@ -88,6 +109,13 @@ void DecoratedTextfield::SetTooltipIcon(const base::string16& text) {
IconChanged();
}
+base::string16 DecoratedTextfield::GetPlaceholderText() const {
+ if (!editable_)
+ return base::string16();
+
+ return views::Textfield::GetPlaceholderText();
+}
+
const char* DecoratedTextfield::GetClassName() const {
return kViewClassName;
}
@@ -113,7 +141,7 @@ gfx::Size DecoratedTextfield::GetPreferredSize() {
void DecoratedTextfield::Layout() {
views::Textfield::Layout();
- if (icon_view_) {
+ if (icon_view_ && icon_view_->visible()) {
gfx::Rect bounds = GetContentsBounds();
gfx::Size icon_size = icon_view_->GetPreferredSize();
int x = base::i18n::IsRTL() ?
@@ -128,7 +156,15 @@ void DecoratedTextfield::Layout() {
}
}
+void DecoratedTextfield::UpdateBackground() {
+ set_background(
+ views::Background::CreateSolidBackground(GetBackgroundColor()));
+}
+
void DecoratedTextfield::IconChanged() {
+ // Don't show the icon if nothing else is showing.
+ icon_view_->SetVisible(editable_ || !text().empty());
+
int icon_space = icon_view_ ?
icon_view_->GetPreferredSize().width() + 2 * kTextfieldIconPadding : 0;
diff --git a/chrome/browser/ui/views/autofill/decorated_textfield.h b/chrome/browser/ui/views/autofill/decorated_textfield.h
index 77195af78a..9acf971ced 100644
--- a/chrome/browser/ui/views/autofill/decorated_textfield.h
+++ b/chrome/browser/ui/views/autofill/decorated_textfield.h
@@ -33,6 +33,10 @@ class DecoratedTextfield : public views::Textfield {
void SetInvalid(bool invalid);
bool invalid() const { return invalid_; }
+ // See docs for |editable_|.
+ void SetEditable(bool editable);
+ bool editable() const { return editable_; }
+
// Sets the icon to be displayed inside the textfield at the end of the
// text.
void SetIcon(const gfx::Image& icon);
@@ -41,6 +45,9 @@ class DecoratedTextfield : public views::Textfield {
// SetIcon(), if any, and will be overridden by future calls to SetIcon().
void SetTooltipIcon(const base::string16& text);
+ // views::Textfield implementation.
+ virtual base::string16 GetPlaceholderText() const OVERRIDE;
+
// views::View implementation.
virtual const char* GetClassName() const OVERRIDE;
virtual gfx::Size GetPreferredSize() OVERRIDE;
@@ -51,6 +58,10 @@ class DecoratedTextfield : public views::Textfield {
private:
FRIEND_TEST_ALL_PREFIXES(DecoratedTextfieldTest, HeightMatchesButton);
+ // Updates the background of |this| after it may have changed. This is
+ // necessary for the sake of the padding around the native textfield.
+ void UpdateBackground();
+
// Called to update the layout after SetIcon or SetTooltipIcon has been
// called.
void IconChanged();
@@ -71,6 +82,11 @@ class DecoratedTextfield : public views::Textfield {
// shown to indicate invalidness).
bool invalid_;
+ // Whether the user can edit the field. When not editable, many of the
+ // pieces of the textfield disappear (border, background, icon, placeholder
+ // text) and it can't receive focus.
+ bool editable_;
+
DISALLOW_COPY_AND_ASSIGN(DecoratedTextfield);
};
diff --git a/chrome/browser/ui/views/avatar_menu_bubble_view.h b/chrome/browser/ui/views/avatar_menu_bubble_view.h
index 781e6bee97..e9e722553b 100644
--- a/chrome/browser/ui/views/avatar_menu_bubble_view.h
+++ b/chrome/browser/ui/views/avatar_menu_bubble_view.h
@@ -131,7 +131,6 @@ class AvatarMenuBubbleView : public views::BubbleDelegateView,
bool expanded_;
DISALLOW_COPY_AND_ASSIGN(AvatarMenuBubbleView);
- FRIEND_TEST_ALL_PREFIXES(AvatarMenuButtonTest, SignOut);
};
#endif // CHROME_BROWSER_UI_VIEWS_AVATAR_MENU_BUBBLE_VIEW_H_
diff --git a/chrome/browser/ui/views/avatar_menu_button_browsertest.cc b/chrome/browser/ui/views/avatar_menu_button_browsertest.cc
index a3c01250ca..02f5cb33e8 100644
--- a/chrome/browser/ui/views/avatar_menu_button_browsertest.cc
+++ b/chrome/browser/ui/views/avatar_menu_button_browsertest.cc
@@ -7,35 +7,24 @@
#include "base/command_line.h"
#include "base/path_service.h"
#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/profiles/avatar_menu.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/profiles/profiles_state.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/views/avatar_menu_bubble_view.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
-#include "chrome/browser/ui/views/profile_chooser_view.h"
-#include "chrome/browser/ui/views/user_manager_view.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/test_switches.h"
#include "chrome/test/base/testing_browser_process.h"
-#include "content/public/test/test_utils.h"
#include "grit/generated_resources.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/views/controls/button/label_button.h"
-class AvatarMenuButtonTest : public InProcessBrowserTest,
- public testing::WithParamInterface<bool> {
+class AvatarMenuButtonTest : public InProcessBrowserTest {
public:
AvatarMenuButtonTest();
virtual ~AvatarMenuButtonTest();
protected:
- virtual void SetUp() OVERRIDE;
-
- bool UsingNewProfileChooser();
void CreateTestingProfile();
AvatarMenuButton* GetAvatarMenuButton();
void StartAvatarMenu();
@@ -50,33 +39,10 @@ AvatarMenuButtonTest::AvatarMenuButtonTest() {
AvatarMenuButtonTest::~AvatarMenuButtonTest() {
}
-void AvatarMenuButtonTest::SetUp() {
- if (GetParam()) {
- if (!UsingNewProfileChooser()) {
- CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kNewProfileManagement);
- }
- DCHECK(UsingNewProfileChooser());
- } else {
- DCHECK(!UsingNewProfileChooser());
- }
-
- InProcessBrowserTest::SetUp();
-}
-
-bool AvatarMenuButtonTest::UsingNewProfileChooser() {
- return CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kNewProfileManagement);
-}
-
void AvatarMenuButtonTest::CreateTestingProfile() {
ProfileManager* profile_manager = g_browser_process->profile_manager();
EXPECT_EQ(1u, profile_manager->GetNumberOfProfiles());
- // Sign in the default profile
- ProfileInfoCache& cache = profile_manager->GetProfileInfoCache();
- cache.SetUserNameOfProfileAtIndex(0, UTF8ToUTF16("user_name"));
-
base::FilePath path;
PathService::Get(chrome::DIR_USER_DATA, &path);
path = path.AppendASCII("test_profile");
@@ -99,28 +65,25 @@ void AvatarMenuButtonTest::StartAvatarMenu() {
ASSERT_TRUE(button);
AvatarMenuBubbleView::set_close_on_deactivate(false);
- ProfileChooserView::set_close_on_deactivate(false);
static_cast<views::MenuButtonListener*>(button)->OnMenuButtonClicked(
NULL, gfx::Point());
base::MessageLoop::current()->RunUntilIdle();
- EXPECT_NE(AvatarMenuBubbleView::IsShowing(),
- ProfileChooserView::IsShowing());
+ EXPECT_TRUE(AvatarMenuBubbleView::IsShowing());
}
-IN_PROC_BROWSER_TEST_P(AvatarMenuButtonTest, HideOnSecondClick) {
+IN_PROC_BROWSER_TEST_F(AvatarMenuButtonTest, HideOnSecondClick) {
#if defined(OS_WIN) && defined(USE_ASH)
// Disable this test in Metro+Ash for now (http://crbug.com/262796).
if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
return;
#endif
- if (!profiles::IsMultipleProfilesEnabled() ||
- UsingNewProfileChooser()) {
+ // If multiprofile mode is not enabled, you can't switch between profiles.
+ if (!profiles::IsMultipleProfilesEnabled())
return;
- }
CreateTestingProfile();
- StartAvatarMenu();
+ ASSERT_NO_FATAL_FAILURE(StartAvatarMenu());
// Verify that clicking again doesn't reshow it.
AvatarMenuButton* button = GetAvatarMenuButton();
@@ -131,44 +94,4 @@ IN_PROC_BROWSER_TEST_P(AvatarMenuButtonTest, HideOnSecondClick) {
AvatarMenuBubbleView::Hide();
base::MessageLoop::current()->RunUntilIdle();
EXPECT_FALSE(AvatarMenuBubbleView::IsShowing());
- EXPECT_FALSE(ProfileChooserView::IsShowing());
-}
-
-IN_PROC_BROWSER_TEST_P(AvatarMenuButtonTest, NewSignOut) {
- if (!profiles::IsMultipleProfilesEnabled() ||
- !UsingNewProfileChooser()) {
- return;
- }
-
- CreateTestingProfile();
- StartAvatarMenu();
-
- BrowserList* browser_list =
- BrowserList::GetInstance(chrome::GetActiveDesktop());
- EXPECT_EQ(1U, browser_list->size());
- content::WindowedNotificationObserver window_close_observer(
- chrome::NOTIFICATION_BROWSER_CLOSED,
- content::Source<Browser>(browser()));
-
- AvatarMenu* menu =
- ProfileChooserView::profile_bubble_->avatar_menu_.get();
- const AvatarMenu::Item& menu_item_before =
- menu->GetItemAt(menu->GetActiveProfileIndex());
- EXPECT_FALSE(menu_item_before.signin_required);
-
- ui::MouseEvent mouse_ev(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(), 0);
- menu->SetLogoutURL("about:blank");
-
- ProfileChooserView::profile_bubble_->LinkClicked(
- static_cast<views::Link*>(
- ProfileChooserView::profile_bubble_->signout_current_profile_link_),
- 0);
-
- EXPECT_TRUE(menu->GetItemAt(menu->GetActiveProfileIndex()).signin_required);
-
- window_close_observer.Wait(); // Rely on test timeout for failure indication.
- EXPECT_TRUE(browser_list->empty());
}
-
-INSTANTIATE_TEST_CASE_P(Old, AvatarMenuButtonTest, testing::Values(false));
-INSTANTIATE_TEST_CASE_P(New, AvatarMenuButtonTest, testing::Values(true));
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
index 89b63d256c..67f415f546 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
@@ -110,10 +110,6 @@ static gfx::ImageSkia* kDefaultFavicon = NULL;
// Icon used for folders.
static gfx::ImageSkia* kFolderIcon = NULL;
-// Offset for where the menu is shown relative to the bottom of the
-// BookmarkBarView.
-static const int kMenuOffset = 3;
-
// Color of the drop indicator.
static const SkColor kDropIndicatorColor = SK_ColorBLACK;
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc
index c8a29788f6..5cce19047f 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc
@@ -998,7 +998,7 @@ class BookmarkBarViewTest10 : public BookmarkBarViewEventTestBase {
}
};
-VIEW_TEST(BookmarkBarViewTest10, DISABLED_KeyEvents)
+VIEW_TEST(BookmarkBarViewTest10, KeyEvents)
// Make sure the menu closes with the following sequence: show menu, show
// context menu, close context menu (via escape), then click else where. This
diff --git a/chrome/browser/ui/views/browser_actions_container.cc b/chrome/browser/ui/views/browser_actions_container.cc
index 850189762b..5e525e39ee 100644
--- a/chrome/browser/ui/views/browser_actions_container.cc
+++ b/chrome/browser/ui/views/browser_actions_container.cc
@@ -9,10 +9,12 @@
#include "base/stl_util.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/extensions/tab_helper.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sessions/session_tab_helper.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/view_ids.h"
#include "chrome/browser/ui/views/browser_action_view.h"
@@ -459,7 +461,7 @@ void BrowserActionsContainer::OnWidgetDestroying(views::Widget* widget) {
void BrowserActionsContainer::InspectPopup(ExtensionAction* action) {
BrowserActionView* view = GetBrowserActionView(action);
- ShowPopup(view->button(), ExtensionPopup::SHOW_AND_INSPECT);
+ ShowPopup(view->button(), ExtensionPopup::SHOW_AND_INSPECT, true);
}
int BrowserActionsContainer::GetCurrentTabId() const {
@@ -473,7 +475,7 @@ int BrowserActionsContainer::GetCurrentTabId() const {
void BrowserActionsContainer::OnBrowserActionExecuted(
BrowserActionButton* button) {
- ShowPopup(button, ExtensionPopup::SHOW);
+ ShowPopup(button, ExtensionPopup::SHOW, true);
}
void BrowserActionsContainer::OnBrowserActionVisibilityChanged() {
@@ -686,6 +688,27 @@ void BrowserActionsContainer::BrowserActionMoved(const Extension* extension,
SchedulePaint();
}
+bool BrowserActionsContainer::BrowserActionShowPopup(
+ const extensions::Extension* extension) {
+ // Do not override other popups and only show in active window. The window
+ // must also have a toolbar, otherwise it should not be showing popups.
+ // TODO(justinlin): Remove toolbar check when http://crbug.com/308645 is
+ // fixed.
+ if (popup_ ||
+ !browser_->window()->IsActive() ||
+ !browser_->window()->IsToolbarVisible()) {
+ return false;
+ }
+
+ for (BrowserActionViews::iterator it = browser_action_views_.begin();
+ it != browser_action_views_.end(); ++it) {
+ BrowserActionButton* button = (*it)->button();
+ if (button && button->extension() == extension)
+ return ShowPopup(button, ExtensionPopup::SHOW, false);
+ }
+ return false;
+}
+
void BrowserActionsContainer::ModelLoaded() {
SetContainerWidth();
}
@@ -808,18 +831,21 @@ bool BrowserActionsContainer::ShouldDisplayBrowserAction(
// Only display incognito-enabled extensions while in incognito mode.
return
(!profile_->IsOffTheRecord() ||
- extensions::ExtensionSystem::Get(profile_)->extension_service()->
- IsIncognitoEnabled(extension->id()));
+ extension_util::IsIncognitoEnabled(
+ extension->id(),
+ extensions::ExtensionSystem::Get(profile_)->extension_service()));
}
-void BrowserActionsContainer::ShowPopup(
+bool BrowserActionsContainer::ShowPopup(
BrowserActionButton* button,
- ExtensionPopup::ShowAction show_action) {
+ ExtensionPopup::ShowAction show_action,
+ bool should_grant) {
const Extension* extension = button->extension();
GURL popup_url;
- if (model_->ExecuteBrowserAction(extension, browser_, &popup_url) !=
+ if (model_->ExecuteBrowserAction(
+ extension, browser_, &popup_url, should_grant) !=
ExtensionToolbarModel::ACTION_SHOW_POPUP) {
- return;
+ return false;
}
// If we're showing the same popup, just hide it and return.
@@ -830,7 +856,7 @@ void BrowserActionsContainer::ShowPopup(
HidePopup();
if (same_showing)
- return;
+ return false;
// We can get the execute event for browser actions that are not visible,
// since buttons can be activated from the overflow menu (chevron). In that
@@ -845,5 +871,9 @@ void BrowserActionsContainer::ShowPopup(
show_action);
popup_->GetWidget()->AddObserver(this);
popup_button_ = button;
- popup_button_->SetButtonPushed();
+
+ // Only set button as pushed if it was triggered by a user click.
+ if (should_grant)
+ popup_button_->SetButtonPushed();
+ return true;
}
diff --git a/chrome/browser/ui/views/browser_actions_container.h b/chrome/browser/ui/views/browser_actions_container.h
index 9e3fc949c5..70b42812b6 100644
--- a/chrome/browser/ui/views/browser_actions_container.h
+++ b/chrome/browser/ui/views/browser_actions_container.h
@@ -259,6 +259,8 @@ class BrowserActionsContainer
const extensions::Extension* extension) OVERRIDE;
virtual void BrowserActionMoved(const extensions::Extension* extension,
int index) OVERRIDE;
+ virtual bool BrowserActionShowPopup(
+ const extensions::Extension* extension) OVERRIDE;
virtual void ModelLoaded() OVERRIDE;
void LoadImages();
@@ -309,9 +311,12 @@ class BrowserActionsContainer
// for incognito.
bool ShouldDisplayBrowserAction(const extensions::Extension* extension);
- // Show a popup.
- void ShowPopup(BrowserActionButton* button,
- ExtensionPopup::ShowAction show_action);
+ // Show a popup. Returns true if a new popup was shown. Showing the popup will
+ // grant tab permissions if |should_grant| is true. Popup's shown via an API
+ // should not grant permissions.
+ bool ShowPopup(BrowserActionButton* button,
+ ExtensionPopup::ShowAction show_action,
+ bool should_grant);
// The vector of browser actions (icons/image buttons for each action). Note
// that not every BrowserAction in the ToolbarModel will necessarily be in
diff --git a/chrome/browser/ui/views/browser_dialogs.h b/chrome/browser/ui/views/browser_dialogs.h
index b7d684f8a6..d1a941f192 100644
--- a/chrome/browser/ui/views/browser_dialogs.h
+++ b/chrome/browser/ui/views/browser_dialogs.h
@@ -21,10 +21,6 @@ class FindBar;
class Profile;
class TemplateURL;
-namespace extensions {
-class Extension;
-}
-
namespace chrome {
// Creates and returns a find bar for the given browser window. See FindBarWin.
@@ -40,12 +36,6 @@ void EditSearchEngine(gfx::NativeWindow parent,
EditSearchEngineControllerDelegate* delegate,
Profile* profile);
-// Shows the create chrome app shortcut dialog box.
-void ShowCreateChromeAppShortcutsDialog(gfx::NativeWindow parent_window,
- Profile* profile,
- const extensions::Extension* app,
- const base::Closure& close_callback);
-
} // namespace chrome
#endif // CHROME_BROWSER_UI_VIEWS_BROWSER_DIALOGS_H_
diff --git a/chrome/browser/ui/views/constrained_window_views.cc b/chrome/browser/ui/views/constrained_window_views.cc
index 81fb7db462..1309cc221b 100644
--- a/chrome/browser/ui/views/constrained_window_views.cc
+++ b/chrome/browser/ui/views/constrained_window_views.cc
@@ -101,6 +101,10 @@ void UpdateModalDialogPosition(
views::Widget* widget,
web_modal::ModalDialogHost* dialog_host,
const gfx::Size& size) {
+ // Do not forcibly update the dialog widget position if it is being dragged.
+ if (widget->HasCapture())
+ return;
+
gfx::Point position = dialog_host->GetDialogPosition(size);
views::Border* border =
widget->non_client_view()->frame_view()->border();
@@ -319,9 +323,6 @@ namespace {
// The frame border is only visible in restored mode and is hardcoded to 4 px on
// each side regardless of the system window border size.
const int kFrameBorderThickness = 4;
-// Various edges of the frame border have a 1 px shadow along their edges; in a
-// few cases we shift elements based on this amount for visual appeal.
-const int kFrameShadowThickness = 1;
// In the window corners, the resize areas don't actually expand bigger, but the
// 16 px at the end of each edge triggers diagonal resizing.
const int kResizeAreaCornerSize = 16;
@@ -647,8 +648,7 @@ views::NonClientFrameView* CreateConstrainedStyleNonClientFrameView(
force_opaque_border);
}
#if defined(USE_ASH)
- ash::CustomFrameViewAsh* frame = new ash::CustomFrameViewAsh;
- frame->Init(widget);
+ ash::CustomFrameViewAsh* frame = new ash::CustomFrameViewAsh(widget);
// Always use "active" look.
frame->SetInactiveRenderingDisabled(true);
return frame;
diff --git a/chrome/browser/ui/views/constrained_window_views_unittest.cc b/chrome/browser/ui/views/constrained_window_views_unittest.cc
index 16f6d45812..bba0585569 100644
--- a/chrome/browser/ui/views/constrained_window_views_unittest.cc
+++ b/chrome/browser/ui/views/constrained_window_views_unittest.cc
@@ -4,7 +4,7 @@
#include "chrome/browser/ui/views/constrained_window_views.h"
-#include "components/web_modal/web_contents_modal_dialog_host.h"
+#include "components/web_modal/test_web_contents_modal_dialog_host.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/point.h"
#include "ui/gfx/rect.h"
@@ -13,10 +13,6 @@
#include "ui/views/widget/widget.h"
#include "ui/views/window/dialog_delegate.h"
-namespace web_modal {
-class WebContentsModalDialogHostObserver;
-}
-
namespace views {
class DialogContents : public DialogDelegateView {
@@ -39,37 +35,6 @@ class DialogContents : public DialogDelegateView {
DISALLOW_COPY_AND_ASSIGN(DialogContents);
};
-class DialogHost : public web_modal::WebContentsModalDialogHost {
- public:
- explicit DialogHost(gfx::NativeView host_view)
- : host_view_(host_view),
- max_dialog_size_(5000, 5000) {
- }
-
- virtual ~DialogHost() {}
-
- void set_max_dialog_size(const gfx::Size& max_dialog_size) {
- max_dialog_size_ = max_dialog_size;
- }
-
- // Overridden from WebContentsModalDialogHost:
- virtual gfx::NativeView GetHostView() const OVERRIDE { return host_view_; }
- virtual gfx::Point GetDialogPosition(const gfx::Size& size) OVERRIDE {
- return gfx::Point();
- }
- virtual gfx::Size GetMaximumDialogSize() OVERRIDE { return max_dialog_size_; }
- virtual void AddObserver(
- web_modal::ModalDialogHostObserver* observer) OVERRIDE {};
- virtual void RemoveObserver(
- web_modal::ModalDialogHostObserver* observer) OVERRIDE {};
-
- private:
- gfx::NativeView host_view_;
- gfx::Size max_dialog_size_;
-
- DISALLOW_COPY_AND_ASSIGN(DialogHost);
-};
-
class ConstrainedWindowViewsTest : public ViewsTestBase {
public:
ConstrainedWindowViewsTest() : contents_(NULL) {}
@@ -83,7 +48,9 @@ class ConstrainedWindowViewsTest : public ViewsTestBase {
params.delegate = contents_;
dialog_.reset(new Widget);
dialog_->Init(params);
- dialog_host_.reset(new DialogHost(dialog_->GetNativeView()));
+ dialog_host_.reset(new web_modal::TestWebContentsModalDialogHost(
+ dialog_->GetNativeView()));
+ dialog_host_->set_max_dialog_size(gfx::Size(5000, 5000));
// Make sure the dialog size is dominated by the preferred size of the
// contents.
@@ -104,12 +71,14 @@ class ConstrainedWindowViewsTest : public ViewsTestBase {
}
DialogContents* contents() { return contents_; }
- DialogHost* dialog_host() { return dialog_host_.get(); }
+ web_modal::TestWebContentsModalDialogHost* dialog_host() {
+ return dialog_host_.get();
+ }
Widget* dialog() { return dialog_.get(); }
private:
DialogContents* contents_;
- scoped_ptr<DialogHost> dialog_host_;
+ scoped_ptr<web_modal::TestWebContentsModalDialogHost> dialog_host_;
scoped_ptr<Widget> dialog_;
DISALLOW_COPY_AND_ASSIGN(ConstrainedWindowViewsTest);
diff --git a/chrome/browser/ui/views/desktop_media_picker_views.cc b/chrome/browser/ui/views/desktop_media_picker_views.cc
index 782b736ea2..4155e5bac5 100644
--- a/chrome/browser/ui/views/desktop_media_picker_views.cc
+++ b/chrome/browser/ui/views/desktop_media_picker_views.cc
@@ -113,6 +113,9 @@ class DesktopMediaListView : public views::View,
// Called by DesktopMediaSourceView when selection has changed.
void OnSelectionChanged();
+ // Called by DesktopMediaSourceView when a source has been double-clicked.
+ void OnDoubleClick();
+
// Returns currently selected source.
DesktopMediaSourceView* GetSelection();
@@ -149,6 +152,7 @@ class DesktopMediaPickerDialogView : public views::DialogDelegateView {
// Called by DesktopMediaListView.
void OnSelectionChanged();
+ void OnDoubleClick();
// views::View overrides.
virtual gfx::Size GetPreferredSize() OVERRIDE;
@@ -292,7 +296,12 @@ void DesktopMediaSourceView::OnFocus() {
}
bool DesktopMediaSourceView::OnMousePressed(const ui::MouseEvent& event) {
- RequestFocus();
+ if (event.GetClickCount() == 1) {
+ RequestFocus();
+ } else if (event.GetClickCount() == 2) {
+ RequestFocus();
+ parent_->OnDoubleClick();
+ }
return true;
}
@@ -316,6 +325,10 @@ void DesktopMediaListView::OnSelectionChanged() {
parent_->OnSelectionChanged();
}
+void DesktopMediaListView::OnDoubleClick() {
+ parent_->OnDoubleClick();
+}
+
DesktopMediaSourceView* DesktopMediaListView::GetSelection() {
for (int i = 0; i < child_count(); ++i) {
DesktopMediaSourceView* source_view =
@@ -550,6 +563,11 @@ void DesktopMediaPickerDialogView::OnSelectionChanged() {
GetDialogClientView()->UpdateDialogButtons();
}
+void DesktopMediaPickerDialogView::OnDoubleClick() {
+ // This will call Accept() and close the dialog.
+ GetDialogClientView()->AcceptWindow();
+}
+
DesktopMediaPickerViews::DesktopMediaPickerViews()
: dialog_(NULL) {
}
diff --git a/chrome/browser/ui/views/download/download_item_view.cc b/chrome/browser/ui/views/download/download_item_view.cc
index a9d7832f31..3ff7201080 100644
--- a/chrome/browser/ui/views/download/download_item_view.cc
+++ b/chrome/browser/ui/views/download/download_item_view.cc
@@ -51,9 +51,7 @@
// different screen resolutions.
static const int kTextWidth = 140; // Pixels
static const int kDangerousTextWidth = 200; // Pixels
-static const int kHorizontalTextPadding = 2; // Pixels
static const int kVerticalPadding = 3; // Pixels
-static const int kVerticalTextSpacer = 2; // Pixels
static const int kVerticalTextPadding = 2; // Pixels
static const int kTooltipMaxWidth = 800; // Pixels
@@ -1074,7 +1072,7 @@ void DownloadItemView::ClearWarningDialog() {
void DownloadItemView::ShowWarningDialog() {
DCHECK(mode_ != DANGEROUS_MODE && mode_ != MALICIOUS_MODE);
- mode_ = ((model_.IsMalicious()) ? MALICIOUS_MODE : DANGEROUS_MODE);
+ mode_ = model_.MightBeMalicious() ? MALICIOUS_MODE : DANGEROUS_MODE;
body_state_ = NORMAL;
drop_down_state_ = NORMAL;
diff --git a/chrome/browser/ui/views/download/download_started_animation_views.cc b/chrome/browser/ui/views/download/download_started_animation_views.cc
index 31d6879962..82f5b58727 100644
--- a/chrome/browser/ui/views/download/download_started_animation_views.cc
+++ b/chrome/browser/ui/views/download/download_started_animation_views.cc
@@ -21,15 +21,10 @@
using content::WebContents;
// How long to spend moving downwards and fading out after waiting.
-static const int kMoveTimeMs = 600;
+const int kMoveTimeMs = 600;
// The animation framerate.
-static const int kFrameRateHz = 60;
-
-// What fraction of the frame height to move downward from the frame center.
-// Note that setting this greater than 0.5 will mean moving past the bottom of
-// the frame.
-static const double kMoveFraction = 1.0 / 3.0;
+const int kFrameRateHz = 60;
namespace {
diff --git a/chrome/browser/ui/views/external_tab_container_win.cc b/chrome/browser/ui/views/external_tab_container_win.cc
index 5fc81f09c3..de2ba67c5e 100644
--- a/chrome/browser/ui/views/external_tab_container_win.cc
+++ b/chrome/browser/ui/views/external_tab_container_win.cc
@@ -1065,6 +1065,7 @@ bool ExternalTabContainerWin::OnMessageReceived(const IPC::Message& message) {
void ExternalTabContainerWin::DidFailProvisionalLoad(
int64 frame_id,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& validated_url,
int error_code,
diff --git a/chrome/browser/ui/views/external_tab_container_win.h b/chrome/browser/ui/views/external_tab_container_win.h
index 495d579618..91c3dfe3d9 100644
--- a/chrome/browser/ui/views/external_tab_container_win.h
+++ b/chrome/browser/ui/views/external_tab_container_win.h
@@ -183,6 +183,7 @@ class ExternalTabContainerWin : public ExternalTabContainer,
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
virtual void DidFailProvisionalLoad(
int64 frame_id,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& validated_url,
int error_code,
diff --git a/chrome/browser/ui/views/frame/browser_frame.cc b/chrome/browser/ui/views/frame/browser_frame.cc
index 3c5fb8b6ce..e45d211c9b 100644
--- a/chrome/browser/ui/views/frame/browser_frame.cc
+++ b/chrome/browser/ui/views/frame/browser_frame.cc
@@ -45,6 +45,10 @@
#include "chrome/browser/ui/ash/ash_init.h"
#endif
+#if defined(OS_CHROMEOS)
+#include "ash/session_state_delegate.h"
+#endif
+
////////////////////////////////////////////////////////////////////////////////
// BrowserFrame, public:
@@ -240,6 +244,17 @@ void BrowserFrame::ShowContextMenuForView(views::View* source,
}
ui::MenuModel* BrowserFrame::GetSystemMenuModel() {
+#if defined(OS_CHROMEOS)
+ ash::SessionStateDelegate* delegate =
+ ash::Shell::GetInstance()->session_state_delegate();
+ if (delegate && delegate->NumberOfLoggedInUsers() > 1) {
+ // In Multi user mode, the number of users as well as the order of users
+ // can change. Coming here we have more then one user and since the menu
+ // model contains the user information, it must get updated to show any
+ // changes happened since the last invocation.
+ menu_model_builder_.reset();
+ }
+#endif
if (!menu_model_builder_.get()) {
menu_model_builder_.reset(
new SystemMenuModelBuilder(browser_view_, browser_view_->browser()));
@@ -252,6 +267,10 @@ AvatarMenuButton* BrowserFrame::GetAvatarMenuButton() {
return browser_frame_view_->avatar_button();
}
+NewAvatarButton* BrowserFrame::GetNewAvatarMenuButton() {
+ return browser_frame_view_->new_avatar_button();
+}
+
#if !defined(OS_WIN) || defined(USE_AURA)
bool BrowserFrame::ShouldLeaveOffsetNearTopBorder() {
return !IsMaximized();
diff --git a/chrome/browser/ui/views/frame/browser_frame.h b/chrome/browser/ui/views/frame/browser_frame.h
index 023e143a2d..5c130affab 100644
--- a/chrome/browser/ui/views/frame/browser_frame.h
+++ b/chrome/browser/ui/views/frame/browser_frame.h
@@ -16,6 +16,7 @@ class AvatarMenuButton;
class BrowserRootView;
class BrowserView;
class NativeBrowserFrame;
+class NewAvatarButton;
class NonClientFrameView;
class SystemMenuModelBuilder;
@@ -98,7 +99,10 @@ class BrowserFrame
AvatarMenuButton* GetAvatarMenuButton();
+ NewAvatarButton* GetNewAvatarMenuButton();
+
// Returns the menu model. BrowserFrame owns the returned model.
+ // Note that in multi user mode this will upon each call create a new model.
ui::MenuModel* GetSystemMenuModel();
private:
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
index 367aae1466..dd5e2f6704 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
@@ -9,11 +9,14 @@
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_info_cache.h"
#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/profiles/profiles_state.h"
#include "chrome/browser/ui/view_ids.h"
#include "chrome/browser/ui/views/avatar_label.h"
#include "chrome/browser/ui/views/avatar_menu_button.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/frame/taskbar_decorator.h"
+#include "chrome/browser/ui/views/new_avatar_button.h"
+#include "chrome/browser/ui/views/profile_chooser_view.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "third_party/skia/include/core/SkColor.h"
@@ -28,7 +31,8 @@ BrowserNonClientFrameView::BrowserNonClientFrameView(BrowserFrame* frame,
: frame_(frame),
browser_view_(browser_view),
avatar_button_(NULL),
- avatar_label_(NULL) {
+ avatar_label_(NULL),
+ new_avatar_button_(NULL) {
}
BrowserNonClientFrameView::~BrowserNonClientFrameView() {
@@ -41,7 +45,9 @@ void BrowserNonClientFrameView::VisibilityChanged(views::View* starting_from,
// The first time UpdateAvatarInfo() is called the window is not visible so
// DrawTaskBarDecoration() has no effect. Therefore we need to call it again
// once the window is visible.
- UpdateAvatarInfo();
+ if (!browser_view_->IsRegularOrGuestSession() ||
+ !profiles::IsNewProfileManagementEnabled())
+ UpdateAvatarInfo();
}
void BrowserNonClientFrameView::OnThemeChanged() {
@@ -59,8 +65,7 @@ void BrowserNonClientFrameView::UpdateAvatarInfo() {
AddChildView(avatar_label_);
}
avatar_button_ = new AvatarMenuButton(
- browser_view_->browser(),
- browser_view_->IsOffTheRecord() && !browser_view_->IsGuestSession());
+ browser_view_->browser(), !browser_view_->IsRegularOrGuestSession());
avatar_button_->set_id(VIEW_ID_AVATAR_BUTTON);
AddChildView(avatar_button_);
frame_->GetRootView()->Layout();
@@ -111,3 +116,38 @@ void BrowserNonClientFrameView::UpdateAvatarInfo() {
frame_->GetNativeWindow(),
AvatarMenu::ShouldShowAvatarMenu() ? &avatar : NULL);
}
+
+void BrowserNonClientFrameView::UpdateNewStyleAvatarInfo(
+ views::ButtonListener* listener,
+ const NewAvatarButton::AvatarButtonStyle style) {
+ DCHECK(profiles::IsNewProfileManagementEnabled());
+ // This should never be called in incognito mode.
+ DCHECK(browser_view_->IsRegularOrGuestSession());
+
+ if (browser_view_->ShouldShowAvatar()) {
+ if (!new_avatar_button_) {
+ string16 profile_name =
+ profiles::GetActiveProfileDisplayName(browser_view_->browser());
+ new_avatar_button_ = new NewAvatarButton(
+ listener, profile_name, style, browser_view_->browser());
+ new_avatar_button_->set_id(VIEW_ID_NEW_AVATAR_BUTTON);
+ AddChildView(new_avatar_button_);
+ frame_->GetRootView()->Layout();
+ }
+ } else if (new_avatar_button_) {
+ delete new_avatar_button_;
+ new_avatar_button_ = NULL;
+ frame_->GetRootView()->Layout();
+ }
+}
+
+void BrowserNonClientFrameView::ShowProfileChooserViewBubble() {
+ gfx::Point origin;
+ views::View::ConvertPointToScreen(new_avatar_button(), &origin);
+ gfx::Rect bounds(origin, size());
+
+ ProfileChooserView::ShowBubble(
+ new_avatar_button(), views::BubbleBorder::TOP_RIGHT,
+ views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE, bounds,
+ browser_view_->browser());
+}
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view.h b/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
index 91a9b0dc95..681a06e7a4 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
@@ -5,12 +5,14 @@
#ifndef CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_NON_CLIENT_FRAME_VIEW_H_
#define CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_NON_CLIENT_FRAME_VIEW_H_
+#include "chrome/browser/ui/views/new_avatar_button.h"
#include "ui/views/window/non_client_view.h"
class AvatarLabel;
class AvatarMenuButton;
class BrowserFrame;
class BrowserView;
+class NewAvatarButton;
// A specialization of the NonClientFrameView object that provides additional
// Browser-specific methods.
@@ -34,6 +36,8 @@ class BrowserNonClientFrameView : public views::NonClientFrameView {
AvatarMenuButton* avatar_button() const { return avatar_button_; }
+ NewAvatarButton* new_avatar_button() const { return new_avatar_button_; }
+
AvatarLabel* avatar_label() const { return avatar_label_; }
// Returns the bounds within which the TabStrip should be laid out.
@@ -62,6 +66,16 @@ class BrowserNonClientFrameView : public views::NonClientFrameView {
// Updates the title and icon of the avatar button.
void UpdateAvatarInfo();
+ // Updates the title of the avatar button displayed in the caption area.
+ // The button uses |style| to match the browser window style and notifies
+ // |listener| when it is clicked.
+ void UpdateNewStyleAvatarInfo(views::ButtonListener* listener,
+ const NewAvatarButton::AvatarButtonStyle style);
+
+ // Anchor and show the ProfileChooser bubble under the avatar button in
+ // the caption area.
+ void ShowProfileChooserViewBubble();
+
private:
// The frame that hosts this view.
BrowserFrame* frame_;
@@ -75,6 +89,10 @@ class BrowserNonClientFrameView : public views::NonClientFrameView {
// Avatar label that is used for a managed user.
AvatarLabel* avatar_label_;
+
+ // Menu button that displays the name of the active or guest profile.
+ // May be NULL and will not be displayed for off the record profiles.
+ NewAvatarButton* new_avatar_button_;
};
namespace chrome {
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
index 22ef7d3c05..df32b2d005 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
@@ -6,7 +6,8 @@
#include "ash/ash_switches.h"
#include "ash/wm/caption_buttons/frame_caption_button_container_view.h"
-#include "ash/wm/frame_painter.h"
+#include "ash/wm/frame_border_hit_test_controller.h"
+#include "ash/wm/header_painter.h"
#include "chrome/browser/themes/theme_properties.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/immersive_fullscreen_configuration.h"
@@ -83,7 +84,9 @@ BrowserNonClientFrameViewAsh::BrowserNonClientFrameViewAsh(
: BrowserNonClientFrameView(frame, browser_view),
caption_button_container_(NULL),
window_icon_(NULL),
- frame_painter_(new ash::FramePainter) {
+ header_painter_(new ash::HeaderPainter),
+ frame_border_hit_test_controller_(
+ new ash::FrameBorderHitTestController(frame)) {
}
BrowserNonClientFrameViewAsh::~BrowserNonClientFrameViewAsh() {
@@ -106,7 +109,7 @@ void BrowserNonClientFrameViewAsh::Init() {
UpdateAvatarInfo();
// Frame painter handles layout.
- frame_painter_->Init(frame(), window_icon_, caption_button_container_);
+ header_painter_->Init(frame(), this, window_icon_, caption_button_container_);
}
///////////////////////////////////////////////////////////////////////////////
@@ -136,7 +139,7 @@ BrowserNonClientFrameViewAsh::GetTabStripInsets(bool force_restored) const {
int extra_right = ash::switches::UseAlternateFrameCaptionButtonStyle() ?
kTabstripRightSpacingAlternateCaptionButtonStyle :
kTabstripRightSpacing;
- int right = frame_painter_->GetRightInset() + extra_right;
+ int right = header_painter_->GetRightInset() + extra_right;
int top = NonClientTopBorderHeight();
if (force_restored)
@@ -159,7 +162,7 @@ BrowserNonClientFrameViewAsh::GetTabStripInsets(bool force_restored) const {
}
int BrowserNonClientFrameViewAsh::GetThemeBackgroundXInset() const {
- return frame_painter_->GetThemeBackgroundXInset();
+ return header_painter_->GetThemeBackgroundXInset();
}
void BrowserNonClientFrameViewAsh::UpdateThrobber(bool running) {
@@ -172,18 +175,19 @@ void BrowserNonClientFrameViewAsh::UpdateThrobber(bool running) {
gfx::Rect BrowserNonClientFrameViewAsh::GetBoundsForClientView() const {
int top_height = NonClientTopBorderHeight();
- return frame_painter_->GetBoundsForClientView(top_height, bounds());
+ return ash::HeaderPainter::GetBoundsForClientView(top_height, bounds());
}
gfx::Rect BrowserNonClientFrameViewAsh::GetWindowBoundsForClientBounds(
const gfx::Rect& client_bounds) const {
int top_height = NonClientTopBorderHeight();
- return frame_painter_->GetWindowBoundsForClientBounds(top_height,
- client_bounds);
+ return ash::HeaderPainter::GetWindowBoundsForClientBounds(top_height,
+ client_bounds);
}
int BrowserNonClientFrameViewAsh::NonClientHitTest(const gfx::Point& point) {
- int hit_test = frame_painter_->NonClientHitTest(this, point);
+ int hit_test = ash::FrameBorderHitTestController::NonClientHitTest(this,
+ header_painter_.get(), point);
// See if the point is actually within the avatar menu button or within
// the avatar label.
@@ -229,7 +233,7 @@ void BrowserNonClientFrameViewAsh::UpdateWindowIcon() {
void BrowserNonClientFrameViewAsh::UpdateWindowTitle() {
if (!frame()->IsFullscreen())
- frame_painter_->SchedulePaintForTitle(BrowserFrame::GetTitleFont());
+ header_painter_->SchedulePaintForTitle(BrowserFrame::GetTitleFont());
}
///////////////////////////////////////////////////////////////////////////////
@@ -250,25 +254,24 @@ void BrowserNonClientFrameViewAsh::OnPaint(gfx::Canvas* canvas) {
int theme_frame_overlay_image_id = GetThemeFrameOverlayImageId();
ui::ThemeProvider* theme_provider = GetThemeProvider();
- ash::FramePainter::Themed header_themed = ash::FramePainter::THEMED_NO;
+ ash::HeaderPainter::Themed header_themed = ash::HeaderPainter::THEMED_NO;
if (theme_provider->HasCustomImage(theme_frame_image_id) ||
(theme_frame_overlay_image_id != 0 &&
theme_provider->HasCustomImage(theme_frame_overlay_image_id))) {
- header_themed = ash::FramePainter::THEMED_YES;
+ header_themed = ash::HeaderPainter::THEMED_YES;
}
- if (frame_painter_->ShouldUseMinimalHeaderStyle(header_themed))
+ if (header_painter_->ShouldUseMinimalHeaderStyle(header_themed))
theme_frame_image_id = IDR_AURA_WINDOW_HEADER_BASE_MINIMAL;
- frame_painter_->PaintHeader(
- this,
+ header_painter_->PaintHeader(
canvas,
ShouldPaintAsActive() ?
- ash::FramePainter::ACTIVE : ash::FramePainter::INACTIVE,
+ ash::HeaderPainter::ACTIVE : ash::HeaderPainter::INACTIVE,
theme_frame_image_id,
theme_frame_overlay_image_id);
if (browser_view()->ShouldShowWindowTitle())
- frame_painter_->PaintTitleBar(this, canvas, BrowserFrame::GetTitleFont());
+ header_painter_->PaintTitleBar(canvas, BrowserFrame::GetTitleFont());
if (browser_view()->IsToolbarVisible())
PaintToolbarBackground(canvas);
else
@@ -276,7 +279,15 @@ void BrowserNonClientFrameViewAsh::OnPaint(gfx::Canvas* canvas) {
}
void BrowserNonClientFrameViewAsh::Layout() {
- frame_painter_->LayoutHeader(this, UseShortHeader());
+ header_painter_->LayoutHeader(UseShortHeader());
+ int header_height = 0;
+ if (browser_view()->IsTabStripVisible()) {
+ header_height = GetTabStripInsets(false).top +
+ browser_view()->GetTabStripHeight();
+ } else {
+ header_height = NonClientTopBorderHeight();
+ }
+ header_painter_->set_header_height(header_height);
if (avatar_button())
LayoutAvatar();
BrowserNonClientFrameView::Layout();
@@ -339,12 +350,16 @@ void BrowserNonClientFrameViewAsh::GetAccessibleState(
}
gfx::Size BrowserNonClientFrameViewAsh::GetMinimumSize() {
- return frame_painter_->GetMinimumSize(this);
+ gfx::Size min_client_view_size(frame()->client_view()->GetMinimumSize());
+ return gfx::Size(
+ std::max(header_painter_->GetMinimumHeaderWidth(),
+ min_client_view_size.width()),
+ NonClientTopBorderHeight() + min_client_view_size.height());
}
void BrowserNonClientFrameViewAsh::OnThemeChanged() {
BrowserNonClientFrameView::OnThemeChanged();
- frame_painter_->OnThemeChanged();
+ header_painter_->OnThemeChanged();
}
///////////////////////////////////////////////////////////////////////////////
@@ -531,8 +546,7 @@ void BrowserNonClientFrameViewAsh::PaintContentEdge(gfx::Canvas* canvas) {
}
int BrowserNonClientFrameViewAsh::GetThemeFrameImageId() const {
- bool is_incognito = browser_view()->IsOffTheRecord() &&
- !browser_view()->IsGuestSession();
+ bool is_incognito = !browser_view()->IsRegularOrGuestSession();
if (browser_view()->IsBrowserTypeNormal()) {
// Use the standard resource ids to allow users to theme the frames.
if (ShouldPaintAsActive()) {
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h
index 99530ecdd5..121bfd044a 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h
@@ -13,8 +13,9 @@
class TabIconView;
namespace ash {
+class FrameBorderHitTestController;
class FrameCaptionButtonContainerView;
-class FramePainter;
+class HeaderPainter;
}
namespace views {
class ImageButton;
@@ -112,8 +113,12 @@ class BrowserNonClientFrameViewAsh
// For popups, the window icon.
TabIconView* window_icon_;
- // Painter for the frame header.
- scoped_ptr<ash::FramePainter> frame_painter_;
+ // Helper class for painting the header.
+ scoped_ptr<ash::HeaderPainter> header_painter_;
+
+ // Updates the hittest bounds overrides based on the window show type.
+ scoped_ptr<ash::FrameBorderHitTestController>
+ frame_border_hit_test_controller_;
DISALLOW_COPY_AND_ASSIGN(BrowserNonClientFrameViewAsh);
};
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index b12feeab8d..c4fec8a22b 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -165,19 +165,12 @@ using views::GridLayout;
using web_modal::WebContentsModalDialogHost;
namespace {
-// The height of the status bubble.
-const int kStatusBubbleHeight = 20;
// The name of a key to store on the window handle so that other code can
// locate this object using just the handle.
const char* const kBrowserViewKey = "__BROWSER_VIEW__";
// The number of milliseconds between loading animation frames.
const int kLoadingAnimationFrameTimeMs = 30;
-// The amount of space we expect the window border to take up.
-const int kWindowBorderWidth = 5;
-
-// How round the 'new tab' style bookmarks bar is.
-const int kNewtabBarRoundness = 5;
// TODO(kuan): These functions are temporarily for the bookmark bar while its
// detached state is at the top of the page; it'll be moved to float on the
@@ -548,6 +541,15 @@ bool BrowserView::IsOffTheRecord() const {
return browser_->profile()->IsOffTheRecord();
}
+bool BrowserView::IsGuestSession() const {
+ return browser_->profile()->IsGuestSession();
+}
+
+bool BrowserView::IsRegularOrGuestSession() const {
+ Profile* profile = browser_->profile();
+ return (profile->IsGuestSession() || !profile->IsOffTheRecord());
+}
+
int BrowserView::GetOTRIconResourceID() const {
int otr_resource_id = IDR_OTR_ICON;
if (ui::GetDisplayLayout() == ui::LAYOUT_TOUCH) {
@@ -562,10 +564,6 @@ int BrowserView::GetOTRIconResourceID() const {
return otr_resource_id;
}
-bool BrowserView::IsGuestSession() const {
- return browser_->profile()->IsGuestSession();
-}
-
int BrowserView::GetGuestIconResourceID() const {
return IDR_GUEST_ICON;
}
@@ -1218,13 +1216,6 @@ void BrowserView::ConfirmBrowserCloseWithPendingDownloads(
GetNativeWindow(), download_count, dialog_type, app_modal, callback);
}
-void BrowserView::ShowCreateChromeAppShortcutsDialog(
- Profile* profile,
- const extensions::Extension* app) {
- chrome::ShowCreateChromeAppShortcutsDialog(
- GetNativeWindow(), profile, app, base::Closure());
-}
-
void BrowserView::UserChangedTheme() {
frame_->FrameTypeChanged();
}
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h
index 5e589b8014..82bc6b3a95 100644
--- a/chrome/browser/ui/views/frame/browser_view.h
+++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -192,14 +192,18 @@ class BrowserView : public BrowserWindow,
// incognito.
bool IsOffTheRecord() const;
- // Returns the resource ID to use for the OTR icon, which depends on
- // which layout is being shown and whether we are full-screen.
- int GetOTRIconResourceID() const;
-
// Returns true if the profile associated with this Browser window is
// a guest session.
bool IsGuestSession() const;
+ // Returns true if the profile associated with this Browser window is
+ // not off the record or a guest session.
+ bool IsRegularOrGuestSession() const;
+
+ // Returns the resource ID to use for the OTR icon, which depends on
+ // which layout is being shown and whether we are full-screen.
+ int GetOTRIconResourceID() const;
+
// Returns the resource ID to use for the Guest icon, which may depend on
// which layout is being shown and whether we are full-screen.
int GetGuestIconResourceID() const;
@@ -350,8 +354,6 @@ class BrowserView : public BrowserWindow,
bool* is_keyboard_shortcut) OVERRIDE;
virtual void HandleKeyboardEvent(
const content::NativeWebKeyboardEvent& event) OVERRIDE;
- virtual void ShowCreateChromeAppShortcutsDialog(
- Profile*, const extensions::Extension* app) OVERRIDE;
virtual void Cut() OVERRIDE;
virtual void Copy() OVERRIDE;
virtual void Paste() OVERRIDE;
diff --git a/chrome/browser/ui/views/frame/browser_view_layout.cc b/chrome/browser/ui/views/frame/browser_view_layout.cc
index 0b251a7172..6ba0387288 100644
--- a/chrome/browser/ui/views/frame/browser_view_layout.cc
+++ b/chrome/browser/ui/views/frame/browser_view_layout.cc
@@ -39,9 +39,6 @@ namespace {
// The visible height of the shadow above the tabs. Clicks in this area are
// treated as clicks to the frame, rather than clicks to the tab.
const int kTabShadowSize = 2;
-// The number of pixels the bookmark bar should overlap the spacer by if the
-// spacer is visible.
-const int kSpacerBookmarkBarOverlap = 1;
// The number of pixels the metro switcher is offset from the right edge.
const int kWindowSwitcherOffsetX = 7;
// The number of pixels the constrained window should overlap the bottom
diff --git a/chrome/browser/ui/views/frame/glass_browser_frame_view.cc b/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
index b482292827..1d191ad57c 100644
--- a/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
+++ b/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
@@ -11,9 +11,11 @@
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profiles_state.h"
#include "chrome/browser/themes/theme_properties.h"
#include "chrome/browser/ui/views/avatar_menu_button.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/new_avatar_button.h"
#include "chrome/browser/ui/views/tabs/tab.h"
#include "chrome/browser/ui/views/tabs/tab_strip.h"
#include "chrome/browser/ui/views/toolbar_view.h"
@@ -55,6 +57,8 @@ const int kAvatarBottomSpacing = 2;
const int kAvatarLeftSpacing = 2;
// Space between the right edge of the avatar and the tabstrip.
const int kAvatarRightSpacing = -2;
+// How far the new avatar button is from the left of the minimize button.
+const int kNewAvatarButtonOffset = 5;
// The content left/right images have a shadow built into them.
const int kContentEdgeShadowThickness = 2;
// The top 3 px of the tabstrip is shadow; in maximized mode we push this off
@@ -85,7 +89,12 @@ GlassBrowserFrameView::GlassBrowserFrameView(BrowserFrame* frame,
if (browser_view->ShouldShowWindowIcon())
InitThrobberIcons();
- UpdateAvatarInfo();
+ if (browser_view->IsRegularOrGuestSession() &&
+ profiles::IsNewProfileManagementEnabled())
+ UpdateNewStyleAvatarInfo(this, NewAvatarButton::NATIVE_BUTTON);
+ else
+ UpdateAvatarInfo();
+
if (!browser_view->IsOffTheRecord()) {
registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED,
content::NotificationService::AllSources());
@@ -102,6 +111,12 @@ gfx::Rect GlassBrowserFrameView::GetBoundsForTabStrip(
views::View* tabstrip) const {
int minimize_button_offset =
std::min(frame()->GetMinimizeButtonOffset(), width());
+
+ // The new avatar button is optionally displayed to the left of the
+ // minimize button.
+ if (browser_view()->ShouldShowAvatar() && new_avatar_button())
+ minimize_button_offset -= new_avatar_button()->width();
+
int tabstrip_x = browser_view()->ShouldShowAvatar() ?
(avatar_bounds_.right() + kAvatarRightSpacing) :
NonClientBorderThickness() + kTabStripIndent;
@@ -210,6 +225,10 @@ int GlassBrowserFrameView::NonClientHitTest(const gfx::Point& point) {
if (avatar_button() && avatar_button()->GetMirroredBounds().Contains(point))
return HTCLIENT;
+ if (new_avatar_button() &&
+ new_avatar_button()->GetMirroredBounds().Contains(point))
+ return HTCLIENT;
+
int frame_component = frame()->client_view()->NonClientHitTest(point);
// See if we're in the sysmenu region. We still have to check the tabstrip
@@ -244,14 +263,32 @@ void GlassBrowserFrameView::OnPaint(gfx::Canvas* canvas) {
}
void GlassBrowserFrameView::Layout() {
- LayoutAvatar();
+ if (browser_view()->ShouldShowAvatar()) {
+ if (browser_view()->IsRegularOrGuestSession() &&
+ profiles::IsNewProfileManagementEnabled())
+ LayoutNewStyleAvatar();
+ else
+ LayoutAvatar();
+ }
+
LayoutClientView();
}
bool GlassBrowserFrameView::HitTestRect(const gfx::Rect& rect) const {
- return (avatar_button() &&
- avatar_button()->GetMirroredBounds().Intersects(rect)) ||
- !frame()->client_view()->bounds().Intersects(rect);
+ bool hit_avatar_button = avatar_button() &&
+ avatar_button()->GetMirroredBounds().Intersects(rect);
+ bool hit_new_avatar_button = new_avatar_button() &&
+ new_avatar_button()->GetMirroredBounds().Intersects(rect);
+ return hit_avatar_button || hit_new_avatar_button ||
+ !frame()->client_view()->bounds().Intersects(rect);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// GlassBrowserFrameView, views::ButtonListener overrides:
+void GlassBrowserFrameView::ButtonPressed(views::Button* sender,
+ const ui::Event& event) {
+ if (sender == new_avatar_button())
+ ShowProfileChooserViewBubble();
}
///////////////////////////////////////////////////////////////////////////////
@@ -403,6 +440,28 @@ void GlassBrowserFrameView::PaintRestoredClientEdge(gfx::Canvas* canvas) {
toolbar_color);
}
+void GlassBrowserFrameView::LayoutNewStyleAvatar() {
+ if (!new_avatar_button())
+ return;
+
+ gfx::Size label_size = new_avatar_button()->GetPreferredSize();
+ int button_size_with_offset = kNewAvatarButtonOffset + label_size.width();
+
+ int button_x = frame()->GetMinimizeButtonOffset() -
+ kNewAvatarButtonOffset - label_size.width();
+
+ if (base::i18n::IsRTL())
+ button_x = width() - frame()->GetMinimizeButtonOffset() +
+ kNewAvatarButtonOffset;
+
+ int button_y = frame()->IsMaximized() ? NonClientTopBorderHeight(false) : 1;
+ new_avatar_button()->SetBounds(
+ button_x,
+ button_y,
+ label_size.width(),
+ button_y + gfx::win::GetSystemMetricsInDIP(SM_CXMENUSIZE));
+}
+
void GlassBrowserFrameView::LayoutAvatar() {
// Even though the avatar is used for both incognito and profiles we always
// use the incognito icon to layout the avatar button. The profile icon
@@ -504,7 +563,11 @@ void GlassBrowserFrameView::Observe(
const content::NotificationDetails& details) {
switch (type) {
case chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED:
- UpdateAvatarInfo();
+ if (browser_view()->IsRegularOrGuestSession() &&
+ profiles::IsNewProfileManagementEnabled())
+ UpdateNewStyleAvatarInfo(this, NewAvatarButton::NATIVE_BUTTON);
+ else
+ UpdateAvatarInfo();
break;
default:
NOTREACHED() << "Got a notification we didn't register for!";
diff --git a/chrome/browser/ui/views/frame/glass_browser_frame_view.h b/chrome/browser/ui/views/frame/glass_browser_frame_view.h
index d872738c1c..c9b2701c3b 100644
--- a/chrome/browser/ui/views/frame/glass_browser_frame_view.h
+++ b/chrome/browser/ui/views/frame/glass_browser_frame_view.h
@@ -16,6 +16,7 @@
class BrowserView;
class GlassBrowserFrameView : public BrowserNonClientFrameView,
+ public views::ButtonListener,
public content::NotificationObserver {
public:
// Constructs a non-client view for an BrowserFrame.
@@ -46,6 +47,10 @@ class GlassBrowserFrameView : public BrowserNonClientFrameView,
virtual void Layout() OVERRIDE;
virtual bool HitTestRect(const gfx::Rect& rect) const OVERRIDE;
+ // Overidden from views::ButtonListener:
+ virtual void ButtonPressed(views::Button* sender,
+ const ui::Event& event) OVERRIDE;
+
private:
// Returns the thickness of the border that makes up the window frame edges.
// This does not include any client edge.
@@ -66,6 +71,7 @@ class GlassBrowserFrameView : public BrowserNonClientFrameView,
// Layout various sub-components of this view.
void LayoutAvatar();
+ void LayoutNewStyleAvatar();
void LayoutClientView();
// Returns the insets of the client area.
diff --git a/chrome/browser/ui/views/frame/global_menu_bar_x11.cc b/chrome/browser/ui/views/frame/global_menu_bar_x11.cc
index 77db18956f..748fb43333 100644
--- a/chrome/browser/ui/views/frame/global_menu_bar_x11.cc
+++ b/chrome/browser/ui/views/frame/global_menu_bar_x11.cc
@@ -127,8 +127,7 @@ const int MENU_SEPARATOR =-1;
const int MENU_END = -2;
const int MENU_DISABLED_ID = -3;
-// These tag values are used to refer to menu itesm.
-const int TAG_NORMAL = 0;
+// These tag values are used to refer to menu items.
const int TAG_MOST_VISITED = 1;
const int TAG_RECENTLY_CLOSED = 2;
const int TAG_MOST_VISITED_HEADER = 3;
@@ -228,6 +227,7 @@ GlobalMenuBarCommand tools_menu[] = {
{ IDS_VIEW_SOURCE, IDC_VIEW_SOURCE },
{ IDS_DEV_TOOLS, IDC_DEV_TOOLS },
{ IDS_DEV_TOOLS_CONSOLE, IDC_DEV_TOOLS_CONSOLE },
+ { IDS_DEV_TOOLS_DEVICES, IDC_DEV_TOOLS_DEVICES },
{ MENU_END, MENU_END }
};
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_ash_unittest.cc b/chrome/browser/ui/views/frame/immersive_mode_controller_ash_unittest.cc
index c09c9e1347..f24f95d724 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller_ash_unittest.cc
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller_ash_unittest.cc
@@ -4,7 +4,7 @@
#include "chrome/browser/ui/views/frame/immersive_mode_controller_ash.h"
-#include "ash/display/display_controller.h"
+#include "ash/display/display_manager.h"
#include "ash/shell.h"
#include "ash/test/ash_test_base.h"
#include "chrome/app/chrome_command_ids.h"
@@ -357,7 +357,7 @@ TEST_F(ImmersiveModeControllerAshTest, MouseEventsVerticalDisplayLayout) {
// Set up initial state.
UpdateDisplay("800x600,800x600");
ash::DisplayLayout display_layout(ash::DisplayLayout::TOP, 0);
- ash::Shell::GetInstance()->display_controller()->SetLayoutForCurrentDisplays(
+ ash::Shell::GetInstance()->display_manager()->SetLayoutForCurrentDisplays(
display_layout);
controller()->SetEnabled(true);
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
index fdfe4c7bb2..4de7694c3d 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
@@ -12,6 +12,7 @@
#include "base/prefs/pref_service.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/profiles/profiles_state.h"
#include "chrome/browser/themes/theme_properties.h"
#include "chrome/browser/ui/views/avatar_label.h"
#include "chrome/browser/ui/views/avatar_menu_button.h"
@@ -19,6 +20,7 @@
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h"
#include "chrome/browser/ui/views/frame/opaque_browser_frame_view_platform_specific.h"
+#include "chrome/browser/ui/views/new_avatar_button.h"
#include "chrome/browser/ui/views/tab_icon_view.h"
#include "chrome/browser/ui/views/tabs/tab_strip.h"
#include "chrome/browser/ui/views/toolbar_view.h"
@@ -150,7 +152,12 @@ OpaqueBrowserFrameView::OpaqueBrowserFrameView(BrowserFrame* frame,
window_title_->set_id(VIEW_ID_WINDOW_TITLE);
AddChildView(window_title_);
- UpdateAvatarInfo();
+ if (browser_view->IsRegularOrGuestSession() &&
+ profiles::IsNewProfileManagementEnabled())
+ UpdateNewStyleAvatarInfo(this, NewAvatarButton::THEMED_BUTTON);
+ else
+ UpdateAvatarInfo();
+
if (!browser_view->IsOffTheRecord()) {
registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED,
content::NotificationService::AllSources());
@@ -215,7 +222,9 @@ int OpaqueBrowserFrameView::NonClientHitTest(const gfx::Point& point) {
// label.
if ((avatar_button() &&
avatar_button()->GetMirroredBounds().Contains(point)) ||
- (avatar_label() && avatar_label()->GetMirroredBounds().Contains(point)))
+ (avatar_label() && avatar_label()->GetMirroredBounds().Contains(point)) ||
+ (new_avatar_button() &&
+ new_avatar_button()->GetMirroredBounds().Contains(point)))
return HTCLIENT;
int frame_component = frame()->client_view()->NonClientHitTest(point);
@@ -396,6 +405,8 @@ void OpaqueBrowserFrameView::ButtonPressed(views::Button* sender,
frame()->Restore();
else if (sender == close_button_)
frame()->Close();
+ else if (sender == new_avatar_button())
+ ShowProfileChooserViewBubble();
}
///////////////////////////////////////////////////////////////////////////////
@@ -427,7 +438,11 @@ void OpaqueBrowserFrameView::Observe(
const content::NotificationDetails& details) {
switch (type) {
case chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED:
- UpdateAvatarInfo();
+ if (browser_view() ->IsRegularOrGuestSession() &&
+ profiles::IsNewProfileManagementEnabled())
+ UpdateNewStyleAvatarInfo(this, NewAvatarButton::THEMED_BUTTON);
+ else
+ UpdateAvatarInfo();
break;
default:
NOTREACHED() << "Got a notification we didn't register for!";
@@ -477,6 +492,10 @@ bool OpaqueBrowserFrameView::ShouldShowAvatar() const {
return browser_view()->ShouldShowAvatar();
}
+bool OpaqueBrowserFrameView::IsRegularOrGuestSession() const {
+ return browser_view()->IsRegularOrGuestSession();
+}
+
gfx::ImageSkia OpaqueBrowserFrameView::GetOTRAvatarIcon() const {
return browser_view()->GetOTRAvatarIcon();
}
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view.h b/chrome/browser/ui/views/frame/opaque_browser_frame_view.h
index e732d019bb..1e9b018daf 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view.h
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view.h
@@ -20,6 +20,7 @@ class BrowserView;
class OpaqueBrowserFrameViewLayout;
class OpaqueBrowserFrameViewPlatformSpecific;
class TabIconView;
+class NewAvatarButton;
namespace views {
class ImageButton;
@@ -87,6 +88,7 @@ class OpaqueBrowserFrameView : public BrowserNonClientFrameView,
virtual bool ShouldLeaveOffsetNearTopBorder() const OVERRIDE;
virtual gfx::Size GetBrowserViewMinimumSize() const OVERRIDE;
virtual bool ShouldShowAvatar() const OVERRIDE;
+ virtual bool IsRegularOrGuestSession() const OVERRIDE;
virtual gfx::ImageSkia GetOTRAvatarIcon() const OVERRIDE;
virtual bool IsMaximized() const OVERRIDE;
virtual bool IsMinimized() const OVERRIDE;
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc
index c0848d869f..071e3921fd 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h"
+#include "chrome/browser/profiles/profiles_state.h"
+#include "chrome/browser/ui/views/new_avatar_button.h"
#include "ui/gfx/font.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/controls/label.h"
@@ -49,6 +51,9 @@ const int kAvatarLeftSpacing = 2;
// Space between the right edge of the avatar and the tabstrip.
const int kAvatarRightSpacing = -4;
+// How far the new avatar button is from the closest caption button.
+const int kNewAvatarButtonOffset = 5;
+
// In restored mode, the New Tab button isn't at the same height as the caption
// buttons, but the space will look cluttered if it actually slides under them,
// so we stop it when the gap between the two is down to 5 px.
@@ -101,7 +106,8 @@ OpaqueBrowserFrameViewLayout::OpaqueBrowserFrameViewLayout(
window_icon_(NULL),
window_title_(NULL),
avatar_label_(NULL),
- avatar_button_(NULL) {
+ avatar_button_(NULL),
+ new_avatar_button_(NULL) {
trailing_buttons_.push_back(views::FRAME_BUTTON_MINIMIZE);
trailing_buttons_.push_back(views::FRAME_BUTTON_MAXIMIZE);
trailing_buttons_.push_back(views::FRAME_BUTTON_CLOSE);
@@ -355,6 +361,24 @@ void OpaqueBrowserFrameViewLayout::LayoutTitleBar(views::View* host) {
}
}
+void OpaqueBrowserFrameViewLayout::LayoutNewStyleAvatar(views::View* host) {
+ gfx::Size label_size = new_avatar_button_->GetPreferredSize();
+ int button_size_with_offset = kNewAvatarButtonOffset + label_size.width();
+
+ int button_x = host->width() - trailing_button_start_ -
+ button_size_with_offset;
+ int button_y = CaptionButtonY(false);
+
+ trailing_button_start_ += button_size_with_offset;
+ minimum_size_for_buttons_ += button_size_with_offset;
+
+ new_avatar_button_->SetBounds(
+ button_x,
+ button_y,
+ label_size.width(),
+ button_y + kCaptionButtonHeightWithPadding);
+}
+
void OpaqueBrowserFrameViewLayout::LayoutAvatar() {
// Even though the avatar is used for both incognito and profiles we always
// use the incognito icon to layout the avatar button. The profile icon
@@ -567,6 +591,9 @@ void OpaqueBrowserFrameViewLayout::SetView(int id, views::View* view) {
case VIEW_ID_AVATAR_BUTTON:
avatar_button_ = view;
break;
+ case VIEW_ID_NEW_AVATAR_BUTTON:
+ new_avatar_button_ = static_cast<NewAvatarButton*>(view);
+ break;
default:
NOTIMPLEMENTED() << "Unknown view id " << id;
break;
@@ -593,7 +620,11 @@ void OpaqueBrowserFrameViewLayout::Layout(views::View* host) {
// on the trailing side.
leading_button_start_++;
- LayoutAvatar();
+ if (delegate_->IsRegularOrGuestSession() &&
+ profiles::IsNewProfileManagementEnabled())
+ LayoutNewStyleAvatar(host);
+ else
+ LayoutAvatar();
client_view_bounds_ = CalculateClientAreaBounds(
host->width(), host->height());
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h
index 12f6dea270..b37bd51436 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h
@@ -9,6 +9,7 @@
#include "ui/views/layout/layout_manager.h"
#include "ui/views/window/frame_buttons.h"
+class NewAvatarButton;
class OpaqueBrowserFrameViewLayoutDelegate;
namespace views {
@@ -100,6 +101,7 @@ class OpaqueBrowserFrameViewLayout : public views::LayoutManager {
void LayoutWindowControls(views::View* host);
void LayoutTitleBar(views::View* host);
void LayoutAvatar();
+ void LayoutNewStyleAvatar(views::View* host);
void ConfigureButton(views::View* host,
views::FrameButton button_id,
@@ -167,6 +169,7 @@ class OpaqueBrowserFrameViewLayout : public views::LayoutManager {
views::View* avatar_label_;
views::View* avatar_button_;
+ NewAvatarButton* new_avatar_button_;
std::vector<views::FrameButton> leading_buttons_;
std::vector<views::FrameButton> trailing_buttons_;
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout_delegate.h b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout_delegate.h
index 7858ed1f68..58709c8cbd 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout_delegate.h
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout_delegate.h
@@ -35,6 +35,9 @@ class OpaqueBrowserFrameViewLayoutDelegate {
// Controls the visualization of the avatar
virtual bool ShouldShowAvatar() const = 0;
+ // Returns true if in guest mode or a non off the record session.
+ virtual bool IsRegularOrGuestSession() const = 0;
+
// We don't have a ThemeProvider in the layout manager, so plumb in the icon
// source here.
virtual gfx::ImageSkia GetOTRAvatarIcon() const = 0;
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout_unittest.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout_unittest.cc
index 5962fb0328..c75f09a1b0 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout_unittest.cc
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout_unittest.cc
@@ -5,9 +5,11 @@
#include "chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h"
#include "base/basictypes.h"
+#include "base/command_line.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/ui/views/tab_icon_view.h"
#include "chrome/browser/ui/views/tabs/tab.h"
+#include "chrome/common/chrome_switches.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_skia_rep.h"
#include "ui/gfx/text_constants.h"
@@ -80,6 +82,10 @@ class TestLayoutDelegate : public OpaqueBrowserFrameViewLayoutDelegate {
return show_avatar_;
}
+ virtual bool IsRegularOrGuestSession() const OVERRIDE {
+ return true;
+ }
+
virtual gfx::ImageSkia GetOTRAvatarIcon() const OVERRIDE {
// The calculations depend on the size of the OTR resource, and chromeos
// uses a different sized image, so hard code the size of the current
@@ -213,6 +219,12 @@ class OpaqueBrowserFrameViewLayoutTest : public views::ViewsTestBase {
AddAvatarButton();
}
+ void AddNewAvatarButton() {
+ new_avatar_button_ = new views::MenuButton(NULL, string16(), NULL, false);
+ new_avatar_button_->set_id(VIEW_ID_NEW_AVATAR_BUTTON);
+ root_view_->AddChildView(new_avatar_button_);
+ }
+
void ExpectBasicWindowBounds() {
EXPECT_EQ("428,1 25x18", maximize_button_->bounds().ToString());
EXPECT_EQ("402,1 26x18", minimize_button_->bounds().ToString());
@@ -238,6 +250,7 @@ class OpaqueBrowserFrameViewLayoutTest : public views::ViewsTestBase {
views::MenuButton* menu_button_;
views::MenuButton* avatar_label_;
+ views::MenuButton* new_avatar_button_;
DISALLOW_COPY_AND_ASSIGN(OpaqueBrowserFrameViewLayoutTest);
};
@@ -314,6 +327,28 @@ TEST_F(OpaqueBrowserFrameViewLayoutTest, WindowWithAvatar) {
EXPECT_EQ("261x73", layout_manager_->GetMinimumSize(kWidth).ToString());
}
+
+TEST_F(OpaqueBrowserFrameViewLayoutTest, WindowWithNewAvatar) {
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kNewProfileManagement);
+
+ // Tests a normal tabstrip window with the new style avatar icon.
+ AddNewAvatarButton();
+ root_view_->Layout();
+
+ ExpectBasicWindowBounds();
+
+ // Check the location of the caption button
+ EXPECT_EQ("385,1 12x20", new_avatar_button_->bounds().ToString());
+ // The basic window bounds are (-1, 13 398x29). There should not be an icon
+ // avatar in the left, and the new avatar button has an offset of 5 to its
+ // next control.
+ EXPECT_EQ("-1,13 381x29",
+ layout_manager_->GetBoundsForTabStrip(
+ delegate_->GetTabstripPreferredSize(), kWidth).ToString());
+ EXPECT_EQ("261x73", layout_manager_->GetMinimumSize(kWidth).ToString());
+}
+
TEST_F(OpaqueBrowserFrameViewLayoutTest, WindowWithAvatarLabelAndButton) {
AddAvatarLabel();
root_view_->Layout();
diff --git a/chrome/browser/ui/views/frame/system_menu_model_builder.cc b/chrome/browser/ui/views/frame/system_menu_model_builder.cc
index f07118174c..f6ade584e4 100644
--- a/chrome/browser/ui/views/frame/system_menu_model_builder.cc
+++ b/chrome/browser/ui/views/frame/system_menu_model_builder.cc
@@ -15,6 +15,14 @@
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/models/simple_menu_model.h"
+#if defined(OS_CHROMEOS)
+#include "ash/session_state_delegate.h"
+#include "ash/shell.h"
+#include "chrome/browser/ui/ash/multi_user_window_manager.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "ui/base/l10n/l10n_util.h"
+#endif
+
SystemMenuModelBuilder::SystemMenuModelBuilder(
ui::AcceleratorProvider* provider,
Browser* browser)
@@ -55,6 +63,7 @@ void SystemMenuModelBuilder::BuildSystemMenuForBrowserWindow(
model->AddSeparator(ui::NORMAL_SEPARATOR);
model->AddItemWithStringId(IDC_TASK_MANAGER, IDS_TASK_MANAGER);
}
+ AppendTeleportMenu(model);
// If it's a regular browser window with tabs, we don't add any more items,
// since it already has menus (Page, Chrome).
}
@@ -87,6 +96,8 @@ void SystemMenuModelBuilder::BuildSystemMenuForAppOrPopupWindow(
model->AddSeparator(ui::NORMAL_SEPARATOR);
model->AddItemWithStringId(IDC_TASK_MANAGER, IDS_TASK_MANAGER);
}
+
+ AppendTeleportMenu(model);
}
void SystemMenuModelBuilder::AddFrameToggleItems(ui::SimpleMenuModel* model) {
@@ -97,3 +108,38 @@ void SystemMenuModelBuilder::AddFrameToggleItems(ui::SimpleMenuModel* model) {
}
}
+void SystemMenuModelBuilder::AppendTeleportMenu(ui::SimpleMenuModel* model) {
+#if defined(OS_CHROMEOS)
+ DCHECK(browser()->window());
+ chrome::MultiUserWindowManager* manager =
+ chrome::MultiUserWindowManager::GetInstance();
+ // If there is no manager, we are not in the proper multi user mode.
+ if (!manager)
+ return;
+
+ // To show the menu we need at least two logged in users.
+ ash::SessionStateDelegate* delegate =
+ ash::Shell::GetInstance()->session_state_delegate();
+ int logged_in_users = delegate->NumberOfLoggedInUsers();
+ if (logged_in_users <= 1)
+ return;
+
+ // If this does not belong to a profile or there is no window, or the window
+ // is not owned by anyone, we don't show the menu addition.
+ const std::string user_id =
+ manager->GetUserIDFromProfile(browser()->profile());
+ aura::Window* window = browser()->window()->GetNativeWindow();
+ if (user_id.empty() || !window || manager->GetWindowOwner(window).empty())
+ return;
+
+ model->AddSeparator(ui::NORMAL_SEPARATOR);
+ DCHECK(logged_in_users <= 3);
+ for (int user_index = 1; user_index < logged_in_users; ++user_index) {
+ model->AddItem(
+ user_index == 1 ? IDC_VISIT_DESKTOP_OF_LRU_USER_2 :
+ IDC_VISIT_DESKTOP_OF_LRU_USER_3,
+ l10n_util::GetStringFUTF16(IDC_VISIT_DESKTOP_OF_LRU_USER,
+ delegate->GetUserDisplayName(user_index)));
+ }
+#endif
+}
diff --git a/chrome/browser/ui/views/frame/system_menu_model_builder.h b/chrome/browser/ui/views/frame/system_menu_model_builder.h
index 280d5de44e..d12dc336cc 100644
--- a/chrome/browser/ui/views/frame/system_menu_model_builder.h
+++ b/chrome/browser/ui/views/frame/system_menu_model_builder.h
@@ -42,6 +42,9 @@ class SystemMenuModelBuilder {
// Adds items for toggling the frame type (if necessary).
void AddFrameToggleItems(ui::SimpleMenuModel* model);
+ // Add the items to allow the window to visit the desktop of another user.
+ void AppendTeleportMenu(ui::SimpleMenuModel* model);
+
SystemMenuModelDelegate menu_delegate_;
scoped_ptr<ui::MenuModel> menu_model_;
scoped_ptr<ZoomMenuModel> zoom_menu_contents_;
diff --git a/chrome/browser/ui/views/importer/import_lock_dialog_view.cc b/chrome/browser/ui/views/importer/import_lock_dialog_view.cc
index b1e41ba6d0..dcc97208e4 100644
--- a/chrome/browser/ui/views/importer/import_lock_dialog_view.cc
+++ b/chrome/browser/ui/views/importer/import_lock_dialog_view.cc
@@ -19,10 +19,6 @@
using content::UserMetricsAction;
-// Default size of the dialog window.
-static const int kDefaultWindowWidth = 320;
-static const int kDefaultWindowHeight = 100;
-
namespace importer {
void ShowImportLockDialog(gfx::NativeWindow parent,
diff --git a/chrome/browser/ui/views/login_prompt_views.cc b/chrome/browser/ui/views/login_prompt_views.cc
index 7994e7a96a..42b99e431d 100644
--- a/chrome/browser/ui/views/login_prompt_views.cc
+++ b/chrome/browser/ui/views/login_prompt_views.cc
@@ -157,7 +157,7 @@ class LoginHandlerViews : public LoginHandler,
WebContentsModalDialogManager::FromWebContents(requesting_contents);
WebContentsModalDialogManagerDelegate* modal_delegate =
web_contents_modal_dialog_manager->delegate();
- DCHECK(modal_delegate);
+ CHECK(modal_delegate);
dialog_ = views::Widget::CreateWindowAsFramelessChild(
this,
requesting_contents->GetView()->GetNativeView(),
diff --git a/chrome/browser/ui/views/message_center/message_center_frame_view.cc b/chrome/browser/ui/views/message_center/message_center_frame_view.cc
index 0efd863462..095a3b85de 100644
--- a/chrome/browser/ui/views/message_center/message_center_frame_view.cc
+++ b/chrome/browser/ui/views/message_center/message_center_frame_view.cc
@@ -9,20 +9,15 @@
#include "ui/views/shadow_border.h"
#include "ui/views/widget/widget.h"
-namespace {
-
-const int kBorderWidth = 1;
-const int kShadowBlur = 8;
-
-} // namepspace
-
namespace message_center {
MessageCenterFrameView::MessageCenterFrameView() {
#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ const int kBorderWidth = 1;
set_border(views::Border::CreateSolidBorder(
kBorderWidth, message_center::kMessageCenterBorderColor));
#else
+ const int kShadowBlur = 8;
set_border(new views::ShadowBorder(kShadowBlur,
message_center::kMessageCenterShadowColor,
0, // Vertical offset
diff --git a/chrome/browser/ui/views/message_center/web_notification_tray.cc b/chrome/browser/ui/views/message_center/web_notification_tray.cc
index f58482a058..6c6675f6d4 100644
--- a/chrome/browser/ui/views/message_center/web_notification_tray.cc
+++ b/chrome/browser/ui/views/message_center/web_notification_tray.cc
@@ -32,10 +32,6 @@ namespace {
// Tray constants
const int kScreenEdgePadding = 2;
-const int kSystemTrayWidth = 16;
-const int kSystemTrayHeight = 16;
-const int kNumberOfSystemTraySprites = 10;
-
// Number of pixels the message center is offset from the mouse.
const int kMouseOffset = 5;
diff --git a/chrome/browser/ui/views/new_avatar_button.cc b/chrome/browser/ui/views/new_avatar_button.cc
new file mode 100644
index 0000000000..049afb3902
--- /dev/null
+++ b/chrome/browser/ui/views/new_avatar_button.cc
@@ -0,0 +1,128 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/new_avatar_button.h"
+
+#include "base/win/windows_version.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/profiles/profiles_state.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/color_utils.h"
+#include "ui/views/border.h"
+#include "ui/views/painter.h"
+
+namespace {
+
+// Text padding within the button border.
+const int kInset = 10;
+
+views::TextButtonDefaultBorder* CreateBorder(const int normal_image_set[],
+ const int hot_image_set[],
+ const int pushed_image_set[]) {
+ views::TextButtonDefaultBorder* border = new views::TextButtonDefaultBorder();
+
+ border->SetInsets(gfx::Insets(kInset, kInset, kInset, kInset));
+ border->set_normal_painter(
+ views::Painter::CreateImageGridPainter(normal_image_set));
+ border->set_hot_painter(
+ views::Painter::CreateImageGridPainter(hot_image_set));
+ border->set_pushed_painter(
+ views::Painter::CreateImageGridPainter(pushed_image_set));
+
+ return border;
+}
+
+} // namespace
+
+NewAvatarButton::NewAvatarButton(
+ views::ButtonListener* listener,
+ const string16& profile_name,
+ AvatarButtonStyle button_style,
+ Browser* browser)
+ : MenuButton(listener, profile_name, NULL, true),
+ browser_(browser) {
+ set_animate_on_state_change(false);
+
+ ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
+ SetFont(rb->GetFont(ui::ResourceBundle::BaseFont));
+
+ bool is_win8 = false;
+#if defined(OS_WIN)
+ is_win8 = base::win::GetVersion() >= base::win::VERSION_WIN8;
+#endif
+
+ if (button_style == THEMED_BUTTON) {
+ const int kNormalImageSet[] = IMAGE_GRID(IDR_AVATAR_THEMED_BUTTON_NORMAL);
+ const int kHotImageSet[] = IMAGE_GRID(IDR_AVATAR_THEMED_BUTTON_HOVER);
+ const int kPushedImageSet[] = IMAGE_GRID(IDR_AVATAR_THEMED_BUTTON_PRESSED);
+
+ set_border(CreateBorder(kNormalImageSet, kHotImageSet, kPushedImageSet));
+ set_menu_marker(
+ rb->GetImageNamed(IDR_AVATAR_THEMED_BUTTON_DROPARROW).ToImageSkia());
+ } else if (is_win8) {
+ const int kNormalImageSet[] = IMAGE_GRID(IDR_AVATAR_METRO_BUTTON_NORMAL);
+ const int kHotImageSet[] = IMAGE_GRID(IDR_AVATAR_METRO_BUTTON_HOVER);
+ const int kPushedImageSet[] = IMAGE_GRID(IDR_AVATAR_METRO_BUTTON_PRESSED);
+
+ set_border(CreateBorder(kNormalImageSet, kHotImageSet, kPushedImageSet));
+ set_menu_marker(
+ rb->GetImageNamed(IDR_AVATAR_METRO_BUTTON_DROPARROW).ToImageSkia());
+ } else {
+ const int kNormalImageSet[] = IMAGE_GRID(IDR_AVATAR_GLASS_BUTTON_NORMAL);
+ const int kHotImageSet[] = IMAGE_GRID(IDR_AVATAR_GLASS_BUTTON_HOVER);
+ const int kPushedImageSet[] = IMAGE_GRID(IDR_AVATAR_GLASS_BUTTON_PRESSED);
+
+ set_border(CreateBorder(kNormalImageSet, kHotImageSet, kPushedImageSet));
+ set_menu_marker(
+ rb->GetImageNamed(IDR_AVATAR_GLASS_BUTTON_DROPARROW).ToImageSkia());
+ }
+
+ avatar_menu_.reset(new AvatarMenu(
+ &g_browser_process->profile_manager()->GetProfileInfoCache(),
+ this,
+ browser_));
+ avatar_menu_->RebuildMenu();
+
+ SchedulePaint();
+}
+
+NewAvatarButton::~NewAvatarButton() {
+}
+
+void NewAvatarButton::OnPaint(gfx::Canvas* canvas) {
+ // From TextButton::PaintButton, draw everything but the text.
+ OnPaintBackground(canvas);
+ OnPaintBorder(canvas);
+ OnPaintFocusBorder(canvas);
+
+ gfx::Rect rect;
+ // In RTL languages the marker gets drawn leftmost, so account for its offset.
+ if (base::i18n::IsRTL())
+ rect = gfx::Rect(-kInset, 0, size().width(), size().height());
+ else
+ rect = gfx::Rect(kInset, 0, size().width(), size().height());
+ // TODO(noms): This should be DrawStringRectWithHalo but that function
+ // has a bug at the moment and incorrectly draws the background.
+ canvas->DrawStringRectWithFlags(
+ text(),
+ gfx::FontList(ui::ResourceBundle::GetSharedInstance().GetFont(
+ ui::ResourceBundle::BaseFont)),
+ SK_ColorBLACK,
+ rect,
+ gfx::Canvas::NO_SUBPIXEL_RENDERING);
+
+ // From MenuButton::PaintButton, paint the marker
+ PaintMenuMarker(canvas);
+}
+
+void NewAvatarButton::OnAvatarMenuChanged(AvatarMenu* avatar_menu) {
+ SetText(profiles::GetActiveProfileDisplayName(browser_));
+ // We need to redraw the entire button because the width might have changed.
+ SchedulePaint();
+}
diff --git a/chrome/browser/ui/views/new_avatar_button.h b/chrome/browser/ui/views/new_avatar_button.h
new file mode 100644
index 0000000000..076d822f94
--- /dev/null
+++ b/chrome/browser/ui/views/new_avatar_button.h
@@ -0,0 +1,44 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_NEW_AVATAR_BUTTON_H_
+#define CHROME_BROWSER_UI_VIEWS_NEW_AVATAR_BUTTON_H_
+
+#include "chrome/browser/profiles/avatar_menu.h"
+#include "chrome/browser/profiles/avatar_menu_observer.h"
+#include "ui/views/controls/button/menu_button.h"
+
+// Avatar button that displays the active profile's name in the caption area.
+class NewAvatarButton : public views::MenuButton,
+ public AvatarMenuObserver {
+ public:
+ // Different button styles that can be applied.
+ enum AvatarButtonStyle {
+ THEMED_BUTTON, // Used in a themed browser window.
+ NATIVE_BUTTON, // Used in a native aero or metro window.
+ };
+
+ NewAvatarButton(views::ButtonListener* listener,
+ const string16& profile_name,
+ AvatarButtonStyle button_style,
+ Browser* browser);
+ virtual ~NewAvatarButton();
+
+ // views::View:
+ virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
+
+ private:
+ friend class NewAvatarMenuButtonTest;
+ FRIEND_TEST_ALL_PREFIXES(NewAvatarMenuButtonTest, SignOut);
+
+ // AvatarMenuObserver:
+ virtual void OnAvatarMenuChanged(AvatarMenu* avatar_menu) OVERRIDE;
+
+ scoped_ptr<AvatarMenu> avatar_menu_;
+ Browser* browser_;
+
+ DISALLOW_COPY_AND_ASSIGN(NewAvatarButton);
+};
+
+#endif // CHROME_BROWSER_UI_VIEWS_NEW_AVATAR_BUTTON_H_
diff --git a/chrome/browser/ui/views/new_avatar_menu_button_browsertest.cc b/chrome/browser/ui/views/new_avatar_menu_button_browsertest.cc
new file mode 100644
index 0000000000..c4b21df85e
--- /dev/null
+++ b/chrome/browser/ui/views/new_avatar_menu_button_browsertest.cc
@@ -0,0 +1,123 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/command_line.h"
+#include "base/path_service.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/profiles/profiles_state.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/views/avatar_menu_button.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/new_avatar_button.h"
+#include "chrome/browser/ui/views/profile_chooser_view.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/test_switches.h"
+#include "chrome/test/base/testing_browser_process.h"
+#include "content/public/test/test_utils.h"
+#include "grit/generated_resources.h"
+
+class NewAvatarMenuButtonTest : public InProcessBrowserTest {
+ public:
+ NewAvatarMenuButtonTest();
+ virtual ~NewAvatarMenuButtonTest();
+
+ protected:
+ virtual void SetUp() OVERRIDE;
+ virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE;
+ void CreateTestingProfile();
+ void StartAvatarMenu();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NewAvatarMenuButtonTest);
+};
+
+NewAvatarMenuButtonTest::NewAvatarMenuButtonTest() {
+}
+
+NewAvatarMenuButtonTest::~NewAvatarMenuButtonTest() {
+}
+
+void NewAvatarMenuButtonTest::SetUp() {
+ InProcessBrowserTest::SetUp();
+ DCHECK(CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kNewProfileManagement));
+}
+
+void NewAvatarMenuButtonTest::SetUpCommandLine(CommandLine* command_line) {
+ command_line->AppendSwitch(switches::kNewProfileManagement);
+}
+
+void NewAvatarMenuButtonTest::CreateTestingProfile() {
+ ProfileManager* profile_manager = g_browser_process->profile_manager();
+ EXPECT_EQ(1u, profile_manager->GetNumberOfProfiles());
+
+ // Sign in the default profile
+ ProfileInfoCache& cache = profile_manager->GetProfileInfoCache();
+ cache.SetUserNameOfProfileAtIndex(0, UTF8ToUTF16("user_name"));
+
+ base::FilePath path;
+ PathService::Get(chrome::DIR_USER_DATA, &path);
+ path = path.AppendASCII("test_profile");
+ if (!base::PathExists(path))
+ ASSERT_TRUE(file_util::CreateDirectory(path));
+ Profile* profile =
+ Profile::CreateProfile(path, NULL, Profile::CREATE_MODE_SYNCHRONOUS);
+ profile_manager->RegisterTestingProfile(profile, true, false);
+ EXPECT_EQ(2u, profile_manager->GetNumberOfProfiles());
+}
+
+void NewAvatarMenuButtonTest::StartAvatarMenu() {
+ BrowserView* browser_view = reinterpret_cast<BrowserView*>(
+ browser()->window());
+
+ // Ensure that the avatar icon button is not also showing.
+ NewAvatarButton* button = browser_view->frame()->GetNewAvatarMenuButton();
+ ASSERT_TRUE(button);
+ ASSERT_FALSE(browser_view->frame()->GetAvatarMenuButton());
+
+ ProfileChooserView::set_close_on_deactivate(false);
+ ui::MouseEvent mouse_ev(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(), 0);
+ button->NotifyClick(mouse_ev);
+ base::MessageLoop::current()->RunUntilIdle();
+ EXPECT_TRUE(ProfileChooserView::IsShowing());
+}
+
+IN_PROC_BROWSER_TEST_F(NewAvatarMenuButtonTest, SignOut) {
+ // If multiprofile mode is not enabled, you can't switch between profiles.
+ if (!profiles::IsMultipleProfilesEnabled())
+ return;
+
+ CreateTestingProfile();
+ ASSERT_NO_FATAL_FAILURE(StartAvatarMenu());
+
+ BrowserList* browser_list =
+ BrowserList::GetInstance(chrome::GetActiveDesktop());
+ EXPECT_EQ(1U, browser_list->size());
+ content::WindowedNotificationObserver window_close_observer(
+ chrome::NOTIFICATION_BROWSER_CLOSED,
+ content::Source<Browser>(browser()));
+
+ AvatarMenu* menu =
+ ProfileChooserView::profile_bubble_->avatar_menu_.get();
+ const AvatarMenu::Item& menu_item_before =
+ menu->GetItemAt(menu->GetActiveProfileIndex());
+ EXPECT_FALSE(menu_item_before.signin_required);
+
+ ui::MouseEvent mouse_ev(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(), 0);
+ menu->SetLogoutURL("about:blank");
+
+ ProfileChooserView::profile_bubble_->LinkClicked(
+ static_cast<views::Link*>(
+ ProfileChooserView::profile_bubble_->signout_current_profile_link_),
+ 0);
+
+ EXPECT_TRUE(menu->GetItemAt(menu->GetActiveProfileIndex()).signin_required);
+
+ window_close_observer.Wait(); // Rely on test timeout for failure indication.
+ EXPECT_TRUE(browser_list->empty());
+}
diff --git a/chrome/browser/ui/views/notifications/balloon_view_views.cc b/chrome/browser/ui/views/notifications/balloon_view_views.cc
index 2680f78eb3..a288d01040 100644
--- a/chrome/browser/ui/views/notifications/balloon_view_views.cc
+++ b/chrome/browser/ui/views/notifications/balloon_view_views.cc
@@ -74,9 +74,6 @@ const int kBottomShadowWidth = 6;
// Optional animation.
const bool kAnimateEnabled = true;
-// Menu commands
-const int kRevokePermissionCommand = 0;
-
// Colors
const SkColor kControlBarBackgroundColor = SkColorSetRGB(245, 245, 245);
const SkColor kControlBarTextColor = SkColorSetRGB(125, 125, 125);
diff --git a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
index 12193bb594..d52726fd99 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
@@ -23,20 +23,10 @@
#include "ui/views/corewm/window_animations.h"
#endif
-namespace {
-
-// This is the number of pixels in the border image used to draw the bottom
-// border + drop shadow interior to the "visual" border. We lay out assuming
-// that this many pixels inside the border is "in the popup."
-const SkAlpha kGlassPopupAlpha = 240;
-const SkAlpha kOpaquePopupAlpha = 255;
-
// This is the number of pixels in the border image interior to the actual
// border.
const int kBorderInterior = 6;
-} // namespace
-
class OmniboxPopupContentsView::AutocompletePopupWidget
: public views::Widget,
public base::SupportsWeakPtr<AutocompletePopupWidget> {
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
index 1248754004..b87a6af911 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -55,7 +55,7 @@
#endif
#if defined(USE_AURA)
-#include "ui/aura/focus_manager.h"
+#include "ui/aura/client/focus_client.h"
#include "ui/aura/root_window.h"
#include "ui/compositor/layer.h"
#endif
diff --git a/chrome/browser/ui/views/panels/panel_frame_view.cc b/chrome/browser/ui/views/panels/panel_frame_view.cc
index 7b9ed293bb..4b81d3db4d 100644
--- a/chrome/browser/ui/views/panels/panel_frame_view.cc
+++ b/chrome/browser/ui/views/panels/panel_frame_view.cc
@@ -58,7 +58,6 @@ const SkColor kAttentionBackgroundDefaultColor =
// Color used to draw the minimized panel.
const SkColor kMinimizeBackgroundDefaultColor = SkColorSetRGB(0xf5, 0xf4, 0xf0);
-const SkColor kMinimizeBorderDefaultColor = SkColorSetRGB(0xc9, 0xc9, 0xc9);
// Color used to draw the title text under default theme.
const SkColor kTitleTextDefaultColor = SkColorSetRGB(0xf9, 0xf9, 0xf9);
diff --git a/chrome/browser/ui/views/panels/panel_view.cc b/chrome/browser/ui/views/panels/panel_view.cc
index aef7111c7e..97aa507eeb 100644
--- a/chrome/browser/ui/views/panels/panel_view.cc
+++ b/chrome/browser/ui/views/panels/panel_view.cc
@@ -38,10 +38,12 @@
namespace {
+#if defined(OS_WIN)
// If the height of a stacked panel shrinks below this threshold during the
// user resizing, it will be treated as minimized.
const int kStackedPanelHeightShrinkThresholdToBecomeMinimized =
panel::kTitlebarHeight + 20;
+#endif
// Supported accelerators.
// Note: We can't use the acclerator table defined in chrome/browser/ui/views
diff --git a/chrome/browser/ui/views/profile_chooser_view.cc b/chrome/browser/ui/views/profile_chooser_view.cc
index 8518378724..3c53784f51 100644
--- a/chrome/browser/ui/views/profile_chooser_view.cc
+++ b/chrome/browser/ui/views/profile_chooser_view.cc
@@ -48,6 +48,7 @@ const int kLargeImageSide = 64;
const int kSmallImageSide = 32;
const int kMinMenuWidth = 250;
const int kButtonHeight = 29;
+const int kArrowHeight = 10;
// Current profile avatar image.
views::View* CreateProfileImageView(const gfx::Image& icon) {
@@ -55,8 +56,8 @@ views::View* CreateProfileImageView(const gfx::Image& icon) {
gfx::Image image = profiles::GetSizedAvatarIconWithBorder(
icon, true,
- kLargeImageSide + profiles::kAvatarIconBorder,
- kLargeImageSide + profiles::kAvatarIconBorder);
+ kLargeImageSide + profiles::kAvatarIconPadding,
+ kLargeImageSide + profiles::kAvatarIconPadding);
view->SetImage(image.ToImageSkia());
return view;
@@ -199,6 +200,7 @@ void ProfileChooserView::ShowBubble(
profile_bubble_->set_close_on_deactivate(close_on_deactivate_);
profile_bubble_->SetAlignment(border_alignment);
profile_bubble_->GetWidget()->Show();
+ profile_bubble_->SetArrowPaintType(views::BubbleBorder::PAINT_NONE);
}
// static
@@ -220,6 +222,8 @@ ProfileChooserView::ProfileChooserView(views::View* anchor_view,
browser_(browser) {
// Reset the default margins inherited from the BubbleDelegateView.
set_margins(gfx::Insets());
+ // Compensate for built-in vertical padding in the anchor view's image.
+ set_anchor_view_insets(gfx::Insets(kArrowHeight, 0, kArrowHeight, 0));
ResetLinksAndButtons();
@@ -274,12 +278,18 @@ void ProfileChooserView::ShowView(BubbleViewMode view_to_display,
layout->set_minimum_size(gfx::Size(kMinMenuWidth, 0));
if (view_to_display == GAIA_SIGNIN_VIEW) {
+ const int kMinGaiaViewWidth = 280;
+ const int kMinGaiaViewHeight = 300;
Profile* profile = browser_->profile();
views::WebView* web_view = new views::WebView(profile);
web_view->LoadInitialURL(GURL(chrome::kChromeUIInlineLoginURL));
layout->StartRow(1, 0);
layout->AddView(web_view);
+ layout->set_minimum_size(
+ gfx::Size(kMinGaiaViewWidth, kMinGaiaViewHeight));
Layout();
+ if (GetBubbleFrameView())
+ SizeToContents();
return;
}
@@ -329,6 +339,8 @@ void ProfileChooserView::ShowView(BubbleViewMode view_to_display,
layout->AddView(option_buttons_view);
Layout();
+ if (GetBubbleFrameView())
+ SizeToContents();
}
void ProfileChooserView::WindowClosing() {
@@ -367,7 +379,6 @@ void ProfileChooserView::LinkClicked(views::Link* sender, int event_flags) {
if (sender == manage_accounts_link_) {
// ShowView() will DCHECK if this view is displayed for non signed-in users.
ShowView(ACCOUNT_MANAGEMENT_VIEW, avatar_menu_.get());
- SizeToContents(); // The account list changes the height of the bubble.
} else if (sender == signout_current_profile_link_) {
avatar_menu_->BeginSignOut();
} else if (sender == signin_current_profile_link_) {
@@ -505,8 +516,8 @@ views::View* ProfileChooserView::CreateOtherProfilesView(
gfx::Image image = profiles::GetSizedAvatarIconWithBorder(
item.icon, true,
- kSmallImageSide + profiles::kAvatarIconBorder,
- kSmallImageSide + profiles::kAvatarIconBorder);
+ kSmallImageSide + profiles::kAvatarIconPadding,
+ kSmallImageSide + profiles::kAvatarIconPadding);
views::TextButton* button = new views::TextButton(this, item.name);
open_other_profile_indexes_map_[button] = index;
diff --git a/chrome/browser/ui/views/profile_chooser_view.h b/chrome/browser/ui/views/profile_chooser_view.h
index eec7f2edcb..8affea1ae6 100644
--- a/chrome/browser/ui/views/profile_chooser_view.h
+++ b/chrome/browser/ui/views/profile_chooser_view.h
@@ -55,9 +55,8 @@ class ProfileChooserView : public views::BubbleDelegateView,
}
private:
- friend class AvatarMenuButtonTest;
- FRIEND_TEST_ALL_PREFIXES(AvatarMenuButtonTest, NewSignOut);
- FRIEND_TEST_ALL_PREFIXES(AvatarMenuButtonTest, LaunchUserManagerScreen);
+ friend class NewAvatarMenuButtonTest;
+ FRIEND_TEST_ALL_PREFIXES(NewAvatarMenuButtonTest, SignOut);
typedef std::vector<size_t> Indexes;
typedef std::map<views::Button*, int> ButtonIndexes;
diff --git a/chrome/browser/ui/views/speech_recognition_bubble_views.cc b/chrome/browser/ui/views/speech_recognition_bubble_views.cc
index 2434c1d06f..71b3919327 100644
--- a/chrome/browser/ui/views/speech_recognition_bubble_views.cc
+++ b/chrome/browser/ui/views/speech_recognition_bubble_views.cc
@@ -35,8 +35,6 @@ namespace {
const int kBubbleHorizMargin = 6;
const int kBubbleVertMargin = 4;
const int kBubbleHeadingVertMargin = 6;
-const int kIconHorizontalOffset = 27;
-const int kIconVerticalOffset = -7;
// This is the SpeechRecognitionBubble content and views bubble delegate.
class SpeechRecognitionBubbleView : public views::BubbleDelegateView,
diff --git a/chrome/browser/ui/views/stubs_aura.cc b/chrome/browser/ui/views/stubs_aura.cc
index 5a77b51ead..bb90ffde01 100644
--- a/chrome/browser/ui/views/stubs_aura.cc
+++ b/chrome/browser/ui/views/stubs_aura.cc
@@ -2,34 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/callback.h"
#include "base/logging.h"
#include "chrome/browser/external_protocol/external_protocol_handler.h"
-#include "ui/gfx/native_widget_types.h"
-
-#if !defined(OS_WIN)
-#include "chrome/browser/ui/certificate_dialogs.h"
-#endif
-
-#if defined(USE_NSS)
-#include "chrome/browser/ui/crypto_module_password_dialog.h"
-#endif
-
-class SSLClientAuthHandler;
-
-namespace content {
-class WebContents;
-}
-
-namespace net {
-class HttpNetworkSession;
-class SSLCertRequestInfo;
-class X509Certificate;
-}
-
-namespace views {
-class Widget;
-}
+#include "chrome/browser/ui/browser_dialogs.h"
namespace chrome {
@@ -43,6 +18,8 @@ void ShowAboutIPCDialog() {
#if !defined(OS_CHROMEOS) && !defined(OS_WIN)
// static
void ExternalProtocolHandler::RunExternalProtocolDialog(
- const GURL& url, int render_process_host_id, int routing_id) {
+ const GURL& url,
+ int render_process_host_id,
+ int routing_id) {
}
#endif
diff --git a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
index 1c21c890de..804be07503 100644
--- a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
+++ b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
@@ -388,7 +388,7 @@ void BrowserTabStripController::TabInsertedAt(WebContents* contents,
int model_index,
bool is_active) {
DCHECK(contents);
- CHECK(model_->ContainsIndex(model_index));
+ DCHECK(model_->ContainsIndex(model_index));
AddTab(contents, model_index, is_active);
}
diff --git a/chrome/browser/ui/views/tabs/dragged_tab_view.cc b/chrome/browser/ui/views/tabs/dragged_tab_view.cc
index d7b8cf81ca..b62e1cf304 100644
--- a/chrome/browser/ui/views/tabs/dragged_tab_view.cc
+++ b/chrome/browser/ui/views/tabs/dragged_tab_view.cc
@@ -18,7 +18,6 @@
#endif
static const int kTransparentAlpha = 200;
-static const int kOpaqueAlpha = 255;
static const int kDragFrameBorderSize = 2;
static const int kTwiceDragFrameBorderSize = 2 * kDragFrameBorderSize;
static const float kScalingFactor = 0.5;
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
index 6f13d81163..ba0564b2e5 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
@@ -59,6 +59,11 @@
#include "ui/events/gestures/gesture_recognizer.h"
#endif
+#if defined(OS_WIN) && defined(USE_AURA)
+#include "ui/aura/window.h"
+#include "ui/events/gestures/gesture_recognizer.h"
+#endif
+
using content::OpenURLParams;
using content::UserMetricsAction;
using content::WebContents;
@@ -897,6 +902,18 @@ TabDragController::DragBrowserToNewTabStrip(
target_tabstrip->GetWidget()->SetCapture(attached_tabstrip_);
else
browser_widget->ReleaseCapture();
+#if defined(OS_WIN) && defined(USE_AURA)
+ // The Gesture recognizer does not work well currently when capture changes
+ // while a touch gesture is in progress. So we need to manually transfer
+ // gesture sequence and the GR's touch events queue to the new window. This
+ // should really be done somewhere in capture change code and or inside the
+ // GR. But we currently do not have a consistent way for doing it that would
+ // work in all cases. Hence this hack.
+ ui::GestureRecognizer::Get()->TransferEventsTo(
+ browser_widget->GetNativeView(),
+ target_tabstrip->GetWidget()->GetNativeView());
+#endif
+
// The window is going away. Since the drag is still on going we don't want
// that to effect the position of any windows.
SetWindowPositionManaged(browser_widget->GetNativeView(), false);
@@ -2227,9 +2244,8 @@ gfx::Point TabDragController::GetCursorScreenPoint() {
aura::Window* widget_window = widget->GetNativeWindow();
DCHECK(widget_window->GetRootWindow());
gfx::Point touch_point;
- bool got_touch_point = widget_window->GetRootWindow()->
- gesture_recognizer()->GetLastTouchPointForTarget(widget_window,
- &touch_point);
+ bool got_touch_point = ui::GestureRecognizer::Get()->
+ GetLastTouchPointForTarget(widget_window, &touch_point);
DCHECK(got_touch_point);
ash::wm::ConvertPointToScreen(widget_window->GetRootWindow(), &touch_point);
return touch_point;
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
index bd7183a62b..54b91d531d 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -875,8 +875,14 @@ void DragAllStep2(DetachToBrowserTabDragControllerTest* test,
} // namespace
+// Flaky on Windows Aura. crbug.com/309054
+#if defined(OS_WIN) && defined(USE_AURA)
+#define MAYBE_DragAll DISABLED_DragAll
+#else
+#define MAYBE_DragAll DragAll
+#endif
// Selects multiple tabs and starts dragging the window.
-IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, DragAll) {
+IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, MAYBE_DragAll) {
// Add another tab.
AddTabAndResetBrowser(browser());
TabStrip* tab_strip = GetTabStripForBrowser(browser());
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index 12ec61cfdb..0e3ac65f49 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -96,8 +96,10 @@ static const int kMaxStackedCount = 4;
static const int kStackedPadding = 6;
// See UpdateLayoutTypeFromMouseEvent() for a description of these.
+#if !defined(USE_ASH)
const int kMouseMoveTimeMS = 200;
const int kMouseMoveCountBeforeConsiderReal = 3;
+#endif
// Amount of time we delay before resizing after a close from a touch.
const int kTouchResizeLayoutTimeMS = 2000;
@@ -1639,7 +1641,6 @@ Tab* TabStrip::CreateTab() {
}
void TabStrip::StartInsertTabAnimation(int model_index) {
- CHECK_LT(model_index, tabs_.view_size());
PrepareForAnimation();
// The TabStrip can now use its entire width to lay out Tabs.
@@ -1647,7 +1648,7 @@ void TabStrip::StartInsertTabAnimation(int model_index) {
available_width_for_tabs_ = -1;
GenerateIdealBounds();
- CHECK_LT(model_index, tabs_.view_size());
+
Tab* tab = tab_at(model_index);
if (model_index == 0) {
tab->SetBounds(0, ideal_bounds(model_index).y(), 0,
diff --git a/chrome/browser/ui/views/toolbar_view.cc b/chrome/browser/ui/views/toolbar_view.cc
index 8ac94c0af4..b9f31afc1c 100644
--- a/chrome/browser/ui/views/toolbar_view.cc
+++ b/chrome/browser/ui/views/toolbar_view.cc
@@ -93,10 +93,6 @@ const int kContentShadowHeightAsh = 2;
// Non-ash uses a rounded content area with no shadow in the assets.
const int kContentShadowHeight = 0;
-// Top margin for the wrench menu badges (badge is placed in the upper right
-// corner of the wrench menu).
-const int kBadgeTopMargin = 2;
-
int GetButtonSpacing() {
return (ui::GetDisplayLayout() == ui::LAYOUT_TOUCH) ?
ToolbarView::kStandardSpacing : 0;
@@ -575,9 +571,10 @@ void ToolbarView::Layout() {
}
bool ToolbarView::HitTestRect(const gfx::Rect& rect) const {
- // Don't take hits in our top shadow edge. Let them fall through to the
- // tab strip above us.
- if (rect.y() < content_shadow_height())
+ // Fall through to the tab strip above us if none of |rect| intersects
+ // with this view (intersection with the top shadow edge does not
+ // count as intersection with this view).
+ if (rect.bottom() < content_shadow_height())
return false;
// Otherwise let our superclass take care of it.
return AccessiblePaneView::HitTestRect(rect);
diff --git a/chrome/browser/ui/views/translate/translate_bubble_view.cc b/chrome/browser/ui/views/translate/translate_bubble_view.cc
new file mode 100644
index 0000000000..f24b936003
--- /dev/null
+++ b/chrome/browser/ui/views/translate/translate_bubble_view.cc
@@ -0,0 +1,753 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/translate/translate_bubble_view.h"
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include "base/i18n/string_compare.h"
+#include "base/memory/singleton.h"
+#include "base/metrics/histogram.h"
+#include "base/prefs/pref_service.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/translate/translate_manager.h"
+#include "chrome/browser/translate/translate_tab_helper.h"
+#include "chrome/browser/translate/translate_ui_delegate.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/translate/translate_bubble_model_impl.h"
+#include "chrome/common/url_constants.h"
+#include "content/public/browser/web_contents.h"
+#include "grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/models/combobox_model.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/views/controls/button/checkbox.h"
+#include "ui/views/controls/button/label_button.h"
+#include "ui/views/controls/combobox/combobox.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/controls/link.h"
+#include "ui/views/layout/box_layout.h"
+#include "ui/views/layout/grid_layout.h"
+#include "ui/views/layout/layout_constants.h"
+#include "ui/views/widget/widget.h"
+
+namespace {
+
+views::LabelButton* CreateLabelButton(views::ButtonListener* listener,
+ const string16& label, int id) {
+ views::LabelButton* button = new views::LabelButton(listener, label);
+ button->set_id(id);
+ button->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
+ return button;
+}
+
+views::Link* CreateLink(views::LinkListener* listener,
+ int resource_id,
+ int id) {
+ views::Link* link = new views::Link(
+ l10n_util::GetStringUTF16(resource_id));
+ link->set_listener(listener);
+ link->set_id(id);
+ return link;
+}
+
+void GetTranslateLanguages(content::WebContents* web_contents,
+ std::string* source,
+ std::string* target) {
+ DCHECK(source != NULL);
+ DCHECK(target != NULL);
+
+ TranslateTabHelper* translate_tab_helper =
+ TranslateTabHelper::FromWebContents(web_contents);
+ *source = translate_tab_helper->language_state().original_language();
+ *target = TranslateManager::GetLanguageCode(
+ g_browser_process->GetApplicationLocale());
+}
+
+// TODO(hajimehoshi): The interface to offer denial choices should be another
+// control instead of Combobox. See crbug/305494.
+class TranslateDenialComboboxModel : public ui::ComboboxModel {
+ public:
+ enum {
+ INDEX_NOPE = 0,
+ INDEX_NEVER_TRANSLATE_LANGUAGE = 2,
+ INDEX_NEVER_TRANSLATE_SITE = 4,
+ };
+
+ explicit TranslateDenialComboboxModel(
+ const string16& original_language_name) {
+ items_.push_back(l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_DENY));
+ items_.push_back(string16());
+ items_.push_back(l10n_util::GetStringFUTF16(
+ IDS_TRANSLATE_BUBBLE_NEVER_TRANSLATE_LANG,
+ original_language_name));
+ items_.push_back(string16());
+ items_.push_back(l10n_util::GetStringUTF16(
+ IDS_TRANSLATE_BUBBLE_NEVER_TRANSLATE_SITE));
+ }
+ virtual ~TranslateDenialComboboxModel() {}
+
+ private:
+ // Overridden from ui::ComboboxModel:
+ virtual int GetItemCount() const OVERRIDE {
+ return items_.size();
+ }
+ virtual string16 GetItemAt(int index) OVERRIDE {
+ return items_[index];
+ }
+ virtual bool IsItemSeparatorAt(int index) OVERRIDE {
+ return items_[index].empty();
+ }
+ virtual int GetDefaultIndex() const OVERRIDE {
+ return 0;
+ }
+
+ std::vector<string16> items_;
+
+ DISALLOW_COPY_AND_ASSIGN(TranslateDenialComboboxModel);
+};
+
+const char* kUMATranslateModifyOriginalLang = "Translate.ModifyOriginalLang";
+const char* kUMATranslateModifyTargetLang = "Translate.ModifyTargetLang";
+
+} // namespace
+
+// static
+TranslateBubbleView* TranslateBubbleView::translate_bubble_view_ = NULL;
+
+TranslateBubbleView::~TranslateBubbleView() {
+ // A child view could refer to a model which is owned by this class when
+ // the child view is destructed. For example, |source_language_combobx_model_|
+ // is referred by Combobox's destructor. Before destroying the models,
+ // removing the child views is needed.
+ RemoveAllChildViews(true);
+}
+
+// static
+void TranslateBubbleView::ShowBubble(views::View* anchor_view,
+ content::WebContents* web_contents,
+ TranslateBubbleModel::ViewState type,
+ Browser* browser) {
+ if (IsShowing()) {
+ translate_bubble_view_->SwitchView(type);
+ return;
+ }
+
+ std::string source_language;
+ std::string target_language;
+ GetTranslateLanguages(web_contents, &source_language, &target_language);
+
+ scoped_ptr<TranslateUIDelegate> ui_delegate(
+ new TranslateUIDelegate(web_contents, source_language, target_language));
+ scoped_ptr<TranslateBubbleModel> model(
+ new TranslateBubbleModelImpl(type, ui_delegate.Pass()));
+ bool is_in_incognito_window =
+ web_contents->GetBrowserContext()->IsOffTheRecord();
+ TranslateBubbleView* view = new TranslateBubbleView(anchor_view,
+ model.Pass(),
+ is_in_incognito_window,
+ browser);
+ views::BubbleDelegateView::CreateBubble(view)->Show();
+}
+
+// static
+bool TranslateBubbleView::IsShowing() {
+ return translate_bubble_view_ != NULL;
+}
+
+void TranslateBubbleView::Init() {
+ SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical,
+ 0, 0, 0));
+
+ before_translate_view_ = CreateViewBeforeTranslate();
+ translating_view_ = CreateViewTranslating();
+ after_translate_view_ = CreateViewAfterTranslate();
+ error_view_ = CreateViewError();
+ advanced_view_ = CreateViewAdvanced();
+
+ AddChildView(before_translate_view_);
+ AddChildView(translating_view_);
+ AddChildView(after_translate_view_);
+ AddChildView(error_view_);
+ AddChildView(advanced_view_);
+
+ AddAccelerator(ui::Accelerator(ui::VKEY_RETURN, ui::EF_NONE));
+
+ UpdateChildVisibilities();
+}
+
+void TranslateBubbleView::ButtonPressed(views::Button* sender,
+ const ui::Event& event) {
+ HandleButtonPressed(static_cast<ButtonID>(sender->id()));
+}
+
+void TranslateBubbleView::WindowClosing() {
+ if (!translate_executed_)
+ model_->TranslationDeclined();
+
+ // We have to reset |translate_bubble_view_| here, not in our destructor,
+ // because we'll be destroyed asynchronously and the shown state will be
+ // checked before then.
+ DCHECK_EQ(translate_bubble_view_, this);
+ translate_bubble_view_ = NULL;
+}
+
+bool TranslateBubbleView::AcceleratorPressed(
+ const ui::Accelerator& accelerator) {
+ switch (model_->GetViewState()) {
+ case TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE: {
+ if (accelerator.key_code() == ui::VKEY_RETURN) {
+ HandleButtonPressed(BUTTON_ID_TRANSLATE);
+ return true;
+ }
+ break;
+ }
+ case TranslateBubbleModel::VIEW_STATE_TRANSLATING:
+ break;
+ case TranslateBubbleModel::VIEW_STATE_AFTER_TRANSLATE: {
+ if (accelerator.key_code() == ui::VKEY_RETURN) {
+ HandleButtonPressed(BUTTON_ID_SHOW_ORIGINAL);
+ return true;
+ }
+ break;
+ }
+ case TranslateBubbleModel::VIEW_STATE_ERROR:
+ break;
+ case TranslateBubbleModel::VIEW_STATE_ADVANCED: {
+ if (accelerator.key_code() == ui::VKEY_RETURN) {
+ HandleButtonPressed(BUTTON_ID_DONE);
+ return true;
+ }
+ break;
+ }
+ }
+ return BubbleDelegateView::AcceleratorPressed(accelerator);
+}
+
+gfx::Size TranslateBubbleView::GetPreferredSize() {
+ int width = 0;
+ for (int i = 0; i < child_count(); i++) {
+ views::View* child = child_at(i);
+ width = std::max(width, child->GetPreferredSize().width());
+ }
+ int height = GetCurrentView()->GetPreferredSize().height();
+ return gfx::Size(width, height);
+}
+
+void TranslateBubbleView::OnSelectedIndexChanged(views::Combobox* combobox) {
+ switch (static_cast<ComboboxID>(combobox->id())) {
+ case COMBOBOX_ID_DENIAL: {
+ int index = combobox->selected_index();
+ switch (index) {
+ case TranslateDenialComboboxModel::INDEX_NOPE:
+ if (!translate_executed_)
+ model_->TranslationDeclined();
+ StartFade(false);
+ break;
+ case TranslateDenialComboboxModel::INDEX_NEVER_TRANSLATE_LANGUAGE:
+ model_->SetNeverTranslateLanguage(true);
+ StartFade(false);
+ break;
+ case TranslateDenialComboboxModel::INDEX_NEVER_TRANSLATE_SITE:
+ model_->SetNeverTranslateSite(true);
+ StartFade(false);
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ break;
+ }
+ case COMBOBOX_ID_SOURCE_LANGUAGE: {
+ // TODO(hajimehoshi): This UMA should be counted at a model or a delegate
+ // not to dependent on platforms. However, this UMA has not been used at
+ // some platforms. See crbug/306365.
+ UMA_HISTOGRAM_BOOLEAN(kUMATranslateModifyOriginalLang, true);
+ UpdateAdvancedView();
+ break;
+ }
+ case COMBOBOX_ID_TARGET_LANGUAGE: {
+ // TODO(hajimehoshi): Ditto.
+ UMA_HISTOGRAM_BOOLEAN(kUMATranslateModifyTargetLang, true);
+ UpdateAdvancedView();
+ break;
+ }
+ }
+}
+
+void TranslateBubbleView::LinkClicked(views::Link* source, int event_flags) {
+ HandleLinkClicked(static_cast<LinkID>(source->id()));
+}
+
+TranslateBubbleModel::ViewState TranslateBubbleView::GetViewState() const {
+ return model_->GetViewState();
+}
+
+TranslateBubbleView::TranslateBubbleView(
+ views::View* anchor_view,
+ scoped_ptr<TranslateBubbleModel> model,
+ bool is_in_incognito_window,
+ Browser* browser)
+ : BubbleDelegateView(anchor_view, views::BubbleBorder::TOP_RIGHT),
+ source_language_combobox_(NULL),
+ target_language_combobox_(NULL),
+ always_translate_checkbox_(NULL),
+ model_(model.Pass()),
+ is_in_incognito_window_(is_in_incognito_window),
+ browser_(browser),
+ translate_executed_(false) {
+ if (model_->GetViewState() !=
+ TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE) {
+ translate_executed_ = true;
+ }
+
+ set_margins(gfx::Insets(views::kPanelVertMargin, views::kPanelHorizMargin,
+ views::kPanelVertMargin, views::kPanelHorizMargin));
+
+ translate_bubble_view_ = this;
+}
+
+views::View* TranslateBubbleView::GetCurrentView() {
+ switch (model_->GetViewState()) {
+ case TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE:
+ return before_translate_view_;
+ case TranslateBubbleModel::VIEW_STATE_TRANSLATING:
+ return translating_view_;
+ case TranslateBubbleModel::VIEW_STATE_AFTER_TRANSLATE:
+ return after_translate_view_;
+ case TranslateBubbleModel::VIEW_STATE_ERROR:
+ return error_view_;
+ case TranslateBubbleModel::VIEW_STATE_ADVANCED:
+ return advanced_view_;
+ }
+ NOTREACHED();
+ return NULL;
+}
+
+void TranslateBubbleView::HandleButtonPressed(
+ TranslateBubbleView::ButtonID sender_id) {
+ switch (sender_id) {
+ case BUTTON_ID_TRANSLATE: {
+ translate_executed_ = true;
+ model_->Translate();
+ break;
+ }
+ case BUTTON_ID_DONE: {
+ translate_executed_ = true;
+ DCHECK(source_language_combobox_);
+ DCHECK(target_language_combobox_);
+
+ model_->SetOriginalLanguageIndex(
+ source_language_combobox_->selected_index());
+ model_->SetTargetLanguageIndex(
+ target_language_combobox_->selected_index());
+ model_->Translate();
+ break;
+ }
+ case BUTTON_ID_CANCEL: {
+ model_->GoBackFromAdvanced();
+ UpdateChildVisibilities();
+ SizeToContents();
+ break;
+ }
+ case BUTTON_ID_TRY_AGAIN: {
+ translate_executed_ = true;
+ model_->Translate();
+ break;
+ }
+ case BUTTON_ID_SHOW_ORIGINAL: {
+ model_->RevertTranslation();
+ StartFade(false);
+ break;
+ }
+ case BUTTON_ID_ALWAYS_TRANSLATE: {
+ DCHECK(always_translate_checkbox_);
+ model_->SetAlwaysTranslate(always_translate_checkbox_->checked());
+ UpdateAdvancedView();
+ break;
+ }
+ }
+}
+
+void TranslateBubbleView::HandleLinkClicked(
+ TranslateBubbleView::LinkID sender_id) {
+ switch (sender_id) {
+ case LINK_ID_ADVANCED: {
+ SwitchView(TranslateBubbleModel::VIEW_STATE_ADVANCED);
+ break;
+ }
+ case LINK_ID_LEARN_MORE: {
+ browser_->OpenURL(content::OpenURLParams(
+ GURL(chrome::kAboutGoogleTranslateURL),
+ content::Referrer(),
+ NEW_FOREGROUND_TAB,
+ content::PAGE_TRANSITION_LINK,
+ false));
+ break;
+ }
+ }
+}
+
+void TranslateBubbleView::UpdateChildVisibilities() {
+ for (int i = 0; i < child_count(); i++) {
+ views::View* view = child_at(i);
+ view->SetVisible(view == GetCurrentView());
+ }
+}
+
+views::View* TranslateBubbleView::CreateViewBeforeTranslate() {
+ views::Label* message_label = new views::Label(
+ l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_BEFORE_TRANSLATE));
+
+ string16 original_language_name =
+ model_->GetLanguageNameAt(model_->GetOriginalLanguageIndex());
+ views::Combobox* denial_combobox = new views::Combobox(
+ new TranslateDenialComboboxModel(original_language_name));
+ denial_combobox->set_id(COMBOBOX_ID_DENIAL);
+ denial_combobox->set_listener(this);
+
+ views::View* view = new views::View();
+ views::GridLayout* layout = new views::GridLayout(view);
+ view->SetLayoutManager(layout);
+
+ using views::GridLayout;
+
+ enum {
+ COLUMN_SET_ID_MESSAGE,
+ COLUMN_SET_ID_CONTENT,
+ };
+
+ views::ColumnSet* cs = layout->AddColumnSet(COLUMN_SET_ID_MESSAGE);
+ cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
+ 0, GridLayout::USE_PREF, 0, 0);
+ cs->AddPaddingColumn(0, views::kRelatedButtonHSpacing);
+ cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
+ 0, GridLayout::USE_PREF, 0, 0);
+ cs->AddPaddingColumn(1, 0);
+
+ cs = layout->AddColumnSet(COLUMN_SET_ID_CONTENT);
+ cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
+ 0, GridLayout::USE_PREF, 0, 0);
+ cs->AddPaddingColumn(1, views::kUnrelatedControlHorizontalSpacing);
+ cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
+ 0, GridLayout::USE_PREF, 0, 0);
+ cs->AddPaddingColumn(0, views::kRelatedButtonHSpacing);
+ cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
+ 0, GridLayout::USE_PREF, 0, 0);
+
+ layout->StartRow(0, COLUMN_SET_ID_MESSAGE);
+ layout->AddView(message_label);
+ layout->AddView(CreateLink(this,
+ IDS_TRANSLATE_BUBBLE_ADVANCED,
+ LINK_ID_ADVANCED));
+
+ layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing);
+
+ layout->StartRow(0, COLUMN_SET_ID_CONTENT);
+ layout->AddView(CreateLink(this,
+ IDS_TRANSLATE_BUBBLE_LEARN_MORE,
+ LINK_ID_LEARN_MORE));
+ layout->AddView(denial_combobox);
+ layout->AddView(CreateLabelButton(
+ this,
+ l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_ACCEPT),
+ BUTTON_ID_TRANSLATE));
+
+ return view;
+}
+
+views::View* TranslateBubbleView::CreateViewTranslating() {
+ string16 target_language_name =
+ model_->GetLanguageNameAt(model_->GetTargetLanguageIndex());
+ views::Label* label = new views::Label(
+ l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_TRANSLATING));
+
+ views::View* view = new views::View();
+ views::GridLayout* layout = new views::GridLayout(view);
+ view->SetLayoutManager(layout);
+
+ using views::GridLayout;
+
+ enum {
+ COLUMN_SET_ID_MESSAGE,
+ COLUMN_SET_ID_CONTENT,
+ };
+
+ views::ColumnSet* cs = layout->AddColumnSet(COLUMN_SET_ID_MESSAGE);
+ cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
+ 0, views::GridLayout::USE_PREF, 0, 0);
+ cs->AddPaddingColumn(1, 0);
+
+ cs = layout->AddColumnSet(COLUMN_SET_ID_CONTENT);
+ cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
+ 0, GridLayout::USE_PREF, 0, 0);
+ cs->AddPaddingColumn(1, views::kUnrelatedControlHorizontalSpacing);
+ cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
+ 0, GridLayout::USE_PREF, 0, 0);
+
+ layout->StartRow(0, COLUMN_SET_ID_MESSAGE);
+ layout->AddView(label);
+
+ layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing);
+
+ layout->StartRow(0, COLUMN_SET_ID_CONTENT);
+ layout->AddView(CreateLink(this,
+ IDS_TRANSLATE_BUBBLE_LEARN_MORE,
+ LINK_ID_LEARN_MORE));
+ views::LabelButton* revert_button = CreateLabelButton(
+ this,
+ l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_REVERT),
+ BUTTON_ID_SHOW_ORIGINAL);
+ revert_button->SetEnabled(false);
+ layout->AddView(revert_button);
+
+ return view;
+}
+
+views::View* TranslateBubbleView::CreateViewAfterTranslate() {
+ views::Label* label = new views::Label(
+ l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_TRANSLATED));
+
+ views::View* view = new views::View();
+ views::GridLayout* layout = new views::GridLayout(view);
+ view->SetLayoutManager(layout);
+
+ using views::GridLayout;
+
+ enum {
+ COLUMN_SET_ID_MESSAGE,
+ COLUMN_SET_ID_CONTENT,
+ };
+
+ views::ColumnSet* cs = layout->AddColumnSet(COLUMN_SET_ID_MESSAGE);
+ cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
+ 0, views::GridLayout::USE_PREF, 0, 0);
+ cs->AddPaddingColumn(0, views::kRelatedButtonHSpacing);
+ cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
+ 0, views::GridLayout::USE_PREF, 0, 0);
+ cs->AddPaddingColumn(1, 0);
+
+ cs = layout->AddColumnSet(COLUMN_SET_ID_CONTENT);
+ cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
+ 0, GridLayout::USE_PREF, 0, 0);
+ cs->AddPaddingColumn(1, views::kUnrelatedControlHorizontalSpacing);
+ cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
+ 0, GridLayout::USE_PREF, 0, 0);
+
+ layout->StartRow(0, COLUMN_SET_ID_MESSAGE);
+ layout->AddView(label);
+ layout->AddView(CreateLink(this,
+ IDS_TRANSLATE_BUBBLE_ADVANCED,
+ LINK_ID_ADVANCED));
+
+ layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing);
+
+ layout->StartRow(0, COLUMN_SET_ID_CONTENT);
+ layout->AddView(CreateLink(this,
+ IDS_TRANSLATE_BUBBLE_LEARN_MORE,
+ LINK_ID_LEARN_MORE));
+ layout->AddView(CreateLabelButton(
+ this,
+ l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_REVERT),
+ BUTTON_ID_SHOW_ORIGINAL));
+
+ return view;
+}
+
+views::View* TranslateBubbleView::CreateViewError() {
+ views::Label* label = new views::Label(
+ l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_COULD_NOT_TRANSLATE));
+
+ views::View* view = new views::View();
+ views::GridLayout* layout = new views::GridLayout(view);
+ view->SetLayoutManager(layout);
+
+ using views::GridLayout;
+
+ enum {
+ COLUMN_SET_ID_MESSAGE,
+ COLUMN_SET_ID_CONTENT,
+ };
+
+ views::ColumnSet* cs = layout->AddColumnSet(COLUMN_SET_ID_MESSAGE);
+ cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
+ 0, GridLayout::USE_PREF, 0, 0);
+ cs->AddPaddingColumn(0, views::kRelatedButtonHSpacing);
+ cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
+ 0, GridLayout::USE_PREF, 0, 0);
+ cs->AddPaddingColumn(1, 0);
+
+ cs = layout->AddColumnSet(COLUMN_SET_ID_CONTENT);
+ cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
+ 0, GridLayout::USE_PREF, 0, 0);
+ cs->AddPaddingColumn(1, views::kUnrelatedControlHorizontalSpacing);
+ cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
+ 0, GridLayout::USE_PREF, 0, 0);
+
+ layout->StartRow(0, COLUMN_SET_ID_MESSAGE);
+ layout->AddView(label);
+ layout->AddView(CreateLink(this,
+ IDS_TRANSLATE_BUBBLE_ADVANCED,
+ LINK_ID_ADVANCED));
+
+ layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing);
+
+ layout->StartRow(0, COLUMN_SET_ID_CONTENT);
+ layout->AddView(CreateLink(this,
+ IDS_TRANSLATE_BUBBLE_LEARN_MORE,
+ LINK_ID_LEARN_MORE));
+ layout->AddView(CreateLabelButton(
+ this,
+ l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_TRY_AGAIN),
+ BUTTON_ID_TRY_AGAIN));
+
+ return view;
+}
+
+// TODO(hajimehoshi): Revice this later to show a specific message for each
+// error. (crbug/307350)
+views::View* TranslateBubbleView::CreateViewAdvanced() {
+ views::Label* source_language_label = new views::Label(
+ l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_PAGE_LANGUAGE));
+
+ views::Label* target_language_label = new views::Label(
+ l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_TRANSLATION_LANGUAGE));
+
+ int source_default_index = model_->GetOriginalLanguageIndex();
+ source_language_combobox_model_.reset(
+ new LanguageComboboxModel(source_default_index, model_.get()));
+ source_language_combobox_ =
+ new views::Combobox(source_language_combobox_model_.get());
+
+ source_language_combobox_->set_id(COMBOBOX_ID_SOURCE_LANGUAGE);
+ source_language_combobox_->set_listener(this);
+
+ int target_default_index = model_->GetTargetLanguageIndex();
+ target_language_combobox_model_.reset(
+ new LanguageComboboxModel(target_default_index, model_.get()));
+ target_language_combobox_ =
+ new views::Combobox(target_language_combobox_model_.get());
+
+ target_language_combobox_->set_id(COMBOBOX_ID_TARGET_LANGUAGE);
+ target_language_combobox_->set_listener(this);
+
+ // In an incognito window, "Always translate" checkbox shouldn't be shown.
+ if (!is_in_incognito_window_) {
+ always_translate_checkbox_ = new views::Checkbox(string16());
+ always_translate_checkbox_->set_id(BUTTON_ID_ALWAYS_TRANSLATE);
+ always_translate_checkbox_->set_listener(this);
+ }
+
+ views::View* view = new views::View();
+ views::GridLayout* layout = new views::GridLayout(view);
+ view->SetLayoutManager(layout);
+
+ using views::GridLayout;
+
+ enum {
+ COLUMN_SET_ID_LANGUAGES,
+ COLUMN_SET_ID_ALWAYS_TRANSLATE,
+ COLUMN_SET_ID_BUTTONS,
+ };
+
+ views::ColumnSet* cs = layout->AddColumnSet(COLUMN_SET_ID_LANGUAGES);
+ cs->AddColumn(GridLayout::TRAILING, GridLayout::CENTER,
+ 0, GridLayout::USE_PREF, 0, 0);
+ cs->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
+ cs->AddColumn(GridLayout::FILL, GridLayout::CENTER,
+ 0, GridLayout::USE_PREF, 0, 0);
+ cs->AddPaddingColumn(1, 0);
+
+ if (!is_in_incognito_window_) {
+ cs = layout->AddColumnSet(COLUMN_SET_ID_ALWAYS_TRANSLATE);
+ cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
+ 0, GridLayout::USE_PREF, 0, 0);
+ cs->AddPaddingColumn(1, 0);
+ }
+
+ cs = layout->AddColumnSet(COLUMN_SET_ID_BUTTONS);
+ cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
+ 0, GridLayout::USE_PREF, 0, 0);
+ cs->AddPaddingColumn(1, views::kUnrelatedControlHorizontalSpacing);
+ cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
+ 0, GridLayout::USE_PREF, 0, 0);
+ cs->AddPaddingColumn(0, views::kRelatedButtonHSpacing);
+ cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
+ 0, GridLayout::USE_PREF, 0, 0);
+
+ layout->StartRow(0, COLUMN_SET_ID_LANGUAGES);
+ layout->AddView(source_language_label);
+ layout->AddView(source_language_combobox_);
+
+ layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
+
+ layout->StartRow(0, COLUMN_SET_ID_LANGUAGES);
+ layout->AddView(target_language_label);
+ layout->AddView(target_language_combobox_);
+
+ if (!is_in_incognito_window_) {
+ layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing);
+
+ layout->StartRow(0, COLUMN_SET_ID_ALWAYS_TRANSLATE);
+ layout->AddView(always_translate_checkbox_);
+ }
+
+ layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing);
+
+ layout->StartRow(0, COLUMN_SET_ID_BUTTONS);
+ layout->AddView(CreateLink(this,
+ IDS_TRANSLATE_BUBBLE_LEARN_MORE,
+ LINK_ID_LEARN_MORE));
+ views::LabelButton* cancel_button = CreateLabelButton(
+ this, l10n_util::GetStringUTF16(IDS_CANCEL), BUTTON_ID_CANCEL);
+ layout->AddView(cancel_button);
+ views::LabelButton* done_button = CreateLabelButton(
+ this, l10n_util::GetStringUTF16(IDS_DONE), BUTTON_ID_DONE);
+ done_button->SetIsDefault(true);
+ layout->AddView(done_button);
+
+ UpdateAdvancedView();
+
+ return view;
+}
+
+void TranslateBubbleView::SwitchView(
+ TranslateBubbleModel::ViewState view_state) {
+ if (model_->GetViewState() == view_state)
+ return;
+
+ model_->SetViewState(view_state);
+ UpdateChildVisibilities();
+ SizeToContents();
+}
+
+void TranslateBubbleView::UpdateAdvancedView() {
+ DCHECK(source_language_combobox_);
+ DCHECK(target_language_combobox_);
+
+ model_->SetOriginalLanguageIndex(
+ source_language_combobox_->selected_index());
+ model_->SetTargetLanguageIndex(
+ target_language_combobox_->selected_index());
+
+ string16 source_language_name =
+ model_->GetLanguageNameAt(model_->GetOriginalLanguageIndex());
+ string16 target_language_name =
+ model_->GetLanguageNameAt(model_->GetTargetLanguageIndex());
+
+ string16 message =
+ l10n_util::GetStringFUTF16(IDS_TRANSLATE_BUBBLE_ALWAYS,
+ source_language_name,
+ target_language_name);
+ // "Always translate" checkbox doesn't exist in an incognito window.
+ if (always_translate_checkbox_) {
+ always_translate_checkbox_->SetText(message);
+ always_translate_checkbox_->SetChecked(
+ model_->ShouldAlwaysTranslate());
+ }
+}
diff --git a/chrome/browser/ui/views/translate/translate_bubble_view.h b/chrome/browser/ui/views/translate/translate_bubble_view.h
new file mode 100644
index 0000000000..937ced284f
--- /dev/null
+++ b/chrome/browser/ui/views/translate/translate_bubble_view.h
@@ -0,0 +1,176 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_TRANSLATE_TRANSLATE_BUBBLE_VIEW_H_
+#define CHROME_BROWSER_UI_VIEWS_TRANSLATE_TRANSLATE_BUBBLE_VIEW_H_
+
+#include <map>
+#include <string>
+
+#include "base/basictypes.h"
+#include "chrome/browser/ui/translate/language_combobox_model.h"
+#include "chrome/browser/ui/translate/translate_bubble_model.h"
+#include "ui/views/bubble/bubble_delegate.h"
+#include "ui/views/controls/button/button.h"
+#include "ui/views/controls/combobox/combobox_listener.h"
+#include "ui/views/controls/link_listener.h"
+
+class Browser;
+class PrefService;
+class TranslateBubbleModel;
+
+namespace content {
+class WebContents;
+}
+
+namespace views {
+class Checkbox;
+class GridLayout;
+class LabelButton;
+class Link;
+class View;
+}
+
+class TranslateBubbleView : public views::BubbleDelegateView,
+ public views::ButtonListener,
+ public views::ComboboxListener,
+ public views::LinkListener {
+ public:
+ virtual ~TranslateBubbleView();
+
+ // Shows the Translate bubble.
+ static void ShowBubble(views::View* anchor_view,
+ content::WebContents* web_contents,
+ TranslateBubbleModel::ViewState type,
+ Browser* browser);
+
+ // If true, the Translate bubble is being shown.
+ static bool IsShowing();
+
+ // views::BubbleDelegateView methods.
+ virtual void Init() OVERRIDE;
+ virtual void ButtonPressed(views::Button* sender,
+ const ui::Event& event) OVERRIDE;
+
+ // views::WidgetDelegate method.
+ virtual void WindowClosing() OVERRIDE;
+
+ // views::View methods.
+ virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE;
+ virtual gfx::Size GetPreferredSize() OVERRIDE;
+
+ // views::CombboxListener method.
+ virtual void OnSelectedIndexChanged(views::Combobox* combobox) OVERRIDE;
+
+ // views::LinkListener method.
+ virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE;
+
+ // Returns the current view state.
+ TranslateBubbleModel::ViewState GetViewState() const;
+
+ private:
+ enum LinkID {
+ LINK_ID_ADVANCED,
+ LINK_ID_LEARN_MORE,
+ };
+
+ enum ButtonID {
+ BUTTON_ID_TRANSLATE,
+ BUTTON_ID_DONE,
+ BUTTON_ID_CANCEL,
+ BUTTON_ID_SHOW_ORIGINAL,
+ BUTTON_ID_TRY_AGAIN,
+ BUTTON_ID_ALWAYS_TRANSLATE,
+ };
+
+ enum ComboboxID {
+ COMBOBOX_ID_DENIAL,
+ COMBOBOX_ID_SOURCE_LANGUAGE,
+ COMBOBOX_ID_TARGET_LANGUAGE,
+ };
+
+ friend class TranslateBubbleViewTest;
+ FRIEND_TEST_ALL_PREFIXES(TranslateBubbleViewTest, TranslateButton);
+ FRIEND_TEST_ALL_PREFIXES(TranslateBubbleViewTest, AdvancedLink);
+ FRIEND_TEST_ALL_PREFIXES(TranslateBubbleViewTest, ShowOriginalButton);
+ FRIEND_TEST_ALL_PREFIXES(TranslateBubbleViewTest, TryAgainButton);
+ FRIEND_TEST_ALL_PREFIXES(TranslateBubbleViewTest, AlwaysTranslateCheckbox);
+ FRIEND_TEST_ALL_PREFIXES(TranslateBubbleViewTest, DoneButton);
+ FRIEND_TEST_ALL_PREFIXES(TranslateBubbleViewTest,
+ CancelButtonReturningBeforeTranslate);
+ FRIEND_TEST_ALL_PREFIXES(TranslateBubbleViewTest,
+ CancelButtonReturningAfterTranslate);
+ FRIEND_TEST_ALL_PREFIXES(TranslateBubbleViewTest, CancelButtonReturningError);
+
+ TranslateBubbleView(views::View* anchor_view,
+ scoped_ptr<TranslateBubbleModel> model,
+ bool is_in_incognito_window,
+ Browser* browser);
+
+ // Returns the current child view.
+ views::View* GetCurrentView();
+
+ // Handles the event when the user presses a button.
+ void HandleButtonPressed(ButtonID sender_id);
+
+ // Handles the event when the user clicks a link.
+ void HandleLinkClicked(LinkID sender_id);
+
+ // Updates the visibilities of child views according to the current view type.
+ void UpdateChildVisibilities();
+
+ // Creates the 'before translate' view. Caller takes ownership of the returned
+ // view.
+ views::View* CreateViewBeforeTranslate();
+
+ // Creates the 'translating' view. Caller takes ownership of the returned
+ // view.
+ views::View* CreateViewTranslating();
+
+ // Creates the 'after translate' view. Caller takes ownership of the returned
+ // view.
+ views::View* CreateViewAfterTranslate();
+
+ // Creates the 'error' view. Caller takes ownership of the returned view.
+ views::View* CreateViewError();
+
+ // Creates the 'advanced' view. Caller takes ownership of the returned view.
+ views::View* CreateViewAdvanced();
+
+ // Switches the view type.
+ void SwitchView(TranslateBubbleModel::ViewState view_state);
+
+ // Updates the advanced view.
+ void UpdateAdvancedView();
+
+ static TranslateBubbleView* translate_bubble_view_;
+
+ views::View* before_translate_view_;
+ views::View* translating_view_;
+ views::View* after_translate_view_;
+ views::View* error_view_;
+ views::View* advanced_view_;
+
+ scoped_ptr<LanguageComboboxModel> source_language_combobox_model_;
+ scoped_ptr<LanguageComboboxModel> target_language_combobox_model_;
+
+ views::Combobox* source_language_combobox_;
+ views::Combobox* target_language_combobox_;
+ views::Checkbox* always_translate_checkbox_;
+
+ scoped_ptr<TranslateBubbleModel> model_;
+
+ // Whether the window is an incognito window.
+ bool is_in_incognito_window_;
+
+ // The browser to open the help URL into a new tab.
+ Browser* browser_;
+
+ // Whether the translation is acutually executed.
+ bool translate_executed_;
+
+ DISALLOW_COPY_AND_ASSIGN(TranslateBubbleView);
+};
+
+#endif // CHROME_BROWSER_UI_VIEWS_TRANSLATE_TRANSLATE_BUBBLE_VIEW_H_
diff --git a/chrome/browser/ui/views/translate/translate_bubble_view_unittest.cc b/chrome/browser/ui/views/translate/translate_bubble_view_unittest.cc
new file mode 100644
index 0000000000..9082f0698a
--- /dev/null
+++ b/chrome/browser/ui/views/translate/translate_bubble_view_unittest.cc
@@ -0,0 +1,256 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/translate/translate_bubble_view.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/ui/translate/translate_bubble_model.h"
+#include "chrome/browser/ui/translate/translate_bubble_view_state_transition.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/views/controls/button/checkbox.h"
+#include "ui/views/controls/combobox/combobox.h"
+#include "ui/views/test/views_test_base.h"
+#include "ui/views/widget/widget.h"
+
+namespace {
+
+class MockTranslateBubbleModel : public TranslateBubbleModel {
+ public:
+ explicit MockTranslateBubbleModel(TranslateBubbleModel::ViewState view_state)
+ : view_state_transition_(view_state),
+ original_language_index_(0),
+ target_language_index_(1),
+ never_translate_language_(false),
+ never_translate_site_(false),
+ should_always_translate_(false),
+ set_always_translate_called_count_(0),
+ translate_called_(false),
+ revert_translation_called_(false),
+ translation_declined_called_(false) {
+ }
+
+ virtual TranslateBubbleModel::ViewState GetViewState() const OVERRIDE {
+ return view_state_transition_.view_state();
+ }
+
+ virtual void SetViewState(TranslateBubbleModel::ViewState view_state)
+ OVERRIDE {
+ view_state_transition_.SetViewState(view_state);
+ }
+
+ virtual void GoBackFromAdvanced() OVERRIDE {
+ view_state_transition_.GoBackFromAdvanced();
+ }
+
+ virtual int GetNumberOfLanguages() const OVERRIDE {
+ return 1000;
+ }
+
+ virtual string16 GetLanguageNameAt(int index) const OVERRIDE {
+ return string16();
+ }
+
+ virtual int GetOriginalLanguageIndex() const OVERRIDE {
+ return original_language_index_;
+ }
+
+ virtual void SetOriginalLanguageIndex(int index) OVERRIDE {
+ original_language_index_ = index;
+ }
+
+ virtual int GetTargetLanguageIndex() const OVERRIDE {
+ return target_language_index_;
+ }
+
+ virtual void SetTargetLanguageIndex(int index) OVERRIDE {
+ target_language_index_ = index;
+ }
+
+ virtual void SetNeverTranslateLanguage(bool value) OVERRIDE {
+ never_translate_language_ = value;
+ }
+
+ virtual void SetNeverTranslateSite(bool value) OVERRIDE {
+ never_translate_site_ = value;
+ }
+
+ virtual bool ShouldAlwaysTranslate() const OVERRIDE {
+ return should_always_translate_;
+ }
+
+ virtual void SetAlwaysTranslate(bool value) OVERRIDE {
+ should_always_translate_ = value;
+ set_always_translate_called_count_++;
+ }
+
+ virtual void Translate() OVERRIDE {
+ translate_called_ = true;
+ }
+
+ virtual void RevertTranslation() OVERRIDE {
+ revert_translation_called_ = true;
+ }
+
+ virtual void TranslationDeclined() OVERRIDE {
+ translation_declined_called_ = true;
+ }
+
+ TranslateBubbleViewStateTransition view_state_transition_;
+ int original_language_index_;
+ int target_language_index_;
+ bool never_translate_language_;
+ bool never_translate_site_;
+ bool should_always_translate_;
+ int set_always_translate_called_count_;
+ bool translate_called_;
+ bool revert_translation_called_;
+ bool translation_declined_called_;
+};
+
+} // namespace
+
+class TranslateBubbleViewTest : public views::ViewsTestBase {
+ public:
+ TranslateBubbleViewTest() {
+ }
+
+ protected:
+ virtual void SetUp() OVERRIDE {
+ views::ViewsTestBase::SetUp();
+
+ // The bubble needs the parent as an anchor.
+ views::Widget::InitParams params =
+ CreateParams(views::Widget::InitParams::TYPE_WINDOW);
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+
+ anchor_widget_.reset(new views::Widget());
+ anchor_widget_->Init(params);
+ anchor_widget_->Show();
+
+ mock_model_ = new MockTranslateBubbleModel(
+ TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE);
+ scoped_ptr<TranslateBubbleModel> model(mock_model_);
+ bubble_ = new TranslateBubbleView(anchor_widget_->GetContentsView(),
+ model.Pass(),
+ false,
+ NULL);
+ views::BubbleDelegateView::CreateBubble(bubble_)->Show();
+ }
+
+ virtual void TearDown() OVERRIDE {
+ bubble_->GetWidget()->CloseNow();
+ anchor_widget_.reset();
+
+ views::ViewsTestBase::TearDown();
+ }
+
+ scoped_ptr<views::Widget> anchor_widget_;
+ MockTranslateBubbleModel* mock_model_;
+ TranslateBubbleView* bubble_;
+};
+
+TEST_F(TranslateBubbleViewTest, TranslateButton) {
+ EXPECT_FALSE(mock_model_->translate_called_);
+
+ // Press the "Translate" button.
+ bubble_->HandleButtonPressed(TranslateBubbleView::BUTTON_ID_TRANSLATE);
+ EXPECT_TRUE(mock_model_->translate_called_);
+}
+
+TEST_F(TranslateBubbleViewTest, AdvancedLink) {
+ EXPECT_EQ(TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE,
+ bubble_->GetViewState());
+
+ // Click the "Advanced" link.
+ bubble_->HandleLinkClicked(TranslateBubbleView::LINK_ID_ADVANCED);
+ EXPECT_EQ(TranslateBubbleModel::VIEW_STATE_ADVANCED, bubble_->GetViewState());
+}
+
+TEST_F(TranslateBubbleViewTest, ShowOriginalButton) {
+ bubble_->SwitchView(TranslateBubbleModel::VIEW_STATE_AFTER_TRANSLATE);
+
+ // Click the "Show original" button to revert translation.
+ EXPECT_FALSE(mock_model_->revert_translation_called_);
+ bubble_->HandleButtonPressed(TranslateBubbleView::BUTTON_ID_SHOW_ORIGINAL);
+ EXPECT_TRUE(mock_model_->revert_translation_called_);
+}
+
+TEST_F(TranslateBubbleViewTest, TryAgainButton) {
+ bubble_->SwitchView(TranslateBubbleModel::VIEW_STATE_ERROR);
+
+ // Click the "Try again" button to translate.
+ EXPECT_FALSE(mock_model_->translate_called_);
+ bubble_->HandleButtonPressed(TranslateBubbleView::BUTTON_ID_TRY_AGAIN);
+ EXPECT_TRUE(mock_model_->translate_called_);
+}
+
+TEST_F(TranslateBubbleViewTest, AlwaysTranslateCheckbox) {
+ bubble_->SwitchView(TranslateBubbleModel::VIEW_STATE_ADVANCED);
+
+ // Click the "Always Translate" checkbox. Changing the state of this checkbox
+ // should affect the model immediately.
+
+ // Check the initial state.
+ EXPECT_FALSE(mock_model_->should_always_translate_);
+ EXPECT_EQ(0, mock_model_->set_always_translate_called_count_);
+ EXPECT_FALSE(bubble_->always_translate_checkbox_->checked());
+
+ // Click the checkbox.
+ bubble_->always_translate_checkbox_->SetChecked(true);
+ bubble_->HandleButtonPressed(TranslateBubbleView::BUTTON_ID_ALWAYS_TRANSLATE);
+ EXPECT_TRUE(mock_model_->should_always_translate_);
+ EXPECT_EQ(1, mock_model_->set_always_translate_called_count_);
+
+ // Click this again and check the state is reverted.
+ bubble_->always_translate_checkbox_->SetChecked(false);
+ bubble_->HandleButtonPressed(TranslateBubbleView::BUTTON_ID_ALWAYS_TRANSLATE);
+ EXPECT_FALSE(mock_model_->should_always_translate_);
+ EXPECT_EQ(2, mock_model_->set_always_translate_called_count_);
+}
+
+TEST_F(TranslateBubbleViewTest, DoneButton) {
+ bubble_->SwitchView(TranslateBubbleModel::VIEW_STATE_ADVANCED);
+
+ // Click the "Done" button to translate. The selected languages by the user
+ // are applied.
+ EXPECT_FALSE(mock_model_->translate_called_);
+ bubble_->source_language_combobox_->SetSelectedIndex(10);
+ bubble_->target_language_combobox_->SetSelectedIndex(20);
+ bubble_->HandleButtonPressed(TranslateBubbleView::BUTTON_ID_DONE);
+ EXPECT_TRUE(mock_model_->translate_called_);
+ EXPECT_EQ(10, mock_model_->original_language_index_);
+ EXPECT_EQ(20, mock_model_->target_language_index_);
+}
+
+TEST_F(TranslateBubbleViewTest, CancelButtonReturningBeforeTranslate) {
+ bubble_->SwitchView(TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE);
+ bubble_->SwitchView(TranslateBubbleModel::VIEW_STATE_ADVANCED);
+
+ // Click the "Cancel" button to go back.
+ EXPECT_EQ(TranslateBubbleModel::VIEW_STATE_ADVANCED, bubble_->GetViewState());
+ bubble_->HandleButtonPressed(TranslateBubbleView::BUTTON_ID_CANCEL);
+ EXPECT_EQ(TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE,
+ bubble_->GetViewState());
+}
+
+TEST_F(TranslateBubbleViewTest, CancelButtonReturningAfterTranslate) {
+ bubble_->SwitchView(TranslateBubbleModel::VIEW_STATE_AFTER_TRANSLATE);
+ bubble_->SwitchView(TranslateBubbleModel::VIEW_STATE_ADVANCED);
+
+ // Click the "Cancel" button to go back.
+ EXPECT_EQ(TranslateBubbleModel::VIEW_STATE_ADVANCED, bubble_->GetViewState());
+ bubble_->HandleButtonPressed(TranslateBubbleView::BUTTON_ID_CANCEL);
+ EXPECT_EQ(TranslateBubbleModel::VIEW_STATE_AFTER_TRANSLATE,
+ bubble_->GetViewState());
+}
+
+TEST_F(TranslateBubbleViewTest, CancelButtonReturningError) {
+ bubble_->SwitchView(TranslateBubbleModel::VIEW_STATE_ERROR);
+ bubble_->SwitchView(TranslateBubbleModel::VIEW_STATE_ADVANCED);
+
+ // Click the "Cancel" button to go back.
+ EXPECT_EQ(TranslateBubbleModel::VIEW_STATE_ADVANCED, bubble_->GetViewState());
+ bubble_->HandleButtonPressed(TranslateBubbleView::BUTTON_ID_CANCEL);
+ EXPECT_EQ(TranslateBubbleModel::VIEW_STATE_ERROR, bubble_->GetViewState());
+}
diff --git a/chrome/browser/ui/webui/chromeos/diagnostics/diagnostics_ui.cc b/chrome/browser/ui/webui/chromeos/diagnostics/diagnostics_ui.cc
index e891a1622f..2d0ec453d3 100644
--- a/chrome/browser/ui/webui/chromeos/diagnostics/diagnostics_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/diagnostics/diagnostics_ui.cc
@@ -22,8 +22,11 @@ namespace chromeos {
namespace {
+// Key for devices dictionary in JSON returned from GetNetworkStatus.
+const char kDevicesKey[] = "devices";
+
// JS API callback names.
-const char kJsApiSetNetifStatus[] = "diag.DiagPage.setNetifStatus";
+const char kJsApiSetDeviceStatus[] = "diag.DiagPage.setDeviceStatus";
const char kJsApiSetTestICMPStatus[] = "diag.DiagPage.setTestICMPStatus";
////////////////////////////////////////////////////////////////////////////////
@@ -47,11 +50,11 @@ class DiagnosticsWebUIHandler : public content::WebUIMessageHandler {
// Called by JS layer to test ICMP connectivity to a specified host.
void TestICMP(const base::ListValue* args);
- // Called when GetNetworkInterfaces() is complete.
+ // Called when GetNetworkStatus() is complete.
// |succeeded|: information was obtained successfully.
// |status|: network interfaces information in json. See
- // DebugDaemonClient::GetNetworkInterfaces() for details.
- void OnGetNetworkInterfaces(bool succeeded, const std::string& status);
+ // DebugDaemonClient::GetNetworkStatus() for details.
+ void OnGetNetworkStatus(bool succeeded, const std::string& status);
// Called when TestICMP() is complete.
// |succeeded|: information was obtained successfully.
@@ -80,8 +83,8 @@ void DiagnosticsWebUIHandler::GetNetworkInterfaces(
chromeos::DBusThreadManager::Get()->GetDebugDaemonClient();
DCHECK(debugd_client);
- debugd_client->GetNetworkInterfaces(
- base::Bind(&DiagnosticsWebUIHandler::OnGetNetworkInterfaces,
+ debugd_client->GetNetworkStatus(
+ base::Bind(&DiagnosticsWebUIHandler::OnGetNetworkStatus,
weak_ptr_factory_.GetWeakPtr()));
}
@@ -103,7 +106,7 @@ void DiagnosticsWebUIHandler::TestICMP(const base::ListValue* args) {
weak_ptr_factory_.GetWeakPtr()));
}
-void DiagnosticsWebUIHandler::OnGetNetworkInterfaces(
+void DiagnosticsWebUIHandler::OnGetNetworkStatus(
bool succeeded, const std::string& status) {
if (!succeeded)
return;
@@ -111,7 +114,12 @@ void DiagnosticsWebUIHandler::OnGetNetworkInterfaces(
if (parsed_value.get() && parsed_value->IsType(Value::TYPE_DICTIONARY)) {
base::DictionaryValue* result =
static_cast<DictionaryValue*>(parsed_value.get());
- web_ui()->CallJavascriptFunction(kJsApiSetNetifStatus, *result);
+ base::DictionaryValue* devices_info;
+ if (!result->GetDictionary(std::string(kDevicesKey), &devices_info)) {
+ NOTREACHED() <<
+ "Received improperly formatted result from GetNetworkStatus";
+ }
+ web_ui()->CallJavascriptFunction(kJsApiSetDeviceStatus, *devices_info);
}
}
@@ -150,10 +158,10 @@ DiagnosticsUI::DiagnosticsUI(content::WebUI* web_ui)
source->AddLocalizedString("connectivity",
IDS_DIAGNOSTICS_CONNECTIVITY_TITLE);
source->AddLocalizedString("loading", IDS_DIAGNOSTICS_LOADING);
- source->AddLocalizedString("wlan0", IDS_DIAGNOSTICS_ADAPTER_WLAN0);
- source->AddLocalizedString("eth0", IDS_DIAGNOSTICS_ADAPTER_ETH0);
- source->AddLocalizedString("eth1", IDS_DIAGNOSTICS_ADAPTER_ETH1);
- source->AddLocalizedString("wwan0", IDS_DIAGNOSTICS_ADAPTER_WWAN0);
+ source->AddLocalizedString("wifi", IDS_DIAGNOSTICS_ADAPTER_WIFI);
+ source->AddLocalizedString("ethernet1", IDS_DIAGNOSTICS_ADAPTER_ETHERNET1);
+ source->AddLocalizedString("ethernet2", IDS_DIAGNOSTICS_ADAPTER_ETHERNET2);
+ source->AddLocalizedString("3g", IDS_DIAGNOSTICS_ADAPTER_3G);
source->AddLocalizedString("testing-hardware",
IDS_DIAGNOSTICS_TESTING_HARDWARE);
source->AddLocalizedString("testing-connection-to-router",
diff --git a/chrome/browser/ui/webui/chromeos/drive_internals_ui.cc b/chrome/browser/ui/webui/chromeos/drive_internals_ui.cc
index 051437391a..cd009b09df 100644
--- a/chrome/browser/ui/webui/chromeos/drive_internals_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/drive_internals_ui.cc
@@ -52,7 +52,7 @@ namespace {
// Gets metadata of all files and directories in |root_path|
// recursively. Stores the result as a list of dictionaries like:
//
-// [{ path: 'GCache/v1/tmp/<resource_id>',
+// [{ path: 'GCache/v1/tmp/<local_id>',
// size: 12345,
// is_directory: false,
// last_modified: '2005-08-09T09:57:00-08:00',
@@ -130,6 +130,7 @@ std::string FormatEntry(const base::FilePath& path,
std::string out;
StringAppendF(&out, "%s\n", path.AsUTF8Unsafe().c_str());
StringAppendF(&out, " title: %s\n", entry.title().c_str());
+ StringAppendF(&out, " local_id: %s\n", entry.local_id().c_str());
StringAppendF(&out, " resource_id: %s\n", entry.resource_id().c_str());
StringAppendF(&out, " parent_local_id: %s\n",
entry.parent_local_id().c_str());
@@ -159,8 +160,6 @@ std::string FormatEntry(const base::FilePath& path,
if (entry.has_file_specific_info()) {
const drive::FileSpecificInfo& file_specific_info =
entry.file_specific_info();
- StringAppendF(&out, " thumbnail_url: %s\n",
- file_specific_info.thumbnail_url().c_str());
StringAppendF(&out, " alternate_url: %s\n",
file_specific_info.alternate_url().c_str());
StringAppendF(&out, " content_mime_type: %s\n",
@@ -260,7 +259,7 @@ class DriveInternalsWebUIHandler : public content::WebUIMessageHandler {
scoped_ptr<drive::ResourceEntryVector> entries);
// Called as the iterator for DebugInfoCollector::IterateFileCache().
- void UpdateCacheEntry(const std::string& resource_id,
+ void UpdateCacheEntry(const std::string& local_id,
const drive::FileCacheEntry& cache_entry);
// Called when GetFreeDiskSpace() is complete.
@@ -791,13 +790,13 @@ void DriveInternalsWebUIHandler::OnReadDirectoryByPath(
}
void DriveInternalsWebUIHandler::UpdateCacheEntry(
- const std::string& resource_id,
+ const std::string& local_id,
const drive::FileCacheEntry& cache_entry) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
// Convert |cache_entry| into a dictionary.
base::DictionaryValue value;
- value.SetString("resource_id", resource_id);
+ value.SetString("local_id", local_id);
value.SetString("md5", cache_entry.md5());
value.SetBoolean("is_present", cache_entry.is_present());
value.SetBoolean("is_pinned", cache_entry.is_pinned());
diff --git a/chrome/browser/ui/webui/chromeos/imageburner/imageburner_ui.cc b/chrome/browser/ui/webui/chromeos/imageburner/imageburner_ui.cc
index 99125e9e87..08b3146a7e 100644
--- a/chrome/browser/ui/webui/chromeos/imageburner/imageburner_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/imageburner/imageburner_ui.cc
@@ -31,7 +31,6 @@ namespace {
const char kPropertyDevicePath[] = "devicePath";
const char kPropertyFilePath[] = "filePath";
const char kPropertyLabel[] = "label";
-const char kPropertyPath[] = "path";
const char kPropertyDeviceType[] = "type";
// Link displayed on imageburner ui.
diff --git a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
index 70536f75b3..3b256e0a02 100644
--- a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
@@ -37,8 +37,6 @@ const char kGaiaExtStartPage[] =
// Enrollment step names.
const char kEnrollmentStepSignin[] = "signin";
-const char kEnrollmentStepWorking[] = "working";
-const char kEnrollmentStepError[] = "error";
const char kEnrollmentStepSuccess[] = "success";
} // namespace
diff --git a/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc
index cddd932b63..8724a7b9a1 100644
--- a/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc
@@ -27,22 +27,6 @@ const char kJsScreenPath[] = "login.ErrorMessageScreen";
namespace chromeos {
-namespace {
-
-void EnableLazyDetection() {
- NetworkPortalDetector* detector = NetworkPortalDetector::GetInstance();
- if (NetworkPortalDetector::IsEnabledInCommandLine() && detector)
- detector->EnableLazyDetection();
-}
-
-void DisableLazyDetection() {
- NetworkPortalDetector* detector = NetworkPortalDetector::GetInstance();
- if (NetworkPortalDetector::IsEnabledInCommandLine() && detector)
- detector->DisableLazyDetection();
-}
-
-} // namespace
-
ErrorScreenHandler::ErrorScreenHandler(
const scoped_refptr<NetworkStateInformer>& network_state_informer)
: BaseScreenHandler(kJsScreenPath),
@@ -63,7 +47,7 @@ void ErrorScreenHandler::Show(OobeDisplay::Screen parent_screen,
parent_screen_ = parent_screen;
ShowScreen(OobeUI::kScreenErrorMessage, params);
NetworkErrorShown();
- EnableLazyDetection();
+ NetworkPortalDetector::Get()->EnableLazyDetection();
LOG(WARNING) << "Offline message is displayed";
}
@@ -73,7 +57,7 @@ void ErrorScreenHandler::Hide() {
std::string screen_name;
if (GetScreenName(parent_screen_, &screen_name))
ShowScreen(screen_name.c_str(), NULL);
- DisableLazyDetection();
+ NetworkPortalDetector::Get()->DisableLazyDetection();
LOG(WARNING) << "Offline message is hidden";
}
diff --git a/chrome/browser/ui/webui/chromeos/login/locally_managed_user_creation_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/locally_managed_user_creation_screen_handler.cc
index 92ba6b8624..5af0b3f8ab 100644
--- a/chrome/browser/ui/webui/chromeos/login/locally_managed_user_creation_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/locally_managed_user_creation_screen_handler.cc
@@ -7,6 +7,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/chromeos/login/managed/locally_managed_user_creation_flow.h"
+#include "chrome/browser/chromeos/login/supervised_user_manager.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/chromeos/login/wallpaper_manager.h"
#include "chrome/browser/chromeos/settings/cros_settings.h"
@@ -19,16 +20,8 @@
#include "net/base/escape.h"
#include "ui/base/l10n/l10n_util.h"
-namespace {
-
const char kJsScreenPath[] = "login.LocallyManagedUserCreationScreen";
-// Locally managed user creation screen id.
-const char kLocallyManagedUserCreationScreen[] =
- "locally-managed-user-creation";
-
-} // namespace
-
namespace chromeos {
LocallyManagedUserCreationScreenHandler::
@@ -115,6 +108,21 @@ void LocallyManagedUserCreationScreenHandler::DeclareLocalizedValues(
builder->Add("createManagedUserCreatedText3",
IDS_CREATE_LOCALLY_MANAGED_USER_CREATED_1_TEXT_3);
+ builder->Add("importExistingSupervisedUserTitle",
+ IDS_IMPORT_EXISTING_MANAGED_USER_TITLE);
+ builder->Add("importExistingSupervisedUserText",
+ IDS_IMPORT_EXISTING_MANAGED_USER_TEXT);
+ builder->Add("managedUserCreationFlowImportButtonTitle",
+ IDS_IMPORT_EXISTING_MANAGED_USER_OK);
+ builder->Add("importSupervisedUserLink",
+ IDS_PROFILES_IMPORT_EXISTING_MANAGED_USER_LINK);
+ builder->Add("createSupervisedUserLink",
+ IDS_CREATE_NEW_USER_LINK);
+ builder->Add("importBubbleText", IDS_SUPERVISED_USER_IMPORT_BUBBLE_TEXT);
+ builder->Add("importUserExists", IDS_SUPERVISED_USER_IMPORT_USER_EXIST);
+ builder->Add("importUsernameExists",
+ IDS_SUPERVISED_USER_IMPORT_USERNAME_EXIST);
+
builder->Add("managementURL", chrome::kSupervisedUserManagementDisplayURL);
// TODO(antrim) : this is an explicit code duplications with UserImageScreen.
@@ -145,6 +153,13 @@ void LocallyManagedUserCreationScreenHandler::RegisterMessages() {
AddCallback("managerSelectedOnLocallyManagedUserCreationFlow",
&LocallyManagedUserCreationScreenHandler::
HandleManagerSelected);
+ AddCallback("userSelectedForImportInManagedUserCreationFlow",
+ &LocallyManagedUserCreationScreenHandler::
+ HandleImportUserSelected);
+ AddCallback("importSupervisedUser",
+ &LocallyManagedUserCreationScreenHandler::
+ HandleImportSupervisedUser);
+
// TODO(antrim) : this is an explicit code duplications with UserImageScreen.
// It should be removed by issue 251179.
@@ -244,10 +259,17 @@ void LocallyManagedUserCreationScreenHandler::HandleManagerSelected(
WallpaperManager::Get()->SetUserWallpaper(manager_id);
}
+void LocallyManagedUserCreationScreenHandler::HandleImportUserSelected(
+ const std::string& user_id) {
+ if (!delegate_)
+ return;
+}
+
void LocallyManagedUserCreationScreenHandler::HandleCheckLocallyManagedUserName(
const string16& name) {
- if (NULL != UserManager::Get()->
- FindLocallyManagedUser(CollapseWhitespace(name, true))) {
+ std::string user_id;
+ if (NULL != UserManager::Get()->GetSupervisedUserManager()->
+ FindByDisplayName(CollapseWhitespace(name, true))) {
CallJS("managedUserNameError", name,
l10n_util::GetStringUTF16(
IDS_CREATE_LOCALLY_MANAGED_USER_CREATE_USERNAME_ALREADY_EXISTS));
@@ -255,6 +277,9 @@ void LocallyManagedUserCreationScreenHandler::HandleCheckLocallyManagedUserName(
CallJS("managedUserNameError", name,
l10n_util::GetStringUTF16(
IDS_CREATE_LOCALLY_MANAGED_USER_CREATE_ILLEGAL_USERNAME));
+ } else if (delegate_ && delegate_->FindUserByDisplayName(
+ CollapseWhitespace(name, true), &user_id)) {
+ CallJS("managedUserSuggestImport", name, user_id);
} else {
CallJS("managedUserNameOk", name);
}
@@ -266,7 +291,8 @@ void LocallyManagedUserCreationScreenHandler::HandleCreateManagedUser(
if (!delegate_)
return;
const string16 new_user_name = CollapseWhitespace(new_raw_user_name, true);
- if (NULL != UserManager::Get()->FindLocallyManagedUser(new_user_name)) {
+ if (NULL != UserManager::Get()->GetSupervisedUserManager()->
+ FindByDisplayName(new_user_name)) {
CallJS("managedUserNameError", new_user_name,
l10n_util::GetStringFUTF16(
IDS_CREATE_LOCALLY_MANAGED_USER_CREATE_USERNAME_ALREADY_EXISTS,
@@ -293,6 +319,17 @@ void LocallyManagedUserCreationScreenHandler::HandleCreateManagedUser(
delegate_->CreateManagedUser(new_user_name, new_user_password);
}
+void LocallyManagedUserCreationScreenHandler::HandleImportSupervisedUser(
+ const std::string& user_id) {
+ if (!delegate_)
+ return;
+
+ ShowStatusMessage(true /* progress */, l10n_util::GetStringUTF16(
+ IDS_CREATE_LOCALLY_MANAGED_USER_CREATION_CREATION_PROGRESS_MESSAGE));
+
+ delegate_->ImportManagedUser(user_id);
+}
+
void LocallyManagedUserCreationScreenHandler::HandleAuthenticateManager(
const std::string& raw_manager_username,
const std::string& manager_password) {
@@ -361,4 +398,9 @@ void LocallyManagedUserCreationScreenHandler::SetCameraPresent(bool present) {
CallJS("setCameraPresent", present);
}
+void LocallyManagedUserCreationScreenHandler::ShowExistingManagedUsers(
+ const base::ListValue* users) {
+ CallJS("setExistingManagedUsers", *users);
+}
+
} // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/login/locally_managed_user_creation_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/locally_managed_user_creation_screen_handler.h
index 2d0bf73d62..f39c93e577 100644
--- a/chrome/browser/ui/webui/chromeos/login/locally_managed_user_creation_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/locally_managed_user_creation_screen_handler.h
@@ -14,7 +14,7 @@
#include "content/public/browser/web_ui.h"
namespace base {
-class DictionaryValue;
+class ListValue;
}
namespace chromeos {
@@ -35,13 +35,21 @@ class LocallyManagedUserCreationScreenHandler : public BaseScreenHandler {
virtual void AuthenticateManager(const std::string& manager_id,
const std::string& manager_password) = 0;
- // Starts managed user creation flow, with manager identified by
- // |manager_id| and |manager_password|, and locally managed user that would
- // have |display_name| and authenticated by the |managed_user_password|.
+ // Starts managed user creation flow, with supervised user that would have
+ // |display_name| and authenticated by the |managed_user_password|.
virtual void CreateManagedUser(
const string16& display_name,
const std::string& managed_user_password) = 0;
+ // Look up if user with name |display_name| already exist and can be
+ // imported. Returns user ID in |out_id|. Returns true if user was found,
+ // false otherwise.
+ virtual bool FindUserByDisplayName(const string16& display_name,
+ std::string *out_id) const = 0;
+
+ // Starts managed user import flow for user identified with |user_id|.
+ virtual void ImportManagedUser(const std::string& user_id) = 0;
+
virtual void AbortFlow() = 0;
virtual void FinishFlow() = 0;
@@ -81,6 +89,8 @@ class LocallyManagedUserCreationScreenHandler : public BaseScreenHandler {
void SetCameraPresent(bool enabled);
+ void ShowExistingManagedUsers(const base::ListValue* users);
+
// BaseScreenHandler implementation:
virtual void DeclareLocalizedValues(LocalizedValuesBuilder* builder) OVERRIDE;
virtual void Initialize() OVERRIDE;
@@ -93,6 +103,7 @@ class LocallyManagedUserCreationScreenHandler : public BaseScreenHandler {
void HandleCheckLocallyManagedUserName(const string16& name);
void HandleManagerSelected(const std::string& manager_id);
+ void HandleImportUserSelected(const std::string& user_id);
void HandleFinishLocalManagedUserCreation();
void HandleAbortLocalManagedUserCreation();
@@ -103,6 +114,7 @@ class LocallyManagedUserCreationScreenHandler : public BaseScreenHandler {
const std::string& manager_password);
void HandleCreateManagedUser(const string16& new_raw_user_name,
const std::string& new_user_password);
+ void HandleImportSupervisedUser(const std::string& user_id);
void HandleGetImages();
void HandlePhotoTaken(const std::string& image_url);
diff --git a/chrome/browser/ui/webui/chromeos/login/network_state_informer.cc b/chrome/browser/ui/webui/chromeos/login/network_state_informer.cc
index a7381db48e..115f5451bc 100644
--- a/chrome/browser/ui/webui/chromeos/login/network_state_informer.cc
+++ b/chrome/browser/ui/webui/chromeos/login/network_state_informer.cc
@@ -41,10 +41,9 @@ NetworkStateInformer::State GetStateForDefaultNetwork() {
if (!network)
return NetworkStateInformer::OFFLINE;
- if (NetworkPortalDetector::IsEnabledInCommandLine() &&
- NetworkPortalDetector::GetInstance()) {
+ if (NetworkPortalDetector::Get()->IsEnabled()) {
NetworkPortalDetector::CaptivePortalState state =
- NetworkPortalDetector::GetInstance()->GetCaptivePortalState(network);
+ NetworkPortalDetector::Get()->GetCaptivePortalState(network);
NetworkPortalDetector::CaptivePortalStatus status = state.status;
if (status == NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN &&
NetworkState::StateIsConnecting(network->connection_state())) {
@@ -90,10 +89,7 @@ NetworkStateInformer::~NetworkStateInformer() {
NetworkHandler::Get()->network_state_handler()->RemoveObserver(
this, FROM_HERE);
}
- if (NetworkPortalDetector::IsEnabledInCommandLine() &&
- NetworkPortalDetector::GetInstance()) {
- NetworkPortalDetector::GetInstance()->RemoveObserver(this);
- }
+ NetworkPortalDetector::Get()->RemoveObserver(this);
}
void NetworkStateInformer::Init() {
@@ -101,10 +97,7 @@ void NetworkStateInformer::Init() {
NetworkHandler::Get()->network_state_handler()->AddObserver(
this, FROM_HERE);
- if (NetworkPortalDetector::IsEnabledInCommandLine() &&
- NetworkPortalDetector::GetInstance()) {
- NetworkPortalDetector::GetInstance()->AddAndFireObserver(this);
- }
+ NetworkPortalDetector::Get()->AddAndFireObserver(this);
registrar_.Add(this,
chrome::NOTIFICATION_LOGIN_PROXY_CHANGED,
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
index 9a85f0a86f..1d65c13cd7 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
@@ -240,7 +240,7 @@ std::string GetNetworkName(const std::string& service_path) {
// Returns captive portal state for a network by its service path.
NetworkPortalDetector::CaptivePortalState GetCaptivePortalState(
const std::string& service_path) {
- NetworkPortalDetector* detector = NetworkPortalDetector::GetInstance();
+ NetworkPortalDetector* detector = NetworkPortalDetector::Get();
const NetworkState* network = NetworkHandler::Get()->network_state_handler()->
GetNetworkState(service_path);
if (!detector || !network)
diff --git a/chrome/browser/ui/webui/chromeos/mobile_setup_ui.cc b/chrome/browser/ui/webui/chromeos/mobile_setup_ui.cc
index 6a8bf23ca3..c9bc8d7338 100644
--- a/chrome/browser/ui/webui/chromeos/mobile_setup_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/mobile_setup_ui.cc
@@ -33,7 +33,6 @@
#include "chromeos/network/network_state_handler.h"
#include "chromeos/network/network_state_handler_observer.h"
#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/render_view_host_observer.h"
#include "content/public/browser/url_data_source.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui.h"
@@ -132,51 +131,6 @@ void GetDeviceInfo(const DictionaryValue& properties, DictionaryValue* value) {
} // namespace
-// Observes IPC messages from the rederer and notifies JS if frame loading error
-// appears.
-class PortalFrameLoadObserver : public content::RenderViewHostObserver {
- public:
- PortalFrameLoadObserver(const base::WeakPtr<MobileSetupUI>& parent,
- RenderViewHost* host)
- : content::RenderViewHostObserver(host), parent_(parent) {
- Send(new ChromeViewMsg_StartFrameSniffer(routing_id(),
- UTF8ToUTF16("paymentForm")));
- }
-
- // IPC::Listener implementation.
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(PortalFrameLoadObserver, message)
- IPC_MESSAGE_HANDLER(ChromeViewHostMsg_FrameLoadingError, OnFrameLoadError)
- IPC_MESSAGE_HANDLER(ChromeViewHostMsg_FrameLoadingCompleted,
- OnFrameLoadCompleted)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
- }
-
- private:
- void OnFrameLoadError(int error) {
- if (!parent_.get())
- return;
-
- base::FundamentalValue result_value(error);
- parent_->web_ui()->CallJavascriptFunction(kJsPortalFrameLoadFailedCallback,
- result_value);
- }
-
- void OnFrameLoadCompleted() {
- if (!parent_.get())
- return;
-
- parent_->web_ui()->CallJavascriptFunction(
- kJsPortalFrameLoadCompletedCallback);
- }
-
- base::WeakPtr<MobileSetupUI> parent_;
- DISALLOW_COPY_AND_ASSIGN(PortalFrameLoadObserver);
-};
-
class MobileSetupUIHTMLSource : public content::URLDataSource {
public:
MobileSetupUIHTMLSource();
@@ -661,9 +615,36 @@ MobileSetupUI::MobileSetupUI(content::WebUI* web_ui)
// Set up the chrome://mobilesetup/ source.
Profile* profile = Profile::FromWebUI(web_ui);
content::URLDataSource::Add(profile, html_source);
+
+ content::WebContentsObserver::Observe(web_ui->GetWebContents());
+}
+
+void MobileSetupUI::DidCommitProvisionalLoadForFrame(
+ int64 frame_id,
+ const string16& frame_unique_name,
+ bool is_main_frame,
+ const GURL& url,
+ content::PageTransition transition_type,
+ content::RenderViewHost* render_view_host) {
+ if (frame_unique_name != UTF8ToUTF16("paymentForm"))
+ return;
+
+ web_ui()->CallJavascriptFunction(
+ kJsPortalFrameLoadCompletedCallback);
}
-void MobileSetupUI::RenderViewCreated(RenderViewHost* host) {
- // Destroyed by the corresponding RenderViewHost
- new PortalFrameLoadObserver(AsWeakPtr(), host);
+void MobileSetupUI::DidFailProvisionalLoad(
+ int64 frame_id,
+ const string16& frame_unique_name,
+ bool is_main_frame,
+ const GURL& validated_url,
+ int error_code,
+ const string16& error_description,
+ content::RenderViewHost* render_view_host) {
+ if (frame_unique_name != UTF8ToUTF16("paymentForm"))
+ return;
+
+ base::FundamentalValue result_value(-error_code);
+ web_ui()->CallJavascriptFunction(kJsPortalFrameLoadFailedCallback,
+ result_value);
}
diff --git a/chrome/browser/ui/webui/chromeos/mobile_setup_ui.h b/chrome/browser/ui/webui/chromeos/mobile_setup_ui.h
index b16ce7e16d..336d2fd993 100644
--- a/chrome/browser/ui/webui/chromeos/mobile_setup_ui.h
+++ b/chrome/browser/ui/webui/chromeos/mobile_setup_ui.h
@@ -6,18 +6,33 @@
#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_MOBILE_SETUP_UI_H_
#include "base/memory/weak_ptr.h"
+#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_ui_controller.h"
// A custom WebUI that defines datasource for mobile setup registration page
// that is used in Chrome OS activate modem and perform plan subscription tasks.
class MobileSetupUI : public content::WebUIController,
+ public content::WebContentsObserver,
public base::SupportsWeakPtr<MobileSetupUI> {
public:
explicit MobileSetupUI(content::WebUI* web_ui);
private:
- // WebUIController overrides.
- virtual void RenderViewCreated(
+ // content::WebContentsObserver overrides.
+ virtual void DidCommitProvisionalLoadForFrame(
+ int64 frame_id,
+ const string16& frame_unique_name,
+ bool is_main_frame,
+ const GURL& url,
+ content::PageTransition transition_type,
+ content::RenderViewHost* render_view_host) OVERRIDE;
+ virtual void DidFailProvisionalLoad(
+ int64 frame_id,
+ const string16& frame_unique_name,
+ bool is_main_frame,
+ const GURL& validated_url,
+ int error_code,
+ const string16& error_description,
content::RenderViewHost* render_view_host) OVERRIDE;
DISALLOW_COPY_AND_ASSIGN(MobileSetupUI);
diff --git a/chrome/browser/ui/webui/chromeos/network_ui.cc b/chrome/browser/ui/webui/chromeos/network_ui.cc
index 4478131e26..42c391f250 100644
--- a/chrome/browser/ui/webui/chromeos/network_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/network_ui.cc
@@ -30,7 +30,6 @@ const char kRequestNetworkInfoCallback[] = "requestNetworkInfo";
const char kNetworkEventLogTag[] = "networkEventLog";
const char kNetworkStateTag[] = "networkState";
const char kOnNetworkInfoReceivedFunction[] = "NetworkUI.onNetworkInfoReceived";
-const char kLevelDebugTag[] = "Debug";
class NetworkMessageHandler : public content::WebUIMessageHandler {
public:
diff --git a/chrome/browser/ui/webui/chromeos/sim_unlock_ui.cc b/chrome/browser/ui/webui/chromeos/sim_unlock_ui.cc
index e46177aed4..3a804010a3 100644
--- a/chrome/browser/ui/webui/chromeos/sim_unlock_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/sim_unlock_ui.cc
@@ -64,7 +64,6 @@ const char kTriesLeft[] = "tries";
// Error constants, passed to the page.
const char kErrorPin[] = "incorrectPin";
-const char kErrorPuk[] = "incorrectPuk";
const char kErrorOk[] = "ok";
chromeos::NetworkDeviceHandler* GetNetworkDeviceHandler() {
diff --git a/chrome/browser/ui/webui/devtools_ui.cc b/chrome/browser/ui/webui/devtools_ui.cc
index 0a71d19a72..f75527214f 100644
--- a/chrome/browser/ui/webui/devtools_ui.cc
+++ b/chrome/browser/ui/webui/devtools_ui.cc
@@ -40,10 +40,15 @@ const char kHttpNotFound[] = "HTTP/1.1 404 Not Found\n\n";
#if defined(DEBUG_DEVTOOLS)
// Local frontend url provided by InspectUI.
-const char kLocalFrontendURL[] =
+const char kFallbackFrontendURL[] =
"chrome-devtools://devtools/bundled/devtools.html";
+#else
+// URL causing the DevTools window to display a plain text warning.
+const char kFallbackFrontendURL[] =
+ "data:text/plain,Cannot load DevTools frontend from an untrusted origin";
#endif // defined(DEBUG_DEVTOOLS)
+
class FetchRequest : public net::URLFetcherDelegate {
public:
FetchRequest(net::URLRequestContextGetter* request_context,
@@ -190,13 +195,9 @@ class DevToolsDataSource : public content::URLDataSource {
// static
GURL DevToolsUI::GetProxyURL(const std::string& frontend_url) {
GURL url(frontend_url);
-#if defined(DEBUG_DEVTOOLS)
if (!url.is_valid() || url.host() != kRemoteFrontendDomain) {
- return GURL(kLocalFrontendURL);
+ return GURL(kFallbackFrontendURL);
}
-#endif // defined(DEBUG_DEVTOOLS)
- CHECK(url.is_valid());
- CHECK_EQ(url.host(), kRemoteFrontendDomain);
return GURL(base::StringPrintf("%s://%s/%s/%s",
chrome::kChromeDevToolsScheme,
chrome::kChromeUIDevToolsHost,
diff --git a/chrome/browser/ui/webui/downloads_dom_handler.cc b/chrome/browser/ui/webui/downloads_dom_handler.cc
index 562856f646..f964d84566 100644
--- a/chrome/browser/ui/webui/downloads_dom_handler.cc
+++ b/chrome/browser/ui/webui/downloads_dom_handler.cc
@@ -24,7 +24,6 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/download/download_crx_util.h"
#include "chrome/browser/download/download_danger_prompt.h"
-#include "chrome/browser/download/download_field_trial.h"
#include "chrome/browser/download/download_history.h"
#include "chrome/browser/download/download_item_model.h"
#include "chrome/browser/download/download_prefs.h"
@@ -182,29 +181,14 @@ DictionaryValue* CreateDownloadItemValue(
content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST ||
download_item->GetDangerType() ==
content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED);
- std::string trial_condition =
- base::FieldTrialList::FindFullName(kMalwareWarningFinchTrialName);
const char* danger_type_value =
GetDangerTypeString(download_item->GetDangerType());
file_value->SetString("danger_type", danger_type_value);
- if (!trial_condition.empty()) {
- base::string16 finch_string;
- content::DownloadDangerType danger_type =
- download_item->GetDangerType();
- if (danger_type == content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL ||
- danger_type == content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT ||
- danger_type == content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST) {
- finch_string =
- AssembleMalwareFinchString(trial_condition, file_name);
- }
- file_value->SetString("finch_string", finch_string);
- }
} else if (download_item->IsPaused()) {
file_value->SetString("state", "PAUSED");
} else {
file_value->SetString("state", "IN_PROGRESS");
}
-
file_value->SetString("progress_status_text",
download_model.GetTabProgressStatusText());
diff --git a/chrome/browser/ui/webui/downloads_ui.cc b/chrome/browser/ui/webui/downloads_ui.cc
index 6b71ca3fe5..5a88c51d1a 100644
--- a/chrome/browser/ui/webui/downloads_ui.cc
+++ b/chrome/browser/ui/webui/downloads_ui.cc
@@ -63,6 +63,7 @@ content::WebUIDataSource* CreateDownloadsUIHTMLSource(Profile* profile) {
source->AddLocalizedString("danger_potentially_unwanted_desc",
IDS_PROMPT_DOWNLOAD_CHANGES_SEARCH_SETTINGS);
source->AddLocalizedString("danger_save", IDS_CONFIRM_DOWNLOAD);
+ source->AddLocalizedString("danger_restore", IDS_CONFIRM_DOWNLOAD_RESTORE);
source->AddLocalizedString("danger_discard", IDS_DISCARD_DOWNLOAD);
// Controls.
diff --git a/chrome/browser/ui/webui/downloads_ui_browsertest.cc b/chrome/browser/ui/webui/downloads_ui_browsertest.cc
index 1abeb5ecaf..41958640a3 100644
--- a/chrome/browser/ui/webui/downloads_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/downloads_ui_browsertest.cc
@@ -4,27 +4,26 @@
#include "chrome/browser/ui/webui/downloads_ui_browsertest.h"
+#include "base/command_line.h"
#include "base/prefs/pref_service.h"
#include "chrome/browser/managed_mode/managed_user_service.h"
#include "chrome/browser/managed_mode/managed_user_service_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "content/public/test/test_utils.h"
-DownloadsUIBrowserTest::DownloadsUIBrowserTest() {
-}
+DownloadsUIBrowserTest::DownloadsUIBrowserTest() {}
-DownloadsUIBrowserTest::~DownloadsUIBrowserTest() {
-}
+DownloadsUIBrowserTest::~DownloadsUIBrowserTest() {}
void DownloadsUIBrowserTest::SetDeleteAllowed(bool allowed) {
browser()->profile()->GetPrefs()->
SetBoolean(prefs::kAllowDeletingBrowserHistory, allowed);
}
-void DownloadsUIBrowserTest::ChangeProfileToSupervised() {
- ManagedUserServiceFactory::GetForProfile(
- browser()->profile())->InitForTesting();
- content::RunAllPendingInMessageLoop();
+void DownloadsWebUIForSupervisedUsersTest::SetUpCommandLine(
+ CommandLine* command_line) {
+ command_line->AppendSwitch(switches::kNewProfileIsSupervised);
}
diff --git a/chrome/browser/ui/webui/downloads_ui_browsertest.h b/chrome/browser/ui/webui/downloads_ui_browsertest.h
index f5370c8392..d38ee1e9cb 100644
--- a/chrome/browser/ui/webui/downloads_ui_browsertest.h
+++ b/chrome/browser/ui/webui/downloads_ui_browsertest.h
@@ -17,10 +17,14 @@ class DownloadsUIBrowserTest : public WebUIBrowserTest {
// Sets the pref to allow or prohibit deleting history entries.
void SetDeleteAllowed(bool allowed);
- void ChangeProfileToSupervised();
-
private:
DISALLOW_COPY_AND_ASSIGN(DownloadsUIBrowserTest);
};
+class DownloadsWebUIForSupervisedUsersTest : public DownloadsUIBrowserTest {
+ public:
+ // InProcessBrowserTest overrides:
+ virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE;
+};
+
#endif // CHROME_BROWSER_UI_WEBUI_DOWNLOADS_UI_BROWSERTEST_H_
diff --git a/chrome/browser/ui/webui/downloads_ui_browsertest.js b/chrome/browser/ui/webui/downloads_ui_browsertest.js
index c55ca6f614..f4e43c82f4 100644
--- a/chrome/browser/ui/webui/downloads_ui_browsertest.js
+++ b/chrome/browser/ui/webui/downloads_ui_browsertest.js
@@ -171,9 +171,7 @@ DownloadsWebUIForSupervisedUsersTest.prototype = {
__proto__: BaseDownloadsWebUITest.prototype,
/** @override */
- testGenPreamble: function() {
- GEN(' ChangeProfileToSupervised();');
- },
+ typedefCppFixture: 'DownloadsWebUIForSupervisedUsersTest',
};
// Test UI for supervised users, removing entries should be disabled
diff --git a/chrome/browser/ui/webui/extensions/command_handler.cc b/chrome/browser/ui/webui/extensions/command_handler.cc
index f89634c501..6086dc0679 100644
--- a/chrome/browser/ui/webui/extensions/command_handler.cc
+++ b/chrome/browser/ui/webui/extensions/command_handler.cc
@@ -37,6 +37,12 @@ void CommandHandler::GetLocalizedValues(content::WebUIDataSource* source) {
l10n_util::GetStringUTF16(IDS_EXTENSION_TYPE_SHORTCUT));
source->AddString("extensionCommandsDelete",
l10n_util::GetStringUTF16(IDS_EXTENSION_DELETE_SHORTCUT));
+ source->AddString("extensionCommandsGlobalTooltip",
+ l10n_util::GetStringUTF16(IDS_EXTENSION_COMMANDS_GLOBAL));
+ source->AddString("extensionCommandsNotGlobalTooltip",
+ l10n_util::GetStringUTF16(IDS_EXTENSION_COMMANDS_NOT_GLOBAL));
+ source->AddString("extensionCommandsNotGlobalPermanentTooltip",
+ l10n_util::GetStringUTF16(IDS_EXTENSION_COMMANDS_NOT_GLOBAL_PERMANENT));
source->AddString("ok", l10n_util::GetStringUTF16(IDS_OK));
}
@@ -55,6 +61,9 @@ void CommandHandler::RegisterMessages() {
web_ui()->RegisterMessageCallback("setExtensionCommandShortcut",
base::Bind(&CommandHandler::HandleSetExtensionCommandShortcut,
base::Unretained(this)));
+ web_ui()->RegisterMessageCallback("toggleCommandScope",
+ base::Bind(&CommandHandler::HandleToggleCommandScope,
+ base::Unretained(this)));
}
void CommandHandler::Observe(
@@ -96,6 +105,23 @@ void CommandHandler::HandleSetExtensionCommandShortcut(
UpdateCommandDataOnPage();
}
+void CommandHandler::HandleToggleCommandScope(
+ const base::ListValue* args) {
+ std::string extension_id;
+ std::string command_name;
+ if (!args->GetString(0, &extension_id) ||
+ !args->GetString(1, &command_name)) {
+ NOTREACHED();
+ return;
+ }
+
+ Profile* profile = Profile::FromWebUI(web_ui());
+ CommandService* command_service = CommandService::Get(profile);
+ command_service->ToggleScope(extension_id, command_name);
+
+ UpdateCommandDataOnPage();
+}
+
void CommandHandler::HandleSetShortcutHandlingSuspended(const ListValue* args) {
bool suspended;
if (args->GetBoolean(0, &suspended))
@@ -153,9 +179,10 @@ void CommandHandler::GetAllCommands(base::DictionaryValue* commands) {
&named_commands)) {
for (extensions::CommandMap::const_iterator iter = named_commands.begin();
iter != named_commands.end(); ++iter) {
- ui::Accelerator shortcut_assigned =
- command_service->FindShortcutForCommand(
+ extensions::Command command = command_service->FindCommandByName(
(*extension)->id(), iter->second.command_name());
+ ui::Accelerator shortcut_assigned = command.accelerator();
+
active = (shortcut_assigned.key_code() != ui::VKEY_UNKNOWN);
extensions_list->Append(
diff --git a/chrome/browser/ui/webui/extensions/command_handler.h b/chrome/browser/ui/webui/extensions/command_handler.h
index 0b43f1a2df..69f869a5bb 100644
--- a/chrome/browser/ui/webui/extensions/command_handler.h
+++ b/chrome/browser/ui/webui/extensions/command_handler.h
@@ -60,6 +60,10 @@ class CommandHandler : public content::WebUIMessageHandler,
// for a given extension command.
void HandleSetExtensionCommandShortcut(const base::ListValue* args);
+ // Handles requests from javascript to change the scope of a particular
+ // keyboard shortcut for a given extension command.
+ void HandleToggleCommandScope(const base::ListValue* args);
+
// Handles requests from javascript to temporarily disable general Chrome
// shortcut handling while the web page is capturing which shortcut to use.
void HandleSetShortcutHandlingSuspended(const base::ListValue* args);
diff --git a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc
new file mode 100644
index 0000000000..612d8fbe6a
--- /dev/null
+++ b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc
@@ -0,0 +1,130 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/extensions/extension_settings_browsertest.h"
+
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "base/strings/string_number_conversions.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/extensions/crx_installer.h"
+#include "chrome/browser/extensions/extension_error_reporter.h"
+#include "chrome/browser/extensions/extension_install_prompt.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/unpacked_installer.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/chrome_paths.h"
+#include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/test_utils.h"
+
+using extensions::Extension;
+
+ExtensionSettingsUIBrowserTest::ExtensionSettingsUIBrowserTest()
+ : profile_(NULL) {}
+
+ExtensionSettingsUIBrowserTest::~ExtensionSettingsUIBrowserTest() {}
+
+Profile* ExtensionSettingsUIBrowserTest::GetProfile() {
+ if (!profile_) {
+ profile_ =
+ browser() ? browser()->profile() : ProfileManager::GetDefaultProfile();
+ }
+ return profile_;
+}
+
+void ExtensionSettingsUIBrowserTest::SetUpOnMainThread() {
+ WebUIBrowserTest::SetUpOnMainThread();
+ observer_.reset(new ExtensionTestNotificationObserver(browser()));
+}
+
+void ExtensionSettingsUIBrowserTest::InstallGoodExtension() {
+ base::FilePath test_data_dir;
+ if (!PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir)) {
+ ADD_FAILURE();
+ return;
+ }
+ base::FilePath extensions_data_dir = test_data_dir.AppendASCII("extensions");
+ InstallExtension(extensions_data_dir.AppendASCII("good.crx"));
+}
+
+class MockAutoConfirmExtensionInstallPrompt : public ExtensionInstallPrompt {
+ public:
+ explicit MockAutoConfirmExtensionInstallPrompt(
+ content::WebContents* web_contents)
+ : ExtensionInstallPrompt(web_contents) {}
+
+ // Proceed without confirmation prompt.
+ virtual void ConfirmInstall(
+ Delegate* delegate,
+ const Extension* extension,
+ const ShowDialogCallback& show_dialog_callback) OVERRIDE {
+ delegate->InstallUIProceed();
+ }
+};
+
+const Extension* ExtensionSettingsUIBrowserTest::InstallExtension(
+ const base::FilePath& path) {
+ Profile* profile = this->GetProfile();
+ ExtensionService* service = profile->GetExtensionService();
+ service->set_show_extensions_prompts(false);
+ size_t num_before = service->extensions()->size();
+ {
+ scoped_ptr<ExtensionInstallPrompt> install_ui;
+ install_ui.reset(new MockAutoConfirmExtensionInstallPrompt(
+ browser()->tab_strip_model()->GetActiveWebContents()));
+
+ base::FilePath crx_path = path;
+ DCHECK(crx_path.Extension() == FILE_PATH_LITERAL(".crx"));
+ if (crx_path.empty())
+ return NULL;
+
+ scoped_refptr<extensions::CrxInstaller> installer(
+ extensions::CrxInstaller::Create(service, install_ui.Pass()));
+ installer->set_expected_id(std::string());
+ installer->set_is_gallery_install(false);
+ installer->set_install_source(extensions::Manifest::INTERNAL);
+ installer->set_install_wait_for_idle(false);
+ installer->set_off_store_install_allow_reason(
+ extensions::CrxInstaller::OffStoreInstallAllowedInTest);
+
+ observer_->Watch(
+ chrome::NOTIFICATION_CRX_INSTALLER_DONE,
+ content::Source<extensions::CrxInstaller>(installer.get()));
+
+ installer->InstallCrx(crx_path);
+
+ observer_->Wait();
+ }
+
+ size_t num_after = service->extensions()->size();
+ if (num_before + 1 != num_after) {
+ VLOG(1) << "Num extensions before: " << base::IntToString(num_before)
+ << " num after: " << base::IntToString(num_after)
+ << " Installed extensions follow:";
+
+ for (ExtensionSet::const_iterator it = service->extensions()->begin();
+ it != service->extensions()->end(); ++it)
+ VLOG(1) << " " << (*it)->id();
+
+ VLOG(1) << "Errors follow:";
+ const std::vector<string16>* errors =
+ ExtensionErrorReporter::GetInstance()->GetErrors();
+ for (std::vector<string16>::const_iterator iter = errors->begin();
+ iter != errors->end(); ++iter)
+ VLOG(1) << *iter;
+
+ return NULL;
+ }
+
+ if (!observer_->WaitForExtensionViewsToLoad())
+ return NULL;
+ return service->GetExtensionById(last_loaded_extension_id(), false);
+}
diff --git a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.h b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.h
new file mode 100644
index 0000000000..14edcd58d4
--- /dev/null
+++ b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.h
@@ -0,0 +1,46 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_EXTENSIONS_EXTENSION_SETTINGS_BROWSERTEST_H_
+#define CHROME_BROWSER_UI_WEBUI_EXTENSIONS_EXTENSION_SETTINGS_BROWSERTEST_H_
+
+#include "chrome/browser/extensions/extension_test_notification_observer.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/test/base/web_ui_browsertest.h"
+
+class Profile;
+
+// C++ test fixture used by extension_settings_browsertest.js.
+class ExtensionSettingsUIBrowserTest : public WebUIBrowserTest {
+ public:
+ ExtensionSettingsUIBrowserTest();
+ virtual ~ExtensionSettingsUIBrowserTest();
+
+ protected:
+ // Get the profile to use.
+ Profile* GetProfile();
+
+ const std::string& last_loaded_extension_id() {
+ return observer_->last_loaded_extension_id();
+ }
+
+ virtual void SetUpOnMainThread() OVERRIDE;
+
+ void InstallGoodExtension();
+
+ private:
+ bool WaitForExtensionViewsToLoad();
+ const extensions::Extension* LoadUnpackedExtension(
+ const base::FilePath& path);
+ const extensions::Extension* InstallExtension(const base::FilePath& path);
+
+ scoped_ptr<ExtensionTestNotificationObserver> observer_;
+
+ // The default profile to be used.
+ Profile* profile_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExtensionSettingsUIBrowserTest);
+};
+
+#endif // CHROME_BROWSER_UI_WEBUI_EXTENSIONS_EXTENSION_SETTINGS_BROWSERTEST_H_
diff --git a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.js b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.js
index 8b403198fd..2324d6df02 100644
--- a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.js
+++ b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.js
@@ -4,6 +4,16 @@
// TODO(dbeam): test for loading upacked extensions?
+GEN('#include "chrome/browser/ui/webui/extensions/' +
+ 'extension_settings_browsertest.h"');
+
+/**
+ * Test C++ fixture for settings WebUI testing.
+ * @constructor
+ * @extends {testing.Test}
+ */
+function ExtensionSettingsUIBrowserTest() {}
+
/**
* TestFixture for extension settings WebUI testing.
* @extends {testing.Test}
@@ -14,12 +24,29 @@ function ExtensionSettingsWebUITest() {}
ExtensionSettingsWebUITest.prototype = {
__proto__: testing.Test.prototype,
+ accessibilityIssuesAreErrors: true,
+
+ /** @override */
+ setUp: function() {
+ // TODO(aboxhall): remove these when crbug.com/267035 is closed.
+ this.accessibilityAuditConfig.ignoreSelectors(
+ 'lowContrastElements',
+ '.enable-checkbox input:disabled + .enable-checkbox-text > *');
+ this.accessibilityAuditConfig.ignoreSelectors(
+ 'lowContrastElements', '.extension-description > *');
+ this.accessibilityAuditConfig.ignoreSelectors(
+ 'lowContrastElements', '.location-text');
+ },
+
/**
* A URL to load before starting each test.
* @type {string}
* @const
*/
browsePreload: 'chrome://extensions-frame/',
+
+ /** @override */
+ typedefCppFixture: 'ExtensionSettingsUIBrowserTest',
};
TEST_F('ExtensionSettingsWebUITest', 'testChromeSendHandled', function() {
@@ -43,6 +70,8 @@ function ExtensionSettingsCommandsConfigWebUITest() {}
ExtensionSettingsCommandsConfigWebUITest.prototype = {
__proto__: testing.Test.prototype,
+ accessibilityIssuesAreErrors: true,
+
/**
* A URL to load before starting each test.
* @type {string}
@@ -57,3 +86,23 @@ TEST_F('ExtensionSettingsCommandsConfigWebUITest', 'testChromeSendHandler',
assertEquals(this.browsePreload, document.location.href);
assertTrue($('extension-commands-overlay').classList.contains('showing'));
});
+
+function ExtensionSettingsWebUITestWithExtensionInstalled() {}
+
+ExtensionSettingsWebUITestWithExtensionInstalled.prototype = {
+ __proto__: ExtensionSettingsWebUITest.prototype,
+
+ /** @override */
+ typedefCppFixture: 'ExtensionSettingsUIBrowserTest',
+
+ /** @override */
+ testGenPreamble: function() {
+ GEN(' InstallGoodExtension();');
+ }
+}
+
+TEST_F('ExtensionSettingsWebUITestWithExtensionInstalled',
+ 'baseAccessibilityIsOk', function() {
+ assertEquals(this.browsePreload, document.location.href);
+ this.runAccessibilityAudit();
+});
diff --git a/chrome/browser/ui/webui/extensions/extension_settings_handler.cc b/chrome/browser/ui/webui/extensions/extension_settings_handler.cc
index 6fea215761..403ee9e8e9 100644
--- a/chrome/browser/ui/webui/extensions/extension_settings_handler.cc
+++ b/chrome/browser/ui/webui/extensions/extension_settings_handler.cc
@@ -37,6 +37,7 @@
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/extensions/extension_tab_util.h"
+#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/extensions/extension_warning_set.h"
#include "chrome/browser/extensions/lazy_background_task_queue.h"
#include "chrome/browser/extensions/management_policy.h"
@@ -209,13 +210,13 @@ base::DictionaryValue* ExtensionSettingsHandler::CreateExtensionDetailValue(
extension_data->SetBoolean("terminated",
extension_service_->terminated_extensions()->Contains(extension->id()));
extension_data->SetBoolean("enabledIncognito",
- extension_service_->IsIncognitoEnabled(extension->id()));
+ extension_util::IsIncognitoEnabled(extension->id(), extension_service_));
extension_data->SetBoolean("incognitoCanBeToggled",
extension->can_be_incognito_enabled() &&
!extension->force_incognito_enabled());
extension_data->SetBoolean("wantsFileAccess", extension->wants_file_access());
extension_data->SetBoolean("allowFileAccess",
- extension_service_->AllowFileAccess(extension));
+ extension_util::AllowFileAccess(extension, extension_service_));
extension_data->SetBoolean("allow_reload",
Manifest::IsUnpackedLocation(extension->location()));
extension_data->SetBoolean("is_hosted_app", extension->is_hosted_app());
@@ -861,8 +862,9 @@ void ExtensionSettingsHandler::HandleEnableIncognitoMessage(
// Bug: http://crbug.com/41384
base::AutoReset<bool> auto_reset_ignore_notifications(
&ignore_notifications_, true);
- extension_service_->SetIsIncognitoEnabled(extension->id(),
- enable_str == "true");
+ extension_util::SetIsIncognitoEnabled(extension->id(),
+ extension_service_,
+ enable_str == "true");
}
void ExtensionSettingsHandler::HandleAllowFileAccessMessage(
@@ -883,7 +885,8 @@ void ExtensionSettingsHandler::HandleAllowFileAccessMessage(
return;
}
- extension_service_->SetAllowFileAccess(extension, allow_str == "true");
+ extension_util::SetAllowFileAccess(
+ extension, extension_service_, allow_str == "true");
}
void ExtensionSettingsHandler::HandleUninstallMessage(
diff --git a/chrome/browser/ui/webui/inline_login_ui.cc b/chrome/browser/ui/webui/inline_login_ui.cc
index f7f7a5e57f..810ee748b3 100644
--- a/chrome/browser/ui/webui/inline_login_ui.cc
+++ b/chrome/browser/ui/webui/inline_login_ui.cc
@@ -7,17 +7,24 @@
#include "base/bind.h"
#include "base/command_line.h"
#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/tab_helper.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/signin_global_error.h"
#include "chrome/browser/signin/signin_manager_cookie_helper.h"
+#include "chrome/browser/signin/signin_names_io_thread.h"
#include "chrome/browser/signin/signin_promo.h"
#include "chrome/browser/signin/token_service.h"
#include "chrome/browser/signin/token_service_factory.h"
+#include "chrome/browser/sync/profile_sync_service.h"
+#include "chrome/browser/sync/profile_sync_service_factory.h"
+#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/sync/one_click_signin_sync_starter.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/url_constants.h"
#include "content/public/browser/storage_partition.h"
@@ -29,6 +36,7 @@
#include "google_apis/gaia/gaia_urls.h"
#include "grit/browser_resources.h"
#include "net/base/escape.h"
+#include "net/base/url_util.h"
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/login/oauth2_token_fetcher.h"
@@ -84,7 +92,7 @@ class InlineLoginUIOAuth2Delegate
class InlineLoginUIHandler : public content::WebUIMessageHandler {
public:
explicit InlineLoginUIHandler(Profile* profile)
- : profile_(profile), weak_factory_(this) {}
+ : profile_(profile), weak_factory_(this), choose_what_to_sync_(false) {}
virtual ~InlineLoginUIHandler() {}
// content::WebUIMessageHandler overrides:
@@ -119,20 +127,34 @@ class InlineLoginUIHandler : public content::WebUIMessageHandler {
switches::kEnableInlineSignin);
params.SetInteger("authMode",
enable_inline ? kInlineAuthMode : kDefaultAuthMode);
- // Set continueUrl param for the inline sign in flow. It should point to
- // the oauth2 auth code URL so that later we can grab the auth code from
- // the cookie jar of the embedded webview.
+
+ // Set parameters specific for inline signin flow.
+#if !defined(OS_CHROMEOS)
if (enable_inline) {
+ // Set continueUrl param for the inline sign in flow. It should point to
+ // the oauth2 auth code URL so that later we can grab the auth code from
+ // the cookie jar of the embedded webview.
std::string scope = net::EscapeUrlEncodedData(
gaiaUrls->oauth1_login_scope(), true);
std::string client_id = net::EscapeUrlEncodedData(
gaiaUrls->oauth2_chrome_client_id(), true);
std::string encoded_continue_params = base::StringPrintf(
"?scope=%s&client_id=%s", scope.c_str(), client_id.c_str());
+
+ const GURL& current_url = web_ui()->GetWebContents()->GetURL();
+ signin::Source source = signin::GetSourceForPromoURL(current_url);
+ if (source != signin::SOURCE_UNKNOWN) {
+ params.SetString("service", "chromiumsync");
+ base::StringAppendF(
+ &encoded_continue_params, "&%s=%d", "source",
+ static_cast<int>(source));
+ }
+
params.SetString("continueUrl",
gaiaUrls->client_login_to_oauth2_url().Resolve(
encoded_continue_params).spec());
}
+#endif
web_ui()->CallJavascriptFunction("inline.login.loadAuthExtension", params);
}
@@ -160,6 +182,7 @@ class InlineLoginUIHandler : public content::WebUIMessageHandler {
NOTREACHED();
return;
}
+ dict->GetBoolean("chooseWhatToSync", &choose_what_to_sync_);
content::WebContents* web_contents = web_ui()->GetWebContents();
content::StoragePartition* partition =
@@ -183,24 +206,85 @@ class InlineLoginUIHandler : public content::WebUIMessageHandler {
net::CookieList::const_iterator it;
for (it = cookie_list.begin(); it != cookie_list.end(); ++it) {
if (it->Name() == "oauth_code") {
+ content::WebContents* contents = web_ui()->GetWebContents();
+ ProfileSyncService* sync_service =
+ ProfileSyncServiceFactory::GetForProfile(profile_);
+ const GURL& current_url = contents->GetURL();
+ signin::Source source = signin::GetSourceForPromoURL(current_url);
+
+ OneClickSigninSyncStarter::StartSyncMode start_mode =
+ source == signin::SOURCE_SETTINGS || choose_what_to_sync_ ?
+ (SigninGlobalError::GetForProfile(profile_)->HasMenuItem() &&
+ sync_service && sync_service->HasSyncSetupCompleted()) ?
+ OneClickSigninSyncStarter::SHOW_SETTINGS_WITHOUT_CONFIGURE :
+ OneClickSigninSyncStarter::CONFIGURE_SYNC_FIRST :
+ OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS;
+ OneClickSigninSyncStarter::ConfirmationRequired confirmation_required =
+ source == signin::SOURCE_SETTINGS ||
+ source == signin::SOURCE_WEBSTORE_INSTALL ||
+ choose_what_to_sync_?
+ OneClickSigninSyncStarter::NO_CONFIRMATION :
+ OneClickSigninSyncStarter::CONFIRM_AFTER_SIGNIN;
// Call OneClickSigninSyncStarter to exchange oauth code for tokens.
// OneClickSigninSyncStarter will delete itself once the job is done.
- // TODO(guohui): should collect from user whether they want to use
- // default sync settings or configure first.
new OneClickSigninSyncStarter(
profile_, NULL, "0" /* session_index 0 for the default user */,
UTF16ToASCII(email), UTF16ToASCII(password), it->Value(),
- OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS,
- web_ui()->GetWebContents(),
- OneClickSigninSyncStarter::NO_CONFIRMATION,
- OneClickSigninSyncStarter::Callback());
+ start_mode,
+ contents,
+ confirmation_required,
+ base::Bind(&InlineLoginUIHandler::SyncStarterCallback,
+ weak_factory_.GetWeakPtr()));
+ break;
}
}
web_ui()->CallJavascriptFunction("inline.login.closeDialog");
}
+ void SyncStarterCallback(OneClickSigninSyncStarter::SyncSetupResult result) {
+ content::WebContents* contents = web_ui()->GetWebContents();
+ const GURL& current_url = contents->GetURL();
+ bool auto_close = signin::IsAutoCloseEnabledInURL(current_url);
+ signin::Source source = signin::GetSourceForPromoURL(current_url);
+ if (auto_close) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &InlineLoginUIHandler::CloseTab, weak_factory_.GetWeakPtr()));
+ } else if (source != signin::SOURCE_UNKNOWN &&
+ source != signin::SOURCE_SETTINGS &&
+ source != signin::SOURCE_WEBSTORE_INSTALL) {
+ // Redirect to NTP/Apps page and display a confirmation bubble.
+ // TODO(guohui): should redirect to the given continue url for webstore
+ // install flows.
+ GURL url(source == signin::SOURCE_APPS_PAGE_LINK ?
+ chrome::kChromeUIAppsURL : chrome::kChromeUINewTabURL);
+ content::OpenURLParams params(url,
+ content::Referrer(),
+ CURRENT_TAB,
+ content::PAGE_TRANSITION_AUTO_TOPLEVEL,
+ false);
+ contents->OpenURL(params);
+ }
+ }
+
+ void CloseTab() {
+ content::WebContents* tab = web_ui()->GetWebContents();
+ Browser* browser = chrome::FindBrowserWithWebContents(tab);
+ if (browser) {
+ TabStripModel* tab_strip_model = browser->tab_strip_model();
+ if (tab_strip_model) {
+ int index = tab_strip_model->GetIndexOfWebContents(tab);
+ if (index != TabStripModel::kNoTab) {
+ tab_strip_model->ExecuteContextMenuCommand(
+ index, TabStripModel::CommandCloseTab);
+ }
+ }
+ }
+ }
Profile* profile_;
base::WeakPtrFactory<InlineLoginUIHandler> weak_factory_;
+ bool choose_what_to_sync_;
#if defined(OS_CHROMEOS)
scoped_ptr<chromeos::OAuth2TokenFetcher> oauth2_token_fetcher_;
scoped_ptr<InlineLoginUIOAuth2Delegate> oauth2_delegate_;
diff --git a/chrome/browser/ui/webui/inspect_ui.cc b/chrome/browser/ui/webui/inspect_ui.cc
index 5f52409f5e..4a7253d72c 100644
--- a/chrome/browser/ui/webui/inspect_ui.cc
+++ b/chrome/browser/ui/webui/inspect_ui.cc
@@ -19,8 +19,12 @@
#include "chrome/browser/devtools/port_forwarding_controller.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser_navigator.h"
+#include "chrome/browser/ui/singleton_tabs.h"
#include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
+#include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
#include "chrome/browser/ui/webui/theme_source.h"
+#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "content/public/browser/browser_child_process_observer.h"
@@ -36,6 +40,7 @@
#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/user_metrics.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui.h"
#include "content/public/browser/web_ui_data_source.h"
@@ -181,6 +186,9 @@ DictionaryValue* BuildTargetDescriptor(RenderViewHost* rvh, bool is_tab) {
else
target_type = kExtensionTargetType;
title = extension->name();
+ favicon_url = extensions::ExtensionIconSource::GetIconURL(
+ extension, extension_misc::EXTENSION_ICON_SMALLISH,
+ ExtensionIconSet::MATCH_BIGGER, false, NULL);
}
}
}
@@ -555,6 +563,14 @@ void InspectUI::OpenRemotePage(const std::string& browser_id,
it->second->Open(gurl.spec());
}
+void InspectUI::InspectDevices(Browser* browser) {
+ content::RecordAction(content::UserMetricsAction("InspectDevices"));
+ chrome::NavigateParams params(chrome::GetSingletonTabNavigateParams(
+ browser, GURL(chrome::kChromeUIInspectURL)));
+ params.path_behavior = chrome::NavigateParams::IGNORE_AND_NAVIGATE;
+ ShowSingletonTabOverwritingNTP(browser, params);
+}
+
void InspectUI::PopulateLists() {
std::set<RenderViewHost*> tab_rvhs;
for (TabContentsIterator it; !it.done(); it.Next())
diff --git a/chrome/browser/ui/webui/inspect_ui.h b/chrome/browser/ui/webui/inspect_ui.h
index 85ec1c5e35..6d48b3c808 100644
--- a/chrome/browser/ui/webui/inspect_ui.h
+++ b/chrome/browser/ui/webui/inspect_ui.h
@@ -20,6 +20,8 @@ namespace base {
class Value;
}
+class Browser;
+
class InspectUI : public content::WebUIController,
public content::NotificationObserver,
public DevToolsAdbBridge::Listener {
@@ -34,6 +36,8 @@ class InspectUI : public content::WebUIController,
void ReloadRemotePage(const std::string& page_id);
void OpenRemotePage(const std::string& browser_id, const std::string& url);
+ static void InspectDevices(Browser* browser);
+
private:
class WorkerCreationDestructionListener;
diff --git a/chrome/browser/ui/webui/local_discovery/local_discovery_ui_browsertest.cc b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_browsertest.cc
index 716dc737f5..01f6c18068 100644
--- a/chrome/browser/ui/webui/local_discovery/local_discovery_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_browsertest.cc
@@ -238,9 +238,6 @@ const char kURLRegisterComplete[] =
const char kURLGaiaToken[] =
"https://accounts.google.com/o/oauth2/token";
-const char kSampleServiceName[] = "myService._privet._tcp.local";
-const char kSampleDeviceID[] = "MyFakeID";
-const char kSampleDeviceHost[] = "myservice.local";
const char kSampleUser[] = "user@host.com";
class TestMessageLoopCondition {
diff --git a/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.cc b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.cc
index 7c9bb88971..d1fafa6402 100644
--- a/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.cc
+++ b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.cc
@@ -59,7 +59,6 @@ const int kRegistrationAnnouncementTimeoutSeconds = 5;
const int kInitialRequeryTimeSeconds = 1;
const int kMaxRequeryTimeSeconds = 2; // Time for last requery
-const int kRequeryExpontentialGrowthBase = 2;
int g_num_visible = 0;
diff --git a/chrome/browser/ui/webui/media/webrtc_logs_ui.cc b/chrome/browser/ui/webui/media/webrtc_logs_ui.cc
index 54de606df1..ce676eb0d4 100644
--- a/chrome/browser/ui/webui/media/webrtc_logs_ui.cc
+++ b/chrome/browser/ui/webui/media/webrtc_logs_ui.cc
@@ -54,9 +54,6 @@ content::WebUIDataSource* CreateWebRtcLogsUIHTMLSource() {
source->AddLocalizedString("bugLinkText", IDS_WEBRTC_LOGS_BUG_LINK_LABEL);
source->AddLocalizedString("noLogsMessage",
IDS_WEBRTC_LOGS_NO_LOGS_MESSAGE);
- source->AddLocalizedString("disabledHeader", IDS_WEBRTC_LOGS_DISABLED_HEADER);
- source->AddLocalizedString("disabledMessage",
- IDS_WEBRTC_LOGS_DISABLED_MESSAGE);
source->SetJsonPath("strings.js");
source->AddResourcePath("webrtc_logs.js", IDR_WEBRTC_LOGS_JS);
source->SetDefaultResource(IDR_WEBRTC_LOGS_HTML);
@@ -73,7 +70,7 @@ content::WebUIDataSource* CreateWebRtcLogsUIHTMLSource() {
class WebRtcLogsDOMHandler : public WebUIMessageHandler,
public WebRtcLogUploadList::Delegate {
public:
- explicit WebRtcLogsDOMHandler();
+ explicit WebRtcLogsDOMHandler(Profile* profile);
virtual ~WebRtcLogsDOMHandler();
// WebUIMessageHandler implementation.
@@ -102,9 +99,9 @@ class WebRtcLogsDOMHandler : public WebUIMessageHandler,
DISALLOW_COPY_AND_ASSIGN(WebRtcLogsDOMHandler);
};
-WebRtcLogsDOMHandler::WebRtcLogsDOMHandler()
+WebRtcLogsDOMHandler::WebRtcLogsDOMHandler(Profile* profile)
: list_available_(false), js_request_pending_(false) {
- upload_list_ = WebRtcLogUploadList::Create(this);
+ upload_list_ = WebRtcLogUploadList::Create(this, profile);
}
WebRtcLogsDOMHandler::~WebRtcLogsDOMHandler() {
@@ -120,7 +117,7 @@ void WebRtcLogsDOMHandler::RegisterMessages() {
}
void WebRtcLogsDOMHandler::HandleRequestWebRtcLogs(const ListValue* args) {
- if (!WebRtcLogsUI::WebRtcLogsUIEnabled() || list_available_)
+ if (list_available_)
UpdateUI();
else
js_request_pending_ = true;
@@ -133,28 +130,22 @@ void WebRtcLogsDOMHandler::OnUploadListAvailable() {
}
void WebRtcLogsDOMHandler::UpdateUI() {
- bool webrtc_logs_enabled = WebRtcLogsUI::WebRtcLogsUIEnabled();
- ListValue upload_list;
+ std::vector<WebRtcLogUploadList::UploadInfo> uploads;
+ upload_list_->GetUploads(50, &uploads);
- if (webrtc_logs_enabled) {
- std::vector<WebRtcLogUploadList::UploadInfo> uploads;
- upload_list_->GetUploads(50, &uploads);
-
- for (std::vector<WebRtcLogUploadList::UploadInfo>::iterator i =
- uploads.begin(); i != uploads.end(); ++i) {
- DictionaryValue* upload = new DictionaryValue();
- upload->SetString("id", i->id);
- upload->SetString("time", base::TimeFormatFriendlyDateAndTime(i->time));
- upload_list.Append(upload);
- }
+ ListValue upload_list;
+ for (std::vector<WebRtcLogUploadList::UploadInfo>::iterator i =
+ uploads.begin(); i != uploads.end(); ++i) {
+ DictionaryValue* upload = new DictionaryValue();
+ upload->SetString("id", i->id);
+ upload->SetString("time", base::TimeFormatFriendlyDateAndTime(i->time));
+ upload_list.Append(upload);
}
- base::FundamentalValue enabled(webrtc_logs_enabled);
-
const chrome::VersionInfo version_info;
base::StringValue version(version_info.Version());
- web_ui()->CallJavascriptFunction("updateWebRtcLogsList", enabled, upload_list,
+ web_ui()->CallJavascriptFunction("updateWebRtcLogsList", upload_list,
version);
}
@@ -167,30 +158,9 @@ void WebRtcLogsDOMHandler::UpdateUI() {
///////////////////////////////////////////////////////////////////////////////
WebRtcLogsUI::WebRtcLogsUI(content::WebUI* web_ui) : WebUIController(web_ui) {
- web_ui->AddMessageHandler(new WebRtcLogsDOMHandler());
+ Profile* profile = Profile::FromWebUI(web_ui);
+ web_ui->AddMessageHandler(new WebRtcLogsDOMHandler(profile));
// Set up the chrome://webrtc-logs/ source.
- Profile* profile = Profile::FromWebUI(web_ui);
content::WebUIDataSource::Add(profile, CreateWebRtcLogsUIHTMLSource());
}
-
-// static
-bool WebRtcLogsUI::WebRtcLogsUIEnabled() {
-#if defined(GOOGLE_CHROME_BUILD)
-#if defined(OS_CHROMEOS)
- bool reporting_enabled = false;
- chromeos::CrosSettings::Get()->GetBoolean(chromeos::kStatsReportingPref,
- &reporting_enabled);
- return reporting_enabled;
-#elif defined(OS_ANDROID)
- // Android has it's own setings for metrics / crash uploading.
- PrefService* prefs = g_browser_process->local_state();
- return prefs->GetBoolean(prefs::kCrashReportingEnabled);
-#else
- PrefService* prefs = g_browser_process->local_state();
- return prefs->GetBoolean(prefs::kMetricsReportingEnabled);
-#endif
-#else
- return false;
-#endif
-}
diff --git a/chrome/browser/ui/webui/media/webrtc_logs_ui.h b/chrome/browser/ui/webui/media/webrtc_logs_ui.h
index 3c375483d9..c2e7ee1dc3 100644
--- a/chrome/browser/ui/webui/media/webrtc_logs_ui.h
+++ b/chrome/browser/ui/webui/media/webrtc_logs_ui.h
@@ -17,9 +17,6 @@ class WebRtcLogsUI : public content::WebUIController {
public:
explicit WebRtcLogsUI(content::WebUI* web_ui);
- // Whether WebRTC logs UI has been enabled.
- static bool WebRtcLogsUIEnabled();
-
private:
DISALLOW_COPY_AND_ASSIGN(WebRtcLogsUI);
};
diff --git a/chrome/browser/ui/webui/net_internals/net_internals_ui.cc b/chrome/browser/ui/webui/net_internals/net_internals_ui.cc
index 3f55e34ad4..cee252a653 100644
--- a/chrome/browser/ui/webui/net_internals/net_internals_ui.cc
+++ b/chrome/browser/ui/webui/net_internals/net_internals_ui.cc
@@ -1552,9 +1552,14 @@ void NetInternalsMessageHandler::OnImportONCFile(const ListValue* list) {
onc::ONCSource onc_source = onc::ONC_SOURCE_USER_IMPORT;
base::ListValue network_configs;
+ base::DictionaryValue global_network_config;
base::ListValue certificates;
- if (!chromeos::onc::ParseAndValidateOncForImport(
- onc_blob, onc_source, passcode, &network_configs, &certificates)) {
+ if (!chromeos::onc::ParseAndValidateOncForImport(onc_blob,
+ onc_source,
+ passcode,
+ &network_configs,
+ &global_network_config,
+ &certificates)) {
error = "Errors occurred during the ONC parsing. ";
}
diff --git a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
index 2420bc5b81..9be9f3005c 100644
--- a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
+++ b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
@@ -27,6 +27,7 @@
#include "chrome/browser/favicon/favicon_service_factory.h"
#include "chrome/browser/prefs/scoped_user_pref_update.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser_dialogs.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/browser_window.h"
@@ -566,8 +567,8 @@ void AppLauncherHandler::HandleUninstallApp(const ListValue* args) {
std::string extension_id;
CHECK(args->GetString(0, &extension_id));
- const Extension* extension = extension_service_->GetExtensionById(
- extension_id, true);
+ const Extension* extension = extension_service_->GetInstalledExtension(
+ extension_id);
if (!extension)
return;
@@ -602,8 +603,9 @@ void AppLauncherHandler::HandleCreateAppShortcut(const ListValue* args) {
Browser* browser = chrome::FindBrowserWithWebContents(
web_ui()->GetWebContents());
- browser->window()->ShowCreateChromeAppShortcutsDialog(
- browser->profile(), extension);
+ chrome::ShowCreateChromeAppShortcutsDialog(
+ browser->window()->GetNativeWindow(), browser->profile(), extension,
+ base::Closure());
}
void AppLauncherHandler::HandleReorderApps(const ListValue* args) {
@@ -790,7 +792,7 @@ void AppLauncherHandler::ExtensionUninstallAccepted() {
// The extension can be uninstalled in another window while the UI was
// showing. Do nothing in that case.
const Extension* extension =
- extension_service_->GetExtensionById(extension_id_prompting_, true);
+ extension_service_->GetInstalledExtension(extension_id_prompting_);
if (!extension)
return;
diff --git a/chrome/browser/ui/webui/options/browser_options_handler.cc b/chrome/browser/ui/webui/options/browser_options_handler.cc
index 27ba092e0e..03d3d1fa66 100644
--- a/chrome/browser/ui/webui/options/browser_options_handler.cc
+++ b/chrome/browser/ui/webui/options/browser_options_handler.cc
@@ -95,6 +95,7 @@
#endif
#if defined(OS_CHROMEOS)
+#include "ash/ash_switches.h"
#include "ash/magnifier/magnifier_constants.h"
#include "chrome/browser/chromeos/accessibility/accessibility_util.h"
#include "chrome/browser/chromeos/extensions/wallpaper_manager_util.h"
@@ -346,6 +347,20 @@ void BrowserOptionsHandler::GetLocalizedValues(DictionaryValue* values) {
IDS_OPTIONS_SETTINGS_ACCESSIBILITY_VIRTUAL_KEYBOARD_DESCRIPTION },
{ "accessibilityAlwaysShowMenu",
IDS_OPTIONS_SETTINGS_ACCESSIBILITY_SHOULD_ALWAYS_SHOW_MENU },
+ { "accessibilityAutoclick",
+ IDS_OPTIONS_SETTINGS_ACCESSIBILITY_AUTOCLICK_DESCRIPTION },
+ { "accessibilityAutoclickDropdown",
+ IDS_OPTIONS_SETTINGS_ACCESSIBILITY_AUTOCLICK_DROPDOWN_DESCRIPTION },
+ { "autoclickDelayExtremelyShort",
+ IDS_OPTIONS_SETTINGS_ACCESSIBILITY_AUTOCLICK_DELAY_EXTREMELY_SHORT },
+ { "autoclickDelayVeryShort",
+ IDS_OPTIONS_SETTINGS_ACCESSIBILITY_AUTOCLICK_DELAY_VERY_SHORT },
+ { "autoclickDelayShort",
+ IDS_OPTIONS_SETTINGS_ACCESSIBILITY_AUTOCLICK_DELAY_SHORT },
+ { "autoclickDelayLong",
+ IDS_OPTIONS_SETTINGS_ACCESSIBILITY_AUTOCLICK_DELAY_LONG },
+ { "autoclickDelayVeryLong",
+ IDS_OPTIONS_SETTINGS_ACCESSIBILITY_AUTOCLICK_DELAY_VERY_LONG },
{ "enableContentProtectionAttestation",
IDS_OPTIONS_ENABLE_CONTENT_PROTECTION_ATTESTATION },
{ "factoryResetHeading", IDS_OPTIONS_FACTORY_RESET_HEADING },
@@ -492,6 +507,9 @@ void BrowserOptionsHandler::GetLocalizedValues(DictionaryValue* values) {
const CommandLine& command_line = *CommandLine::ForCurrentProcess();
values->SetBoolean("enableStickyKeys",
command_line.HasSwitch(switches::kEnableStickyKeys));
+ values->SetBoolean("enableAutoclick",
+ command_line.HasSwitch(
+ ash::switches::kAshEnableAutoclick));
#endif
#if defined(OS_MACOSX)
@@ -655,6 +673,10 @@ void BrowserOptionsHandler::RegisterMessages() {
#endif
}
+void BrowserOptionsHandler::Uninitialize() {
+ registrar_.RemoveAll();
+}
+
void BrowserOptionsHandler::OnStateChanged() {
UpdateSyncState();
}
@@ -996,13 +1018,7 @@ void BrowserOptionsHandler::Observe(
break;
#endif
case chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED:
- // If the browser shuts down during supervised-profile creation, deleting
- // the unregistered supervised-user profile triggers this notification,
- // but the RenderViewHost the profile info would be sent to has already
- // been destroyed.
- if (!web_ui()->GetWebContents()->GetRenderViewHost())
- return;
- SendProfilesInfo();
+ SendProfilesInfo();
break;
case chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL:
case chrome::NOTIFICATION_GOOGLE_SIGNED_OUT:
diff --git a/chrome/browser/ui/webui/options/browser_options_handler.h b/chrome/browser/ui/webui/options/browser_options_handler.h
index 40fc417d7c..8b8d5ec667 100644
--- a/chrome/browser/ui/webui/options/browser_options_handler.h
+++ b/chrome/browser/ui/webui/options/browser_options_handler.h
@@ -53,6 +53,7 @@ class BrowserOptionsHandler
virtual void InitializeHandler() OVERRIDE;
virtual void InitializePage() OVERRIDE;
virtual void RegisterMessages() OVERRIDE;
+ virtual void Uninitialize() OVERRIDE;
// ProfileSyncServiceObserver implementation.
virtual void OnStateChanged() OVERRIDE;
diff --git a/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc b/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc
index 8d4045dc91..5fc6abccbc 100644
--- a/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc
+++ b/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc
@@ -160,7 +160,6 @@ const char kShowMorePlanInfoMessage[] = "showMorePlanInfo";
// These are strings used to communicate with JavaScript.
const char kTagActivate[] = "activate";
-const char kTagActivated[] = "activated";
const char kTagActivationState[] = "activationState";
const char kTagAddConnection[] = "add";
const char kTagApn[] = "apn";
@@ -178,7 +177,6 @@ const char kTagConnected[] = "connected";
const char kTagConnecting[] = "connecting";
const char kTagConnectionState[] = "connectionState";
const char kTagControlledBy[] = "controlledBy";
-const char kTagDataRemaining[] = "dataRemaining";
const char kTagDeviceConnected[] = "deviceConnected";
const char kTagDisableConnectButton[] = "disableConnectButton";
const char kTagDisconnect[] = "disconnect";
@@ -231,7 +229,6 @@ const char kTagServiceName[] = "serviceName";
const char kTagServicePath[] = "servicePath";
const char kTagShared[] = "shared";
const char kTagShowActivateButton[] = "showActivateButton";
-const char kTagShowBuyButton[] = "showBuyButton";
const char kTagShowPreferred[] = "showPreferred";
const char kTagShowProxy[] = "showProxy";
const char kTagShowStaticIPConfig[] = "showStaticIPConfig";
@@ -246,7 +243,6 @@ const char kTagUsername[] = "username";
const char kTagValue[] = "value";
const char kTagVpn[] = "vpn";
const char kTagVpnList[] = "vpnList";
-const char kTagWarning[] = "warning";
const char kTagWifi[] = "wifi";
const char kTagWifiAvailable[] = "wifiAvailable";
const char kTagWifiEnabled[] = "wifiEnabled";
@@ -547,18 +543,32 @@ base::DictionaryValue* BuildIPInfoDictionary(
return ip_info_dict.release();
}
-static bool CanForgetNetworkType(const std::string& type) {
+bool CanForgetNetworkType(const std::string& type) {
return type == shill::kTypeWifi ||
type == shill::kTypeWimax ||
type == shill::kTypeVPN;
}
-static bool CanAddNetworkType(const std::string& type) {
+bool CanAddNetworkType(const std::string& type) {
return type == shill::kTypeWifi ||
type == shill::kTypeVPN ||
type == shill::kTypeCellular;
}
+// Decorate dictionary |value_dict| with policy information from |ui_data|.
+void DecorateValueDictionary(const NetworkPropertyUIData& ui_data,
+ const base::Value& value,
+ base::DictionaryValue* value_dict) {
+ const base::Value* recommended_value = ui_data.default_value();
+ if (ui_data.IsManaged())
+ value_dict->SetString(kTagControlledBy, kTagPolicy);
+ else if (recommended_value && recommended_value->Equals(&value))
+ value_dict->SetString(kTagControlledBy, kTagRecommended);
+
+ if (recommended_value)
+ value_dict->Set(kTagRecommendedValue, recommended_value->DeepCopy());
+}
+
// Decorate pref value as CoreOptionsHandler::CreateValueForPref() does and
// store it under |key| in |settings|. Takes ownership of |value|.
void SetValueDictionary(base::DictionaryValue* settings,
@@ -568,15 +578,34 @@ void SetValueDictionary(base::DictionaryValue* settings,
base::DictionaryValue* dict = new base::DictionaryValue();
// DictionaryValue::Set() takes ownership of |value|.
dict->Set(kTagValue, value);
- const base::Value* recommended_value = ui_data.default_value();
- if (ui_data.IsManaged())
- dict->SetString(kTagControlledBy, kTagPolicy);
- else if (recommended_value && recommended_value->Equals(value))
- dict->SetString(kTagControlledBy, kTagRecommended);
-
- if (recommended_value)
- dict->Set(kTagRecommendedValue, recommended_value->DeepCopy());
settings->Set(key, dict);
+ DecorateValueDictionary(ui_data, *value, dict);
+}
+
+// Creates a decorated dictionary like SetValueDictionary does, but extended for
+// the Autoconnect property, which respects additionally global network policy.
+void SetAutoconnectValueDictionary(bool network_is_private,
+ ::onc::ONCSource onc_source,
+ bool current_autoconnect,
+ const NetworkPropertyUIData& ui_data,
+ base::DictionaryValue* settings) {
+ base::DictionaryValue* dict = new base::DictionaryValue();
+ base::Value* value = new base::FundamentalValue(current_autoconnect);
+ // DictionaryValue::Set() takes ownership of |value|.
+ dict->Set(kTagValue, value);
+ settings->Set(kTagAutoConnect, dict);
+ if (onc_source != ::onc::ONC_SOURCE_USER_POLICY &&
+ onc_source != ::onc::ONC_SOURCE_DEVICE_POLICY) {
+ // Autoconnect can be controlled by the GlobalNetworkConfiguration of the
+ // ONC policy.
+ bool only_policy_autoconnect =
+ onc::PolicyAllowsOnlyPolicyNetworksToAutoconnect(network_is_private);
+ if (only_policy_autoconnect) {
+ dict->SetString(kTagControlledBy, kTagPolicy);
+ return;
+ }
+ }
+ DecorateValueDictionary(ui_data, *value, dict);
}
std::string CopyStringFromDictionary(const base::DictionaryValue& source,
@@ -1588,9 +1617,11 @@ void InternetOptionsHandler::PopulateDictionaryDetailsCallback(
bool auto_connect = false;
shill_properties.GetBooleanWithoutPathExpansion(
shill::kAutoConnectProperty, &auto_connect);
- SetValueDictionary(&dictionary, kTagAutoConnect,
- new base::FundamentalValue(auto_connect),
- auto_connect_ui_data);
+ SetAutoconnectValueDictionary(network->IsPrivate(),
+ onc_source,
+ auto_connect,
+ auto_connect_ui_data,
+ &dictionary);
PopulateConnectionDetails(network, shill_properties, &dictionary);
diff --git a/chrome/browser/ui/webui/options/manage_profile_handler.cc b/chrome/browser/ui/webui/options/manage_profile_handler.cc
index 345e58bd06..ada4acddf8 100644
--- a/chrome/browser/ui/webui/options/manage_profile_handler.cc
+++ b/chrome/browser/ui/webui/options/manage_profile_handler.cc
@@ -195,17 +195,15 @@ void ManageProfileHandler::RegisterMessages() {
base::Unretained(this)));
}
+void ManageProfileHandler::Uninitialize() {
+ registrar_.RemoveAll();
+}
+
void ManageProfileHandler::Observe(
int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
if (type == chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED) {
- // If the browser shuts down during supervised-profile creation, deleting
- // the unregistered supervised-user profile triggers this notification,
- // but the RenderViewHost the profile info would be sent to has already been
- // destroyed.
- if (!web_ui()->GetWebContents()->GetRenderViewHost())
- return;
SendProfileNames();
base::StringValue value(kManageProfileIconGridName);
SendProfileIcons(value);
diff --git a/chrome/browser/ui/webui/options/manage_profile_handler.h b/chrome/browser/ui/webui/options/manage_profile_handler.h
index e4988fa393..90c9820810 100644
--- a/chrome/browser/ui/webui/options/manage_profile_handler.h
+++ b/chrome/browser/ui/webui/options/manage_profile_handler.h
@@ -30,6 +30,7 @@ class ManageProfileHandler : public OptionsPageUIHandler,
base::DictionaryValue* localized_strings) OVERRIDE;
virtual void InitializeHandler() OVERRIDE;
virtual void InitializePage() OVERRIDE;
+ virtual void Uninitialize() OVERRIDE;
// WebUIMessageHandler:
virtual void RegisterMessages() OVERRIDE;
diff --git a/chrome/browser/ui/webui/options/options_ui.cc b/chrome/browser/ui/webui/options/options_ui.cc
index cf3e584df1..61bd0f6477 100644
--- a/chrome/browser/ui/webui/options/options_ui.cc
+++ b/chrome/browser/ui/webui/options/options_ui.cc
@@ -7,6 +7,7 @@
#include <algorithm>
#include <vector>
+#include "base/basictypes.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/memory/ref_counted_memory.h"
@@ -64,6 +65,7 @@
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/webui/jstemplate_builder.h"
#include "ui/base/webui/web_ui_util.h"
+#include "url/gurl.h"
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/system/pointer_device_observer.h"
@@ -235,6 +237,7 @@ void OptionsPageUIHandler::RegisterTitle(DictionaryValue* localized_strings,
OptionsUI::OptionsUI(content::WebUI* web_ui)
: WebUIController(web_ui),
+ WebContentsObserver(web_ui->GetWebContents()),
initialized_handlers_(false) {
DictionaryValue* localized_strings = new DictionaryValue();
localized_strings->Set(OptionsPageUIHandler::kSettingsAppKey,
@@ -376,6 +379,21 @@ base::RefCountedMemory* OptionsUI::GetFaviconResourceBytes(
LoadDataResourceBytesForScale(IDR_SETTINGS_FAVICON, scale_factor);
}
+void OptionsUI::DidStartProvisionalLoadForFrame(
+ int64 frame_id,
+ int64 parent_frame_id,
+ bool is_main_frame,
+ const GURL& validated_url,
+ bool is_error_page,
+ bool is_iframe_srcdoc,
+ content::RenderViewHost* render_view_host) {
+ if (render_view_host == web_ui()->GetWebContents()->GetRenderViewHost() &&
+ validated_url.host() == chrome::kChromeUISettingsFrameHost) {
+ for (size_t i = 0; i < handlers_.size(); ++i)
+ handlers_[i]->PageLoadStarted();
+ }
+}
+
void OptionsUI::InitializeHandlers() {
Profile* profile = Profile::FromWebUI(web_ui());
DCHECK(!profile->IsOffTheRecord() || profile->IsGuestSession());
@@ -405,18 +423,6 @@ void OptionsUI::InitializeHandlers() {
"BrowserOptions.notifyInitializationComplete");
}
-void OptionsUI::RenderViewCreated(content::RenderViewHost* render_view_host) {
- content::WebUIController::RenderViewCreated(render_view_host);
- for (size_t i = 0; i < handlers_.size(); ++i)
- handlers_[i]->PageLoadStarted();
-}
-
-void OptionsUI::RenderViewReused(content::RenderViewHost* render_view_host) {
- content::WebUIController::RenderViewReused(render_view_host);
- for (size_t i = 0; i < handlers_.size(); ++i)
- handlers_[i]->PageLoadStarted();
-}
-
void OptionsUI::AddOptionsPageUIHandler(DictionaryValue* localized_strings,
OptionsPageUIHandler* handler_raw) {
scoped_ptr<OptionsPageUIHandler> handler(handler_raw);
diff --git a/chrome/browser/ui/webui/options/options_ui.h b/chrome/browser/ui/webui/options/options_ui.h
index ac2a98b658..8117ed6a62 100644
--- a/chrome/browser/ui/webui/options/options_ui.h
+++ b/chrome/browser/ui/webui/options/options_ui.h
@@ -13,6 +13,7 @@
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/notification_types.h"
+#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_ui_controller.h"
#include "content/public/browser/web_ui_message_handler.h"
#include "ui/base/layout.h"
@@ -114,6 +115,7 @@ class OptionsPageUIHandlerHost {
// The WebUI for chrome:settings-frame.
class OptionsUI : public content::WebUIController,
+ public content::WebContentsObserver,
public OptionsPageUIHandlerHost {
public:
explicit OptionsUI(content::WebUI* web_ui);
@@ -128,15 +130,19 @@ class OptionsUI : public content::WebUIController,
static base::RefCountedMemory* GetFaviconResourceBytes(
ui::ScaleFactor scale_factor);
+ // Overridden from content::WebContentsObserver:
+ virtual void DidStartProvisionalLoadForFrame(
+ int64 frame_id,
+ int64 parent_frame_id,
+ bool is_main_frame,
+ const GURL& validated_url,
+ bool is_error_page,
+ bool is_iframe_srcdoc,
+ content::RenderViewHost* render_view_host) OVERRIDE;
+
// Overridden from OptionsPageUIHandlerHost:
virtual void InitializeHandlers() OVERRIDE;
- // Overridden from content::WebUIController:
- virtual void RenderViewCreated(content::RenderViewHost* render_view_host)
- OVERRIDE;
- virtual void RenderViewReused(content::RenderViewHost* render_view_host)
- OVERRIDE;
-
private:
// Adds OptionsPageUiHandler to the handlers list if handler is enabled.
void AddOptionsPageUIHandler(base::DictionaryValue* localized_strings,
diff --git a/chrome/browser/ui/webui/options/options_ui_browsertest.cc b/chrome/browser/ui/webui/options/options_ui_browsertest.cc
index e23ec2133f..f185076d43 100644
--- a/chrome/browser/ui/webui/options/options_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/options/options_ui_browsertest.cc
@@ -15,8 +15,38 @@
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
+#if !defined(OS_CHROMEOS)
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/run_loop.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/browser_commands.h"
+#include "content/public/test/test_navigation_observer.h"
+#include "ui/base/window_open_disposition.h"
+#include "url/gurl.h"
+#endif
+
namespace options {
+namespace {
+
+#if !defined(OS_CHROMEOS)
+void RunClosureWhenProfileInitialized(const base::Closure& closure,
+ Profile* profile,
+ Profile::CreateStatus status) {
+ if (status == Profile::CREATE_STATUS_INITIALIZED)
+ closure.Run();
+}
+#endif
+
+} // namespace
+
OptionsUIBrowserTest::OptionsUIBrowserTest() {
}
@@ -49,4 +79,54 @@ IN_PROC_BROWSER_TEST_F(OptionsUIBrowserTest, DISABLED_LoadOptionsByURL) {
VerifyNavbar();
}
+#if !defined(OS_CHROMEOS)
+// Regression test for http://crbug.com/301436, excluded on Chrome OS because
+// profile management in the settings UI exists on desktop platforms only.
+IN_PROC_BROWSER_TEST_F(OptionsUIBrowserTest, NavigateBackFromOverlayDialog) {
+ // Navigate to the settings page.
+ ui_test_utils::NavigateToURL(browser(), GURL("chrome://settings-frame"));
+
+ // Click a button that opens an overlay dialog.
+ content::WebContents* contents =
+ browser()->tab_strip_model()->GetActiveWebContents();
+ ASSERT_TRUE(content::ExecuteScript(
+ contents, "$('manage-default-search-engines').click();"));
+
+ // Go back to the settings page.
+ content::TestNavigationObserver observer(contents);
+ chrome::GoBack(browser(), CURRENT_TAB);
+ observer.Wait();
+
+ // Verify that the settings page lists one profile.
+ const char javascript[] =
+ "domAutomationController.send("
+ " document.querySelectorAll('list#profiles-list > div[role=listitem]')"
+ " .length);";
+ int profiles;
+ ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
+ contents, javascript, &profiles));
+ EXPECT_EQ(1, profiles);
+
+ // Create a second profile.
+ ProfileManager* profile_manager = g_browser_process->profile_manager();
+ const base::FilePath profile_path =
+ profile_manager->GenerateNextProfileDirectoryPath();
+
+ base::RunLoop run_loop;
+ profile_manager->CreateProfileAsync(
+ profile_manager->GenerateNextProfileDirectoryPath(),
+ base::Bind(&RunClosureWhenProfileInitialized,
+ run_loop.QuitClosure()),
+ string16(),
+ string16(),
+ std::string());
+ run_loop.Run();
+
+ // Verify that the settings page has updated and lists two profiles.
+ ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
+ contents, javascript, &profiles));
+ EXPECT_EQ(2, profiles);
+}
+#endif
+
} // namespace options
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
index 28e2e5fbc8..962e93b6c2 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
@@ -173,6 +173,10 @@ const char kPrinterId[] = "printerId";
const char kDisableColorOption[] = "disableColorOption";
const char kSetDuplexAsDefault[] = "setDuplexAsDefault";
const char kPrinterDefaultDuplexValue[] = "printerDefaultDuplexValue";
+#if defined(USE_CUPS)
+const char kCUPSsColorModel[] = "cupsColorModel";
+const char kCUPSsBWModel[] = "cupsBWModel";
+#endif
// Get the print job settings dictionary from |args|. The caller takes
// ownership of the returned DictionaryValue. Returns NULL on failure.
@@ -328,6 +332,11 @@ void GetPrinterCapabilitiesOnFileThread(
settings_info->SetBoolean(kDisableColorOption, !info.color_changeable);
settings_info->SetBoolean(printing::kSettingSetColorAsDefault,
info.color_default);
+#if defined(USE_CUPS)
+ settings_info->SetInteger(kCUPSsColorModel, info.color_model);
+ settings_info->SetInteger(kCUPSsBWModel, info.bw_model);
+#endif
+
// TODO(gene): Make new capabilities format for Print Preview
// that will suit semantic capabiltities better.
// Refactor pld API code below
@@ -352,6 +361,14 @@ printing::StickySettings* GetStickySettings() {
} // namespace
+#if defined(USE_CUPS)
+struct PrintPreviewHandler::CUPSPrinterColorModels {
+ std::string printer_name;
+ printing::ColorModel color_model;
+ printing::ColorModel bw_model;
+};
+#endif
+
class PrintPreviewHandler::AccessTokenService
: public OAuth2TokenService::Consumer {
public:
@@ -658,6 +675,10 @@ void PrintPreviewHandler::HandlePrint(const ListValue* args) {
// Remove selection only flag for the same reason.
settings->Remove(printing::kSettingShouldPrintSelectionOnly, NULL);
+#if defined(USE_CUPS)
+ ConvertColorSettingToCUPSColorModel(settings.get());
+#endif
+
// Set ID to know whether printing is for preview.
settings->SetInteger(printing::kPreviewUIID,
print_preview_ui->GetIDForPrintPreviewUI());
@@ -992,6 +1013,11 @@ void PrintPreviewHandler::SendAccessToken(const std::string& type,
void PrintPreviewHandler::SendPrinterCapabilities(
const DictionaryValue* settings_info) {
VLOG(1) << "Get printer capabilities finished";
+
+#if defined(USE_CUPS)
+ SaveCUPSColorSetting(settings_info);
+#endif
+
web_ui()->CallJavascriptFunction("updateWithPrinterCapabilities",
*settings_info);
}
@@ -1171,3 +1197,48 @@ bool PrintPreviewHandler::GetPreviewDataAndTitle(
*title = print_preview_ui->initiator_title();
return true;
}
+
+#if defined(USE_CUPS)
+void PrintPreviewHandler::SaveCUPSColorSetting(
+ const base::DictionaryValue* settings) {
+ cups_printer_color_models_.reset(new CUPSPrinterColorModels);
+ settings->GetString(kPrinterId, &cups_printer_color_models_->printer_name);
+ settings->GetInteger(
+ kCUPSsColorModel,
+ reinterpret_cast<int*>(&cups_printer_color_models_->color_model));
+ settings->GetInteger(
+ kCUPSsBWModel,
+ reinterpret_cast<int*>(&cups_printer_color_models_->bw_model));
+}
+
+void PrintPreviewHandler::ConvertColorSettingToCUPSColorModel(
+ base::DictionaryValue* settings) const {
+ if (!cups_printer_color_models_)
+ return;
+
+ // Sanity check the printer name.
+ std::string printer_name;
+ if (!settings->GetString(printing::kSettingDeviceName, &printer_name) ||
+ printer_name != cups_printer_color_models_->printer_name) {
+ NOTREACHED();
+ return;
+ }
+
+ int color;
+ if (!settings->GetInteger(printing::kSettingColor, &color)) {
+ NOTREACHED();
+ return;
+ }
+
+ printing::ColorModel bw_model = cups_printer_color_models_->bw_model;
+ if (color == printing::GRAY && bw_model != printing::UNKNOWN_COLOR_MODEL) {
+ settings->SetInteger(printing::kSettingColor, bw_model);
+ return;
+ }
+ DCHECK_EQ(printing::COLOR, color);
+ printing::ColorModel color_model = cups_printer_color_models_->color_model;
+ if (color_model != printing::UNKNOWN_COLOR_MODEL)
+ settings->SetInteger(printing::kSettingColor, color_model);
+}
+
+#endif
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.h b/chrome/browser/ui/webui/print_preview/print_preview_handler.h
index 452f311559..5500c32143 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler.h
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.h
@@ -67,6 +67,9 @@ class PrintPreviewHandler : public content::WebUIMessageHandler,
void ShowSystemDialog();
private:
+ class AccessTokenService;
+ struct CUPSPrinterColorModels;
+
content::WebContents* preview_web_contents() const;
// Gets the list of printers. |args| is unused.
@@ -191,6 +194,13 @@ class PrintPreviewHandler : public content::WebUIMessageHandler,
bool GetPreviewDataAndTitle(scoped_refptr<base::RefCountedBytes>* data,
string16* title) const;
+#if defined(USE_CUPS)
+ void SaveCUPSColorSetting(const base::DictionaryValue* settings);
+
+ void ConvertColorSettingToCUPSColorModel(
+ base::DictionaryValue* settings) const;
+#endif
+
// Pointer to current print system.
scoped_refptr<printing::PrintBackend> print_backend_;
@@ -216,9 +226,13 @@ class PrintPreviewHandler : public content::WebUIMessageHandler,
scoped_ptr<base::FilePath> print_to_pdf_path_;
// Holds token service to get OAuth2 access tokens.
- class AccessTokenService;
scoped_ptr<AccessTokenService> token_service_;
+#if defined(USE_CUPS)
+ // The color capabilities from the last printer queried.
+ scoped_ptr<CUPSPrinterColorModels> cups_printer_color_models_;
+#endif
+
base::WeakPtrFactory<PrintPreviewHandler> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(PrintPreviewHandler);
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
index a6352a679b..d01fffa40a 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
@@ -46,7 +46,7 @@ namespace {
#if defined(OS_MACOSX)
// U+0028 U+21E7 U+2318 U+0050 U+0029 in UTF8
const char kAdvancedPrintShortcut[] = "\x28\xE2\x8c\xA5\xE2\x8C\x98\x50\x29";
-#elif defined(OS_WIN)
+#elif defined(OS_WIN) || defined(OS_CHROMEOS)
const char kAdvancedPrintShortcut[] = "(Ctrl+Shift+P)";
#else
const char kAdvancedPrintShortcut[] = "(Shift+Ctrl+P)";
diff --git a/chrome/browser/ui/window_sizer/window_sizer_ash_uitest.cc b/chrome/browser/ui/window_sizer/window_sizer_ash_uitest.cc
index 65b40962e3..cd38b3ab0a 100644
--- a/chrome/browser/ui/window_sizer/window_sizer_ash_uitest.cc
+++ b/chrome/browser/ui/window_sizer/window_sizer_ash_uitest.cc
@@ -3,7 +3,7 @@
// found in the LICENSE file.
#include "ash/launcher/launcher.h"
-#include "ash/launcher/launcher_view.h"
+#include "ash/shelf/shelf_view.h"
#include "ash/shell.h"
#include "ash/test/launcher_test_api.h"
#include "base/command_line.h"
@@ -45,9 +45,9 @@ void CloseBrowser(Browser* browser) {
gfx::Rect GetChromeIconBoundsForRootWindow(aura::RootWindow* root_window) {
ash::Launcher* launcher = ash::Launcher::ForWindow(root_window);
- const ash::internal::LauncherView* launcher_view =
- ash::test::LauncherTestAPI(launcher).launcher_view();
- const views::ViewModel* view_model = launcher_view->view_model_for_test();
+ const ash::internal::ShelfView* shelf_view =
+ ash::test::LauncherTestAPI(launcher).shelf_view();
+ const views::ViewModel* view_model = shelf_view->view_model_for_test();
EXPECT_EQ(2, view_model->view_size());
return view_model->view_at(1)->GetBoundsInScreen();
diff --git a/chrome/browser/unload_browsertest.cc b/chrome/browser/unload_browsertest.cc
index 2d4917e5d4..433d20601f 100644
--- a/chrome/browser/unload_browsertest.cc
+++ b/chrome/browser/unload_browsertest.cc
@@ -406,11 +406,10 @@ IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserCloseTabWhenOtherTabHasListener) {
load_stop_observer.Wait();
CheckTitle("popup");
- content::WindowedNotificationObserver tab_close_observer(
- content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
- content::NotificationService::AllSources());
+ content::WebContentsDestroyedWatcher destroyed_watcher(
+ browser()->tab_strip_model()->GetActiveWebContents());
chrome::CloseTab(browser());
- tab_close_observer.Wait();
+ destroyed_watcher.Wait();
CheckTitle("only_one_unload");
}
@@ -494,6 +493,9 @@ IN_PROC_BROWSER_TEST_F(FastUnloadTest, MAYBE_UnloadHidden) {
NavigateToPageInNewTab("unload_sets_cookie");
EXPECT_EQ("", GetCookies("no_listeners"));
+ content::WebContentsDestroyedWatcher destroyed_watcher(
+ browser()->tab_strip_model()->GetActiveWebContents());
+
{
base::RunLoop run_loop;
FastTabCloseTabStripModelObserver observer(
@@ -506,16 +508,10 @@ IN_PROC_BROWSER_TEST_F(FastUnloadTest, MAYBE_UnloadHidden) {
CheckTitle("no_listeners");
EXPECT_EQ(1, browser()->tab_strip_model()->count());
- // Show that the web contents to go away after the was removed.
- // Without unload-detached, this times-out because it happens earlier.
- content::WindowedNotificationObserver contents_destroyed_observer(
- content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
- content::NotificationService::AllSources());
- contents_destroyed_observer.Wait();
+ // Wait for the actual destruction.
+ destroyed_watcher.Wait();
- // Browser still has the same tab.
- CheckTitle("no_listeners");
- EXPECT_EQ(1, browser()->tab_strip_model()->count());
+ // Verify that the destruction had the desired effect.
EXPECT_EQ("unloaded=ohyeah", GetCookies("no_listeners"));
}
diff --git a/chrome/browser/web_applications/web_app_mac.mm b/chrome/browser/web_applications/web_app_mac.mm
index dad22c57a4..e5b5c2c5ba 100644
--- a/chrome/browser/web_applications/web_app_mac.mm
+++ b/chrome/browser/web_applications/web_app_mac.mm
@@ -24,6 +24,8 @@
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#import "chrome/browser/mac/dock.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/web_applications/web_app_ui.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
@@ -133,12 +135,17 @@ bool AddGfxImageToIconFamily(IconFamilyHandle icon_family,
base::FilePath GetWritableApplicationsDirectory() {
base::FilePath path;
- if (base::mac::GetLocalDirectory(NSApplicationDirectory, &path) &&
- base::PathIsWritable(path)) {
- return path;
+ if (base::mac::GetUserDirectory(NSApplicationDirectory, &path)) {
+ if (!base::DirectoryExists(path)) {
+ if (!file_util::CreateDirectory(path))
+ return base::FilePath();
+
+ // Create a zero-byte ".localized" file to inherit localizations from OSX
+ // for folders that have special meaning.
+ file_util::WriteFile(path.Append(".localized"), NULL, 0);
+ }
+ return base::PathIsWritable(path) ? path : base::FilePath();
}
- if (base::mac::GetUserDirectory(NSApplicationDirectory, &path))
- return path;
return base::FilePath();
}
@@ -338,8 +345,34 @@ ShellIntegration::ShortcutInfo BuildShortcutInfoFromBundle(
return shortcut_info;
}
+void CreateShortcutsAndRunCallback(
+ const base::Closure& close_callback,
+ const ShellIntegration::ShortcutInfo& shortcut_info) {
+ // creation_locations will be ignored by CreatePlatformShortcuts on Mac.
+ ShellIntegration::ShortcutLocations creation_locations;
+ web_app::CreateShortcuts(shortcut_info, creation_locations,
+ web_app::SHORTCUT_CREATION_BY_USER);
+ if (!close_callback.is_null())
+ close_callback.Run();
+}
+
} // namespace
+namespace chrome {
+
+void ShowCreateChromeAppShortcutsDialog(gfx::NativeWindow /*parent_window*/,
+ Profile* profile,
+ const extensions::Extension* app,
+ const base::Closure& close_callback) {
+ // Normally we would show a dialog, but since we always create the app
+ // shortcut in /Applications there are no options for the user to choose.
+ web_app::UpdateShortcutInfoAndIconForApp(
+ *app, profile,
+ base::Bind(&CreateShortcutsAndRunCallback, close_callback));
+}
+
+} // namespace chrome
+
namespace web_app {
WebAppShortcutCreator::WebAppShortcutCreator(