bug 607939 - fail to opened a URL / link from another application after launching r=dougt a=blocking-fennec
authorMichael Wu <mwu@mozilla.com>
Wed, 24 Nov 2010 17:51:41 -0500
changeset 58306 2c41d108edb8b77664fbe935015e38fe9cfaaaa3
parent 58305 cc2a24cd718a4a054e17d0e0cd81428c93b39daf
child 58307 24aed997dbcd9b157252b4bb1ec0ce77005c3a2b
push id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
reviewersdougt, blocking-fennec
bugs607939
milestone2.0b8pre
bug 607939 - fail to opened a URL / link from another application after launching r=dougt a=blocking-fennec
embedding/android/GeckoApp.java
embedding/android/GeckoAppShell.java
embedding/android/GeckoSurfaceView.java
--- a/embedding/android/GeckoApp.java
+++ b/embedding/android/GeckoApp.java
@@ -66,53 +66,93 @@ abstract public class GeckoApp
     public static final String ACTION_ALERT_CLEAR = "org.mozilla.gecko.ACTION_ALERT_CLEAR";
 
     public static FrameLayout mainLayout;
     public static GeckoSurfaceView surfaceView;
     public static GeckoApp mAppContext;
     public static boolean mFullscreen = false;
     ProgressDialog mProgressDialog;
 
+    enum LaunchState {PreLaunch, Launching, WaitButton,
+                      Launched, GeckoRunning, GeckoExiting};
+    private static LaunchState sLaunchState = LaunchState.PreLaunch;
+
+    
+    static boolean checkLaunchState(LaunchState checkState) {
+        synchronized(sLaunchState) {
+            return sLaunchState == checkState;
+        }
+    }
+    
+    static void setLaunchState(LaunchState setState) {
+        synchronized(sLaunchState) {
+            sLaunchState = setState;
+        }
+    }
+
+    // if mLaunchState is equal to checkState this sets mLaunchState to setState
+    // and return true. Otherwise we return false.
+    static boolean checkAndSetLaunchState(LaunchState checkState, LaunchState setState) {
+        synchronized(sLaunchState) {
+            if (sLaunchState != checkState)
+                return false;
+            sLaunchState = setState;
+            return true;
+        }
+    }
+
     void showErrorDialog(String message)
     {
         new AlertDialog.Builder(this)
             .setMessage(message)
             .setCancelable(false)
             .setPositiveButton("Exit",
                                new DialogInterface.OnClickListener() {
                                    public void onClick(DialogInterface dialog,
                                                        int id)
                                    {
                                        GeckoApp.this.finish();
                                    }
                                }).show();
     }
 
-    void launch()
+    // Returns true when the intent is going to be handled by gecko launch
+    boolean launch(Intent i)
     {
+        if (!checkAndSetLaunchState(LaunchState.Launching, LaunchState.Launched))
+            return false;
+
         // unpack files in the components directory
         try {
             unpackComponents();
         } catch (FileNotFoundException fnfe) {
             showErrorDialog(getString(R.string.error_loading_file));
-            return;
+            return false;
         } catch (IOException ie) {
             String msg = ie.getMessage();
             if (msg.equalsIgnoreCase("No space left on device"))
                 showErrorDialog(getString(R.string.no_space_to_start_error));
             else
                 showErrorDialog(getString(R.string.error_loading_file));
-            return;
+            return false;
         }
+
+        mProgressDialog = 
+            ProgressDialog.show(GeckoApp.this, "",
+                                getString(R.string.splash_screen_label),
+                                true);
+
         // and then fire us up
-        Intent i = getIntent();
+        if (i == null)
+            i = getIntent();
         String env = i.getStringExtra("env0");
         GeckoAppShell.runGecko(getApplication().getPackageResourcePath(),
                                i.getStringExtra("args"),
                                i.getDataString());
+        return true;
     }
 
     /** Called when the activity is first created. */
     @Override
     public void onCreate(Bundle savedInstanceState)
     {
         Log.i("GeckoApp", "create");
         super.onCreate(savedInstanceState);
@@ -131,21 +171,91 @@ abstract public class GeckoApp
         mainLayout = new FrameLayout(this);
         mainLayout.addView(surfaceView,
                            new FrameLayout.LayoutParams(FrameLayout.LayoutParams.FILL_PARENT,
                                                         FrameLayout.LayoutParams.FILL_PARENT));
 
         setContentView(mainLayout,
                        new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
                                                   ViewGroup.LayoutParams.FILL_PARENT));
+
+        if (!checkAndSetLaunchState(LaunchState.PreLaunch,
+                                    LaunchState.Launching))
+            return;
+
+        checkAndLaunchUpdate();
+
+        if (!checkCPUCompatability())
+            return;
+        // Load our JNI libs
+        GeckoAppShell.loadGeckoLibs(getApplication().getPackageResourcePath());
+    }
+
+
+    boolean checkCPUCompatability() {
+        try {
+            BufferedReader reader =
+                new BufferedReader(new FileReader("/proc/cpuinfo"));
+            String line;
+            while ((line = reader.readLine()) != null) {
+                int index = line.indexOf("Processor");
+                if (index == -1)
+                    continue;
+
+                int version = 5;
+                if (line.indexOf("(v8l)") != -1)
+                    version = 8;
+                if (line.indexOf("(v7l)") != -1)
+                    version = 7;
+                if (line.indexOf("(v6l)") != -1)
+                    version = 6;
+                
+                if (version < getMinCPUVersion()) {
+                    showErrorDialog(
+                        getString(R.string.incompatable_cpu_error));
+                    return false;
+                }
+                else {
+                    break;
+                }
+            }
+        } catch (Exception ex) {
+            // Not much we can do here, just continue assuming we're okay
+            Log.i("GeckoApp", "exception: " + ex);
+        }
+        return true;
     }
 
     @Override
     protected void onNewIntent(Intent intent) {
+        if (checkLaunchState(LaunchState.GeckoExiting)) {
+            // We're exiting and shouldn't try to do anything else just incase
+            // we're hung for some reason we'll force the process to exit
+            System.exit(0);
+            return;
+        }
         final String action = intent.getAction();
+        if (action.equals("org.mozilla.gecko.DEBUG") &&
+            checkAndSetLaunchState(LaunchState.Launching, LaunchState.WaitButton)) {
+            final Button launchButton = new Button(this);
+            launchButton.setText("Launch"); // don't need to localize
+            launchButton.setOnClickListener(new Button.OnClickListener() {
+                    public void onClick (View v) {
+                        // hide the button so we can't be launched again
+                        mainLayout.removeView(launchButton);
+                        setLaunchState(LaunchState.Launching);
+                        launch(null);
+                    }
+                });
+            mainLayout.addView(launchButton, 300, 200);
+            return;
+        }
+        if (checkLaunchState(LaunchState.WaitButton) || launch(intent))
+            return;
+
         if (Intent.ACTION_VIEW.equals(action)) {
             String uri = intent.getDataString();
             GeckoAppShell.sendEventToGecko(new GeckoEvent(uri));
             Log.i("GeckoApp","onNewIntent: "+uri);
         }
         else if (Intent.ACTION_MAIN.equals(action)) {
             Log.i("GeckoApp", "Intent : ACTION_MAIN");
             GeckoAppShell.sendEventToGecko(new GeckoEvent(""));
@@ -172,21 +282,26 @@ abstract public class GeckoApp
         // onPause will be followed by either onResume or onStop.
         super.onPause();
     }
 
     @Override
     public void onResume()
     {
         Log.i("GeckoApp", "resume");
-        if (GeckoAppShell.sGeckoRunning)
+        if (checkLaunchState(LaunchState.GeckoRunning))
             GeckoAppShell.onResume();
         // After an onPause, the activity is back in the foreground.
         // Undo whatever we did in onPause.
         super.onResume();
+
+        // Just in case. Normally we start in onNewIntent
+        if (checkLaunchState(LaunchState.PreLaunch) ||
+            checkLaunchState(LaunchState.Launching))
+            onNewIntent(getIntent());
     }
 
     @Override
     public void onStop()
     {
         Log.i("GeckoApp", "stop");
         // We're about to be stopped, potentially in preparation for
         // being destroyed.  We're killable after this point -- as I
@@ -211,85 +326,16 @@ abstract public class GeckoApp
         super.onRestart();
     }
 
     @Override
     public void onStart()
     {
         Log.i("GeckoApp", "start");
         super.onStart();
-
-        boolean useLaunchButton = false;
-
-        String intentAction = getIntent().getAction();
-        if (intentAction != null && intentAction.equals("org.mozilla.gecko.DEBUG"))
-            useLaunchButton = true;
-
-        if (!GeckoAppShell.sGeckoRunning) {
-            checkAndLaunchUpdate();
-
-            try {
-                BufferedReader reader =
-                    new BufferedReader(new FileReader("/proc/cpuinfo"));
-                String line;
-                while ((line = reader.readLine()) != null) {
-                    int index = line.indexOf("Processor");
-                    if (index == -1)
-                        continue;
-
-                    int version = 5;
-                    if (line.indexOf("(v8l)") != -1)
-                        version = 8;
-                    if (line.indexOf("(v7l)") != -1)
-                        version = 7;
-                    if (line.indexOf("(v6l)") != -1)
-                        version = 6;
-
-                    if (version < getMinCPUVersion()) {
-                        showErrorDialog(
-                            getString(R.string.incompatable_cpu_error));
-                        return;
-                    }
-                    else {
-                        break;
-                    }
-                }
-                
-            } catch (Exception ex) {
-                // Not much we can do here, just continue assuming we're okay
-                Log.i("GeckoApp", "exception: " + ex);
-            }
-
-            if (!useLaunchButton) {
-                mProgressDialog = 
-                    ProgressDialog.show(GeckoApp.this, "",
-                                        getString(R.string.splash_screen_label),
-                                        true);
-            }
-
-            // Load our JNI libs; we need to do this before launch() because
-            // setInitialSize will be called even before Gecko is actually up
-            // and running.
-            GeckoAppShell.loadGeckoLibs(getApplication().getPackageResourcePath());
-
-            if (useLaunchButton) {
-                final Button b = new Button(this);
-                b.setText("Launch"); // don't need to localize
-                b.setOnClickListener(new Button.OnClickListener() {
-                        public void onClick (View v) {
-                            // hide the button so we can't be launched again
-                            mainLayout.removeView(b);
-                            launch();
-                        }
-                    });
-                mainLayout.addView(b, 300, 200);
-            } else {
-                launch();
-            }
-        }
     }
 
     @Override
     public void onDestroy()
     {
         Log.i("GeckoApp", "destroy");
         // Tell Gecko to shutting down; we'll end up calling System.exit()
         // in onXreExit.
@@ -306,17 +352,17 @@ abstract public class GeckoApp
         // nothing, just ignore
         super.onConfigurationChanged(newConfig);
     }
 
     @Override
     public void onLowMemory()
     {
         Log.i("GeckoApp", "low memory");
-        if (GeckoAppShell.sGeckoRunning)
+        if (checkLaunchState(LaunchState.GeckoRunning))
             GeckoAppShell.onLowMemory();
         super.onLowMemory();
     }
 
     public boolean onKeyDown(int keyCode, KeyEvent event) {
         switch (keyCode) {
             case KeyEvent.KEYCODE_BACK:
                 if (event.getRepeatCount() == 0) {
--- a/embedding/android/GeckoAppShell.java
+++ b/embedding/android/GeckoAppShell.java
@@ -56,24 +56,19 @@ import android.widget.*;
 import android.hardware.*;
 import android.location.*;
 
 import android.util.*;
 import android.net.Uri;
 
 class GeckoAppShell
 {
-    static {
-        sGeckoRunning = false;
-    }
-
     // static members only
     private GeckoAppShell() { }
 
-    static boolean sGeckoRunning;
     static private GeckoEvent gPendingResize = null;
 
     static private boolean gRestartScheduled = false;
 
     static private final Timer mIMETimer = new Timer();
     static private final HashMap<Integer, AlertNotification>
          mAlertNotifications = new HashMap<Integer, AlertNotification>();
 
@@ -144,17 +139,17 @@ class GeckoAppShell
             combinedArgs += " " + url;
         // and go
         GeckoAppShell.nativeRun(combinedArgs);
     }
 
     private static GeckoEvent mLastDrawEvent;
 
     public static void sendEventToGecko(GeckoEvent e) {
-        if (sGeckoRunning) {
+        if (GeckoApp.checkLaunchState(GeckoApp.LaunchState.GeckoRunning)) {
             if (gPendingResize != null) {
                 notifyGeckoOfEvent(gPendingResize);
                 gPendingResize = null;
             }
             notifyGeckoOfEvent(e);
         } else {
             if (e.mType == GeckoEvent.SIZE_CHANGED)
                 gPendingResize = e;
@@ -333,25 +328,27 @@ class GeckoAppShell
         try {
             GeckoApp.surfaceView.inputConnection.mQueryResult.put(result);
         } catch (InterruptedException e) {
         }
     }
 
     static void onAppShellReady()
     {
-        sGeckoRunning = true;
+        // mLaunchState can only be Launched at this point
+        GeckoApp.setLaunchState(GeckoApp.LaunchState.GeckoRunning);
         if (gPendingResize != null) {
             notifyGeckoOfEvent(gPendingResize);
             gPendingResize = null;
         }
     }
 
     static void onXreExit() {
-        sGeckoRunning = false;
+        // mLaunchState can only be Launched or GeckoRunning at this point
+        GeckoApp.setLaunchState(GeckoApp.LaunchState.GeckoExiting);
         Log.i("GeckoAppJava", "XRE exited");
         if (gRestartScheduled) {
             GeckoApp.mAppContext.doRestart();
         } else {
             Log.i("GeckoAppJava", "we're done, good bye");
             GeckoApp.mAppContext.finish();
             System.exit(0);
         }
--- a/embedding/android/GeckoSurfaceView.java
+++ b/embedding/android/GeckoSurfaceView.java
@@ -108,18 +108,18 @@ class GeckoSurfaceView
             }
 
             if (width == 0 || height == 0)
                 mSoftwareBuffer = null;
             else if (mSoftwareBuffer == null ||
                      mSoftwareBuffer.capacity() < (width * height * 2) ||
                      mWidth != width || mHeight != height)
                 mSoftwareBuffer = ByteBuffer.allocateDirect(width * height * 2);
-            boolean doSyncDraw = GeckoAppShell.sGeckoRunning && m2DMode &&
-                                 mSoftwareBuffer != null;
+            boolean doSyncDraw = m2DMode && mSoftwareBuffer != null &&
+                GeckoApp.checkLaunchState(GeckoApp.LaunchState.GeckoRunning);
             mSyncDraw = doSyncDraw;
 
             mFormat = format;
             mWidth = width;
             mHeight = height;
             mSurfaceValid = true;
 
             Log.i("GeckoAppJava", "surfaceChanged: fmt: " + format + " dim: " + width + " " + height);