public class SplashScreen extends CordovaPlugin { private static final String LOG_TAG = "SplashScreen"; // Cordova 3.x.x has a copy of this plugin bundled with it (SplashScreenInternal.java). // Enable functionality only if running on 4.x.x. private static final boolean HAS_BUILT_IN_SPLASH_SCREEN = Integer.valueOf(CordovaWebView.CORDOVA_VERSION.split("\\.")[0]) < 4; private static Dialog splashDialog; private static ProgressDialog spinnerDialog; private static boolean firstShow = true; // Helper to be compile-time compatable with both Cordova 3.x and 4.x. private View getView() { try { return (View) webView.getClass().getMethod("getView").invoke(webView); } catch (Exception e) { return (View) webView; } } @Override protected void pluginInitialize() { if (HAS_BUILT_IN_SPLASH_SCREEN || !firstShow) { return; } // Make WebView invisible while loading URL getView().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()); if (drawableId == 0) { drawableId = cordova .getActivity() .getResources() .getIdentifier( splashResource, "drawable", cordova.getActivity().getPackageName()); } preferences.set("SplashDrawableId", drawableId); } } firstShow = false; loadSpinner(); showSplashScreen(true); } @Override public void onPause(boolean multitasking) { if (HAS_BUILT_IN_SPLASH_SCREEN) { return; } // hide the splash screen to avoid leaking a window this.removeSplashScreen(); } @Override public void onDestroy() { if (HAS_BUILT_IN_SPLASH_SCREEN) { return; } // 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")) { if (!HAS_BUILT_IN_SPLASH_SCREEN) { 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 (HAS_BUILT_IN_SPLASH_SCREEN) { return null; } if ("splashscreen".equals(id)) { if ("hide".equals(data.toString())) { this.removeSplashScreen(); } else { this.showSplashScreen(false); } } else if ("spinner".equals(id)) { if ("stop".equals(data.toString())) { this.spinnerStop(); getView().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 boolean hideAfterDelay) { 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 && hideAfterDelay)) { 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 RelativeLayout root = new RelativeLayout(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.setGravity(Gravity.CENTER); root.setLayoutParams( new RelativeLayout.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); } // add spinner ProgressBar progressBar = new ProgressBar(context, null, android.R.attr.progressBarStyleSmall); root.addView(progressBar); splashDialog.setContentView(root); splashDialog.setCancelable(false); splashDialog.show(); // Set Runnable to remove splash screen just in case if (hideAfterDelay) { 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; } } }); } }
public class SplashScreen extends CordovaPlugin { private static final String LOG_TAG = "SplashScreen"; // Cordova 3.x.x has a copy of this plugin bundled with it (SplashScreenInternal.java). // Enable functionality only if running on 4.x.x. private static final boolean HAS_BUILT_IN_SPLASH_SCREEN = Integer.valueOf(CordovaWebView.CORDOVA_VERSION.split("\\.")[0]) < 4; private static final int DEFAULT_SPLASHSCREEN_DURATION = 3000; private static final int DEFAULT_FADE_DURATION = 500; private static Dialog splashDialog; private static ProgressDialog spinnerDialog; private static boolean firstShow = true; private static boolean lastHideAfterDelay; // https://issues.apache.org/jira/browse/CB-9094 /** Displays the splash drawable. */ private ImageView splashImageView; /** Remember last device orientation to detect orientation changes. */ private int orientation; // Helper to be compile-time compatible with both Cordova 3.x and 4.x. private View getView() { try { return (View) webView.getClass().getMethod("getView").invoke(webView); } catch (Exception e) { return (View) webView; } } @Override protected void pluginInitialize() { if (HAS_BUILT_IN_SPLASH_SCREEN) { return; } // Make WebView invisible while loading URL // CB-11326 Ensure we're calling this on UI thread cordova .getActivity() .runOnUiThread( new Runnable() { @Override public void run() { getView().setVisibility(View.INVISIBLE); } }); int drawableId = preferences.getInteger("SplashDrawableId", 0); if (drawableId == 0) { String splashResource = preferences.getString("SplashScreen", "screen"); if (splashResource != null) { drawableId = cordova .getActivity() .getResources() .getIdentifier( splashResource, "drawable", cordova.getActivity().getClass().getPackage().getName()); if (drawableId == 0) { drawableId = cordova .getActivity() .getResources() .getIdentifier( splashResource, "drawable", cordova.getActivity().getPackageName()); } preferences.set("SplashDrawableId", drawableId); } } // Save initial orientation. orientation = cordova.getActivity().getResources().getConfiguration().orientation; if (firstShow) { boolean autoHide = preferences.getBoolean("AutoHideSplashScreen", true); showSplashScreen(autoHide); } if (preferences.getBoolean("SplashShowOnlyFirstTime", true)) { firstShow = false; } } /** Shorter way to check value of "SplashMaintainAspectRatio" preference. */ private boolean isMaintainAspectRatio() { return preferences.getBoolean("SplashMaintainAspectRatio", false); } private int getFadeDuration() { int fadeSplashScreenDuration = preferences.getBoolean("FadeSplashScreen", true) ? preferences.getInteger("FadeSplashScreenDuration", DEFAULT_FADE_DURATION) : 0; if (fadeSplashScreenDuration < 30) { // [CB-9750] This value used to be in decimal seconds, so we will assume that if someone // specifies 10 // they mean 10 seconds, and not the meaningless 10ms fadeSplashScreenDuration *= 1000; } return fadeSplashScreenDuration; } @Override public void onPause(boolean multitasking) { if (HAS_BUILT_IN_SPLASH_SCREEN) { return; } // hide the splash screen to avoid leaking a window this.removeSplashScreen(true); } @Override public void onDestroy() { if (HAS_BUILT_IN_SPLASH_SCREEN) { return; } // hide the splash screen to avoid leaking a window this.removeSplashScreen(true); // If we set this to true onDestroy, we lose track when we go from page to page! // 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 { return false; } callbackContext.success(); return true; } @Override public Object onMessage(String id, Object data) { if (HAS_BUILT_IN_SPLASH_SCREEN) { return null; } if ("splashscreen".equals(id)) { if ("hide".equals(data.toString())) { this.removeSplashScreen(false); } else { this.showSplashScreen(false); } } else if ("spinner".equals(id)) { if ("stop".equals(data.toString())) { getView().setVisibility(View.VISIBLE); } } else if ("onReceivedError".equals(id)) { this.spinnerStop(); } return null; } // Don't add @Override so that plugin still compiles on 3.x.x for a while public void onConfigurationChanged(Configuration newConfig) { if (newConfig.orientation != orientation) { orientation = newConfig.orientation; // Splash drawable may change with orientation, so reload it. if (splashImageView != null) { int drawableId = preferences.getInteger("SplashDrawableId", 0); if (drawableId != 0) { splashImageView.setImageDrawable( cordova.getActivity().getResources().getDrawable(drawableId)); } } } } private void removeSplashScreen(final boolean forceHideImmediately) { cordova .getActivity() .runOnUiThread( new Runnable() { public void run() { if (splashDialog != null && splashDialog.isShowing()) { final int fadeSplashScreenDuration = getFadeDuration(); // CB-10692 If the plugin is being paused/destroyed, skip the fading and hide it // immediately if (fadeSplashScreenDuration > 0 && forceHideImmediately == false) { AlphaAnimation fadeOut = new AlphaAnimation(1, 0); fadeOut.setInterpolator(new DecelerateInterpolator()); fadeOut.setDuration(fadeSplashScreenDuration); splashImageView.setAnimation(fadeOut); splashImageView.startAnimation(fadeOut); fadeOut.setAnimationListener( new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { spinnerStop(); } @Override public void onAnimationEnd(Animation animation) { if (splashDialog != null && splashDialog.isShowing()) { splashDialog.dismiss(); splashDialog = null; splashImageView = null; } } @Override public void onAnimationRepeat(Animation animation) {} }); } else { spinnerStop(); splashDialog.dismiss(); splashDialog = null; splashImageView = null; } } } }); } /** Shows the splash screen over the full Activity */ @SuppressWarnings("deprecation") private void showSplashScreen(final boolean hideAfterDelay) { final int splashscreenTime = preferences.getInteger("SplashScreenDelay", DEFAULT_SPLASHSCREEN_DURATION); final int drawableId = preferences.getInteger("SplashDrawableId", 0); final int fadeSplashScreenDuration = getFadeDuration(); final int effectiveSplashDuration = Math.max(0, splashscreenTime - fadeSplashScreenDuration); lastHideAfterDelay = hideAfterDelay; // If the splash dialog is showing don't try to show it again if (splashDialog != null && splashDialog.isShowing()) { return; } if (drawableId == 0 || (splashscreenTime <= 0 && hideAfterDelay)) { return; } cordova .getActivity() .runOnUiThread( new Runnable() { public void run() { // Get reference to display Display display = cordova.getActivity().getWindowManager().getDefaultDisplay(); Context context = webView.getContext(); // Use an ImageView to render the image because of its flexible scaling options. splashImageView = new ImageView(context); splashImageView.setImageResource(drawableId); LayoutParams layoutParams = new LinearLayout.LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); splashImageView.setLayoutParams(layoutParams); splashImageView.setMinimumHeight(display.getHeight()); splashImageView.setMinimumWidth(display.getWidth()); // TODO: Use the background color of the webView's parent instead of using the // preference. splashImageView.setBackgroundColor( preferences.getInteger("backgroundColor", Color.BLACK)); if (isMaintainAspectRatio()) { // CENTER_CROP scale mode is equivalent to CSS "background-size:cover" splashImageView.setScaleType(ImageView.ScaleType.CENTER_CROP); } else { // FIT_XY scales image non-uniformly to fit into image view. splashImageView.setScaleType(ImageView.ScaleType.FIT_XY); } // 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(splashImageView); splashDialog.setCancelable(false); splashDialog.show(); if (preferences.getBoolean("ShowSplashScreenSpinner", true)) { spinnerStart(); } // Set Runnable to remove splash screen just in case if (hideAfterDelay) { final Handler handler = new Handler(); handler.postDelayed( new Runnable() { public void run() { if (lastHideAfterDelay) { removeSplashScreen(false); } } }, effectiveSplashDuration); } } }); } // Show only spinner in the center of the screen private void spinnerStart() { cordova .getActivity() .runOnUiThread( new Runnable() { public void run() { spinnerStop(); spinnerDialog = new ProgressDialog(webView.getContext()); spinnerDialog.setOnCancelListener( new DialogInterface.OnCancelListener() { public void onCancel(DialogInterface dialog) { spinnerDialog = null; } }); spinnerDialog.setCancelable(false); spinnerDialog.setIndeterminate(true); RelativeLayout centeredLayout = new RelativeLayout(cordova.getActivity()); centeredLayout.setGravity(Gravity.CENTER); centeredLayout.setLayoutParams( new RelativeLayout.LayoutParams( LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); ProgressBar progressBar = new ProgressBar(webView.getContext()); RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams( LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE); progressBar.setLayoutParams(layoutParams); centeredLayout.addView(progressBar); spinnerDialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); spinnerDialog .getWindow() .setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); spinnerDialog.show(); spinnerDialog.setContentView(centeredLayout); } }); } private void spinnerStop() { cordova .getActivity() .runOnUiThread( new Runnable() { public void run() { if (spinnerDialog != null && spinnerDialog.isShowing()) { spinnerDialog.dismiss(); spinnerDialog = null; } } }); } }