From 66fa12a091c44d062ce4423e9e413e647895c466 Mon Sep 17 00:00:00 2001 From: Andrew Grieve Date: Thu, 4 Dec 2014 09:58:00 -0500 Subject: [PATCH 1/5] CB-8119 Restart adb when we detect it's hung --- bin/templates/cordova/lib/build.js | 42 +++++++++++++++++++++++++---- bin/templates/cordova/lib/device.js | 40 ++++++++++++++++++++------- 2 files changed, 67 insertions(+), 15 deletions(-) diff --git a/bin/templates/cordova/lib/build.js b/bin/templates/cordova/lib/build.js index 85a6e7cd..0d4d0046 100644 --- a/bin/templates/cordova/lib/build.js +++ b/bin/templates/cordova/lib/build.js @@ -398,12 +398,44 @@ module.exports.run = function(options, optResolvedTarget) { * Returns "arm" or "x86". */ module.exports.detectArchitecture = function(target) { - return exec('adb -s ' + target + ' shell cat /proc/cpuinfo') - .then(function(output) { - if (/intel/i.exec(output)) { - return 'x86'; + function helper() { + return exec('adb -s ' + target + ' shell cat /proc/cpuinfo') + .then(function(output) { + if (/intel/i.exec(output)) { + return 'x86'; + } + return 'arm'; + }); + } + // It sometimes happens (at least on OS X), that this command will hang forever. + // To fix it, either unplug & replug device, or restart adb server. + return helper().timeout(1000, 'Device communication timed out. Try unplugging & replugging the device.') + .then(null, function(err) { + if (/timed out/.exec('' + err)) { + // adb kill-server doesn't seem to do the trick. + // Could probably find a x-platform version of killall, but I'm not actually + // sure that this scenario even happens on non-OSX machines. + return exec('killall adb') + .then(function() { + console.log('adb seems hung. retrying.'); + return helper() + .then(null, function() { + // The double kill is sadly often necessary, at least on mac. + console.log('Now device not found... restarting adb again.'); + return exec('killall adb') + .then(function() { + return helper() + .then(null, function() { + return Q.reject('USB is flakey. Try unplugging & replugging the device.'); + }); + }); + }); + }, function() { + // For non-killall OS's. + return Q.reject(err); + }) } - return 'arm'; + throw err; }); }; diff --git a/bin/templates/cordova/lib/device.js b/bin/templates/cordova/lib/device.js index 6be55e30..6430d732 100644 --- a/bin/templates/cordova/lib/device.js +++ b/bin/templates/cordova/lib/device.js @@ -28,23 +28,43 @@ var exec = require('./exec'), /** * Returns a promise for the list of the device ID's found + * @param lookHarder When true, try restarting adb if no devices are found. */ -module.exports.list = function() { - return exec('adb devices') - .then(function(output) { - var response = output.split('\n'); - var device_list = []; - for (var i = 1; i < response.length; i++) { - if (response[i].match(/\w+\tdevice/) && !response[i].match(/emulator/)) { - device_list.push(response[i].replace(/\tdevice/, '').replace('\r', '')); +module.exports.list = function(lookHarder) { + function helper() { + return exec('adb devices') + .then(function(output) { + var response = output.split('\n'); + var device_list = []; + for (var i = 1; i < response.length; i++) { + if (response[i].match(/\w+\tdevice/) && !response[i].match(/emulator/)) { + device_list.push(response[i].replace(/\tdevice/, '').replace('\r', '')); + } } + return device_list; + }); + } + return helper() + .then(function(list) { + if (list.length === 0 && lookHarder) { + // adb kill-server doesn't seem to do the trick. + // Could probably find a x-platform version of killall, but I'm not actually + // sure that this scenario even happens on non-OSX machines. + return exec('killall adb') + .then(function() { + console.log('Restarting adb to see if more devices are detected.'); + return helper(); + }, function() { + // For non-killall OS's. + return list; + }); } - return device_list; + return list; }); } module.exports.resolveTarget = function(target) { - return this.list() + return this.list(true) .then(function(device_list) { if (!device_list || !device_list.length) { return Q.reject('ERROR: Failed to deploy to device, no devices found.'); From ffd14fe7d95161f98ce88dc9f8b58046a51bbd79 Mon Sep 17 00:00:00 2001 From: Brian Geppert Date: Tue, 9 Dec 2014 11:57:29 -0600 Subject: [PATCH 2/5] Revert Gradle distributionUrlRegex cleanup. This reverts commit 75a0a6752a77e2e0f491ae4de7137f5163c7a4bd. --- bin/templates/cordova/lib/build.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/templates/cordova/lib/build.js b/bin/templates/cordova/lib/build.js index 0d4d0046..fead2067 100644 --- a/bin/templates/cordova/lib/build.js +++ b/bin/templates/cordova/lib/build.js @@ -239,7 +239,8 @@ var builders = { // If the gradle distribution URL is set, make sure it points to version 1.12. // If it's not set, do nothing, assuming that we're using a future version of gradle that we don't want to mess with. - var distributionUrlRegex = '/^distributionUrl=.*$/'; + // For some reason, using ^ and $ don't work. This does the job, though. + var distributionUrlRegex = /distributionUrl.*zip/; var distributionUrl = 'distributionUrl=http\\://services.gradle.org/distributions/gradle-1.12-all.zip'; var gradleWrapperPropertiesPath = path.join(projectPath, 'gradle', 'wrapper', 'gradle-wrapper.properties'); shell.sed('-i', distributionUrlRegex, distributionUrl, gradleWrapperPropertiesPath); From f953e6adb8478edee1d68419cba35d35a400b641 Mon Sep 17 00:00:00 2001 From: Ian Clelland Date: Wed, 10 Dec 2014 10:07:05 -0500 Subject: [PATCH 3/5] CB-8143: Use the correct Android Gradle plugin for the installed Gradle version --- bin/templates/project/build.gradle | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/bin/templates/project/build.gradle b/bin/templates/project/build.gradle index 63ecd810..5a997e6d 100644 --- a/bin/templates/project/build.gradle +++ b/bin/templates/project/build.gradle @@ -31,8 +31,18 @@ buildscript { mavenCentral() } - dependencies { - classpath 'com.android.tools.build:gradle:0.12.0+' + // Switch the Android Gradle plugin version requirement depending on the + // installed version of Gradle. This dependency is documented at + // http://tools.android.com/tech-docs/new-build-system/version-compatibility + // and https://issues.apache.org/jira/browse/CB-8143 + if (gradle.gradleVersion >= "2.1") { + dependencies { + classpath 'com.android.tools.build:gradle:0.14.0+' + } + } else { + dependencies { + classpath 'com.android.tools.build:gradle:0.12.0+' + } } } From 27f1181d53a6feca77f5bb645892f7d357a6f35a Mon Sep 17 00:00:00 2001 From: Andrew Grieve Date: Mon, 17 Nov 2014 23:46:39 -0800 Subject: [PATCH 4/5] CB-3679 Move splashscreen logic into splashscreen plugin Tried as hard as possible for this not to be a breaking change (all symbols were preserved). Planning to remove delegating symbols in 4.0.x though. Also for backwards compatability - a copy of the plugin is bundled. It will likewise be removed in 4.0.x --- .../org/apache/cordova/CordovaActivity.java | 198 +++----------- .../org/apache/cordova/CordovaWebView.java | 11 +- .../apache/cordova/SplashScreenInternal.java | 252 ++++++++++++++++++ 3 files changed, 296 insertions(+), 165 deletions(-) create mode 100644 framework/src/org/apache/cordova/SplashScreenInternal.java diff --git a/framework/src/org/apache/cordova/CordovaActivity.java b/framework/src/org/apache/cordova/CordovaActivity.java index 816b12b9..b61fa987 100755 --- a/framework/src/org/apache/cordova/CordovaActivity.java +++ b/framework/src/org/apache/cordova/CordovaActivity.java @@ -24,17 +24,13 @@ import java.util.Locale; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import org.apache.cordova.CordovaInterface; -import org.apache.cordova.CordovaPlugin; -import org.apache.cordova.LOG; +import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.annotation.SuppressLint; import android.app.Activity; import android.app.AlertDialog; -import android.app.Dialog; -import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; @@ -42,7 +38,6 @@ import android.graphics.Color; import android.media.AudioManager; import android.net.Uri; import android.os.Bundle; -import android.os.Handler; import android.util.Log; import android.view.Display; import android.view.KeyEvent; @@ -100,7 +95,6 @@ public class CordovaActivity extends Activity implements CordovaInterface { @Deprecated // Will be removed. Use findViewById() to retrieve views. protected LinearLayout root; - protected ProgressDialog spinnerDialog = null; private final ExecutorService threadPool = Executors.newCachedThreadPool(); private static int ACTIVITY_STARTING = 0; @@ -117,9 +111,10 @@ public class CordovaActivity extends Activity implements CordovaInterface { */ // Draw a splash screen using an image located in the drawable resource directory. - // This is not the same as calling super.loadSplashscreen(url) + @Deprecated // Use "SplashScreen" preference instead. protected int splashscreen = 0; - protected int splashscreenTime = 3000; + @Deprecated // Use "SplashScreenDelay" preference instead. + protected int splashscreenTime = -1; // LoadUrl timeout value in msec (default of 20 sec) protected int loadUrlTimeoutValue = 20000; @@ -267,9 +262,6 @@ public class CordovaActivity extends Activity implements CordovaInterface { ViewGroup.LayoutParams.MATCH_PARENT, 1.0F)); - // Add web view but make it invisible while loading URL - appView.setVisibility(View.INVISIBLE); - // need to remove appView from any existing parent before invoking root.addView(appView) ViewParent parent = appView.getParent(); if ((parent != null) && (parent != root)) { @@ -334,6 +326,13 @@ public class CordovaActivity extends Activity implements CordovaInterface { public void init(CordovaWebView webView, CordovaWebViewClient webViewClient, CordovaChromeClient webChromeClient) { LOG.d(TAG, "CordovaActivity.init()"); + if (splashscreenTime >= 0) { + preferences.set("SplashScreenDelay", splashscreenTime); + } + if (splashscreen != 0) { + preferences.set("SplashDrawableId", splashscreen); + } + appView = webView != null ? webView : makeWebView(); if (appView.pluginManager == null) { appView.init(this, webViewClient != null ? webViewClient : makeWebViewClient(appView), @@ -361,36 +360,10 @@ public class CordovaActivity extends Activity implements CordovaInterface { if (appView == null) { init(); } - this.splashscreenTime = preferences.getInteger("SplashScreenDelay", this.splashscreenTime); - String splash = preferences.getString("SplashScreen", null); - if(this.splashscreenTime > 0 && splash != null) - { - this.splashscreen = getResources().getIdentifier(splash, "drawable", getClass().getPackage().getName());; - if(this.splashscreen != 0) - { - this.showSplashScreen(this.splashscreenTime); - } - } - // If keepRunning this.keepRunning = preferences.getBoolean("KeepRunning", true); - //Check if the view is attached to anything - if(appView.getParent() != null) - { - // Then load the spinner - this.loadSpinner(); - } - //Load the correct splashscreen - - if(this.splashscreen != 0) - { - this.appView.loadUrl(url, this.splashscreenTime); - } - else - { - this.appView.loadUrl(url); - } + appView.loadUrlIntoView(url, true); } /** @@ -400,44 +373,12 @@ public class CordovaActivity extends Activity implements CordovaInterface { * @param url * @param time The number of ms to wait before loading webview */ + @Deprecated // Use loadUrl(String url) instead. public void loadUrl(final String url, int time) { this.splashscreenTime = time; this.loadUrl(url); } - - /* - * Load the spinner - */ - void loadSpinner() { - - // If loadingDialog property, then show the App loading dialog for first page of app - String loading = null; - if ((this.appView == null) || !this.appView.canGoBack()) { - loading = preferences.getString("LoadingDialog", null); - } - else { - loading = preferences.getString("LoadingPageDialog", null); - } - if (loading != null) { - - String title = ""; - String message = "Loading Application..."; - - if (loading.length() > 0) { - int comma = loading.indexOf(','); - if (comma > 0) { - title = loading.substring(0, comma); - message = loading.substring(comma + 1); - } - else { - title = ""; - message = loading; - } - } - this.spinnerStart(title, message); - } - } @Deprecated public void cancelLoadUrl() { @@ -588,9 +529,6 @@ public class CordovaActivity extends Activity implements CordovaInterface { { this.appView.handlePause(this.keepRunning); } - - // hide the splash screen to avoid leaking a window - this.removeSplashScreen(); } /** @@ -645,9 +583,6 @@ public class CordovaActivity extends Activity implements CordovaInterface { LOG.d(TAG, "CordovaActivity.onDestroy()"); super.onDestroy(); - // hide the splash screen to avoid leaking a window - this.removeSplashScreen(); - if (this.appView != null) { appView.handleDestroy(); } @@ -697,28 +632,20 @@ public class CordovaActivity extends Activity implements CordovaInterface { * @param title Title of the dialog * @param message The message of the dialog */ + @Deprecated // Call this directly on SplashScreen plugin instead. public void spinnerStart(final String title, final String message) { - if (this.spinnerDialog != null) { - this.spinnerDialog.dismiss(); - this.spinnerDialog = null; - } - final CordovaActivity me = this; - this.spinnerDialog = ProgressDialog.show(CordovaActivity.this, title, message, true, true, - new DialogInterface.OnCancelListener() { - public void onCancel(DialogInterface dialog) { - me.spinnerDialog = null; - } - }); + JSONArray args = new JSONArray(); + args.put(title); + args.put(message); + doSplashScreenAction("spinnerStart", args); } /** * Stop spinner - Must be called from UI thread */ + @Deprecated // Call this directly on SplashScreen plugin instead. public void spinnerStop() { - if (this.spinnerDialog != null && this.spinnerDialog.isShowing()) { - this.spinnerDialog.dismiss(); - this.spinnerDialog = null; - } + doSplashScreenAction("spinnerStop", null); } /** @@ -810,8 +737,6 @@ public class CordovaActivity extends Activity implements CordovaInterface { // Load URL on UI thread me.runOnUiThread(new Runnable() { public void run() { - // Stop "app loading" spinner if showing - me.spinnerStop(); me.appView.showWebPage(errorUrl, false, true, null); } }); @@ -915,62 +840,34 @@ public class CordovaActivity extends Activity implements CordovaInterface { } } - protected Dialog splashDialog; + private void doSplashScreenAction(String action, JSONArray args) { + CordovaPlugin p = appView.pluginManager.getPlugin("org.apache.cordova.splashscreeninternal"); + if (p != null) { + args = args == null ? new JSONArray() : args; + try { + p.execute(action, args, null); + } catch (JSONException e) { + e.printStackTrace(); + } + } + } /** * Removes the Dialog that displays the splash screen */ + @Deprecated public void removeSplashScreen() { - if (splashDialog != null && splashDialog.isShowing()) { - splashDialog.dismiss(); - splashDialog = null; - } + doSplashScreenAction("hide", null); } /** * Shows the splash screen over the full Activity */ @SuppressWarnings("deprecation") + @Deprecated protected void showSplashScreen(final int time) { - final CordovaActivity that = this; - - Runnable runnable = new Runnable() { - public void run() { - // Get reference to display - Display display = getWindowManager().getDefaultDisplay(); - - // Create the layout for the dialog - LinearLayout root = new LinearLayout(that.getActivity()); - root.setMinimumHeight(display.getHeight()); - root.setMinimumWidth(display.getWidth()); - root.setOrientation(LinearLayout.VERTICAL); - root.setBackgroundColor(preferences.getInteger("backgroundColor", Color.BLACK)); - root.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT, 0.0F)); - root.setBackgroundResource(that.splashscreen); - - // Create and show the dialog - splashDialog = new Dialog(that, android.R.style.Theme_Translucent_NoTitleBar); - // check to see if the splash screen should be full screen - if ((getWindow().getAttributes().flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) - == WindowManager.LayoutParams.FLAG_FULLSCREEN) { - splashDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, - WindowManager.LayoutParams.FLAG_FULLSCREEN); - } - splashDialog.setContentView(root); - splashDialog.setCancelable(false); - splashDialog.show(); - - // Set Runnable to remove splash screen just in case - final Handler handler = new Handler(); - handler.postDelayed(new Runnable() { - public void run() { - removeSplashScreen(); - } - }, time); - } - }; - this.runOnUiThread(runnable); + preferences.set("SplashScreenDelay", time); + doSplashScreenAction("show", null); } @Override @@ -1015,28 +912,7 @@ public class CordovaActivity extends Activity implements CordovaInterface { LOG.d(TAG, "onMessage(" + id + "," + data + ")"); } - if ("splashscreen".equals(id)) { - if ("hide".equals(data.toString())) { - this.removeSplashScreen(); - } - else { - // If the splash dialog is showing don't try to show it again - if (this.splashDialog == null || !this.splashDialog.isShowing()) { - String splashResource = preferences.getString("SplashScreen", null); - if (splashResource != null) { - splashscreen = getResources().getIdentifier(splashResource, "drawable", getClass().getPackage().getName()); - } - this.showSplashScreen(this.splashscreenTime); - } - } - } - else if ("spinner".equals(id)) { - if ("stop".equals(data.toString())) { - this.spinnerStop(); - this.appView.setVisibility(View.VISIBLE); - } - } - else if ("onReceivedError".equals(id)) { + if ("onReceivedError".equals(id)) { JSONObject d = (JSONObject) data; try { this.onReceivedError(d.getInt("errorCode"), d.getString("description"), d.getString("url")); diff --git a/framework/src/org/apache/cordova/CordovaWebView.java b/framework/src/org/apache/cordova/CordovaWebView.java index 62a641b5..feec5a96 100755 --- a/framework/src/org/apache/cordova/CordovaWebView.java +++ b/framework/src/org/apache/cordova/CordovaWebView.java @@ -156,6 +156,9 @@ public class CordovaWebView extends WebView { resourceApi = new CordovaResourceApi(this.getContext(), pluginManager); pluginManager.addService("App", "org.apache.cordova.App"); + // This will be removed in 4.0.x in favour of the plugin not being bundled. + pluginManager.addService(new PluginEntry("SplashScreenInternal", "org.apache.cordova.SplashScreenInternal", true)); + pluginManager.init(); initWebViewSettings(); exposeJsInterface(); } @@ -383,8 +386,11 @@ public class CordovaWebView extends WebView { initIfNecessary(); if (recreatePlugins) { + // Don't re-initialize on first load. + if (loadedUrl != null) { + this.pluginManager.init(); + } this.loadedUrl = url; - this.pluginManager.init(); } // Create a timeout timer for loadUrl @@ -462,9 +468,6 @@ public class CordovaWebView extends WebView { else { LOG.d(TAG, "loadUrlIntoView(%s, %d)", url, time); - - // Send message to show splashscreen now if desired - this.postMessage("splashscreen", "show"); } // Load url diff --git a/framework/src/org/apache/cordova/SplashScreenInternal.java b/framework/src/org/apache/cordova/SplashScreenInternal.java new file mode 100644 index 00000000..605fce7d --- /dev/null +++ b/framework/src/org/apache/cordova/SplashScreenInternal.java @@ -0,0 +1,252 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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 org.apache.cordova; + +import android.app.Dialog; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.graphics.Color; +import android.os.Handler; +import android.view.Display; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.widget.LinearLayout; + +import org.json.JSONArray; +import org.json.JSONException; + +// This file is a copy of SplashScreen.java from cordova-plugin-splashscreen, and is required only +// for pre-4.0 Cordova as a transition path to it being extracted into the plugin. +public class SplashScreenInternal extends CordovaPlugin { + private static final String LOG_TAG = "SplashScreenInternal"; + private static Dialog splashDialog; + private static ProgressDialog spinnerDialog; + private static boolean firstShow = true; + + @Override + protected void pluginInitialize() { + if (!firstShow) { + return; + } + // Make WebView invisible while loading URL + webView.setVisibility(View.INVISIBLE); + int drawableId = preferences.getInteger("SplashDrawableId", 0); + if (drawableId == 0) { + String splashResource = preferences.getString("SplashScreen", null); + if (splashResource != null) { + drawableId = cordova.getActivity().getResources().getIdentifier(splashResource, "drawable", cordova.getActivity().getClass().getPackage().getName()); + preferences.set("SplashDrawableId", drawableId); + } + } + + firstShow = false; + loadSpinner(); + showSplashScreen(); + } + + @Override + public void onPause(boolean multitasking) { + // hide the splash screen to avoid leaking a window + this.removeSplashScreen(); + } + + @Override + public void onDestroy() { + // hide the splash screen to avoid leaking a window + this.removeSplashScreen(); + firstShow = true; + } + + @Override + public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException { + if (action.equals("hide")) { + cordova.getActivity().runOnUiThread(new Runnable() { + public void run() { + webView.postMessage("splashscreen", "hide"); + } + }); + } else if (action.equals("show")) { + cordova.getActivity().runOnUiThread(new Runnable() { + public void run() { + webView.postMessage("splashscreen", "show"); + } + }); + } else if (action.equals("spinnerStart")) { + final String title = args.getString(0); + final String message = args.getString(1); + cordova.getActivity().runOnUiThread(new Runnable() { + public void run() { + spinnerStart(title, message); + } + }); + } else { + return false; + } + + callbackContext.success(); + return true; + } + + @Override + public Object onMessage(String id, Object data) { + if ("splashscreen".equals(id)) { + if ("hide".equals(data.toString())) { + this.removeSplashScreen(); + } else { + this.showSplashScreen(); + } + } else if ("spinner".equals(id)) { + if ("stop".equals(data.toString())) { + this.spinnerStop(); + webView.setVisibility(View.VISIBLE); + } + } else if ("onReceivedError".equals(id)) { + spinnerStop(); + } + return null; + } + + private void removeSplashScreen() { + cordova.getActivity().runOnUiThread(new Runnable() { + public void run() { + if (splashDialog != null && splashDialog.isShowing()) { + splashDialog.dismiss(); + splashDialog = null; + } + } + }); + } + + /** + * Shows the splash screen over the full Activity + */ + @SuppressWarnings("deprecation") + private void showSplashScreen() { + final int splashscreenTime = preferences.getInteger("SplashScreenDelay", 3000); + final int drawableId = preferences.getInteger("SplashDrawableId", 0); + + // If the splash dialog is showing don't try to show it again + if (this.splashDialog != null && splashDialog.isShowing()) { + return; + } + if (drawableId == 0 || splashscreenTime <= 0) { + return; + } + + cordova.getActivity().runOnUiThread(new Runnable() { + public void run() { + // Get reference to display + Display display = cordova.getActivity().getWindowManager().getDefaultDisplay(); + Context context = webView.getContext(); + + // Create the layout for the dialog + LinearLayout root = new LinearLayout(context); + root.setMinimumHeight(display.getHeight()); + root.setMinimumWidth(display.getWidth()); + root.setOrientation(LinearLayout.VERTICAL); + + // TODO: Use the background color of the webview's parent instead of using the + // preference. + root.setBackgroundColor(preferences.getInteger("backgroundColor", Color.BLACK)); + root.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT, 0.0F)); + root.setBackgroundResource(drawableId); + + // Create and show the dialog + splashDialog = new Dialog(context, android.R.style.Theme_Translucent_NoTitleBar); + // check to see if the splash screen should be full screen + if ((cordova.getActivity().getWindow().getAttributes().flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) + == WindowManager.LayoutParams.FLAG_FULLSCREEN) { + splashDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + } + splashDialog.setContentView(root); + splashDialog.setCancelable(false); + splashDialog.show(); + + // Set Runnable to remove splash screen just in case + final Handler handler = new Handler(); + handler.postDelayed(new Runnable() { + public void run() { + removeSplashScreen(); + } + }, splashscreenTime); + } + }); + } + + /* + * Load the spinner + */ + private void loadSpinner() { + // If loadingDialog property, then show the App loading dialog for first page of app + String loading = null; + if (webView.canGoBack()) { + loading = preferences.getString("LoadingDialog", null); + } + else { + loading = preferences.getString("LoadingPageDialog", null); + } + if (loading != null) { + String title = ""; + String message = "Loading Application..."; + + if (loading.length() > 0) { + int comma = loading.indexOf(','); + if (comma > 0) { + title = loading.substring(0, comma); + message = loading.substring(comma + 1); + } + else { + title = ""; + message = loading; + } + } + spinnerStart(title, message); + } + } + + private void spinnerStart(final String title, final String message) { + cordova.getActivity().runOnUiThread(new Runnable() { + public void run() { + spinnerStop(); + spinnerDialog = ProgressDialog.show(webView.getContext(), title, message, true, true, + new DialogInterface.OnCancelListener() { + public void onCancel(DialogInterface dialog) { + spinnerDialog = null; + } + }); + } + }); + } + + private void spinnerStop() { + cordova.getActivity().runOnUiThread(new Runnable() { + public void run() { + if (spinnerDialog != null && spinnerDialog.isShowing()) { + spinnerDialog.dismiss(); + spinnerDialog = null; + } + } + }); + } +} From ba140a8a84ea770e9d9cff48cec606122ed0de04 Mon Sep 17 00:00:00 2001 From: fujunwei Date: Mon, 17 Nov 2014 15:52:40 +0800 Subject: [PATCH 5/5] Add a section for plugin extensions The build.gradle will apply gradle srcipte from plugin extension When install the plugin with "gradleReference" framework. The gradle can set ext.multiarch=true to support multiple APKs by default, so add this section in here. --- bin/templates/project/build.gradle | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bin/templates/project/build.gradle b/bin/templates/project/build.gradle index 5a997e6d..f427561c 100644 --- a/bin/templates/project/build.gradle +++ b/bin/templates/project/build.gradle @@ -50,6 +50,9 @@ task wrapper(type: Wrapper) { gradleVersion = '1.12' } +// PLUGIN GRADLE EXTENSIONS START +// PLUGIN GRADLE EXTENSIONS END + ext.multiarch=false android {