From 0a7e0ff458505735434b51cfa564902cdb901fc1 Mon Sep 17 00:00:00 2001 From: Eurogiciel-BOT Date: Mon, 6 Oct 2014 13:49:55 +0000 Subject: [PATCH] Upstream version 10.38.217.0 Upstream commit-id 025fc90b6c5d17d2ae84beda0cd8426fd415ce7c Change-Id: I8ecf263b86d785d4cbcca1a3510bd89f3aa632d0 Signed-off-by: Eurogiciel-BOT --- packaging/crosswalk.spec | 9 +- src/content/renderer/render_view_impl.cc | 2 + src/media/audio/pulse/pulse.sigs | 5 - src/media/audio/pulse/pulse_util.cc | 9 -- ...x-crash-when-switching-to-console-VT-mode.patch | 30 +++++ .../desktop_window_tree_host_wayland.cc | 5 + src/ui/gl/gl_context_egl.cc | 4 + src/xwalk/DEPS.xwalk | 4 +- src/xwalk/VERSION | 2 +- .../org/xwalk/app/XWalkRuntimeActivityBase.java | 3 +- src/xwalk/app/tools/android/customize.py | 14 ++- src/xwalk/app/tools/android/make_apk.py | 125 +++++++++++++-------- src/xwalk/app/tools/android/make_apk_test.py | 34 +++--- .../app/tools/android/manifest_json_parser.py | 52 +++++---- src/xwalk/application/browser/application_tizen.cc | 8 ++ src/xwalk/application/browser/application_tizen.h | 1 + .../browser/linux/running_application_object.cc | 1 + .../common/tizen/application_storage_impl.cc | 2 +- .../application/common/tizen/package_query.cc | 6 +- .../tools/tizen/xwalk_platform_installer.cc | 6 + .../tools/tizen/xwalk_platform_installer.h | 4 +- src/xwalk/packaging/crosswalk.spec | 9 +- .../core/src/org/xwalk/core/SharedXWalkView.java | 8 +- .../org/xwalk/core/internal/ReflectionHelper.java | 34 +++++- .../core/internal/XWalkContentsClientBridge.java | 17 +++ .../xwalk/core/internal/XWalkUIClientInternal.java | 28 ++++- .../org/xwalk/core/internal/XWalkViewDelegate.java | 62 +++++++--- src/xwalk/runtime/browser/android/xwalk_content.cc | 8 +- .../android/xwalk_contents_client_bridge.cc | 40 ++++++- .../browser/android/xwalk_contents_client_bridge.h | 18 ++- .../runtime/browser/android/xwalk_icon_helper.cc | 76 +++++++++++++ .../runtime/browser/android/xwalk_icon_helper.h | 63 +++++++++++ .../core/xwview/test/OnFullscreenToggledTest.java | 35 ++++++ .../xwview/test/OnJavascriptModalDialogTest.java | 35 ++++++ .../core/xwview/test/OnPageLoadStartedTest.java | 65 +++++++++++ .../core/xwview/test/OnPageLoadStoppedTest.java | 119 ++++++++++++++++++++ .../core/xwview/test/OnUnhandledKeyEventTest.java | 56 +++++++++ .../core/xwview/test/OpenFileChooserTest.java | 35 ++++++ .../xwview/test/ShouldOverrideKeyEventTest.java | 38 +++++++ .../xwalk/core/xwview/test/TestHelperBridge.java | 109 +++++++++++++++++- .../xwalk/core/xwview/test/XWalkViewTestBase.java | 51 ++++++++- src/xwalk/test/android/data/file_chooser.html | 8 ++ src/xwalk/test/android/data/fullscreen_togged.html | 12 ++ src/xwalk/test/android/data/js_modal_dialog.html | 5 + src/xwalk/xwalk.gyp | 2 + src/xwalk/xwalk_android_tests.gypi | 6 + 46 files changed, 1112 insertions(+), 153 deletions(-) create mode 100644 src/ozone/patches/0008-Fix-crash-when-switching-to-console-VT-mode.patch create mode 100644 src/xwalk/runtime/browser/android/xwalk_icon_helper.cc create mode 100644 src/xwalk/runtime/browser/android/xwalk_icon_helper.h create mode 100644 src/xwalk/test/android/core/javatests/src/org/xwalk/core/xwview/test/OnFullscreenToggledTest.java create mode 100644 src/xwalk/test/android/core/javatests/src/org/xwalk/core/xwview/test/OnJavascriptModalDialogTest.java create mode 100644 src/xwalk/test/android/core/javatests/src/org/xwalk/core/xwview/test/OnPageLoadStartedTest.java create mode 100644 src/xwalk/test/android/core/javatests/src/org/xwalk/core/xwview/test/OnPageLoadStoppedTest.java create mode 100644 src/xwalk/test/android/core/javatests/src/org/xwalk/core/xwview/test/OnUnhandledKeyEventTest.java create mode 100644 src/xwalk/test/android/core/javatests/src/org/xwalk/core/xwview/test/OpenFileChooserTest.java create mode 100644 src/xwalk/test/android/core/javatests/src/org/xwalk/core/xwview/test/ShouldOverrideKeyEventTest.java create mode 100644 src/xwalk/test/android/data/file_chooser.html create mode 100644 src/xwalk/test/android/data/fullscreen_togged.html create mode 100644 src/xwalk/test/android/data/js_modal_dialog.html diff --git a/packaging/crosswalk.spec b/packaging/crosswalk.spec index b8c576a..88d9c84 100644 --- a/packaging/crosswalk.spec +++ b/packaging/crosswalk.spec @@ -16,7 +16,7 @@ %endif Name: crosswalk -Version: 10.38.212.0 +Version: 10.38.217.0 Release: 0 Summary: Chromium-based app runtime License: (BSD-3-Clause and LGPL-2.1+) @@ -140,6 +140,13 @@ cp -a src/xwalk/LICENSE LICENSE.xwalk %build +# Stop unconditionally passing -Wall to the compiler. Chromium has its own +# mechanisms for deciding which parts of the code need -Wall and which need it +# to be left out (since several pieces are built with -Werror). At least in +# M39, this is preventing the "rtc_base" target from being built because it +# does not expect -Wall to be passed to the compiler (see webrtc issue 3307). +export CXXFLAGS=`echo $CXXFLAGS | sed s,-Wall,,g` + # For ffmpeg on ia32. The original CFLAGS set by the gyp and config files in # src/third_party/ffmpeg already pass -O2 -fomit-frame-pointer, but Tizen's # CFLAGS end up appending -fno-omit-frame-pointer. See http://crbug.com/37246 diff --git a/src/content/renderer/render_view_impl.cc b/src/content/renderer/render_view_impl.cc index 671ed9e..9e4ac4a 100644 --- a/src/content/renderer/render_view_impl.cc +++ b/src/content/renderer/render_view_impl.cc @@ -1138,6 +1138,8 @@ void RenderView::ApplyWebPreferences(const WebPreferences& prefs, // Enable double tap to zoom when zoomable. settings->setDoubleTapToZoomEnabled(true); + + settings->setShrinksViewportContentToFit(true); #endif #if defined(OS_ANDROID) diff --git a/src/media/audio/pulse/pulse.sigs b/src/media/audio/pulse/pulse.sigs index 45718b9..8d2dab7 100644 --- a/src/media/audio/pulse/pulse.sigs +++ b/src/media/audio/pulse/pulse.sigs @@ -50,8 +50,3 @@ void pa_stream_unref(pa_stream* s); int pa_context_errno(pa_context *c); const char* pa_strerror(int error); pa_cvolume* pa_cvolume_set(pa_cvolume* a, unsigned channels, pa_volume_t v); -# Functions from pulse used in TIZEN to tag the audio stream as "browser". -pa_proplist* pa_proplist_new(void); -void pa_proplist_free(pa_proplist* p); -int pa_proplist_sets(pa_proplist *p, const char *key, const char *value); -pa_stream* pa_stream_new_with_proplist(pa_context* c, const char* name, const pa_sample_spec* ss, const pa_channel_map* map, pa_proplist* proplist); diff --git a/src/media/audio/pulse/pulse_util.cc b/src/media/audio/pulse/pulse_util.cc index 357352a..c06195e 100644 --- a/src/media/audio/pulse/pulse_util.cc +++ b/src/media/audio/pulse/pulse_util.cc @@ -259,16 +259,7 @@ bool CreateOutputStream(pa_threaded_mainloop** mainloop, // than the default channel map (NULL). map = &source_channel_map; } -#if defined(OS_TIZEN) - pa_proplist* proplist = pa_proplist_new(); - pa_proplist_sets(proplist, PA_PROP_MEDIA_ROLE, "browser"); - *stream = pa_stream_new_with_proplist(*context, "Playback", - &sample_specifications, - map, proplist); - pa_proplist_free(proplist); -#else *stream = pa_stream_new(*context, "Playback", &sample_specifications, map); -#endif RETURN_ON_FAILURE(*stream, "failed to create PA playback stream"); pa_stream_set_state_callback(*stream, stream_callback, user_data); diff --git a/src/ozone/patches/0008-Fix-crash-when-switching-to-console-VT-mode.patch b/src/ozone/patches/0008-Fix-crash-when-switching-to-console-VT-mode.patch new file mode 100644 index 0000000..803ff93 --- /dev/null +++ b/src/ozone/patches/0008-Fix-crash-when-switching-to-console-VT-mode.patch @@ -0,0 +1,30 @@ +From 841609f8245f94194d9e6caabafb4d3878de7051 Mon Sep 17 00:00:00 2001 +From: Joone Hur +Date: Wed, 1 Oct 2014 15:10:54 -0700 +Subject: [PATCH] Fix crash when switching to console(VT) mode + +Buffer swapping should not be synchronized so that the GPU process +is not blocked by waiting for a frame update from Weston. + +Bug: TC-341 +--- + ui/gl/gl_context_egl.cc | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/ui/gl/gl_context_egl.cc b/ui/gl/gl_context_egl.cc +index 2554f8c..6cd5d4c 100644 +--- a/ui/gl/gl_context_egl.cc ++++ b/ui/gl/gl_context_egl.cc +@@ -112,6 +112,10 @@ bool GLContextEGL::MakeCurrent(GLSurface* surface) { + return false; + } + ++#if defined(USE_OZONE) ++ eglSwapInterval(display_, 0); ++#endif ++ + // Set this as soon as the context is current, since we might call into GL. + SetRealGLApi(); + +-- +1.7.9.5 diff --git a/src/ozone/ui/desktop_aura/desktop_window_tree_host_wayland.cc b/src/ozone/ui/desktop_aura/desktop_window_tree_host_wayland.cc index 117a872..ad6ba7c 100644 --- a/src/ozone/ui/desktop_aura/desktop_window_tree_host_wayland.cc +++ b/src/ozone/ui/desktop_aura/desktop_window_tree_host_wayland.cc @@ -457,8 +457,10 @@ void DesktopWindowTreeHostWayland::Minimize() { state_ |= Minimized; previous_bounds_ = bounds_; + bounds_ = gfx::Rect(); ui::WindowStateChangeHandler::GetInstance()->SetWidgetState(window_, ui::MINIMIZED); + OnHostResized(bounds_.size()); } void DesktopWindowTreeHostWayland::Restore() { @@ -791,6 +793,9 @@ void DesktopWindowTreeHostWayland::HandleWindowResize(unsigned width, void DesktopWindowTreeHostWayland::HandleWindowUnminimized() { state_ &= ~Minimized; + bounds_ = previous_bounds_; + previous_bounds_ = gfx::Rect(); + OnHostResized(bounds_.size()); } void DesktopWindowTreeHostWayland::HandleCommit(const std::string& text) { diff --git a/src/ui/gl/gl_context_egl.cc b/src/ui/gl/gl_context_egl.cc index 2554f8c..6cd5d4c 100644 --- a/src/ui/gl/gl_context_egl.cc +++ b/src/ui/gl/gl_context_egl.cc @@ -112,6 +112,10 @@ bool GLContextEGL::MakeCurrent(GLSurface* surface) { return false; } +#if defined(USE_OZONE) + eglSwapInterval(display_, 0); +#endif + // Set this as soon as the context is current, since we might call into GL. SetRealGLApi(); diff --git a/src/xwalk/DEPS.xwalk b/src/xwalk/DEPS.xwalk index 03685f6..abc193b 100644 --- a/src/xwalk/DEPS.xwalk +++ b/src/xwalk/DEPS.xwalk @@ -17,10 +17,10 @@ # Edit these when rolling DEPS.xwalk. # ----------------------------------- -chromium_crosswalk_rev = '5ee6f9bf16ecbb3d56b195063b9b55d42effb67b' +chromium_crosswalk_rev = '66c669af8a18cf8d4aa2cc8b798d27e8e1a2feae' blink_crosswalk_rev = 'bc7b6c17bc9634579c6df664d04fdf38a1edd56a' v8_crosswalk_rev = '452135ceb9d31a6bc30fb39bf743623e0f553afa' -ozone_wayland_rev = '9595d59e35e37675587523590e21397addf78446' +ozone_wayland_rev = '113c32025bee544ee34460ce3a29497e69024cee' crosswalk_git = 'https://github.com/crosswalk-project' ozone_wayland_git = 'https://github.com/01org' diff --git a/src/xwalk/VERSION b/src/xwalk/VERSION index 2c762c0..ee9aaa4 100644 --- a/src/xwalk/VERSION +++ b/src/xwalk/VERSION @@ -1,4 +1,4 @@ MAJOR=10 MINOR=38 -BUILD=212 +BUILD=217 PATCH=0 diff --git a/src/xwalk/app/android/runtime_activity/src/org/xwalk/app/XWalkRuntimeActivityBase.java b/src/xwalk/app/android/runtime_activity/src/org/xwalk/app/XWalkRuntimeActivityBase.java index 1d06038..245b1b6 100644 --- a/src/xwalk/app/android/runtime_activity/src/org/xwalk/app/XWalkRuntimeActivityBase.java +++ b/src/xwalk/app/android/runtime_activity/src/org/xwalk/app/XWalkRuntimeActivityBase.java @@ -179,8 +179,9 @@ public abstract class XWalkRuntimeActivityBase extends Activity { private void showRuntimeLibraryExceptionDialog(String title, String message) { if (!mShownNotFoundDialog) { + if (SharedXWalkView.isUsingLibrary()) return; AlertDialog.Builder builder = new AlertDialog.Builder(this); - if (!SharedXWalkView.usesLibraryOutOfPackage()) { + if (SharedXWalkView.containsLibrary()) { builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { diff --git a/src/xwalk/app/tools/android/customize.py b/src/xwalk/app/tools/android/customize.py index 7b661e9..e828997 100755 --- a/src/xwalk/app/tools/android/customize.py +++ b/src/xwalk/app/tools/android/customize.py @@ -66,7 +66,7 @@ def ReplaceInvalidChars(value, mode='default'): invalid_chars = '\/:.*?"<>|- ' for c in invalid_chars: if mode == 'apkname' and c in value: - print("Illegal character: '%s' is replaced with '_'" % c) + print('Illegal character: "%s" replaced with "_"' % c) value = value.replace(c, '_') return value @@ -126,6 +126,10 @@ def Prepare(app_info, compressor): # 1) copy template project to app_dir CleanDir(app_dir) + if not os.path.isdir(template_app_dir): + print('Error: The template directory could not be found (%s).' % + template_app_dir) + sys.exit(7) shutil.copytree(template_app_dir, app_dir) # 2) replace app_dir 'src' dir with template 'src' dir @@ -271,7 +275,7 @@ def ReplaceString(file_path, src, dest): def SetVariable(file_path, string_line, variable, value): function_string = ('%sset%s(%s);\n' % - (' ', variable, value)) + (' ', variable, value)) temp_file_path = file_path + '.backup' file_handle = open(temp_file_path, 'w+') for line in open(file_path): @@ -335,7 +339,7 @@ def CopyExtensionFile(extension_name, suffix, src_path, dest_path): dest_extension_path = os.path.join(dest_path, extension_name) if os.path.exists(dest_extension_path): # TODO: Refine it by renaming it internally. - print('Error: duplicated extension names "%s" are found. Please rename it.' + print('Error: duplicate extension names were found (%s). Please rename it.' % extension_name) sys.exit(9) else: @@ -387,7 +391,7 @@ def CustomizeExtensions(app_info, extensions): extension_json_list = [] for source_path in extension_paths: if not os.path.exists(source_path): - print('Error: can\'t find the extension directory \'%s\'.' % source_path) + print('Error: can not find the extension directory \'%s\'.' % source_path) sys.exit(9) # Remove redundant separators to avoid empty basename. source_path = os.path.normpath(source_path) @@ -403,7 +407,7 @@ def CustomizeExtensions(app_info, extensions): file_name = extension_name + '.json' src_file = os.path.join(source_path, file_name) if not os.path.isfile(src_file): - print('Error: %s is not found in %s.' % (file_name, source_path)) + print('Error: %s was not found in %s.' % (file_name, source_path)) sys.exit(9) else: src_file_handle = open(src_file) diff --git a/src/xwalk/app/tools/android/make_apk.py b/src/xwalk/app/tools/android/make_apk.py index 19d14e0..b94b6cd 100755 --- a/src/xwalk/app/tools/android/make_apk.py +++ b/src/xwalk/app/tools/android/make_apk.py @@ -237,19 +237,14 @@ def Customize(options, app_info, manifest): def Execution(options, name): + arch_string = (' ('+options.arch+')' if options.arch else '') + print('\nStarting application build' + arch_string) app_dir = os.path.join(tempfile.gettempdir(), name) android_path = Which('android') - if android_path is None: - print('The "android" binary could not be found. Check your Android SDK ' - 'installation and your PATH environment variable.') - sys.exit(1) - api_level = GetAndroidApiLevel(android_path) - if api_level < 14: - print('Please install Android API level (>=14) first.') - sys.exit(3) target_string = 'android-%d' % api_level + print (' * Checking keystore for signing') if options.keystore_path: key_store = os.path.expanduser(options.keystore_path) if options.keystore_alias: @@ -266,33 +261,31 @@ def Execution(options, name): else: key_alias_code = None else: - print ('Use xwalk\'s keystore by default for debugging. ' - 'Please switch to your keystore when distributing it to app market.') + print(' No keystore provided for signing. Using xwalk\'s keystore ' + 'for debugging.\n Please use a valid keystore when ' + 'distributing to the app market.') key_store = os.path.join(xwalk_dir, 'xwalk-debug.keystore') key_alias = 'xwalkdebugkey' key_code = 'xwalkdebug' key_alias_code = 'xwalkdebug' - # Check whether ant is installed. - ant_path = Which('ant') - if ant_path is None: - print('Ant could not be found. Please make sure it is installed.') - sys.exit(4) - # Update android project for app and xwalk_core_library. update_project_cmd = [android_path, 'update', 'project', '--path', app_dir, '--target', target_string, '--name', name] if options.mode == 'embedded': + print(' * Updating project with xwalk_core_library') RunCommand([android_path, 'update', 'lib-project', '--path', os.path.join(app_dir, 'xwalk_core_library'), '--target', target_string]) update_project_cmd.extend(['-l', 'xwalk_core_library']) - + else: + print(' * Updating project') RunCommand(update_project_cmd) # Check whether external extensions are included. + print(' * Checking for external extensions') extensions_string = 'xwalk-extensions' extensions_dir = os.path.join(app_dir, extensions_string) external_extension_jars = FindExtensionJars(extensions_dir) @@ -302,6 +295,7 @@ def Execution(options, name): os.path.basename(external_extension_jar))) if options.mode == 'embedded': + print (' * Copying native libraries for %s' % options.arch) # Remove existing native libraries in xwalk_core_library, they are probably # for the last execution to make apk for another CPU arch. # And then copy the native libraries for the specified arch into @@ -324,22 +318,33 @@ def Execution(options, name): sys.exit(10) if options.project_only: + print (' (Skipping apk package creation)') return # Build the APK + if options.mode == 'embedded': + print(' * Building Android apk package with Crosswalk embedded' + + arch_string) + else: + print(' * Building Android apk package') + ant_path = Which('ant') ant_cmd = [ant_path, 'release', '-f', os.path.join(app_dir, 'build.xml')] - if not options.verbose: - ant_cmd.extend(['-quiet']) ant_cmd.extend(['-Dkey.store=%s' % os.path.abspath(key_store)]) ant_cmd.extend(['-Dkey.alias=%s' % key_alias]) if key_code: ant_cmd.extend(['-Dkey.store.password=%s' % key_code]) if key_alias_code: ant_cmd.extend(['-Dkey.alias.password=%s' % key_alias_code]) + + cmd_display = ' '.join([str(item) for item in ant_cmd]) + if options.verbose: + print('Executing:\n %s\n' % cmd_display) + else: + ant_cmd.extend(['-quiet']) ant_result = subprocess.call(ant_cmd) if ant_result != 0: print('Command "%s" exited with non-zero exit code %d' - % (' '.join(ant_cmd), ant_result)) + % (cmd_display, ant_result)) sys.exit(ant_result) src_file = os.path.join(app_dir, 'bin', '%s-release.apk' % name) @@ -352,7 +357,7 @@ def Execution(options, name): dst_file = os.path.join(options.target_dir, '%s_%s.apk' % (package_name, options.arch)) shutil.copyfile(src_file, dst_file) - + print(' (Location: %s)' % dst_file) def PrintPackageInfo(options, name, packaged_archs): package_name_version = os.path.join(options.target_dir, name) @@ -360,38 +365,55 @@ def PrintPackageInfo(options, name, packaged_archs): package_name_version += '_' + options.app_version if len(packaged_archs) == 0: - print ('A non-platform specific APK for the web application "%s" was ' - 'generated successfully at\n%s.apk. It requires a shared Crosswalk ' - 'Runtime to be present.' + print ('\nA non-platform specific APK for the web application "%s" was ' + 'generated successfully at:\n %s.apk.\nIt requires a shared ' + 'Crosswalk Runtime to be present.' % (name, package_name_version)) return - for arch in packaged_archs: - print ('An APK for the web application "%s" including the Crosswalk ' - 'Runtime built for %s was generated successfully, which can be ' - 'found at\n%s_%s.apk.' - % (name, arch, package_name_version, arch)) - all_archs = set(AllArchitectures()) if len(packaged_archs) != len(all_archs): missed_archs = all_archs - set(packaged_archs) - print ('\n\nWARNING: ') - print ('This APK will only work on %s based Android devices. Consider ' - 'building for %s as well.' % + print ('\nNote: This APK will only work on %s-based Android devices.' + ' Consider building\nfor %s as well.' % (', '.join(packaged_archs), ', '.join(missed_archs))) else: - print ('\n\n%d APKs were created for %s devices. ' - % (len(all_archs), ', '.join(all_archs))) - print ('Please install the one that matches the processor architecture ' - 'of your device.\n\n') - print ('If you are going to submit this application to an application ' - 'store, please make sure you submit both packages.\nInstructions ' - 'for submitting multiple APKs to Google Play Store are available ' - 'here:\nhttps://software.intel.com/en-us/html5/articles/submitting' + print ("\nApplication apk's were created for %d architectures (%s)." % + (len(all_archs), (','.join(all_archs)))) + print ('If you submit this application to an application ' + 'store, please submit both\npackages. Instructions ' + 'for submitting multiple APKs to Google Play Store are\navailable ' + 'here:') + print (' https://software.intel.com/en-us/html5/articles/submitting' '-multiple-crosswalk-apk-to-google-play-store') + +def CheckSystemRequirements(): + ''' Check for android, ant, template dir ''' + sys.stdout.write('Checking system requirements...') + sys.stdout.flush() + # check android install + android_path = Which('android') + if android_path is None: + print('failed\nThe "android" binary could not be found. Check your Android ' + 'SDK installation and your PATH environment variable.') + sys.exit(1) + if GetAndroidApiLevel(android_path) < 14: + print('failed\nPlease install Android API level (>=14) first.') + sys.exit(3) + + # Check ant install + ant_path = Which('ant') + if ant_path is None: + print('failed\nAnt could not be found. Please make sure it is installed.') + sys.exit(4) + + print('ok') + + def MakeApk(options, app_info, manifest): + CheckSystemRequirements() Customize(options, app_info, manifest) name = app_info.android_name app_dir = os.path.join(tempfile.gettempdir(), name) @@ -445,15 +467,16 @@ def MakeApk(options, app_info, manifest): # if project_dir, save build directory if options.project_dir: + print ('\nCreating project directory') save_dir = os.path.join(options.project_dir, name) if CreateAndCopyDir(app_dir, save_dir, True): - print ('\nA project directory was created successfully in %s' % - save_dir) - print ('To generate an APK manually, go to %s and run the ' - 'following command:' % save_dir) - print (' ant release -f build.xml') - print ('For more information, see\n' - ' http://developer.android.com/tools/building/' + print (' A project directory was created successfully in:\n %s' % + os.path.abspath(save_dir)) + print (' To manually generate an APK, run the following in that ' + 'directory:') + print (' ant release -f build.xml') + print (' For more information, see:\n' + ' http://developer.android.com/tools/building/' 'building-cmdline.html') else: print ('Error: Unable to create a project directory during the build. ' @@ -703,4 +726,8 @@ def main(argv): if __name__ == '__main__': - sys.exit(main(sys.argv)) + try: + sys.exit(main(sys.argv)) + except KeyboardInterrupt: + print('') + diff --git a/src/xwalk/app/tools/android/make_apk_test.py b/src/xwalk/app/tools/android/make_apk_test.py index 261a241..08389e4 100755 --- a/src/xwalk/app/tools/android/make_apk_test.py +++ b/src/xwalk/app/tools/android/make_apk_test.py @@ -552,8 +552,8 @@ class TestMakeApk(unittest.TestCase): self.checkApks('Example', '1.0.0', keystore_path) Clean('Example', '1.0.0') - keystore_path_with_space = os.path.join( - 'test_data', 'keystore', 'test keystore') + keystore_path_with_space = os.path.join('test_data', 'keystore', + 'test keystore') shutil.copy2(keystore_path, keystore_path_with_space) keystore_path = os.path.join('test_data', 'keystore', 'xwalk-test.keystore') @@ -615,8 +615,8 @@ class TestMakeApk(unittest.TestCase): '--manifest=%s' % manifest_path, self._mode] out = RunCommand(cmd) self.addCleanup(Clean, 'Example', '1.0.0') - self.assertIn('WARNING: app.launch.local_path is deprecated for Crosswalk', - out) + self.assertIn('Warning: The following fields have been deprecated', out) + self.assertIn('app.launch.local_path', out) Clean('Example', '1.0.0') manifest_path = os.path.join('test_data', 'manifest', 'deprecated', @@ -624,7 +624,8 @@ class TestMakeApk(unittest.TestCase): cmd = ['python', 'make_apk.py', '--package=org.xwalk.example', '--manifest=%s' % manifest_path, self._mode] out = RunCommand(cmd) - self.assertIn('WARNING: launch_path is deprecated for Crosswalk', out) + self.assertIn('Warning: The following fields have been deprecated', out) + self.assertIn('launch_path', out) Clean('Example', '1.0.0') manifest_path = os.path.join('test_data', 'manifest', 'deprecated', @@ -632,7 +633,8 @@ class TestMakeApk(unittest.TestCase): cmd = ['python', 'make_apk.py', '--package=org.xwalk.example', '--manifest=%s' % manifest_path, self._mode] out = RunCommand(cmd) - self.assertIn('WARNING: permissions is deprecated for Crosswalk', out) + self.assertIn('Warning: The following fields have been deprecated', out) + self.assertIn('permissions', out) Clean('Example', '1.0.0') manifest_path = os.path.join('test_data', 'manifest', @@ -640,8 +642,8 @@ class TestMakeApk(unittest.TestCase): cmd = ['python', 'make_apk.py', '--package=org.xwalk.example', '--manifest=%s' % manifest_path, self._mode] out = RunCommand(cmd) - self.assertIn('WARNING: icons defined as dictionary form is deprecated', - out) + self.assertIn('Warning: The following fields have been deprecated', out) + self.assertIn('icons', out) Clean('Example', '1.0.0') manifest_path = os.path.join('test_data', 'manifest', 'deprecated', @@ -649,7 +651,8 @@ class TestMakeApk(unittest.TestCase): cmd = ['python', 'make_apk.py', '--package=org.xwalk.example', '--manifest=%s' % manifest_path, self._mode] out = RunCommand(cmd) - self.assertIn('WARNING: description is deprecated for Crosswalk', out) + self.assertIn('Warning: The following fields have been deprecated', out) + self.assertIn('description', out) Clean('Example', '1.0.0') manifest_path = os.path.join('test_data', 'manifest', 'deprecated', @@ -657,7 +660,8 @@ class TestMakeApk(unittest.TestCase): cmd = ['python', 'make_apk.py', '--package=org.xwalk.example', '--manifest=%s' % manifest_path, self._mode] out = RunCommand(cmd) - self.assertIn('WARNING: version is deprecated for Crosswalk', out) + self.assertIn('Warning: The following fields have been deprecated', out) + self.assertIn('version', out) def testManifestWithError(self): manifest_path = os.path.join('test_data', 'manifest', @@ -715,14 +719,12 @@ class TestMakeApk(unittest.TestCase): self.checkApks('Example', '1.0.0') def testExtensionsWithNonExtension(self): - # Test with a non-existed extension. + # Test with a non-existing extension. extension_path = 'test_data/extensions/myextension' cmd = ['python', 'make_apk.py', '--name=Example', '--app-version=1.0.0', '--package=org.xwalk.example', '--app-url=http://www.intel.com', '--extensions=%s1' % extension_path, self._mode, '--verbose'] out = RunCommand(cmd) - error_msg = 'Error: can\'t find the extension directory' - self.assertTrue(out.find(error_msg) != -1) self.assertTrue(out.find('Exiting with error code: 9') != -1) def testExtensionWithPermissions(self): @@ -936,7 +938,7 @@ class TestMakeApk(unittest.TestCase): for img_type in img_types: name = orientation + '_' + img_type + '_' + dimension path_tmp = os.path.join(launch_screen_path, name) - _file = open(path_tmp,'w+') + _file = open(path_tmp, 'w+') _file.write(name) _file.close() # Run Test. @@ -945,8 +947,8 @@ class TestMakeApk(unittest.TestCase): cmd = ['python', 'make_apk.py', '--package=org.xwalk.example', '--manifest=%s' % manifest_path, self._mode] out = RunCommand(cmd) - self.assertTrue( - out.find('WARNING: launch_screen is deprecated for Crosswalk') != -1) + self.assertIn('Warning: The following fields have been deprecated', out) + self.assertTrue(out.find('launch_screen') != -1) Clean('Example', '1.0.0') manifest_path = os.path.join('test_data', 'launchScreen', 'manifest.json') cmd = ['python', 'make_apk.py', '--package=org.xwalk.example', diff --git a/src/xwalk/app/tools/android/manifest_json_parser.py b/src/xwalk/app/tools/android/manifest_json_parser.py index 889b516..4da994a 100755 --- a/src/xwalk/app/tools/android/manifest_json_parser.py +++ b/src/xwalk/app/tools/android/manifest_json_parser.py @@ -58,9 +58,13 @@ def ParseLaunchScreen(ret_dict, launch_screen_dict, orientation): sub_dict['image_border']) -def PrintDeprecationWarning(item): - print ('WARNING: %s is deprecated for Crosswalk. Please follow ' - 'https://www.crosswalk-project.org/#documentation/manifest.' % item) +def PrintDeprecationWarning(deprecated_items): + if len(deprecated_items) > 0: + print (' Warning: The following fields have been deprecated for ' + 'Crosswalk:\n %s' % + ', '.join([str(item) for item in deprecated_items])) + print (' Please follow: https://www.crosswalk-project.org/#documentation/' + 'manifest.') class ManifestJsonParser(object): @@ -108,7 +112,9 @@ class ManifestJsonParser(object): fullscreen: The fullscreen flag of the application. launch_screen: The launch screen configuration. """ + print ("Checking manifest file") ret_dict = {} + deprecated_items = [] if 'name' not in self.data_src: print('Error: no \'name\' field in manifest.json file.') sys.exit(1) @@ -121,17 +127,17 @@ class ManifestJsonParser(object): elif 'xwalk_version' in self.data_src: ret_dict['version'] = self.data_src['xwalk_version'] elif 'version' in self.data_src: - PrintDeprecationWarning('version') + deprecated_items.append('version') ret_dict['version'] = self.data_src['version'] if 'start_url' in self.data_src: app_url = self.data_src['start_url'] elif 'launch_path' in self.data_src: - PrintDeprecationWarning('launch_path') + deprecated_items.append('launch_path') app_url = self.data_src['launch_path'] elif ('app' in self.data_src and 'launch' in self.data_src['app'] and 'local_path' in self.data_src['app']['launch']): - PrintDeprecationWarning('app.launch.local_path') + deprecated_items.append('app.launch.local_path') app_url = self.data_src['app']['launch']['local_path'] else: app_url = '' @@ -144,7 +150,7 @@ class ManifestJsonParser(object): if 'icons' in self.data_src: icons = self.data_src['icons'] if type(icons) == dict: - PrintDeprecationWarning('icons defined as dictionary form') + deprecated_items.append('icons defined as index:value') ret_dict['icons'] = icons elif type(icons) == list: icons_dict = {} @@ -165,7 +171,7 @@ class ManifestJsonParser(object): elif 'xwalk_description' in self.data_src: ret_dict['description'] = self.data_src['xwalk_description'] elif 'description' in self.data_src: - PrintDeprecationWarning('description') + deprecated_items.append('description') ret_dict['description'] = self.data_src['description'] ret_dict['app_url'] = app_url ret_dict['app_root'] = app_root @@ -179,7 +185,7 @@ class ManifestJsonParser(object): print('\'Permissions\' field error in manifest.json file.') sys.exit(1) elif 'permissions' in self.data_src: - PrintDeprecationWarning('permissions') + deprecated_items.append('permissions') try: permission_list = self.data_src['permissions'] ret_dict['permissions'] = HandlePermissionList(permission_list) @@ -211,11 +217,13 @@ class ManifestJsonParser(object): ParseLaunchScreen(ret_dict, launch_screen_dict, 'portrait') ParseLaunchScreen(ret_dict, launch_screen_dict, 'landscape') elif 'launch_screen' in self.data_src: - PrintDeprecationWarning('launch_screen') + deprecated_items.append('launch_screen') launch_screen_dict = self.data_src['launch_screen'] ParseLaunchScreen(ret_dict, launch_screen_dict, 'default') ParseLaunchScreen(ret_dict, launch_screen_dict, 'portrait') ParseLaunchScreen(ret_dict, launch_screen_dict, 'landscape') + + PrintDeprecationWarning(deprecated_items) return ret_dict def ShowItems(self): @@ -232,29 +240,29 @@ class ManifestJsonParser(object): print("orientation: %s" % self.GetOrientation()) print("fullscreen: %s" % self.GetFullScreenFlag()) print('launch_screen.default.background_color: %s' % - self.GetLaunchScreenBackgroundColor('default')) + self.GetLaunchScreenBackgroundColor('default')) print('launch_screen.default.background_image: %s' % - self.GetLaunchScreenBackgroundImage('default')) + self.GetLaunchScreenBackgroundImage('default')) print('launch_screen.default.image: %s' % - self.GetLaunchScreenImage('default')) + self.GetLaunchScreenImage('default')) print('launch_screen.default.image_border: %s' % - self.GetLaunchScreenImageBorder('default')) + self.GetLaunchScreenImageBorder('default')) print('launch_screen.portrait.background_color: %s' % - self.GetLaunchScreenBackgroundColor('portrait')) + self.GetLaunchScreenBackgroundColor('portrait')) print('launch_screen.portrait.background_image: %s' % - self.GetLaunchScreenBackgroundImage('portrait')) + self.GetLaunchScreenBackgroundImage('portrait')) print('launch_screen.portrait.image: %s' % - self.GetLaunchScreenImage('portrait')) + self.GetLaunchScreenImage('portrait')) print('launch_screen.portrait.image_border: %s' % - self.GetLaunchScreenImageBorder('portrait')) + self.GetLaunchScreenImageBorder('portrait')) print('launch_screen.landscape.background_color: %s' % - self.GetLaunchScreenBackgroundColor('landscape')) + self.GetLaunchScreenBackgroundColor('landscape')) print('launch_screen.landscape.background_image: %s' % - self.GetLaunchScreenBackgroundImage('landscape')) + self.GetLaunchScreenBackgroundImage('landscape')) print('launch_screen.landscape.image: %s' % - self.GetLaunchScreenImage('landscape')) + self.GetLaunchScreenImage('landscape')) print('launch_screen.landscape.image_border: %s' % - self.GetLaunchScreenImageBorder('landscape')) + self.GetLaunchScreenImageBorder('landscape')) def GetAppName(self): """Return the application name.""" diff --git a/src/xwalk/application/browser/application_tizen.cc b/src/xwalk/application/browser/application_tizen.cc index cc8b7c5..0f2ba0b 100644 --- a/src/xwalk/application/browser/application_tizen.cc +++ b/src/xwalk/application/browser/application_tizen.cc @@ -123,6 +123,14 @@ void ApplicationTizen::Hide() { } } +void ApplicationTizen::Show() { + DCHECK(!runtimes_.empty()); + for (Runtime* runtime : runtimes_) { + if (auto window = runtime->window()) + window->Restore(); + } +} + bool ApplicationTizen::Launch(const LaunchParams& launch_params) { if (Application::Launch(launch_params)) { DCHECK(web_contents_); diff --git a/src/xwalk/application/browser/application_tizen.h b/src/xwalk/application/browser/application_tizen.h index 64767c3..6302ad8 100644 --- a/src/xwalk/application/browser/application_tizen.h +++ b/src/xwalk/application/browser/application_tizen.h @@ -27,6 +27,7 @@ class ApplicationTizen : // NOLINT public: virtual ~ApplicationTizen(); void Hide(); + void Show(); void Suspend(); void Resume(); diff --git a/src/xwalk/application/browser/linux/running_application_object.cc b/src/xwalk/application/browser/linux/running_application_object.cc index 2437f48..87877dc 100644 --- a/src/xwalk/application/browser/linux/running_application_object.cc +++ b/src/xwalk/application/browser/linux/running_application_object.cc @@ -269,6 +269,7 @@ void RunningApplicationObject::OnResume( } ToApplicationTizen(application_)->Resume(); + ToApplicationTizen(application_)->Show(); scoped_ptr response = dbus::Response::FromMethodCall(method_call); diff --git a/src/xwalk/application/common/tizen/application_storage_impl.cc b/src/xwalk/application/common/tizen/application_storage_impl.cc index 3736a56..693ccf2 100644 --- a/src/xwalk/application/common/tizen/application_storage_impl.cc +++ b/src/xwalk/application/common/tizen/application_storage_impl.cc @@ -20,7 +20,7 @@ namespace { ail_cb_ret_e appinfo_get_app_id_cb( - const ail_appinfo_h appinfo, void* user_data) { + const ail_appinfo_h appinfo, void* user_data, uid_t /*uid*/) { std::vector* app_ids = static_cast*>(user_data); char* app_id; diff --git a/src/xwalk/application/common/tizen/package_query.cc b/src/xwalk/application/common/tizen/package_query.cc index 1165554..0ad9df2 100644 --- a/src/xwalk/application/common/tizen/package_query.cc +++ b/src/xwalk/application/common/tizen/package_query.cc @@ -13,10 +13,10 @@ namespace { -typedef ail_cb_ret_e (*PropertyCallback)(const ail_appinfo_h, void*); +typedef ail_cb_ret_e (*PropertyCallback)(const ail_appinfo_h, void*, uid_t); ail_cb_ret_e callback_x_slp_exe_path(const ail_appinfo_h appinfo, - void* user_data) { + void* user_data, uid_t /*uid*/) { char* package_exec; ail_appinfo_get_str(appinfo, AIL_PROP_X_SLP_EXE_PATH, &package_exec); if (!package_exec) @@ -28,7 +28,7 @@ ail_cb_ret_e callback_x_slp_exe_path(const ail_appinfo_h appinfo, } ail_cb_ret_e callback_installed_time(const ail_appinfo_h appinfo, - void* user_data) { + void* user_data, uid_t /*uid*/) { int* installed_time = static_cast(user_data); ail_appinfo_get_int(appinfo, AIL_PROP_X_SLP_INSTALLEDTIME_INT, installed_time); diff --git a/src/xwalk/application/tools/tizen/xwalk_platform_installer.cc b/src/xwalk/application/tools/tizen/xwalk_platform_installer.cc index 967ea4f..f3079d9 100644 --- a/src/xwalk/application/tools/tizen/xwalk_platform_installer.cc +++ b/src/xwalk/application/tools/tizen/xwalk_platform_installer.cc @@ -6,6 +6,12 @@ #include #include + +#include +// logging and dlog uses same macro name +// to avoid warnings we need to undefine dlog's one +#undef LOG + #include #include diff --git a/src/xwalk/application/tools/tizen/xwalk_platform_installer.h b/src/xwalk/application/tools/tizen/xwalk_platform_installer.h index 5867ce2..31e175a 100644 --- a/src/xwalk/application/tools/tizen/xwalk_platform_installer.h +++ b/src/xwalk/application/tools/tizen/xwalk_platform_installer.h @@ -5,12 +5,12 @@ #ifndef XWALK_APPLICATION_TOOLS_TIZEN_XWALK_PLATFORM_INSTALLER_H_ #define XWALK_APPLICATION_TOOLS_TIZEN_XWALK_PLATFORM_INSTALLER_H_ -#include - #include #include "base/files/file_path.h" +struct pkgmgr_installer; + class PlatformInstaller { public: PlatformInstaller(); diff --git a/src/xwalk/packaging/crosswalk.spec b/src/xwalk/packaging/crosswalk.spec index b8c576a..88d9c84 100644 --- a/src/xwalk/packaging/crosswalk.spec +++ b/src/xwalk/packaging/crosswalk.spec @@ -16,7 +16,7 @@ %endif Name: crosswalk -Version: 10.38.212.0 +Version: 10.38.217.0 Release: 0 Summary: Chromium-based app runtime License: (BSD-3-Clause and LGPL-2.1+) @@ -140,6 +140,13 @@ cp -a src/xwalk/LICENSE LICENSE.xwalk %build +# Stop unconditionally passing -Wall to the compiler. Chromium has its own +# mechanisms for deciding which parts of the code need -Wall and which need it +# to be left out (since several pieces are built with -Werror). At least in +# M39, this is preventing the "rtc_base" target from being built because it +# does not expect -Wall to be passed to the compiler (see webrtc issue 3307). +export CXXFLAGS=`echo $CXXFLAGS | sed s,-Wall,,g` + # For ffmpeg on ia32. The original CFLAGS set by the gyp and config files in # src/third_party/ffmpeg already pass -O2 -fomit-frame-pointer, but Tizen's # CFLAGS end up appending -fno-omit-frame-pointer. See http://crbug.com/37246 diff --git a/src/xwalk/runtime/android/core/src/org/xwalk/core/SharedXWalkView.java b/src/xwalk/runtime/android/core/src/org/xwalk/core/SharedXWalkView.java index 2b83866..e63d754 100644 --- a/src/xwalk/runtime/android/core/src/org/xwalk/core/SharedXWalkView.java +++ b/src/xwalk/runtime/android/core/src/org/xwalk/core/SharedXWalkView.java @@ -39,7 +39,11 @@ public class SharedXWalkView extends XWalkView { initialized = true; } - public static boolean usesLibraryOutOfPackage() { - return ReflectionHelper.shouldUseLibrary(); + public static boolean containsLibrary() { + return !ReflectionHelper.shouldUseLibrary(); + } + + public static boolean isUsingLibrary() { + return ReflectionHelper.isUsingLibrary(); } } diff --git a/src/xwalk/runtime/android/core_internal/src/org/xwalk/core/internal/ReflectionHelper.java b/src/xwalk/runtime/android/core_internal/src/org/xwalk/core/internal/ReflectionHelper.java index 883a448..4aa5cfe 100644 --- a/src/xwalk/runtime/android/core_internal/src/org/xwalk/core/internal/ReflectionHelper.java +++ b/src/xwalk/runtime/android/core_internal/src/org/xwalk/core/internal/ReflectionHelper.java @@ -73,24 +73,49 @@ public class ReflectionHelper { private final static String LIBRARY_APK_PACKAGE = "org.xwalk.core"; /* Wrapper Only private static boolean sAllowCrossPackage = false; + private static boolean sAlreadyUsingLibrary = false; private static SharedXWalkExceptionHandler sExceptionHandler = null; static void setExceptionHandler(SharedXWalkExceptionHandler handler) { sExceptionHandler = handler; } - public static boolean shouldUseLibrary() { + static boolean isUsingLibrary() { + return sAlreadyUsingLibrary; + } + + static boolean shouldUseLibrary() { + if (sAlreadyUsingLibrary) return true; + // TODO(wang16): There are many other conditions here. // e.g. Whether application uses the ApplicationClass we provided, // Whether native library arch is correct. assert isWrapper(); + Class delegateClass = null; try { - ReflectionHelper.class.getClassLoader().loadClass( - INTERNAL_PACKAGE + "." + "ReflectionHelper"); - return false; + ClassLoader classLoader = ReflectionHelper.class.getClassLoader(); + delegateClass = classLoader.loadClass( + INTERNAL_PACKAGE + "." + "XWalkViewDelegate"); } catch (ClassNotFoundException e) { return true; } + if (delegateClass == null) return true; + try { + Method loadXWalkLibrary = delegateClass.getDeclaredMethod( + "loadXWalkLibrary", Context.class); + loadXWalkLibrary.invoke(null, (Context)null); + } catch (NoSuchMethodException e) { + return true; + } catch (IllegalArgumentException e) { + return true; + } catch (IllegalAccessException e) { + return true; + } catch (InvocationTargetException e) { + return true; + } catch (UnsatisfiedLinkError e) { + return true; + } + return false; } Wrapper Only */ @@ -121,6 +146,7 @@ public class ReflectionHelper { sBridgeContext = app.createPackageContext( LIBRARY_APK_PACKAGE, Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY); + sAlreadyUsingLibrary = true; } catch (PackageManager.NameNotFoundException e) { handleException(e); } diff --git a/src/xwalk/runtime/android/core_internal/src/org/xwalk/core/internal/XWalkContentsClientBridge.java b/src/xwalk/runtime/android/core_internal/src/org/xwalk/core/internal/XWalkContentsClientBridge.java index b00d31f..0755f6f 100644 --- a/src/xwalk/runtime/android/core_internal/src/org/xwalk/core/internal/XWalkContentsClientBridge.java +++ b/src/xwalk/runtime/android/core_internal/src/org/xwalk/core/internal/XWalkContentsClientBridge.java @@ -41,6 +41,7 @@ class XWalkContentsClientBridge extends XWalkContentsClient implements ContentViewDownloadDelegate { private static final String TAG = XWalkContentsClientBridge.class.getName(); private static final int NEW_XWALKVIEW_CREATED = 100; + private static final int NEW_ICON_DOWNLOAD = 101; private XWalkViewInternal mXWalkView; private XWalkUIClientInternal mXWalkUIClient; @@ -110,6 +111,10 @@ class XWalkContentsClientBridge extends XWalkContentsClient mXWalkView.completeWindowCreation(newXWalkView); break; + case NEW_ICON_DOWNLOAD: + String url = (String) msg.obj; + nativeDownloadIcon(mNativeContentsClientBridge, url); + break; default: throw new IllegalStateException(); } @@ -711,6 +716,17 @@ class XWalkContentsClientBridge extends XWalkContentsClient onScaleChanged(oldPageScaleFactor, mPageScaleFactor); } + @CalledByNative + public void onIconAvailable(String url) { + Message m = mUiThreadHandler.obtainMessage(NEW_ICON_DOWNLOAD, url); + mXWalkUIClient.onIconAvailable(mXWalkView, url, m); + } + + @CalledByNative + public void onReceivedIcon(String url, Bitmap icon) { + mXWalkUIClient.onReceivedIcon(mXWalkView, url, icon); + } + //-------------------------------------------------------------------------------------------- // Native methods //-------------------------------------------------------------------------------------------- @@ -729,4 +745,5 @@ class XWalkContentsClientBridge extends XWalkContentsClient int processId, int renderId, int mode_flags, String filepath, String displayName); private native void nativeOnFilesNotSelected(long nativeXWalkContentsClientBridge, int processId, int renderId, int mode_flags); + private native void nativeDownloadIcon(long nativeXWalkContentsClientBridge, String url); } diff --git a/src/xwalk/runtime/android/core_internal/src/org/xwalk/core/internal/XWalkUIClientInternal.java b/src/xwalk/runtime/android/core_internal/src/org/xwalk/core/internal/XWalkUIClientInternal.java index 72ee258..f184189 100644 --- a/src/xwalk/runtime/android/core_internal/src/org/xwalk/core/internal/XWalkUIClientInternal.java +++ b/src/xwalk/runtime/android/core_internal/src/org/xwalk/core/internal/XWalkUIClientInternal.java @@ -8,9 +8,11 @@ import android.app.Activity; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; +import android.graphics.Bitmap; import android.net.Uri; import android.os.Build.VERSION; import android.os.Build.VERSION_CODES; +import android.os.Message; import android.view.KeyEvent; import android.view.View; import android.view.WindowManager; @@ -78,8 +80,8 @@ public class XWalkUIClientInternal { /** * Request the host application to create a new window - * @param view The XWalkView from which the request for a new window originated - * @param initiator The request was initiated by a user gesture of javascript + * @param view The XWalkView which initiate the request for a new window + * @param initiator How the request was initiated * @param callback Callback when once a new XWalkView has been created * @return Return true if the host application will create a new window * @since 4.0 @@ -91,6 +93,28 @@ public class XWalkUIClientInternal { } /** + * Notify the host application that an icon is available, send the message to start the downloading + * @param view The XWalkView that icon belongs to + * @param url The icon url + * @param startDownload Message to initiate icon download + * @since 4.0 + */ + @XWalkAPI + public void onIconAvailable(XWalkViewInternal view, String url, Message startDownload) { + } + + /** + * Notify the host application of a new icon has been downloaded + * @param view The XWalkView that icon belongs to + * @param url The icon url + * @param icon The icon image + * @since 4.0 + */ + @XWalkAPI + public void onReceivedIcon(XWalkViewInternal view, String url, Bitmap icon) { + } + + /** * Request display and focus for this XWalkViewInternal. * @param view the owner XWalkViewInternal instance. * @since 1.0 diff --git a/src/xwalk/runtime/android/core_internal/src/org/xwalk/core/internal/XWalkViewDelegate.java b/src/xwalk/runtime/android/core_internal/src/org/xwalk/core/internal/XWalkViewDelegate.java index 238c43e..d61c82d 100644 --- a/src/xwalk/runtime/android/core_internal/src/org/xwalk/core/internal/XWalkViewDelegate.java +++ b/src/xwalk/runtime/android/core_internal/src/org/xwalk/core/internal/XWalkViewDelegate.java @@ -4,6 +4,7 @@ package org.xwalk.core.internal; +import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.IOException; @@ -33,6 +34,7 @@ import org.chromium.net.NetworkChangeNotifier; @JNINamespace("xwalk") class XWalkViewDelegate { private static boolean sInitialized = false; + private static boolean sLibraryLoaded = false; private static boolean sRunningOnIA = true; private static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "xwalkcore"; private static final String[] MANDATORY_PAKS = { @@ -77,11 +79,38 @@ class XWalkViewDelegate { } } + public static void loadXWalkLibrary(Context context) throws UnsatisfiedLinkError { + if (sLibraryLoaded) return; + + // If context is null, it's called from wrapper's ReflectionHelper to try + // loading native library within the package. No need to try load from library + // package in this case. + // If context's applicationContext is not the same package with itself, + // It's a cross package invoking, load core library from library apk. + // Only load the native library from /data/data if the Android version is + // lower than 4.2. Android enables a system path /data/app-lib to store native + // libraries starting from 4.2 and load them automatically. + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1 && context != null && + !context.getApplicationContext().getPackageName().equals(context.getPackageName())) { + for (String library : MANDATORY_LIBRARIES) { + System.load("/data/data/" + context.getPackageName() + "/lib/" + library); + } + } + loadLibrary(context); + + if (sRunningOnIA && !nativeIsLibraryBuiltForIA()) { + throw new UnsatisfiedLinkError(); + } + sLibraryLoaded = true; + } + public static void init(XWalkViewInternal xwalkView) throws UnsatisfiedLinkError { if (sInitialized) { return; } + loadXWalkLibrary(xwalkView.getContext()); + // Initialize the ActivityStatus. This is needed and used by many internal // features such as location provider to listen to activity status. ApplicationStatusManager.init(xwalkView.getActivity().getApplication()); @@ -105,23 +134,6 @@ class XWalkViewDelegate { CommandLine.init(readCommandLine(context.getApplicationContext())); } - // If context's applicationContext is not the same package with itself, - // It's a cross package invoking, load core library from library apk. - // Only load the native library from /data/data if the Android version is - // lower than 4.2. Android enables a system path /data/app-lib to store native - // libraries starting from 4.2 and load them automatically. - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1 && - !context.getApplicationContext().getPackageName().equals(context.getPackageName())) { - for (String library : MANDATORY_LIBRARIES) { - System.load("/data/data/" + context.getPackageName() + "/lib/" + library); - } - } - loadLibrary(context); - - if (sRunningOnIA && !nativeIsLibraryBuiltForIA()) { - throw new UnsatisfiedLinkError(); - } - ResourceExtractor.setMandatoryPaksToExtract(MANDATORY_PAKS); final int resourcesListResId = context.getResources().getIdentifier( XWALK_RESOURCES_LIST_RES_NAME, "array", context.getPackageName()); @@ -232,5 +244,21 @@ class XWalkViewDelegate { static { sRunningOnIA = Build.CPU_ABI.equalsIgnoreCase("x86"); + if (!sRunningOnIA) { + // This is not the final decision yet. + // With latest Houdini, an app with ARM binary will see system abi as if it's running on + // arm device. Here needs some further check for real system abi. + try { + Process process = Runtime.getRuntime().exec("getprop ro.product.cpu.abi"); + InputStreamReader ir = new InputStreamReader(process.getInputStream()); + BufferedReader input = new BufferedReader(ir); + String abi = input.readLine(); + sRunningOnIA = abi.contains("x86"); + input.close(); + ir.close(); + } catch (IOException e) { + Log.w(TAG, Log.getStackTraceString(e)); + } + } } } diff --git a/src/xwalk/runtime/browser/android/xwalk_content.cc b/src/xwalk/runtime/browser/android/xwalk_content.cc index 4450014..a7fb148 100644 --- a/src/xwalk/runtime/browser/android/xwalk_content.cc +++ b/src/xwalk/runtime/browser/android/xwalk_content.cc @@ -142,10 +142,10 @@ void XWalkContent::SetJavaPeers(JNIEnv* env, DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); java_ref_ = JavaObjectWeakGlobalRef(env, xwalk_content); - web_contents_delegate_.reset( - new XWalkWebContentsDelegate(env, web_contents_delegate)); - contents_client_bridge_.reset( - new XWalkContentsClientBridge(env, contents_client_bridge)); + web_contents_delegate_.reset(new XWalkWebContentsDelegate( + env, web_contents_delegate)); + contents_client_bridge_.reset(new XWalkContentsClientBridge( + env, contents_client_bridge, web_contents_.get())); web_contents_->SetUserData( kXWalkContentUserDataKey, new XWalkContentUserData(this)); diff --git a/src/xwalk/runtime/browser/android/xwalk_contents_client_bridge.cc b/src/xwalk/runtime/browser/android/xwalk_contents_client_bridge.cc index 992db8b..d5b30af 100644 --- a/src/xwalk/runtime/browser/android/xwalk_contents_client_bridge.cc +++ b/src/xwalk/runtime/browser/android/xwalk_contents_client_bridge.cc @@ -60,11 +60,15 @@ ScopedPtrHashMap g_notification_map_; } // namespace -XWalkContentsClientBridge::XWalkContentsClientBridge(JNIEnv* env, jobject obj) - : java_ref_(env, obj) { +XWalkContentsClientBridge::XWalkContentsClientBridge( + JNIEnv* env, jobject obj, + content::WebContents* web_contents) + : java_ref_(env, obj), + icon_helper_(new XWalkIconHelper(web_contents)) { DCHECK(obj); Java_XWalkContentsClientBridge_setNativeContentsClientBridge( env, obj, reinterpret_cast(this)); + icon_helper_->SetListener(this); } XWalkContentsClientBridge::~XWalkContentsClientBridge() { @@ -433,6 +437,38 @@ void XWalkContentsClientBridge::OnFilesNotSelected( files, static_cast(mode)); } +void XWalkContentsClientBridge::DownloadIcon(JNIEnv* env, + jobject obj, + jstring url) { + std::string url_str = base::android::ConvertJavaStringToUTF8(env, url); + icon_helper_->DownloadIcon(GURL(url_str)); +} + +void XWalkContentsClientBridge::OnIconAvailable(const GURL& icon_url) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef obj = java_ref_.get(env); + + ScopedJavaLocalRef jurl( + ConvertUTF8ToJavaString(env, icon_url.spec())); + + Java_XWalkContentsClientBridge_onIconAvailable(env, obj.obj(), jurl.obj()); +} + +void XWalkContentsClientBridge::OnReceivedIcon(const GURL& icon_url, + const SkBitmap& bitmap) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef obj = java_ref_.get(env); + + ScopedJavaLocalRef jurl( + ConvertUTF8ToJavaString(env, icon_url.spec())); + ScopedJavaLocalRef jicon = gfx::ConvertToJavaBitmap(&bitmap); + + Java_XWalkContentsClientBridge_onReceivedIcon( + env, obj.obj(), jurl.obj(), jicon.obj()); +} + bool RegisterXWalkContentsClientBridge(JNIEnv* env) { return RegisterNativesImpl(env) >= 0; } diff --git a/src/xwalk/runtime/browser/android/xwalk_contents_client_bridge.h b/src/xwalk/runtime/browser/android/xwalk_contents_client_bridge.h index a1e6ed9..18ee50b 100644 --- a/src/xwalk/runtime/browser/android/xwalk_contents_client_bridge.h +++ b/src/xwalk/runtime/browser/android/xwalk_contents_client_bridge.h @@ -17,6 +17,7 @@ #include "base/id_map.h" #include "content/public/browser/javascript_dialog_manager.h" #include "xwalk/runtime/browser/android/xwalk_contents_client_bridge_base.h" +#include "xwalk/runtime/browser/android/xwalk_icon_helper.h" namespace gfx { class Size; @@ -26,6 +27,10 @@ namespace net { class X509Certificate; } +namespace content { +class WebContents; +} + class SkBitmap; namespace xwalk { @@ -37,9 +42,11 @@ namespace xwalk { // indirect refs from the Application (via callbacks) and so can outlive // XWalkView, this class notifies it before being destroyed and to nullify // any references. -class XWalkContentsClientBridge : public XWalkContentsClientBridgeBase { +class XWalkContentsClientBridge : public XWalkContentsClientBridgeBase , + public XWalkIconHelper::Listener { public: - XWalkContentsClientBridge(JNIEnv* env, jobject obj); + XWalkContentsClientBridge(JNIEnv* env, jobject obj, + content::WebContents* web_contents); virtual ~XWalkContentsClientBridge(); // XWalkContentsClientBridgeBase implementation @@ -100,6 +107,11 @@ class XWalkContentsClientBridge : public XWalkContentsClientBridgeBase { int mode, jstring filepath, jstring display_name); void OnFilesNotSelected( JNIEnv*, jobject, int process_id, int render_id, int mode); + void DownloadIcon(JNIEnv* env, jobject obj, jstring url); + + // XWalkIconHelper::Listener Interface + virtual void OnIconAvailable(const GURL& icon_url); + virtual void OnReceivedIcon(const GURL& icon_url, const SkBitmap& bitmap); private: JavaObjectWeakGlobalRef java_ref_; @@ -114,6 +126,8 @@ class XWalkContentsClientBridge : public XWalkContentsClientBridgeBase { typedef std::map NotificationDownloadRequestIdMap; NotificationDownloadRequestIdMap downloading_icon_notifications_; + + scoped_ptr icon_helper_; }; bool RegisterXWalkContentsClientBridge(JNIEnv* env); diff --git a/src/xwalk/runtime/browser/android/xwalk_icon_helper.cc b/src/xwalk/runtime/browser/android/xwalk_icon_helper.cc new file mode 100644 index 0000000..804f043 --- /dev/null +++ b/src/xwalk/runtime/browser/android/xwalk_icon_helper.cc @@ -0,0 +1,76 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Copyright (c) 2014 Intel Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "xwalk/runtime/browser/android/xwalk_icon_helper.h" + +#include "base/bind.h" +#include "base/callback.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/web_contents.h" +#include "content/public/common/favicon_url.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "ui/gfx/size.h" + +using content::BrowserThread; +using content::WebContents; + +namespace xwalk { + +XWalkIconHelper::XWalkIconHelper(WebContents* web_contents) + : content::WebContentsObserver(web_contents), + listener_(NULL) { +} + +XWalkIconHelper::~XWalkIconHelper() { +} + +void XWalkIconHelper::SetListener(Listener* listener) { + listener_ = listener; +} + +void XWalkIconHelper::DownloadIcon(const GURL& icon_url) { + web_contents()->DownloadImage(icon_url, true, 0, + base::Bind(&XWalkIconHelper::DownloadFaviconCallback, + base::Unretained(this))); +} + +void XWalkIconHelper::DidUpdateFaviconURL( + const std::vector& candidates) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + for (std::vector::const_iterator i = candidates.begin(); + i != candidates.end(); ++i) { + if (!i->icon_url.is_valid()) + continue; + + switch (i->icon_type) { + case content::FaviconURL::FAVICON: + if (listener_) listener_->OnIconAvailable(i->icon_url); + break; + case content::FaviconURL::TOUCH_ICON: + break; + case content::FaviconURL::TOUCH_PRECOMPOSED_ICON: + break; + case content::FaviconURL::INVALID_ICON: + break; + default: + NOTREACHED(); + break; + } + } +} + +void XWalkIconHelper::DownloadFaviconCallback( + int id, + int http_status_code, + const GURL& image_url, + const std::vector& bitmaps, + const std::vector& original_bitmap_sizes) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + if (http_status_code == 404 || bitmaps.size() == 0) return; + + if (listener_) listener_->OnReceivedIcon(image_url, bitmaps[0]); +} + +} // namespace xwalk diff --git a/src/xwalk/runtime/browser/android/xwalk_icon_helper.h b/src/xwalk/runtime/browser/android/xwalk_icon_helper.h new file mode 100644 index 0000000..0bff471 --- /dev/null +++ b/src/xwalk/runtime/browser/android/xwalk_icon_helper.h @@ -0,0 +1,63 @@ +// Copyright (c) 2014 Intel Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef XWALK_RUNTIME_BROWSER_ANDROID_XWALK_ICON_HELPER_H_ +#define XWALK_RUNTIME_BROWSER_ANDROID_XWALK_ICON_HELPER_H_ + +#include +#include +#include "content/public/browser/web_contents_observer.h" +#include "url/gurl.h" + +class SkBitmap; + +namespace content { +struct FaviconURL; +class WebContents; +} + +namespace gfx { +class Size; +} + +namespace xwalk { + +class XWalkIconHelper : public content::WebContentsObserver { + public: + class Listener { + public: + virtual void OnIconAvailable(const GURL& icon_url) = 0; + virtual void OnReceivedIcon(const GURL& icon_url, + const SkBitmap& bitmap) = 0; + protected: + virtual ~Listener() {} + }; + + explicit XWalkIconHelper(content::WebContents* web_contents); + virtual ~XWalkIconHelper(); + + void SetListener(Listener* listener); + + void DownloadIcon(const GURL& icon_url); + + // From WebContentsObserver + virtual void DidUpdateFaviconURL( + const std::vector& candidates) OVERRIDE; + + void DownloadFaviconCallback( + int id, + int http_status_code, + const GURL& image_url, + const std::vector& bitmaps, + const std::vector& original_bitmap_sizes); + + private: + Listener* listener_; + + DISALLOW_COPY_AND_ASSIGN(XWalkIconHelper); +}; + +} // namespace xwalk + +#endif // XWALK_RUNTIME_BROWSER_ANDROID_XWALK_ICON_HELPER_H_ diff --git a/src/xwalk/test/android/core/javatests/src/org/xwalk/core/xwview/test/OnFullscreenToggledTest.java b/src/xwalk/test/android/core/javatests/src/org/xwalk/core/xwview/test/OnFullscreenToggledTest.java new file mode 100644 index 0000000..4754def --- /dev/null +++ b/src/xwalk/test/android/core/javatests/src/org/xwalk/core/xwview/test/OnFullscreenToggledTest.java @@ -0,0 +1,35 @@ +// Copyright (c) 2014 Intel Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.xwalk.core.xwview.test; + +import android.test.suitebuilder.annotation.SmallTest; + +import org.chromium.base.test.util.Feature; + +/** + * Test suite for OnFullscreenToggled(). + */ +public class OnFullscreenToggledTest extends XWalkViewTestBase { + private TestHelperBridge.OnFullscreenToggledHelper mOnFullscreenToggledHelper; + + @Override + public void setUp() throws Exception { + super.setUp(); + mOnFullscreenToggledHelper = mTestHelperBridge.getOnFullscreenToggledHelper(); + } + + @SmallTest + @Feature({"OnFullscreenToggled"}) + public void testOnFullscreenToggled() throws Throwable { + final String name = "fullscreen_togged.html"; + String fileContent = getFileContent(name); + int count = mOnFullscreenToggledHelper.getCallCount(); + + loadDataSync(null, fileContent, "text/html", false); + clickOnElementId("fullscreen_toggled", null); + mOnFullscreenToggledHelper.waitForCallback(count); + assertTrue(mOnFullscreenToggledHelper.getEnterFullscreen()); + } +} diff --git a/src/xwalk/test/android/core/javatests/src/org/xwalk/core/xwview/test/OnJavascriptModalDialogTest.java b/src/xwalk/test/android/core/javatests/src/org/xwalk/core/xwview/test/OnJavascriptModalDialogTest.java new file mode 100644 index 0000000..d14b983 --- /dev/null +++ b/src/xwalk/test/android/core/javatests/src/org/xwalk/core/xwview/test/OnJavascriptModalDialogTest.java @@ -0,0 +1,35 @@ +// Copyright (c) 2014 Intel Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.xwalk.core.xwview.test; + +import android.test.suitebuilder.annotation.SmallTest; + +import org.chromium.base.test.util.Feature; + +/** + * Test suite for OnJavascriptModalDialog(). + */ +public class OnJavascriptModalDialogTest extends XWalkViewTestBase { + private TestHelperBridge.OnJavascriptModalDialogHelper mOnJavascriptModalDialogHelper; + + @Override + public void setUp() throws Exception { + super.setUp(); + mOnJavascriptModalDialogHelper = mTestHelperBridge.getOnJavascriptModalDialogHelper(); + } + + @SmallTest + @Feature({"OnJavascriptModalDialog"}) + public void testOnJavascriptModalDialog() throws Throwable { + final String url = "js_modal_dialog.html"; + String fileContent = getFileContent(url); + int count = mOnJavascriptModalDialogHelper.getCallCount(); + + loadDataSync(null, fileContent, "text/html", false); + clickOnElementId("js_modal_dialog", null); + mOnJavascriptModalDialogHelper.waitForCallback(count); + assertEquals("hello", mOnJavascriptModalDialogHelper.getMessage()); + } +} diff --git a/src/xwalk/test/android/core/javatests/src/org/xwalk/core/xwview/test/OnPageLoadStartedTest.java b/src/xwalk/test/android/core/javatests/src/org/xwalk/core/xwview/test/OnPageLoadStartedTest.java new file mode 100644 index 0000000..f80cfc2 --- /dev/null +++ b/src/xwalk/test/android/core/javatests/src/org/xwalk/core/xwview/test/OnPageLoadStartedTest.java @@ -0,0 +1,65 @@ +// Copyright (c) 2014 Intel Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.xwalk.core.xwview.test; + +import android.test.suitebuilder.annotation.MediumTest; + +import org.chromium.base.test.util.Feature; +import org.chromium.content.browser.test.util.TestCallbackHelperContainer; +import org.chromium.net.test.util.TestWebServer; + +/** + * Tests for the XWalkUIClient.onPageLoadStarted() method. + */ +public class OnPageLoadStartedTest extends XWalkViewTestBase { + TestCallbackHelperContainer.OnPageStartedHelper mOnPageStartedHelper; + + public void setUp() throws Exception { + super.setUp(); + mOnPageStartedHelper = mTestHelperBridge.getOnPageStartedHelper(); + } + + @MediumTest + @Feature({"OnPageLoadStarted"}) + public void testOnPageLoadStartedWithLocalUrl() throws Throwable { + String url = "file:///android_asset/www/index.html"; + int currentCallCount = mOnPageStartedHelper.getCallCount(); + loadUrlAsync(url); + + mOnPageStartedHelper.waitForCallback(currentCallCount); + assertEquals(url, mOnPageStartedHelper.getUrl()); + } + + @MediumTest + @Feature({"OnPageLoadStarted"}) + public void testOnPageLoadStartedWithServer() throws Throwable { + TestWebServer webServer = null; + try { + webServer = new TestWebServer(false); + final String testHtml = "HeaderBody"; + final String testPath = "/test.html"; + + final String testUrl = webServer.setResponse(testPath, testHtml, null); + int currentCallCount = mOnPageStartedHelper.getCallCount(); + loadUrlAsync(testUrl); + + mOnPageStartedHelper.waitForCallback(currentCallCount); + assertEquals(testUrl, mOnPageStartedHelper.getUrl()); + } finally { + if (webServer != null) webServer.shutdown(); + } + } + + @MediumTest + @Feature({"OnPageLoadStarted"}) + public void testOnPageLoadStartedWithInvalidUrl() throws Throwable { + String url = "http://this.url.is.invalid/"; + int currentCallCount = mOnPageStartedHelper.getCallCount(); + loadUrlAsync(url); + + mOnPageStartedHelper.waitForCallback(currentCallCount); + assertEquals(url, mOnPageStartedHelper.getUrl()); + } +} diff --git a/src/xwalk/test/android/core/javatests/src/org/xwalk/core/xwview/test/OnPageLoadStoppedTest.java b/src/xwalk/test/android/core/javatests/src/org/xwalk/core/xwview/test/OnPageLoadStoppedTest.java new file mode 100644 index 0000000..9602b56 --- /dev/null +++ b/src/xwalk/test/android/core/javatests/src/org/xwalk/core/xwview/test/OnPageLoadStoppedTest.java @@ -0,0 +1,119 @@ +// Copyright (c) 2014 Intel Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.xwalk.core.xwview.test; + +import android.test.suitebuilder.annotation.MediumTest; + +import java.util.concurrent.TimeUnit; + +import org.chromium.base.test.util.Feature; +import org.chromium.content.browser.test.util.TestCallbackHelperContainer; +import org.chromium.net.test.util.TestWebServer; + +import org.xwalk.core.XWalkUIClient.LoadStatus; + +import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout; + +/** + * Tests for the XWalkUIClient.onPageLoadStopped() method. + */ +public class OnPageLoadStoppedTest extends XWalkViewTestBase { + private static final long WAIT_TIMEOUT_MS = scaleTimeout(2000); + TestWebServer mWebServer = null; + TestCallbackHelperContainer.OnPageFinishedHelper mOnPageFinishedHelper; + TestCallbackHelperContainer.OnReceivedErrorHelper mOnReceivedErrorHelper; + TestCallbackHelperContainer.OnPageStartedHelper mOnPageStartedHelper; + + public void setUp() throws Exception { + super.setUp(); + mWebServer = new TestWebServer(false); + mOnPageFinishedHelper = mTestHelperBridge.getOnPageFinishedHelper(); + mOnReceivedErrorHelper = mTestHelperBridge.getOnReceivedErrorHelper(); + mOnPageStartedHelper = mTestHelperBridge.getOnPageStartedHelper(); + } + + @Override + protected void tearDown() throws Exception { + mWebServer.shutdown(); + super.tearDown(); + } + + @MediumTest + @Feature({"OnPageLoadStopped"}) + public void testOnPageLoadStoppedWithLocalUrl() throws Throwable { + String url = "file:///android_asset/www/index.html"; + int currentCallCount = mOnPageFinishedHelper.getCallCount(); + loadUrlAsync(url); + + mOnPageFinishedHelper.waitForCallback(currentCallCount); + assertEquals(url, mOnPageFinishedHelper.getUrl()); + assertEquals(LoadStatus.FINISHED, mTestHelperBridge.getLoadStatus()); + } + + @MediumTest + @Feature({"OnPageLoadStopped"}) + public void testOnPageLoadStoppedWithServer() throws Throwable { + final String testHtml = "HeaderBody"; + final String testPath = "/test.html"; + + final String testUrl = mWebServer.setResponse(testPath, testHtml, null); + int currentCallCount = mOnPageFinishedHelper.getCallCount(); + loadUrlAsync(testUrl); + + mOnPageFinishedHelper.waitForCallback(currentCallCount); + assertEquals(testUrl, mOnPageFinishedHelper.getUrl()); + assertEquals(LoadStatus.FINISHED, mTestHelperBridge.getLoadStatus()); + } + + @MediumTest + @Feature({"OnPageLoadStopped"}) + public void testOnPageLoadStoppedWithData() throws Throwable { + final String name = "index.html"; + String fileContent = getFileContent(name); + int currentCallCount = mOnPageFinishedHelper.getCallCount(); + loadDataAsync(null, fileContent, "text/html", false); + + mOnPageFinishedHelper.waitForCallback(currentCallCount); + assertEquals("about:blank", mOnPageFinishedHelper.getUrl()); + assertEquals(LoadStatus.FINISHED, mTestHelperBridge.getLoadStatus()); + } + + @MediumTest + @Feature({"OnPageLoadStopped"}) + public void testOnPageLoadStoppedWithInvalidUrl() throws Throwable { + String url = "http://localhost/non_existent"; + int currentCallCount = mOnPageFinishedHelper.getCallCount(); + int onReceivedErrorCallCount = mOnReceivedErrorHelper.getCallCount(); + assertEquals(0, mOnReceivedErrorHelper.getCallCount()); + loadUrlAsync(url); + + mOnReceivedErrorHelper.waitForCallback(onReceivedErrorCallCount, + 1, WAIT_TIMEOUT_MS, + TimeUnit.MILLISECONDS); + mOnPageFinishedHelper.waitForCallback(currentCallCount, + 1, WAIT_TIMEOUT_MS, + TimeUnit.MILLISECONDS); + assertEquals(1, mOnReceivedErrorHelper.getCallCount()); + assertEquals(url, mOnPageFinishedHelper.getUrl()); + assertEquals(LoadStatus.FAILED, mTestHelperBridge.getLoadStatus()); + } + + @MediumTest + @Feature({"OnPageLoadStopped"}) + public void testOnPageLoadStoppedWithStopLoading() throws Throwable { + final String testHtml = "HeaderBody"; + final String testPath = "/test.html"; + + final String testUrl = mWebServer.setResponse(testPath, testHtml, null); + int currentCallCount = mOnPageFinishedHelper.getCallCount(); + int startedCount = mOnPageStartedHelper.getCallCount(); + loadUrlAsync(testUrl); + mOnPageStartedHelper.waitForCallback(startedCount); + stopLoading(); + mOnPageFinishedHelper.waitForCallback(currentCallCount); + assertEquals(testUrl, mOnPageFinishedHelper.getUrl()); + assertEquals(LoadStatus.CANCELLED, mTestHelperBridge.getLoadStatus()); + } +} diff --git a/src/xwalk/test/android/core/javatests/src/org/xwalk/core/xwview/test/OnUnhandledKeyEventTest.java b/src/xwalk/test/android/core/javatests/src/org/xwalk/core/xwview/test/OnUnhandledKeyEventTest.java new file mode 100644 index 0000000..c457f1a --- /dev/null +++ b/src/xwalk/test/android/core/javatests/src/org/xwalk/core/xwview/test/OnUnhandledKeyEventTest.java @@ -0,0 +1,56 @@ +// Copyright (c) 2014 Intel Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.xwalk.core.xwview.test; + +import android.test.suitebuilder.annotation.SmallTest; +import android.view.KeyEvent; + +import org.chromium.base.test.util.Feature; +import org.xwalk.core.XWalkUIClient; +import org.xwalk.core.XWalkView; + +/** + * Test suite for onUnhandledKeyEvent(). + */ +public class OnUnhandledKeyEventTest extends XWalkViewTestBase { + TestHelperBridge.OverrideOrUnhandledKeyEventHelper mOverrideOrUnhandledKeyEventHelper; + + class TestXWalkUIClientForKeyEvent extends XWalkUIClient { + public TestXWalkUIClientForKeyEvent() { + super(getXWalkView()); + } + + @Override + public boolean shouldOverrideKeyEvent(XWalkView view, KeyEvent event) { + return false; + } + + @Override + public void onUnhandledKeyEvent(XWalkView view, KeyEvent event) { + mTestHelperBridge.overrideOrUnhandledKeyEvent(event); + } + } + + @Override + public void setUp() throws Exception { + super.setUp(); + mOverrideOrUnhandledKeyEventHelper = mTestHelperBridge.getOverrideOrUnhandledKeyEventHelper(); + setUIClient(new TestXWalkUIClientForKeyEvent()); + } + + @SmallTest + @Feature({"onUnhandledKeyEvent"}) + public void testOnUnhandledKeyEvent() throws Throwable { + final String name = "index.html"; + String fileContent = getFileContent(name); + int count = mOverrideOrUnhandledKeyEventHelper.getCallCount(); + loadDataAsync(null, fileContent, "text/html", false); + simulateKeyAction(KeyEvent.ACTION_UP); + mOverrideOrUnhandledKeyEventHelper.waitForCallback(count); + + KeyEvent event = mOverrideOrUnhandledKeyEventHelper.getKeyEvent(); + assertTrue(KeyEvent.ACTION_UP == event.getAction()); + } +} diff --git a/src/xwalk/test/android/core/javatests/src/org/xwalk/core/xwview/test/OpenFileChooserTest.java b/src/xwalk/test/android/core/javatests/src/org/xwalk/core/xwview/test/OpenFileChooserTest.java new file mode 100644 index 0000000..d21edd3 --- /dev/null +++ b/src/xwalk/test/android/core/javatests/src/org/xwalk/core/xwview/test/OpenFileChooserTest.java @@ -0,0 +1,35 @@ +// Copyright (c) 2014 Intel Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.xwalk.core.xwview.test; + +import android.test.suitebuilder.annotation.SmallTest; + +import org.chromium.base.test.util.Feature; + +/** + * Test suite for OpenFileChooser(). + */ +public class OpenFileChooserTest extends XWalkViewTestBase { + private TestHelperBridge.OpenFileChooserHelper mOpenFileChooserHelper; + + @Override + public void setUp() throws Exception { + super.setUp(); + mOpenFileChooserHelper = mTestHelperBridge.getOpenFileChooserHelper(); + } + + @SmallTest + @Feature({"OpenFileChooser"}) + public void testOpenFileChooser() throws Throwable { + final String name = "file_chooser.html"; + String fileContent = getFileContent(name); + int count = mOpenFileChooserHelper.getCallCount(); + + loadDataSync(null, fileContent, "text/html", false); + clickOnElementId("upload_input", null); + mOpenFileChooserHelper.waitForCallback(count); + assertNotNull(mOpenFileChooserHelper.getCallback()); + } +} diff --git a/src/xwalk/test/android/core/javatests/src/org/xwalk/core/xwview/test/ShouldOverrideKeyEventTest.java b/src/xwalk/test/android/core/javatests/src/org/xwalk/core/xwview/test/ShouldOverrideKeyEventTest.java new file mode 100644 index 0000000..05ab4a8 --- /dev/null +++ b/src/xwalk/test/android/core/javatests/src/org/xwalk/core/xwview/test/ShouldOverrideKeyEventTest.java @@ -0,0 +1,38 @@ +// Copyright (c) 2014 Intel Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.xwalk.core.xwview.test; + +import android.test.suitebuilder.annotation.SmallTest; +import android.view.KeyEvent; + +import org.chromium.base.test.util.Feature; + +/** + * Test suite for shouldOverrideKeyEvent(). + */ +public class ShouldOverrideKeyEventTest extends XWalkViewTestBase { + TestHelperBridge.OverrideOrUnhandledKeyEventHelper mOverrideOrUnhandledKeyEventHelper; + + @Override + public void setUp() throws Exception { + super.setUp(); + mOverrideOrUnhandledKeyEventHelper = mTestHelperBridge.getOverrideOrUnhandledKeyEventHelper(); + } + + @SmallTest + @Feature({"ShouldOverrideKeyEvent"}) + public void testShouldOverrideKeyEvent() throws Throwable { + final String name = "index.html"; + String fileContent = getFileContent(name); + int count = mOverrideOrUnhandledKeyEventHelper.getCallCount(); + + loadDataAsync(null, fileContent, "text/html", false); + simulateKeyAction(KeyEvent.ACTION_DOWN); + mOverrideOrUnhandledKeyEventHelper.waitForCallback(count); + + KeyEvent event = mOverrideOrUnhandledKeyEventHelper.getKeyEvent(); + assertTrue(KeyEvent.ACTION_DOWN == event.getAction()); + } +} diff --git a/src/xwalk/test/android/core/javatests/src/org/xwalk/core/xwview/test/TestHelperBridge.java b/src/xwalk/test/android/core/javatests/src/org/xwalk/core/xwview/test/TestHelperBridge.java index 90f615e..a5bed93 100644 --- a/src/xwalk/test/android/core/javatests/src/org/xwalk/core/xwview/test/TestHelperBridge.java +++ b/src/xwalk/test/android/core/javatests/src/org/xwalk/core/xwview/test/TestHelperBridge.java @@ -5,7 +5,9 @@ package org.xwalk.core.xwview.test; +import android.net.Uri; import android.util.Log; +import android.view.KeyEvent; import android.webkit.ValueCallback; import android.webkit.WebResourceResponse; @@ -22,6 +24,7 @@ import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnPage import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnPageStartedHelper; import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnReceivedErrorHelper; +import org.xwalk.core.XWalkUIClient.LoadStatus; import org.xwalk.core.XWalkView; class TestHelperBridge { @@ -220,7 +223,64 @@ class TestHelperBridge { } } + public class OnJavascriptModalDialogHelper extends CallbackHelper { + private String mMessage; + + public String getMessage() { + assert getCallCount() > 0; + return mMessage; + } + + public void notifyCalled(String message) { + mMessage = message; + notifyCalled(); + } + } + + public class OpenFileChooserHelper extends CallbackHelper { + private ValueCallback mCallback; + + public ValueCallback getCallback() { + assert getCallCount() > 0; + return mCallback; + } + + public void notifyCalled(ValueCallback callback) { + mCallback = callback; + notifyCalled(); + } + } + + public class OnFullscreenToggledHelper extends CallbackHelper { + private boolean mEnterFullscreen = false; + + public boolean getEnterFullscreen() { + assert getCallCount() > 0; + return mEnterFullscreen; + } + + public void notifyCalled(boolean enterFullscreen) { + mEnterFullscreen = enterFullscreen; + notifyCalled(); + } + } + + public class OverrideOrUnhandledKeyEventHelper extends CallbackHelper { + private KeyEvent mEvent; + + public KeyEvent getKeyEvent() { + assert getCallCount() > 0; + return mEvent; + } + + public void notifyCalled(KeyEvent event) { + mEvent = event; + notifyCalled(); + } + } + private String mChangedTitle; + private LoadStatus mLoadStatus; private final OnPageStartedHelper mOnPageStartedHelper; private final OnPageFinishedHelper mOnPageFinishedHelper; private final OnReceivedErrorHelper mOnReceivedErrorHelper; @@ -235,6 +295,10 @@ class TestHelperBridge { private final ShouldOverrideUrlLoadingHelper mShouldOverrideUrlLoadingHelper; private final OnScaleChangedHelper mOnScaleChangedHelper; private final OnRequestFocusHelper mOnRequestFocusHelper; + private final OnJavascriptModalDialogHelper mOnJavascriptModalDialogHelper; + private final OpenFileChooserHelper mOpenFileChooserHelper; + private final OnFullscreenToggledHelper mOnFullscreenToggledHelper; + private final OverrideOrUnhandledKeyEventHelper mOverrideOrUnhandledKeyEventHelper; public TestHelperBridge() { mOnPageStartedHelper = new OnPageStartedHelper(); @@ -249,6 +313,10 @@ class TestHelperBridge { mShouldOverrideUrlLoadingHelper = new ShouldOverrideUrlLoadingHelper(); mOnScaleChangedHelper = new OnScaleChangedHelper(); mOnRequestFocusHelper = new OnRequestFocusHelper(); + mOnJavascriptModalDialogHelper = new OnJavascriptModalDialogHelper(); + mOpenFileChooserHelper = new OpenFileChooserHelper(); + mOnFullscreenToggledHelper = new OnFullscreenToggledHelper(); + mOverrideOrUnhandledKeyEventHelper = new OverrideOrUnhandledKeyEventHelper(); } public OnPageStartedHelper getOnPageStartedHelper() { @@ -299,6 +367,22 @@ class TestHelperBridge { return mOnRequestFocusHelper; } + public OnJavascriptModalDialogHelper getOnJavascriptModalDialogHelper() { + return mOnJavascriptModalDialogHelper; + } + + public OpenFileChooserHelper getOpenFileChooserHelper() { + return mOpenFileChooserHelper; + } + + public OnFullscreenToggledHelper getOnFullscreenToggledHelper() { + return mOnFullscreenToggledHelper; + } + + public OverrideOrUnhandledKeyEventHelper getOverrideOrUnhandledKeyEventHelper() { + return mOverrideOrUnhandledKeyEventHelper; + } + public void onTitleChanged(String title) { mChangedTitle = title; mOnTitleUpdatedHelper.notifyCalled(title); @@ -312,10 +396,15 @@ class TestHelperBridge { mOnPageStartedHelper.notifyCalled(url); } - public void onPageFinished(String url) { + public void onPageFinished(String url, LoadStatus status) { + mLoadStatus = status; mOnPageFinishedHelper.notifyCalled(url); } + public LoadStatus getLoadStatus() { + return mLoadStatus; + } + public void onReceivedLoadError(int errorCode, String description, String failingUrl) { mOnReceivedErrorHelper.notifyCalled(errorCode, description, failingUrl); } @@ -352,4 +441,22 @@ class TestHelperBridge { public void onRequestFocus() { mOnRequestFocusHelper.notifyCalled(true); } + + public boolean onJavascriptModalDialog(String message) { + mOnJavascriptModalDialogHelper.notifyCalled(message); + return true; + } + + public void openFileChooser(ValueCallback uploadFile) { + mOpenFileChooserHelper.notifyCalled(uploadFile); + } + + public void onFullscreenToggled(boolean enterFullscreen) { + mOnFullscreenToggledHelper.notifyCalled(enterFullscreen); + } + + public boolean overrideOrUnhandledKeyEvent(KeyEvent event) { + mOverrideOrUnhandledKeyEventHelper.notifyCalled(event); + return true; + } } diff --git a/src/xwalk/test/android/core/javatests/src/org/xwalk/core/xwview/test/XWalkViewTestBase.java b/src/xwalk/test/android/core/javatests/src/org/xwalk/core/xwview/test/XWalkViewTestBase.java index 01ae91b..6537905 100644 --- a/src/xwalk/test/android/core/javatests/src/org/xwalk/core/xwview/test/XWalkViewTestBase.java +++ b/src/xwalk/test/android/core/javatests/src/org/xwalk/core/xwview/test/XWalkViewTestBase.java @@ -7,8 +7,11 @@ package org.xwalk.core.xwview.test; import android.app.Activity; import android.content.Context; +import android.net.Uri; import android.test.ActivityInstrumentationTestCase2; import android.util.Log; +import android.view.KeyEvent; +import android.webkit.ValueCallback; import android.webkit.WebResourceResponse; import java.io.InputStream; @@ -25,6 +28,7 @@ import org.chromium.content.browser.test.util.CallbackHelper; import org.chromium.content.browser.test.util.Criteria; import org.chromium.content.browser.test.util.CriteriaHelper; +import org.xwalk.core.XWalkJavascriptResult; import org.xwalk.core.XWalkNavigationHistory; import org.xwalk.core.XWalkNavigationItem; import org.xwalk.core.XWalkResourceClient; @@ -54,7 +58,7 @@ public class XWalkViewTestBase @Override public void onPageLoadStopped(XWalkView view, String url, LoadStatus status) { - mInnerContentsClient.onPageFinished(url); + mInnerContentsClient.onPageFinished(url, status); } @Override @@ -76,6 +80,29 @@ public class XWalkViewTestBase public void onRequestFocus(XWalkView view) { mInnerContentsClient.onRequestFocus(); } + + @Override + public boolean onJavascriptModalDialog(XWalkView view, + XWalkUIClient.JavascriptMessageType type, String url, String message, + String defaultValue, XWalkJavascriptResult result) { + return mInnerContentsClient.onJavascriptModalDialog(message); + } + + @Override + public void openFileChooser(XWalkView view, ValueCallback uploadFile, + String acceptType, String capture) { + mInnerContentsClient.openFileChooser(uploadFile); + } + + @Override + public void onFullscreenToggled(XWalkView view, boolean enterFullscreen) { + mInnerContentsClient.onFullscreenToggled(enterFullscreen); + } + + @Override + public boolean shouldOverrideKeyEvent(XWalkView view, KeyEvent event) { + return mInnerContentsClient.overrideOrUnhandledKeyEvent(event); + } } class TestXWalkUIClient extends TestXWalkUIClientBase { @@ -524,4 +551,26 @@ public class XWalkViewTestBase t.printStackTrace(); } } + + public void simulateKeyAction(final int action) { + new Thread(new Runnable() { + public void run() { + try { + getInstrumentation().sendKeySync(new KeyEvent(action, + KeyEvent.KEYCODE_DPAD_CENTER)); + } catch (Exception e) { + e.printStackTrace(); + } + } + }).start(); + } + + protected void stopLoading() throws Exception { + getInstrumentation().runOnMainSync(new Runnable() { + @Override + public void run() { + mXWalkView.stopLoading(); + } + }); + } } diff --git a/src/xwalk/test/android/data/file_chooser.html b/src/xwalk/test/android/data/file_chooser.html new file mode 100644 index 0000000..6d0e485 --- /dev/null +++ b/src/xwalk/test/android/data/file_chooser.html @@ -0,0 +1,8 @@ + + +
+ + +
+ + diff --git a/src/xwalk/test/android/data/fullscreen_togged.html b/src/xwalk/test/android/data/fullscreen_togged.html new file mode 100644 index 0000000..eea9ece --- /dev/null +++ b/src/xwalk/test/android/data/fullscreen_togged.html @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/src/xwalk/test/android/data/js_modal_dialog.html b/src/xwalk/test/android/data/js_modal_dialog.html new file mode 100644 index 0000000..5e0d4ac --- /dev/null +++ b/src/xwalk/test/android/data/js_modal_dialog.html @@ -0,0 +1,5 @@ + + + Click Me + + diff --git a/src/xwalk/xwalk.gyp b/src/xwalk/xwalk.gyp index 467e20d..0cc9217 100644 --- a/src/xwalk/xwalk.gyp +++ b/src/xwalk/xwalk.gyp @@ -129,6 +129,8 @@ 'runtime/browser/android/xwalk_login_delegate.h', 'runtime/browser/android/xwalk_path_helper.cc', 'runtime/browser/android/xwalk_path_helper.h', + 'runtime/browser/android/xwalk_icon_helper.cc', + 'runtime/browser/android/xwalk_icon_helper.h', 'runtime/browser/android/xwalk_request_interceptor.cc', 'runtime/browser/android/xwalk_request_interceptor.h', 'runtime/browser/android/xwalk_settings.cc', diff --git a/src/xwalk/xwalk_android_tests.gypi b/src/xwalk/xwalk_android_tests.gypi index 25c88b9..bbc2ee9 100644 --- a/src/xwalk/xwalk_android_tests.gypi +++ b/src/xwalk/xwalk_android_tests.gypi @@ -136,9 +136,12 @@ '<(PRODUCT_DIR)/xwalk_xwview_test/assets/add_js_interface.html', '<(PRODUCT_DIR)/xwalk_xwview_test/assets/echo.html', '<(PRODUCT_DIR)/xwalk_xwview_test/assets/echoSync.html', + '<(PRODUCT_DIR)/xwalk_xwview_test/assets/file_chooser.html', '<(PRODUCT_DIR)/xwalk_xwview_test/assets/framesEcho.html', '<(PRODUCT_DIR)/xwalk_xwview_test/assets/fullscreen_enter_exit.html', + '<(PRODUCT_DIR)/xwalk_xwview_test/assets/fullscreen_togged.html', '<(PRODUCT_DIR)/xwalk_xwview_test/assets/index.html', + '<(PRODUCT_DIR)/xwalk_xwview_test/assets/js_modal_dialog.html', '<(PRODUCT_DIR)/xwalk_xwview_test/assets/profile.html', '<(PRODUCT_DIR)/xwalk_xwview_test/assets/scale_changed.html', '<(PRODUCT_DIR)/xwalk_xwview_test/assets/window.close.html', @@ -152,9 +155,12 @@ 'test/android/data/add_js_interface.html', 'test/android/data/echo.html', 'test/android/data/echoSync.html', + 'test/android/data/file_chooser.html', 'test/android/data/framesEcho.html', 'test/android/data/fullscreen_enter_exit.html', + 'test/android/data/fullscreen_togged.html', 'test/android/data/index.html', + 'test/android/data/js_modal_dialog.html', 'test/android/data/profile.html', 'test/android/data/scale_changed.html', 'test/android/data/window.close.html', -- 2.7.4