1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-/ * ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
14 * The Original Code is Mozilla Android code.
16 * The Initial Developer of the Original Code is Mozilla Foundation.
17 * Portions created by the Initial Developer are Copyright (C) 2009-2010
18 * the Initial Developer. All Rights Reserved.
21 * Vladimir Vukicevic <vladimir@pobox.com>
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
37 package org
.mozilla
.gecko
;
41 import java
.util
.zip
.*;
46 import android
.text
.*;
47 import android
.view
.*;
48 import android
.view
.inputmethod
.*;
49 import android
.content
.*;
50 import android
.graphics
.*;
51 import android
.widget
.*;
52 import android
.hardware
.*;
54 import android
.util
.*;
56 abstract public class GeckoApp
59 public static FrameLayout mainLayout
;
60 public static GeckoSurfaceView surfaceView
;
61 public static GeckoApp mAppContext
;
65 // unpack files in the components directory
67 // and then fire us up
68 Intent i
= getIntent();
69 String env
= i
.getStringExtra("env0");
70 GeckoAppShell
.runGecko(getApplication().getPackageResourcePath(),
71 i
.getStringExtra("args"),
75 /** Called when the activity is first created. */
77 public void onCreate(Bundle savedInstanceState
)
79 Log
.i("GeckoApp", "create");
80 super.onCreate(savedInstanceState
);
84 // hide our window's title, we don't want it
85 requestWindowFeature(Window
.FEATURE_NO_TITLE
);
87 surfaceView
= new GeckoSurfaceView(this);
89 mainLayout
= new FrameLayout(this);
90 mainLayout
.addView(surfaceView
,
91 new FrameLayout
.LayoutParams(FrameLayout
.LayoutParams
.FILL_PARENT
,
92 FrameLayout
.LayoutParams
.FILL_PARENT
));
94 boolean useLaunchButton
= false;
96 String intentAction
= getIntent().getAction();
97 if (intentAction
!= null && intentAction
.equals("org.mozilla.gecko.DEBUG"))
98 useLaunchButton
= true;
100 setContentView(mainLayout
,
101 new ViewGroup
.LayoutParams(ViewGroup
.LayoutParams
.FILL_PARENT
,
102 ViewGroup
.LayoutParams
.FILL_PARENT
));
104 if (!GeckoAppShell
.sGeckoRunning
) {
105 // Load our JNI libs; we need to do this before launch() because
106 // setInitialSize will be called even before Gecko is actually up
108 GeckoAppShell
.loadGeckoLibs();
110 if (useLaunchButton
) {
111 final Button b
= new Button(this);
113 b
.setOnClickListener(new Button
.OnClickListener() {
114 public void onClick (View v
) {
115 // hide the button so we can't be launched again
116 mainLayout
.removeView(b
);
120 mainLayout
.addView(b
, 300, 200);
126 super.onCreate(savedInstanceState
);
130 protected void onNewIntent(Intent intent
) {
131 final String action
= intent
.getAction();
132 if (Intent
.ACTION_VIEW
.equals(action
)) {
133 String uri
= intent
.getDataString();
134 GeckoAppShell
.sendEventToGecko(new GeckoEvent(uri
));
135 Log
.i("GeckoApp","onNewIntent: "+uri
);
140 public void onPause()
143 Log
.i("GeckoApp", "pause");
144 GeckoAppShell
.sendEventToGecko(new GeckoEvent(GeckoEvent
.ACTIVITY_PAUSING
));
145 // The user is navigating away from this activity, but nothing
146 // has come to the foreground yet; for Gecko, we may want to
147 // stop repainting, for example.
149 // Whatever we do here should be fast, because we're blocking
150 // the next activity from showing up until we finish.
152 // onPause will be followed by either onResume or onStop.
157 public void onResume()
159 Log
.i("GeckoApp", "resume");
160 GeckoAppShell
.onResume();
161 if (surfaceView
!= null)
162 surfaceView
.mSurfaceNeedsRedraw
= true;
163 // After an onPause, the activity is back in the foreground.
164 // Undo whatever we did in onPause.
171 Log
.i("GeckoApp", "stop");
172 // We're about to be stopped, potentially in preparation for
173 // being destroyed. We're killable after this point -- as I
174 // understand it, in extreme cases the process can be terminated
175 // without going through onDestroy.
177 // We might also get an onRestart after this; not sure what
178 // that would mean for Gecko if we were to kill it here.
179 // Instead, what we should do here is save prefs, session,
180 // etc., and generally mark the profile as 'clean', and then
181 // dirty it again if we get an onResume.
189 public void onRestart()
191 Log
.i("GeckoApp", "restart");
196 public void onStart()
198 Log
.i("GeckoApp", "start");
203 public void onDestroy()
205 Log
.i("GeckoApp", "destroy");
206 // Tell Gecko to shutting down; we'll end up calling System.exit()
208 GeckoAppShell
.sendEventToGecko(new GeckoEvent(GeckoEvent
.ACTIVITY_STOPPING
));
214 public void onConfigurationChanged(android
.content
.res
.Configuration newConfig
)
216 Log
.i("GeckoApp", "configuration changed");
217 // nothing, just ignore
218 super.onConfigurationChanged(newConfig
);
222 public void onLowMemory()
224 Log
.i("GeckoApp", "low memory");
229 public boolean onKeyDown(int keyCode
, KeyEvent event
) {
231 case KeyEvent
.KEYCODE_BACK
:
232 if (event
.getRepeatCount() == 0) {
233 event
.startTracking();
238 case KeyEvent
.KEYCODE_VOLUME_UP
:
239 case KeyEvent
.KEYCODE_VOLUME_DOWN
:
240 case KeyEvent
.KEYCODE_SEARCH
:
242 case KeyEvent
.KEYCODE_DEL
:
243 // See comments in GeckoInputConnection.onKeyDel
244 if (surfaceView
!= null &&
245 surfaceView
.inputConnection
!= null &&
246 surfaceView
.inputConnection
.onKeyDel()) {
253 GeckoAppShell
.sendEventToGecko(new GeckoEvent(event
));
257 public boolean onKeyUp(int keyCode
, KeyEvent event
) {
259 case KeyEvent
.KEYCODE_BACK
:
260 if (!event
.isTracking() || event
.isCanceled())
266 GeckoAppShell
.sendEventToGecko(new GeckoEvent(event
));
270 public boolean onKeyMultiple(int keyCode
, int repeatCount
, KeyEvent event
) {
271 GeckoAppShell
.sendEventToGecko(new GeckoEvent(event
));
275 abstract public String
getAppName();
276 abstract public String
getContentProcessName();
278 protected void unpackComponents()
281 InputStream listStream
;
284 File componentsDir
= new File("/data/data/org.mozilla." + getAppName() +"/components");
285 componentsDir
.mkdir();
286 zip
= new ZipFile(getApplication().getPackageResourcePath());
288 ZipEntry componentsList
= zip
.getEntry("components/components.manifest");
289 if (componentsList
== null) {
290 Log
.i("GeckoAppJava", "Can't find components.list !");
294 listStream
= new BufferedInputStream(zip
.getInputStream(componentsList
));
295 } catch (Exception e
) {
296 Log
.i("GeckoAppJava", e
.toString());
300 byte[] buf
= new byte[8192];
302 StreamTokenizer tkn
= new StreamTokenizer(new InputStreamReader(listStream
));
303 String line
= "components/";
305 boolean addnext
= false;
306 tkn
.eolIsSignificant(true);
309 status
= tkn
.nextToken();
310 } catch (IOException e
) {
311 Log
.i("GeckoAppJava", e
.toString());
315 case StreamTokenizer
.TT_WORD
:
316 if (tkn
.sval
.equals("binary-component"))
323 case StreamTokenizer
.TT_NUMBER
:
325 case StreamTokenizer
.TT_EOF
:
326 case StreamTokenizer
.TT_EOL
:
327 unpackFile(zip
, buf
, null, line
);
328 line
= "components/";
331 } while (status
!= StreamTokenizer
.TT_EOF
);
333 unpackFile(zip
, buf
, null, "application.ini");
334 unpackFile(zip
, buf
, null, getContentProcessName());
337 private void unpackFile(ZipFile zip
, byte[] buf
, ZipEntry fileEntry
, String name
)
339 if (fileEntry
== null)
340 fileEntry
= zip
.getEntry(name
);
341 if (fileEntry
== null) {
342 Log
.i("GeckoAppJava", "Can't find " + name
+ " in " + zip
.getName());
346 File outFile
= new File("/data/data/org.mozilla." + getAppName() + "/" + name
);
347 if (outFile
.exists() &&
348 outFile
.lastModified() >= fileEntry
.getTime() &&
349 outFile
.length() == fileEntry
.getSize())
353 File dir
= outFile
.getParentFile();
354 if (!outFile
.exists())
356 } catch (Exception e
) {
357 Log
.i("GeckoAppJava", e
.toString());
361 InputStream fileStream
;
363 fileStream
= zip
.getInputStream(fileEntry
);
364 } catch (Exception e
) {
365 Log
.i("GeckoAppJava", e
.toString());
369 OutputStream outStream
;
371 outStream
= new FileOutputStream(outFile
);
373 while (fileStream
.available() > 0) {
374 int read
= fileStream
.read(buf
, 0, buf
.length
);
375 outStream
.write(buf
, 0, read
);
380 } catch (Exception e
) {
381 Log
.i("GeckoAppJava", e
.toString());
386 public String
getEnvString() {
387 Map
<String
,String
> envMap
= System
.getenv();
388 Set
<Map
.Entry
<String
,String
>> envSet
= envMap
.entrySet();
389 Iterator
<Map
.Entry
<String
,String
>> envIter
= envSet
.iterator();
390 StringBuffer envstr
= new StringBuffer();
392 while (envIter
.hasNext()) {
393 Map
.Entry
<String
,String
> entry
= envIter
.next();
394 // No need to pass env vars that we know the system provides
395 // Unnecessary vars need to be trimmed since amount of data
396 // we can pass this way is limited
397 if (!entry
.getKey().equals("BOOTCLASSPATH") &&
398 !entry
.getKey().equals("ANDROID_SOCKET_zygote") &&
399 !entry
.getKey().equals("TMPDIR") &&
400 !entry
.getKey().equals("ANDROID_BOOTLOGO") &&
401 !entry
.getKey().equals("EXTERNAL_STORAGE") &&
402 !entry
.getKey().equals("ANDROID_ASSETS") &&
403 !entry
.getKey().equals("PATH") &&
404 !entry
.getKey().equals("TERMINFO") &&
405 !entry
.getKey().equals("LD_LIBRARY_PATH") &&
406 !entry
.getKey().equals("ANDROID_DATA") &&
407 !entry
.getKey().equals("ANDROID_PROPERTY_WORKSPACE") &&
408 !entry
.getKey().equals("ANDROID_ROOT")) {
409 envstr
.append(" --es env" + c
+ " " + entry
.getKey() + "="
414 return envstr
.toString();
417 public void doRestart() {
419 String action
= "org.mozilla.gecko.restart" + getAppName();
420 String amCmd
= "/system/bin/am broadcast -a " + action
+ getEnvString() + " -n org.mozilla." + getAppName() + "/org.mozilla." + getAppName() + ".Restarter";
421 Log
.i("GeckoAppJava", amCmd
);
422 Runtime
.getRuntime().exec(amCmd
);
423 } catch (Exception e
) {
424 Log
.i("GeckoAppJava", e
.toString());