1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mobile/android/base/home/TwoLinePageRow.java Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,238 @@ 1.4 +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +package org.mozilla.gecko.home; 1.10 + 1.11 +import java.lang.ref.WeakReference; 1.12 + 1.13 +import org.mozilla.gecko.R; 1.14 +import org.mozilla.gecko.Tab; 1.15 +import org.mozilla.gecko.Tabs; 1.16 +import org.mozilla.gecko.db.BrowserContract.Combined; 1.17 +import org.mozilla.gecko.db.BrowserDB.URLColumns; 1.18 +import org.mozilla.gecko.favicons.Favicons; 1.19 +import org.mozilla.gecko.favicons.OnFaviconLoadedListener; 1.20 +import org.mozilla.gecko.util.ThreadUtils; 1.21 +import org.mozilla.gecko.widget.FaviconView; 1.22 + 1.23 +import android.content.Context; 1.24 +import android.database.Cursor; 1.25 +import android.graphics.Bitmap; 1.26 +import android.text.TextUtils; 1.27 +import android.util.AttributeSet; 1.28 +import android.view.Gravity; 1.29 +import android.view.LayoutInflater; 1.30 +import android.widget.LinearLayout; 1.31 +import android.widget.TextView; 1.32 + 1.33 +public class TwoLinePageRow extends LinearLayout 1.34 + implements Tabs.OnTabsChangedListener { 1.35 + 1.36 + protected static final int NO_ICON = 0; 1.37 + 1.38 + private final TextView mTitle; 1.39 + private final TextView mUrl; 1.40 + 1.41 + private int mSwitchToTabIconId; 1.42 + private int mPageTypeIconId; 1.43 + 1.44 + private final FaviconView mFavicon; 1.45 + 1.46 + private boolean mShowIcons; 1.47 + private int mLoadFaviconJobId = Favicons.NOT_LOADING; 1.48 + 1.49 + // Only holds a reference to the FaviconView itself, so if the row gets 1.50 + // discarded while a task is outstanding, we'll leak less memory. 1.51 + private static class UpdateViewFaviconLoadedListener implements OnFaviconLoadedListener { 1.52 + private final WeakReference<FaviconView> view; 1.53 + public UpdateViewFaviconLoadedListener(FaviconView view) { 1.54 + this.view = new WeakReference<FaviconView>(view); 1.55 + } 1.56 + 1.57 + @Override 1.58 + public void onFaviconLoaded(String url, String faviconURL, Bitmap favicon) { 1.59 + FaviconView v = view.get(); 1.60 + if (v == null) { 1.61 + // Guess we stuck around after the TwoLinePageRow went away. 1.62 + return; 1.63 + } 1.64 + 1.65 + if (favicon == null) { 1.66 + v.showDefaultFavicon(); 1.67 + return; 1.68 + } 1.69 + 1.70 + v.updateImage(favicon, faviconURL); 1.71 + } 1.72 + } 1.73 + 1.74 + // Listener for handling Favicon loads. 1.75 + private final OnFaviconLoadedListener mFaviconListener; 1.76 + 1.77 + // The URL for the page corresponding to this view. 1.78 + private String mPageUrl; 1.79 + 1.80 + public TwoLinePageRow(Context context) { 1.81 + this(context, null); 1.82 + } 1.83 + 1.84 + public TwoLinePageRow(Context context, AttributeSet attrs) { 1.85 + super(context, attrs); 1.86 + 1.87 + setGravity(Gravity.CENTER_VERTICAL); 1.88 + 1.89 + LayoutInflater.from(context).inflate(R.layout.two_line_page_row, this); 1.90 + mTitle = (TextView) findViewById(R.id.title); 1.91 + mUrl = (TextView) findViewById(R.id.url); 1.92 + 1.93 + mSwitchToTabIconId = NO_ICON; 1.94 + mPageTypeIconId = NO_ICON; 1.95 + mShowIcons = true; 1.96 + 1.97 + mFavicon = (FaviconView) findViewById(R.id.icon); 1.98 + mFaviconListener = new UpdateViewFaviconLoadedListener(mFavicon); 1.99 + } 1.100 + 1.101 + @Override 1.102 + protected void onAttachedToWindow() { 1.103 + Tabs.registerOnTabsChangedListener(this); 1.104 + } 1.105 + 1.106 + @Override 1.107 + protected void onDetachedFromWindow() { 1.108 + // Tabs' listener array is safe to modify during use: its 1.109 + // iteration pattern is based on snapshots. 1.110 + Tabs.unregisterOnTabsChangedListener(this); 1.111 + } 1.112 + 1.113 + @Override 1.114 + public void onTabChanged(final Tab tab, final Tabs.TabEvents msg, final Object data) { 1.115 + switch(msg) { 1.116 + case ADDED: 1.117 + case CLOSED: 1.118 + case LOCATION_CHANGE: 1.119 + updateDisplayedUrl(); 1.120 + break; 1.121 + } 1.122 + } 1.123 + 1.124 + private void setTitle(String text) { 1.125 + mTitle.setText(text); 1.126 + } 1.127 + 1.128 + protected void setUrl(String text) { 1.129 + mUrl.setText(text); 1.130 + } 1.131 + 1.132 + protected void setUrl(int stringId) { 1.133 + mUrl.setText(stringId); 1.134 + } 1.135 + 1.136 + protected String getUrl() { 1.137 + return mPageUrl; 1.138 + } 1.139 + 1.140 + protected void setSwitchToTabIcon(int iconId) { 1.141 + if (mSwitchToTabIconId == iconId) { 1.142 + return; 1.143 + } 1.144 + 1.145 + mSwitchToTabIconId = iconId; 1.146 + mUrl.setCompoundDrawablesWithIntrinsicBounds(mSwitchToTabIconId, 0, mPageTypeIconId, 0); 1.147 + } 1.148 + 1.149 + private void setPageTypeIcon(int iconId) { 1.150 + if (mPageTypeIconId == iconId) { 1.151 + return; 1.152 + } 1.153 + 1.154 + mPageTypeIconId = iconId; 1.155 + mUrl.setCompoundDrawablesWithIntrinsicBounds(mSwitchToTabIconId, 0, mPageTypeIconId, 0); 1.156 + } 1.157 + 1.158 + /** 1.159 + * Stores the page URL, so that we can use it to replace "Switch to tab" if the open 1.160 + * tab changes or is closed. 1.161 + */ 1.162 + private void updateDisplayedUrl(String url) { 1.163 + mPageUrl = url; 1.164 + updateDisplayedUrl(); 1.165 + } 1.166 + 1.167 + /** 1.168 + * Replaces the page URL with "Switch to tab" if there is already a tab open with that URL. 1.169 + * Only looks for tabs that are either private or non-private, depending on the current 1.170 + * selected tab. 1.171 + */ 1.172 + protected void updateDisplayedUrl() { 1.173 + boolean isPrivate = Tabs.getInstance().getSelectedTab().isPrivate(); 1.174 + Tab tab = Tabs.getInstance().getFirstTabForUrl(mPageUrl, isPrivate); 1.175 + if (!mShowIcons || tab == null) { 1.176 + setUrl(mPageUrl); 1.177 + setSwitchToTabIcon(NO_ICON); 1.178 + } else { 1.179 + setUrl(R.string.switch_to_tab); 1.180 + setSwitchToTabIcon(R.drawable.ic_url_bar_tab); 1.181 + } 1.182 + } 1.183 + 1.184 + public void setShowIcons(boolean showIcons) { 1.185 + mShowIcons = showIcons; 1.186 + } 1.187 + 1.188 + public void updateFromCursor(Cursor cursor) { 1.189 + if (cursor == null) { 1.190 + return; 1.191 + } 1.192 + 1.193 + int titleIndex = cursor.getColumnIndexOrThrow(URLColumns.TITLE); 1.194 + final String title = cursor.getString(titleIndex); 1.195 + 1.196 + int urlIndex = cursor.getColumnIndexOrThrow(URLColumns.URL); 1.197 + final String url = cursor.getString(urlIndex); 1.198 + 1.199 + if (mShowIcons) { 1.200 + final int bookmarkIdIndex = cursor.getColumnIndex(Combined.BOOKMARK_ID); 1.201 + if (bookmarkIdIndex != -1) { 1.202 + final long bookmarkId = cursor.getLong(bookmarkIdIndex); 1.203 + final int displayIndex = cursor.getColumnIndex(Combined.DISPLAY); 1.204 + 1.205 + final int display; 1.206 + if (displayIndex != -1) { 1.207 + display = cursor.getInt(displayIndex); 1.208 + } else { 1.209 + display = Combined.DISPLAY_NORMAL; 1.210 + } 1.211 + 1.212 + // The bookmark id will be 0 (null in database) when the url 1.213 + // is not a bookmark. 1.214 + if (bookmarkId == 0) { 1.215 + setPageTypeIcon(NO_ICON); 1.216 + } else if (display == Combined.DISPLAY_READER) { 1.217 + setPageTypeIcon(R.drawable.ic_url_bar_reader); 1.218 + } else { 1.219 + setPageTypeIcon(R.drawable.ic_url_bar_star); 1.220 + } 1.221 + } else { 1.222 + setPageTypeIcon(NO_ICON); 1.223 + } 1.224 + } 1.225 + 1.226 + // Use the URL instead of an empty title for consistency with the normal URL 1.227 + // bar view - this is the equivalent of getDisplayTitle() in Tab.java 1.228 + setTitle(TextUtils.isEmpty(title) ? url : title); 1.229 + 1.230 + // No point updating the below things if URL has not changed. Prevents evil Favicon flicker. 1.231 + if (url.equals(mPageUrl)) { 1.232 + return; 1.233 + } 1.234 + 1.235 + // Blank the Favicon, so we don't show the wrong Favicon if we scroll and miss DB. 1.236 + mFavicon.clearImage(); 1.237 + mLoadFaviconJobId = Favicons.getSizedFaviconForPageFromLocal(url, mFaviconListener); 1.238 + 1.239 + updateDisplayedUrl(url); 1.240 + } 1.241 +}