Bug 865060 - Clean up threads in AboutHome views. r=lucasr

This commit is contained in:
Brian Nicholson 2013-04-24 11:11:21 -07:00
parent 597f33c342
commit 9d8e74f38e
4 changed files with 199 additions and 163 deletions

View File

@ -10,6 +10,7 @@ import org.mozilla.gecko.Favicons;
import org.mozilla.gecko.R;
import org.mozilla.gecko.util.GamepadUtils;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.util.UiAsyncTask;
import org.json.JSONArray;
import org.json.JSONException;
@ -26,6 +27,7 @@ import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.io.File;
@ -138,9 +140,9 @@ public class AddonsSection extends AboutHomeSection {
}
public void readRecommendedAddons() {
ThreadUtils.postToBackgroundThread(new Runnable() {
new UiAsyncTask<Void, Void, JSONArray>(ThreadUtils.getBackgroundHandler()) {
@Override
public void run() {
public JSONArray doInBackground(Void... params) {
final String addonsFilename = "recommended-addons.json";
String jsonString;
try {
@ -159,68 +161,72 @@ public class AddonsSection extends AboutHomeSection {
}
}
final JSONArray array = addonsArray;
post(new Runnable() {
@Override
public void run() {
try {
if (array == null || array.length() == 0) {
hide();
return;
}
return addonsArray;
}
for (int i = 0; i < array.length(); i++) {
JSONObject jsonobj = array.getJSONObject(i);
String name = jsonobj.getString("name");
String version = jsonobj.getString("version");
String text = name + " " + version;
@Override
public void onPostExecute(JSONArray addons) {
if (addons == null || addons.length() == 0) {
hide();
return;
}
SpannableString spannable = new SpannableString(text);
spannable.setSpan(sSubTitleSpan, name.length() + 1, text.length(), 0);
final TextView row = (TextView) LayoutInflater.from(mContext).inflate(R.layout.abouthome_addon_row, getItemsContainer(), false);
row.setText(spannable, TextView.BufferType.SPANNABLE);
Drawable drawable = mContext.getResources().getDrawable(R.drawable.ic_addons_empty);
drawable.setBounds(sIconBounds);
row.setCompoundDrawables(drawable, null, null, null);
String iconUrl = jsonobj.getString("iconURL");
String pageUrl = getPageUrlFromIconUrl(iconUrl);
final String homepageUrl = jsonobj.getString("homepageURL");
row.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mUriLoadListener != null)
mUriLoadListener.onAboutHomeUriLoad(homepageUrl);
}
});
row.setOnKeyListener(GamepadUtils.getClickDispatcher());
Favicons favicons = Favicons.getInstance();
favicons.loadFavicon(pageUrl, iconUrl, true,
new Favicons.OnFaviconLoadedListener() {
@Override
public void onFaviconLoaded(String url, Bitmap favicon) {
if (favicon != null) {
Drawable drawable = new BitmapDrawable(favicon);
drawable.setBounds(sIconBounds);
row.setCompoundDrawables(drawable, null, null, null);
}
}
});
addItem(row);
}
show();
} catch (JSONException e) {
Log.i(LOGTAG, "error reading json file", e);
}
try {
for (int i = 0; i < addons.length(); i++) {
View addonView = createAddonView(addons.getJSONObject(i), getItemsContainer());
addItem(addonView);
}
});
} catch (JSONException e) {
Log.e(LOGTAG, "Error reading JSON", e);
return;
}
show();
}
}.execute();
}
View createAddonView(JSONObject addonJSON, ViewGroup parent) throws JSONException {
String name = addonJSON.getString("name");
String version = addonJSON.getString("version");
String text = name + " " + version;
SpannableString spannable = new SpannableString(text);
spannable.setSpan(sSubTitleSpan, name.length() + 1, text.length(), 0);
final TextView row = (TextView) LayoutInflater.from(mContext).inflate(R.layout.abouthome_addon_row, getItemsContainer(), false);
row.setText(spannable, TextView.BufferType.SPANNABLE);
Drawable drawable = mContext.getResources().getDrawable(R.drawable.ic_addons_empty);
drawable.setBounds(sIconBounds);
row.setCompoundDrawables(drawable, null, null, null);
String iconUrl = addonJSON.getString("iconURL");
String pageUrl = getPageUrlFromIconUrl(iconUrl);
final String homepageUrl = addonJSON.getString("homepageURL");
row.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mUriLoadListener != null)
mUriLoadListener.onAboutHomeUriLoad(homepageUrl);
}
});
row.setOnKeyListener(GamepadUtils.getClickDispatcher());
Favicons favicons = Favicons.getInstance();
favicons.loadFavicon(pageUrl, iconUrl, true,
new Favicons.OnFaviconLoadedListener() {
@Override
public void onFaviconLoaded(String url, Bitmap favicon) {
if (favicon != null) {
Drawable drawable = new BitmapDrawable(favicon);
drawable.setBounds(sIconBounds);
row.setCompoundDrawables(drawable, null, null, null);
}
}
});
return row;
}
}

View File

@ -12,6 +12,7 @@ import org.mozilla.gecko.Tabs;
import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.util.GamepadUtils;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.util.UiAsyncTask;
import android.content.ContentResolver;
import android.content.Context;
@ -19,6 +20,7 @@ import android.graphics.Bitmap;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
@ -27,22 +29,34 @@ import java.util.ArrayList;
public class LastTabsSection extends AboutHomeSection {
private Context mContext;
private class TabInfo {
final String url;
final String title;
final Bitmap favicon;
TabInfo(String url, String title, Bitmap favicon) {
this.url = url;
this.title = title;
this.favicon = favicon;
}
}
public LastTabsSection(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
}
public void readLastTabs() {
ThreadUtils.postToBackgroundThread(new Runnable() {
new UiAsyncTask<Void, Void, ArrayList<TabInfo>>(ThreadUtils.getBackgroundHandler()) {
@Override
public void run() {
protected ArrayList<TabInfo> doInBackground(Void... params) {
String jsonString = GeckoProfile.get(mContext).readSessionFile(true);
if (jsonString == null) {
// no previous session data
return;
return null;
}
final ArrayList<String> lastTabUrlsList = new ArrayList<String>();
final ArrayList<TabInfo> lastTabs = new ArrayList<TabInfo>();
new SessionParser() {
@Override
public void onTabRead(final SessionTab tab) {
@ -54,61 +68,74 @@ public class LastTabsSection extends AboutHomeSection {
ContentResolver resolver = mContext.getContentResolver();
final Bitmap favicon = BrowserDB.getFaviconForUrl(resolver, url);
lastTabUrlsList.add(url);
LastTabsSection.this.post(new Runnable() {
@Override
public void run() {
View container = LayoutInflater.from(mContext).inflate(R.layout.abouthome_last_tabs_row, getItemsContainer(), false);
((TextView) container.findViewById(R.id.last_tab_title)).setText(tab.getSelectedTitle());
((TextView) container.findViewById(R.id.last_tab_url)).setText(tab.getSelectedUrl());
if (favicon != null) {
((ImageView) container.findViewById(R.id.last_tab_favicon)).setImageBitmap(favicon);
}
container.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int flags = Tabs.LOADURL_NEW_TAB;
if (Tabs.getInstance().getSelectedTab().isPrivate())
flags |= Tabs.LOADURL_PRIVATE;
Tabs.getInstance().loadUrl(url, flags);
}
});
container.setOnKeyListener(GamepadUtils.getClickDispatcher());
addItem(container);
}
});
final String title = tab.getSelectedTitle();
lastTabs.add(new TabInfo(url, title, favicon));
}
}.parse(jsonString);
final int nu = lastTabUrlsList.size();
if (nu >= 1) {
post(new Runnable() {
return lastTabs;
}
@Override
public void onPostExecute(final ArrayList<TabInfo> lastTabs) {
if (lastTabs == null) {
return;
}
for (TabInfo tab : lastTabs) {
final View tabView = createTabView(tab, getItemsContainer());
addItem(tabView);
}
// If we have at least one tab from last time, show the
// container view.
final int numTabs = lastTabs.size();
if (numTabs > 1) {
// If we have more than one tab from last time, show the
// "Open all tabs" button
showMoreText();
setOnMoreTextClickListener(new View.OnClickListener() {
@Override
public void run() {
if (nu > 1) {
showMoreText();
setOnMoreTextClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int flags = Tabs.LOADURL_NEW_TAB;
if (Tabs.getInstance().getSelectedTab().isPrivate())
flags |= Tabs.LOADURL_PRIVATE;
for (String url : lastTabUrlsList) {
Tabs.getInstance().loadUrl(url, flags);
}
}
});
} else if (nu == 1) {
hideMoreText();
public void onClick(View v) {
int flags = Tabs.LOADURL_NEW_TAB;
if (Tabs.getInstance().getSelectedTab().isPrivate())
flags |= Tabs.LOADURL_PRIVATE;
for (TabInfo tab : lastTabs) {
Tabs.getInstance().loadUrl(tab.url, flags);
}
show();
}
});
show();
} else if (numTabs == 1) {
hideMoreText();
show();
}
}
}.execute();
}
View createTabView(final TabInfo tab, ViewGroup parent) {
final String url = tab.url;
final Bitmap favicon = tab.favicon;
View tabView = LayoutInflater.from(mContext).inflate(R.layout.abouthome_last_tabs_row, parent, false);
((TextView) tabView.findViewById(R.id.last_tab_title)).setText(tab.title);
((TextView) tabView.findViewById(R.id.last_tab_url)).setText(url);
if (favicon != null) {
((ImageView) tabView.findViewById(R.id.last_tab_favicon)).setImageBitmap(favicon);
}
tabView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int flags = Tabs.LOADURL_NEW_TAB;
if (Tabs.getInstance().getSelectedTab().isPrivate())
flags |= Tabs.LOADURL_PRIVATE;
Tabs.getInstance().loadUrl(url, flags);
}
});
tabView.setOnKeyListener(GamepadUtils.getClickDispatcher());
return tabView;
}
}

View File

@ -12,6 +12,7 @@ import org.mozilla.gecko.TabsAccessor;
import org.mozilla.gecko.sync.setup.SyncAccounts;
import org.mozilla.gecko.util.GamepadUtils;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.util.UiAsyncTask;
import android.content.Context;
import android.text.TextUtils;
@ -56,22 +57,22 @@ public class RemoteTabsSection extends AboutHomeSection
}
public void loadRemoteTabs() {
ThreadUtils.postToBackgroundThread(new Runnable() {
new UiAsyncTask<Void, Void, Boolean>(ThreadUtils.getBackgroundHandler()) {
@Override
public void run() {
public Boolean doInBackground(Void... params) {
if (!SyncAccounts.syncAccountsExist(mActivity)) {
post(new Runnable() {
@Override
public void run() {
hide();
}
});
return;
return false;
}
TabsAccessor.getTabs(getContext(), NUMBER_OF_REMOTE_TABS, RemoteTabsSection.this);
return true;
}
});
public void onPostExecute(Boolean syncAccountsExist) {
if (!syncAccountsExist) {
hide();
}
}
}.execute();
}
@Override

View File

@ -194,46 +194,43 @@ public class TopSitesView extends GridView {
}
public void loadTopSites() {
ThreadUtils.postToBackgroundThread(new Runnable() {
final ContentResolver resolver = mContext.getContentResolver();
final Cursor oldCursor = (mTopSitesAdapter != null) ? mTopSitesAdapter.getCursor() : null;
new UiAsyncTask<Void, Void, Cursor>(ThreadUtils.getBackgroundHandler()) {
@Override
public void run() {
final ContentResolver resolver = mContext.getContentResolver();
// Swap in the new cursor.
final Cursor oldCursor = (mTopSitesAdapter != null) ? mTopSitesAdapter.getCursor() : null;
final Cursor newCursor = BrowserDB.getTopSites(resolver, mNumberOfTopSites);
post(new Runnable() {
@Override
public void run() {
if (mTopSitesAdapter == null) {
mTopSitesAdapter = new TopSitesCursorAdapter(mContext,
R.layout.abouthome_topsite_item,
newCursor,
new String[] { URLColumns.TITLE },
new int[] { R.id.title });
setAdapter(mTopSitesAdapter);
} else {
mTopSitesAdapter.changeCursor(newCursor);
}
if (mTopSitesAdapter.getCount() > 0)
loadTopSitesThumbnails(resolver);
// Free the old Cursor in the right thread now.
if (oldCursor != null && !oldCursor.isClosed())
oldCursor.close();
// Even if AboutHome isn't necessarily entirely loaded if we
// get here, for phones this is the part the user initially sees,
// so it's the one we will care about for now.
if (mLoadCompleteListener != null)
mLoadCompleteListener.onAboutHomeLoadComplete();
}
});
protected Cursor doInBackground(Void... params) {
return BrowserDB.getTopSites(resolver, mNumberOfTopSites);
}
});
@Override
protected void onPostExecute(Cursor newCursor) {
if (mTopSitesAdapter == null) {
mTopSitesAdapter = new TopSitesCursorAdapter(mContext,
R.layout.abouthome_topsite_item,
newCursor,
new String[] { URLColumns.TITLE },
new int[] { R.id.title });
setAdapter(mTopSitesAdapter);
} else {
mTopSitesAdapter.changeCursor(newCursor);
}
if (mTopSitesAdapter.getCount() > 0)
loadTopSitesThumbnails(resolver);
// Free the old Cursor in the right thread now.
if (oldCursor != null && !oldCursor.isClosed())
oldCursor.close();
// Even if AboutHome isn't necessarily entirely loaded if we
// get here, for phones this is the part the user initially sees,
// so it's the one we will care about for now.
if (mLoadCompleteListener != null)
mLoadCompleteListener.onAboutHomeLoadComplete();
}
}.execute();
}
@Override
@ -331,18 +328,23 @@ public class TopSitesView extends GridView {
}
private void loadTopSitesThumbnails(final ContentResolver cr) {
final List<String> urls = getTopSitesUrls();
if (urls.size() == 0)
return;
(new UiAsyncTask<Void, Void, Map<String, Bitmap> >(ThreadUtils.getBackgroundHandler()) {
@Override
public Map<String, Bitmap> doInBackground(Void... params) {
final List<String> urls = getTopSitesUrls();
if (urls.size() == 0) {
return null;
}
return getThumbnailsFromCursor(BrowserDB.getThumbnailsForUrls(cr, urls));
}
@Override
public void onPostExecute(Map<String, Bitmap> thumbnails) {
if (thumbnails == null) {
return;
}
// If we're waiting for a layout to happen, the GridView may be
// stale, so store the pending thumbnails here. They will be
// shown on the next layout pass.