Wed, 31 Dec 2014 07:22:50 +0100
Correct previous dual key logic pending first delivery installment.
1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 package org.mozilla.gecko.home;
8 import org.mozilla.gecko.AboutPages;
9 import org.mozilla.gecko.GeckoProfile;
10 import org.mozilla.gecko.R;
11 import org.mozilla.gecko.SessionParser;
12 import org.mozilla.gecko.Telemetry;
13 import org.mozilla.gecko.TelemetryContract;
14 import org.mozilla.gecko.db.BrowserContract.Combined;
15 import org.mozilla.gecko.home.HomePager.OnNewTabsListener;
17 import android.app.Activity;
18 import android.content.Context;
19 import android.database.Cursor;
20 import android.database.MatrixCursor;
21 import android.database.MatrixCursor.RowBuilder;
22 import android.os.Bundle;
23 import android.support.v4.app.LoaderManager.LoaderCallbacks;
24 import android.support.v4.content.Loader;
25 import android.support.v4.widget.CursorAdapter;
26 import android.view.LayoutInflater;
27 import android.view.View;
28 import android.view.ViewGroup;
29 import android.view.ViewStub;
30 import android.widget.AdapterView;
31 import android.widget.ImageView;
32 import android.widget.TextView;
34 /**
35 * Fragment that displays tabs from last session in a ListView.
36 */
37 public class LastTabsPanel extends HomeFragment {
38 // Logging tag name
39 private static final String LOGTAG = "GeckoLastTabsPanel";
41 // Cursor loader ID for the session parser
42 private static final int LOADER_ID_LAST_TABS = 0;
44 // Adapter for the list of search results
45 private LastTabsAdapter mAdapter;
47 // The view shown by the fragment.
48 private HomeListView mList;
50 // The title for this HomeFragment panel.
51 private TextView mTitle;
53 // The button view for restoring tabs from last session.
54 private View mRestoreButton;
56 // Reference to the View to display when there are no results.
57 private View mEmptyView;
59 // Callbacks used for the search and favicon cursor loaders
60 private CursorLoaderCallbacks mCursorLoaderCallbacks;
62 // On new tabs listener
63 private OnNewTabsListener mNewTabsListener;
65 public static LastTabsPanel newInstance() {
66 return new LastTabsPanel();
67 }
69 public LastTabsPanel() {
70 mNewTabsListener = null;
71 }
73 @Override
74 public void onAttach(Activity activity) {
75 super.onAttach(activity);
77 try {
78 mNewTabsListener = (OnNewTabsListener) activity;
79 } catch (ClassCastException e) {
80 throw new ClassCastException(activity.toString()
81 + " must implement HomePager.OnNewTabsListener");
82 }
83 }
85 @Override
86 public void onDetach() {
87 super.onDetach();
89 mNewTabsListener = null;
90 }
92 @Override
93 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
94 return inflater.inflate(R.layout.home_last_tabs_panel, container, false);
95 }
97 @Override
98 public void onViewCreated(View view, Bundle savedInstanceState) {
99 mTitle = (TextView) view.findViewById(R.id.title);
100 if (mTitle != null) {
101 mTitle.setText(R.string.home_last_tabs_title);
102 }
104 mList = (HomeListView) view.findViewById(R.id.list);
105 mList.setTag(HomePager.LIST_TAG_LAST_TABS);
107 mList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
108 @Override
109 public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
110 final Cursor c = mAdapter.getCursor();
111 if (c == null || !c.moveToPosition(position)) {
112 return;
113 }
115 Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL);
117 final String url = c.getString(c.getColumnIndexOrThrow(Combined.URL));
118 mNewTabsListener.onNewTabs(new String[] { url });
119 }
120 });
122 mList.setContextMenuInfoFactory(new HomeContextMenuInfo.Factory() {
123 @Override
124 public HomeContextMenuInfo makeInfoForCursor(View view, int position, long id, Cursor cursor) {
125 final HomeContextMenuInfo info = new HomeContextMenuInfo(view, position, id);
126 info.url = cursor.getString(cursor.getColumnIndexOrThrow(Combined.URL));
127 info.title = cursor.getString(cursor.getColumnIndexOrThrow(Combined.TITLE));
128 return info;
129 }
130 });
132 registerForContextMenu(mList);
134 mRestoreButton = view.findViewById(R.id.open_all_tabs_button);
135 mRestoreButton.setOnClickListener(new View.OnClickListener() {
136 @Override
137 public void onClick(View v) {
138 openAllTabs();
139 }
140 });
141 }
143 @Override
144 public void onDestroyView() {
145 super.onDestroyView();
146 mList = null;
147 mTitle = null;
148 mEmptyView = null;
149 mRestoreButton = null;
150 }
152 @Override
153 public void onActivityCreated(Bundle savedInstanceState) {
154 super.onActivityCreated(savedInstanceState);
156 // Intialize adapter
157 mAdapter = new LastTabsAdapter(getActivity());
158 mList.setAdapter(mAdapter);
160 // Create callbacks before the initial loader is started
161 mCursorLoaderCallbacks = new CursorLoaderCallbacks();
162 loadIfVisible();
163 }
165 private void updateUiFromCursor(Cursor c) {
166 if (c != null && c.getCount() > 0) {
167 if (mTitle != null) {
168 mTitle.setVisibility(View.VISIBLE);
169 }
170 mRestoreButton.setVisibility(View.VISIBLE);
171 return;
172 }
174 // Cursor is empty, so hide the title and set the
175 // empty view if it hasn't been set already.
176 if (mTitle != null) {
177 mTitle.setVisibility(View.GONE);
178 }
179 mRestoreButton.setVisibility(View.GONE);
181 if (mEmptyView == null) {
182 // Set empty panel view. We delay this so that the empty view won't flash.
183 final ViewStub emptyViewStub = (ViewStub) getView().findViewById(R.id.home_empty_view_stub);
184 mEmptyView = emptyViewStub.inflate();
186 final ImageView emptyIcon = (ImageView) mEmptyView.findViewById(R.id.home_empty_image);
187 emptyIcon.setImageResource(R.drawable.icon_last_tabs_empty);
189 final TextView emptyText = (TextView) mEmptyView.findViewById(R.id.home_empty_text);
190 emptyText.setText(R.string.home_last_tabs_empty);
192 mList.setEmptyView(mEmptyView);
193 }
194 }
196 @Override
197 protected void load() {
198 getLoaderManager().initLoader(LOADER_ID_LAST_TABS, null, mCursorLoaderCallbacks);
199 }
201 private void openAllTabs() {
202 final Cursor c = mAdapter.getCursor();
203 if (c == null || !c.moveToFirst()) {
204 return;
205 }
207 final String[] urls = new String[c.getCount()];
209 do {
210 urls[c.getPosition()] = c.getString(c.getColumnIndexOrThrow(Combined.URL));
211 } while (c.moveToNext());
213 Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.BUTTON);
215 mNewTabsListener.onNewTabs(urls);
216 }
218 private static class LastTabsCursorLoader extends SimpleCursorLoader {
219 public LastTabsCursorLoader(Context context) {
220 super(context);
221 }
223 @Override
224 public Cursor loadCursor() {
225 final Context context = getContext();
227 final String jsonString = GeckoProfile.get(context).readSessionFile(true);
228 if (jsonString == null) {
229 // No previous session data
230 return null;
231 }
233 final MatrixCursor c = new MatrixCursor(new String[] { Combined._ID,
234 Combined.URL,
235 Combined.TITLE });
237 new SessionParser() {
238 @Override
239 public void onTabRead(SessionTab tab) {
240 final String url = tab.getUrl();
242 // Don't show last tabs for about:home
243 if (AboutPages.isAboutHome(url)) {
244 return;
245 }
247 final RowBuilder row = c.newRow();
248 row.add(-1);
249 row.add(url);
251 final String title = tab.getTitle();
252 row.add(title);
253 }
254 }.parse(jsonString);
256 return c;
257 }
258 }
260 private static class LastTabsAdapter extends CursorAdapter {
261 public LastTabsAdapter(Context context) {
262 super(context, null, 0);
263 }
265 @Override
266 public void bindView(View view, Context context, Cursor cursor) {
267 ((TwoLinePageRow) view).updateFromCursor(cursor);
268 }
270 @Override
271 public View newView(Context context, Cursor cursor, ViewGroup parent) {
272 return LayoutInflater.from(context).inflate(R.layout.home_item_row, parent, false);
273 }
274 }
276 private class CursorLoaderCallbacks implements LoaderCallbacks<Cursor> {
277 @Override
278 public Loader<Cursor> onCreateLoader(int id, Bundle args) {
279 return new LastTabsCursorLoader(getActivity());
280 }
282 @Override
283 public void onLoadFinished(Loader<Cursor> loader, Cursor c) {
284 mAdapter.swapCursor(c);
285 updateUiFromCursor(c);
286 }
288 @Override
289 public void onLoaderReset(Loader<Cursor> loader) {
290 mAdapter.swapCursor(null);
291 }
292 }
293 }