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.

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

mercurial