EMMA Coverage Report (generated Fri Aug 23 16:39:17 PDT 2013)
[all classes][org.chromium.chrome.browser]

COVERAGE SUMMARY FOR SOURCE FILE [NavigationPopup.java]

nameclass, %method, %block, %line, %
NavigationPopup.java75%  (3/4)95%  (19/20)94%  (381/407)97%  (88.2/91)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class NavigationPopup$10%   (0/1)100% (0/0)100% (0/0)100% (0/0)
     
class NavigationPopup$ListItemFactory100% (1/1)100% (3/3)89%  (92/103)96%  (23/24)
createListItem (): TextView 100% (1/1)81%  (46/57)92%  (11/12)
NavigationPopup$ListItemFactory (Context): void 100% (1/1)100% (8/8)100% (4/4)
computeFadeDimensions (): void 100% (1/1)100% (38/38)100% (8/8)
     
class NavigationPopup$NavigationAdapter100% (1/1)100% (6/6)92%  (67/73)95%  (13.3/14)
getView (int, View, ViewGroup): View 100% (1/1)87%  (39/45)93%  (9.3/10)
NavigationPopup$NavigationAdapter (NavigationPopup): void 100% (1/1)100% (6/6)100% (1/1)
NavigationPopup$NavigationAdapter (NavigationPopup, NavigationPopup$1): void 100% (1/1)100% (4/4)100% (1/1)
getCount (): int 100% (1/1)100% (5/5)100% (1/1)
getItem (int): Object 100% (1/1)100% (6/6)100% (1/1)
getItemId (int): long 100% (1/1)100% (7/7)100% (1/1)
     
class NavigationPopup100% (1/1)91%  (10/11)96%  (222/231)98%  (51.9/53)
shouldBeShown (): boolean 0%   (0/1)0%   (0/8)0%   (0/1)
initializeNative (): void 100% (1/1)98%  (48/49)99%  (11.9/12)
NavigationPopup (Context, NavigationClient, boolean): void 100% (1/1)100% (65/65)100% (14/14)
access$100 (NavigationPopup): NavigationHistory 100% (1/1)100% (3/3)100% (1/1)
access$200 (NavigationPopup): NavigationPopup$ListItemFactory 100% (1/1)100% (3/3)100% (1/1)
access$300 (NavigationPopup, TextView, Bitmap): void 100% (1/1)100% (5/5)100% (1/1)
dismiss (): void 100% (1/1)100% (13/13)100% (5/5)
onFaviconUpdated (String, Object): void 100% (1/1)100% (27/27)100% (5/5)
onItemClick (AdapterView, View, int, long): void 100% (1/1)100% (13/13)100% (4/4)
show (): void 100% (1/1)100% (8/8)100% (3/3)
updateBitmapForTextView (TextView, Bitmap): void 100% (1/1)100% (37/37)100% (8/8)

1// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4 
5package org.chromium.chrome.browser;
6 
7import android.content.Context;
8import android.graphics.Bitmap;
9import android.graphics.Color;
10import android.graphics.drawable.BitmapDrawable;
11import android.graphics.drawable.ColorDrawable;
12import android.graphics.drawable.Drawable;
13import android.text.TextUtils;
14import android.view.Gravity;
15import android.view.View;
16import android.view.ViewGroup;
17import android.widget.AdapterView;
18import android.widget.BaseAdapter;
19import android.widget.HeaderViewListAdapter;
20import android.widget.ListPopupWindow;
21import android.widget.ListView;
22import android.widget.ListView.FixedViewInfo;
23import android.widget.PopupWindow;
24import android.widget.TextView;
25 
26import org.chromium.base.CalledByNative;
27import org.chromium.base.ThreadUtils;
28import org.chromium.ui.LocalizationUtils;
29import org.chromium.chrome.R;
30import org.chromium.content.browser.ContentViewCore;
31import org.chromium.content.browser.NavigationClient;
32import org.chromium.content.browser.NavigationEntry;
33import org.chromium.content.browser.NavigationHistory;
34 
35import java.util.ArrayList;
36import java.util.HashSet;
37import java.util.Set;
38 
39/**
40 * A popup that handles displaying the navigation history for a given tab.
41 */
42public class NavigationPopup extends ListPopupWindow implements AdapterView.OnItemClickListener {
43 
44    private static final int FAVICON_SIZE_DP = 16;
45 
46    private static final int MAXIMUM_HISTORY_ITEMS = 8;
47 
48    private final Context mContext;
49    private final NavigationClient mNavigationClient;
50    private final NavigationHistory mHistory;
51    private final NavigationAdapter mAdapter;
52    private final ListItemFactory mListItemFactory;
53 
54    private final int mFaviconSize;
55 
56    private int mNativeNavigationPopup;
57 
58    /**
59     * Constructs a new popup with the given history information.
60     *
61     * @param context The context used for building the popup.
62     * @param navigationClient The owner of the history being displayed.
63     * @param isForward Whether to request forward navigation entries.
64     */
65    public NavigationPopup(
66            Context context, NavigationClient navigationClient, boolean isForward) {
67        super(context, null, android.R.attr.popupMenuStyle);
68        mContext = context;
69        mNavigationClient = navigationClient;
70        mHistory = mNavigationClient.getDirectedNavigationHistory(
71                isForward, MAXIMUM_HISTORY_ITEMS);
72        mAdapter = new NavigationAdapter();
73 
74        float density = mContext.getResources().getDisplayMetrics().density;
75        mFaviconSize = (int) (density * FAVICON_SIZE_DP);
76 
77        setModal(true);
78        setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
79        setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
80        setOnItemClickListener(this);
81 
82        setAdapter(new HeaderViewListAdapter(null, null, mAdapter));
83 
84        mListItemFactory = new ListItemFactory(context);
85    }
86 
87    /**
88     * @return Whether a navigation popup is valid for the given page.
89     */
90    public boolean shouldBeShown() {
91        return mHistory.getEntryCount() > 0;
92    }
93 
94    @Override
95    public void show() {
96        if (mNativeNavigationPopup == 0) initializeNative();
97        super.show();
98    }
99 
100    @Override
101    public void dismiss() {
102        if (mNativeNavigationPopup != 0) {
103            nativeDestroy(mNativeNavigationPopup);
104            mNativeNavigationPopup = 0;
105        }
106        super.dismiss();
107    }
108 
109    private void initializeNative() {
110        ThreadUtils.assertOnUiThread();
111        mNativeNavigationPopup = nativeInit();
112 
113        Set<String> requestedUrls = new HashSet<String>();
114        for (int i = 0; i < mHistory.getEntryCount(); i++) {
115            NavigationEntry entry = mHistory.getEntryAtIndex(i);
116            if (entry.getFavicon() != null) continue;
117            String url = entry.getUrl();
118            if (!requestedUrls.contains(url)) {
119                nativeFetchFaviconForUrl(mNativeNavigationPopup, url);
120                requestedUrls.add(url);
121            }
122        }
123        nativeFetchFaviconForUrl(mNativeNavigationPopup, nativeGetHistoryUrl());
124    }
125 
126    @CalledByNative
127    private void onFaviconUpdated(String url, Object favicon) {
128        for (int i = 0; i < mHistory.getEntryCount(); i++) {
129            NavigationEntry entry = mHistory.getEntryAtIndex(i);
130            if (TextUtils.equals(url, entry.getUrl())) entry.updateFavicon((Bitmap) favicon);
131        }
132        mAdapter.notifyDataSetChanged();
133    }
134 
135    @Override
136    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
137        NavigationEntry entry = (NavigationEntry) parent.getItemAtPosition(position);
138        mNavigationClient.goToNavigationIndex(entry.getIndex());
139        dismiss();
140    }
141 
142    private void updateBitmapForTextView(TextView view, Bitmap bitmap) {
143        Drawable faviconDrawable = null;
144        if (bitmap != null) {
145            faviconDrawable = new BitmapDrawable(mContext.getResources(), bitmap);
146            ((BitmapDrawable) faviconDrawable).setGravity(Gravity.FILL);
147        } else {
148            faviconDrawable = new ColorDrawable(Color.TRANSPARENT);
149        }
150        faviconDrawable.setBounds(0, 0, mFaviconSize, mFaviconSize);
151        view.setCompoundDrawables(faviconDrawable, null, null, null);
152    }
153 
154    private static class ListItemFactory {
155        private static final int LIST_ITEM_HEIGHT_DP = 48;
156        private static final int PADDING_DP = 8;
157        private static final int TEXT_SIZE_SP = 18;
158        private static final float FADE_LENGTH_DP = 25.0f;
159        private static final float FADE_STOP = 0.75f;
160 
161        int mFadeEdgeLength;
162        int mFadePadding;
163        int mListItemHeight;
164        int mPadding;
165        boolean mIsLayoutDirectionRTL;
166        Context mContext;
167 
168        public ListItemFactory(Context context) {
169            mContext = context;
170            computeFadeDimensions();
171        }
172 
173        private void computeFadeDimensions() {
174            // Fade with linear gradient starting 25dp from right margin.
175            // Reaches 0% opacity at 75% length. (Simulated with extra padding)
176            float density = mContext.getResources().getDisplayMetrics().density;
177            float fadeLength = (FADE_LENGTH_DP * density);
178            mFadeEdgeLength = (int)(fadeLength * FADE_STOP);
179            mFadePadding = (int)(fadeLength * (1 - FADE_STOP));
180            mListItemHeight = (int) (density * LIST_ITEM_HEIGHT_DP);
181            mPadding = (int) (density * PADDING_DP);
182            mIsLayoutDirectionRTL = LocalizationUtils.isSystemLayoutDirectionRtl();
183        }
184 
185        public TextView createListItem() {
186            TextView view = new TextView(mContext);
187            view.setFadingEdgeLength(mFadeEdgeLength);
188            view.setHorizontalFadingEdgeEnabled(true);
189            view.setSingleLine();
190            view.setTextSize(TEXT_SIZE_SP);
191            view.setMinimumHeight(mListItemHeight);
192            view.setGravity(Gravity.CENTER_VERTICAL);
193            view.setCompoundDrawablePadding(mPadding);
194            if (!mIsLayoutDirectionRTL) {
195                view.setPadding(mPadding, 0, mPadding + mFadePadding , 0);
196            }
197            else {
198                view.setPadding(mPadding + mFadePadding, 0, mPadding, 0);
199            }
200            return view;
201        }
202    }
203 
204    private class NavigationAdapter extends BaseAdapter {
205        @Override
206        public int getCount() {
207            return mHistory.getEntryCount();
208        }
209 
210        @Override
211        public Object getItem(int position) {
212            return mHistory.getEntryAtIndex(position);
213        }
214 
215        @Override
216        public long getItemId(int position) {
217            return ((NavigationEntry) getItem(position)).getIndex();
218        }
219 
220        @Override
221        public View getView(int position, View convertView, ViewGroup parent) {
222            TextView view;
223            if (convertView != null && convertView instanceof TextView) {
224                view = (TextView) convertView;
225            } else {
226                view = mListItemFactory.createListItem();
227            }
228            NavigationEntry entry = (NavigationEntry) getItem(position);
229 
230            String entryText = entry.getTitle();
231            if (TextUtils.isEmpty(entryText)) entryText = entry.getVirtualUrl();
232            if (TextUtils.isEmpty(entryText)) entryText = entry.getUrl();
233            view.setText(entryText);
234            updateBitmapForTextView(view, entry.getFavicon());
235 
236            return view;
237        }
238    }
239 
240    private static native String nativeGetHistoryUrl();
241 
242    private native int nativeInit();
243    private native void nativeDestroy(int nativeNavigationPopup);
244    private native void nativeFetchFaviconForUrl(int nativeNavigationPopup, String url);
245}

[all classes][org.chromium.chrome.browser]
EMMA 2.0.5312 (C) Vladimir Roubtsov