diff --git a/embedding/android/AndroidManifest.xml.in b/embedding/android/AndroidManifest.xml.in
index 87e6bdc2035..5061c3f5091 100644
--- a/embedding/android/AndroidManifest.xml.in
+++ b/embedding/android/AndroidManifest.xml.in
@@ -143,15 +143,5 @@
-
-
-
diff --git a/embedding/android/BrowserToolbar.java b/embedding/android/BrowserToolbar.java
index 09760cb81eb..7d01bead355 100644
--- a/embedding/android/BrowserToolbar.java
+++ b/embedding/android/BrowserToolbar.java
@@ -56,8 +56,8 @@ import org.mozilla.gecko.R;
public class BrowserToolbar extends LinearLayout {
final private ProgressBar mProgressBar;
final private Button mAwesomeBar;
+ final private Button mTabs;
final private ImageButton mFavicon;
- final private ImageButton mReloadButton;
public BrowserToolbar(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -77,22 +77,27 @@ public class BrowserToolbar extends LinearLayout {
}
});
- mFavicon = (ImageButton) findViewById(R.id.favimage);
-
- mReloadButton = (ImageButton) findViewById(R.id.reload);
- mReloadButton.setOnClickListener(new ImageButton.OnClickListener() {
+ mTabs = (Button) findViewById(R.id.tabs);
+ mTabs.setText("1");
+ mTabs.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
- onReload();
+ showTabs();
}
});
+
+ mFavicon = (ImageButton) findViewById(R.id.favimage);
}
private void onAwesomeBarSearch() {
GeckoApp.mAppContext.onSearchRequested();
}
- private void onReload() {
- GeckoApp.mAppContext.doReload();
+ private void showTabs() {
+ GeckoApp.mAppContext.showTabs();
+ }
+
+ public void updateTabs(int count) {
+ mTabs.setText("" + count);
}
public void updateProgress(int progress, int total) {
diff --git a/embedding/android/GeckoApp.java b/embedding/android/GeckoApp.java
index c79c3951071..84e15434a20 100644
--- a/embedding/android/GeckoApp.java
+++ b/embedding/android/GeckoApp.java
@@ -22,6 +22,7 @@
* Vladimir Vukicevic
* Matt Brubeck
* Vivien Nicolas
+ * Sriram Ramasubramanian
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -49,6 +50,8 @@ import java.nio.channels.FileChannel;
import java.util.concurrent.*;
import java.lang.reflect.*;
+import org.json.*;
+
import android.os.*;
import android.app.*;
import android.text.*;
@@ -58,6 +61,7 @@ import android.content.*;
import android.content.res.*;
import android.graphics.*;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.BitmapDrawable;
import android.widget.*;
import android.hardware.*;
@@ -72,7 +76,7 @@ import android.content.SharedPreferences.*;
import dalvik.system.*;
abstract public class GeckoApp
- extends Activity
+ extends Activity implements GeckoEventListener
{
private static final String LOG_FILE_NAME = "GeckoApp";
@@ -93,6 +97,9 @@ abstract public class GeckoApp
private IntentFilter mConnectivityFilter;
private BroadcastReceiver mConnectivityReceiver;
private BrowserToolbar mBrowserToolbar;
+ private PopupWindow mTabsTray;
+ private TabsAdapter mTabsAdapter;
+ private static boolean isTabsTrayShowing;
enum LaunchState {Launching, WaitButton,
Launched, GeckoRunning, GeckoExiting};
@@ -102,7 +109,6 @@ abstract public class GeckoApp
private static final int FILE_PICKER_REQUEST = 1;
private static final int AWESOMEBAR_REQUEST = 2;
private static final int CAMERA_CAPTURE_REQUEST = 3;
- private static final int SHOW_TABS_REQUEST = 4;
static boolean checkLaunchState(LaunchState checkState) {
synchronized(sLaunchState) {
@@ -296,7 +302,7 @@ abstract public class GeckoApp
boolean launch(Intent intent)
{
Log.w(LOGTAG, "zerdatime " + new Date().getTime() + " - launch");
-
+
if (!checkAndSetLaunchState(LaunchState.Launching, LaunchState.Launched))
return false;
@@ -408,10 +414,8 @@ abstract public class GeckoApp
Intent.ACTION_SEND, he.mTitle);
}
return true;
- case R.id.show_tabs:
- Intent showTabsIntent = new Intent(this, ShowTabs.class);
- showTabsIntent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_NO_HISTORY);
- startActivityForResult(showTabsIntent, SHOW_TABS_REQUEST);
+ case R.id.reload:
+ doReload();
return true;
default:
return super.onOptionsItemSelected(item);
@@ -477,6 +481,177 @@ abstract public class GeckoApp
});
}
+ void showTabs() {
+ DisplayMetrics metrics = new DisplayMetrics();
+ getWindowManager().getDefaultDisplay().getMetrics(metrics);
+
+ int width = metrics.widthPixels;
+ int height = (int) (metrics.widthPixels * 0.75);
+ LayoutInflater inflater = (LayoutInflater) mAppContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ mTabsTray = new PopupWindow(inflater.inflate(R.layout.tabs_tray, null, false),
+ width,
+ height,
+ true);
+ mTabsTray.setBackgroundDrawable(new BitmapDrawable());
+ mTabsTray.setOutsideTouchable(true);
+
+ ListView list = (ListView) mTabsTray.getContentView().findViewById(R.id.list);
+ Button addTab = new Button(this);
+ addTab.setText(R.string.new_tab);
+ addTab.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ hideTabs();
+ Intent intent = new Intent(mAppContext, AwesomeBar.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_NO_HISTORY);
+ intent.putExtra(AwesomeBar.TYPE_KEY, AwesomeBar.Type.ADD.name());
+ startActivityForResult(intent, AWESOMEBAR_REQUEST);
+ }
+ });
+
+ list.addFooterView(addTab);
+ isTabsTrayShowing = true;
+ onTabsChanged();
+ mTabsTray.showAsDropDown(mBrowserToolbar.findViewById(R.id.tabs));
+ }
+
+ void hideTabs() {
+ if (mTabsTray.isShowing()) {
+ mTabsAdapter = null;
+ ((ListView) mTabsTray.getContentView().findViewById(R.id.list)).invalidateViews();
+ mTabsTray.dismiss();
+ isTabsTrayShowing = false;
+ }
+ }
+
+ public void onTabsChanged() {
+ if (mTabsTray == null)
+ return;
+
+ if (!isTabsTrayShowing)
+ return;
+
+ final HashMap tabs = Tabs.getInstance().getTabs();
+ if (mTabsAdapter != null) {
+ mTabsAdapter = new TabsAdapter(mAppContext, tabs);
+ mTabsAdapter.notifyDataSetChanged();
+ ListView list = (ListView) mTabsTray.getContentView().findViewById(R.id.list);
+ list.invalidateViews();
+ list.setAdapter(mTabsAdapter);
+ } else {
+ mTabsAdapter = new TabsAdapter(mAppContext, tabs);
+ ListView list = (ListView) mTabsTray.getContentView().findViewById(R.id.list);
+ list.setAdapter(mTabsAdapter);
+ }
+ }
+
+ public void handleMessage(String event, JSONObject message) {
+ try {
+ if (event.equals("DOMContentLoaded")) {
+ final int tabId = message.getInt("tabID");
+ final String uri = message.getString("uri");
+ final String title = message.getString("title");
+ final CharSequence titleText = title;
+ handleContentLoaded(tabId, uri, title);
+ Log.i("GeckoShell", "URI - " + uri + ", title - " + title);
+ } else if (event.equals("DOMTitleChanged")) {
+ final int tabId = message.getInt("tabID");
+ final String title = message.getString("title");
+ final CharSequence titleText = title;
+ handleTitleChanged(tabId, title);
+ Log.i("GeckoShell", "title - " + title);
+ } else if (event.equals("DOMLinkAdded")) {
+ final int tabId = message.getInt("tabID");
+ final String rel = message.getString("rel");
+ final String href = message.getString("href");
+ Log.i("GeckoShell", "link rel - " + rel + ", href - " + href);
+ handleLinkAdded(tabId, rel, href);
+ } else if (event.equals("log")) {
+ // generic log listener
+ final String msg = message.getString("msg");
+ Log.i("GeckoShell", "Log: " + msg);
+ } else if (event.equals("onLocationChange")) {
+ final int tabId = message.getInt("tabID");
+ final String uri = message.getString("uri");
+ Log.i("GeckoShell", "URI - " + uri);
+ handleLocationChange(tabId, uri);
+ } else if (event.equals("onStateChange")) {
+ final int tabId = message.getInt("tabID");
+ int state = message.getInt("state");
+ Log.i("GeckoShell", "State - " + state);
+ if ((state & GeckoAppShell.WPL_STATE_IS_DOCUMENT) != 0) {
+ if ((state & GeckoAppShell.WPL_STATE_START) != 0) {
+ Log.i("GeckoShell", "Got a document start");
+ handleDocumentStart(tabId);
+ } else if ((state & GeckoAppShell.WPL_STATE_STOP) != 0) {
+ Log.i("GeckoShell", "Got a document stop");
+ handleDocumentStop(tabId);
+ }
+ }
+ } else if (event.equals("onProgressChange")) {
+ final int tabId = message.getInt("tabID");
+ final int current = message.getInt("current");
+ final int total = message.getInt("total");
+
+ handleProgressChange(tabId, current, total);
+ Log.i("GeckoShell", "progress - " + current + "/" + total);
+ } else if (event.equals("onCameraCapture")) {
+ //GeckoApp.mAppContext.doCameraCapture(message.getString("path"));
+ doCameraCapture();
+ } else if (event.equals("Tab:Added")) {
+ Log.i("GeckoShell", "Created a new tab");
+ int tabId = message.getInt("tabID");
+ String uri = message.getString("uri");
+ handleAddTab(tabId, uri);
+ } else if (event.equals("Tab:Closed")) {
+ Log.i("GeckoShell", "Destroyed a tab");
+ int tabId = message.getInt("tabID");
+ handleCloseTab(tabId);
+ } else if (event.equals("Tab:Selected")) {
+ int tabId = message.getInt("tabID");
+ Log.i("GeckoShell", "Switched to tab: " + tabId);
+ handleSelectTab(tabId);
+ }
+ } catch (Exception e) {
+ Log.i("GeckoApp", "handleMessage throws " + e + " for message: " + event);
+ }
+ }
+
+ void handleAddTab(final int tabId, final String uri) {
+ Tab tab = Tabs.getInstance().addTab(tabId, uri);
+ tab.updateFavicon(mAppContext.getResources().getDrawable(R.drawable.favicon));
+ mMainHandler.post(new Runnable() {
+ public void run() {
+ onTabsChanged();
+ mBrowserToolbar.updateTabs(Tabs.getInstance().getCount());
+ }
+ });
+ }
+
+ void handleCloseTab(final int tabId) {
+ Tabs.getInstance().removeTab(tabId);
+
+ mMainHandler.post(new Runnable() {
+ public void run() {
+ onTabsChanged();
+ mBrowserToolbar.updateTabs(Tabs.getInstance().getCount());
+ }
+ });
+ }
+
+ void handleSelectTab(final int tabId) {
+ final Tab tab = Tabs.getInstance().selectTab(tabId);
+ if (tab == null)
+ return;
+
+ mMainHandler.post(new Runnable() {
+ public void run() {
+ mBrowserToolbar.setTitle(tab.getTitle());
+ mBrowserToolbar.setFavicon(tab.getFavicon());
+ mBrowserToolbar.setProgressVisibility(tab.isLoading());
+ }
+ });
+ }
+
void handleDocumentStart(final int tabId) {
Tab tab = Tabs.getInstance().getTab(tabId);
@@ -485,6 +660,12 @@ abstract public class GeckoApp
tab.setLoading(true);
+ mMainHandler.post(new Runnable() {
+ public void run() {
+ onTabsChanged();
+ }
+ });
+
if (!Tabs.getInstance().isSelectedTab(tab))
return;
@@ -498,7 +679,17 @@ abstract public class GeckoApp
void handleDocumentStop(final int tabId) {
Tab tab = Tabs.getInstance().getTab(tabId);
- tab.setLoading(false);
+
+ if (tab == null)
+ return;
+
+ tab.setLoading(false);
+
+ mMainHandler.post(new Runnable() {
+ public void run() {
+ onTabsChanged();
+ }
+ });
if (!Tabs.getInstance().isSelectedTab(tab))
return;
@@ -513,6 +704,9 @@ abstract public class GeckoApp
void handleProgressChange(final int tabId, final int current, final int total) {
Tab tab = Tabs.getInstance().getTab(tabId);
+ if (tab == null)
+ return;
+
if (!Tabs.getInstance().isSelectedTab(tab))
return;
@@ -525,9 +719,18 @@ abstract public class GeckoApp
void handleContentLoaded(final int tabId, final String uri, final String title) {
Tab tab = Tabs.getInstance().getTab(tabId);
+ if (tab == null)
+ return;
+
tab.updateTitle(title);
tab.addHistory(new Tab.HistoryEntry(uri, title));
+ mMainHandler.post(new Runnable() {
+ public void run() {
+ onTabsChanged();
+ }
+ });
+
if (!Tabs.getInstance().isSelectedTab(tab))
return;
@@ -540,6 +743,9 @@ abstract public class GeckoApp
void handleTitleChanged(final int tabId, final String title) {
Tab tab = Tabs.getInstance().getTab(tabId);
+ if (tab == null)
+ return;
+
tab.updateTitle(title);
if (!Tabs.getInstance().isSelectedTab(tab))
@@ -547,12 +753,13 @@ abstract public class GeckoApp
mMainHandler.post(new Runnable() {
public void run() {
+ onTabsChanged();
mBrowserToolbar.setTitle(title);
}
});
}
- void handleLinkAdded(String rel, final String href) {
+ void handleLinkAdded(final int tabId, String rel, final String href) {
class DownloadFaviconTask extends AsyncTask {
protected Drawable doInBackground(URL... url) {
Drawable image = null;
@@ -566,6 +773,21 @@ abstract public class GeckoApp
}
protected void onPostExecute(Drawable image) {
if (image != null) {
+ Tab tab = Tabs.getInstance().getTab(tabId);
+ if (tab == null)
+ return;
+
+ tab.updateFavicon(image);
+
+ mMainHandler.post(new Runnable() {
+ public void run() {
+ onTabsChanged();
+ }
+ });
+
+ if (!Tabs.getInstance().isSelectedTab(tab))
+ return;
+
final Drawable postImage = image;
mMainHandler.post(new Runnable() {
public void run() {
@@ -585,7 +807,7 @@ abstract public class GeckoApp
}
}
}
-
+
void addPluginView(final View view,
final double x, final double y,
final double w, final double h) {
@@ -699,6 +921,20 @@ abstract public class GeckoApp
mMainLayout = (LinearLayout) findViewById(R.id.mainLayout);
mBrowserToolbar = (BrowserToolbar) findViewById(R.id.browserToolbar);
+
+ //register for events
+ GeckoAppShell.registerGeckoEventListener("DOMContentLoaded", GeckoApp.mAppContext);
+ GeckoAppShell.registerGeckoEventListener("DOMTitleChanged", GeckoApp.mAppContext);
+ GeckoAppShell.registerGeckoEventListener("DOMLinkAdded", GeckoApp.mAppContext);
+ GeckoAppShell.registerGeckoEventListener("log", GeckoApp.mAppContext);
+ GeckoAppShell.registerGeckoEventListener("onLocationChange", GeckoApp.mAppContext);
+ GeckoAppShell.registerGeckoEventListener("onStateChange", GeckoApp.mAppContext);
+ GeckoAppShell.registerGeckoEventListener("onProgressChange", GeckoApp.mAppContext);
+ GeckoAppShell.registerGeckoEventListener("onCameraCapture", GeckoApp.mAppContext);
+ GeckoAppShell.registerGeckoEventListener("Tab:Added", GeckoApp.mAppContext);
+ GeckoAppShell.registerGeckoEventListener("Tab:Closed", GeckoApp.mAppContext);
+ GeckoAppShell.registerGeckoEventListener("Tab:Selected", GeckoApp.mAppContext);
+
mConnectivityFilter = new IntentFilter();
mConnectivityFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
@@ -874,6 +1110,23 @@ abstract public class GeckoApp
GeckoAppShell.getPromptService().onDestroy();
}
});
+
+ if (mTabsTray != null && mTabsTray.isShowing()) {
+ hideTabs();
+ mTabsTray = null;
+ }
+
+ GeckoAppShell.unregisterGeckoEventListener("DOMContentLoaded", GeckoApp.mAppContext);
+ GeckoAppShell.unregisterGeckoEventListener("DOMTitleChanged", GeckoApp.mAppContext);
+ GeckoAppShell.unregisterGeckoEventListener("DOMLinkAdded", GeckoApp.mAppContext);
+ GeckoAppShell.unregisterGeckoEventListener("log", GeckoApp.mAppContext);
+ GeckoAppShell.unregisterGeckoEventListener("onLocationChange", GeckoApp.mAppContext);
+ GeckoAppShell.unregisterGeckoEventListener("onStateChange", GeckoApp.mAppContext);
+ GeckoAppShell.unregisterGeckoEventListener("onProgressChange", GeckoApp.mAppContext);
+ GeckoAppShell.unregisterGeckoEventListener("onCameraCapture", GeckoApp.mAppContext);
+ GeckoAppShell.unregisterGeckoEventListener("Tab:Added", GeckoApp.mAppContext);
+ GeckoAppShell.unregisterGeckoEventListener("Tab:Closed", GeckoApp.mAppContext);
+ GeckoAppShell.unregisterGeckoEventListener("Tab:Selected", GeckoApp.mAppContext);
super.onDestroy();
}
@@ -1145,24 +1398,6 @@ abstract public class GeckoApp
"{\"ok\": false, \"path\": \"" + file.getPath() + "\" }");
GeckoAppShell.sendEventToGecko(e);
break;
- case SHOW_TABS_REQUEST:
- if (data != null) {
- ShowTabs.Type type = ShowTabs.Type.valueOf(data.getStringExtra(ShowTabs.TYPE));
- if (type == ShowTabs.Type.ADD) {
- Intent intent = new Intent(this, AwesomeBar.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_NO_HISTORY);
- intent.putExtra(AwesomeBar.TYPE_KEY, AwesomeBar.Type.ADD.name());
- startActivityForResult(intent, AWESOMEBAR_REQUEST);
- } else {
- int id = Integer.parseInt(data.getStringExtra(ShowTabs.ID));
- Tab tab = Tabs.getInstance().selectTab(id);
- if (tab != null) {
- mBrowserToolbar.setTitle(tab.getTitle());
- mBrowserToolbar.setProgressVisibility(tab.isLoading());
- }
- GeckoAppShell.sendEventToGecko(new GeckoEvent("tab-select", "" + id));
- }
- }
}
}
@@ -1179,9 +1414,109 @@ abstract public class GeckoApp
mBrowserToolbar.setTitle(url);
Log.d(LOG_FILE_NAME, type.name());
if (type == AwesomeBar.Type.ADD) {
- GeckoAppShell.sendEventToGecko(new GeckoEvent("tab-add", url));
+ GeckoAppShell.sendEventToGecko(new GeckoEvent("Tab:Add", url));
} else {
- GeckoAppShell.sendEventToGecko(new GeckoEvent("tab-load", url));
+ GeckoAppShell.sendEventToGecko(new GeckoEvent("Tab:Load", url));
}
- }
+ }
+
+ // Adapter to bind tabs into a list
+ private class TabsAdapter extends BaseAdapter {
+ public TabsAdapter(Context context, HashMap tabs) {
+ mContext = context;
+ mTabs = new ArrayList();
+
+ if (tabs != null) {
+ Iterator keys = tabs.keySet().iterator();
+ Tab tab;
+ while (keys.hasNext()) {
+ tab = tabs.get(keys.next());
+ mTabs.add(tab);
+ }
+ }
+
+ mInflater = LayoutInflater.from(mContext);
+ }
+
+ @Override
+ public int getCount() {
+ return mTabs.size();
+ }
+
+ @Override
+ public Tab getItem(int position) {
+ return mTabs.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+
+ if (convertView == null)
+ convertView = mInflater.inflate(R.layout.tabs_row, null);
+
+ Tab tab = mTabs.get(position);
+
+ LinearLayout info = (LinearLayout) convertView.findViewById(R.id.info);
+ info.setTag("" + tab.getId());
+ info.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ hideTabs();
+ GeckoAppShell.sendEventToGecko(new GeckoEvent("Tab:Select", "" + v.getTag()));
+ }
+ });
+
+ ImageView favicon = (ImageView) convertView.findViewById(R.id.favicon);
+ favicon.setImageDrawable(tab.getFavicon());
+
+ TextView title = (TextView) convertView.findViewById(R.id.title);
+ title.setText(tab.getTitle());
+
+ TextView url = (TextView) convertView.findViewById(R.id.url);
+ url.setText(tab.getURL());
+
+ ImageButton close = (ImageButton) convertView.findViewById(R.id.close);
+ if (mTabs.size() > 1) {
+ close.setTag("" + tab.getId());
+ close.setOnClickListener(new Button.OnClickListener() {
+ public void onClick(View v) {
+ int tabId = Integer.parseInt("" + v.getTag());
+ Tabs tabs = Tabs.getInstance();
+ Tab tab = tabs.getTab(tabId);
+
+ if (tabs.isSelectedTab(tab)) {
+ int index = tabs.getIndexOf(tab);
+ if (index >= 1)
+ index--;
+ else
+ index = 1;
+ int id = tabs.getTabAt(index).getId();
+ GeckoAppShell.sendEventToGecko(new GeckoEvent("Tab:Select", "" + id));
+ GeckoAppShell.sendEventToGecko(new GeckoEvent("Tab:Close", "" + v.getTag()));
+ } else {
+ GeckoAppShell.sendEventToGecko(new GeckoEvent("Tab:Close", "" + v.getTag()));
+ GeckoAppShell.sendEventToGecko(new GeckoEvent("Tab:Select", "" + tabs.getSelectedTabId()));
+ }
+ }
+ });
+ } else {
+ close.setVisibility(View.GONE);
+ }
+
+ return convertView;
+ }
+
+ @Override
+ public void notifyDataSetChanged() {
+ }
+
+
+ private Context mContext;
+ private ArrayList mTabs;
+ private LayoutInflater mInflater;
+ }
}
diff --git a/embedding/android/GeckoAppShell.java b/embedding/android/GeckoAppShell.java
index 9cd50d05a5d..5f400933d74 100644
--- a/embedding/android/GeckoAppShell.java
+++ b/embedding/android/GeckoAppShell.java
@@ -20,6 +20,7 @@
*
* Contributor(s):
* Vladimir Vukicevic
+ * Sriram Ramasubramanian
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -99,13 +100,15 @@ public class GeckoAppShell
/* Keep in sync with constants found here:
http://mxr.mozilla.org/mozilla-central/source/uriloader/base/nsIWebProgressListener.idl
*/
- static private final int WPL_STATE_START = 0x00000001;
- static private final int WPL_STATE_STOP = 0x00000010;
- static private final int WPL_STATE_IS_DOCUMENT = 0x00020000;
+ static public final int WPL_STATE_START = 0x00000001;
+ static public final int WPL_STATE_STOP = 0x00000010;
+ static public final int WPL_STATE_IS_DOCUMENT = 0x00020000;
static private File sCacheFile = null;
static private int sFreeSpace = -1;
+ private static HashMap> mEventListeners;
+
/* The Android-side API: API methods that Android calls */
// Initialization methods
@@ -1502,6 +1505,28 @@ public class GeckoAppShell
static SynchronousQueue sPromptQueue = null;
+ public static void registerGeckoEventListener(String event, GeckoEventListener listener) {
+ if (mEventListeners == null)
+ mEventListeners = new HashMap>();
+
+ if (!mEventListeners.containsKey(event))
+ mEventListeners.put(event, new ArrayList());
+
+ ArrayList listeners = mEventListeners.get(event);
+ listeners.add(listener);
+ }
+
+ public static void unregisterGeckoEventListener(String event, GeckoEventListener listener) {
+ if (mEventListeners == null)
+ return;
+
+ if (!mEventListeners.containsKey(event))
+ return;
+
+ ArrayList listeners = mEventListeners.get(event);
+ listeners.remove(listener);
+ }
+
public static String handleGeckoMessage(String message) {
//
// {"gecko": {
@@ -1512,63 +1537,8 @@ public class GeckoAppShell
JSONObject json = new JSONObject(message);
final JSONObject geckoObject = json.getJSONObject("gecko");
String type = geckoObject.getString("type");
-
- if (type.equals("DOMContentLoaded")) {
- final int tabId = geckoObject.getInt("tabID");
- final String uri = geckoObject.getString("uri");
- final String title = geckoObject.getString("title");
- final CharSequence titleText = title;
- GeckoApp.mAppContext.handleContentLoaded(tabId, uri, title);
- Log.i("GeckoShell", "URI - " + uri + ", title - " + title);
- } else if (type.equals("DOMTitleChanged")) {
- final int tabId = geckoObject.getInt("tabID");
- final String title = geckoObject.getString("title");
- final CharSequence titleText = title;
- GeckoApp.mAppContext.handleTitleChanged(tabId, title);
- Log.i("GeckoShell", "title - " + title);
- } else if (type.equals("DOMLinkAdded")) {
- final String rel = geckoObject.getString("rel");
- final String href = geckoObject.getString("href");
- Log.i("GeckoShell", "link rel - " + rel + ", href - " + href);
- GeckoApp.mAppContext.handleLinkAdded(rel, href);
- } else if (type.equals("log")) {
- // generic log listener
- final String msg = geckoObject.getString("msg");
- Log.i("GeckoShell", "Log: " + msg);
- } else if (type.equals("onLocationChange")) {
- final int tabId = geckoObject.getInt("tabID");
- final String uri = geckoObject.getString("uri");
- Log.i("GeckoShell", "URI - " + uri);
- GeckoApp.mAppContext.handleLocationChange(tabId, uri);
- } else if (type.equals("onStateChange")) {
- final int tabId = geckoObject.getInt("tabID");
- int state = geckoObject.getInt("state");
- Log.i("GeckoShell", "State - " + state);
- if ((state & WPL_STATE_IS_DOCUMENT) != 0) {
- if ((state & WPL_STATE_START) != 0) {
- Log.i("GeckoShell", "Got a document start");
- GeckoApp.mAppContext.handleDocumentStart(tabId);
- } else if ((state & WPL_STATE_STOP) != 0) {
- Log.i("GeckoShell", "Got a document stop");
- GeckoApp.mAppContext.handleDocumentStop(tabId);
- }
- }
- } else if (type.equals("onProgressChange")) {
- final int tabId = geckoObject.getInt("tabID");
- final int current = geckoObject.getInt("current");
- final int total = geckoObject.getInt("total");
-
- GeckoApp.mAppContext.handleProgressChange(tabId, current, total);
- Log.i("GeckoShell", "progress - " + current + "/" + total);
- } else if (type.equals("onCameraCapture")) {
- //GeckoApp.mAppContext.doCameraCapture(geckoObject.getString("path"));
- GeckoApp.mAppContext.doCameraCapture();
- } else if (type.equals("onCreateTab")) {
- Log.i("GeckoShell", "Created a new tab");
- int tabId = geckoObject.getInt("tabID");
- String uri = geckoObject.getString("uri");
- Tabs.getInstance().addTab(tabId, uri);
- } else if (type.equals("prompt")) {
+
+ if (type.equals("prompt")) {
if (sPromptQueue == null)
sPromptQueue = new SynchronousQueue();
getHandler().post(new Runnable() {
@@ -1586,9 +1556,23 @@ public class GeckoAppShell
}
return promptServiceResult;
}
+
+ if (mEventListeners == null)
+ return "";
+
+ if (!mEventListeners.containsKey(type))
+ return "";
+
+ ArrayList listeners = mEventListeners.get(type);
+ Iterator items = listeners.iterator();
+ while (items.hasNext()) {
+ ((GeckoEventListener) items.next()).handleMessage(type, geckoObject);
+ }
+
} catch (Exception e) {
Log.i("GeckoShell", "handleGeckoMessage throws " + e);
}
+
return "";
}
diff --git a/embedding/android/GeckoEventListener.java b/embedding/android/GeckoEventListener.java
new file mode 100644
index 00000000000..670513f2cfb
--- /dev/null
+++ b/embedding/android/GeckoEventListener.java
@@ -0,0 +1,44 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (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.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009-2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Sriram Ramasubramanian
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.gecko;
+
+import org.json.JSONObject;
+
+public interface GeckoEventListener {
+ public void handleMessage(String event, JSONObject message);
+}
diff --git a/embedding/android/Makefile.in b/embedding/android/Makefile.in
index 7ae29f56eee..d8c2334ee97 100644
--- a/embedding/android/Makefile.in
+++ b/embedding/android/Makefile.in
@@ -58,7 +58,7 @@ JAVAFILES = \
GeckoBookmarks.java \
Tab.java \
Tabs.java \
- ShowTabs.java \
+ GeckoEventListener.java \
PromptService.java \
SurfaceInfo.java \
$(NULL)
@@ -139,7 +139,8 @@ RES_LAYOUT = \
res/layout/browser_toolbar.xml \
res/layout/bookmarks.xml \
res/layout/bookmark_list_row.xml \
- res/layout/show_tabs.xml \
+ res/layout/tabs_tray.xml \
+ res/layout/tabs_row.xml \
res/layout/dialog_checkbox.xml \
$(NULL)
diff --git a/embedding/android/ShowTabs.java b/embedding/android/ShowTabs.java
deleted file mode 100644
index 21de8f71623..00000000000
--- a/embedding/android/ShowTabs.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (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.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla Android code.
- *
- * The Initial Developer of the Original Code is Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 2011
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Sriram Ramasubramanian
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-package org.mozilla.gecko;
-
-import java.io.*;
-import java.util.*;
-
-import org.mozilla.gecko.*;
-
-import android.os.*;
-import android.content.*;
-import android.app.*;
-import android.text.*;
-import android.util.*;
-import android.widget.*;
-import android.database.sqlite.*;
-import android.database.*;
-import android.view.*;
-import android.view.View.*;
-import android.net.Uri;
-import android.graphics.*;
-
-public class ShowTabs extends ListActivity {
- private static final String LOG_FILE_NAME = "ShowTabs";
- public static final String ID = "id";
- public static final String TYPE = "type";
- private ArrayList > tabsList = null;
- public static enum Type { ADD, SWITCH };
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- requestWindowFeature(Window.FEATURE_NO_TITLE);
- setContentView(R.layout.show_tabs);
-
- ListView list = (ListView) findViewById(android.R.id.list);
- Button addTab = new Button(this);
- addTab.setText("+ add tab");
- addTab.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- Intent resultIntent = new Intent();
- resultIntent.putExtra(TYPE, Type.ADD.name());
- setResult(Activity.RESULT_OK, resultIntent);
- finish();
- }
- });
-
- list.addHeaderView(addTab);
-
- HashMap tabs = Tabs.getInstance().getTabs();
- tabsList = new ArrayList> ();
-
- if (tabs != null) {
- Iterator keys = tabs.keySet().iterator();
- HashMap map;
- Tab tab;
- while (keys.hasNext()) {
- tab = tabs.get(keys.next());
- map = new HashMap();
- map.put("id", "" + tab.getId());
- map.put("title", tab.getTitle());
- map.put("url", tab.getURL());
- tabsList.add(map);
- }
- }
-
- list.setAdapter(new SimpleAdapter(
- ShowTabs.this,
- tabsList,
- R.layout.awesomebar_row,
- new String[] { "title", "url" },
- new int[] { R.id.title, R.id.url }
- ));
- }
-
- @Override
- public void onListItemClick(ListView l, View v, int position, long id) {
- HashMap map = tabsList.get((int) id);
- Intent resultIntent = new Intent();
- resultIntent.putExtra(TYPE, Type.SWITCH.name());
- resultIntent.putExtra(ID, map.get("id"));
- setResult(Activity.RESULT_OK, resultIntent);
- finish();
- }
-}
diff --git a/embedding/android/Tab.java b/embedding/android/Tab.java
index d450d2dece4..f25483f61cf 100644
--- a/embedding/android/Tab.java
+++ b/embedding/android/Tab.java
@@ -95,6 +95,10 @@ public class Tab {
return title;
}
+ public Drawable getFavicon() {
+ return favicon;
+ }
+
public boolean isLoading() {
return loading;
}
diff --git a/embedding/android/Tabs.java b/embedding/android/Tabs.java
index eeb32a49096..0c369144e1f 100644
--- a/embedding/android/Tabs.java
+++ b/embedding/android/Tabs.java
@@ -47,9 +47,11 @@ public class Tabs {
private static final String LOG_FILE_NAME = "Tabs";
private static int selectedTab = -1;
private HashMap tabs;
+ private ArrayList order;
private Tabs() {
tabs = new HashMap();
+ order = new ArrayList();
}
public int getCount() {
@@ -62,6 +64,7 @@ public class Tabs {
Tab tab = new Tab(id, url);
tabs.put(id, tab);
+ order.add(tab);
Log.i(LOG_FILE_NAME, "Added a tab with id: " + id + ", url: " + url);
selectedTab = id;
return tab;
@@ -69,6 +72,7 @@ public class Tabs {
public void removeTab(int id) {
if (tabs.containsKey(id)) {
+ order.remove(getTab(id));
tabs.remove(id);
Log.i(LOG_FILE_NAME, "Removed a tab with id: " + id);
}
@@ -82,6 +86,17 @@ public class Tabs {
return tabs.get(id);
}
+ public int getIndexOf(Tab tab) {
+ return order.lastIndexOf(tab);
+ }
+
+ public Tab getTabAt(int index) {
+ if (index < order.size())
+ return order.get(index);
+ else
+ return null;
+ }
+
public Tab getSelectedTab() {
return tabs.get(selectedTab);
}
diff --git a/embedding/android/locales/en-US/android_strings.dtd b/embedding/android/locales/en-US/android_strings.dtd
index cb2c0acfb26..a846ce0a599 100644
--- a/embedding/android/locales/en-US/android_strings.dtd
+++ b/embedding/android/locales/en-US/android_strings.dtd
@@ -23,7 +23,9 @@
-
+
+
+
diff --git a/embedding/android/resources/layout/browser_toolbar.xml b/embedding/android/resources/layout/browser_toolbar.xml
index 30eb5010458..e3db012cd25 100644
--- a/embedding/android/resources/layout/browser_toolbar.xml
+++ b/embedding/android/resources/layout/browser_toolbar.xml
@@ -9,19 +9,18 @@
+
+
-
-
diff --git a/embedding/android/resources/layout/gecko_menu.xml b/embedding/android/resources/layout/gecko_menu.xml
index e55d8cc530d..b70c55ef159 100644
--- a/embedding/android/resources/layout/gecko_menu.xml
+++ b/embedding/android/resources/layout/gecko_menu.xml
@@ -1,9 +1,8 @@
diff --git a/embedding/android/resources/layout/show_tabs.xml b/embedding/android/resources/layout/show_tabs.xml
deleted file mode 100644
index 8a411bb58af..00000000000
--- a/embedding/android/resources/layout/show_tabs.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
diff --git a/embedding/android/resources/layout/tabs_row.xml b/embedding/android/resources/layout/tabs_row.xml
new file mode 100644
index 00000000000..415b236a71c
--- /dev/null
+++ b/embedding/android/resources/layout/tabs_row.xml
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/embedding/android/resources/layout/tabs_tray.xml b/embedding/android/resources/layout/tabs_tray.xml
new file mode 100644
index 00000000000..8a262192b6e
--- /dev/null
+++ b/embedding/android/resources/layout/tabs_tray.xml
@@ -0,0 +1,9 @@
+
+
diff --git a/embedding/android/resources/values/styles.xml b/embedding/android/resources/values/styles.xml
index 75e7303f8eb..e177406d512 100644
--- a/embedding/android/resources/values/styles.xml
+++ b/embedding/android/resources/values/styles.xml
@@ -45,23 +45,23 @@
-
-
@@ -71,7 +71,8 @@
-