Bug 575870 - Enable the firefox button on xp themed, classic, and aero basic. r=dao...
[mozilla-central.git] / embedding / android / GeckoApp.java
blob01a6ef1bf397328b66ddeb2f8a8bd4052534c084
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
12 * License.
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.
20 * Contributor(s):
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;
39 import java.io.*;
40 import java.util.*;
41 import java.util.zip.*;
42 import java.nio.*;
44 import android.os.*;
45 import android.app.*;
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
57 extends Activity
59 public static FrameLayout mainLayout;
60 public static GeckoSurfaceView surfaceView;
61 public static GeckoApp mAppContext;
63 void launch()
65 // unpack files in the components directory
66 unpackComponents();
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"),
72 i.getDataString());
75 /** Called when the activity is first created. */
76 @Override
77 public void onCreate(Bundle savedInstanceState)
79 Log.i("GeckoApp", "create");
80 super.onCreate(savedInstanceState);
82 mAppContext = this;
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
107 // and running.
108 GeckoAppShell.loadGeckoLibs();
110 if (useLaunchButton) {
111 final Button b = new Button(this);
112 b.setText("Launch");
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);
117 launch();
120 mainLayout.addView(b, 300, 200);
121 } else {
122 launch();
126 super.onCreate(savedInstanceState);
129 @Override
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);
139 @Override
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.
153 super.onPause();
156 @Override
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.
165 super.onResume();
168 @Override
169 public void onStop()
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.
183 // XXX do the above.
185 super.onStop();
188 @Override
189 public void onRestart()
191 Log.i("GeckoApp", "restart");
192 super.onRestart();
195 @Override
196 public void onStart()
198 Log.i("GeckoApp", "start");
199 super.onStart();
202 @Override
203 public void onDestroy()
205 Log.i("GeckoApp", "destroy");
206 // Tell Gecko to shutting down; we'll end up calling System.exit()
207 // in onXreExit.
208 GeckoAppShell.sendEventToGecko(new GeckoEvent(GeckoEvent.ACTIVITY_STOPPING));
210 super.onDestroy();
213 @Override
214 public void onConfigurationChanged(android.content.res.Configuration newConfig)
216 Log.i("GeckoApp", "configuration changed");
217 // nothing, just ignore
218 super.onConfigurationChanged(newConfig);
221 @Override
222 public void onLowMemory()
224 Log.i("GeckoApp", "low memory");
225 // XXX TODO
226 super.onLowMemory();
229 public boolean onKeyDown(int keyCode, KeyEvent event) {
230 switch (keyCode) {
231 case KeyEvent.KEYCODE_BACK:
232 if (event.getRepeatCount() == 0) {
233 event.startTracking();
234 return true;
235 } else {
236 return false;
238 case KeyEvent.KEYCODE_VOLUME_UP:
239 case KeyEvent.KEYCODE_VOLUME_DOWN:
240 case KeyEvent.KEYCODE_SEARCH:
241 return false;
242 case KeyEvent.KEYCODE_DEL:
243 // See comments in GeckoInputConnection.onKeyDel
244 if (surfaceView != null &&
245 surfaceView.inputConnection != null &&
246 surfaceView.inputConnection.onKeyDel()) {
247 return true;
249 break;
250 default:
251 break;
253 GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
254 return true;
257 public boolean onKeyUp(int keyCode, KeyEvent event) {
258 switch(keyCode) {
259 case KeyEvent.KEYCODE_BACK:
260 if (!event.isTracking() || event.isCanceled())
261 return false;
262 break;
263 default:
264 break;
266 GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
267 return true;
270 public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
271 GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
272 return true;
275 abstract public String getAppName();
276 abstract public String getContentProcessName();
278 protected void unpackComponents()
280 ZipFile zip;
281 InputStream listStream;
283 try {
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 !");
291 return;
294 listStream = new BufferedInputStream(zip.getInputStream(componentsList));
295 } catch (Exception e) {
296 Log.i("GeckoAppJava", e.toString());
297 return;
300 byte[] buf = new byte[8192];
302 StreamTokenizer tkn = new StreamTokenizer(new InputStreamReader(listStream));
303 String line = "components/";
304 int status;
305 boolean addnext = false;
306 tkn.eolIsSignificant(true);
307 do {
308 try {
309 status = tkn.nextToken();
310 } catch (IOException e) {
311 Log.i("GeckoAppJava", e.toString());
312 return;
314 switch (status) {
315 case StreamTokenizer.TT_WORD:
316 if (tkn.sval.equals("binary-component"))
317 addnext = true;
318 else if (addnext) {
319 line += tkn.sval;
320 addnext = false;
322 break;
323 case StreamTokenizer.TT_NUMBER:
324 break;
325 case StreamTokenizer.TT_EOF:
326 case StreamTokenizer.TT_EOL:
327 unpackFile(zip, buf, null, line);
328 line = "components/";
329 break;
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());
343 return;
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())
350 return;
352 try {
353 File dir = outFile.getParentFile();
354 if (!outFile.exists())
355 dir.mkdirs();
356 } catch (Exception e) {
357 Log.i("GeckoAppJava", e.toString());
358 return;
361 InputStream fileStream;
362 try {
363 fileStream = zip.getInputStream(fileEntry);
364 } catch (Exception e) {
365 Log.i("GeckoAppJava", e.toString());
366 return;
369 OutputStream outStream;
370 try {
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);
378 fileStream.close();
379 outStream.close();
380 } catch (Exception e) {
381 Log.i("GeckoAppJava", e.toString());
382 return;
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();
391 int c = 0;
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() + "="
410 + entry.getValue());
411 c++;
414 return envstr.toString();
417 public void doRestart() {
418 try {
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());
426 System.exit(0);