| // Copyright (C) 2009 The Android Open Source Project | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| package com.google.gwtexpui.user.client; | |
| import com.google.gwt.core.client.GWT; | |
| import com.google.gwt.user.client.Window; | |
| /** | |
| * User agent feature tests we don't create permutations for. | |
| * | |
| * <p>Some features aren't worth creating full permutations in GWT for, as each new boolean | |
| * permutation (only two settings) doubles the compile time required. If the setting only affects a | |
| * couple of lines of JavaScript code, the slightly larger cache files for user agents that lack the | |
| * functionality requested is trivial compared to the time developers lose building their | |
| * application. | |
| */ | |
| public class UserAgent { | |
| private static boolean jsClip = guessJavaScriptClipboard(); | |
| public static boolean hasJavaScriptClipboard() { | |
| return jsClip; | |
| } | |
| public static void disableJavaScriptClipboard() { | |
| jsClip = false; | |
| } | |
| private static native boolean nativeHasCopy() | |
| /*-{ return $doc['queryCommandSupported'] && $doc.queryCommandSupported('copy') }-*/ ; | |
| private static boolean guessJavaScriptClipboard() { | |
| String ua = Window.Navigator.getUserAgent(); | |
| int chrome = major(ua, "Chrome/"); | |
| if (chrome > 0) { | |
| return 42 <= chrome; | |
| } | |
| int ff = major(ua, "Firefox/"); | |
| if (ff > 0) { | |
| return 41 <= ff; | |
| } | |
| int opera = major(ua, "OPR/"); | |
| if (opera > 0) { | |
| return 29 <= opera; | |
| } | |
| int msie = major(ua, "MSIE "); | |
| if (msie > 0) { | |
| return 9 <= msie; | |
| } | |
| if (nativeHasCopy()) { | |
| // Firefox 39.0 lies and says it supports copy, then fails. | |
| // So we try this after the browser specific test above. | |
| return true; | |
| } | |
| // Safari is not planning to support document.execCommand('copy'). | |
| // Assume the browser does not have the feature. | |
| return false; | |
| } | |
| private static int major(String ua, String product) { | |
| int entry = ua.indexOf(product); | |
| if (entry >= 0) { | |
| String s = ua.substring(entry + product.length()); | |
| String p = s.split("[ /;,.)]", 2)[0]; | |
| try { | |
| return Integer.parseInt(p); | |
| } catch (NumberFormatException nan) { | |
| // Ignored | |
| } | |
| } | |
| return -1; | |
| } | |
| public static class Flash { | |
| private static boolean checked; | |
| private static boolean installed; | |
| /** | |
| * Does the browser have ShockwaveFlash plugin installed? | |
| * | |
| * <p>This method may still return true if the user has disabled Flash or set the plugin to | |
| * "click to run". | |
| */ | |
| public static boolean isInstalled() { | |
| if (!checked) { | |
| installed = hasFlash(); | |
| checked = true; | |
| } | |
| return installed; | |
| } | |
| private static native boolean hasFlash() /*-{ | |
| if (navigator.plugins && navigator.plugins.length) { | |
| if (navigator.plugins['Shockwave Flash']) return true; | |
| if (navigator.plugins['Shockwave Flash 2.0']) return true; | |
| } else if (navigator.mimeTypes && navigator.mimeTypes.length) { | |
| var mimeType = navigator.mimeTypes['application/x-shockwave-flash']; | |
| if (mimeType && mimeType.enabledPlugin) return true; | |
| } else { | |
| try { new ActiveXObject('ShockwaveFlash.ShockwaveFlash.7'); return true; } catch (e) {} | |
| try { new ActiveXObject('ShockwaveFlash.ShockwaveFlash.6'); return true; } catch (e) {} | |
| try { new ActiveXObject('ShockwaveFlash.ShockwaveFlash'); return true; } catch (e) {} | |
| } | |
| return false; | |
| }-*/; | |
| } | |
| /** | |
| * Test for and disallow running this application in an <iframe>. | |
| * | |
| * <p>If the application is running within an iframe this method requests a browser generated | |
| * redirect to pop the application out of the iframe into the top level window, and then aborts | |
| * execution by throwing an exception. This is call should be placed early within the module's | |
| * onLoad() method, before any real UI can be initialized that an attacking site could try to snip | |
| * out and present in a confusing context. | |
| * | |
| * <p>If the break out works, execution will restart automatically in a proper top level window, | |
| * where the script has full control over the display. If the break out fails, execution will | |
| * abort and stop immediately, preventing UI widgets from being created, leaving the user with an | |
| * empty frame. | |
| */ | |
| public static void assertNotInIFrame() { | |
| if (GWT.isScript() && amInsideIFrame()) { | |
| bustOutOfIFrame(Window.Location.getHref()); | |
| throw new RuntimeException(); | |
| } | |
| } | |
| private static native boolean amInsideIFrame() /*-{ return top.location != $wnd.location; }-*/; | |
| private static native void bustOutOfIFrame(String newloc) /*-{ top.location.href = newloc }-*/; | |
| /** | |
| * Test if Gerrit is running on a mobile browser. This check could be incomplete, but should cover | |
| * most cases. Regexes shamelessly borrowed from CodeMirror. | |
| */ | |
| public static native boolean isMobile() /*-{ | |
| var ua = $wnd.navigator.userAgent; | |
| var ios = /AppleWebKit/.test(ua) && /Mobile\/\w+/.test(ua); | |
| return ios | |
| || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(ua); | |
| }-*/; | |
| /** Check if the height of the browser view is greater than its width. */ | |
| public static boolean isPortrait() { | |
| return Window.getClientHeight() > Window.getClientWidth(); | |
| } | |
| private UserAgent() {} | |
| } |