mobile/android/base/home/TopSitesGridView.java

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

michael@0 1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
michael@0 2 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 package org.mozilla.gecko.home;
michael@0 7
michael@0 8 import java.util.EnumSet;
michael@0 9
michael@0 10 import org.mozilla.gecko.R;
michael@0 11 import org.mozilla.gecko.Telemetry;
michael@0 12 import org.mozilla.gecko.TelemetryContract;
michael@0 13 import org.mozilla.gecko.ThumbnailHelper;
michael@0 14 import org.mozilla.gecko.db.BrowserDB.URLColumns;
michael@0 15 import org.mozilla.gecko.db.TopSitesCursorWrapper;
michael@0 16 import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
michael@0 17
michael@0 18 import android.content.Context;
michael@0 19 import android.content.res.TypedArray;
michael@0 20 import android.database.Cursor;
michael@0 21 import android.graphics.Rect;
michael@0 22 import android.text.TextUtils;
michael@0 23 import android.util.AttributeSet;
michael@0 24 import android.view.ContextMenu.ContextMenuInfo;
michael@0 25 import android.view.View;
michael@0 26 import android.widget.AbsListView;
michael@0 27 import android.widget.AdapterView;
michael@0 28 import android.widget.GridView;
michael@0 29
michael@0 30 /**
michael@0 31 * A grid view of top and pinned sites.
michael@0 32 * Each cell in the grid is a TopSitesGridItemView.
michael@0 33 */
michael@0 34 public class TopSitesGridView extends GridView {
michael@0 35 private static final String LOGTAG = "GeckoTopSitesGridView";
michael@0 36
michael@0 37 // Listener for editing pinned sites.
michael@0 38 public static interface OnEditPinnedSiteListener {
michael@0 39 public void onEditPinnedSite(int position, String searchTerm);
michael@0 40 }
michael@0 41
michael@0 42 // Max number of top sites that needs to be shown.
michael@0 43 private final int mMaxSites;
michael@0 44
michael@0 45 // Number of columns to show.
michael@0 46 private final int mNumColumns;
michael@0 47
michael@0 48 // Horizontal spacing in between the rows.
michael@0 49 private final int mHorizontalSpacing;
michael@0 50
michael@0 51 // Vertical spacing in between the rows.
michael@0 52 private final int mVerticalSpacing;
michael@0 53
michael@0 54 // Measured width of this view.
michael@0 55 private int mMeasuredWidth;
michael@0 56
michael@0 57 // Measured height of this view.
michael@0 58 private int mMeasuredHeight;
michael@0 59
michael@0 60 // On URL open listener.
michael@0 61 private OnUrlOpenListener mUrlOpenListener;
michael@0 62
michael@0 63 // Edit pinned site listener.
michael@0 64 private OnEditPinnedSiteListener mEditPinnedSiteListener;
michael@0 65
michael@0 66 // Context menu info.
michael@0 67 private TopSitesGridContextMenuInfo mContextMenuInfo;
michael@0 68
michael@0 69 // Whether we're handling focus changes or not. This is used
michael@0 70 // to avoid infinite re-layouts when using this GridView as
michael@0 71 // a ListView header view (see bug 918044).
michael@0 72 private boolean mIsHandlingFocusChange;
michael@0 73
michael@0 74 public TopSitesGridView(Context context) {
michael@0 75 this(context, null);
michael@0 76 }
michael@0 77
michael@0 78 public TopSitesGridView(Context context, AttributeSet attrs) {
michael@0 79 this(context, attrs, R.attr.topSitesGridViewStyle);
michael@0 80 }
michael@0 81
michael@0 82 public TopSitesGridView(Context context, AttributeSet attrs, int defStyle) {
michael@0 83 super(context, attrs, defStyle);
michael@0 84 mMaxSites = getResources().getInteger(R.integer.number_of_top_sites);
michael@0 85 mNumColumns = getResources().getInteger(R.integer.number_of_top_sites_cols);
michael@0 86 setNumColumns(mNumColumns);
michael@0 87
michael@0 88 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TopSitesGridView, defStyle, 0);
michael@0 89 mHorizontalSpacing = a.getDimensionPixelOffset(R.styleable.TopSitesGridView_android_horizontalSpacing, 0x00);
michael@0 90 mVerticalSpacing = a.getDimensionPixelOffset(R.styleable.TopSitesGridView_android_verticalSpacing, 0x00);
michael@0 91 a.recycle();
michael@0 92
michael@0 93 mIsHandlingFocusChange = false;
michael@0 94 }
michael@0 95
michael@0 96 /**
michael@0 97 * {@inheritDoc}
michael@0 98 */
michael@0 99 @Override
michael@0 100 public void onAttachedToWindow() {
michael@0 101 super.onAttachedToWindow();
michael@0 102
michael@0 103 setOnItemClickListener(new AdapterView.OnItemClickListener() {
michael@0 104 @Override
michael@0 105 public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
michael@0 106 TopSitesGridItemView row = (TopSitesGridItemView) view;
michael@0 107
michael@0 108 // Decode "user-entered" URLs before loading them.
michael@0 109 String url = HomeFragment.decodeUserEnteredUrl(row.getUrl());
michael@0 110
michael@0 111 // If the url is empty, the user can pin a site.
michael@0 112 // If not, navigate to the page given by the url.
michael@0 113 if (!TextUtils.isEmpty(url)) {
michael@0 114 if (mUrlOpenListener != null) {
michael@0 115 Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.GRID_ITEM, Integer.toString(position));
michael@0 116
michael@0 117 mUrlOpenListener.onUrlOpen(url, EnumSet.noneOf(OnUrlOpenListener.Flags.class));
michael@0 118 }
michael@0 119 } else {
michael@0 120 if (mEditPinnedSiteListener != null) {
michael@0 121 mEditPinnedSiteListener.onEditPinnedSite(position, "");
michael@0 122 }
michael@0 123 }
michael@0 124 }
michael@0 125 });
michael@0 126
michael@0 127 setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
michael@0 128 @Override
michael@0 129 public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
michael@0 130 Cursor cursor = (Cursor) parent.getItemAtPosition(position);
michael@0 131
michael@0 132 TopSitesGridItemView gridView = (TopSitesGridItemView) view;
michael@0 133 if (cursor == null || gridView.isEmpty()) {
michael@0 134 mContextMenuInfo = null;
michael@0 135 return false;
michael@0 136 }
michael@0 137
michael@0 138 mContextMenuInfo = new TopSitesGridContextMenuInfo(view, position, id);
michael@0 139 updateContextMenuFromCursor(mContextMenuInfo, cursor);
michael@0 140 return showContextMenuForChild(TopSitesGridView.this);
michael@0 141 }
michael@0 142 });
michael@0 143 }
michael@0 144
michael@0 145 @Override
michael@0 146 public void onDetachedFromWindow() {
michael@0 147 super.onDetachedFromWindow();
michael@0 148
michael@0 149 mUrlOpenListener = null;
michael@0 150 mEditPinnedSiteListener = null;
michael@0 151 }
michael@0 152
michael@0 153 @Override
michael@0 154 protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
michael@0 155 mIsHandlingFocusChange = true;
michael@0 156 super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
michael@0 157 mIsHandlingFocusChange = false;
michael@0 158 }
michael@0 159
michael@0 160 @Override
michael@0 161 public void requestLayout() {
michael@0 162 if (!mIsHandlingFocusChange) {
michael@0 163 super.requestLayout();
michael@0 164 }
michael@0 165 }
michael@0 166
michael@0 167 /**
michael@0 168 * {@inheritDoc}
michael@0 169 */
michael@0 170 @Override
michael@0 171 public int getColumnWidth() {
michael@0 172 // This method will be called from onMeasure() too.
michael@0 173 // It's better to use getMeasuredWidth(), as it is safe in this case.
michael@0 174 final int totalHorizontalSpacing = mNumColumns > 0 ? (mNumColumns - 1) * mHorizontalSpacing : 0;
michael@0 175 return (getMeasuredWidth() - getPaddingLeft() - getPaddingRight() - totalHorizontalSpacing) / mNumColumns;
michael@0 176 }
michael@0 177
michael@0 178 /**
michael@0 179 * {@inheritDoc}
michael@0 180 */
michael@0 181 @Override
michael@0 182 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
michael@0 183 // Sets the padding for this view.
michael@0 184 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
michael@0 185
michael@0 186 final int measuredWidth = getMeasuredWidth();
michael@0 187 if (measuredWidth == mMeasuredWidth) {
michael@0 188 // Return the cached values as the width is the same.
michael@0 189 setMeasuredDimension(mMeasuredWidth, mMeasuredHeight);
michael@0 190 return;
michael@0 191 }
michael@0 192
michael@0 193 final int columnWidth = getColumnWidth();
michael@0 194
michael@0 195 // Get the first child from the adapter.
michael@0 196 final TopSitesGridItemView child = new TopSitesGridItemView(getContext());
michael@0 197
michael@0 198 // Set a default LayoutParams on the child, if it doesn't have one on its own.
michael@0 199 AbsListView.LayoutParams params = (AbsListView.LayoutParams) child.getLayoutParams();
michael@0 200 if (params == null) {
michael@0 201 params = new AbsListView.LayoutParams(AbsListView.LayoutParams.WRAP_CONTENT,
michael@0 202 AbsListView.LayoutParams.WRAP_CONTENT);
michael@0 203 child.setLayoutParams(params);
michael@0 204 }
michael@0 205
michael@0 206 // Measure the exact width of the child, and the height based on the width.
michael@0 207 // Note: the child (and TopSitesThumbnailView) takes care of calculating its height.
michael@0 208 int childWidthSpec = MeasureSpec.makeMeasureSpec(columnWidth, MeasureSpec.EXACTLY);
michael@0 209 int childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
michael@0 210 child.measure(childWidthSpec, childHeightSpec);
michael@0 211 final int childHeight = child.getMeasuredHeight();
michael@0 212
michael@0 213 // This is the maximum width of the contents of each child in the grid.
michael@0 214 // Use this as the target width for thumbnails.
michael@0 215 final int thumbnailWidth = child.getMeasuredWidth() - child.getPaddingLeft() - child.getPaddingRight();
michael@0 216 ThumbnailHelper.getInstance().setThumbnailWidth(thumbnailWidth);
michael@0 217
michael@0 218 // Number of rows required to show these top sites.
michael@0 219 final int rows = (int) Math.ceil((double) mMaxSites / mNumColumns);
michael@0 220 final int childrenHeight = childHeight * rows;
michael@0 221 final int totalVerticalSpacing = rows > 0 ? (rows - 1) * mVerticalSpacing : 0;
michael@0 222
michael@0 223 // Total height of this view.
michael@0 224 final int measuredHeight = childrenHeight + getPaddingTop() + getPaddingBottom() + totalVerticalSpacing;
michael@0 225 setMeasuredDimension(measuredWidth, measuredHeight);
michael@0 226 mMeasuredWidth = measuredWidth;
michael@0 227 mMeasuredHeight = measuredHeight;
michael@0 228 }
michael@0 229
michael@0 230 @Override
michael@0 231 public ContextMenuInfo getContextMenuInfo() {
michael@0 232 return mContextMenuInfo;
michael@0 233 }
michael@0 234
michael@0 235 /*
michael@0 236 * Update the fields of a TopSitesGridContextMenuInfo object
michael@0 237 * from a cursor.
michael@0 238 *
michael@0 239 * @param info context menu info object to be updated
michael@0 240 * @param cursor used to update the context menu info object
michael@0 241 */
michael@0 242 private void updateContextMenuFromCursor(TopSitesGridContextMenuInfo info, Cursor cursor) {
michael@0 243 info.url = cursor.getString(cursor.getColumnIndexOrThrow(URLColumns.URL));
michael@0 244 info.title = cursor.getString(cursor.getColumnIndexOrThrow(URLColumns.TITLE));
michael@0 245 info.isPinned = ((TopSitesCursorWrapper) cursor).isPinned();
michael@0 246 }
michael@0 247 /**
michael@0 248 * Set an url open listener to be used by this view.
michael@0 249 *
michael@0 250 * @param listener An url open listener for this view.
michael@0 251 */
michael@0 252 public void setOnUrlOpenListener(OnUrlOpenListener listener) {
michael@0 253 mUrlOpenListener = listener;
michael@0 254 }
michael@0 255
michael@0 256 /**
michael@0 257 * Set an edit pinned site listener to be used by this view.
michael@0 258 *
michael@0 259 * @param listener An edit pinned site listener for this view.
michael@0 260 */
michael@0 261 public void setOnEditPinnedSiteListener(final OnEditPinnedSiteListener listener) {
michael@0 262 mEditPinnedSiteListener = listener;
michael@0 263 }
michael@0 264
michael@0 265 /**
michael@0 266 * Stores information regarding the creation of the context menu for a GridView item.
michael@0 267 */
michael@0 268 public static class TopSitesGridContextMenuInfo extends HomeContextMenuInfo {
michael@0 269 public boolean isPinned = false;
michael@0 270
michael@0 271 public TopSitesGridContextMenuInfo(View targetView, int position, long id) {
michael@0 272 super(targetView, position, id);
michael@0 273 }
michael@0 274 }
michael@0 275 }

mercurial