|
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/. */ |
|
5 |
|
6 package org.mozilla.gecko.home; |
|
7 |
|
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; |
|
16 |
|
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; |
|
33 |
|
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"; |
|
40 |
|
41 // Cursor loader ID for the session parser |
|
42 private static final int LOADER_ID_LAST_TABS = 0; |
|
43 |
|
44 // Adapter for the list of search results |
|
45 private LastTabsAdapter mAdapter; |
|
46 |
|
47 // The view shown by the fragment. |
|
48 private HomeListView mList; |
|
49 |
|
50 // The title for this HomeFragment panel. |
|
51 private TextView mTitle; |
|
52 |
|
53 // The button view for restoring tabs from last session. |
|
54 private View mRestoreButton; |
|
55 |
|
56 // Reference to the View to display when there are no results. |
|
57 private View mEmptyView; |
|
58 |
|
59 // Callbacks used for the search and favicon cursor loaders |
|
60 private CursorLoaderCallbacks mCursorLoaderCallbacks; |
|
61 |
|
62 // On new tabs listener |
|
63 private OnNewTabsListener mNewTabsListener; |
|
64 |
|
65 public static LastTabsPanel newInstance() { |
|
66 return new LastTabsPanel(); |
|
67 } |
|
68 |
|
69 public LastTabsPanel() { |
|
70 mNewTabsListener = null; |
|
71 } |
|
72 |
|
73 @Override |
|
74 public void onAttach(Activity activity) { |
|
75 super.onAttach(activity); |
|
76 |
|
77 try { |
|
78 mNewTabsListener = (OnNewTabsListener) activity; |
|
79 } catch (ClassCastException e) { |
|
80 throw new ClassCastException(activity.toString() |
|
81 + " must implement HomePager.OnNewTabsListener"); |
|
82 } |
|
83 } |
|
84 |
|
85 @Override |
|
86 public void onDetach() { |
|
87 super.onDetach(); |
|
88 |
|
89 mNewTabsListener = null; |
|
90 } |
|
91 |
|
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 } |
|
96 |
|
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 } |
|
103 |
|
104 mList = (HomeListView) view.findViewById(R.id.list); |
|
105 mList.setTag(HomePager.LIST_TAG_LAST_TABS); |
|
106 |
|
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 } |
|
114 |
|
115 Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL); |
|
116 |
|
117 final String url = c.getString(c.getColumnIndexOrThrow(Combined.URL)); |
|
118 mNewTabsListener.onNewTabs(new String[] { url }); |
|
119 } |
|
120 }); |
|
121 |
|
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 }); |
|
131 |
|
132 registerForContextMenu(mList); |
|
133 |
|
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 } |
|
142 |
|
143 @Override |
|
144 public void onDestroyView() { |
|
145 super.onDestroyView(); |
|
146 mList = null; |
|
147 mTitle = null; |
|
148 mEmptyView = null; |
|
149 mRestoreButton = null; |
|
150 } |
|
151 |
|
152 @Override |
|
153 public void onActivityCreated(Bundle savedInstanceState) { |
|
154 super.onActivityCreated(savedInstanceState); |
|
155 |
|
156 // Intialize adapter |
|
157 mAdapter = new LastTabsAdapter(getActivity()); |
|
158 mList.setAdapter(mAdapter); |
|
159 |
|
160 // Create callbacks before the initial loader is started |
|
161 mCursorLoaderCallbacks = new CursorLoaderCallbacks(); |
|
162 loadIfVisible(); |
|
163 } |
|
164 |
|
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 } |
|
173 |
|
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); |
|
180 |
|
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(); |
|
185 |
|
186 final ImageView emptyIcon = (ImageView) mEmptyView.findViewById(R.id.home_empty_image); |
|
187 emptyIcon.setImageResource(R.drawable.icon_last_tabs_empty); |
|
188 |
|
189 final TextView emptyText = (TextView) mEmptyView.findViewById(R.id.home_empty_text); |
|
190 emptyText.setText(R.string.home_last_tabs_empty); |
|
191 |
|
192 mList.setEmptyView(mEmptyView); |
|
193 } |
|
194 } |
|
195 |
|
196 @Override |
|
197 protected void load() { |
|
198 getLoaderManager().initLoader(LOADER_ID_LAST_TABS, null, mCursorLoaderCallbacks); |
|
199 } |
|
200 |
|
201 private void openAllTabs() { |
|
202 final Cursor c = mAdapter.getCursor(); |
|
203 if (c == null || !c.moveToFirst()) { |
|
204 return; |
|
205 } |
|
206 |
|
207 final String[] urls = new String[c.getCount()]; |
|
208 |
|
209 do { |
|
210 urls[c.getPosition()] = c.getString(c.getColumnIndexOrThrow(Combined.URL)); |
|
211 } while (c.moveToNext()); |
|
212 |
|
213 Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.BUTTON); |
|
214 |
|
215 mNewTabsListener.onNewTabs(urls); |
|
216 } |
|
217 |
|
218 private static class LastTabsCursorLoader extends SimpleCursorLoader { |
|
219 public LastTabsCursorLoader(Context context) { |
|
220 super(context); |
|
221 } |
|
222 |
|
223 @Override |
|
224 public Cursor loadCursor() { |
|
225 final Context context = getContext(); |
|
226 |
|
227 final String jsonString = GeckoProfile.get(context).readSessionFile(true); |
|
228 if (jsonString == null) { |
|
229 // No previous session data |
|
230 return null; |
|
231 } |
|
232 |
|
233 final MatrixCursor c = new MatrixCursor(new String[] { Combined._ID, |
|
234 Combined.URL, |
|
235 Combined.TITLE }); |
|
236 |
|
237 new SessionParser() { |
|
238 @Override |
|
239 public void onTabRead(SessionTab tab) { |
|
240 final String url = tab.getUrl(); |
|
241 |
|
242 // Don't show last tabs for about:home |
|
243 if (AboutPages.isAboutHome(url)) { |
|
244 return; |
|
245 } |
|
246 |
|
247 final RowBuilder row = c.newRow(); |
|
248 row.add(-1); |
|
249 row.add(url); |
|
250 |
|
251 final String title = tab.getTitle(); |
|
252 row.add(title); |
|
253 } |
|
254 }.parse(jsonString); |
|
255 |
|
256 return c; |
|
257 } |
|
258 } |
|
259 |
|
260 private static class LastTabsAdapter extends CursorAdapter { |
|
261 public LastTabsAdapter(Context context) { |
|
262 super(context, null, 0); |
|
263 } |
|
264 |
|
265 @Override |
|
266 public void bindView(View view, Context context, Cursor cursor) { |
|
267 ((TwoLinePageRow) view).updateFromCursor(cursor); |
|
268 } |
|
269 |
|
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 } |
|
275 |
|
276 private class CursorLoaderCallbacks implements LoaderCallbacks<Cursor> { |
|
277 @Override |
|
278 public Loader<Cursor> onCreateLoader(int id, Bundle args) { |
|
279 return new LastTabsCursorLoader(getActivity()); |
|
280 } |
|
281 |
|
282 @Override |
|
283 public void onLoadFinished(Loader<Cursor> loader, Cursor c) { |
|
284 mAdapter.swapCursor(c); |
|
285 updateUiFromCursor(c); |
|
286 } |
|
287 |
|
288 @Override |
|
289 public void onLoaderReset(Loader<Cursor> loader) { |
|
290 mAdapter.swapCursor(null); |
|
291 } |
|
292 } |
|
293 } |