michael@0: /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: package org.mozilla.gecko.home; michael@0: michael@0: import org.mozilla.gecko.AboutPages; michael@0: import org.mozilla.gecko.GeckoProfile; michael@0: import org.mozilla.gecko.R; michael@0: import org.mozilla.gecko.SessionParser; michael@0: import org.mozilla.gecko.Telemetry; michael@0: import org.mozilla.gecko.TelemetryContract; michael@0: import org.mozilla.gecko.db.BrowserContract.Combined; michael@0: import org.mozilla.gecko.home.HomePager.OnNewTabsListener; michael@0: michael@0: import android.app.Activity; michael@0: import android.content.Context; michael@0: import android.database.Cursor; michael@0: import android.database.MatrixCursor; michael@0: import android.database.MatrixCursor.RowBuilder; michael@0: import android.os.Bundle; michael@0: import android.support.v4.app.LoaderManager.LoaderCallbacks; michael@0: import android.support.v4.content.Loader; michael@0: import android.support.v4.widget.CursorAdapter; michael@0: import android.view.LayoutInflater; michael@0: import android.view.View; michael@0: import android.view.ViewGroup; michael@0: import android.view.ViewStub; michael@0: import android.widget.AdapterView; michael@0: import android.widget.ImageView; michael@0: import android.widget.TextView; michael@0: michael@0: /** michael@0: * Fragment that displays tabs from last session in a ListView. michael@0: */ michael@0: public class LastTabsPanel extends HomeFragment { michael@0: // Logging tag name michael@0: private static final String LOGTAG = "GeckoLastTabsPanel"; michael@0: michael@0: // Cursor loader ID for the session parser michael@0: private static final int LOADER_ID_LAST_TABS = 0; michael@0: michael@0: // Adapter for the list of search results michael@0: private LastTabsAdapter mAdapter; michael@0: michael@0: // The view shown by the fragment. michael@0: private HomeListView mList; michael@0: michael@0: // The title for this HomeFragment panel. michael@0: private TextView mTitle; michael@0: michael@0: // The button view for restoring tabs from last session. michael@0: private View mRestoreButton; michael@0: michael@0: // Reference to the View to display when there are no results. michael@0: private View mEmptyView; michael@0: michael@0: // Callbacks used for the search and favicon cursor loaders michael@0: private CursorLoaderCallbacks mCursorLoaderCallbacks; michael@0: michael@0: // On new tabs listener michael@0: private OnNewTabsListener mNewTabsListener; michael@0: michael@0: public static LastTabsPanel newInstance() { michael@0: return new LastTabsPanel(); michael@0: } michael@0: michael@0: public LastTabsPanel() { michael@0: mNewTabsListener = null; michael@0: } michael@0: michael@0: @Override michael@0: public void onAttach(Activity activity) { michael@0: super.onAttach(activity); michael@0: michael@0: try { michael@0: mNewTabsListener = (OnNewTabsListener) activity; michael@0: } catch (ClassCastException e) { michael@0: throw new ClassCastException(activity.toString() michael@0: + " must implement HomePager.OnNewTabsListener"); michael@0: } michael@0: } michael@0: michael@0: @Override michael@0: public void onDetach() { michael@0: super.onDetach(); michael@0: michael@0: mNewTabsListener = null; michael@0: } michael@0: michael@0: @Override michael@0: public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { michael@0: return inflater.inflate(R.layout.home_last_tabs_panel, container, false); michael@0: } michael@0: michael@0: @Override michael@0: public void onViewCreated(View view, Bundle savedInstanceState) { michael@0: mTitle = (TextView) view.findViewById(R.id.title); michael@0: if (mTitle != null) { michael@0: mTitle.setText(R.string.home_last_tabs_title); michael@0: } michael@0: michael@0: mList = (HomeListView) view.findViewById(R.id.list); michael@0: mList.setTag(HomePager.LIST_TAG_LAST_TABS); michael@0: michael@0: mList.setOnItemClickListener(new AdapterView.OnItemClickListener() { michael@0: @Override michael@0: public void onItemClick(AdapterView parent, View view, int position, long id) { michael@0: final Cursor c = mAdapter.getCursor(); michael@0: if (c == null || !c.moveToPosition(position)) { michael@0: return; michael@0: } michael@0: michael@0: Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL); michael@0: michael@0: final String url = c.getString(c.getColumnIndexOrThrow(Combined.URL)); michael@0: mNewTabsListener.onNewTabs(new String[] { url }); michael@0: } michael@0: }); michael@0: michael@0: mList.setContextMenuInfoFactory(new HomeContextMenuInfo.Factory() { michael@0: @Override michael@0: public HomeContextMenuInfo makeInfoForCursor(View view, int position, long id, Cursor cursor) { michael@0: final HomeContextMenuInfo info = new HomeContextMenuInfo(view, position, id); michael@0: info.url = cursor.getString(cursor.getColumnIndexOrThrow(Combined.URL)); michael@0: info.title = cursor.getString(cursor.getColumnIndexOrThrow(Combined.TITLE)); michael@0: return info; michael@0: } michael@0: }); michael@0: michael@0: registerForContextMenu(mList); michael@0: michael@0: mRestoreButton = view.findViewById(R.id.open_all_tabs_button); michael@0: mRestoreButton.setOnClickListener(new View.OnClickListener() { michael@0: @Override michael@0: public void onClick(View v) { michael@0: openAllTabs(); michael@0: } michael@0: }); michael@0: } michael@0: michael@0: @Override michael@0: public void onDestroyView() { michael@0: super.onDestroyView(); michael@0: mList = null; michael@0: mTitle = null; michael@0: mEmptyView = null; michael@0: mRestoreButton = null; michael@0: } michael@0: michael@0: @Override michael@0: public void onActivityCreated(Bundle savedInstanceState) { michael@0: super.onActivityCreated(savedInstanceState); michael@0: michael@0: // Intialize adapter michael@0: mAdapter = new LastTabsAdapter(getActivity()); michael@0: mList.setAdapter(mAdapter); michael@0: michael@0: // Create callbacks before the initial loader is started michael@0: mCursorLoaderCallbacks = new CursorLoaderCallbacks(); michael@0: loadIfVisible(); michael@0: } michael@0: michael@0: private void updateUiFromCursor(Cursor c) { michael@0: if (c != null && c.getCount() > 0) { michael@0: if (mTitle != null) { michael@0: mTitle.setVisibility(View.VISIBLE); michael@0: } michael@0: mRestoreButton.setVisibility(View.VISIBLE); michael@0: return; michael@0: } michael@0: michael@0: // Cursor is empty, so hide the title and set the michael@0: // empty view if it hasn't been set already. michael@0: if (mTitle != null) { michael@0: mTitle.setVisibility(View.GONE); michael@0: } michael@0: mRestoreButton.setVisibility(View.GONE); michael@0: michael@0: if (mEmptyView == null) { michael@0: // Set empty panel view. We delay this so that the empty view won't flash. michael@0: final ViewStub emptyViewStub = (ViewStub) getView().findViewById(R.id.home_empty_view_stub); michael@0: mEmptyView = emptyViewStub.inflate(); michael@0: michael@0: final ImageView emptyIcon = (ImageView) mEmptyView.findViewById(R.id.home_empty_image); michael@0: emptyIcon.setImageResource(R.drawable.icon_last_tabs_empty); michael@0: michael@0: final TextView emptyText = (TextView) mEmptyView.findViewById(R.id.home_empty_text); michael@0: emptyText.setText(R.string.home_last_tabs_empty); michael@0: michael@0: mList.setEmptyView(mEmptyView); michael@0: } michael@0: } michael@0: michael@0: @Override michael@0: protected void load() { michael@0: getLoaderManager().initLoader(LOADER_ID_LAST_TABS, null, mCursorLoaderCallbacks); michael@0: } michael@0: michael@0: private void openAllTabs() { michael@0: final Cursor c = mAdapter.getCursor(); michael@0: if (c == null || !c.moveToFirst()) { michael@0: return; michael@0: } michael@0: michael@0: final String[] urls = new String[c.getCount()]; michael@0: michael@0: do { michael@0: urls[c.getPosition()] = c.getString(c.getColumnIndexOrThrow(Combined.URL)); michael@0: } while (c.moveToNext()); michael@0: michael@0: Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.BUTTON); michael@0: michael@0: mNewTabsListener.onNewTabs(urls); michael@0: } michael@0: michael@0: private static class LastTabsCursorLoader extends SimpleCursorLoader { michael@0: public LastTabsCursorLoader(Context context) { michael@0: super(context); michael@0: } michael@0: michael@0: @Override michael@0: public Cursor loadCursor() { michael@0: final Context context = getContext(); michael@0: michael@0: final String jsonString = GeckoProfile.get(context).readSessionFile(true); michael@0: if (jsonString == null) { michael@0: // No previous session data michael@0: return null; michael@0: } michael@0: michael@0: final MatrixCursor c = new MatrixCursor(new String[] { Combined._ID, michael@0: Combined.URL, michael@0: Combined.TITLE }); michael@0: michael@0: new SessionParser() { michael@0: @Override michael@0: public void onTabRead(SessionTab tab) { michael@0: final String url = tab.getUrl(); michael@0: michael@0: // Don't show last tabs for about:home michael@0: if (AboutPages.isAboutHome(url)) { michael@0: return; michael@0: } michael@0: michael@0: final RowBuilder row = c.newRow(); michael@0: row.add(-1); michael@0: row.add(url); michael@0: michael@0: final String title = tab.getTitle(); michael@0: row.add(title); michael@0: } michael@0: }.parse(jsonString); michael@0: michael@0: return c; michael@0: } michael@0: } michael@0: michael@0: private static class LastTabsAdapter extends CursorAdapter { michael@0: public LastTabsAdapter(Context context) { michael@0: super(context, null, 0); michael@0: } michael@0: michael@0: @Override michael@0: public void bindView(View view, Context context, Cursor cursor) { michael@0: ((TwoLinePageRow) view).updateFromCursor(cursor); michael@0: } michael@0: michael@0: @Override michael@0: public View newView(Context context, Cursor cursor, ViewGroup parent) { michael@0: return LayoutInflater.from(context).inflate(R.layout.home_item_row, parent, false); michael@0: } michael@0: } michael@0: michael@0: private class CursorLoaderCallbacks implements LoaderCallbacks { michael@0: @Override michael@0: public Loader onCreateLoader(int id, Bundle args) { michael@0: return new LastTabsCursorLoader(getActivity()); michael@0: } michael@0: michael@0: @Override michael@0: public void onLoadFinished(Loader loader, Cursor c) { michael@0: mAdapter.swapCursor(c); michael@0: updateUiFromCursor(c); michael@0: } michael@0: michael@0: @Override michael@0: public void onLoaderReset(Loader loader) { michael@0: mAdapter.swapCursor(null); michael@0: } michael@0: } michael@0: }