зеркало из https://github.com/mozilla/gecko-dev.git
Bug 734425: Support remote tabs on about:home [r=rnewman, r=mfinkle]
This commit is contained in:
Родитель
bc75b7a8de
Коммит
867bd17a79
|
@ -47,6 +47,7 @@ import java.net.URL;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipFile;
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
|
@ -70,6 +71,7 @@ import android.graphics.Bitmap;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
import android.graphics.drawable.BitmapDrawable;
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.os.SystemClock;
|
||||||
import android.text.SpannableString;
|
import android.text.SpannableString;
|
||||||
import android.text.style.StyleSpan;
|
import android.text.style.StyleSpan;
|
||||||
import android.text.style.UnderlineSpan;
|
import android.text.style.UnderlineSpan;
|
||||||
|
@ -89,8 +91,10 @@ import android.widget.RelativeLayout;
|
||||||
import android.widget.ScrollView;
|
import android.widget.ScrollView;
|
||||||
import android.widget.SimpleCursorAdapter;
|
import android.widget.SimpleCursorAdapter;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
public class AboutHomeContent extends ScrollView {
|
public class AboutHomeContent extends ScrollView
|
||||||
|
implements TabsAccessor.OnQueryTabsCompleteListener {
|
||||||
private static final String LOGTAG = "GeckoAboutHome";
|
private static final String LOGTAG = "GeckoAboutHome";
|
||||||
|
|
||||||
private static final int NUMBER_OF_TOP_SITES_PORTRAIT = 4;
|
private static final int NUMBER_OF_TOP_SITES_PORTRAIT = 4;
|
||||||
|
@ -99,10 +103,13 @@ public class AboutHomeContent extends ScrollView {
|
||||||
private static final int NUMBER_OF_COLS_PORTRAIT = 2;
|
private static final int NUMBER_OF_COLS_PORTRAIT = 2;
|
||||||
private static final int NUMBER_OF_COLS_LANDSCAPE = 3;
|
private static final int NUMBER_OF_COLS_LANDSCAPE = 3;
|
||||||
|
|
||||||
|
private static final int NUMBER_OF_REMOTE_TABS = 10;
|
||||||
|
|
||||||
static enum UpdateFlags {
|
static enum UpdateFlags {
|
||||||
TOP_SITES,
|
TOP_SITES,
|
||||||
PREVIOUS_TABS,
|
PREVIOUS_TABS,
|
||||||
RECOMMENDED_ADDONS;
|
RECOMMENDED_ADDONS,
|
||||||
|
REMOTE_TABS;
|
||||||
|
|
||||||
public static final EnumSet<UpdateFlags> ALL = EnumSet.allOf(UpdateFlags.class);
|
public static final EnumSet<UpdateFlags> ALL = EnumSet.allOf(UpdateFlags.class);
|
||||||
}
|
}
|
||||||
|
@ -119,6 +126,9 @@ public class AboutHomeContent extends ScrollView {
|
||||||
|
|
||||||
protected LinearLayout mAddonsLayout;
|
protected LinearLayout mAddonsLayout;
|
||||||
protected LinearLayout mLastTabsLayout;
|
protected LinearLayout mLastTabsLayout;
|
||||||
|
protected LinearLayout mRemoteTabsLayout;
|
||||||
|
|
||||||
|
private View.OnClickListener mRemoteTabClickListener;
|
||||||
|
|
||||||
public interface UriLoadCallback {
|
public interface UriLoadCallback {
|
||||||
public void callback(String uriSpec);
|
public void callback(String uriSpec);
|
||||||
|
@ -172,6 +182,7 @@ public class AboutHomeContent extends ScrollView {
|
||||||
|
|
||||||
mAddonsLayout = (LinearLayout) findViewById(R.id.recommended_addons);
|
mAddonsLayout = (LinearLayout) findViewById(R.id.recommended_addons);
|
||||||
mLastTabsLayout = (LinearLayout) findViewById(R.id.last_tabs);
|
mLastTabsLayout = (LinearLayout) findViewById(R.id.last_tabs);
|
||||||
|
mRemoteTabsLayout = (LinearLayout) findViewById(R.id.remote_tabs);
|
||||||
|
|
||||||
TextView allTopSitesText = (TextView) findViewById(R.id.all_top_sites_text);
|
TextView allTopSitesText = (TextView) findViewById(R.id.all_top_sites_text);
|
||||||
allTopSitesText.setOnClickListener(new View.OnClickListener() {
|
allTopSitesText.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@ -188,6 +199,14 @@ public class AboutHomeContent extends ScrollView {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
TextView allRemoteTabsText = (TextView) findViewById(R.id.all_remote_tabs_text);
|
||||||
|
allRemoteTabsText.setOnClickListener(new View.OnClickListener() {
|
||||||
|
public void onClick(View v) {
|
||||||
|
Context context = v.getContext();
|
||||||
|
context.startActivity(new Intent(context, RemoteTabs.class));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
TextView syncTextView = (TextView) findViewById(R.id.sync_text);
|
TextView syncTextView = (TextView) findViewById(R.id.sync_text);
|
||||||
String syncText = syncTextView.getText().toString() + " \u00BB";
|
String syncText = syncTextView.getText().toString() + " \u00BB";
|
||||||
String boldName = getContext().getResources().getString(R.string.abouthome_sync_bold_name);
|
String boldName = getContext().getResources().getString(R.string.abouthome_sync_bold_name);
|
||||||
|
@ -209,6 +228,24 @@ public class AboutHomeContent extends ScrollView {
|
||||||
context.startActivity(intent);
|
context.startActivity(intent);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
mRemoteTabClickListener = new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
String url = ((String) v.getTag());
|
||||||
|
JSONObject args = new JSONObject();
|
||||||
|
try {
|
||||||
|
args.put("url", url);
|
||||||
|
args.put("engine", null);
|
||||||
|
args.put("userEntered", false);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(LOGTAG, "error building JSON arguments");
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.d(LOGTAG, "Sending message to Gecko: " + SystemClock.uptimeMillis() + " - Tab:Add");
|
||||||
|
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Tab:Add", args.toString()));
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
|
@ -243,6 +280,14 @@ public class AboutHomeContent extends ScrollView {
|
||||||
findViewById(R.id.no_top_sites_text).setVisibility(visibilityWithoutTopSites);
|
findViewById(R.id.no_top_sites_text).setVisibility(visibilityWithoutTopSites);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setRemoteTabsVisibility(boolean visible) {
|
||||||
|
int visibility = visible ? View.VISIBLE : View.GONE;
|
||||||
|
findViewById(R.id.remote_tabs_title).setVisibility(visibility);
|
||||||
|
findViewById(R.id.remote_tabs_client).setVisibility(visibility);
|
||||||
|
findViewById(R.id.remote_tabs).setVisibility(visibility);
|
||||||
|
findViewById(R.id.all_remote_tabs_text).setVisibility(visibility);
|
||||||
|
}
|
||||||
|
|
||||||
private void setSyncVisibility(boolean visible) {
|
private void setSyncVisibility(boolean visible) {
|
||||||
int visibility = visible ? View.VISIBLE : View.GONE;
|
int visibility = visible ? View.VISIBLE : View.GONE;
|
||||||
findViewById(R.id.sync_box_container).setVisibility(visibility);
|
findViewById(R.id.sync_box_container).setVisibility(visibility);
|
||||||
|
@ -353,6 +398,9 @@ public class AboutHomeContent extends ScrollView {
|
||||||
|
|
||||||
if (flags.contains(UpdateFlags.RECOMMENDED_ADDONS))
|
if (flags.contains(UpdateFlags.RECOMMENDED_ADDONS))
|
||||||
readRecommendedAddons(activity);
|
readRecommendedAddons(activity);
|
||||||
|
|
||||||
|
if (flags.contains(UpdateFlags.REMOTE_TABS))
|
||||||
|
loadRemoteTabs(activity);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -605,6 +653,44 @@ public class AboutHomeContent extends ScrollView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void loadRemoteTabs(final Activity activity) {
|
||||||
|
if (!isSyncSetup()) {
|
||||||
|
setRemoteTabsVisibility(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TabsAccessor.getTabs(getContext(), NUMBER_OF_REMOTE_TABS, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onQueryTabsComplete(List<TabsAccessor.RemoteTab> tabsList) {
|
||||||
|
ArrayList<TabsAccessor.RemoteTab> tabs = new ArrayList<TabsAccessor.RemoteTab> (tabsList);
|
||||||
|
if (tabs == null || tabs.size() == 0) {
|
||||||
|
setRemoteTabsVisibility(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mRemoteTabsLayout.removeAllViews();
|
||||||
|
|
||||||
|
String client = null;
|
||||||
|
|
||||||
|
for (TabsAccessor.RemoteTab tab : tabs) {
|
||||||
|
if (client == null)
|
||||||
|
client = tab.name;
|
||||||
|
else if (!TextUtils.equals(client, tab.name))
|
||||||
|
break;
|
||||||
|
|
||||||
|
final TextView row = (TextView) mInflater.inflate(R.layout.abouthome_remote_tab_row, mRemoteTabsLayout, false);
|
||||||
|
row.setText(tab.title);
|
||||||
|
row.setTag(tab.url);
|
||||||
|
mRemoteTabsLayout.addView(row);
|
||||||
|
row.setOnClickListener(mRemoteTabClickListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
((TextView) findViewById(R.id.remote_tabs_client)).setText(client);
|
||||||
|
setRemoteTabsVisibility(true);
|
||||||
|
}
|
||||||
|
|
||||||
public static class TopSitesGridView extends GridView {
|
public static class TopSitesGridView extends GridView {
|
||||||
/** From layout xml:
|
/** From layout xml:
|
||||||
* 80dip image height
|
* 80dip image height
|
||||||
|
|
|
@ -1107,7 +1107,8 @@ abstract public class GeckoApp
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
mAboutHomeContent.update(GeckoApp.mAppContext,
|
mAboutHomeContent.update(GeckoApp.mAppContext,
|
||||||
EnumSet.of(AboutHomeContent.UpdateFlags.TOP_SITES));
|
EnumSet.of(AboutHomeContent.UpdateFlags.TOP_SITES,
|
||||||
|
AboutHomeContent.UpdateFlags.REMOTE_TABS));
|
||||||
}
|
}
|
||||||
|
|
||||||
mAboutHomeContent.setVisibility(View.VISIBLE);
|
mAboutHomeContent.setVisibility(View.VISIBLE);
|
||||||
|
@ -2562,7 +2563,7 @@ abstract public class GeckoApp
|
||||||
Log.e(LOGTAG, "error building JSON arguments");
|
Log.e(LOGTAG, "error building JSON arguments");
|
||||||
}
|
}
|
||||||
if (type == AwesomeBar.Type.ADD) {
|
if (type == AwesomeBar.Type.ADD) {
|
||||||
Log.i(LOGTAG, "Sending message to Gecko: " + SystemClock.uptimeMillis() + " - Tab:Add");
|
Log.d(LOGTAG, "Sending message to Gecko: " + SystemClock.uptimeMillis() + " - Tab:Add");
|
||||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Tab:Add", args.toString()));
|
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Tab:Add", args.toString()));
|
||||||
} else {
|
} else {
|
||||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Tab:Load", args.toString()));
|
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Tab:Load", args.toString()));
|
||||||
|
|
|
@ -109,6 +109,7 @@ FENNEC_JAVA_FILES = \
|
||||||
Tab.java \
|
Tab.java \
|
||||||
Tabs.java \
|
Tabs.java \
|
||||||
TabsTray.java \
|
TabsTray.java \
|
||||||
|
TabsAccessor.java \
|
||||||
gfx/BitmapUtils.java \
|
gfx/BitmapUtils.java \
|
||||||
gfx/BufferedCairoImage.java \
|
gfx/BufferedCairoImage.java \
|
||||||
gfx/CairoGLInfo.java \
|
gfx/CairoGLInfo.java \
|
||||||
|
@ -260,6 +261,7 @@ RES_LAYOUT = \
|
||||||
res/layout/abouthome_topsite_item.xml \
|
res/layout/abouthome_topsite_item.xml \
|
||||||
res/layout/abouthome_addon_row.xml \
|
res/layout/abouthome_addon_row.xml \
|
||||||
res/layout/abouthome_last_tabs_row.xml \
|
res/layout/abouthome_last_tabs_row.xml \
|
||||||
|
res/layout/abouthome_remote_tab_row.xml \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
RES_LAYOUT_V11 = \
|
RES_LAYOUT_V11 = \
|
||||||
|
|
|
@ -6,10 +6,7 @@ package org.mozilla.gecko;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import org.mozilla.gecko.db.BrowserContract.Clients;
|
|
||||||
import org.mozilla.gecko.db.BrowserContract.Tabs;
|
|
||||||
import org.mozilla.gecko.db.BrowserContract;
|
|
||||||
|
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
@ -31,15 +28,16 @@ import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
public class RemoteTabs extends Activity
|
public class RemoteTabs extends Activity
|
||||||
implements ExpandableListView.OnGroupClickListener, ExpandableListView.OnChildClickListener {
|
implements ExpandableListView.OnGroupClickListener, ExpandableListView.OnChildClickListener,
|
||||||
|
TabsAccessor.OnQueryTabsCompleteListener {
|
||||||
private static final String LOGTAG = "GeckoRemoteTabs";
|
private static final String LOGTAG = "GeckoRemoteTabs";
|
||||||
|
|
||||||
private static int sPreferredHeight;
|
private static int sPreferredHeight;
|
||||||
private static int sChildItemHeight;
|
private static int sChildItemHeight;
|
||||||
private static int sGroupItemHeight;
|
private static int sGroupItemHeight;
|
||||||
private static ExpandableListView mList;
|
private static ExpandableListView mList;
|
||||||
|
private static boolean mExitToTabsTray;
|
||||||
private static ArrayList <HashMap <String, String>> mClientsList;
|
|
||||||
private static ArrayList <ArrayList <HashMap <String, String>>> mTabsList;
|
private static ArrayList <ArrayList <HashMap <String, String>>> mTabsList;
|
||||||
|
|
||||||
// 50 for child + 2 for divider
|
// 50 for child + 2 for divider
|
||||||
|
@ -48,13 +46,6 @@ public class RemoteTabs extends Activity
|
||||||
// 30 for group + 2 for divider
|
// 30 for group + 2 for divider
|
||||||
private static final int GROUP_ITEM_HEIGHT = 32;
|
private static final int GROUP_ITEM_HEIGHT = 32;
|
||||||
|
|
||||||
private static final String[] PROJECTION_COLUMNS = new String[] {
|
|
||||||
BrowserContract.Tabs.TITLE, // 0
|
|
||||||
BrowserContract.Tabs.URL, // 1
|
|
||||||
BrowserContract.Clients.GUID, // 2
|
|
||||||
BrowserContract.Clients.NAME // 3
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final String[] CLIENT_KEY = new String[] { "name" };
|
private static final String[] CLIENT_KEY = new String[] { "name" };
|
||||||
private static final String[] TAB_KEY = new String[] { "title" };
|
private static final String[] TAB_KEY = new String[] { "title" };
|
||||||
private static final int[] CLIENT_RESOURCE = new int[] { R.id.client };
|
private static final int[] CLIENT_RESOURCE = new int[] { R.id.client };
|
||||||
|
@ -84,14 +75,19 @@ public class RemoteTabs extends Activity
|
||||||
sGroupItemHeight = (int) (GROUP_ITEM_HEIGHT * metrics.density);
|
sGroupItemHeight = (int) (GROUP_ITEM_HEIGHT * metrics.density);
|
||||||
sPreferredHeight = (int) (0.67 * metrics.heightPixels);
|
sPreferredHeight = (int) (0.67 * metrics.heightPixels);
|
||||||
|
|
||||||
// Query the database for remote tabs in AsyncTask
|
TabsAccessor.getTabs(getApplicationContext(), this);
|
||||||
(new QueryRemoteTabsTask()).execute();
|
|
||||||
|
// Exit to tabs-tray
|
||||||
|
mExitToTabsTray = getIntent().getBooleanExtra("exit-to-tabs-tray", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBackPressed() {
|
public void onBackPressed() {
|
||||||
startActivity(new Intent(this, TabsTray.class));
|
if (mExitToTabsTray) {
|
||||||
overridePendingTransition(R.anim.grow_fade_in, 0);
|
startActivity(new Intent(this, TabsTray.class));
|
||||||
|
overridePendingTransition(R.anim.grow_fade_in, R.anim.shrink_fade_out);
|
||||||
|
}
|
||||||
|
|
||||||
finishActivity();
|
finishActivity();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,7 +120,7 @@ public class RemoteTabs extends Activity
|
||||||
Log.e(LOGTAG, "error building JSON arguments");
|
Log.e(LOGTAG, "error building JSON arguments");
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.i(LOGTAG, "Sending message to Gecko: " + SystemClock.uptimeMillis() + " - Tab:Add");
|
Log.d(LOGTAG, "Sending message to Gecko: " + SystemClock.uptimeMillis() + " - Tab:Add");
|
||||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Tab:Add", args.toString()));
|
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Tab:Add", args.toString()));
|
||||||
finishActivity();
|
finishActivity();
|
||||||
return true;
|
return true;
|
||||||
|
@ -154,77 +150,53 @@ public class RemoteTabs extends Activity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AsyncTask to query the database
|
@Override
|
||||||
private class QueryRemoteTabsTask extends GeckoAsyncTask<Void, Void, Void> {
|
public void onQueryTabsComplete(List<TabsAccessor.RemoteTab> remoteTabsList) {
|
||||||
@Override
|
ArrayList<TabsAccessor.RemoteTab> remoteTabs = new ArrayList<TabsAccessor.RemoteTab> (remoteTabsList);
|
||||||
protected Void doInBackground(Void... unused) {
|
if (remoteTabs == null || remoteTabs.size() == 0) {
|
||||||
mClientsList = new ArrayList <HashMap <String, String>>();
|
finishActivity();
|
||||||
mTabsList = new ArrayList <ArrayList <HashMap <String, String>>>();
|
return;
|
||||||
|
|
||||||
Cursor tabs = getContentResolver().query(BrowserContract.Tabs.CONTENT_URI,
|
|
||||||
PROJECTION_COLUMNS,
|
|
||||||
BrowserContract.Tabs.CLIENT_GUID + " IS NOT NULL",
|
|
||||||
null,
|
|
||||||
null);
|
|
||||||
|
|
||||||
if (tabs == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
String oldGuid = null;
|
|
||||||
ArrayList <HashMap <String, String>> tabsForClient = null;
|
|
||||||
HashMap <String, String> client;
|
|
||||||
HashMap <String, String> tab;
|
|
||||||
|
|
||||||
try {
|
|
||||||
while (tabs.moveToNext()) {
|
|
||||||
String title = tabs.getString(0);
|
|
||||||
String url = tabs.getString(1);
|
|
||||||
String guid = tabs.getString(2);
|
|
||||||
String name = tabs.getString(3);
|
|
||||||
|
|
||||||
if (oldGuid == null || !TextUtils.equals(oldGuid, guid)) {
|
|
||||||
client = new HashMap <String, String>();
|
|
||||||
client.put("name", name);
|
|
||||||
mClientsList.add(client);
|
|
||||||
|
|
||||||
tabsForClient = new ArrayList <HashMap <String, String>>();
|
|
||||||
mTabsList.add(tabsForClient);
|
|
||||||
|
|
||||||
oldGuid = new String(guid);
|
|
||||||
}
|
|
||||||
|
|
||||||
tab = new HashMap<String, String>();
|
|
||||||
tab.put("title", TextUtils.isEmpty(title) ? url : title);
|
|
||||||
tab.put("url", url);
|
|
||||||
tabsForClient.add(tab);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
tabs.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ArrayList <HashMap <String, String>> clients = new ArrayList <HashMap <String, String>>();
|
||||||
|
|
||||||
@Override
|
mTabsList = new ArrayList <ArrayList <HashMap <String, String>>>();
|
||||||
protected void onPostExecute(Void unused) {
|
|
||||||
if (mClientsList.size() == 0) {
|
String oldGuid = null;
|
||||||
finishActivity();
|
ArrayList <HashMap <String, String>> tabsForClient = null;
|
||||||
return;
|
HashMap <String, String> client;
|
||||||
}
|
HashMap <String, String> tab;
|
||||||
|
|
||||||
mList.setAdapter(new SimpleExpandableListAdapter(getApplicationContext(),
|
for (TabsAccessor.RemoteTab remoteTab : remoteTabs) {
|
||||||
mClientsList,
|
if (oldGuid == null || !TextUtils.equals(oldGuid, remoteTab.guid)) {
|
||||||
R.layout.remote_tabs_group,
|
client = new HashMap <String, String>();
|
||||||
CLIENT_KEY,
|
client.put("name", remoteTab.name);
|
||||||
CLIENT_RESOURCE,
|
clients.add(client);
|
||||||
mTabsList,
|
|
||||||
R.layout.remote_tabs_child,
|
tabsForClient = new ArrayList <HashMap <String, String>>();
|
||||||
TAB_KEY,
|
mTabsList.add(tabsForClient);
|
||||||
TAB_RESOURCE));
|
|
||||||
|
oldGuid = new String(remoteTab.guid);
|
||||||
for (int i = 0; i < mClientsList.size(); i++) {
|
|
||||||
mList.expandGroup(i);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tab = new HashMap<String, String>();
|
||||||
|
tab.put("title", TextUtils.isEmpty(remoteTab.title) ? remoteTab.url : remoteTab.title);
|
||||||
|
tab.put("url", remoteTab.url);
|
||||||
|
tabsForClient.add(tab);
|
||||||
|
}
|
||||||
|
|
||||||
|
mList.setAdapter(new SimpleExpandableListAdapter(getApplicationContext(),
|
||||||
|
clients,
|
||||||
|
R.layout.remote_tabs_group,
|
||||||
|
CLIENT_KEY,
|
||||||
|
CLIENT_RESOURCE,
|
||||||
|
mTabsList,
|
||||||
|
R.layout.remote_tabs_child,
|
||||||
|
TAB_KEY,
|
||||||
|
TAB_RESOURCE));
|
||||||
|
|
||||||
|
for (int i = 0; i < clients.size(); i++) {
|
||||||
|
mList.expandGroup(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,144 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
package org.mozilla.gecko;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.mozilla.gecko.db.BrowserContract.Clients;
|
||||||
|
import org.mozilla.gecko.db.BrowserContract.Tabs;
|
||||||
|
import org.mozilla.gecko.db.BrowserContract;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
public final class TabsAccessor {
|
||||||
|
private static final String LOGTAG = "GeckoTabsAccessor";
|
||||||
|
|
||||||
|
private static final String[] TABS_PROJECTION_COLUMNS = new String[] {
|
||||||
|
BrowserContract.Tabs.TITLE,
|
||||||
|
BrowserContract.Tabs.URL,
|
||||||
|
BrowserContract.Clients.GUID,
|
||||||
|
BrowserContract.Clients.NAME
|
||||||
|
};
|
||||||
|
|
||||||
|
// Projection column numbers
|
||||||
|
public static enum TABS_COLUMN {
|
||||||
|
TITLE,
|
||||||
|
URL,
|
||||||
|
GUID,
|
||||||
|
NAME
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final String TABS_SELECTION = BrowserContract.Tabs.CLIENT_GUID + " IS NOT NULL";
|
||||||
|
|
||||||
|
public static class RemoteTab {
|
||||||
|
public String title;
|
||||||
|
public String url;
|
||||||
|
public String guid;
|
||||||
|
public String name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface OnQueryTabsCompleteListener {
|
||||||
|
public void onQueryTabsComplete(List<RemoteTab> tabs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface OnClientsAvailableListener {
|
||||||
|
public void areAvailable(boolean available);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper method to check if there are any clients available
|
||||||
|
public static void areClientsAvailable(final Context context, final OnClientsAvailableListener listener) {
|
||||||
|
if (listener == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
(new GeckoAsyncTask<Void, Void, Boolean> () {
|
||||||
|
@Override
|
||||||
|
protected Boolean doInBackground(Void... unused) {
|
||||||
|
Cursor cursor = context.getContentResolver().query(BrowserContract.Clients.CONTENT_URI,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null);
|
||||||
|
|
||||||
|
if (cursor == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
return cursor.moveToNext();
|
||||||
|
} finally {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Boolean availability) {
|
||||||
|
listener.areAvailable(availability);
|
||||||
|
}
|
||||||
|
}).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method returns all tabs from all remote clients,
|
||||||
|
// ordered by most recent client first, most recent tab first
|
||||||
|
public static void getTabs(final Context context, final OnQueryTabsCompleteListener listener) {
|
||||||
|
getTabs(context, 0, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method returns limited number of tabs from all remote clients,
|
||||||
|
// ordered by most recent client first, most recent tab first
|
||||||
|
public static void getTabs(final Context context, final int limit, final OnQueryTabsCompleteListener listener) {
|
||||||
|
// If there is no listener, no point in doing work.
|
||||||
|
if (listener == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
(new GeckoAsyncTask<Void, Void, List<RemoteTab>> () {
|
||||||
|
@Override
|
||||||
|
protected List<RemoteTab> doInBackground(Void... unused) {
|
||||||
|
Uri uri = BrowserContract.Tabs.CONTENT_URI;
|
||||||
|
|
||||||
|
if (limit > 0) {
|
||||||
|
uri = uri.buildUpon()
|
||||||
|
.appendQueryParameter(BrowserContract.PARAM_LIMIT, String.valueOf(limit))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
Cursor cursor = context.getContentResolver().query(uri,
|
||||||
|
TABS_PROJECTION_COLUMNS,
|
||||||
|
TABS_SELECTION,
|
||||||
|
null,
|
||||||
|
null);
|
||||||
|
|
||||||
|
if (cursor == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
RemoteTab tab;
|
||||||
|
final ArrayList<RemoteTab> tabs = new ArrayList<RemoteTab> ();
|
||||||
|
try {
|
||||||
|
while (cursor.moveToNext()) {
|
||||||
|
tab = new RemoteTab();
|
||||||
|
tab.title = cursor.getString(TABS_COLUMN.TITLE.ordinal());
|
||||||
|
tab.url = cursor.getString(TABS_COLUMN.URL.ordinal());
|
||||||
|
tab.guid = cursor.getString(TABS_COLUMN.GUID.ordinal());
|
||||||
|
tab.name = cursor.getString(TABS_COLUMN.NAME.ordinal());
|
||||||
|
|
||||||
|
tabs.add(tab);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Collections.unmodifiableList(tabs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(List<RemoteTab> tabs) {
|
||||||
|
listener.onQueryTabsComplete(tabs);
|
||||||
|
}
|
||||||
|
}).execute();
|
||||||
|
}
|
||||||
|
}
|
|
@ -39,13 +39,9 @@ package org.mozilla.gecko;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import org.mozilla.gecko.db.BrowserContract.Clients;
|
|
||||||
import org.mozilla.gecko.db.BrowserContract;
|
|
||||||
|
|
||||||
import android.accounts.AccountManager;
|
import android.accounts.AccountManager;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
@ -128,8 +124,17 @@ public class TabsTray extends Activity implements Tabs.OnTabsChangedListener {
|
||||||
|
|
||||||
// If sync is set up, query the database for remote clients
|
// If sync is set up, query the database for remote clients
|
||||||
// Cleanup after Bug: 734211 is fixed
|
// Cleanup after Bug: 734211 is fixed
|
||||||
if (AccountManager.get(getApplicationContext()).getAccountsByType("org.mozilla.firefox_sync").length > 0)
|
if (AccountManager.get(getApplicationContext()).getAccountsByType("org.mozilla.firefox_sync").length > 0) {
|
||||||
(new QueryForRemoteClientsTask()).execute();
|
TabsAccessor.areClientsAvailable(getApplicationContext(), new TabsAccessor.OnClientsAvailableListener() {
|
||||||
|
@Override
|
||||||
|
public void areAvailable(boolean available) {
|
||||||
|
if (available)
|
||||||
|
mRemoteTabs.setVisibility(View.VISIBLE);
|
||||||
|
else
|
||||||
|
mRemoteTabs.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -177,8 +182,10 @@ public class TabsTray extends Activity implements Tabs.OnTabsChangedListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
void showRemoteTabs() {
|
void showRemoteTabs() {
|
||||||
startActivity(new Intent(this, RemoteTabs.class));
|
Intent intent = new Intent(this, RemoteTabs.class);
|
||||||
overridePendingTransition(R.anim.grow_fade_in, 0);
|
intent.putExtra("exit-to-tabs-tray", true);
|
||||||
|
startActivity(intent);
|
||||||
|
overridePendingTransition(R.anim.grow_fade_in, R.anim.shrink_fade_out);
|
||||||
finishActivity();
|
finishActivity();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,35 +218,6 @@ public class TabsTray extends Activity implements Tabs.OnTabsChangedListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AsyncTask to see if there is any remote tabs in the database
|
|
||||||
private class QueryForRemoteClientsTask extends GeckoAsyncTask<Void, Void, Boolean> {
|
|
||||||
@Override
|
|
||||||
protected Boolean doInBackground(Void... unused) {
|
|
||||||
Cursor clients = getContentResolver().query(BrowserContract.Clients.CONTENT_URI,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null);
|
|
||||||
|
|
||||||
if (clients == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
try {
|
|
||||||
return clients.moveToNext();
|
|
||||||
} finally {
|
|
||||||
clients.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(Boolean clientsExist) {
|
|
||||||
if (clientsExist.booleanValue())
|
|
||||||
mRemoteTabs.setVisibility(View.VISIBLE);
|
|
||||||
else
|
|
||||||
mRemoteTabs.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adapter to bind tabs into a list
|
// Adapter to bind tabs into a list
|
||||||
private class TabsAdapter extends BaseAdapter {
|
private class TabsAdapter extends BaseAdapter {
|
||||||
public TabsAdapter(Context context, ArrayList<Tab> tabs) {
|
public TabsAdapter(Context context, ArrayList<Tab> tabs) {
|
||||||
|
|
|
@ -511,6 +511,7 @@ public class TabsProvider extends ContentProvider {
|
||||||
final int match = URI_MATCHER.match(uri);
|
final int match = URI_MATCHER.match(uri);
|
||||||
|
|
||||||
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
|
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
|
||||||
|
String limit = uri.getQueryParameter(BrowserContract.PARAM_LIMIT);
|
||||||
|
|
||||||
switch (match) {
|
switch (match) {
|
||||||
case TABS_ID:
|
case TABS_ID:
|
||||||
|
@ -555,7 +556,7 @@ public class TabsProvider extends ContentProvider {
|
||||||
|
|
||||||
trace("Running built query.");
|
trace("Running built query.");
|
||||||
Cursor cursor = qb.query(db, projection, selection, selectionArgs, null,
|
Cursor cursor = qb.query(db, projection, selection, selectionArgs, null,
|
||||||
null, sortOrder, null);
|
null, sortOrder, limit);
|
||||||
cursor.setNotificationUri(getContext().getContentResolver(),
|
cursor.setNotificationUri(getContext().getContentResolver(),
|
||||||
BrowserContract.TABS_AUTHORITY_URI);
|
BrowserContract.TABS_AUTHORITY_URI);
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<!ENTITY awesomebar_default_text "Enter Search or Address">
|
<!ENTITY awesomebar_default_text "Enter Search or Address">
|
||||||
|
|
||||||
<!ENTITY remote_tabs "Synced Tabs">
|
<!ENTITY remote_tabs "Synced Tabs">
|
||||||
|
<!ENTITY remote_tabs_show_all "Show all tabs">
|
||||||
|
|
||||||
<!ENTITY bookmark "Bookmark">
|
<!ENTITY bookmark "Bookmark">
|
||||||
<!ENTITY bookmark_added "Bookmark added">
|
<!ENTITY bookmark_added "Bookmark added">
|
||||||
|
|
|
@ -177,6 +177,45 @@
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
android:text="@string/abouthome_addons_browse"/>
|
android:text="@string/abouthome_addons_browse"/>
|
||||||
|
|
||||||
|
<TextView android:id="@+id/remote_tabs_title"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="26dip"
|
||||||
|
android:paddingLeft="12dip"
|
||||||
|
android:background="@drawable/abouthome_separator"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:textColor="#000000"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:gravity="left|center_vertical"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:text="@string/remote_tabs"/>
|
||||||
|
|
||||||
|
<TextView android:id="@+id/remote_tabs_client"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="26dip"
|
||||||
|
android:paddingLeft="12dip"
|
||||||
|
android:background="@drawable/abouthome_separator"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:textColor="#666666"
|
||||||
|
android:gravity="left|center_vertical"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
|
||||||
|
<LinearLayout android:id="@+id/remote_tabs"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:isScrollContainer="false"/>
|
||||||
|
|
||||||
|
<org.mozilla.gecko.LinkTextView android:id="@+id/all_remote_tabs_text"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="47dip"
|
||||||
|
android:background="@drawable/abouthome_separator"
|
||||||
|
android:textColor="#22629e"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:text="@string/remote_tabs_show_all"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</merge>
|
</merge>
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/remote_tab_title"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="47dip"
|
||||||
|
android:paddingLeft="12dip"
|
||||||
|
android:paddingRight="12dip"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:textSize="15sp"
|
||||||
|
android:textColor="#222222"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:ellipsize="middle"
|
||||||
|
android:background="@drawable/abouthome_separator"/>
|
|
@ -35,6 +35,7 @@
|
||||||
<string name="awesomebar_default_text">&awesomebar_default_text;</string>
|
<string name="awesomebar_default_text">&awesomebar_default_text;</string>
|
||||||
|
|
||||||
<string name="remote_tabs">&remote_tabs;</string>
|
<string name="remote_tabs">&remote_tabs;</string>
|
||||||
|
<string name="remote_tabs_show_all">&remote_tabs_show_all;</string>
|
||||||
|
|
||||||
<string name="quit">&quit;</string>
|
<string name="quit">&quit;</string>
|
||||||
<string name="bookmark">&bookmark;</string>
|
<string name="bookmark">&bookmark;</string>
|
||||||
|
|
Загрузка…
Ссылка в новой задаче