From e572f95eb794461ad8bb7459175fd3b034b5202e Mon Sep 17 00:00:00 2001 From: atalis Date: Wed, 25 Mar 2015 13:47:56 -0700 Subject: [PATCH 1/2] =?UTF-8?q?Added=20"SplashMaintainAspectRatio=E2=80=9D?= =?UTF-8?q?=20boolean=20preference=20to=20maintain=20Splash=20Screen=20asp?= =?UTF-8?q?ect=20ratio=20instead=20of=20scaling=20it=20to=20dialog.=20Adde?= =?UTF-8?q?d=20=E2=80=9CSplashReloadOnOrientationChange=E2=80=9D=20boolean?= =?UTF-8?q?=20preference=20to=20reload=20drawable=20when=20orientation=20c?= =?UTF-8?q?hanges.=20Notify=20plugins=20of=20orientation=20changes=20by=20?= =?UTF-8?q?posting=20"orientationChanged"=20message.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/cordova/CordovaActivity.java | 18 +++++ .../apache/cordova/SplashScreenInternal.java | 81 +++++++++++++++++-- 2 files changed, 94 insertions(+), 5 deletions(-) diff --git a/framework/src/org/apache/cordova/CordovaActivity.java b/framework/src/org/apache/cordova/CordovaActivity.java index cb8f27d4e..3de821a89 100755 --- a/framework/src/org/apache/cordova/CordovaActivity.java +++ b/framework/src/org/apache/cordova/CordovaActivity.java @@ -34,6 +34,7 @@ Licensed to the Apache Software Foundation (ASF) under one import android.content.Context; import android.content.DialogInterface; import android.content.Intent; +import android.content.res.Configuration; import android.graphics.Color; import android.media.AudioManager; import android.os.Bundle; @@ -131,6 +132,11 @@ public class CordovaActivity extends Activity implements CordovaInterface { protected Whitelist externalWhitelist; protected String launchUrl; protected ArrayList pluginEntries; + + /** + * Last orientation of device. Used to detect orientation changes. + */ + private int orientation; /** * Sets the authentication token. @@ -219,6 +225,9 @@ public void onCreate(Bundle savedInstanceState) { } super.onCreate(savedInstanceState); + + // Save startup orientation. Used to determine when orientation changes in "onConfigurationChanged". + orientation = getResources().getConfiguration().orientation; if(savedInstanceState != null) { @@ -948,4 +957,13 @@ protected void onSaveInstanceState(Bundle outState) outState.putString("callbackClass", cClass); } } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + if (newConfig.orientation != orientation) { + orientation = newConfig.orientation; + postMessage("orientationChanged", orientation); + } + } } diff --git a/framework/src/org/apache/cordova/SplashScreenInternal.java b/framework/src/org/apache/cordova/SplashScreenInternal.java index e1154a53f..d94fbb8fd 100644 --- a/framework/src/org/apache/cordova/SplashScreenInternal.java +++ b/framework/src/org/apache/cordova/SplashScreenInternal.java @@ -19,6 +19,9 @@ Licensed to the Apache Software Foundation (ASF) under one package org.apache.cordova; +import org.json.JSONArray; +import org.json.JSONException; + import android.app.Dialog; import android.app.ProgressDialog; import android.content.Context; @@ -28,12 +31,11 @@ Licensed to the Apache Software Foundation (ASF) under one import android.view.Display; import android.view.View; import android.view.ViewGroup; +import android.view.ViewGroup.LayoutParams; import android.view.WindowManager; +import android.widget.ImageView; 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 { @@ -41,6 +43,38 @@ public class SplashScreenInternal extends CordovaPlugin { private static Dialog splashDialog; private static ProgressDialog spinnerDialog; private static boolean firstShow = true; + + /** + * Set by "SplashMaintainAspectRatio" preference. If true, + * use an ImageView to display splash drawable maintaining aspect + * ratio. The result is equivalent to CSS "background-size:cover". + * This is useful for splash drawables that are not 9-patch and do + * not look good if scaled non-uniformly, for example images with text. + * This works best if splash images have large safe areas around edges. + * If this flag is false (default), the image is scaled as necessary + * to fit into the Splash Screen dialog. + */ + private boolean maintainAspectRatio; + + /** + * Set by "SplashReloadOnOrientationChange" preference. If true, + * reload splash drawable whenever the Activity handles a configuration + * change that included change of orientation. Setting this to true makes + * sense only if the app has different splash resources for portrait + * and landscape orientations. + */ + private boolean reloadOnOrientationChange; + + /** + * This ImageView is created and used only if {@link #maintainAspectRatio} is true. + */ + private ImageView splashImageView; + + /** + * Content view for splash dialog. This view either shows splash as its + * background or hosts {@link #splashImageView}, depending on preferences. + */ + private LinearLayout root; @Override protected void pluginInitialize() { @@ -60,6 +94,9 @@ protected void pluginInitialize() { preferences.set("SplashDrawableId", drawableId); } } + + maintainAspectRatio = preferences.getBoolean("SplashMaintainAspectRatio", false); + reloadOnOrientationChange = preferences.getBoolean("SplashReloadOnOrientationChange", false); firstShow = false; loadSpinner(); @@ -124,6 +161,24 @@ public Object onMessage(String id, Object data) { } } else if ("onReceivedError".equals(id)) { spinnerStop(); + } else if ("orientationChanged".equals(id)) { + // Reload splash screen drawable if the setting is enabled. + if (reloadOnOrientationChange && (splashImageView != null || root != null)) { + final int drawableId = preferences.getInteger("SplashDrawableId", 0); + if (drawableId != 0) { + cordova.getActivity().runOnUiThread(new Runnable() { + public void run() { + if (splashImageView != null) { + splashImageView.setImageDrawable(cordova.getActivity().getResources().getDrawable(drawableId)); + } + else if (root != null) { + // Using deprecated method for compatibility with older API levels. + root.setBackgroundDrawable(cordova.getActivity().getResources().getDrawable(drawableId)); + } + } + }); + } + } } return null; } @@ -134,6 +189,8 @@ public void run() { if (splashDialog != null && splashDialog.isShowing()) { splashDialog.dismiss(); splashDialog = null; + splashImageView = null; + root = null; } } }); @@ -162,7 +219,7 @@ public void run() { Context context = webView.getContext(); // Create the layout for the dialog - LinearLayout root = new LinearLayout(context); + root = new LinearLayout(context); root.setMinimumHeight(display.getHeight()); root.setMinimumWidth(display.getWidth()); root.setOrientation(LinearLayout.VERTICAL); @@ -172,7 +229,21 @@ public void run() { 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); + + if (maintainAspectRatio) { + // Use an ImageView to scale the image uniformly. + splashImageView = new ImageView(context); + splashImageView.setImageResource(drawableId); + LayoutParams layoutParams = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); + splashImageView.setLayoutParams(layoutParams); + + // CENTER_CROP scale mode is equivalent to CSS "background-size:cover" + splashImageView.setScaleType(ImageView.ScaleType.CENTER_CROP); + root.addView(splashImageView); + } + else { + root.setBackgroundResource(drawableId); + } // Create and show the dialog splashDialog = new Dialog(context, android.R.style.Theme_Translucent_NoTitleBar); From e02a50058749c7411f64a3cebe75555ed7b9f4d2 Mon Sep 17 00:00:00 2001 From: atalis Date: Wed, 25 Mar 2015 13:47:56 -0700 Subject: [PATCH 2/2] =?UTF-8?q?CB-8753=20Maintain=20splash=20screen=20aspe?= =?UTF-8?q?ct=20ratio=20-=20Added=20"SplashMaintainAspectRatio=E2=80=9D=20?= =?UTF-8?q?preference=20to=20maintain=20Splash=20Screen=20aspect=20ratio?= =?UTF-8?q?=20instead=20of=20scaling=20it=20to=20dialog.=20-=20Added=20?= =?UTF-8?q?=E2=80=9CSplashReloadOnOrientationChange=E2=80=9D=20boolean=20p?= =?UTF-8?q?reference=20to=20reload=20drawable=20when=20orientation=20chang?= =?UTF-8?q?es.=20-=20Notify=20plugins=20of=20orientation=20changes=20by=20?= =?UTF-8?q?posting=20"orientationChanged"=20message.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/cordova/CordovaActivity.java | 18 +++++ .../apache/cordova/SplashScreenInternal.java | 81 +++++++++++++++++-- 2 files changed, 94 insertions(+), 5 deletions(-) diff --git a/framework/src/org/apache/cordova/CordovaActivity.java b/framework/src/org/apache/cordova/CordovaActivity.java index cb8f27d4e..3de821a89 100755 --- a/framework/src/org/apache/cordova/CordovaActivity.java +++ b/framework/src/org/apache/cordova/CordovaActivity.java @@ -34,6 +34,7 @@ Licensed to the Apache Software Foundation (ASF) under one import android.content.Context; import android.content.DialogInterface; import android.content.Intent; +import android.content.res.Configuration; import android.graphics.Color; import android.media.AudioManager; import android.os.Bundle; @@ -131,6 +132,11 @@ public class CordovaActivity extends Activity implements CordovaInterface { protected Whitelist externalWhitelist; protected String launchUrl; protected ArrayList pluginEntries; + + /** + * Last orientation of device. Used to detect orientation changes. + */ + private int orientation; /** * Sets the authentication token. @@ -219,6 +225,9 @@ public void onCreate(Bundle savedInstanceState) { } super.onCreate(savedInstanceState); + + // Save startup orientation. Used to determine when orientation changes in "onConfigurationChanged". + orientation = getResources().getConfiguration().orientation; if(savedInstanceState != null) { @@ -948,4 +957,13 @@ protected void onSaveInstanceState(Bundle outState) outState.putString("callbackClass", cClass); } } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + if (newConfig.orientation != orientation) { + orientation = newConfig.orientation; + postMessage("orientationChanged", orientation); + } + } } diff --git a/framework/src/org/apache/cordova/SplashScreenInternal.java b/framework/src/org/apache/cordova/SplashScreenInternal.java index e1154a53f..d94fbb8fd 100644 --- a/framework/src/org/apache/cordova/SplashScreenInternal.java +++ b/framework/src/org/apache/cordova/SplashScreenInternal.java @@ -19,6 +19,9 @@ Licensed to the Apache Software Foundation (ASF) under one package org.apache.cordova; +import org.json.JSONArray; +import org.json.JSONException; + import android.app.Dialog; import android.app.ProgressDialog; import android.content.Context; @@ -28,12 +31,11 @@ Licensed to the Apache Software Foundation (ASF) under one import android.view.Display; import android.view.View; import android.view.ViewGroup; +import android.view.ViewGroup.LayoutParams; import android.view.WindowManager; +import android.widget.ImageView; 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 { @@ -41,6 +43,38 @@ public class SplashScreenInternal extends CordovaPlugin { private static Dialog splashDialog; private static ProgressDialog spinnerDialog; private static boolean firstShow = true; + + /** + * Set by "SplashMaintainAspectRatio" preference. If true, + * use an ImageView to display splash drawable maintaining aspect + * ratio. The result is equivalent to CSS "background-size:cover". + * This is useful for splash drawables that are not 9-patch and do + * not look good if scaled non-uniformly, for example images with text. + * This works best if splash images have large safe areas around edges. + * If this flag is false (default), the image is scaled as necessary + * to fit into the Splash Screen dialog. + */ + private boolean maintainAspectRatio; + + /** + * Set by "SplashReloadOnOrientationChange" preference. If true, + * reload splash drawable whenever the Activity handles a configuration + * change that included change of orientation. Setting this to true makes + * sense only if the app has different splash resources for portrait + * and landscape orientations. + */ + private boolean reloadOnOrientationChange; + + /** + * This ImageView is created and used only if {@link #maintainAspectRatio} is true. + */ + private ImageView splashImageView; + + /** + * Content view for splash dialog. This view either shows splash as its + * background or hosts {@link #splashImageView}, depending on preferences. + */ + private LinearLayout root; @Override protected void pluginInitialize() { @@ -60,6 +94,9 @@ protected void pluginInitialize() { preferences.set("SplashDrawableId", drawableId); } } + + maintainAspectRatio = preferences.getBoolean("SplashMaintainAspectRatio", false); + reloadOnOrientationChange = preferences.getBoolean("SplashReloadOnOrientationChange", false); firstShow = false; loadSpinner(); @@ -124,6 +161,24 @@ public Object onMessage(String id, Object data) { } } else if ("onReceivedError".equals(id)) { spinnerStop(); + } else if ("orientationChanged".equals(id)) { + // Reload splash screen drawable if the setting is enabled. + if (reloadOnOrientationChange && (splashImageView != null || root != null)) { + final int drawableId = preferences.getInteger("SplashDrawableId", 0); + if (drawableId != 0) { + cordova.getActivity().runOnUiThread(new Runnable() { + public void run() { + if (splashImageView != null) { + splashImageView.setImageDrawable(cordova.getActivity().getResources().getDrawable(drawableId)); + } + else if (root != null) { + // Using deprecated method for compatibility with older API levels. + root.setBackgroundDrawable(cordova.getActivity().getResources().getDrawable(drawableId)); + } + } + }); + } + } } return null; } @@ -134,6 +189,8 @@ public void run() { if (splashDialog != null && splashDialog.isShowing()) { splashDialog.dismiss(); splashDialog = null; + splashImageView = null; + root = null; } } }); @@ -162,7 +219,7 @@ public void run() { Context context = webView.getContext(); // Create the layout for the dialog - LinearLayout root = new LinearLayout(context); + root = new LinearLayout(context); root.setMinimumHeight(display.getHeight()); root.setMinimumWidth(display.getWidth()); root.setOrientation(LinearLayout.VERTICAL); @@ -172,7 +229,21 @@ public void run() { 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); + + if (maintainAspectRatio) { + // Use an ImageView to scale the image uniformly. + splashImageView = new ImageView(context); + splashImageView.setImageResource(drawableId); + LayoutParams layoutParams = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); + splashImageView.setLayoutParams(layoutParams); + + // CENTER_CROP scale mode is equivalent to CSS "background-size:cover" + splashImageView.setScaleType(ImageView.ScaleType.CENTER_CROP); + root.addView(splashImageView); + } + else { + root.setBackgroundResource(drawableId); + } // Create and show the dialog splashDialog = new Dialog(context, android.R.style.Theme_Translucent_NoTitleBar);