arnaucube
arnaucube/commonroutesServerPublic Self-hosted repository
commonroutesServer/www/plugins/cordova-plugin-splashscreen/src/android/SplashScreen.java
www/plugins/cordova-plugin-splashscreen/src/android/SplashScreen.javaRaw
  1/*
  2       Licensed to the Apache Software Foundation (ASF) under one
  3       or more contributor license agreements.  See the NOTICE file
  4       distributed with this work for additional information
  5       regarding copyright ownership.  The ASF licenses this file
  6       to you under the Apache License, Version 2.0 (the
  7       "License"); you may not use this file except in compliance
  8       with the License.  You may obtain a copy of the License at
  9
 10         http://www.apache.org/licenses/LICENSE-2.0
 11
 12       Unless required by applicable law or agreed to in writing,
 13       software distributed under the License is distributed on an
 14       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 15       KIND, either express or implied.  See the License for the
 16       specific language governing permissions and limitations
 17       under the License.
 18*/
 19
 20package org.apache.cordova.splashscreen;
 21
 22import android.app.Dialog;
 23import android.app.ProgressDialog;
 24import android.content.Context;
 25import android.content.DialogInterface;
 26import android.content.res.Configuration;
 27import android.graphics.Color;
 28import android.graphics.drawable.ColorDrawable;
 29import android.os.Handler;
 30import android.view.Display;
 31import android.view.Gravity;
 32import android.view.View;
 33import android.view.ViewGroup.LayoutParams;
 34import android.view.WindowManager;
 35import android.view.animation.Animation;
 36import android.view.animation.AlphaAnimation;
 37import android.view.animation.DecelerateInterpolator;
 38import android.widget.ImageView;
 39import android.widget.LinearLayout;
 40import android.widget.ProgressBar;
 41import android.widget.RelativeLayout;
 42
 43import org.apache.cordova.CallbackContext;
 44import org.apache.cordova.CordovaPlugin;
 45import org.apache.cordova.CordovaWebView;
 46import org.json.JSONArray;
 47import org.json.JSONException;
 48
 49public class SplashScreen extends CordovaPlugin {
 50    private static final String LOG_TAG = "SplashScreen";
 51    // Cordova 3.x.x has a copy of this plugin bundled with it (SplashScreenInternal.java).
 52    // Enable functionality only if running on 4.x.x.
 53    private static final boolean HAS_BUILT_IN_SPLASH_SCREEN = Integer.valueOf(CordovaWebView.CORDOVA_VERSION.split("\\.")[0]) < 4;
 54    private static final int DEFAULT_SPLASHSCREEN_DURATION = 3000;
 55    private static final int DEFAULT_FADE_DURATION = 500;
 56    private static Dialog splashDialog;
 57    private static ProgressDialog spinnerDialog;
 58    private static boolean firstShow = true;
 59    private static boolean lastHideAfterDelay; // https://issues.apache.org/jira/browse/CB-9094
 60
 61    /**
 62     * Displays the splash drawable.
 63     */
 64    private ImageView splashImageView;
 65
 66    /**
 67     * Remember last device orientation to detect orientation changes.
 68     */
 69    private int orientation;
 70
 71    // Helper to be compile-time compatible with both Cordova 3.x and 4.x.
 72    private View getView() {
 73        try {
 74            return (View)webView.getClass().getMethod("getView").invoke(webView);
 75        } catch (Exception e) {
 76            return (View)webView;
 77        }
 78    }
 79
 80    @Override
 81    protected void pluginInitialize() {
 82        if (HAS_BUILT_IN_SPLASH_SCREEN) {
 83            return;
 84        }
 85        // Make WebView invisible while loading URL
 86        // CB-11326 Ensure we're calling this on UI thread
 87        cordova.getActivity().runOnUiThread(new Runnable() {
 88            @Override
 89            public void run() {
 90                getView().setVisibility(View.INVISIBLE);
 91            }
 92        });
 93        int drawableId = preferences.getInteger("SplashDrawableId", 0);
 94        if (drawableId == 0) {
 95            String splashResource = preferences.getString("SplashScreen", "screen");
 96            if (splashResource != null) {
 97                drawableId = cordova.getActivity().getResources().getIdentifier(splashResource, "drawable", cordova.getActivity().getClass().getPackage().getName());
 98                if (drawableId == 0) {
 99                    drawableId = cordova.getActivity().getResources().getIdentifier(splashResource, "drawable", cordova.getActivity().getPackageName());
100                }
101                preferences.set("SplashDrawableId", drawableId);
102            }
103        }
104
105        // Save initial orientation.
106        orientation = cordova.getActivity().getResources().getConfiguration().orientation;
107
108        if (firstShow) {
109            boolean autoHide = preferences.getBoolean("AutoHideSplashScreen", true);
110            showSplashScreen(autoHide);
111        }
112
113        if (preferences.getBoolean("SplashShowOnlyFirstTime", true)) {
114            firstShow = false;
115        }
116    }
117
118    /**
119     * Shorter way to check value of "SplashMaintainAspectRatio" preference.
120     */
121    private boolean isMaintainAspectRatio () {
122        return preferences.getBoolean("SplashMaintainAspectRatio", false);
123    }
124
125    private int getFadeDuration () {
126        int fadeSplashScreenDuration = preferences.getBoolean("FadeSplashScreen", true) ?
127            preferences.getInteger("FadeSplashScreenDuration", DEFAULT_FADE_DURATION) : 0;
128
129        if (fadeSplashScreenDuration < 30) {
130            // [CB-9750] This value used to be in decimal seconds, so we will assume that if someone specifies 10
131            // they mean 10 seconds, and not the meaningless 10ms
132            fadeSplashScreenDuration *= 1000;
133        }
134
135        return fadeSplashScreenDuration;
136    }
137
138    @Override
139    public void onPause(boolean multitasking) {
140        if (HAS_BUILT_IN_SPLASH_SCREEN) {
141            return;
142        }
143        // hide the splash screen to avoid leaking a window
144        this.removeSplashScreen(true);
145    }
146
147    @Override
148    public void onDestroy() {
149        if (HAS_BUILT_IN_SPLASH_SCREEN) {
150            return;
151        }
152        // hide the splash screen to avoid leaking a window
153        this.removeSplashScreen(true);
154        // If we set this to true onDestroy, we lose track when we go from page to page!
155        //firstShow = true;
156    }
157
158    @Override
159    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
160        if (action.equals("hide")) {
161            cordova.getActivity().runOnUiThread(new Runnable() {
162                public void run() {
163                    webView.postMessage("splashscreen", "hide");
164                }
165            });
166        } else if (action.equals("show")) {
167            cordova.getActivity().runOnUiThread(new Runnable() {
168                public void run() {
169                    webView.postMessage("splashscreen", "show");
170                }
171            });
172        } else {
173            return false;
174        }
175
176        callbackContext.success();
177        return true;
178    }
179
180    @Override
181    public Object onMessage(String id, Object data) {
182        if (HAS_BUILT_IN_SPLASH_SCREEN) {
183            return null;
184        }
185        if ("splashscreen".equals(id)) {
186            if ("hide".equals(data.toString())) {
187                this.removeSplashScreen(false);
188            } else {
189                this.showSplashScreen(false);
190            }
191        } else if ("spinner".equals(id)) {
192            if ("stop".equals(data.toString())) {
193                getView().setVisibility(View.VISIBLE);
194            }
195        } else if ("onReceivedError".equals(id)) {
196            this.spinnerStop();
197        }
198        return null;
199    }
200
201    // Don't add @Override so that plugin still compiles on 3.x.x for a while
202    public void onConfigurationChanged(Configuration newConfig) {
203        if (newConfig.orientation != orientation) {
204            orientation = newConfig.orientation;
205
206            // Splash drawable may change with orientation, so reload it.
207            if (splashImageView != null) {
208                int drawableId = preferences.getInteger("SplashDrawableId", 0);
209                if (drawableId != 0) {
210                    splashImageView.setImageDrawable(cordova.getActivity().getResources().getDrawable(drawableId));
211                }
212            }
213        }
214    }
215
216    private void removeSplashScreen(final boolean forceHideImmediately) {
217        cordova.getActivity().runOnUiThread(new Runnable() {
218            public void run() {
219                if (splashDialog != null && splashDialog.isShowing()) {
220                    final int fadeSplashScreenDuration = getFadeDuration();
221                    // CB-10692 If the plugin is being paused/destroyed, skip the fading and hide it immediately
222                    if (fadeSplashScreenDuration > 0 && forceHideImmediately == false) {
223                        AlphaAnimation fadeOut = new AlphaAnimation(1, 0);
224                        fadeOut.setInterpolator(new DecelerateInterpolator());
225                        fadeOut.setDuration(fadeSplashScreenDuration);
226
227                        splashImageView.setAnimation(fadeOut);
228                        splashImageView.startAnimation(fadeOut);
229
230                        fadeOut.setAnimationListener(new Animation.AnimationListener() {
231                            @Override
232                            public void onAnimationStart(Animation animation) {
233                                spinnerStop();
234                            }
235
236                            @Override
237                            public void onAnimationEnd(Animation animation) {
238                                if (splashDialog != null && splashDialog.isShowing()) {
239                                    splashDialog.dismiss();
240                                    splashDialog = null;
241                                    splashImageView = null;
242                                }
243                            }
244
245                            @Override
246                            public void onAnimationRepeat(Animation animation) {
247                            }
248                        });
249                    } else {
250                        spinnerStop();
251                        splashDialog.dismiss();
252                        splashDialog = null;
253                        splashImageView = null;
254                    }
255                }
256            }
257        });
258    }
259
260    /**
261     * Shows the splash screen over the full Activity
262     */
263    @SuppressWarnings("deprecation")
264    private void showSplashScreen(final boolean hideAfterDelay) {
265        final int splashscreenTime = preferences.getInteger("SplashScreenDelay", DEFAULT_SPLASHSCREEN_DURATION);
266        final int drawableId = preferences.getInteger("SplashDrawableId", 0);
267
268        final int fadeSplashScreenDuration = getFadeDuration();
269        final int effectiveSplashDuration = Math.max(0, splashscreenTime - fadeSplashScreenDuration);
270
271        lastHideAfterDelay = hideAfterDelay;
272
273        // If the splash dialog is showing don't try to show it again
274        if (splashDialog != null && splashDialog.isShowing()) {
275            return;
276        }
277        if (drawableId == 0 || (splashscreenTime <= 0 && hideAfterDelay)) {
278            return;
279        }
280
281        cordova.getActivity().runOnUiThread(new Runnable() {
282            public void run() {
283                // Get reference to display
284                Display display = cordova.getActivity().getWindowManager().getDefaultDisplay();
285                Context context = webView.getContext();
286
287                // Use an ImageView to render the image because of its flexible scaling options.
288                splashImageView = new ImageView(context);
289                splashImageView.setImageResource(drawableId);
290                LayoutParams layoutParams = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
291                splashImageView.setLayoutParams(layoutParams);
292
293                splashImageView.setMinimumHeight(display.getHeight());
294                splashImageView.setMinimumWidth(display.getWidth());
295
296                // TODO: Use the background color of the webView's parent instead of using the preference.
297                splashImageView.setBackgroundColor(preferences.getInteger("backgroundColor", Color.BLACK));
298
299                if (isMaintainAspectRatio()) {
300                    // CENTER_CROP scale mode is equivalent to CSS "background-size:cover"
301                    splashImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
302                }
303                else {
304                    // FIT_XY scales image non-uniformly to fit into image view.
305                    splashImageView.setScaleType(ImageView.ScaleType.FIT_XY);
306                }
307
308                // Create and show the dialog
309                splashDialog = new Dialog(context, android.R.style.Theme_Translucent_NoTitleBar);
310                // check to see if the splash screen should be full screen
311                if ((cordova.getActivity().getWindow().getAttributes().flags & WindowManager.LayoutParams.FLAG_FULLSCREEN)
312                        == WindowManager.LayoutParams.FLAG_FULLSCREEN) {
313                    splashDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
314                            WindowManager.LayoutParams.FLAG_FULLSCREEN);
315                }
316                splashDialog.setContentView(splashImageView);
317                splashDialog.setCancelable(false);
318                splashDialog.show();
319
320                if (preferences.getBoolean("ShowSplashScreenSpinner", true)) {
321                    spinnerStart();
322                }
323
324                // Set Runnable to remove splash screen just in case
325                if (hideAfterDelay) {
326                    final Handler handler = new Handler();
327                    handler.postDelayed(new Runnable() {
328                        public void run() {
329                            if (lastHideAfterDelay) {
330                                removeSplashScreen(false);
331                            }
332                        }
333                    }, effectiveSplashDuration);
334                }
335            }
336        });
337    }
338
339    // Show only spinner in the center of the screen
340    private void spinnerStart() {
341        cordova.getActivity().runOnUiThread(new Runnable() {
342            public void run() {
343                spinnerStop();
344
345                spinnerDialog = new ProgressDialog(webView.getContext());
346                spinnerDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
347                    public void onCancel(DialogInterface dialog) {
348                        spinnerDialog = null;
349                    }
350                });
351
352                spinnerDialog.setCancelable(false);
353                spinnerDialog.setIndeterminate(true);
354
355                RelativeLayout centeredLayout = new RelativeLayout(cordova.getActivity());
356                centeredLayout.setGravity(Gravity.CENTER);
357                centeredLayout.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
358
359                ProgressBar progressBar = new ProgressBar(webView.getContext());
360                RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
361                layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
362                progressBar.setLayoutParams(layoutParams);
363
364                centeredLayout.addView(progressBar);
365
366                spinnerDialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
367                spinnerDialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
368
369                spinnerDialog.show();
370                spinnerDialog.setContentView(centeredLayout);
371            }
372        });
373    }
374
375    private void spinnerStop() {
376        cordova.getActivity().runOnUiThread(new Runnable() {
377            public void run() {
378                if (spinnerDialog != null && spinnerDialog.isShowing()) {
379                    spinnerDialog.dismiss();
380                    spinnerDialog = null;
381                }
382            }
383        });
384    }
385}