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