Code drop from //branches/cupcake/...@124589
diff --git a/src/com/android/browser/GearsNativeDialog.java b/src/com/android/browser/GearsNativeDialog.java
new file mode 100644
index 0000000..c8ae741
--- /dev/null
+++ b/src/com/android/browser/GearsNativeDialog.java
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.browser;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Config;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.Window;
+import android.widget.BaseAdapter;
+
+import android.webkit.gears.NativeDialog;
+
+import com.android.browser.GearsBaseDialog;
+import com.android.browser.GearsPermissionsDialog;
+import com.android.browser.GearsSettingsDialog;
+import com.android.browser.GearsShortcutDialog;
+import com.android.browser.GearsFilePickerDialog;
+
+/**
+ * Native dialog Activity used by gears
+ * TODO: rename in GearsNativeDialogActivity
+ * @hide
+ */
+public class GearsNativeDialog extends Activity {
+
+  private static final String TAG = "GearsNativeDialog";
+
+  private String mDialogArguments;
+
+  private String mGearsVersion = null;
+
+  private boolean mDebug = false;
+
+  private int mDialogType;
+  private final int SETTINGS_DIALOG = 1;
+  private final int PERMISSION_DIALOG = 2;
+  private final int SHORTCUT_DIALOG = 3;
+  private final int LOCATION_DIALOG = 4;
+  private final int FILEPICKER_DIALOG = 5;
+
+  private final String VERSION_STRING = "version";
+  private final String SETTINGS_DIALOG_STRING = "settings_dialog";
+  private final String PERMISSION_DIALOG_STRING = "permissions_dialog";
+  private final String SHORTCUT_DIALOG_STRING = "shortcuts_dialog";
+  private final String LOCATION_DIALOG_STRING = "locations_dialog";
+  private final String FILEPICKER_DIALOG_STRING = "filepicker_dialog";
+
+  private boolean mDialogDismissed = false;
+
+  GearsBaseDialog dialog;
+
+  // Handler for callbacks to the UI thread
+  final Handler mHandler = new Handler() {
+    public void handleMessage(Message msg) {
+      if (msg.what == GearsBaseDialog.NEW_ICON) {
+        BaseAdapter adapter = (BaseAdapter) msg.obj;
+        adapter.notifyDataSetChanged();
+      } else if (msg.what == GearsBaseDialog.UPDATE_ICON) {
+        dialog.updateIcon();
+      } else if (msg.what == GearsBaseDialog.ALWAYS_DENY) {
+        closeDialog(GearsBaseDialog.ALWAYS_DENY);
+      } else if (msg.what == GearsBaseDialog.ALLOW) {
+        closeDialog(GearsBaseDialog.ALLOW);
+      } else if (msg.what == GearsBaseDialog.DENY) {
+        closeDialog(GearsBaseDialog.DENY);
+      }
+      super.handleMessage(msg);
+    }
+  };
+
+  @Override
+  public void onCreate(Bundle icicle) {
+    super.onCreate(icicle);
+    requestWindowFeature(Window.FEATURE_NO_TITLE);
+    setContentView(R.layout.gears_dialog);
+    getArguments();
+
+    switch (mDialogType) {
+      case SETTINGS_DIALOG:
+        dialog = new GearsSettingsDialog(this, mHandler, mDialogArguments);
+        dialog.setGearsVersion(mGearsVersion);
+        break;
+      case PERMISSION_DIALOG:
+        dialog = new GearsPermissionsDialog(this, mHandler, mDialogArguments);
+        break;
+      case SHORTCUT_DIALOG:
+        dialog = new GearsShortcutDialog(this, mHandler, mDialogArguments);
+        break;
+      case LOCATION_DIALOG:
+        dialog = new GearsPermissionsDialog(this, mHandler, mDialogArguments);
+        break;
+      case FILEPICKER_DIALOG:
+        dialog = new GearsFilePickerDialog(this, mHandler, mDialogArguments);
+        break;
+      default:
+        dialog = new GearsBaseDialog(this, mHandler, mDialogArguments);
+    }
+    dialog.setDebug(mDebug);
+    dialog.setup();
+  }
+
+  /**
+   * Get the arguments for the dialog
+   *
+   * The dialog needs a json string as an argument, as
+   * well as a dialogType. In debug mode the arguments
+   * are mocked.
+   */
+  private void getArguments() {
+    if (mDebug) {
+      mDialogType = FILEPICKER_DIALOG +1;
+      mockArguments();
+
+      return;
+    }
+
+    Intent intent = getIntent();
+    mDialogArguments = intent.getStringExtra("dialogArguments");
+    String dialogTypeString = intent.getStringExtra("dialogType");
+    if (dialogTypeString == null) {
+      return;
+    }
+
+    if (Config.LOGV) {
+      Log.v(TAG, "dialogtype: " + dialogTypeString);
+    }
+
+    if (dialogTypeString.equalsIgnoreCase(SETTINGS_DIALOG_STRING)) {
+      mDialogType = SETTINGS_DIALOG;
+      mGearsVersion = intent.getStringExtra(VERSION_STRING);
+    } else if (dialogTypeString.equalsIgnoreCase(PERMISSION_DIALOG_STRING)) {
+      mDialogType = PERMISSION_DIALOG;
+    } else if (dialogTypeString.equalsIgnoreCase(SHORTCUT_DIALOG_STRING)) {
+      mDialogType = SHORTCUT_DIALOG;
+    } else if (dialogTypeString.equalsIgnoreCase(LOCATION_DIALOG_STRING)) {
+      mDialogType = LOCATION_DIALOG;
+    } else if (dialogTypeString.equalsIgnoreCase(FILEPICKER_DIALOG_STRING)) {
+      mDialogType = FILEPICKER_DIALOG;
+    }
+  }
+
+  /**
+   * Utility method for debugging the dialog.
+   *
+   * Set mock arguments.
+   */
+  private void mockArguments() {
+    String argumentsShortcuts = "{ locale: \"en-US\","
+        + "name: \"My Application\", link: \"http://www.google.com/\","
+        + "description: \"This application does things does things!\","
+        + "icon16x16: \"http://google-gears.googlecode.com/"
+        + "svn/trunk/gears/test/manual/shortcuts/16.png\","
+        + "icon32x32: \"http://google-gears.googlecode.com/"
+        + "svn/trunk/gears/test/manual/shortcuts/32.png\","
+        + "icon48x48: \"http://google-gears.googlecode.com/"
+        + "svn/trunk/gears/test/manual/shortcuts/48.png\","
+        + "icon128x128: \"http://google-gears.googlecode.com/"
+        + "svn/trunk/gears/test/manual/shortcuts/128.png\"}";
+
+    String argumentsPermissions = "{ locale: \"en-US\", "
+        + "origin: \"http://www.google.com\", dialogType: \"localData\","
+        + "customIcon: \"http://google-gears.googlecode.com/"
+        + "svn/trunk/gears/test/manual/shortcuts/32.png\","
+        + "customName: \"My Application\","
+        + "customMessage: \"Press the button to enable my "
+        + "application to run offline!\" };";
+
+    String argumentsLocation = "{ locale: \"en-US\", "
+        + "origin: \"http://www.google.com\", dialogType: \"locationData\","
+        + "customIcon: \"http://google-gears.googlecode.com/"
+        + "svn/trunk/gears/test/manual/shortcuts/32.png\","
+        + "customName: \"My Application\","
+        + "customMessage: \"Press the button to enable my "
+        + "application to run offline!\" };";
+
+    String argumentsSettings = "{ locale: \"en-US\", permissions: [ { "
+        + "name: \"http://www.google.com\", "
+        + "localStorage: { permissionState: 1 }, "
+        + "locationData: { permissionState: 0 } }, "
+        + "{ name: \"http://www.aaronboodman.com\", "
+        + "localStorage: { permissionState: 1 }, "
+        + "locationData: { permissionState: 2 } }, "
+        + "{ name: \"http://www.evil.org\", "
+        + "localStorage: { permissionState: 2 }, "
+        + "locationData: { permissionState: 2 } } ] }";
+
+    switch (mDialogType) {
+      case SHORTCUT_DIALOG:
+        mDialogArguments = argumentsShortcuts;
+        break;
+      case PERMISSION_DIALOG:
+        mDialogArguments = argumentsPermissions;
+        break;
+      case LOCATION_DIALOG:
+        mDialogArguments = argumentsLocation;
+        break;
+      case SETTINGS_DIALOG:
+        mDialogArguments = argumentsSettings;
+    }
+  }
+
+  /**
+   * Close the dialog and set the return string value.
+   */
+  private void closeDialog(int closingType) {
+    String ret = dialog.closeDialog(closingType);
+
+    if (mDebug) {
+      Log.v(TAG, "closeDialog ret value: " + ret);
+    }
+
+    NativeDialog.closeDialog(ret);
+    notifyEndOfDialog();
+    finish();
+  }
+
+  @Override
+  public void onDestroy() {
+    super.onDestroy();
+    // In case we reach this point without
+    // notifying NativeDialog, we do it now.
+    if (!mDialogDismissed) {
+      notifyEndOfDialog();
+    }
+  }
+
+  @Override
+  public void onPause(){
+    super.onPause();
+    if (!mDialogDismissed) {
+      closeDialog(GearsBaseDialog.CANCEL);
+    }
+  }
+
+  /**
+   * Signal to NativeDialog that we are done.
+   */
+  private void notifyEndOfDialog() {
+    NativeDialog.signalFinishedDialog();
+    mDialogDismissed = true;
+  }
+
+  /**
+   * Intercepts the back key to immediately notify
+   * NativeDialog that we are done.
+   */
+  public boolean dispatchKeyEvent(KeyEvent event) {
+    if (event.getKeyCode() ==  KeyEvent.KEYCODE_BACK && event.isDown()) {
+      closeDialog(GearsBaseDialog.CANCEL);
+    }
+    return super.dispatchKeyEvent(event);
+  }
+
+}