mobile/android/base/home/TwoLinePageRow.java

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:a3931be7e847
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 java.lang.ref.WeakReference;
9
10 import org.mozilla.gecko.R;
11 import org.mozilla.gecko.Tab;
12 import org.mozilla.gecko.Tabs;
13 import org.mozilla.gecko.db.BrowserContract.Combined;
14 import org.mozilla.gecko.db.BrowserDB.URLColumns;
15 import org.mozilla.gecko.favicons.Favicons;
16 import org.mozilla.gecko.favicons.OnFaviconLoadedListener;
17 import org.mozilla.gecko.util.ThreadUtils;
18 import org.mozilla.gecko.widget.FaviconView;
19
20 import android.content.Context;
21 import android.database.Cursor;
22 import android.graphics.Bitmap;
23 import android.text.TextUtils;
24 import android.util.AttributeSet;
25 import android.view.Gravity;
26 import android.view.LayoutInflater;
27 import android.widget.LinearLayout;
28 import android.widget.TextView;
29
30 public class TwoLinePageRow extends LinearLayout
31 implements Tabs.OnTabsChangedListener {
32
33 protected static final int NO_ICON = 0;
34
35 private final TextView mTitle;
36 private final TextView mUrl;
37
38 private int mSwitchToTabIconId;
39 private int mPageTypeIconId;
40
41 private final FaviconView mFavicon;
42
43 private boolean mShowIcons;
44 private int mLoadFaviconJobId = Favicons.NOT_LOADING;
45
46 // Only holds a reference to the FaviconView itself, so if the row gets
47 // discarded while a task is outstanding, we'll leak less memory.
48 private static class UpdateViewFaviconLoadedListener implements OnFaviconLoadedListener {
49 private final WeakReference<FaviconView> view;
50 public UpdateViewFaviconLoadedListener(FaviconView view) {
51 this.view = new WeakReference<FaviconView>(view);
52 }
53
54 @Override
55 public void onFaviconLoaded(String url, String faviconURL, Bitmap favicon) {
56 FaviconView v = view.get();
57 if (v == null) {
58 // Guess we stuck around after the TwoLinePageRow went away.
59 return;
60 }
61
62 if (favicon == null) {
63 v.showDefaultFavicon();
64 return;
65 }
66
67 v.updateImage(favicon, faviconURL);
68 }
69 }
70
71 // Listener for handling Favicon loads.
72 private final OnFaviconLoadedListener mFaviconListener;
73
74 // The URL for the page corresponding to this view.
75 private String mPageUrl;
76
77 public TwoLinePageRow(Context context) {
78 this(context, null);
79 }
80
81 public TwoLinePageRow(Context context, AttributeSet attrs) {
82 super(context, attrs);
83
84 setGravity(Gravity.CENTER_VERTICAL);
85
86 LayoutInflater.from(context).inflate(R.layout.two_line_page_row, this);
87 mTitle = (TextView) findViewById(R.id.title);
88 mUrl = (TextView) findViewById(R.id.url);
89
90 mSwitchToTabIconId = NO_ICON;
91 mPageTypeIconId = NO_ICON;
92 mShowIcons = true;
93
94 mFavicon = (FaviconView) findViewById(R.id.icon);
95 mFaviconListener = new UpdateViewFaviconLoadedListener(mFavicon);
96 }
97
98 @Override
99 protected void onAttachedToWindow() {
100 Tabs.registerOnTabsChangedListener(this);
101 }
102
103 @Override
104 protected void onDetachedFromWindow() {
105 // Tabs' listener array is safe to modify during use: its
106 // iteration pattern is based on snapshots.
107 Tabs.unregisterOnTabsChangedListener(this);
108 }
109
110 @Override
111 public void onTabChanged(final Tab tab, final Tabs.TabEvents msg, final Object data) {
112 switch(msg) {
113 case ADDED:
114 case CLOSED:
115 case LOCATION_CHANGE:
116 updateDisplayedUrl();
117 break;
118 }
119 }
120
121 private void setTitle(String text) {
122 mTitle.setText(text);
123 }
124
125 protected void setUrl(String text) {
126 mUrl.setText(text);
127 }
128
129 protected void setUrl(int stringId) {
130 mUrl.setText(stringId);
131 }
132
133 protected String getUrl() {
134 return mPageUrl;
135 }
136
137 protected void setSwitchToTabIcon(int iconId) {
138 if (mSwitchToTabIconId == iconId) {
139 return;
140 }
141
142 mSwitchToTabIconId = iconId;
143 mUrl.setCompoundDrawablesWithIntrinsicBounds(mSwitchToTabIconId, 0, mPageTypeIconId, 0);
144 }
145
146 private void setPageTypeIcon(int iconId) {
147 if (mPageTypeIconId == iconId) {
148 return;
149 }
150
151 mPageTypeIconId = iconId;
152 mUrl.setCompoundDrawablesWithIntrinsicBounds(mSwitchToTabIconId, 0, mPageTypeIconId, 0);
153 }
154
155 /**
156 * Stores the page URL, so that we can use it to replace "Switch to tab" if the open
157 * tab changes or is closed.
158 */
159 private void updateDisplayedUrl(String url) {
160 mPageUrl = url;
161 updateDisplayedUrl();
162 }
163
164 /**
165 * Replaces the page URL with "Switch to tab" if there is already a tab open with that URL.
166 * Only looks for tabs that are either private or non-private, depending on the current
167 * selected tab.
168 */
169 protected void updateDisplayedUrl() {
170 boolean isPrivate = Tabs.getInstance().getSelectedTab().isPrivate();
171 Tab tab = Tabs.getInstance().getFirstTabForUrl(mPageUrl, isPrivate);
172 if (!mShowIcons || tab == null) {
173 setUrl(mPageUrl);
174 setSwitchToTabIcon(NO_ICON);
175 } else {
176 setUrl(R.string.switch_to_tab);
177 setSwitchToTabIcon(R.drawable.ic_url_bar_tab);
178 }
179 }
180
181 public void setShowIcons(boolean showIcons) {
182 mShowIcons = showIcons;
183 }
184
185 public void updateFromCursor(Cursor cursor) {
186 if (cursor == null) {
187 return;
188 }
189
190 int titleIndex = cursor.getColumnIndexOrThrow(URLColumns.TITLE);
191 final String title = cursor.getString(titleIndex);
192
193 int urlIndex = cursor.getColumnIndexOrThrow(URLColumns.URL);
194 final String url = cursor.getString(urlIndex);
195
196 if (mShowIcons) {
197 final int bookmarkIdIndex = cursor.getColumnIndex(Combined.BOOKMARK_ID);
198 if (bookmarkIdIndex != -1) {
199 final long bookmarkId = cursor.getLong(bookmarkIdIndex);
200 final int displayIndex = cursor.getColumnIndex(Combined.DISPLAY);
201
202 final int display;
203 if (displayIndex != -1) {
204 display = cursor.getInt(displayIndex);
205 } else {
206 display = Combined.DISPLAY_NORMAL;
207 }
208
209 // The bookmark id will be 0 (null in database) when the url
210 // is not a bookmark.
211 if (bookmarkId == 0) {
212 setPageTypeIcon(NO_ICON);
213 } else if (display == Combined.DISPLAY_READER) {
214 setPageTypeIcon(R.drawable.ic_url_bar_reader);
215 } else {
216 setPageTypeIcon(R.drawable.ic_url_bar_star);
217 }
218 } else {
219 setPageTypeIcon(NO_ICON);
220 }
221 }
222
223 // Use the URL instead of an empty title for consistency with the normal URL
224 // bar view - this is the equivalent of getDisplayTitle() in Tab.java
225 setTitle(TextUtils.isEmpty(title) ? url : title);
226
227 // No point updating the below things if URL has not changed. Prevents evil Favicon flicker.
228 if (url.equals(mPageUrl)) {
229 return;
230 }
231
232 // Blank the Favicon, so we don't show the wrong Favicon if we scroll and miss DB.
233 mFavicon.clearImage();
234 mLoadFaviconJobId = Favicons.getSizedFaviconForPageFromLocal(url, mFaviconListener);
235
236 updateDisplayedUrl(url);
237 }
238 }

mercurial