|
1 /* |
|
2 * Copyright (c) 2008-2010 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 package com.nokia.mj.impl.installer.midp2.install.steps; |
|
20 |
|
21 import com.nokia.mj.impl.installer.ui.ApplicationInfo; |
|
22 import com.nokia.mj.impl.installer.ui.LaunchAppInfo; |
|
23 import com.nokia.mj.impl.installer.applicationregistrator.ApplicationRegistrator; |
|
24 import com.nokia.mj.impl.installer.captainservice.CaptainService; |
|
25 import com.nokia.mj.impl.installer.exetable.ExeBall; |
|
26 import com.nokia.mj.impl.installer.exetable.ExeStep; |
|
27 import com.nokia.mj.impl.installer.Installer; |
|
28 import com.nokia.mj.impl.installer.utils.FileUtils; |
|
29 import com.nokia.mj.impl.installer.utils.InstallerException; |
|
30 import com.nokia.mj.impl.installer.utils.Log; |
|
31 import com.nokia.mj.impl.installer.utils.Platform; |
|
32 import com.nokia.mj.impl.utils.Uid; |
|
33 |
|
34 import java.io.InputStream; |
|
35 import java.io.IOException; |
|
36 import java.util.Vector; |
|
37 import java.util.jar.JarFile; |
|
38 import java.util.jar.JarEntry; |
|
39 |
|
40 public class FinalizeInstallation extends ExeStep |
|
41 { |
|
42 // JarFile instance, used for getting icon InputStreams. |
|
43 private JarFile iJarFile = null; |
|
44 |
|
45 public void execute(ExeBall aBall) |
|
46 { |
|
47 InstallBall ball = (InstallBall)aBall; |
|
48 ball.log("Finalizing installation..."); |
|
49 |
|
50 // If posting OTA status notifications is still going on, |
|
51 // stop it now and continue when next installation is made. |
|
52 ball.getNotificationPoster().stop(); |
|
53 |
|
54 // Cleanup security components. |
|
55 ball.cleanupSecurity(); |
|
56 |
|
57 // If -forcecancel option was specified, abort execution |
|
58 // before committing anything. |
|
59 if (ball.iArgs.get("forcecancel") != null) |
|
60 { |
|
61 InstallerException.internalError("FORCED CANCEL"); |
|
62 } |
|
63 |
|
64 // User is not allowed to cancel installation after this step. |
|
65 ball.setCanCancel(false); |
|
66 |
|
67 checkWaitAttribute(ball, "before storage commit"); |
|
68 |
|
69 // StorageHandler must be committed before ApplicationRegistrator |
|
70 // so that platform specific application registry can use the data |
|
71 // in Java Storage (S60 AppArc application list re-scan) |
|
72 ball.iStorageHandler.commitSession(); |
|
73 |
|
74 // StorageHandler commit is asynchronous. In case of |
|
75 // conversion installation or preinstallation wait for |
|
76 // a while so that the commit can be done before the |
|
77 // application registrator commit causes accesses to |
|
78 // Storage (S60 AppArc application list re-scan) |
|
79 if (ball.iConversionInstallation || |
|
80 ball.iPreinstallation) |
|
81 { |
|
82 try |
|
83 { |
|
84 Thread.sleep(1000); |
|
85 } |
|
86 catch (InterruptedException ie) |
|
87 { } |
|
88 } |
|
89 |
|
90 Log.log("StorageHandler committed"); |
|
91 |
|
92 checkWaitAttribute(ball, "after storage commit"); |
|
93 |
|
94 ball.iSifRegistrator.commitSession(); |
|
95 Log.log("SifRegistrator committed"); |
|
96 |
|
97 checkWaitAttribute(ball, "after sif commit"); |
|
98 |
|
99 // ApplicationRegistrator session must be commited before |
|
100 // IntegrityService session so that temp icon files |
|
101 // can be removed. |
|
102 // Make synchronous commit so that the application |
|
103 // becomes visible to all parts of the system before |
|
104 // installer finishes. |
|
105 ball.iApplicationRegistrator.commitSession(true); |
|
106 |
|
107 Log.log("ApplicationRegistrator committed"); |
|
108 |
|
109 checkWaitAttribute(ball, "after apparc commit"); |
|
110 |
|
111 boolean result = ball.iIntegrityService.commit(); |
|
112 if (!result) |
|
113 { |
|
114 InstallerException.internalError("IntegrityService commit failed"); |
|
115 } |
|
116 Log.log("IntegrityService committed"); |
|
117 |
|
118 checkWaitAttribute(ball, "after integrityservice commit"); |
|
119 |
|
120 ball.iInstallationNotifier.finish( |
|
121 ball.iSuite.getUid(), ball.iInstallationNotifier.INSTALL_OK); |
|
122 |
|
123 // All sessions have been committed, do not throw |
|
124 // exceptions anymore after this point! |
|
125 |
|
126 Uid[] uids = ball.iSuite.getApplicationUids(); |
|
127 |
|
128 try |
|
129 { |
|
130 // Notify platform that applications have been added or updated. |
|
131 ball.iSifRegistrator.notifyAppChange( |
|
132 uids, (ball.iOldSuite != null? |
|
133 ball.iSifRegistrator.APP_UPDATED: |
|
134 ball.iSifRegistrator.APP_ADDED)); |
|
135 } |
|
136 catch (Throwable t) |
|
137 { |
|
138 Log.logError("SifRegistrator.notifyAppChange failed", t); |
|
139 } |
|
140 |
|
141 if (ball.iCaptainMsgs) |
|
142 { |
|
143 // Notify JavaCaptain that application has been installed. |
|
144 Uid[] oldUids = null; |
|
145 if (ball.iOldSuite != null) |
|
146 { |
|
147 oldUids = ball.iOldSuite.getApplicationUids(); |
|
148 } |
|
149 ball.getCaptainService().appUpdated(oldUids, uids); |
|
150 Log.log("JavaCaptain notified"); |
|
151 } |
|
152 |
|
153 String midletName = ball.getAttributeValue("MIDlet-Name"); |
|
154 ball.log("Application " + midletName + " successfully installed."); |
|
155 ball.log(ball.iSuite.toShortString()); |
|
156 |
|
157 // Store the uids to Installer static variable |
|
158 // in case CommsInstaller has to send them to |
|
159 // TCK Runner or preinstaller |
|
160 Installer.setInstalledUids(ball.iSuite.getUid(), uids); |
|
161 |
|
162 if (!ball.isSilent()) |
|
163 { |
|
164 if (ball.getInstallerUi() != null && Platform.isS60()) |
|
165 { |
|
166 if (ball.LAUNCH_APP_QUERY) |
|
167 { |
|
168 // Set installation progress to 100% before |
|
169 // displaying application launch query. |
|
170 ball.iInstallationNotifier.set( |
|
171 ball.iInstallationNotifier.getMax()); |
|
172 // Display launch application query to the user. |
|
173 createLaunchAppQueryThread(ball); |
|
174 } |
|
175 } |
|
176 if (Platform.isLinux() && ball.iCaptainMsgs) |
|
177 { |
|
178 // Launch the installed application |
|
179 try |
|
180 { |
|
181 // CaptainService.launchApp() uses RLC message. |
|
182 //ball.getCaptainService().launchApp(uids[0]); |
|
183 // CaptainService.startApp() uses installer specific |
|
184 // message. |
|
185 ball.getCaptainService().startApp(new Uid[] { uids[0] }); |
|
186 } |
|
187 catch (InstallerException ie) |
|
188 { |
|
189 Log.log("Launching application failed: " + ie.toString()); |
|
190 } |
|
191 } |
|
192 } |
|
193 } |
|
194 |
|
195 public void cancel(ExeBall aBall) |
|
196 { |
|
197 // nop |
|
198 } |
|
199 |
|
200 /** |
|
201 * Constructs a new LaunchAppInfo object basing on given InstallBall. |
|
202 */ |
|
203 private LaunchAppInfo createLaunchAppInfo(InstallBall aBall) |
|
204 { |
|
205 // Get suite icon InputStream. |
|
206 InputStream suiteIconInputStream = null; |
|
207 String suiteIconPath = aBall.iSuite.getAttributeValue("MIDlet-Icon"); |
|
208 if (suiteIconPath != null) |
|
209 { |
|
210 try |
|
211 { |
|
212 if (iJarFile == null) |
|
213 { |
|
214 // Temp files have already been deleted, |
|
215 // get the icon from installed jar file. |
|
216 iJarFile = new JarFile(aBall.iSuite.getJarPath()); |
|
217 } |
|
218 suiteIconInputStream = |
|
219 iJarFile.getInputStream |
|
220 (new JarEntry(FileUtils.trimJarEntry(suiteIconPath))); |
|
221 Log.log("LaunchAppInfo: suite icon " + suiteIconPath); |
|
222 } |
|
223 catch (IOException ioe) |
|
224 { |
|
225 Log.logWarning("Getting InputStream for suite icon failed", ioe); |
|
226 } |
|
227 } |
|
228 |
|
229 // Get application icon InputStreams. |
|
230 InputStream[] appIconInputStreams = null; |
|
231 Vector appInfos = aBall.iSuite.getApplications(); |
|
232 if (appInfos != null) |
|
233 { |
|
234 appIconInputStreams = new InputStream[appInfos.size()]; |
|
235 try |
|
236 { |
|
237 if (iJarFile == null) |
|
238 { |
|
239 // Temp files have already been deleted, |
|
240 // get the icon from installed jar file. |
|
241 iJarFile = new JarFile(aBall.iSuite.getJarPath()); |
|
242 } |
|
243 for (int i = 0; i < appIconInputStreams.length; i++) |
|
244 { |
|
245 String iconPath = |
|
246 ((com.nokia.mj.impl.installer.storagehandler.ApplicationInfo) |
|
247 appInfos.elementAt(i)).getIconPath(); |
|
248 if (iconPath != null && iconPath.length() > 0) |
|
249 { |
|
250 appIconInputStreams[i] = |
|
251 iJarFile.getInputStream |
|
252 (new JarEntry(FileUtils.trimJarEntry(iconPath))); |
|
253 Log.log("LaunchAppInfo: app icon " + i + ": " + iconPath); |
|
254 } |
|
255 else |
|
256 { |
|
257 appIconInputStreams[i] = null; |
|
258 Log.log("LaunchAppInfo: app icon " + i + ": null"); |
|
259 } |
|
260 } |
|
261 } |
|
262 catch (IOException ioe) |
|
263 { |
|
264 Log.logWarning("Getting InputStream for application icon failed", ioe); |
|
265 } |
|
266 } |
|
267 |
|
268 return new LaunchAppInfo |
|
269 (ConfirmInstallation.getApplicationInfos(aBall), |
|
270 appIconInputStreams, suiteIconInputStream, suiteIconPath); |
|
271 } |
|
272 |
|
273 /** |
|
274 * Creates and starts a new thread for asking launch |
|
275 * application query from the user. |
|
276 */ |
|
277 private void createLaunchAppQueryThread(InstallBall aBall) |
|
278 { |
|
279 final InstallBall ball = aBall; |
|
280 ball.iDialogOpen = true; |
|
281 new Thread(new Runnable() |
|
282 { |
|
283 public void run() |
|
284 { |
|
285 // Create and init LaunchAppinfo object. |
|
286 LaunchAppInfo launchAppInfo = createLaunchAppInfo(ball); |
|
287 // Display the query. |
|
288 boolean launchApp = |
|
289 ball.getInstallerUi().launchAppQuery(launchAppInfo); |
|
290 |
|
291 // Close the jarFile and icon InputStreams. |
|
292 if (iJarFile != null) |
|
293 { |
|
294 try |
|
295 { |
|
296 iJarFile.close(); // Closes also InputStreams |
|
297 iJarFile = null; |
|
298 } |
|
299 catch (IOException ioe) |
|
300 { |
|
301 Log.logWarning("Closing icon InputStreams failed", ioe); |
|
302 } |
|
303 } |
|
304 |
|
305 //if (ball.iSifRegistrator.getSifMode() > 0 && launchApp) |
|
306 //{ |
|
307 // ball.iSifRegistrator.launchAppView(); |
|
308 //} |
|
309 //else |
|
310 if (ball.iCaptainMsgs && launchApp && |
|
311 launchAppInfo.getApplications() != null && |
|
312 launchAppInfo.getApplications().length > 0) |
|
313 { |
|
314 int selection = launchAppInfo.getSelection(); |
|
315 Log.log("Launching application " + selection + ": " + |
|
316 launchAppInfo.getApplications()[selection] |
|
317 .getName()); |
|
318 ball.getCaptainService().startApp |
|
319 (new Uid[] { launchAppInfo |
|
320 .getApplications()[selection] |
|
321 .getUid() |
|
322 }); |
|
323 } |
|
324 else |
|
325 { |
|
326 Log.log("No application launch"); |
|
327 } |
|
328 |
|
329 synchronized (ball) |
|
330 { |
|
331 ball.iDialogOpen = false; |
|
332 // Notify WaitForLaunchAppQuery step that |
|
333 // we are finished with launch app query. |
|
334 ball.notify(); |
|
335 } |
|
336 } |
|
337 }, "LaunchAppQueryThread").start(); |
|
338 } |
|
339 |
|
340 /** |
|
341 * Wait a moment if Nokia-MIDlet-Install-Commit-Wait atribute has been set. |
|
342 */ |
|
343 private static void checkWaitAttribute(InstallBall aBall, String aWaitMsg) |
|
344 { |
|
345 String commitWaitEnabled = System.getProperty( |
|
346 "com.nokia.mj.impl.installer.commitwaitenabled"); |
|
347 if (commitWaitEnabled != null && |
|
348 commitWaitEnabled.equalsIgnoreCase("true")) |
|
349 { |
|
350 Log.log("commitWaitEnabled: " + commitWaitEnabled); |
|
351 String waitValue = aBall.getAttributeValue( |
|
352 "Nokia-MIDlet-Install-Commit-Wait"); |
|
353 if (waitValue != null && waitValue.equalsIgnoreCase(aWaitMsg)) |
|
354 { |
|
355 try |
|
356 { |
|
357 int waitTime = 30; // secs |
|
358 Log.log("Waiting " + waitTime + " secs " + aWaitMsg); |
|
359 Thread.sleep(waitTime * 1000); |
|
360 } |
|
361 catch (InterruptedException ie) |
|
362 { |
|
363 } |
|
364 } |
|
365 } |
|
366 } |
|
367 } |