Bug 882365: Add a top bookmarks section grid view. [r=lucasr]

This commit is contained in:
Sriram Ramasubramanian 2013-06-20 11:45:58 -07:00
parent 6409b968e3
commit 75f710e68e
17 changed files with 794 additions and 0 deletions

View File

@ -6,6 +6,7 @@ package org.mozilla.gecko;
import org.mozilla.gecko.gfx.LayerView;
import org.mozilla.gecko.home.BookmarkFolderView;
import org.mozilla.gecko.home.BookmarkThumbnailView;
import org.mozilla.gecko.home.BookmarksListView;
import org.mozilla.gecko.home.FadedTextView;
import org.mozilla.gecko.home.TwoLinePageRow;
@ -90,6 +91,7 @@ public final class GeckoViewsFactory implements LayoutInflater.Factory {
mFactoryMap.put("TextView", GeckoTextView.class.getConstructor(arg1Class, arg2Class));
mFactoryMap.put("FaviconView", FaviconView.class.getConstructor(arg1Class, arg2Class));
mFactoryMap.put("home.BookmarkFolderView", BookmarkFolderView.class.getConstructor(arg1Class, arg2Class));
mFactoryMap.put("home.BookmarkThumbnailView", BookmarkThumbnailView.class.getConstructor(arg1Class, arg2Class));
mFactoryMap.put("home.BookmarksListView", BookmarksListView.class.getConstructor(arg1Class, arg2Class));
mFactoryMap.put("home.FadedTextView", FadedTextView.class.getConstructor(arg1Class, arg2Class));
mFactoryMap.put("home.TwoLinePageRow", TwoLinePageRow.class.getConstructor(arg1Class, arg2Class));

View File

@ -216,11 +216,14 @@ FENNEC_JAVA_FILES = \
home/BookmarksListView.java \
home/BookmarksPage.java \
home/BookmarkFolderView.java \
home/BookmarkThumbnailView.java \
home/HomeFragment.java \
home/HomeListView.java \
home/HomePager.java \
home/HomePagerTabStrip.java \
home/FadedTextView.java \
home/TopBookmarkItemView.java \
home/TopBookmarksView.java \
home/TwoLinePageRow.java \
menu/GeckoMenu.java \
menu/GeckoMenuInflater.java \
@ -464,6 +467,7 @@ RES_LAYOUT = \
res/layout/tabs_item_cell.xml \
res/layout/tabs_item_row.xml \
res/layout/text_selection_handles.xml \
res/layout/top_bookmark_item_view.xml \
res/layout/two_line_page_row.xml \
res/layout/list_item_header.xml \
res/layout/select_dialog_list.xml \
@ -982,6 +986,7 @@ RES_COLOR = \
res/color/select_item_multichoice.xml \
res/color/tertiary_text.xml \
res/color/tertiary_text_inverse.xml \
res/color/top_bookmark_item_title.xml \
res/color/url_bar_title.xml \
res/color/url_bar_title_hint.xml \
$(NULL)

View File

@ -0,0 +1,71 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.home;
import org.mozilla.gecko.R;
import org.mozilla.gecko.ThumbnailHelper;
import android.content.Context;
import android.graphics.PorterDuff.Mode;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;
/**
* A height constrained ImageView to show thumbnails of top bookmarks.
*/
public class BookmarkThumbnailView extends ImageView {
private static final String LOGTAG = "GeckoBookmarkThumbnailView";
// 27.34% opacity filter for the dominant color.
private static final int COLOR_FILTER = 0x46FFFFFF;
// Default filter color for "Add a bookmark" views.
private static final int DEFAULT_COLOR = 0x46ECF0F3;
public BookmarkThumbnailView(Context context) {
this(context, null);
}
public BookmarkThumbnailView(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.bookmarkThumbnailViewStyle);
}
public BookmarkThumbnailView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
/**
* Measure the view to determine the measured width and height.
* The height is constrained by the measured width.
*
* @param widthMeasureSpec horizontal space requirements as imposed by the parent.
* @param heightMeasureSpec vertical space requirements as imposed by the parent, but ignored.
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Default measuring.
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// Force the height based on the aspect ratio.
final int width = getMeasuredWidth();
final int height = (int) (width * ThumbnailHelper.THUMBNAIL_ASPECT_RATIO);
setMeasuredDimension(width, height);
}
/**
* Sets the background to a Drawable by applying the specified color as a filter.
*
* @param color the color filter to apply over the drawable.
*/
@Override
public void setBackgroundColor(int color) {
int colorFilter = color == 0 ? DEFAULT_COLOR : color & COLOR_FILTER;
Drawable drawable = getResources().getDrawable(R.drawable.favicon_bg);
drawable.setColorFilter(colorFilter, Mode.SRC_ATOP);
setBackgroundDrawable(drawable);
}
}

View File

@ -0,0 +1,221 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.home;
import org.mozilla.gecko.Favicons;
import org.mozilla.gecko.R;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.PathShape;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
/**
* A view that displays the thumbnail and the title/url for a bookmark.
* If the title/url is longer than the width of the view, they are faded out.
* If there is no valid url, a default string is shown at 50% opacity.
* This is denoted by the empty state.
*/
public class TopBookmarkItemView extends RelativeLayout {
private static final String LOGTAG = "GeckoTopBookmarkItemView";
// Empty state, to denote there is no valid url.
private static final int[] STATE_EMPTY = { android.R.attr.state_empty };
// A Pin Drawable to denote pinned sites.
private static Drawable sPinDrawable = null;
// Child views.
private final TextView mTitleView;
private final ImageView mThumbnailView;
private final ImageView mPinView;
// Data backing this view.
private String mTitle;
private String mUrl;
// Pinned state.
private boolean mIsPinned = false;
// Empty state.
private boolean mIsEmpty = true;
public TopBookmarkItemView(Context context) {
this(context, null);
}
public TopBookmarkItemView(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.topBookmarkItemViewStyle);
}
public TopBookmarkItemView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
LayoutInflater.from(context).inflate(R.layout.top_bookmark_item_view, this);
mTitleView = (TextView) findViewById(R.id.title);
mThumbnailView = (ImageView) findViewById(R.id.thumbnail);
mPinView = (ImageView) findViewById(R.id.pin);
}
/**
* {@inheritDoc}
*/
@Override
public int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
if (mIsEmpty) {
mergeDrawableStates(drawableState, STATE_EMPTY);
}
return drawableState;
}
/**
* @return The title shown by this view.
*/
public String getTitle() {
return (!TextUtils.isEmpty(mTitle) ? mTitle : mUrl);
}
/**
* @return The url shown by this view.
*/
public String getUrl() {
return mUrl;
}
/**
* @return true, if this view is pinned, false otherwise.
*/
public boolean isPinned() {
return mIsPinned;
}
/**
* @param title The title for this view.
*/
public void setTitle(String title) {
if (mTitle != null && mTitle.equals(title)) {
return;
}
mTitle = title;
updateTitleView();
}
/**
* @param url The url for this view.
*/
public void setUrl(String url) {
if (mUrl != null && mUrl.equals(url)) {
return;
}
mUrl = url;
updateTitleView();
}
/**
* @param pinned The pinned state of this view.
*/
public void setPinned(boolean pinned) {
mIsPinned = pinned;
mPinView.setBackgroundDrawable(pinned ? getPinDrawable() : null);
}
/**
* Display the thumbnail from a resource.
*
* @param resId Resource ID of the drawable to show.
*/
public void displayThumbnail(int resId) {
mThumbnailView.setImageResource(resId);
mThumbnailView.setBackgroundColor(0x0);
}
/**
* Display the thumbnail from a bitmap.
*
* @param thumbnail The bitmap to show as thumbnail.
*/
public void displayThumbnail(Bitmap thumbnail) {
if (thumbnail == null) {
// Show a favicon based view instead.
displayThumbnail(R.drawable.favicon);
return;
}
mThumbnailView.setImageBitmap(thumbnail);
mThumbnailView.setBackgroundDrawable(null);
}
/**
* Display the thumbnail from a favicon.
*
* @param favicon The favicon to show as thumbnail.
*/
public void displayFavicon(Bitmap favicon) {
if (favicon == null) {
// Should show default favicon.
displayThumbnail(R.drawable.favicon);
return;
}
mThumbnailView.setImageBitmap(favicon);
mThumbnailView.setBackgroundColor(Favicons.getInstance().getFaviconColor(favicon, mUrl));
}
/**
* Update the title shown by this view. If both title and url
* are empty, mark the state as STATE_EMPTY and show a default text.
*/
private void updateTitleView() {
String title = getTitle();
if (!TextUtils.isEmpty(title)) {
mTitleView.setText(title);
mIsEmpty = false;
} else {
mTitleView.setText(R.string.bookmark_add);
mIsEmpty = true;
}
// Refresh for state change.
refreshDrawableState();
}
/**
* @return Drawable to be used as a pin.
*/
private Drawable getPinDrawable() {
if (sPinDrawable == null) {
int size = getResources().getDimensionPixelSize(R.dimen.abouthome_topsite_pinsize);
// Draw a little triangle in the upper right corner.
Path path = new Path();
path.moveTo(0, 0);
path.lineTo(size, 0);
path.lineTo(size, size);
path.close();
sPinDrawable = new ShapeDrawable(new PathShape(path, size, size));
Paint p = ((ShapeDrawable) sPinDrawable).getPaint();
p.setColor(getResources().getColor(R.color.abouthome_topsite_pin));
}
return sPinDrawable;
}
}

View File

@ -0,0 +1,384 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.home;
import org.mozilla.gecko.R;
import org.mozilla.gecko.ThumbnailHelper;
import org.mozilla.gecko.db.BrowserContract.Thumbnails;
import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.db.BrowserDB.TopSitesCursorWrapper;
import org.mozilla.gecko.db.BrowserDB.URLColumns;
import org.mozilla.gecko.gfx.BitmapUtils;
import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.util.UiAsyncTask;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.CursorAdapter;
import android.widget.GridView;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* A grid view of top bookmarks and pinned tabs.
* Each cell in the grid is a TopBookmarkItemView.
*/
public class TopBookmarksView extends GridView {
private static final String LOGTAG = "GeckoTopBookmarksView";
// Max number of bookmarks that needs to be shown.
private int mMaxBookmarks;
// Number of columns to show.
private int mNumColumns;
// On URL open listener.
private OnUrlOpenListener mUrlOpenListener;
// A cursor based adapter backing this view.
protected TopBookmarksAdapter mAdapter;
// Temporary cache to store the thumbnails until the next layout pass.
private Map<String, Bitmap> mThumbnailsCache;
public TopBookmarksView(Context context) {
this(context, null);
}
public TopBookmarksView(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.topBookmarksViewStyle);
}
public TopBookmarksView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mMaxBookmarks = getResources().getInteger(R.integer.number_of_top_sites);
mNumColumns = getResources().getInteger(R.integer.number_of_top_sites_cols);
setNumColumns(mNumColumns);
}
/**
* {@inheritDoc}
*/
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
// Initialize the adapter.
mAdapter = new TopBookmarksAdapter(getContext(), null);
setAdapter(mAdapter);
setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
TopBookmarkItemView row = (TopBookmarkItemView) view;
String url = row.getUrl();
if (mUrlOpenListener != null && !TextUtils.isEmpty(url)) {
mUrlOpenListener.onUrlOpen(url);
}
}
});
// Load the bookmarks.
new LoadBookmarksTask().execute();
}
/**
* {@inheritDoc}
*/
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mAdapter != null) {
setAdapter(null);
final Cursor cursor = mAdapter.getCursor();
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
if (cursor != null && !cursor.isClosed())
cursor.close();
}
});
}
}
/**
* {@inheritDoc}
*/
@Override
public int getColumnWidth() {
// This method will be called from onMeasure() too.
// It's better to use getMeasuredWidth(), as it is safe in this case.
return (getMeasuredWidth() - getPaddingLeft() - getPaddingRight()) / mNumColumns;
}
/**
* {@inheritDoc}
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Sets the padding for this view.
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
final int measuredWidth = getMeasuredWidth();
final int childWidth = getColumnWidth();
int childHeight = 0;
// Set the column width as the thumbnail width.
ThumbnailHelper.getInstance().setThumbnailWidth(childWidth);
// If there's an adapter, use it to calculate the height of this view.
final TopBookmarksAdapter adapter = (TopBookmarksAdapter) getAdapter();
final int count = (adapter == null ? 0 : adapter.getCount());
if (adapter != null && count > 0) {
// Get the first child from the adapter.
final View child = adapter.getView(0, null, this);
if (child != null) {
// Set a default LayoutParams on the child, if it doesn't have one on its own.
AbsListView.LayoutParams params = (AbsListView.LayoutParams) child.getLayoutParams();
if (params == null) {
params = new AbsListView.LayoutParams(AbsListView.LayoutParams.WRAP_CONTENT,
AbsListView.LayoutParams.WRAP_CONTENT);
child.setLayoutParams(params);
}
// Measure the exact width of the child, and the height based on the width.
// Note: the child (and BookmarkThumbnailView) takes care of calculating its height.
int childWidthSpec = MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY);
int childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
child.measure(childWidthSpec, childHeightSpec);
childHeight = child.getMeasuredHeight();
}
}
// Find the minimum of bookmarks we need to show, and the one given by the cursor.
final int total = Math.min(count > 0 ? count : Integer.MAX_VALUE, mMaxBookmarks);
// Number of rows required to show these bookmarks.
final int rows = (int) Math.ceil((double) total / mNumColumns);
final int childrenHeight = childHeight * rows;
// Total height of this view.
final int measuredHeight = childrenHeight + getPaddingTop() + getPaddingBottom();
setMeasuredDimension(measuredWidth, measuredHeight);
}
/**
* {@inheritDoc}
*/
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
// If there are thumnails in the cache, update them.
if (mThumbnailsCache != null) {
updateThumbnails(mThumbnailsCache);
mThumbnailsCache = null;
}
}
/**
* Set an url open listener to be used by this view.
*
* @param listener An url open listener for this view.
*/
public void setOnUrlOpenListener(OnUrlOpenListener listener) {
mUrlOpenListener = listener;
}
/**
* Update the thumbnails returned by the db.
*
* @param thumbnails A map of urls and their thumbnail bitmaps.
*/
private void updateThumbnails(Map<String, Bitmap> thumbnails) {
final int count = mAdapter.getCount();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
// The grid view might get temporarily out of sync with the
// adapter refreshes (e.g. on device rotation).
if (child == null) {
continue;
}
TopBookmarkItemView view = (TopBookmarkItemView) child;
final String url = view.getUrl();
// If there is no url, then show "add bookmark".
if (TextUtils.isEmpty(url)) {
view.displayThumbnail(R.drawable.abouthome_thumbnail_add);
} else {
// Show the thumbnail.
Bitmap bitmap = (thumbnails != null ? thumbnails.get(url) : null);
view.displayThumbnail(bitmap);
}
}
}
/**
* A cursor adapter holding the pinned and top bookmarks.
*/
public class TopBookmarksAdapter extends CursorAdapter {
public TopBookmarksAdapter(Context context, Cursor cursor) {
super(context, cursor);
}
/**
* {@inheritDoc}
*/
@Override
public int getCount() {
return Math.min(super.getCount(), mMaxBookmarks);
}
/**
* {@inheritDoc}
*/
@Override
protected void onContentChanged () {
// Don't do anything. We don't want to regenerate every time
// our database is updated.
return;
}
/**
* {@inheritDoc}
*/
@Override
public void bindView(View bindView, Context context, Cursor cursor) {
String url = "";
String title = "";
boolean pinned = false;
// Cursor is already moved to required position.
if (!cursor.isAfterLast()) {
url = cursor.getString(cursor.getColumnIndexOrThrow(URLColumns.URL));
title = cursor.getString(cursor.getColumnIndexOrThrow(URLColumns.TITLE));
pinned = ((TopSitesCursorWrapper) cursor).isPinned();
}
TopBookmarkItemView view = (TopBookmarkItemView) bindView;
view.setTitle(title);
view.setUrl(url);
view.setPinned(pinned);
}
/**
* {@inheritDoc}
*/
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return new TopBookmarkItemView(context);
}
}
/**
* An AsyncTask to load the top bookmarks from the db.
*/
private class LoadBookmarksTask extends UiAsyncTask<Void, Void, Cursor> {
public LoadBookmarksTask() {
super(ThreadUtils.getBackgroundHandler());
}
@Override
protected Cursor doInBackground(Void... params) {
return BrowserDB.getTopSites(getContext().getContentResolver(), mMaxBookmarks);
}
@Override
public void onPostExecute(Cursor cursor) {
// Change to new cursor.
mAdapter.changeCursor(cursor);
// Load the thumbnails.
if (mAdapter.getCount() > 0) {
new LoadThumbnailsTask().execute(cursor);
}
}
}
/**
* An AsyncTask to load the thumbnails from a cursor.
*/
private class LoadThumbnailsTask extends UiAsyncTask<Cursor, Void, Map<String,Bitmap>> {
public LoadThumbnailsTask() {
super(ThreadUtils.getBackgroundHandler());
}
@Override
protected Map<String, Bitmap> doInBackground(Cursor... params) {
// TopBookmarksAdapter's cursor.
final Cursor adapterCursor = params[0];
if (adapterCursor == null || !adapterCursor.moveToFirst()) {
return null;
}
final List<String> urls = new ArrayList<String>();
do {
final String url = adapterCursor.getString(adapterCursor.getColumnIndexOrThrow(URLColumns.URL));
urls.add(url);
} while(adapterCursor.moveToNext());
if (urls.size() == 0) {
return null;
}
Map<String, Bitmap> thumbnails = new HashMap<String, Bitmap>();
Cursor cursor = BrowserDB.getThumbnailsForUrls(getContext().getContentResolver(), urls);
if (cursor == null || !cursor.moveToFirst()) {
return null;
}
try {
do {
final String url = cursor.getString(cursor.getColumnIndexOrThrow(Thumbnails.URL));
final byte[] b = cursor.getBlob(cursor.getColumnIndexOrThrow(Thumbnails.DATA));
if (b == null) {
continue;
}
Bitmap thumbnail = BitmapUtils.decodeByteArray(b);
if (thumbnail == null) {
continue;
}
thumbnails.put(url, thumbnail);
} while (cursor.moveToNext());
} finally {
if (cursor != null) {
cursor.close();
}
}
return thumbnails;
}
@Override
public void onPostExecute(Map<String, Bitmap> thumbnails) {
// If there's a layout scheduled on this view, wait for it to happen
// by storing the thumbnails in a cache. If not, update them right away.
if (isLayoutRequested()) {
mThumbnailsCache = thumbnails;
} else {
updateThumbnails(thumbnails);
}
}
}
}

View File

@ -210,6 +210,7 @@ size. -->
<!ENTITY history_removed "Page removed">
<!ENTITY bookmark_add "Add a bookmark">
<!ENTITY bookmark_edit_title "Edit Bookmark">
<!ENTITY bookmark_edit_name "Name">
<!ENTITY bookmark_edit_location "Location">

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- empty with no url -->
<item android:state_empty="true" android:color="#80777777" />
<!-- default -->
<item android:color="#FF777777"/>
</selector>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 249 B

After

Width:  |  Height:  |  Size: 151 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 214 B

After

Width:  |  Height:  |  Size: 137 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 296 B

After

Width:  |  Height:  |  Size: 156 B

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:gecko="http://schemas.android.com/apk/res-auto">
<org.mozilla.gecko.home.BookmarkThumbnailView
android:id="@+id/thumbnail"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"/>
<org.mozilla.gecko.home.FadedTextView
android:id="@+id/title"
style="@style/Widget.TopBookmarkItemTitle"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/thumbnail"
android:duplicateParentState="true"
gecko:fadeWidth="20dip"/>
<ImageView android:id="@+id/pin"
style="@style/Widget.TopBookmarkItemPin"
android:layout_width="@dimen/abouthome_topsite_pinsize"
android:layout_height="@dimen/abouthome_topsite_pinsize"
android:layout_alignTop="@id/thumbnail"
android:layout_alignRight="@id/thumbnail"/>
</merge>

View File

@ -21,6 +21,8 @@
<style name="Widget.BaseListView" parent="android:style/Widget.Holo.ListView"/>
<style name="Widget.BaseGridView" parent="android:style/Widget.Holo.GridView"/>
<style name="Widget.BaseTextView" parent="android:style/Widget.Holo.Light.TextView"/>

View File

@ -35,8 +35,12 @@
<item name="android:windowBackground">@android:color/white</item>
<item name="android:panelBackground">@drawable/menu_panel_bg</item>
<item name="android:listViewStyle">@style/Widget.ListView</item>
<item name="android:gridViewStyle">@style/Widget.GridView</item>
<item name="android:spinnerStyle">@style/Widget.Spinner</item>
<item name="android:spinnerItemStyle">@style/Widget.TextView.SpinnerItem</item>
<item name="bookmarkThumbnailViewStyle">@style/Widget.BookmarkThumbnailView</item>
<item name="topBookmarkItemViewStyle">@style/Widget.TopBookmarkItemView</item>
<item name="topBookmarksViewStyle">@style/Widget.TopBookmarksView</item>
</style>
</resources>

View File

@ -5,6 +5,20 @@
<resources>
<!-- Theme level attributes -->
<declare-styleable name="Theme">
<!-- Default style for the BookmarkThumbnailView -->
<attr name="bookmarkThumbnailViewStyle" format="reference" />
<!-- Default style for the TopBookmarkItemView -->
<attr name="topBookmarkItemViewStyle" format="reference" />
<!-- Default style for the TopBookmarksView -->
<attr name="topBookmarksViewStyle" format="reference" />
</declare-styleable>
<declare-styleable name="AboutHomeSection">
<attr name="title" format="string"/>
<attr name="subtitle" format="string"/>

View File

@ -18,6 +18,8 @@
<style name="Widget.BaseListLiew" parent="android:style/Widget.ListView"/>
<style name="Widget.BaseGridView" parent="android:style/Widget.GridView"/>
<style name="Widget.BaseTextView" parent="android:style/Widget.TextView"/>
<!--
@ -51,6 +53,13 @@
<item name="android:groupIndicator">@android:color/transparent</item>
</style>
<style name="Widget.GridView" parent="Widget.BaseGridView">
<item name="android:verticalSpacing">0dip</item>
<item name="android:horizontalSpacing">0dip</item>
<item name="android:cacheColorHint">@android:color/transparent</item>
<item name="android:listSelector">@drawable/action_bar_button</item>
</style>
<style name="Widget.ListItem">
<item name="android:minHeight">?android:attr/listPreferredItemHeight</item>
<item name="android:textAppearance">?android:attr/textAppearanceLargeInverse</item>
@ -88,6 +97,37 @@
<item name="android:drawableLeft">@drawable/bookmark_folder</item>
</style>
<style name="Widget.TopBookmarksView" parent="Widget.GridView">
<item name="android:padding">7dp</item>
</style>
<style name="Widget.TopBookmarkItemView">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">fill_parent</item>
<item name="android:padding">5dip</item>
<item name="android:orientation">vertical</item>
</style>
<style name="Widget.BookmarkThumbnailView">
<item name="android:padding">0dip</item>
<item name="android:scaleType">center</item>
</style>
<style name="Widget.TopBookmarkItemPin">
<item name="android:minWidth">30dip</item>
<item name="android:minHeight">30dip</item>
<item name="android:padding">0dip</item>
</style>
<style name="Widget.TopBookmarkItemTitle">
<item name="android:textColor">@color/top_bookmark_item_title</item>
<item name="android:textSize">12sp</item>
<item name="android:singleLine">true</item>
<item name="android:ellipsize">none</item>
<item name="android:paddingTop">5dip</item>
<item name="android:gravity">left</item>
</style>
<!--
TextAppearance
Note: Gecko uses light theme as default, while Android uses dark.

View File

@ -74,9 +74,13 @@
<item name="android:buttonStyle">@style/Widget.Button</item>
<item name="android:dropDownItemStyle">@style/Widget.DropDownItem</item>
<item name="android:editTextStyle">@style/Widget.EditText</item>
<item name="android:gridViewStyle">@style/Widget.GridView</item>
<item name="android:textViewStyle">@style/Widget.TextView</item>
<item name="android:spinnerStyle">@style/Widget.Spinner</item>
<item name="android:spinnerItemStyle">@style/Widget.TextView.SpinnerItem</item>
<item name="bookmarkThumbnailViewStyle">@style/Widget.BookmarkThumbnailView</item>
<item name="topBookmarkItemViewStyle">@style/Widget.TopBookmarkItemView</item>
<item name="topBookmarksViewStyle">@style/Widget.TopBookmarksView</item>
</style>
<style name="Gecko.Preferences" parent="GeckoPreferencesBase"/>

View File

@ -202,6 +202,7 @@
<string name="history_removed">&history_removed;</string>
<string name="bookmark_add">&bookmark_add;</string>
<string name="bookmark_edit_title">&bookmark_edit_title;</string>
<string name="bookmark_edit_name">&bookmark_edit_name;</string>
<string name="bookmark_edit_location">&bookmark_edit_location;</string>