javamanager/javainstaller/installer/javasrc/com/nokia/mj/impl/installer/midp2/install/steps/PrepareSplashScreen.java
branchRCL_3
changeset 19 04becd199f91
child 50 023eef975703
child 60 6c158198356e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javamanager/javainstaller/installer/javasrc/com/nokia/mj/impl/installer/midp2/install/steps/PrepareSplashScreen.java	Tue Apr 27 16:30:29 2010 +0300
@@ -0,0 +1,440 @@
+/*
+* Copyright (c) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+
+
+package com.nokia.mj.impl.installer.midp2.install.steps;
+
+import com.nokia.mj.impl.installer.exetable.ExeBall;
+import com.nokia.mj.impl.installer.exetable.ExeStep;
+import com.nokia.mj.impl.installer.integrityservice.IntegrityService;
+import com.nokia.mj.impl.installer.utils.FileUtils;
+import com.nokia.mj.impl.installer.utils.Log;
+import com.nokia.mj.impl.installer.utils.SysUtil;
+import com.nokia.mj.impl.utils.Tokenizer;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.jar.JarFile;
+import java.util.jar.JarEntry;
+
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.ImageLoader;
+import org.eclipse.swt.graphics.Point;
+
+/**
+ * Installation step PrepareSplashScreen prepares splash
+ * screen images from MIDlet-Splash-Screen-Image attribute.
+ */
+public class PrepareSplashScreen extends ExeStep
+{
+    public void execute(ExeBall aBall)
+    {
+        InstallBall ball = (InstallBall)aBall;
+
+        String userImageRoot = ball.iSuite.getRootDir() +
+                               "startupimages" + FileUtils.pathSeparator();
+        if (!deleteSplashScreenDir(ball, userImageRoot))
+        {
+            // Deleting splash screen directory failed,
+            // do not process splash screen images.
+            return;
+        }
+
+        String autoImageRoot = ball.iSuite.getRootDir() +
+                               "autostartupimages" + FileUtils.pathSeparator();
+        if (!deleteSplashScreenDir(ball, autoImageRoot))
+        {
+            // Deleting screenshots directory failed,
+            // do not process splash screen images.
+            return;
+        }
+
+        if (ball.iJarFilename == null)
+        {
+            // No jar file available, do not proceed further.
+            return;
+        }
+
+        String attrName = "MIDlet-Splash-Screen-Image";
+        String attrValue = ball.getAttributeValue(attrName);
+        if (attrValue != null && attrValue.length() > 0)
+        {
+            if (attrValue.equalsIgnoreCase("suppress"))
+            {
+                // Splash screen is suppressed, do not
+                // process splash screen images.
+                Log.log("Splash screen suppressed");
+                // Create splash screen directory to indicate
+                // that splash screen has been suppressed.
+                createSplashScreenDir(ball, userImageRoot);
+                return;
+            }
+
+            // Get the screen size for portrait and landscape.
+            int screenWidth = SysUtil.getScreenWidth();
+            int screenHeight = SysUtil.getScreenHeight();
+            Point portraitScreenSize = new Point(screenWidth, screenHeight);
+            Point landscapeScreenSize = new Point(screenHeight, screenWidth);
+            if (screenWidth > screenHeight)
+            {
+                portraitScreenSize.x = screenHeight;
+                portraitScreenSize.y = screenWidth;
+                landscapeScreenSize.x = screenWidth;
+                landscapeScreenSize.y = screenHeight;
+            }
+            Log.log("Portrait screen size: " + portraitScreenSize);
+            Log.log("Landscape screen size: " + landscapeScreenSize);
+            // Get the sizes of all images specified in the attribute value.
+            ImageData[] currentImage = null;
+            String[] tokens = Tokenizer.split(attrValue, ",");
+            Point[] imageSizes = new Point[tokens.length];
+            for (int i = 0; i < tokens.length; i++)
+            {
+                tokens[i] = tokens[i].trim();
+                currentImage = loadImage(tokens[i], ball.iJarFilename);
+                if (currentImage == null)
+                {
+                    // Image loading failed, proceed to the next image.
+                    imageSizes[i] = new Point(0, 0);
+                    continue;
+                }
+                imageSizes[i] = new Point(
+                    currentImage[0].width, currentImage[0].height);
+            }
+            // Choose the images which best fill the portrait and
+            // landscape screens.
+            String portraitImageName = null;
+            String landscapeImageName = null;
+            int imageIndex = selectImage(portraitScreenSize, imageSizes);
+            if (imageIndex != -1)
+            {
+                portraitImageName = tokens[imageIndex];
+                Log.log("Selected portrait image " + imageIndex +
+                        ": " + portraitImageName);
+            }
+            imageIndex = selectImage(landscapeScreenSize, imageSizes);
+            if (imageIndex != -1)
+            {
+                landscapeImageName = tokens[imageIndex];
+                Log.log("Selected landscape image " + imageIndex +
+                        ": " + landscapeImageName);
+            }
+
+            // Save splash screen image to the disk.
+            if (portraitImageName != null &&
+                    landscapeImageName != null &&
+                    !portraitImageName.equals(landscapeImageName))
+            {
+                // Save portrait and landscape splash screen images.
+                createSplashScreenDir(ball, userImageRoot);
+                saveImage(portraitImageName, ball.iJarFilename,
+                          userImageRoot + "startupscreen_portrait",
+                          ball.iIntegrityService);
+                saveImage(landscapeImageName, ball.iJarFilename,
+                          userImageRoot + "startupscreen_landscape",
+                          ball.iIntegrityService);
+            }
+            else if (portraitImageName != null)
+            {
+                // Save one splash screen image.
+                createSplashScreenDir(ball, userImageRoot);
+                saveImage(portraitImageName, ball.iJarFilename,
+                          userImageRoot + "startupscreen",
+                          ball.iIntegrityService);
+            }
+            else if (landscapeImageName != null)
+            {
+                // Save one splash screen image.
+                createSplashScreenDir(ball, userImageRoot);
+                saveImage(landscapeImageName, ball.iJarFilename,
+                          userImageRoot + "startupscreen",
+                          ball.iIntegrityService);
+            }
+            else
+            {
+                Log.logWarning("No splash screen image selected.");
+            }
+        }
+        else
+        {
+            createSplashScreenDir(ball, autoImageRoot);
+        }
+    }
+
+    public void cancel(ExeBall aBall)
+    {
+        // nop
+    }
+
+    /**
+     * Deletes splash screen image directory if it exists.
+     *
+     * @return true if directory does not exist after this method returns,
+     * false if deleting existing directory fails
+     */
+    private static boolean deleteSplashScreenDir(
+        InstallBall aBall, String aImageRoot)
+    {
+        boolean result = true;
+        if (aBall.iOldSuite != null)
+        {
+            // Note that PrepareSplashScreen step is executed after
+            // CopyAppFiles step, which means that old image root has
+            // already been moved under new application suite root.
+            if (FileUtils.exists(aImageRoot))
+            {
+                // In case of update, remove old splash screen images.
+                result = aBall.iIntegrityService.delete(aImageRoot);
+                if (!result)
+                {
+                    Log.logWarning("Removing " + aImageRoot +
+                                   " failed, aborting splash screen" +
+                                   " image preparation.");
+                    return result;
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Creates splash screen image directory.
+     *
+     * @return true if directory exists after this method returns,
+     * false if creating directory fails
+     */
+    private static boolean createSplashScreenDir(
+        InstallBall aBall, String aImageRoot)
+    {
+        boolean result = true;
+        if (!FileUtils.exists(aImageRoot))
+        {
+            result = aBall.iIntegrityService.createDir(aImageRoot);
+            if (!result)
+            {
+                Log.logWarning("Creating " + aImageRoot +
+                               " failed, aborting splash screen" +
+                               " image preparation.");
+                return result;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Loads image from specified resource from given jar file.
+     *
+     * @param aResource resource file name
+     * @param aJar jar file name
+     * @return loaded image, or null if image loading fails
+     */
+    private static ImageData[] loadImage(String aResource, String aJar)
+    {
+        ImageData[] result = null;
+        JarFile jarFile = null;
+        InputStream is = null;
+        try
+        {
+            // Open jar file and input stream.
+            jarFile = new JarFile(aJar);
+            is = jarFile.getInputStream
+                 (new JarEntry(FileUtils.trimJarEntry(aResource)));
+            if (is != null)
+            {
+                result = (new ImageLoader()).load(is);
+                Log.log("Loaded image " + aResource + " from " + aJar);
+            }
+            else
+            {
+                Log.logWarning("Image " + aResource + " not found from " + aJar);
+            }
+        }
+        catch (Throwable t)
+        {
+            Log.logWarning("Loading image " + aResource + " from " +
+                           aJar + " failed", t);
+        }
+        finally
+        {
+            // Close streams and jar file.
+            if (is != null)
+            {
+                try
+                {
+                    is.close();
+                    is = null;
+                }
+                catch (IOException ioe)
+                {
+                    Log.logWarning("Closing InputStream failed", ioe);
+                }
+            }
+            if (jarFile != null)
+            {
+                try
+                {
+                    jarFile.close();
+                    jarFile = null;
+                }
+                catch (IOException ioe)
+                {
+                    Log.logWarning("Closing " + aJar + " failed", ioe);
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Save image from specified resource from given jar file to disk.
+     *
+     * @param aResource resource file name
+     * @param aJar jar file name
+     * @param aFilename filename for the image (without extension)
+     * @param aIs IntegrityService instance to be used in file creation
+     */
+    private static void saveImage(
+        String aResource, String aJar, String aFilename, IntegrityService aIs)
+    {
+        JarFile jarFile = null;
+        InputStream is = null;
+        OutputStream os = null;
+        String imageFilename = aFilename + ".img";
+        try
+        {
+            // Open jar file and input and output streams.
+            jarFile = new JarFile(aJar);
+            is = jarFile.getInputStream
+                 (new JarEntry(FileUtils.trimJarEntry(aResource)));
+            os = FileUtils.getOutputStream(imageFilename);
+            // Copy the image data from InputStream to OutputStream.
+            byte[] buf = new byte[16384];
+            int i = 0;
+            while ((i = is.read(buf)) != -1)
+            {
+                os.write(buf, 0, i);
+            }
+            // Record file creation to integrityService.
+            aIs.create(imageFilename);
+            Log.log("Saved image to " + imageFilename);
+        }
+        catch (Throwable t)
+        {
+            Log.logWarning("Saving image " + aResource + " from " +
+                           aJar + " to " + imageFilename + " failed", t);
+        }
+        finally
+        {
+            // Close streams and jar file.
+            if (os != null)
+            {
+                try
+                {
+                    os.close();
+                    os = null;
+                }
+                catch (IOException ioe)
+                {
+                    Log.logWarning("Closing OutputStream failed", ioe);
+                }
+            }
+            if (is != null)
+            {
+                try
+                {
+                    is.close();
+                    is = null;
+                }
+                catch (IOException ioe)
+                {
+                    Log.logWarning("Closing InputStream failed", ioe);
+                }
+            }
+            if (jarFile != null)
+            {
+                try
+                {
+                    jarFile.close();
+                    jarFile = null;
+                }
+                catch (IOException ioe)
+                {
+                    Log.logWarning("Closing " + aJar + " failed", ioe);
+                }
+            }
+        }
+    }
+
+    /**
+     * Selects image which best fills the given screen when image
+     * is scaled down so that it fits to the screen.
+     *
+     * @param aScreenSize screen size
+     * @param aImageSizes array of image sizes
+     * @return index to aImageSizes array for the selected image, or -1
+     * if selection could not be made
+     */
+    private static int selectImage(Point aScreenSize, Point[] aImageSizes)
+    {
+        // Amount of fill for the image which best fills
+        // the screen when scaled down to fit the screen.
+        int biggestFill = 0;
+        // Index of the image which best fills the screen.
+        int biggestFillIndex = -1;
+        for (int i = 0; i < aImageSizes.length; i++)
+        {
+            Point imageSize = aImageSizes[i];
+            if (imageSize.x > aScreenSize.x ||
+                    imageSize.y > aScreenSize.y)
+            {
+                imageSize = downscaleImageSize(aScreenSize, imageSize);
+            }
+            int imageFill = imageSize.x * imageSize.y;
+            if (imageFill > biggestFill)
+            {
+                biggestFill = imageFill;
+                biggestFillIndex = i;
+            }
+            Log.log("Image " + i + " fill amount " + imageFill);
+        }
+        return biggestFillIndex;
+    }
+
+    /**
+     * Downscales the given aImageSize so that it fits to aScreenSize.
+     */
+    private static Point downscaleImageSize(Point aScreenSize, Point aImageSize)
+    {
+        Point result = new Point(aImageSize.x, aImageSize.y);
+        if (result.x > aScreenSize.x)
+        {
+            // Downscale the image width.
+            result.y = result.y * aScreenSize.x / result.x;
+            result.x = aScreenSize.x;
+        }
+        if (result.y > aScreenSize.y)
+        {
+            // Downscale the image height.
+            result.x = result.x * aScreenSize.y / result.y;
+            result.y = aScreenSize.y;
+        }
+        Log.log("Image size " + aImageSize + " scaled down to " +
+                result + " for screen size " + aScreenSize);
+        return result;
+    }
+}