diff --git a/build/mobile/robocop/Actions.java.in b/build/mobile/robocop/Actions.java.in
index 6ac6bf81bcc6..e96420755483 100644
--- a/build/mobile/robocop/Actions.java.in
+++ b/build/mobile/robocop/Actions.java.in
@@ -82,6 +82,13 @@ public interface Actions {
void drag(int startingX, int endingX, int startingY, int endingY);
+ /**
+ * This is the implementation of clickLongOnScreen from Robotium 4.0 since this sometimes fails for Robotium 3.6
+ * TODO : Remove this when Robotium is updated
+ */
+
+ void clickLongOnScreen(float x, float y);
+
/**
* Run a sql query on the specified database
*/
diff --git a/build/mobile/robocop/FennecNativeActions.java.in b/build/mobile/robocop/FennecNativeActions.java.in
index 3eff3c8b7ce5..9813fd8746c5 100644
--- a/build/mobile/robocop/FennecNativeActions.java.in
+++ b/build/mobile/robocop/FennecNativeActions.java.in
@@ -22,7 +22,9 @@ import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
+import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewConfiguration;
import com.jayway.android.robotium.solo.Solo;
@@ -458,6 +460,41 @@ public class FennecNativeActions implements Actions {
mSolo.drag(startingX, endingX, startingY, endingY, 10);
}
+ /**
+ * This is the implementation of clickLongOnScreen from Robotium 4.0 since this sometimes fails for Robotium 3.6
+ * TODO : Remove this when Robotium is updated
+ */
+
+ public void clickLongOnScreen(float x, float y) {
+ boolean successfull = false;
+ int retry = 0;
+ long downTime = SystemClock.uptimeMillis();
+ long eventTime = SystemClock.uptimeMillis();
+ MotionEvent event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, x, y, 0);
+
+ while(!successfull && retry < 10) {
+ try{
+ mInstr.sendPointerSync(event);
+ successfull = true;
+ }catch(SecurityException e){
+ FennecNativeDriver.log(LogLevel.ERROR, e);
+ retry++;
+ }
+ }
+
+ mAsserter.ok(successfull, "Trying to click on long on screen at (" + x + "," + y + ")", "Was able to click long on screen");
+
+ eventTime = SystemClock.uptimeMillis();
+ event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, x + 1.0f, y + 1.0f, 0);
+ mInstr.sendPointerSync(event);
+ mSolo.sleep(((int)(ViewConfiguration.getLongPressTimeout() * 2.5f)));
+
+ eventTime = SystemClock.uptimeMillis();
+ event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
+ mInstr.sendPointerSync(event);
+ mSolo.sleep(500);
+ }
+
public Cursor querySql(String dbPath, String sql) {
try {
return (Cursor)mQuerySql.invoke(mRobocopApi, dbPath, sql);
diff --git a/mobile/android/base/ActivityHandlerHelper.java b/mobile/android/base/ActivityHandlerHelper.java
index 9d389c47f5c8..53a5fecd34ee 100644
--- a/mobile/android/base/ActivityHandlerHelper.java
+++ b/mobile/android/base/ActivityHandlerHelper.java
@@ -36,7 +36,6 @@ public class ActivityHandlerHelper implements GeckoEventListener {
private final ActivityResultHandlerMap mActivityResultHandlerMap;
private final FilePickerResultHandlerSync mFilePickerResultHandlerSync;
- private final AwesomebarResultHandler mAwesomebarResultHandler;
private final CameraImageResultHandler mCameraImageResultHandler;
private final CameraVideoResultHandler mCameraVideoResultHandler;
@@ -58,7 +57,6 @@ public class ActivityHandlerHelper implements GeckoEventListener {
};
mActivityResultHandlerMap = new ActivityResultHandlerMap();
mFilePickerResultHandlerSync = new FilePickerResultHandlerSync(mFilePickerResult);
- mAwesomebarResultHandler = new AwesomebarResultHandler();
mCameraImageResultHandler = new CameraImageResultHandler(mFilePickerResult);
mCameraVideoResultHandler = new CameraVideoResultHandler(mFilePickerResult);
GeckoAppShell.getEventDispatcher().registerEventListener("FilePicker:Show", this);
@@ -91,10 +89,6 @@ public class ActivityHandlerHelper implements GeckoEventListener {
}
}
- public int makeRequestCodeForAwesomebar() {
- return mActivityResultHandlerMap.put(mAwesomebarResultHandler);
- }
-
public int makeRequestCode(ActivityResultHandler aHandler) {
return mActivityResultHandlerMap.put(aHandler);
}
diff --git a/mobile/android/base/AndroidManifest.xml.in b/mobile/android/base/AndroidManifest.xml.in
index e6d58df3740e..07b1754fc727 100644
--- a/mobile/android/base/AndroidManifest.xml.in
+++ b/mobile/android/base/AndroidManifest.xml.in
@@ -230,11 +230,6 @@
-
-
KeyEvent.getMaxKeyCode())
- return true;
-
- // This method is called only if the key event was not handled
- // by any of the views, which usually means the edit box lost focus
- if (keyCode == KeyEvent.KEYCODE_BACK ||
- keyCode == KeyEvent.KEYCODE_MENU ||
- keyCode == KeyEvent.KEYCODE_DPAD_UP ||
- keyCode == KeyEvent.KEYCODE_DPAD_DOWN ||
- keyCode == KeyEvent.KEYCODE_DPAD_LEFT ||
- keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ||
- keyCode == KeyEvent.KEYCODE_DPAD_CENTER ||
- keyCode == KeyEvent.KEYCODE_DEL ||
- keyCode == KeyEvent.KEYCODE_VOLUME_UP ||
- keyCode == KeyEvent.KEYCODE_VOLUME_DOWN ||
- GamepadUtils.isActionKey(event)) {
- return super.onKeyDown(keyCode, event);
- } else if (keyCode == KeyEvent.KEYCODE_SEARCH) {
- mText.setText("");
- mText.requestFocus();
- return true;
- } else {
- int prevSelStart = mText.getSelectionStart();
- int prevSelEnd = mText.getSelectionEnd();
-
- // Manually dispatch the key event to the AwesomeBar. If selection changed as
- // a result of the key event, then give focus back to mText
- mText.dispatchKeyEvent(event);
-
- int curSelStart = mText.getSelectionStart();
- int curSelEnd = mText.getSelectionEnd();
- if (prevSelStart != curSelStart || prevSelEnd != curSelEnd) {
- mText.requestFocusFromTouch();
- // Restore the selection, which gets lost due to the focus switch
- mText.setSelection(curSelStart, curSelEnd);
- }
- return true;
- }
- }
-
- @Override
- public void onResume() {
- super.onResume();
- if (mText != null && mText.getText() != null) {
- updateGoButton(mText.getText().toString());
- if (mDelayRestartInput) {
- // call updateGoButton again to force a restartInput call
- updateGoButton(mText.getText().toString());
- }
- }
-
- // Invlidate the cached value that keeps track of whether or
- // not desktop bookmarks exist
- BrowserDB.invalidateCachedState();
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- mAwesomeTabs.destroy();
- }
-
- @Override
- public void onBackPressed() {
- // Let mAwesomeTabs try to handle the back press, since we may be in a
- // bookmarks sub-folder.
- if (mAwesomeTabs.onBackPressed())
- return;
-
- // Otherwise, just exit the awesome screen
- cancelAndFinish();
- }
-
- static public class ContextMenuSubject {
- public int id;
- public String url;
- public byte[] favicon;
- public String title;
- public String keyword;
- public int display;
-
- public ContextMenuSubject(int id, String url, byte[] favicon, String title, String keyword) {
- this(id, url, favicon, title, keyword, Combined.DISPLAY_NORMAL);
- }
-
- public ContextMenuSubject(int id, String url, byte[] favicon, String title, String keyword, int display) {
- this.id = id;
- this.url = url;
- this.favicon = favicon;
- this.title = title;
- this.keyword = keyword;
- this.display = display;
- }
- };
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) {
- super.onCreateContextMenu(menu, view, menuInfo);
- AwesomeBarTab tab = mAwesomeTabs.getAwesomeBarTabForView(view);
- mContextMenuSubject = tab.getSubject(menu, view, menuInfo);
- }
-
- @Override
- public boolean onContextItemSelected(MenuItem item) {
- if (mContextMenuSubject == null)
- return false;
-
- final int id = mContextMenuSubject.id;
- final String url = mContextMenuSubject.url;
- final byte[] b = mContextMenuSubject.favicon;
- final String title = mContextMenuSubject.title;
- final String keyword = mContextMenuSubject.keyword;
- final int display = mContextMenuSubject.display;
-
- final int itemId = item.getItemId();
- if (itemId == R.id.open_private_tab || itemId == R.id.open_new_tab) {
- if (url == null) {
- Log.e(LOGTAG, "Can't open in new tab because URL is null");
- }
-
- String newTabUrl = url;
- if (display == Combined.DISPLAY_READER)
- newTabUrl = ReaderModeUtils.getAboutReaderForUrl(url, true);
-
- int flags = Tabs.LOADURL_NEW_TAB;
- if (item.getItemId() == R.id.open_private_tab)
- flags |= Tabs.LOADURL_PRIVATE;
-
- Tabs.getInstance().loadUrl(newTabUrl, flags);
- Toast.makeText(this, R.string.new_tab_opened, Toast.LENGTH_SHORT).show();
-
- return true;
- }
-
- if (itemId == R.id.open_in_reader) {
- if (url == null) {
- Log.e(LOGTAG, "Can't open in reader mode because URL is null");
- } else {
- openUrlAndFinish(ReaderModeUtils.getAboutReaderForUrl(url, true));
- }
- return true;
- }
-
- if (itemId == R.id.edit_bookmark) {
- new EditBookmarkDialog(this).show(id, title, url, keyword);
- return true;
- }
-
- if (itemId == R.id.remove_bookmark) {
- (new UiAsyncTask(ThreadUtils.getBackgroundHandler()) {
- private boolean mInReadingList;
-
- @Override
- public void onPreExecute() {
- mInReadingList = mAwesomeTabs.isInReadingList();
- }
-
- @Override
- public Integer doInBackground(Void... params) {
- BrowserDB.removeBookmark(getContentResolver(), id);
- Integer count = mInReadingList ?
- BrowserDB.getReadingListCount(getContentResolver()) : 0;
-
- return count;
- }
-
- @Override
- public void onPostExecute(Integer aCount) {
- int messageId = R.string.bookmark_removed;
- if (mInReadingList) {
- messageId = R.string.reading_list_removed;
-
- GeckoEvent e = GeckoEvent.createBroadcastEvent("Reader:Remove", url);
- GeckoAppShell.sendEventToGecko(e);
-
- // Delete from Awesomebar context menu can alter reading list bookmark count
- e = GeckoEvent.createBroadcastEvent("Reader:ListCountUpdated", Integer.toString(aCount));
- GeckoAppShell.sendEventToGecko(e);
- }
-
- Toast.makeText(AwesomeBar.this, messageId, Toast.LENGTH_SHORT).show();
- }
- }).execute();
-
- return true;
- }
-
- if (itemId == R.id.remove_history) {
- (new UiAsyncTask(ThreadUtils.getBackgroundHandler()) {
- @Override
- public Void doInBackground(Void... params) {
- BrowserDB.removeHistoryEntry(getContentResolver(), id);
- return null;
- }
-
- @Override
- public void onPostExecute(Void result) {
- Toast.makeText(AwesomeBar.this, R.string.history_removed, Toast.LENGTH_SHORT).show();
- }
- }).execute();
-
- return true;
- }
-
- if (itemId == R.id.add_to_launcher) {
- if (url == null) {
- Log.e(LOGTAG, "Can't add to home screen because URL is null");
- } else {
- Bitmap bitmap = null;
- if (b != null) {
- bitmap = BitmapUtils.decodeByteArray(b);
- }
-
- String shortcutTitle = TextUtils.isEmpty(title) ? url.replaceAll("^([a-z]+://)?(www\\.)?", "") : title;
- GeckoAppShell.createShortcut(shortcutTitle, url, bitmap, "");
- }
-
- return true;
- }
-
- if (itemId == R.id.share) {
- if (url == null) {
- Log.e(LOGTAG, "Can't share because URL is null");
- } else {
- GeckoAppShell.openUriExternal(url, "text/plain", "", "",
- Intent.ACTION_SEND, title);
- }
-
- return true;
- }
-
- return super.onContextItemSelected(item);
- }
-
- public static String getReaderForUrl(String url) {
- // FIXME: still need to define the final way to open items from
- // reading list. For now, we're using an about:reader page.
- return "about:reader?url=" + Uri.encode(url) + "&readingList=1";
- }
-
- private static boolean hasCompositionString(Editable content) {
- Object[] spans = content.getSpans(0, content.length(), Object.class);
- if (spans != null) {
- for (Object span : spans) {
- if ((content.getSpanFlags(span) & Spanned.SPAN_COMPOSING) != 0) {
- // Found composition string.
- return true;
- }
- }
- }
- return false;
- }
-
- // return early if we're backspacing through the string, or have no autocomplete results
- public void onAutocomplete(final String result) {
- final String text = mText.getText().toString();
-
- if (result == null) {
- mAutoCompleteResult = "";
- return;
- }
-
- if (!result.startsWith(text) || text.equals(result)) {
- return;
- }
-
- mAutoCompleteResult = result;
- mText.getText().append(result.substring(text.length()));
- mText.setSelection(text.length(), result.length());
- }
-
- @Override
- public void afterTextChanged(final Editable s) {
- final String text = s.toString();
- boolean useHandler = false;
- boolean reuseAutocomplete = false;
- if (!hasCompositionString(s) && !StringUtils.isSearchQuery(text, false)) {
- useHandler = true;
-
- // If you're hitting backspace (the string is getting smaller
- // or is unchanged), don't autocomplete.
- if (mAutoCompletePrefix != null && (mAutoCompletePrefix.length() >= text.length())) {
- useHandler = false;
- } else if (mAutoCompleteResult != null && mAutoCompleteResult.startsWith(text)) {
- // If this text already matches our autocomplete text, autocomplete likely
- // won't change. Just reuse the old autocomplete value.
- useHandler = false;
- reuseAutocomplete = true;
- }
- }
-
- // If this is the autocomplete text being set, don't run the filter.
- if (TextUtils.isEmpty(mAutoCompleteResult) || !mAutoCompleteResult.equals(text)) {
- mAwesomeTabs.filter(text, useHandler ? this : null);
- mAutoCompletePrefix = text;
-
- if (reuseAutocomplete) {
- onAutocomplete(mAutoCompleteResult);
- }
- }
-
- // If the AwesomeBar has a composition string, don't call updateGoButton().
- // That method resets IME and composition state will be broken.
- if (!hasCompositionString(s) ||
- InputMethods.isGestureKeyboard(mText.getContext())) {
- updateGoButton(text);
- }
- }
-
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count,
- int after) {
- // do nothing
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before,
- int count) {
- // do nothing
- }
-}
diff --git a/mobile/android/base/AwesomeBarTabs.java b/mobile/android/base/AwesomeBarTabs.java
deleted file mode 100644
index 2782c572890a..000000000000
--- a/mobile/android/base/AwesomeBarTabs.java
+++ /dev/null
@@ -1,381 +0,0 @@
-/* -*- 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;
-
-import android.content.Context;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.StateListDrawable;
-import android.support.v4.view.PagerAdapter;
-import android.support.v4.view.ViewPager;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TabHost;
-import android.widget.TabWidget;
-
-public class AwesomeBarTabs extends TabHost
- implements LightweightTheme.OnChangeListener {
- private static final String LOGTAG = "GeckoAwesomeBarTabs";
-
- private Context mContext;
- private GeckoActivity mActivity;
-
- private boolean mInflated;
- private LayoutInflater mInflater;
- private OnUrlOpenListener mUrlOpenListener;
- private View.OnTouchListener mListTouchListener;
- private boolean mSearching = false;
- private String mTarget;
- private ViewPager mViewPager;
- private AwesomePagerAdapter mPagerAdapter;
-
- private AwesomeBarTab mTabs[];
-
- public interface OnUrlOpenListener {
- public void onUrlOpen(String url, String title);
- public void onSearch(SearchEngine engine, String text);
- public void onEditSuggestion(String suggestion);
- public void onSwitchToTab(final int tabId);
- }
-
- private class AwesomePagerAdapter extends PagerAdapter {
- public AwesomePagerAdapter() {
- super();
- }
-
- @Override
- public Object instantiateItem(ViewGroup group, int index) {
- AwesomeBarTab tab = mTabs[index];
- group.addView(tab.getView());
- return tab;
- }
-
- @Override
- public void destroyItem(ViewGroup group, int index, Object obj) {
- AwesomeBarTab tab = (AwesomeBarTab)obj;
- group.removeView(tab.getView());
- }
-
- @Override
- public int getCount() {
- if (mSearching)
- return 1;
- return mTabs.length;
- }
-
- @Override
- public boolean isViewFromObject(View view, Object object) {
- return getAwesomeBarTabForView(view) == object;
- }
- }
-
- private AwesomeBarTab getCurrentAwesomeBarTab() {
- int index = mViewPager.getCurrentItem();
- return mTabs[index];
- }
-
- public AwesomeBarTab getAwesomeBarTabForView(View view) {
- String tag = (String)view.getTag();
- return getAwesomeBarTabForTag(tag);
- }
-
- public AwesomeBarTab getAwesomeBarTabForTag(String tag) {
- for (AwesomeBarTab tab : mTabs) {
- if (tag.equals(tab.getTag())) {
- return tab;
- }
- }
- return null;
- }
-
- public boolean onBackPressed() {
- AwesomeBarTab tab = getCurrentAwesomeBarTab();
- if (tab == null)
- return false;
- return tab.onBackPressed();
- }
-
- public AwesomeBarTabs(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- Log.d(LOGTAG, "Creating AwesomeBarTabs");
-
- mContext = context;
- mActivity = (GeckoActivity) context;
-
- mInflated = false;
- mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
-
- // HACK: Without this, the onFinishInflate is called twice
- // This issue is due to a bug when Android inflates a layout with a
- // parent. Fixed in Honeycomb
- if (mInflated)
- return;
-
- mInflated = true;
-
- // This should be called before adding any tabs
- // to the TabHost.
- setup();
-
- mListTouchListener = new View.OnTouchListener() {
- @Override
- public boolean onTouch(View view, MotionEvent event) {
- if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
- // take focus away from awesome bar to hide the keyboard
- requestFocus();
- }
- return false;
- }
- };
-
- mTabs = new AwesomeBarTab[] {
- new AllPagesTab(mContext),
- new BookmarksTab(mContext),
- new HistoryTab(mContext)
- };
-
- final TabWidget tabWidget = (TabWidget) findViewById(android.R.id.tabs);
- // hide the strip since we aren't using the TabHost...
- tabWidget.setStripEnabled(false);
-
- mViewPager = (ViewPager) findViewById(R.id.tabviewpager);
- mPagerAdapter = new AwesomePagerAdapter();
- mViewPager.setAdapter(mPagerAdapter);
-
- mViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
- @Override
- public void onPageScrollStateChanged(int state) { }
- @Override
- public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { }
- @Override
- public void onPageSelected(int position) {
- tabWidget.setCurrentTab(position);
- styleSelectedTab();
- // take focus away from awesome bar to hide the keyboard
- requestFocus();
- }
- });
-
- for (int i = 0; i < mTabs.length; i++) {
- mTabs[i].setListTouchListener(mListTouchListener);
- addAwesomeTab(mTabs[i].getTag(),
- mTabs[i].getTitleStringId(),
- i);
- }
-
- // Initialize "All Pages" list with no filter
- filter("", null);
- }
-
- @Override
- public void onAttachedToWindow() {
- super.onAttachedToWindow();
- mActivity.getLightweightTheme().addListener(this);
- }
-
- @Override
- public void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- mActivity.getLightweightTheme().removeListener(this);
- }
-
- @Override
- public void onLightweightThemeChanged() {
- styleSelectedTab();
- }
-
- @Override
- public void onLightweightThemeReset() {
- styleSelectedTab();
- }
-
- public void setCurrentItemByTag(String tag) {
- mViewPager.setCurrentItem(getTabIdByTag(tag));
- }
-
- public int getTabIdByTag(String tag) {
- for (int i = 0; i < mTabs.length; i++) {
- if (tag.equals(mTabs[i].getTag())) {
- return i;
- }
- }
- return -1;
- }
-
- private void styleSelectedTab() {
- int selIndex = mViewPager.getCurrentItem();
- TabWidget tabWidget = getTabWidget();
- boolean isPrivate = false;
-
- if (mTarget != null && mTarget.equals(AwesomeBar.Target.CURRENT_TAB.name())) {
- Tab tab = Tabs.getInstance().getSelectedTab();
- if (tab != null)
- isPrivate = tab.isPrivate();
- }
-
- for (int i = 0; i < tabWidget.getTabCount(); i++) {
- GeckoTextView view = (GeckoTextView) tabWidget.getChildTabViewAt(i);
- if (isPrivate) {
- view.resetTheme();
- view.setPrivateMode((i == selIndex) ? false : true);
- } else {
- if (i == selIndex)
- view.resetTheme();
- else if (mActivity.getLightweightTheme().isEnabled())
- view.setTheme(mActivity.getLightweightTheme().isLightTheme());
- else
- view.resetTheme();
- }
-
- if (i < (selIndex - 1))
- view.getBackground().setLevel(3);
- else if (i == (selIndex - 1))
- view.getBackground().setLevel(1);
- else if (i == (selIndex + 1))
- view.getBackground().setLevel(2);
- else if (i > (selIndex + 1))
- view.getBackground().setLevel(4);
- }
-
- if (selIndex == 0)
- findViewById(R.id.tab_widget_left).getBackground().setLevel(1);
- else
- findViewById(R.id.tab_widget_left).getBackground().setLevel(0);
-
- if (selIndex == (tabWidget.getTabCount() - 1))
- findViewById(R.id.tab_widget_right).getBackground().setLevel(2);
- else
- findViewById(R.id.tab_widget_right).getBackground().setLevel(0);
- }
-
-
- private View addAwesomeTab(String id, int titleId, final int contentId) {
- GeckoTextView indicatorView = (GeckoTextView) mInflater.inflate(R.layout.awesomebar_tab_indicator, null);
- indicatorView.setText(titleId);
-
- getTabWidget().addView(indicatorView);
-
- // this MUST be done after tw.addView to overwrite the listener added by tabWidget
- // which delegates to TabHost (which we don't have)
- indicatorView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- mViewPager.setCurrentItem(contentId, true);
- }
- });
-
- return indicatorView;
- }
-
- public void setOnUrlOpenListener(OnUrlOpenListener listener) {
- mUrlOpenListener = listener;
- for (AwesomeBarTab tab : mTabs) {
- tab.setUrlListener(listener);
- }
- }
-
- public void destroy() {
- for (AwesomeBarTab tab : mTabs) {
- tab.destroy();
- }
- }
-
- public AllPagesTab getAllPagesTab() {
- return (AllPagesTab)getAwesomeBarTabForTag("allPages");
- }
-
- public BookmarksTab getBookmarksTab() {
- return (BookmarksTab)getAwesomeBarTabForTag("bookmarks");
- }
-
- public HistoryTab getHistoryTab() {
- return (HistoryTab)getAwesomeBarTabForTag("history");
- }
-
- public void filter(String searchTerm, AutocompleteHandler handler) {
-
- // If searching, disable left / right tab swipes
- mSearching = searchTerm.length() != 0;
-
- // reset the pager adapter to force repopulating the cache
- mViewPager.setAdapter(mPagerAdapter);
-
- // Ensure the 'All Pages' tab is selected
- AllPagesTab allPages = getAllPagesTab();
- getTabWidget().setCurrentTab(getTabIdByTag(allPages.getTag()));
- styleSelectedTab();
-
- // Perform the actual search
- allPages.filter(searchTerm, handler);
-
- // If searching, hide the tabs bar
- findViewById(R.id.tab_widget_container).setVisibility(mSearching ? View.GONE : View.VISIBLE);
- }
-
- public boolean isInReadingList() {
- return getBookmarksTab().isInReadingList();
- }
-
- public void setTarget(String target) {
- mTarget = target;
- styleSelectedTab();
- if (mTarget.equals(AwesomeBar.Target.CURRENT_TAB.name())) {
- Tab tab = Tabs.getInstance().getSelectedTab();
- if (tab != null && tab.isPrivate())
- ((BackgroundLayout) findViewById(R.id.tab_widget_container)).setPrivateMode(true);
- }
- }
-
- public static class BackgroundLayout extends GeckoLinearLayout {
- private GeckoActivity mActivity;
-
- public BackgroundLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- mActivity = (GeckoActivity) context;
- }
-
- @Override
- public void onLightweightThemeChanged() {
- LightweightThemeDrawable drawable = mActivity.getLightweightTheme().getColorDrawable(this);
- if (drawable == null)
- return;
-
- drawable.setAlpha(255, 0);
-
- StateListDrawable stateList = new StateListDrawable();
- stateList.addState(new int[] { R.attr.state_private }, new ColorDrawable(mActivity.getResources().getColor(R.color.background_private)));
- stateList.addState(new int[] {}, drawable);
-
- int[] padding = new int[] { getPaddingLeft(),
- getPaddingTop(),
- getPaddingRight(),
- getPaddingBottom()
- };
- setBackgroundDrawable(stateList);
- setPadding(padding[0], padding[1], padding[2], padding[3]);
- }
-
- @Override
- public void onLightweightThemeReset() {
- int[] padding = new int[] { getPaddingLeft(),
- getPaddingTop(),
- getPaddingRight(),
- getPaddingBottom()
- };
- setBackgroundResource(R.drawable.address_bar_bg);
- setPadding(padding[0], padding[1], padding[2], padding[3]);
- }
- }
-}
diff --git a/mobile/android/base/AwesomebarResultHandler.java b/mobile/android/base/AwesomebarResultHandler.java
deleted file mode 100644
index c91b594d70b0..000000000000
--- a/mobile/android/base/AwesomebarResultHandler.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/* 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;
-
-import org.mozilla.gecko.util.ActivityResultHandler;
-
-import android.content.Intent;
-import android.util.Log;
-
-class AwesomebarResultHandler implements ActivityResultHandler {
- private static final String LOGTAG = "GeckoAwesomebarResultHandler";
-
- @Override
- public void onActivityResult(int resultCode, Intent data) {
- if (data != null) {
- String tab = data.getStringExtra(AwesomeBar.TAB_KEY);
- if (tab != null) {
- Tabs.getInstance().selectTab(Integer.parseInt(tab));
- return;
- }
-
- String url = data.getStringExtra(AwesomeBar.URL_KEY);
- AwesomeBar.Target target = AwesomeBar.Target.valueOf(data.getStringExtra(AwesomeBar.TARGET_KEY));
- String searchEngine = data.getStringExtra(AwesomeBar.SEARCH_KEY);
- if (url != null && url.length() > 0) {
- int flags = Tabs.LOADURL_NONE;
- if (target == AwesomeBar.Target.NEW_TAB) {
- flags |= Tabs.LOADURL_NEW_TAB;
- }
- if (data.getBooleanExtra(AwesomeBar.USER_ENTERED_KEY, false)) {
- flags |= Tabs.LOADURL_USER_ENTERED;
- }
- Tabs.getInstance().loadUrl(url, searchEngine, -1, flags);
- }
- }
- }
-}
diff --git a/mobile/android/base/BackButton.java b/mobile/android/base/BackButton.java
index 7f7a25eefb96..763d606df913 100644
--- a/mobile/android/base/BackButton.java
+++ b/mobile/android/base/BackButton.java
@@ -73,7 +73,7 @@ public class BackButton extends ShapedButton {
canvas.drawPath(mBorderPath, isPrivateMode() ? mBorderPrivatePaint : mBorderPaint);
}
- // The drawable is constructed as per @drawable/address_bar_nav_button.
+ // The drawable is constructed as per @drawable/url_bar_nav_button.
@Override
public void onLightweightThemeChanged() {
Drawable drawable = mActivity.getLightweightTheme().getDrawable(this);
@@ -95,6 +95,6 @@ public class BackButton extends ShapedButton {
@Override
public void onLightweightThemeReset() {
- setBackgroundResource(R.drawable.address_bar_nav_button);
+ setBackgroundResource(R.drawable.url_bar_nav_button);
}
}
diff --git a/mobile/android/base/BrowserApp.java b/mobile/android/base/BrowserApp.java
index 0c0ae7514be7..6183540fba0b 100644
--- a/mobile/android/base/BrowserApp.java
+++ b/mobile/android/base/BrowserApp.java
@@ -14,6 +14,9 @@ import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
import org.mozilla.gecko.gfx.LayerView;
import org.mozilla.gecko.gfx.PanZoomController;
import org.mozilla.gecko.health.BrowserHealthReporter;
+import org.mozilla.gecko.home.BrowserSearch;
+import org.mozilla.gecko.home.HomePager;
+import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
import org.mozilla.gecko.menu.GeckoMenu;
import org.mozilla.gecko.util.Clipboard;
import org.mozilla.gecko.util.FloatUtils;
@@ -21,7 +24,6 @@ import org.mozilla.gecko.util.GamepadUtils;
import org.mozilla.gecko.util.HardwareUtils;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.util.UiAsyncTask;
-import org.mozilla.gecko.widget.AboutHome;
import org.mozilla.gecko.widget.GeckoActionProvider;
import org.mozilla.gecko.widget.ButtonToast;
@@ -49,6 +51,8 @@ import android.nfc.NfcAdapter;
import android.nfc.NfcEvent;
import android.os.Build;
import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
import android.text.TextUtils;
import android.util.Log;
import android.view.InputDevice;
@@ -70,6 +74,7 @@ import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.util.EnumSet;
+import java.util.List;
import java.util.Vector;
abstract public class BrowserApp extends GeckoApp
@@ -77,8 +82,10 @@ abstract public class BrowserApp extends GeckoApp
PropertyAnimator.PropertyAnimationListener,
View.OnKeyListener,
GeckoLayerClient.OnMetricsChangedListener,
- AboutHome.UriLoadListener,
- AboutHome.LoadCompleteListener {
+ BrowserSearch.OnSearchListener,
+ BrowserSearch.OnEditSuggestionListener,
+ HomePager.OnNewTabsListener,
+ OnUrlOpenListener {
private static final String LOGTAG = "GeckoBrowserApp";
private static final String PREF_CHROME_DYNAMICTOOLBAR = "browser.chrome.dynamictoolbar";
@@ -96,8 +103,13 @@ abstract public class BrowserApp extends GeckoApp
private static final String STATE_ABOUT_HOME_TOP_PADDING = "abouthome_top_padding";
private static final String STATE_DYNAMIC_TOOLBAR_ENABLED = "dynamic_toolbar";
+ private static final String BROWSER_SEARCH_TAG = "browser_search";
+ private BrowserSearch mBrowserSearch;
+ private View mBrowserSearchContainer;
+
public static BrowserToolbar mBrowserToolbar;
- private AboutHome mAboutHome;
+ private HomePager mHomePager;
+ private View mHomePagerContainer;
protected Telemetry.Timer mAboutHomeStartupTimer = null;
// Set the default session restore value
@@ -152,10 +164,6 @@ abstract public class BrowserApp extends GeckoApp
private Integer mPrefObserverId;
- // Tag for the AboutHome fragment. The fragment is automatically attached
- // after restoring from a saved state, so we use this tag to identify it.
- private static final String ABOUTHOME_TAG = "abouthome";
-
private SharedPreferencesHelper mSharedPreferencesHelper;
private OrderedBroadcastHelper mOrderedBroadcastHelper;
@@ -182,14 +190,14 @@ abstract public class BrowserApp extends GeckoApp
case SELECTED:
if (Tabs.getInstance().isSelectedTab(tab)) {
if (isAboutHome(tab)) {
- showAboutHome();
+ showHomePager(tab.getAboutHomePage());
if (isDynamicToolbarEnabled()) {
// Show the toolbar.
mLayerView.getLayerMarginsAnimator().showMargins(false);
}
} else {
- hideAboutHome();
+ hideHomePager();
}
if (mSiteIdentityPopup != null)
@@ -242,12 +250,6 @@ abstract public class BrowserApp extends GeckoApp
super.onTabChanged(tab, msg, data);
}
- @Override
- void handleClearHistory() {
- super.handleClearHistory();
- updateAboutHomeTopSites();
- }
-
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
// Global onKey handler. This is called if the focused UI doesn't
@@ -263,7 +265,7 @@ abstract public class BrowserApp extends GeckoApp
case KeyEvent.KEYCODE_BUTTON_Y:
// Toggle/focus the address bar on gamepad-y button.
if (mBrowserToolbar.isVisible()) {
- if (isDynamicToolbarEnabled() && !mAboutHome.getUserVisibleHint()) {
+ if (isDynamicToolbarEnabled() && !mHomePager.isVisible()) {
if (mLayerView != null) {
mLayerView.getLayerMarginsAnimator().hideMargins(false);
mLayerView.requestFocus();
@@ -330,7 +332,11 @@ abstract public class BrowserApp extends GeckoApp
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (onKey(null, keyCode, event)) {
+ if (!mBrowserToolbar.isEditing() && onKey(null, keyCode, event)) {
+ return true;
+ }
+
+ if (mBrowserToolbar.onKey(keyCode, event)) {
return true;
}
@@ -383,19 +389,6 @@ abstract public class BrowserApp extends GeckoApp
});
}
- @Override
- void onStatePurged() {
- ThreadUtils.postToUiThread(new Runnable() {
- @Override
- public void run() {
- if (mAboutHome != null)
- mAboutHome.setLastTabsVisibility(false);
- }
- });
-
- super.onStatePurged();
- }
-
@Override
protected int getSessionRestoreState(Bundle savedInstanceState) {
if (mSessionRestore > -1) {
@@ -427,29 +420,50 @@ abstract public class BrowserApp extends GeckoApp
// If we get a gamepad panning MotionEvent while the focus is not on the layerview,
// put the focus on the layerview and carry on
if (mLayerView != null && !mLayerView.hasFocus() && GamepadUtils.isPanningControl(event)) {
- if (mAboutHome.getUserVisibleHint()) {
- mAboutHome.requestFocus();
- } else {
+ if (mHomePager.isVisible()) {
mLayerView.requestFocus();
+ } else {
+ mHomePager.requestFocus();
}
}
return false;
}
});
- // Find the Fragment if it was already added from a restored instance state.
- mAboutHome = (AboutHome) getSupportFragmentManager().findFragmentByTag(ABOUTHOME_TAG);
+ mHomePager = (HomePager) findViewById(R.id.home_pager);
+ mHomePagerContainer = findViewById(R.id.home_pager_container);
- if (mAboutHome == null) {
- // AboutHome will be dynamically attached and detached as
- // about:home is shown. Adding/removing the fragment is not synchronous,
- // so we can't use Fragment#isVisible() to determine whether the
- // about:home is shown. Instead, we use Fragment#getUserVisibleHint()
- // with the hint we set ourselves.
- mAboutHome = AboutHome.newInstance();
- mAboutHome.setUserVisibleHint(false);
+ mBrowserSearchContainer = findViewById(R.id.search_container);
+ mBrowserSearch = (BrowserSearch) getSupportFragmentManager().findFragmentByTag(BROWSER_SEARCH_TAG);
+ if (mBrowserSearch == null) {
+ mBrowserSearch = BrowserSearch.newInstance();
+ mBrowserSearch.setUserVisibleHint(false);
}
+ mBrowserToolbar.setOnActivateListener(new BrowserToolbar.OnActivateListener() {
+ public void onActivate() {
+ enterEditingMode();
+ }
+ });
+
+ mBrowserToolbar.setOnCommitListener(new BrowserToolbar.OnCommitListener() {
+ public void onCommit() {
+ commitEditingMode();
+ }
+ });
+
+ mBrowserToolbar.setOnDismissListener(new BrowserToolbar.OnDismissListener() {
+ public void onDismiss() {
+ dismissEditingMode();
+ }
+ });
+
+ mBrowserToolbar.setOnFilterListener(new BrowserToolbar.OnFilterListener() {
+ public void onFilter(String searchText, AutocompleteHandler handler) {
+ filterEditingMode(searchText, handler);
+ }
+ });
+
// Intercept key events for gamepad shortcuts
mBrowserToolbar.setOnKeyListener(this);
@@ -468,6 +482,7 @@ abstract public class BrowserApp extends GeckoApp
registerEventListener("Telemetry:Gather");
registerEventListener("Settings:Show");
registerEventListener("Updater:Launch");
+ registerEventListener("Reader:GoToReadingList");
Distribution.init(this, getPackageResourcePath());
JavaAddonManager.getInstance().init(getApplicationContext());
@@ -493,7 +508,7 @@ abstract public class BrowserApp extends GeckoApp
if (savedInstanceState != null) {
mDynamicToolbarEnabled = savedInstanceState.getBoolean(STATE_DYNAMIC_TOOLBAR_ENABLED);
- mAboutHome.setTopPadding(savedInstanceState.getInt(STATE_ABOUT_HOME_TOP_PADDING));
+ mHomePagerContainer.setPadding(0, savedInstanceState.getInt(STATE_ABOUT_HOME_TOP_PADDING), 0, 0);
}
// Listen to the dynamic toolbar pref
@@ -526,6 +541,25 @@ abstract public class BrowserApp extends GeckoApp
});
}
+ @Override
+ public void onBackPressed() {
+ if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
+ super.onBackPressed();
+ return;
+ }
+
+ if (dismissEditingMode()) {
+ return;
+ }
+
+ if (mSiteIdentityPopup != null && mSiteIdentityPopup.isShowing()) {
+ mSiteIdentityPopup.dismiss();
+ return;
+ }
+
+ super.onBackPressed();
+ }
+
@Override
public void onResume() {
super.onResume();
@@ -539,8 +573,6 @@ abstract public class BrowserApp extends GeckoApp
registerEventListener("Prompt:ShowTop");
}
-
-
private void showBookmarkDialog() {
final Tab tab = Tabs.getInstance().getSelectedTab();
final Prompt ps = new Prompt(this, new Prompt.PromptCallback() {
@@ -583,14 +615,14 @@ abstract public class BrowserApp extends GeckoApp
mLayerView.getLayerClient().setOnMetricsChangedListener(this);
}
setToolbarMargin(0);
- mAboutHome.setTopPadding(mBrowserToolbar.getHeight());
+ mHomePagerContainer.setPadding(0, mBrowserToolbar.getHeight(), 0, 0);
} else {
// Immediately show the toolbar when disabling the dynamic
// toolbar.
if (mLayerView != null) {
mLayerView.getLayerClient().setOnMetricsChangedListener(null);
}
- mAboutHome.setTopPadding(0);
+ mHomePagerContainer.setPadding(0, 0, 0, 0);
if (mBrowserToolbar != null) {
mBrowserToolbar.scrollTo(0, 0);
}
@@ -609,7 +641,8 @@ abstract public class BrowserApp extends GeckoApp
@Override
public boolean onSearchRequested() {
- return showAwesomebar(AwesomeBar.Target.CURRENT_TAB);
+ enterEditingMode();
+ return true;
}
@Override
@@ -631,7 +664,7 @@ abstract public class BrowserApp extends GeckoApp
if (itemId == R.id.paste) {
String text = Clipboard.getText();
if (!TextUtils.isEmpty(text)) {
- showAwesomebar(AwesomeBar.Target.CURRENT_TAB, text);
+ enterEditingMode(text);
}
return true;
}
@@ -690,41 +723,6 @@ abstract public class BrowserApp extends GeckoApp
return false;
}
- public boolean showAwesomebar(AwesomeBar.Target aTarget) {
- return showAwesomebar(aTarget, null);
- }
-
- public boolean showAwesomebar(AwesomeBar.Target aTarget, String aUrl) {
- Intent intent = new Intent(getBaseContext(), AwesomeBar.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
- intent.putExtra(AwesomeBar.TARGET_KEY, aTarget.name());
-
- // If we were passed in a URL, show it.
- if (aUrl != null && !TextUtils.isEmpty(aUrl)) {
- intent.putExtra(AwesomeBar.CURRENT_URL_KEY, aUrl);
- } else if (aTarget == AwesomeBar.Target.CURRENT_TAB) {
- // Otherwise, if we're editing the current tab, show its URL.
- Tab tab = Tabs.getInstance().getSelectedTab();
- if (tab != null) {
- // Check to see if there's a user-entered search term, which we save
- // whenever the user performs a search.
- aUrl = tab.getUserSearch();
- if (TextUtils.isEmpty(aUrl)) {
- aUrl = tab.getURL();
- }
- if (aUrl != null) {
- intent.putExtra(AwesomeBar.CURRENT_URL_KEY, aUrl);
- }
- }
- }
-
- int requestCode = GeckoAppShell.sActivityHelper.makeRequestCodeForAwesomebar();
- startActivityForResult(intent, requestCode);
- overridePendingTransition (R.anim.awesomebar_fade_in, R.anim.awesomebar_hold_still);
- return true;
- }
-
-
@Override
public void setAccessibilityEnabled(boolean enabled) {
if (mAccessibilityEnabled == enabled) {
@@ -776,6 +774,7 @@ abstract public class BrowserApp extends GeckoApp
unregisterEventListener("Telemetry:Gather");
unregisterEventListener("Settings:Show");
unregisterEventListener("Updater:Launch");
+ unregisterEventListener("Reader:GoToReadingList");
if (AppConstants.MOZ_ANDROID_BEAM && Build.VERSION.SDK_INT >= 14) {
NfcAdapter nfc = NfcAdapter.getDefaultAdapter(this);
@@ -843,7 +842,7 @@ abstract public class BrowserApp extends GeckoApp
@Override
public void onMetricsChanged(ImmutableViewportMetrics aMetrics) {
- if (mAboutHome.getUserVisibleHint() || mBrowserToolbar == null) {
+ if (mHomePager.isVisible() || mBrowserToolbar == null) {
return;
}
@@ -878,7 +877,7 @@ abstract public class BrowserApp extends GeckoApp
@Override
public void onPanZoomStopped() {
- if (!isDynamicToolbarEnabled() || mAboutHome.getUserVisibleHint()) {
+ if (!isDynamicToolbarEnabled() || mHomePager.isVisible()) {
return;
}
@@ -900,12 +899,19 @@ abstract public class BrowserApp extends GeckoApp
height = mBrowserToolbar.getHeight();
}
- if (!isDynamicToolbarEnabled()) {
+ if (!isDynamicToolbarEnabled() || mHomePager.isVisible()) {
// Use aVisibleHeight here so that when the dynamic toolbar is
// enabled, the padding will animate with the toolbar becoming
// visible.
- setToolbarMargin(height);
- height = 0;
+ if (isDynamicToolbarEnabled()) {
+ // When the dynamic toolbar is enabled, set the padding on the
+ // about:home widget directly - this is to avoid resizing the
+ // LayerView, which can cause visible artifacts.
+ mHomePagerContainer.setPadding(0, height, 0, 0);
+ } else {
+ setToolbarMargin(height);
+ height = 0;
+ }
} else {
setToolbarMargin(0);
}
@@ -957,37 +963,11 @@ abstract public class BrowserApp extends GeckoApp
}
}
- @Override
- public void onBackPressed() {
- if (mSiteIdentityPopup != null && mSiteIdentityPopup.isShowing()) {
- mSiteIdentityPopup.dismiss();
- return;
- }
-
- super.onBackPressed();
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- String url = null;
-
- // Don't update the url in the toolbar if the activity was cancelled.
- if (resultCode == Activity.RESULT_OK && data != null) {
- // Don't update the url if the activity was launched to pick a site.
- String targetKey = data.getStringExtra(AwesomeBar.TARGET_KEY);
- if (!AwesomeBar.Target.PICK_SITE.toString().equals(targetKey)) {
- // Update the toolbar with the url that was just entered.
- url = data.getStringExtra(AwesomeBar.URL_KEY);
- }
- }
-
- // We always need to call fromAwesomeBarSearch to perform the toolbar animation.
- mBrowserToolbar.fromAwesomeBarSearch(url);
-
- // Trigger any tab-related events after we start restoring
- // the toolbar state above to make ensure animations happen
- // on the correct order.
- super.onActivityResult(requestCode, resultCode, data);
+ public View getActionBarLayout() {
+ RelativeLayout actionBar = (RelativeLayout) LayoutInflater.from(this).inflate(R.layout.browser_toolbar, null);
+ actionBar.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT,
+ (int) getResources().getDimension(R.dimen.browser_toolbar_height)));
+ return actionBar;
}
@Override
@@ -1155,6 +1135,8 @@ abstract public class BrowserApp extends GeckoApp
startActivity(settingsIntent);
} else if (event.equals("Updater:Launch")) {
handleUpdaterLaunch();
+ } else if (event.equals("Reader:GoToReadingList")) {
+ openReadingList();
} else if (event.equals("Prompt:ShowTop")) {
// Bring this activity to front so the prompt is visible..
Intent bringToFrontIntent = new Intent();
@@ -1171,7 +1153,7 @@ abstract public class BrowserApp extends GeckoApp
@Override
public void addTab() {
- showAwesomebar(AwesomeBar.Target.NEW_TAB);
+ Tabs.getInstance().loadUrl("about:home", Tabs.LOADURL_NEW_TAB);
}
@Override
@@ -1234,7 +1216,7 @@ abstract public class BrowserApp extends GeckoApp
}
mMainLayoutAnimator = new PropertyAnimator(animationLength, sTabsInterpolator);
- mMainLayoutAnimator.setPropertyAnimationListener(this);
+ mMainLayoutAnimator.addPropertyAnimationListener(this);
if (hasTabsSideBar()) {
mMainLayoutAnimator.attach(mMainLayout,
@@ -1284,7 +1266,66 @@ abstract public class BrowserApp extends GeckoApp
super.onSaveInstanceState(outState);
mToast.onSaveInstanceState(outState);
outState.putBoolean(STATE_DYNAMIC_TOOLBAR_ENABLED, mDynamicToolbarEnabled);
- outState.putInt(STATE_ABOUT_HOME_TOP_PADDING, mAboutHome.getTopPadding());
+ outState.putInt(STATE_ABOUT_HOME_TOP_PADDING, mHomePagerContainer.getPaddingTop());
+ }
+
+ /**
+ * Attempts to switch to an open tab with the given URL.
+ *
+ * @return true if we successfully switched to a tab, false otherwise.
+ */
+ private boolean maybeSwitchToTab(String url, EnumSet flags) {
+ if (!flags.contains(OnUrlOpenListener.Flags.ALLOW_SWITCH_TO_TAB)) {
+ return false;
+ }
+
+ final Tabs tabs = Tabs.getInstance();
+ final int tabId = tabs.getTabIdForUrl(url);
+ if (tabId < 0) {
+ return false;
+ }
+
+ // If this tab is already selected, just hide the home pager.
+ if (tabs.isSelectedTab(tabs.getTab(tabId))) {
+ hideHomePager();
+ } else {
+ tabs.selectTab(tabId);
+ }
+
+ hideBrowserSearch();
+ mBrowserToolbar.cancelEdit();
+
+ return true;
+ }
+
+ private void openUrl(String url) {
+ openUrl(url, null, false);
+ }
+
+ private void openUrl(String url, boolean newTab) {
+ openUrl(url, null, newTab);
+ }
+
+ private void openUrl(String url, String searchEngine) {
+ openUrl(url, searchEngine, false);
+ }
+
+ private void openUrl(String url, String searchEngine, boolean newTab) {
+ mBrowserToolbar.setProgressVisibility(true);
+
+ int flags = Tabs.LOADURL_NONE;
+ if (newTab) {
+ flags |= Tabs.LOADURL_NEW_TAB;
+ }
+
+ Tabs.getInstance().loadUrl(url, searchEngine, -1, flags);
+
+ hideBrowserSearch();
+ mBrowserToolbar.cancelEdit();
+ }
+
+ private void openReadingList() {
+ Tabs.getInstance().loadUrl(ABOUT_HOME, Tabs.LOADURL_READING_LIST);
}
/* Favicon methods */
@@ -1330,14 +1371,80 @@ abstract public class BrowserApp extends GeckoApp
tab.setFaviconLoadId(Favicons.NOT_LOADING);
}
+ private void enterEditingMode() {
+ String url = null;
- /* About:home UI */
- void updateAboutHomeTopSites() {
- mAboutHome.update(EnumSet.of(AboutHome.UpdateFlags.TOP_SITES));
+ final Tab tab = Tabs.getInstance().getSelectedTab();
+ if (tab != null) {
+ final String userSearch = tab.getUserSearch();
+
+ // Check to see if there's a user-entered search term,
+ // which we save whenever the user performs a search.
+ url = (TextUtils.isEmpty(userSearch) ? tab.getURL() : userSearch);
+ }
+
+ enterEditingMode(url);
}
- private void showAboutHome() {
- if (mAboutHome.getUserVisibleHint()) {
+ /**
+ * Enters editing mode for the current tab. This method will
+ * always open the VISITED page on about:home.
+ */
+ private void enterEditingMode(String url) {
+ if (url == null) {
+ throw new IllegalArgumentException("Cannot handle null URLs in enterEditingMode");
+ }
+
+ final PropertyAnimator animator = new PropertyAnimator(250);
+ animator.setUseHardwareLayer(false);
+
+ mBrowserToolbar.startEditing(url, animator);
+ showHomePagerWithAnimator(HomePager.Page.HISTORY, animator);
+
+ animator.start();
+ }
+
+ void commitEditingMode() {
+ if (!mBrowserToolbar.isEditing()) {
+ return;
+ }
+
+ final String url = mBrowserToolbar.commitEdit();
+ animateHideHomePager();
+ hideBrowserSearch();
+
+ if (!TextUtils.isEmpty(url)) {
+ Tabs.getInstance().loadUrl(url, Tabs.LOADURL_USER_ENTERED);
+ }
+ }
+
+ boolean dismissEditingMode() {
+ if (!mBrowserToolbar.isEditing()) {
+ return false;
+ }
+
+ mBrowserToolbar.cancelEdit();
+ animateHideHomePager();
+ hideBrowserSearch();
+
+ return true;
+ }
+
+ void filterEditingMode(String searchTerm, AutocompleteHandler handler) {
+ if (TextUtils.isEmpty(searchTerm)) {
+ hideBrowserSearch();
+ } else {
+ showBrowserSearch();
+ mBrowserSearch.filter(searchTerm, handler);
+ }
+ }
+
+ private void showHomePager(HomePager.Page page) {
+ showHomePagerWithAnimator(page, null);
+ }
+
+ private void showHomePagerWithAnimator(HomePager.Page page, PropertyAnimator animator) {
+ if (mHomePager.isVisible()) {
return;
}
@@ -1350,29 +1457,29 @@ abstract public class BrowserApp extends GeckoApp
mLayerView.getLayerMarginsAnimator().showMargins(true);
}
- // We use commitAllowingStateLoss() instead of commit() here to avoid an
- // IllegalStateException. showAboutHome() and hideAboutHome() are
- // executed inside of tab's onChange() callback. Since that callback can
- // be triggered asynchronously from Gecko, it's possible that this
- // method can be called while Fennec is in the background. If that
- // happens, using commit() would throw an IllegalStateException since
- // it can't be used between the Activity's onSaveInstanceState() and
- // onResume().
- getSupportFragmentManager().beginTransaction()
- .add(R.id.gecko_layout, mAboutHome, ABOUTHOME_TAG).commitAllowingStateLoss();
- mAboutHome.setUserVisibleHint(true);
-
- mBrowserToolbar.setNextFocusDownId(R.id.abouthome_content);
+ mHomePager.show(getSupportFragmentManager(), page, animator);
}
- private void hideAboutHome() {
- if (!mAboutHome.getUserVisibleHint()) {
+ private void animateHideHomePager() {
+ hideHomePagerWithAnimation(true);
+ }
+
+ private void hideHomePager() {
+ hideHomePagerWithAnimation(false);
+ }
+
+ private void hideHomePagerWithAnimation(boolean animate) {
+ if (!mHomePager.isVisible()) {
return;
}
- getSupportFragmentManager().beginTransaction()
- .remove(mAboutHome).commitAllowingStateLoss();
- mAboutHome.setUserVisibleHint(false);
+ final Tab tab = Tabs.getInstance().getSelectedTab();
+ if (tab != null && isAboutHome(tab)) {
+ return;
+ }
+
+ // FIXME: do animation if animate is true
+ mHomePager.hide();
mBrowserToolbar.setShadowVisibility(true);
mBrowserToolbar.setNextFocusDownId(R.id.layer_view);
@@ -1381,6 +1488,30 @@ abstract public class BrowserApp extends GeckoApp
refreshToolbarHeight();
}
+ private void showBrowserSearch() {
+ if (mBrowserSearch.getUserVisibleHint()) {
+ return;
+ }
+
+ mBrowserSearchContainer.setVisibility(View.VISIBLE);
+
+ getSupportFragmentManager().beginTransaction()
+ .add(R.id.search_container, mBrowserSearch, BROWSER_SEARCH_TAG).commitAllowingStateLoss();
+ mBrowserSearch.setUserVisibleHint(true);
+ }
+
+ private void hideBrowserSearch() {
+ if (!mBrowserSearch.getUserVisibleHint()) {
+ return;
+ }
+
+ mBrowserSearchContainer.setVisibility(View.INVISIBLE);
+
+ getSupportFragmentManager().beginTransaction()
+ .remove(mBrowserSearch).commitAllowingStateLoss();
+ mBrowserSearch.setUserVisibleHint(false);
+ }
+
private class HideTabsTouchListener implements TouchEventInterceptor {
private boolean mIsHidingTabs = false;
@@ -1994,15 +2125,32 @@ abstract public class BrowserApp extends GeckoApp
}).execute();
}
+ // HomePager.OnNewTabsListener
@Override
- public void onAboutHomeUriLoad(String url) {
- mBrowserToolbar.setProgressVisibility(true);
- Tabs.getInstance().loadUrl(url);
+ public void onNewTabs(String[] urls) {
+ for (String url : urls) {
+ openUrl(url, true);
+ }
}
+ // HomePager.OnUrlOpenListener
@Override
- public void onAboutHomeLoadComplete() {
- mAboutHomeStartupTimer.stop();
+ public void onUrlOpen(String url, EnumSet flags) {
+ if (!maybeSwitchToTab(url, flags)) {
+ openUrl(url);
+ }
+ }
+
+ // BrowserSearch.OnSearchListener
+ @Override
+ public void onSearch(String engineId, String text) {
+ openUrl(text, engineId);
+ }
+
+ // BrowserSearch.OnEditSuggestionListener
+ @Override
+ public void onEditSuggestion(String suggestion) {
+ mBrowserToolbar.onEditSuggestion(suggestion);
}
@Override
diff --git a/mobile/android/base/BrowserToolbar.java b/mobile/android/base/BrowserToolbar.java
index dcb521f540d1..d2ff3ffd6eec 100644
--- a/mobile/android/base/BrowserToolbar.java
+++ b/mobile/android/base/BrowserToolbar.java
@@ -9,6 +9,7 @@ import org.mozilla.gecko.animation.PropertyAnimator;
import org.mozilla.gecko.animation.ViewHelper;
import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
import org.mozilla.gecko.gfx.LayerView;
+import org.mozilla.gecko.util.GamepadUtils;
import org.mozilla.gecko.menu.GeckoMenu;
import org.mozilla.gecko.menu.MenuPopup;
import org.mozilla.gecko.PageActionLayout;
@@ -34,12 +35,17 @@ import android.graphics.drawable.StateListDrawable;
import android.os.Build;
import android.os.SystemClock;
import android.text.style.ForegroundColorSpan;
+import android.text.Editable;
+import android.text.InputType;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
+import android.text.Spanned;
import android.text.TextUtils;
+import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.Log;
import android.view.ContextMenu;
+import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MenuInflater;
import android.view.MotionEvent;
@@ -54,8 +60,10 @@ import android.view.animation.AnimationUtils;
import android.view.animation.AlphaAnimation;
import android.view.animation.Interpolator;
import android.view.animation.TranslateAnimation;
+import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
+import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -68,17 +76,38 @@ import java.util.Arrays;
import java.util.List;
public class BrowserToolbar extends GeckoRelativeLayout
- implements Tabs.OnTabsChangedListener,
+ implements TextWatcher,
+ AutocompleteHandler,
+ Tabs.OnTabsChangedListener,
GeckoMenu.ActionItemBarPresenter,
Animation.AnimationListener,
GeckoEventListener {
private static final String LOGTAG = "GeckoToolbar";
public static final String PREF_TITLEBAR_MODE = "browser.chrome.titlebarMode";
+
+ public interface OnActivateListener {
+ public void onActivate();
+ }
+
+ public interface OnCommitListener {
+ public void onCommit();
+ }
+
+ public interface OnDismissListener {
+ public void onDismiss();
+ }
+
+ public interface OnFilterListener {
+ public void onFilter(String searchText, AutocompleteHandler handler);
+ }
+
private LayoutParams mAwesomeBarParams;
private View mUrlDisplayContainer;
- private View mAwesomeBarEntry;
- private ImageView mAwesomeBarRightEdge;
- private BrowserToolbarBackground mAddressBarBg;
+ private View mUrlEditContainer;
+ private CustomEditText mUrlEditText;
+ private View mUrlBarEntry;
+ private ImageView mUrlBarRightEdge;
+ private BrowserToolbarBackground mUrlBarBackground;
private GeckoTextView mTitle;
private int mTitlePadding;
private boolean mSiteSecurityVisible;
@@ -89,6 +118,7 @@ public class BrowserToolbar extends GeckoRelativeLayout
public ImageButton mFavicon;
public ImageButton mStop;
public ImageButton mSiteSecurity;
+ public ImageButton mGo;
public PageActionLayout mPageActionLayout;
private Animation mProgressSpinner;
private TabCounter mTabsCounter;
@@ -98,6 +128,10 @@ public class BrowserToolbar extends GeckoRelativeLayout
private LinearLayout mActionItemBar;
private MenuPopup mMenuPopup;
private List extends View> mFocusOrder;
+ private OnActivateListener mActivateListener;
+ private OnCommitListener mCommitListener;
+ private OnDismissListener mDismissListener;
+ private OnFilterListener mFilterListener;
final private BrowserApp mActivity;
private boolean mHasSoftMenuButton;
@@ -106,13 +140,20 @@ public class BrowserToolbar extends GeckoRelativeLayout
private boolean mShowReader;
private boolean mSpinnerVisible;
+ private boolean mDelayRestartInput;
+ // The previous autocomplete result returned to us
+ private String mAutoCompleteResult = "";
+ // The user typed part of the autocomplete result
+ private String mAutoCompletePrefix = null;
+
+ private boolean mIsEditing;
private boolean mAnimatingEntry;
private AlphaAnimation mLockFadeIn;
private TranslateAnimation mTitleSlideLeft;
private TranslateAnimation mTitleSlideRight;
- private int mAddressBarViewOffset;
+ private int mUrlBarViewOffset;
private int mDefaultForwardMargin;
private PropertyAnimator mForwardAnim = null;
@@ -150,6 +191,7 @@ public class BrowserToolbar extends GeckoRelativeLayout
Tabs.registerOnTabsChangedListener(this);
mSwitchingTabs = true;
+ mIsEditing = false;
mAnimatingEntry = false;
mShowUrl = false;
@@ -195,19 +237,22 @@ public class BrowserToolbar extends GeckoRelativeLayout
mAnimatingEntry = false;
- mAddressBarBg = (BrowserToolbarBackground) findViewById(R.id.address_bar_bg);
- mAddressBarViewOffset = res.getDimensionPixelSize(R.dimen.addressbar_offset_left);
+ mUrlBarBackground = (BrowserToolbarBackground) findViewById(R.id.url_bar_bg);
+ mUrlBarViewOffset = res.getDimensionPixelSize(R.dimen.url_bar_offset_left);
mDefaultForwardMargin = res.getDimensionPixelSize(R.dimen.forward_default_offset);
- mUrlDisplayContainer = findViewById(R.id.awesome_bar_display_container);
- mAwesomeBarEntry = findViewById(R.id.awesome_bar_entry);
+ mUrlDisplayContainer = findViewById(R.id.url_display_container);
+ mUrlBarEntry = findViewById(R.id.url_bar_entry);
+
+ mUrlEditContainer = findViewById(R.id.url_edit_container);
+ mUrlEditText = (CustomEditText) findViewById(R.id.url_edit_text);
// This will clip the right edge's image at half of its width
- mAwesomeBarRightEdge = (ImageView) findViewById(R.id.awesome_bar_right_edge);
- if (mAwesomeBarRightEdge != null) {
- mAwesomeBarRightEdge.getDrawable().setLevel(5000);
+ mUrlBarRightEdge = (ImageView) findViewById(R.id.url_bar_right_edge);
+ if (mUrlBarRightEdge != null) {
+ mUrlBarRightEdge.getDrawable().setLevel(5000);
}
- mTitle = (GeckoTextView) findViewById(R.id.awesome_bar_title);
+ mTitle = (GeckoTextView) findViewById(R.id.url_bar_title);
mTitlePadding = mTitle.getPaddingRight();
mTabs = (ShapedButton) findViewById(R.id.tabs);
@@ -258,14 +303,20 @@ public class BrowserToolbar extends GeckoRelativeLayout
setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick(View v) {
- mActivity.autoHideTabs();
- onAwesomeBarSearch();
+ if (mActivateListener != null) {
+ mActivateListener.onActivate();
+ }
}
});
setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() {
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
+ // We don't the context menu while editing
+ if (isEditing()) {
+ return;
+ }
+
MenuInflater inflater = mActivity.getMenuInflater();
inflater.inflate(R.menu.titlebar_contextmenu, menu);
@@ -296,6 +347,96 @@ public class BrowserToolbar extends GeckoRelativeLayout
}
});
+ mUrlEditText.addTextChangedListener(this);
+
+ mUrlEditText.setOnKeyPreImeListener(new CustomEditText.OnKeyPreImeListener() {
+ @Override
+ public boolean onKeyPreIme(View v, int keyCode, KeyEvent event) {
+ // We only want to process one event per tap
+ if (event.getAction() != KeyEvent.ACTION_DOWN)
+ return false;
+
+ if (keyCode == KeyEvent.KEYCODE_ENTER) {
+ // If the edit text has a composition string, don't submit the text yet.
+ // ENTER is needed to commit the composition string.
+ Editable content = mUrlEditText.getText();
+ if (!hasCompositionString(content)) {
+ if (mCommitListener != null) {
+ mCommitListener.onCommit();
+ }
+ return true;
+ }
+ }
+
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ clearFocus();
+ return true;
+ }
+
+ return false;
+ }
+ });
+
+ mUrlEditText.setOnKeyListener(new View.OnKeyListener() {
+ @Override
+ public boolean onKey(View v, int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_ENTER || GamepadUtils.isActionKey(event)) {
+ if (event.getAction() != KeyEvent.ACTION_DOWN)
+ return true;
+
+ if (mCommitListener != null) {
+ mCommitListener.onCommit();
+ }
+ return true;
+ } else if (GamepadUtils.isBackKey(event)) {
+ if (mDismissListener != null) {
+ mDismissListener.onDismiss();
+ }
+ return true;
+ }
+
+ return false;
+ }
+ });
+
+ mUrlEditText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ if (v == null) {
+ return;
+ }
+
+ setSelected(hasFocus);
+ if (hasFocus) {
+ return;
+ }
+
+ InputMethodManager imm = (InputMethodManager) mActivity.getSystemService(Context.INPUT_METHOD_SERVICE);
+ try {
+ imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
+ } catch (NullPointerException e) {
+ Log.e(LOGTAG, "InputMethodManagerService, why are you throwing"
+ + " a NullPointerException? See bug 782096", e);
+ }
+ }
+ });
+
+ mUrlEditText.setOnLongClickListener(new View.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ if (Build.VERSION.SDK_INT >= 11) {
+ CustomEditText text = (CustomEditText) v;
+
+ if (text.getSelectionStart() == text.getSelectionEnd())
+ return false;
+
+ return false;
+ }
+
+ return false;
+ }
+ });
+
mTabs.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick(View v) {
@@ -360,6 +501,17 @@ public class BrowserToolbar extends GeckoRelativeLayout
}
});
+ mGo = (ImageButton) findViewById(R.id.go);
+ mGo.setOnClickListener(new Button.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mCommitListener != null) {
+ mCommitListener.onCommit();
+ }
+ }
+ });
+
+ mShadow = (ImageView) findViewById(R.id.shadow);
mShadow.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick(View v) {
@@ -416,6 +568,54 @@ public class BrowserToolbar extends GeckoRelativeLayout
}
}
+ public boolean onKey(int keyCode, KeyEvent event) {
+ if (event.getAction() != KeyEvent.ACTION_DOWN) {
+ return false;
+ }
+
+ // Galaxy Note sends key events for the stylus that are outside of the
+ // valid keyCode range (see bug 758427)
+ if (keyCode > KeyEvent.getMaxKeyCode()) {
+ return true;
+ }
+
+ // This method is called only if the key event was not handled
+ // by any of the views, which usually means the edit box lost focus
+ if (keyCode == KeyEvent.KEYCODE_BACK ||
+ keyCode == KeyEvent.KEYCODE_MENU ||
+ keyCode == KeyEvent.KEYCODE_DPAD_UP ||
+ keyCode == KeyEvent.KEYCODE_DPAD_DOWN ||
+ keyCode == KeyEvent.KEYCODE_DPAD_LEFT ||
+ keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ||
+ keyCode == KeyEvent.KEYCODE_DPAD_CENTER ||
+ keyCode == KeyEvent.KEYCODE_DEL ||
+ keyCode == KeyEvent.KEYCODE_VOLUME_UP ||
+ keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
+ return false;
+ } else if (isEditing()) {
+ final int prevSelStart = mUrlEditText.getSelectionStart();
+ final int prevSelEnd = mUrlEditText.getSelectionEnd();
+
+ // Manually dispatch the key event to the edit text. If selection changed as
+ // a result of the key event, then give focus back to mUrlEditText
+ mUrlEditText.dispatchKeyEvent(event);
+
+ final int curSelStart = mUrlEditText.getSelectionStart();
+ final int curSelEnd = mUrlEditText.getSelectionEnd();
+
+ if (prevSelStart != curSelStart || prevSelEnd != curSelEnd) {
+ mUrlEditText.requestFocusFromTouch();
+
+ // Restore the selection, which gets lost due to the focus switch
+ mUrlEditText.setSelection(curSelStart, curSelEnd);
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
@Override
public boolean onTouchEvent(MotionEvent event) {
// If the motion event has occured below the toolbar (due to the scroll
@@ -515,6 +715,78 @@ public class BrowserToolbar extends GeckoRelativeLayout
}
}
+ // Return early if we're backspacing through the string, or
+ // have no autocomplete results
+ @Override
+ public void onAutocomplete(final String result) {
+ final String text = mUrlEditText.getText().toString();
+
+ if (result == null) {
+ mAutoCompleteResult = "";
+ return;
+ }
+
+ if (!result.startsWith(text) || text.equals(result)) {
+ return;
+ }
+
+ mAutoCompleteResult = result;
+ mUrlEditText.getText().append(result.substring(text.length()));
+ mUrlEditText.setSelection(text.length(), result.length());
+ }
+
+ @Override
+ public void afterTextChanged(final Editable s) {
+ final String text = s.toString();
+ boolean useHandler = false;
+ boolean reuseAutocomplete = false;
+ if (!hasCompositionString(s) && !StringUtils.isSearchQuery(text, false)) {
+ useHandler = true;
+
+ // If you're hitting backspace (the string is getting smaller
+ // or is unchanged), don't autocomplete.
+ if (mAutoCompletePrefix != null && (mAutoCompletePrefix.length() >= text.length())) {
+ useHandler = false;
+ } else if (mAutoCompleteResult != null && mAutoCompleteResult.startsWith(text)) {
+ // If this text already matches our autocomplete text, autocomplete likely
+ // won't change. Just reuse the old autocomplete value.
+ useHandler = false;
+ reuseAutocomplete = true;
+ }
+ }
+
+ // If this is the autocomplete text being set, don't run the filter.
+ if (TextUtils.isEmpty(mAutoCompleteResult) || !mAutoCompleteResult.equals(text)) {
+ if (isEditing() && mFilterListener != null) {
+ mFilterListener.onFilter(text, useHandler ? this : null);
+ }
+ mAutoCompletePrefix = text;
+
+ if (reuseAutocomplete) {
+ onAutocomplete(mAutoCompleteResult);
+ }
+ }
+
+ // If the edit text has a composition string, don't call updateGoButton().
+ // That method resets IME and composition state will be broken.
+ if (!hasCompositionString(s) ||
+ InputMethods.isGestureKeyboard(mUrlEditText.getContext())) {
+ updateGoButton(text);
+ }
+ }
+
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count,
+ int after) {
+ // do nothing
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before,
+ int count) {
+ // do nothing
+ }
+
public boolean isVisible() {
return getScrollY() == 0;
}
@@ -559,190 +831,25 @@ public class BrowserToolbar extends GeckoRelativeLayout
}
}
- private int getAwesomeBarEntryTranslation() {
- return getWidth() - mAwesomeBarEntry.getRight();
+ private int getUrlBarEntryTranslation() {
+ return getWidth() - mUrlBarEntry.getRight();
}
- private int getAwesomeBarCurveTranslation() {
+ private int getUrlBarCurveTranslation() {
return getWidth() - mTabs.getLeft();
}
- public void fromAwesomeBarSearch(String url) {
- // Update the title with the url that was just entered. Don't update the title if
- // the AwesomeBar activity was cancelled, or if the user entered an empty string.
- if (url != null && url.length() > 0) {
- setTitle(url);
- }
-
- if (HardwareUtils.isTablet() || Build.VERSION.SDK_INT < 11) {
- return;
- }
-
- // If the awesomebar entry is not selected at this point, this means that
- // we had to reinflate the toolbar layout for some reason (device rotation
- // while in awesome screen, activity was killed in background, etc). In this
- // case, we have to ensure the toolbar is in the correct initial state to
- // shrink back.
- if (!isSelected()) {
- // Keep the entry highlighted during the animation
- setSelected(true);
-
- final int entryTranslation = getAwesomeBarEntryTranslation();
- final int curveTranslation = getAwesomeBarCurveTranslation();
-
- if (mAwesomeBarRightEdge != null) {
- ViewHelper.setTranslationX(mAwesomeBarRightEdge, entryTranslation);
+ private static boolean hasCompositionString(Editable content) {
+ Object[] spans = content.getSpans(0, content.length(), Object.class);
+ if (spans != null) {
+ for (Object span : spans) {
+ if ((content.getSpanFlags(span) & Spanned.SPAN_COMPOSING) != 0) {
+ // Found composition string.
+ return true;
+ }
}
-
- ViewHelper.setTranslationX(mTabs, curveTranslation);
- ViewHelper.setTranslationX(mTabsCounter, curveTranslation);
- ViewHelper.setTranslationX(mActionItemBar, curveTranslation);
-
- if (mHasSoftMenuButton) {
- ViewHelper.setTranslationX(mMenu, curveTranslation);
- ViewHelper.setTranslationX(mMenuIcon, curveTranslation);
- }
-
- ViewHelper.setAlpha(mPageActionLayout, 0);
- ViewHelper.setAlpha(mStop, 0);
}
-
- final PropertyAnimator contentAnimator = new PropertyAnimator(250);
- contentAnimator.setUseHardwareLayer(false);
-
- // Shrink the awesome entry back to its original size
-
- if (mAwesomeBarRightEdge != null) {
- contentAnimator.attach(mAwesomeBarRightEdge,
- PropertyAnimator.Property.TRANSLATION_X,
- 0);
- }
-
- contentAnimator.attach(mTabs,
- PropertyAnimator.Property.TRANSLATION_X,
- 0);
- contentAnimator.attach(mTabsCounter,
- PropertyAnimator.Property.TRANSLATION_X,
- 0);
- contentAnimator.attach(mActionItemBar,
- PropertyAnimator.Property.TRANSLATION_X,
- 0);
-
- if (mHasSoftMenuButton) {
- contentAnimator.attach(mMenu,
- PropertyAnimator.Property.TRANSLATION_X,
- 0);
- contentAnimator.attach(mMenuIcon,
- PropertyAnimator.Property.TRANSLATION_X,
- 0);
- }
-
- contentAnimator.setPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
- @Override
- public void onPropertyAnimationStart() {
- }
-
- @Override
- public void onPropertyAnimationEnd() {
- // Turn off selected state on the entry
- setSelected(false);
-
- PropertyAnimator buttonsAnimator = new PropertyAnimator(300);
-
- // Fade toolbar buttons (reader, stop) after the entry
- // is schrunk back to its original size.
- buttonsAnimator.attach(mPageActionLayout,
- PropertyAnimator.Property.ALPHA,
- 1);
- buttonsAnimator.attach(mStop,
- PropertyAnimator.Property.ALPHA,
- 1);
-
- buttonsAnimator.start();
-
- mAnimatingEntry = false;
-
- // Trigger animation to update the tabs counter once the
- // tabs button is back on screen.
- updateTabCount(Tabs.getInstance().getDisplayCount());
- }
- });
-
- mAnimatingEntry = true;
-
- postDelayed(new Runnable() {
- @Override
- public void run() {
- contentAnimator.start();
- }
- }, 500);
- }
-
- private void onAwesomeBarSearch() {
- // This animation doesn't make much sense in a sidebar UI
- if (HardwareUtils.isTablet() || Build.VERSION.SDK_INT < 11) {
- mActivity.onSearchRequested();
- return;
- }
-
- if (mAnimatingEntry)
- return;
-
- final PropertyAnimator contentAnimator = new PropertyAnimator(250);
- contentAnimator.setUseHardwareLayer(false);
-
- final int entryTranslation = getAwesomeBarEntryTranslation();
- final int curveTranslation = getAwesomeBarCurveTranslation();
-
- // Keep the entry highlighted during the animation
- setSelected(true);
-
- // Hide stop/reader buttons immediately
- ViewHelper.setAlpha(mPageActionLayout, 0);
- ViewHelper.setAlpha(mStop, 0);
-
- // Slide the right side elements of the toolbar
-
- if (mAwesomeBarRightEdge != null) {
- contentAnimator.attach(mAwesomeBarRightEdge,
- PropertyAnimator.Property.TRANSLATION_X,
- entryTranslation);
- }
-
- contentAnimator.attach(mTabs,
- PropertyAnimator.Property.TRANSLATION_X,
- curveTranslation);
- contentAnimator.attach(mTabsCounter,
- PropertyAnimator.Property.TRANSLATION_X,
- curveTranslation);
- contentAnimator.attach(mActionItemBar,
- PropertyAnimator.Property.TRANSLATION_X,
- curveTranslation);
-
- if (mHasSoftMenuButton) {
- contentAnimator.attach(mMenu,
- PropertyAnimator.Property.TRANSLATION_X,
- curveTranslation);
- contentAnimator.attach(mMenuIcon,
- PropertyAnimator.Property.TRANSLATION_X,
- curveTranslation);
- }
-
- contentAnimator.setPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
- @Override
- public void onPropertyAnimationStart() {
- }
-
- @Override
- public void onPropertyAnimationEnd() {
- // Once the entry is fully expanded, start awesome screen
- mActivity.onSearchRequested();
- mAnimatingEntry = false;
- }
- });
-
- mAnimatingEntry = true;
- contentAnimator.start();
+ return false;
}
private void addTab() {
@@ -769,12 +876,32 @@ public class BrowserToolbar extends GeckoRelativeLayout
}
}
- public void updateTabCount(int count) {
- // If toolbar is selected, this means the entry is expanded and the
+ public void updateTabCountAndAnimate(int count) {
+ // Don't animate if the toolbar is hidden.
+ if (!isVisible()) {
+ updateTabCount(count);
+ return;
+ }
+
+ // If toolbar is in edit mode, this means the entry is expanded and the
// tabs button is translated offscreen. Don't trigger tabs counter
// updates until the tabs button is back on screen.
- // See fromAwesomeBarSearch()
- if (isSelected()) {
+ // See stopEditing()
+ if (!isEditing()) {
+ mTabsCounter.setCount(count);
+
+ mTabs.setContentDescription((count > 1) ?
+ mActivity.getString(R.string.num_tabs, count) :
+ mActivity.getString(R.string.one_tab));
+ }
+ }
+
+ public void updateTabCount(int count) {
+ // If toolbar is in edit mode, this means the entry is expanded and the
+ // tabs button is translated offscreen. Don't trigger tabs counter
+ // updates until the tabs button is back on screen.
+ // See stopEditing()
+ if (isEditing()) {
return;
}
@@ -919,15 +1046,28 @@ public class BrowserToolbar extends GeckoRelativeLayout
String url = tab.getURL();
- // Only set shadow to visible when not on about screens except about:blank.
- visible &= !(url == null || (url.startsWith("about:") &&
- !url.equals("about:blank")));
+ // Only set shadow to visible when not on about screens (except about:blank)
+ // and when not in editing mode.
+ visible &= !(url == null || (url.startsWith("about:") &&
+ !url.equals("about:blank"))) && !isEditing();
if ((mShadow.getVisibility() == View.VISIBLE) != visible) {
mShadow.setVisibility(visible ? View.VISIBLE : View.GONE);
}
}
+ public void onEditSuggestion(String suggestion) {
+ if (!isEditing()) {
+ return;
+ }
+
+ mUrlEditText.setText(suggestion);
+ mUrlEditText.setSelection(mUrlEditText.getText().length());
+ mUrlEditText.requestFocus();
+
+ showSoftInput();
+ }
+
private void setTitle(CharSequence title) {
mTitle.setText(title);
setContentDescription(title != null ? title : mTitle.getHint());
@@ -942,6 +1082,11 @@ public class BrowserToolbar extends GeckoRelativeLayout
}
String url = tab.getURL();
+
+ if (!isEditing()) {
+ mUrlEditText.setText(url);
+ }
+
// Setting a null title will ensure we just see the "Enter Search or Address" placeholder text.
if ("about:home".equals(url) || "about:privatebrowsing".equals(url)) {
setTitle(null);
@@ -1027,6 +1172,391 @@ public class BrowserToolbar extends GeckoRelativeLayout
}
}
+ public void finishTabsAnimation(boolean tabsAreShown) {
+ if (tabsAreShown) {
+ return;
+ }
+
+ PropertyAnimator animator = new PropertyAnimator(150);
+
+ animator.attach(mTabsCounter,
+ PropertyAnimator.Property.ALPHA,
+ 1.0f);
+
+ if (mHasSoftMenuButton && !HardwareUtils.isTablet()) {
+ animator.attach(mMenuIcon,
+ PropertyAnimator.Property.ALPHA,
+ 1.0f);
+ }
+
+ animator.start();
+ }
+
+ public void setOnActivateListener(OnActivateListener listener) {
+ mActivateListener = listener;
+ }
+
+ public void setOnCommitListener(OnCommitListener listener) {
+ mCommitListener = listener;
+ }
+
+ public void setOnDismissListener(OnDismissListener listener) {
+ mDismissListener = listener;
+ }
+
+ public void setOnFilterListener(OnFilterListener listener) {
+ mFilterListener = listener;
+ }
+
+ private void showSoftInput() {
+ InputMethodManager imm =
+ (InputMethodManager) mActivity.getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.showSoftInput(mUrlEditText, InputMethodManager.SHOW_IMPLICIT);
+ }
+
+ private void showUrlEditContainer() {
+ setUrlEditContainerVisibility(true, null);
+ }
+
+ private void showUrlEditContainer(PropertyAnimator animator) {
+ setUrlEditContainerVisibility(true, animator);
+ }
+
+ private void hideUrlEditContainer() {
+ setUrlEditContainerVisibility(false, null);
+ }
+
+ private void hideUrlEditContainer(PropertyAnimator animator) {
+ setUrlEditContainerVisibility(false, animator);
+ }
+
+ private void setUrlEditContainerVisibility(final boolean showEditContainer, PropertyAnimator animator) {
+ final View viewToShow = (showEditContainer ? mUrlEditContainer : mUrlDisplayContainer);
+ final View viewToHide = (showEditContainer ? mUrlDisplayContainer : mUrlEditContainer);
+
+ if (animator == null) {
+ viewToHide.setVisibility(View.GONE);
+ viewToShow.setVisibility(View.VISIBLE);
+
+ if (showEditContainer) {
+ mUrlEditText.requestFocus();
+ showSoftInput();
+ }
+
+ return;
+ }
+
+ ViewHelper.setAlpha(viewToShow, 0.0f);
+ animator.attach(viewToShow,
+ PropertyAnimator.Property.ALPHA,
+ 1.0f);
+
+ animator.attach(viewToHide,
+ PropertyAnimator.Property.ALPHA,
+ 0.0f);
+
+ animator.addPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
+ @Override
+ public void onPropertyAnimationStart() {
+ viewToShow.setVisibility(View.VISIBLE);
+
+ if (showEditContainer) {
+ ViewHelper.setAlpha(mGo, 0.0f);
+ mUrlEditText.requestFocus();
+ }
+ }
+
+ @Override
+ public void onPropertyAnimationEnd() {
+ viewToHide.setVisibility(View.GONE);
+ ViewHelper.setAlpha(viewToHide, 1.0f);
+
+ if (showEditContainer) {
+ ViewHelper.setAlpha(mGo, 1.0f);
+ showSoftInput();
+ }
+ }
+ });
+ }
+
+ /**
+ * Returns whether or not the URL bar is in editing mode (url bar is expanded, hiding the new
+ * tab button). Note that selection state is independent of editing mode.
+ */
+ public boolean isEditing() {
+ return mIsEditing;
+ }
+
+ public void startEditing(String url, PropertyAnimator animator) {
+ if (isEditing()) {
+ return;
+ }
+
+ mUrlEditText.setText(url != null ? url : "");
+ mIsEditing = true;
+
+ final int entryTranslation = getUrlBarEntryTranslation();
+ final int curveTranslation = getUrlBarCurveTranslation();
+
+ // This animation doesn't make much sense in a sidebar UI
+ if (HardwareUtils.isTablet() || Build.VERSION.SDK_INT < 11) {
+ showUrlEditContainer();
+
+ if (!HardwareUtils.isTablet()) {
+ if (mUrlBarRightEdge != null) {
+ ViewHelper.setTranslationX(mUrlBarRightEdge, entryTranslation);
+ }
+
+ ViewHelper.setTranslationX(mTabs, curveTranslation);
+ ViewHelper.setTranslationX(mTabsCounter, curveTranslation);
+ ViewHelper.setTranslationX(mActionItemBar, curveTranslation);
+
+ if (mHasSoftMenuButton) {
+ ViewHelper.setTranslationX(mMenu, curveTranslation);
+ ViewHelper.setTranslationX(mMenuIcon, curveTranslation);
+ }
+ }
+
+ return;
+ }
+
+ if (mAnimatingEntry)
+ return;
+
+ // Highlight the toolbar from the start of the animation.
+ setSelected(true);
+
+ // Hide page actions/stop buttons immediately
+ ViewHelper.setAlpha(mPageActionLayout, 0);
+ ViewHelper.setAlpha(mStop, 0);
+
+ // Slide the right side elements of the toolbar
+
+ if (mUrlBarRightEdge != null) {
+ animator.attach(mUrlBarRightEdge,
+ PropertyAnimator.Property.TRANSLATION_X,
+ entryTranslation);
+ }
+
+ animator.attach(mTabs,
+ PropertyAnimator.Property.TRANSLATION_X,
+ curveTranslation);
+ animator.attach(mTabsCounter,
+ PropertyAnimator.Property.TRANSLATION_X,
+ curveTranslation);
+ animator.attach(mActionItemBar,
+ PropertyAnimator.Property.TRANSLATION_X,
+ curveTranslation);
+
+ if (mHasSoftMenuButton) {
+ animator.attach(mMenu,
+ PropertyAnimator.Property.TRANSLATION_X,
+ curveTranslation);
+
+ animator.attach(mMenuIcon,
+ PropertyAnimator.Property.TRANSLATION_X,
+ curveTranslation);
+ }
+
+ showUrlEditContainer(animator);
+
+ animator.addPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
+ @Override
+ public void onPropertyAnimationStart() {
+ }
+
+ @Override
+ public void onPropertyAnimationEnd() {
+ mAnimatingEntry = false;
+ }
+ });
+
+ mAnimatingEntry = true;
+ }
+
+ /**
+ * Exits edit mode without updating the toolbar title.
+ *
+ * @return the url that was entered
+ */
+ public String cancelEdit() {
+ return stopEditing();
+ }
+
+ /**
+ * Exits edit mode, updating the toolbar title with the url that was just entered.
+ *
+ * @return the url that was entered
+ */
+ public String commitEdit() {
+ final String url = stopEditing();
+ if (!TextUtils.isEmpty(url)) {
+ setTitle(url);
+ }
+ return url;
+ }
+
+ private String stopEditing() {
+ final String url = mUrlEditText.getText().toString();
+ if (!isEditing()) {
+ return url;
+ }
+ mIsEditing = false;
+
+ if (HardwareUtils.isTablet() || Build.VERSION.SDK_INT < 11) {
+ hideUrlEditContainer();
+ updateTabCountAndAnimate(Tabs.getInstance().getDisplayCount());
+
+ if (!HardwareUtils.isTablet()) {
+ if (mUrlBarRightEdge != null) {
+ ViewHelper.setTranslationX(mUrlBarRightEdge, 0);
+ }
+
+ ViewHelper.setTranslationX(mTabs, 0);
+ ViewHelper.setTranslationX(mTabsCounter, 0);
+ ViewHelper.setTranslationX(mActionItemBar, 0);
+
+ if (mHasSoftMenuButton) {
+ ViewHelper.setTranslationX(mMenu, 0);
+ ViewHelper.setTranslationX(mMenuIcon, 0);
+ }
+ }
+
+ return url;
+ }
+
+ final PropertyAnimator contentAnimator = new PropertyAnimator(250);
+ contentAnimator.setUseHardwareLayer(false);
+
+ // Shrink the urlbar entry back to its original size
+
+ if (mUrlBarRightEdge != null) {
+ contentAnimator.attach(mUrlBarRightEdge,
+ PropertyAnimator.Property.TRANSLATION_X,
+ 0);
+ }
+
+ contentAnimator.attach(mTabs,
+ PropertyAnimator.Property.TRANSLATION_X,
+ 0);
+ contentAnimator.attach(mTabsCounter,
+ PropertyAnimator.Property.TRANSLATION_X,
+ 0);
+ contentAnimator.attach(mActionItemBar,
+ PropertyAnimator.Property.TRANSLATION_X,
+ 0);
+
+ if (mHasSoftMenuButton) {
+ contentAnimator.attach(mMenu,
+ PropertyAnimator.Property.TRANSLATION_X,
+ 0);
+
+ contentAnimator.attach(mMenuIcon,
+ PropertyAnimator.Property.TRANSLATION_X,
+ 0);
+ }
+
+ hideUrlEditContainer(contentAnimator);
+
+ contentAnimator.addPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
+ @Override
+ public void onPropertyAnimationStart() {
+ }
+
+ @Override
+ public void onPropertyAnimationEnd() {
+ setShadowVisibility(true);
+
+ PropertyAnimator buttonsAnimator = new PropertyAnimator(300);
+
+ // Fade toolbar buttons (page actions, stop) after the entry
+ // is schrunk back to its original size.
+ buttonsAnimator.attach(mPageActionLayout,
+ PropertyAnimator.Property.ALPHA,
+ 1);
+ buttonsAnimator.attach(mStop,
+ PropertyAnimator.Property.ALPHA,
+ 1);
+
+ buttonsAnimator.start();
+
+ mAnimatingEntry = false;
+
+ // Trigger animation to update the tabs counter once the
+ // tabs button is back on screen.
+ updateTabCountAndAnimate(Tabs.getInstance().getDisplayCount());
+ }
+ });
+
+ mAnimatingEntry = true;
+ contentAnimator.start();
+
+ return url;
+ }
+
+ private void updateGoButton(String text) {
+ if (text.length() == 0) {
+ mGo.setVisibility(View.GONE);
+ return;
+ }
+
+ mGo.setVisibility(View.VISIBLE);
+
+ int imageResource = R.drawable.ic_url_bar_go;
+ String contentDescription = mActivity.getString(R.string.go);
+ int imeAction = EditorInfo.IME_ACTION_GO;
+
+ int actionBits = mUrlEditText.getImeOptions() & EditorInfo.IME_MASK_ACTION;
+ if (StringUtils.isSearchQuery(text, actionBits == EditorInfo.IME_ACTION_SEARCH)) {
+ imageResource = R.drawable.ic_url_bar_search;
+ contentDescription = mActivity.getString(R.string.search);
+ imeAction = EditorInfo.IME_ACTION_SEARCH;
+ }
+
+ InputMethodManager imm = InputMethods.getInputMethodManager(mUrlEditText.getContext());
+ if (imm == null) {
+ return;
+ }
+ boolean restartInput = false;
+ if (actionBits != imeAction) {
+ int optionBits = mUrlEditText.getImeOptions() & ~EditorInfo.IME_MASK_ACTION;
+ mUrlEditText.setImeOptions(optionBits | imeAction);
+
+ mDelayRestartInput = (imeAction == EditorInfo.IME_ACTION_GO) &&
+ (InputMethods.shouldDelayUrlBarUpdate(mUrlEditText.getContext()));
+ if (!mDelayRestartInput) {
+ restartInput = true;
+ }
+ } else if (mDelayRestartInput) {
+ // Only call delayed restartInput when actionBits == imeAction
+ // so if there are two restarts in a row, the first restarts will
+ // be discarded and the second restart will be properly delayed
+ mDelayRestartInput = false;
+ restartInput = true;
+ }
+ if (restartInput) {
+ updateKeyboardInputType();
+ imm.restartInput(mUrlEditText);
+ mGo.setImageResource(imageResource);
+ mGo.setContentDescription(contentDescription);
+ }
+ }
+
+ private void updateKeyboardInputType() {
+ // If the user enters a space, then we know they are entering search terms, not a URL.
+ // We can then switch to text mode so,
+ // 1) the IME auto-inserts spaces between words
+ // 2) the IME doesn't reset input keyboard to Latin keyboard.
+ String text = mUrlEditText.getText().toString();
+ int currentInputType = mUrlEditText.getInputType();
+ int newInputType = StringUtils.isSearchQuery(text, false)
+ ? (currentInputType & ~InputType.TYPE_TEXT_VARIATION_URI) // Text mode
+ : (currentInputType | InputType.TYPE_TEXT_VARIATION_URI); // URL mode
+ if (newInputType != currentInputType) {
+ mUrlEditText.setRawInputType(newInputType);
+ }
+ }
+
public void updateBackButton(boolean enabled) {
Drawable drawable = mBack.getDrawable();
if (drawable != null)
@@ -1050,7 +1580,7 @@ public class BrowserToolbar extends GeckoRelativeLayout
mForwardAnim = new PropertyAnimator(mSwitchingTabs ? 10 : FORWARD_ANIMATION_DURATION);
final int width = mForward.getWidth() / 2;
- mForwardAnim.setPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
+ mForwardAnim.addPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
@Override
public void onPropertyAnimationStart() {
if (!enabled) {
@@ -1059,7 +1589,12 @@ public class BrowserToolbar extends GeckoRelativeLayout
ViewGroup.MarginLayoutParams layoutParams =
(ViewGroup.MarginLayoutParams)mUrlDisplayContainer.getLayoutParams();
layoutParams.leftMargin = 0;
- mUrlDisplayContainer.requestLayout();
+
+ // Do the same on the URL edit container
+ layoutParams = (ViewGroup.MarginLayoutParams)mUrlEditContainer.getLayoutParams();
+ layoutParams.leftMargin = 0;
+
+ requestLayout();
// Note, we already translated the favicon, site security, and text field
// in prepareForwardAnimation, so they should appear to have not moved at
// all at this point.
@@ -1071,7 +1606,10 @@ public class BrowserToolbar extends GeckoRelativeLayout
if (enabled) {
ViewGroup.MarginLayoutParams layoutParams =
(ViewGroup.MarginLayoutParams)mUrlDisplayContainer.getLayoutParams();
- layoutParams.leftMargin = mAddressBarViewOffset;
+ layoutParams.leftMargin = mUrlBarViewOffset;
+
+ layoutParams = (ViewGroup.MarginLayoutParams)mUrlEditContainer.getLayoutParams();
+ layoutParams.leftMargin = mUrlBarViewOffset;
ViewHelper.setTranslationX(mTitle, 0);
ViewHelper.setTranslationX(mFavicon, 0);
@@ -1083,7 +1621,7 @@ public class BrowserToolbar extends GeckoRelativeLayout
layoutParams.leftMargin = mDefaultForwardMargin + (mForward.isEnabled() ? width : 0);
ViewHelper.setTranslationX(mForward, 0);
- mUrlDisplayContainer.requestLayout();
+ requestLayout();
mForwardAnim = null;
}
});
@@ -1113,9 +1651,9 @@ public class BrowserToolbar extends GeckoRelativeLayout
// We're hiding the forward button. We're going to reset the margin before
// the animation starts, so we shift these items to the right so that they don't
// appear to move initially.
- ViewHelper.setTranslationX(mTitle, mAddressBarViewOffset);
- ViewHelper.setTranslationX(mFavicon, mAddressBarViewOffset);
- ViewHelper.setTranslationX(mSiteSecurity, mAddressBarViewOffset);
+ ViewHelper.setTranslationX(mTitle, mUrlBarViewOffset);
+ ViewHelper.setTranslationX(mFavicon, mUrlBarViewOffset);
+ ViewHelper.setTranslationX(mSiteSecurity, mUrlBarViewOffset);
} else {
anim.attach(mForward,
PropertyAnimator.Property.TRANSLATION_X,
@@ -1125,13 +1663,13 @@ public class BrowserToolbar extends GeckoRelativeLayout
1);
anim.attach(mTitle,
PropertyAnimator.Property.TRANSLATION_X,
- mAddressBarViewOffset);
+ mUrlBarViewOffset);
anim.attach(mFavicon,
PropertyAnimator.Property.TRANSLATION_X,
- mAddressBarViewOffset);
+ mUrlBarViewOffset);
anim.attach(mSiteSecurity,
PropertyAnimator.Property.TRANSLATION_X,
- mAddressBarViewOffset);
+ mUrlBarViewOffset);
}
}
@@ -1166,12 +1704,13 @@ public class BrowserToolbar extends GeckoRelativeLayout
updateForwardButton(tab.canDoForward());
final boolean isPrivate = tab.isPrivate();
- mAddressBarBg.setPrivateMode(isPrivate);
+ mUrlBarBackground.setPrivateMode(isPrivate);
setPrivateMode(isPrivate);
mTabs.setPrivateMode(isPrivate);
mTitle.setPrivateMode(isPrivate);
mMenu.setPrivateMode(isPrivate);
mMenuIcon.setPrivateMode(isPrivate);
+ mUrlEditText.setPrivateMode(isPrivate);
if (mBack instanceof BackButton)
((BackButton) mBack).setPrivateMode(isPrivate);
diff --git a/mobile/android/base/BrowserToolbarBackground.java b/mobile/android/base/BrowserToolbarBackground.java
index e56a0689dbfa..26079ee9652d 100644
--- a/mobile/android/base/BrowserToolbarBackground.java
+++ b/mobile/android/base/BrowserToolbarBackground.java
@@ -37,6 +37,6 @@ public class BrowserToolbarBackground extends GeckoLinearLayout {
@Override
public void onLightweightThemeReset() {
- setBackgroundResource(R.drawable.address_bar_bg);
+ setBackgroundResource(R.drawable.url_bar_bg);
}
}
diff --git a/mobile/android/base/Favicons.java b/mobile/android/base/Favicons.java
index 473580cfd12e..0f6915b3af7d 100644
--- a/mobile/android/base/Favicons.java
+++ b/mobile/android/base/Favicons.java
@@ -243,10 +243,10 @@ public class Favicons {
public void attachToContext(Context context) {
mContext = context;
if (sFaviconSmallSize < 0) {
- sFaviconSmallSize = Math.round(mContext.getResources().getDimension(R.dimen.awesomebar_row_favicon_size_small));
+ sFaviconSmallSize = Math.round(mContext.getResources().getDimension(R.dimen.favicon_size_small));
}
if (sFaviconLargeSize < 0) {
- sFaviconLargeSize = Math.round(mContext.getResources().getDimension(R.dimen.awesomebar_row_favicon_size_large));
+ sFaviconLargeSize = Math.round(mContext.getResources().getDimension(R.dimen.favicon_size_large));
}
}
diff --git a/mobile/android/base/ForwardButton.java b/mobile/android/base/ForwardButton.java
index 44e1435de6b6..a27db2054465 100644
--- a/mobile/android/base/ForwardButton.java
+++ b/mobile/android/base/ForwardButton.java
@@ -66,7 +66,7 @@ public class ForwardButton extends ShapedButton {
canvas.drawPath(mBorderPath, isPrivateMode() ? mBorderPrivatePaint : mBorderPaint);
}
- // The drawable is constructed as per @drawable/address_bar_nav_button.
+ // The drawable is constructed as per @drawable/url_bar_nav_button.
@Override
public void onLightweightThemeChanged() {
Drawable drawable = mActivity.getLightweightTheme().getDrawable(this);
@@ -88,6 +88,6 @@ public class ForwardButton extends ShapedButton {
@Override
public void onLightweightThemeReset() {
- setBackgroundResource(R.drawable.address_bar_nav_button);
+ setBackgroundResource(R.drawable.url_bar_nav_button);
}
}
diff --git a/mobile/android/base/GeckoApp.java b/mobile/android/base/GeckoApp.java
index 1d2e5a288dc8..4a9be3ea931a 100644
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -567,8 +567,6 @@ abstract public class GeckoApp
} else if (event.equals("Reader:FaviconRequest")) {
final String url = message.getString("url");
handleFaviconRequest(url);
- } else if (event.equals("Reader:GoToReadingList")) {
- showReadingList();
} else if (event.equals("Gecko:Ready")) {
mGeckoReadyStartupTimer.stop();
geckoConnected();
@@ -1479,7 +1477,6 @@ abstract public class GeckoApp
registerEventListener("Reader:Removed");
registerEventListener("Reader:Share");
registerEventListener("Reader:FaviconRequest");
- registerEventListener("Reader:GoToReadingList");
registerEventListener("onCameraCapture");
registerEventListener("Menu:Add");
registerEventListener("Menu:Remove");
@@ -2028,7 +2025,6 @@ abstract public class GeckoApp
unregisterEventListener("Reader:Removed");
unregisterEventListener("Reader:Share");
unregisterEventListener("Reader:FaviconRequest");
- unregisterEventListener("Reader:GoToReadingList");
unregisterEventListener("onCameraCapture");
unregisterEventListener("Menu:Add");
unregisterEventListener("Menu:Remove");
@@ -2261,18 +2257,13 @@ abstract public class GeckoApp
return mPromptService;
}
- public void showReadingList() {
- Intent intent = new Intent(getBaseContext(), AwesomeBar.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_NO_HISTORY);
- intent.putExtra(AwesomeBar.TARGET_KEY, AwesomeBar.Target.CURRENT_TAB.toString());
- intent.putExtra(AwesomeBar.READING_LIST_KEY, true);
-
- int requestCode = GeckoAppShell.sActivityHelper.makeRequestCodeForAwesomebar();
- startActivityForResult(intent, requestCode);
- }
-
@Override
public void onBackPressed() {
+ if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
+ super.onBackPressed();
+ return;
+ }
+
if (autoHideTabs()) {
return;
}
diff --git a/mobile/android/base/GeckoAppShell.java b/mobile/android/base/GeckoAppShell.java
index 381a2236fbef..4fa8e24f79f3 100644
--- a/mobile/android/base/GeckoAppShell.java
+++ b/mobile/android/base/GeckoAppShell.java
@@ -697,8 +697,8 @@ public class GeckoAppShell
createShortcut(aTitle, aURI, aURI, aIconData, aType);
}
- // internal, for non-webapps
- static void createShortcut(String aTitle, String aURI, Bitmap aBitmap, String aType) {
+ // for non-webapps
+ public static void createShortcut(String aTitle, String aURI, Bitmap aBitmap, String aType) {
createShortcut(aTitle, aURI, aURI, aBitmap, aType);
}
@@ -1069,12 +1069,12 @@ public class GeckoAppShell
* @param title the title to use in ACTION_SEND
intents.
* @return true if the activity started successfully; false otherwise.
*/
- static boolean openUriExternal(String targetURI,
- String mimeType,
- String packageName,
- String className,
- String action,
- String title) {
+ public static boolean openUriExternal(String targetURI,
+ String mimeType,
+ String packageName,
+ String className,
+ String action,
+ String title) {
final Context context = getContext();
final Intent intent = getOpenURIIntent(context, targetURI,
mimeType, action, title);
diff --git a/mobile/android/base/InputMethods.java b/mobile/android/base/InputMethods.java
index be20949ff35e..f191bd8f3e29 100644
--- a/mobile/android/base/InputMethods.java
+++ b/mobile/android/base/InputMethods.java
@@ -61,7 +61,7 @@ final class InputMethods {
return METHOD_HTC_TOUCH_INPUT.equals(inputMethod);
}
- public static boolean shouldDelayAwesomebarUpdate(Context context) {
+ public static boolean shouldDelayUrlBarUpdate(Context context) {
String inputMethod = getCurrentInputMethod(context);
return METHOD_SAMSUNG.equals(inputMethod) ||
METHOD_SWIFTKEY.equals(inputMethod);
diff --git a/mobile/android/base/Makefile.in b/mobile/android/base/Makefile.in
index 68fced083368..ea4961e88f44 100644
--- a/mobile/android/base/Makefile.in
+++ b/mobile/android/base/Makefile.in
@@ -54,18 +54,12 @@ FENNEC_JAVA_FILES = \
AndroidImportPreference.java \
AnimatedHeightLayout.java \
AppNotificationClient.java \
- AwesomeBar.java \
- AwesomebarResultHandler.java \
- AwesomeBarTabs.java \
+ AutocompleteHandler.java \
animation/AnimatorProxy.java \
animation/HeightChangeAnimation.java \
animation/PropertyAnimator.java \
animation/Rotate3DAnimation.java \
animation/ViewHelper.java \
- awesomebar/AwesomeBarTab.java \
- awesomebar/AllPagesTab.java \
- awesomebar/BookmarksTab.java \
- awesomebar/HistoryTab.java \
BackButton.java \
BrowserApp.java \
BrowserToolbar.java \
@@ -138,7 +132,6 @@ FENNEC_JAVA_FILES = \
PromptInput.java \
PromptService.java \
Restarter.java \
- SearchEngine.java \
sqlite/ByteBufferInputStream.java \
sqlite/MatrixBlobCursor.java \
sqlite/SQLiteBridge.java \
@@ -146,7 +139,6 @@ FENNEC_JAVA_FILES = \
ReaderModeUtils.java \
RemoteTabs.java \
RobocopAPI.java \
- SearchEngineRow.java \
ServiceNotificationClient.java \
ScrollAnimator.java \
SessionParser.java \
@@ -154,7 +146,6 @@ FENNEC_JAVA_FILES = \
SharedPreferencesHelper.java \
SiteIdentityPopup.java \
SmsManager.java \
- SuggestClient.java \
SurfaceBits.java \
SyncPreference.java \
Tab.java \
@@ -224,6 +215,36 @@ FENNEC_JAVA_FILES = \
gfx/TouchEventHandler.java \
gfx/ViewTransform.java \
gfx/VirtualLayer.java \
+ home/BookmarksListAdapter.java \
+ home/BookmarksListView.java \
+ home/BookmarksPage.java \
+ home/BookmarkFolderView.java \
+ home/BookmarkThumbnailView.java \
+ home/BrowserSearch.java \
+ home/HistoryPage.java \
+ home/HomeCursorLoaderCallbacks.java \
+ home/HomeFragment.java \
+ home/HomeListView.java \
+ home/HomePager.java \
+ home/HomePagerTabStrip.java \
+ home/FadedTextView.java \
+ home/FaviconsLoader.java \
+ home/LastTabsPage.java \
+ home/MostRecentPage.java \
+ home/MostVisitedPage.java \
+ home/MultiTypeCursorAdapter.java \
+ home/PinBookmarkDialog.java \
+ home/ReadingListPage.java \
+ home/SearchEngine.java \
+ home/SearchEngineRow.java \
+ home/SearchLoader.java \
+ home/SimpleCursorLoader.java \
+ home/SuggestClient.java \
+ home/TabMenuStrip.java \
+ home/TopBookmarkItemView.java \
+ home/TopBookmarksAdapter.java \
+ home/TopBookmarksView.java \
+ home/TwoLinePageRow.java \
menu/GeckoMenu.java \
menu/GeckoMenuInflater.java \
menu/GeckoMenuItem.java \
@@ -235,11 +256,7 @@ FENNEC_JAVA_FILES = \
menu/MenuPopup.java \
preferences/SearchPreferenceCategory.java \
preferences/SearchEnginePreference.java \
- widget/AboutHome.java \
- widget/AboutHomeView.java \
- widget/AboutHomeSection.java \
widget/ActivityChooserModel.java \
- widget/AddonsSection.java \
widget/ButtonToast.java \
widget/ArrowPopup.java \
widget/DateTimePicker.java \
@@ -248,11 +265,6 @@ FENNEC_JAVA_FILES = \
widget/GeckoPopupMenu.java \
widget/GeckoActionProvider.java \
widget/IconTabWidget.java \
- widget/LastTabsSection.java \
- widget/LinkTextView.java \
- widget/PromoBox.java \
- widget/RemoteTabsSection.java \
- widget/TopSitesView.java \
widget/TabRow.java \
widget/ThumbnailView.java \
widget/TwoWayView.java \
@@ -441,20 +453,13 @@ endif
RES_LAYOUT = \
$(SYNC_RES_LAYOUT) \
- res/layout/abouthome_content.xml \
res/layout/arrow_popup.xml \
res/layout/autocomplete_list.xml \
res/layout/autocomplete_list_item.xml \
- res/layout/awesomebar.xml \
- res/layout/awesomebar_folder_row.xml \
- res/layout/awesomebar_header_row.xml \
- res/layout/awesomebar_allpages_list.xml \
- res/layout/awesomebar_row.xml \
- res/layout/awesomebar_search.xml \
- res/layout/awesomebar_suggestion_prompt.xml \
- res/layout/awesomebar_tab_indicator.xml \
- res/layout/awesomebar_tabs.xml \
res/layout/bookmark_edit.xml \
+ res/layout/bookmark_folder_row.xml \
+ res/layout/bookmark_item_row.xml \
+ res/layout/browser_search.xml \
res/layout/browser_toolbar.xml \
res/layout/datetime_picker.xml \
res/layout/doorhanger.xml \
@@ -462,7 +467,21 @@ RES_LAYOUT = \
res/layout/find_in_page_content.xml \
res/layout/font_size_preference.xml \
res/layout/gecko_app.xml \
+ res/layout/home_bookmarks_page.xml \
+ res/layout/home_empty_page.xml \
+ res/layout/home_empty_reading_page.xml \
+ res/layout/home_item_row.xml \
+ res/layout/home_header_row.xml \
+ res/layout/home_history_page.xml \
+ res/layout/home_history_tabs_indicator.xml \
+ res/layout/home_last_tabs_page.xml \
+ res/layout/home_history_list.xml \
+ res/layout/home_most_recent_page.xml \
+ res/layout/home_most_visited_page.xml \
+ res/layout/home_pager.xml \
+ res/layout/home_reading_list_page.xml \
res/layout/home_search_item_row.xml \
+ res/layout/home_suggestion_prompt.xml \
res/layout/web_app.xml \
res/layout/launch_app_list.xml \
res/layout/launch_app_listitem.xml \
@@ -472,6 +491,7 @@ RES_LAYOUT = \
res/layout/notification_icon_text.xml \
res/layout/notification_progress.xml \
res/layout/notification_progress_text.xml \
+ res/layout/pin_bookmark_dialog.xml \
res/layout/preference_rightalign_icon.xml \
res/layout/preference_search_tip.xml \
res/layout/search_engine_row.xml \
@@ -482,6 +502,8 @@ RES_LAYOUT = \
res/layout/suggestion_item.xml \
res/layout/remote_tabs_child.xml \
res/layout/remote_tabs_group.xml \
+ res/layout/search_engine_row.xml \
+ res/layout/tab_menu_strip.xml \
res/layout/tabs_panel.xml \
res/layout/tabs_counter.xml \
res/layout/tabs_panel_header.xml \
@@ -489,42 +511,41 @@ 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 \
res/layout/select_dialog_multichoice.xml \
res/layout/select_dialog_singlechoice.xml \
res/layout/simple_dropdown_item_1line.xml \
- res/layout/abouthome_addon_row.xml \
- res/layout/abouthome_last_tabs_row.xml \
- res/layout/abouthome_section.xml \
- res/layout/abouthome_remote_tab_row.xml \
- res/layout/abouthome_topsite_item.xml \
+ res/layout/suggestion_item.xml \
res/layout/validation_message.xml \
res/layout/videoplayer.xml \
$(NULL)
RES_LAYOUT_LARGE_V11 = \
- res/layout-large-v11/awesomebar_search.xml \
res/layout-large-v11/browser_toolbar.xml \
+ res/layout-large-v11/home_pager.xml \
$(NULL)
RES_LAYOUT_LARGE_LAND_V11 = \
+ res/layout-large-land-v11/home_history_page.xml \
+ res/layout-large-land-v11/home_history_tabs_indicator.xml \
+ res/layout-large-land-v11/home_history_list.xml \
res/layout-large-land-v11/tabs_panel.xml \
res/layout-large-land-v11/tabs_panel_header.xml \
res/layout-large-land-v11/tabs_panel_footer.xml \
$(NULL)
RES_LAYOUT_XLARGE_V11 = \
- res/layout-xlarge-v11/awesomebar_search.xml \
res/layout-xlarge-v11/font_size_preference.xml \
+ res/layout-xlarge-v11/home_history_page.xml \
+ res/layout-xlarge-v11/home_history_tabs_indicator.xml \
+ res/layout-xlarge-v11/home_history_list.xml \
res/layout-xlarge-v11/remote_tabs_child.xml \
res/layout-xlarge-v11/remote_tabs_group.xml \
$(NULL)
-RES_LAYOUT_XLARGE_LAND_V11 = \
- res/layout-xlarge-land-v11/abouthome_content.xml \
- $(NULL)
-
RES_VALUES = \
$(SYNC_RES_VALUES) \
res/values/attrs.xml \
@@ -560,6 +581,7 @@ RES_VALUES_LARGE_V11 = \
$(NULL)
RES_VALUES_LARGE_LAND_V11 = \
+ res/values-large-land-v11/dimens.xml \
res/values-large-land-v11/styles.xml \
$(NULL)
@@ -569,10 +591,19 @@ RES_VALUES_XLARGE_V11 = \
res/values-xlarge-v11/styles.xml \
$(NULL)
+RES_VALUES_XLARGE_LAND_V11 = \
+ res/values-xlarge-land-v11/dimens.xml \
+ res/values-xlarge-land-v11/styles.xml \
+ $(NULL)
+
RES_VALUES_V14 = \
res/values-v14/styles.xml \
$(NULL)
+RES_VALUES_V16 = \
+ res/values-v16/styles.xml \
+ $(NULL)
+
RES_XML = \
res/xml/preferences_display.xml \
res/xml/preferences_search.xml \
@@ -590,11 +621,8 @@ RES_XML_V11 = \
$(NULL)
RES_ANIM = \
- res/anim/awesomebar_fade_in.xml \
res/anim/popup_show.xml \
res/anim/popup_hide.xml \
- res/anim/awesomebar_fade_out.xml \
- res/anim/awesomebar_hold_still.xml \
res/anim/grow_fade_in.xml \
res/anim/grow_fade_in_center.xml \
res/anim/progress_spinner.xml \
@@ -606,17 +634,7 @@ RES_DRAWABLE_MDPI = \
res/drawable-mdpi/blank.png \
res/drawable-mdpi/favicon.png \
res/drawable-mdpi/folder.png \
- res/drawable-mdpi/abouthome_icon.png \
- res/drawable-mdpi/abouthome_logo_dark.png \
- res/drawable-mdpi/abouthome_logo_light.png \
- res/drawable-mdpi/abouthome_promo_box_bg.9.png \
- res/drawable-mdpi/abouthome_promo_box_pressed_bg.9.png \
- res/drawable-mdpi/abouthome_promo_logo_apps.png \
- res/drawable-mdpi/abouthome_promo_logo_sync.png \
res/drawable-mdpi/abouthome_thumbnail.png \
- res/drawable-mdpi/abouthome_thumbnail_bg.png \
- res/drawable-mdpi/abouthome_thumbnail_add.png \
- res/drawable-mdpi/address_bar_bg_shadow.png \
res/drawable-mdpi/alert_addon.png \
res/drawable-mdpi/alert_app.png \
res/drawable-mdpi/alert_download.png \
@@ -625,18 +643,10 @@ RES_DRAWABLE_MDPI = \
res/drawable-mdpi/alert_mic_camera.png \
res/drawable-mdpi/arrow_popup_bg.9.png \
res/drawable-mdpi/autocomplete_list_bg.9.png \
- res/drawable-mdpi/awesomebar_tab_center.9.png \
- res/drawable-mdpi/awesomebar_tab_left.9.png \
- res/drawable-mdpi/awesomebar_tab_right.9.png \
- res/drawable-mdpi/awesomebar_sep_left.9.png \
- res/drawable-mdpi/awesomebar_sep_right.9.png \
+ res/drawable-mdpi/bookmark_folder_closed.png \
+ res/drawable-mdpi/bookmark_folder_opened.png \
res/drawable-mdpi/desktop_notification.png \
- res/drawable-mdpi/ic_addons_empty.png \
- res/drawable-mdpi/ic_awesomebar_go.png \
- res/drawable-mdpi/ic_awesomebar_reader.png \
- res/drawable-mdpi/ic_awesomebar_search.png \
- res/drawable-mdpi/ic_awesomebar_star.png \
- res/drawable-mdpi/ic_awesomebar_tab.png \
+ res/drawable-mdpi/home_tab_menu_strip.9.png \
res/drawable-mdpi/ic_menu_addons_filler.png \
res/drawable-mdpi/ic_menu_bookmark_add.png \
res/drawable-mdpi/ic_menu_bookmark_remove.png \
@@ -648,7 +658,19 @@ RES_DRAWABLE_MDPI = \
res/drawable-mdpi/ic_menu_new_tab.png \
res/drawable-mdpi/ic_menu_reload.png \
res/drawable-mdpi/ic_status_logo.png \
+ res/drawable-mdpi/ic_url_bar_go.png \
+ res/drawable-mdpi/ic_url_bar_reader.png \
+ res/drawable-mdpi/ic_url_bar_search.png \
+ res/drawable-mdpi/ic_url_bar_star.png \
+ res/drawable-mdpi/ic_url_bar_tab.png \
+ res/drawable-mdpi/icon_last_tabs.png \
+ res/drawable-mdpi/icon_last_tabs_empty.png \
+ res/drawable-mdpi/icon_most_recent.png \
+ res/drawable-mdpi/icon_most_recent_empty.png \
+ res/drawable-mdpi/icon_most_visited.png \
+ res/drawable-mdpi/icon_most_visited_empty.png \
res/drawable-mdpi/icon_pageaction.png \
+ res/drawable-mdpi/icon_reading_list_empty.png \
res/drawable-mdpi/progress_spinner.png \
res/drawable-mdpi/tab_indicator_divider.9.png \
res/drawable-mdpi/tab_indicator_selected.9.png \
@@ -663,15 +685,16 @@ RES_DRAWABLE_MDPI = \
res/drawable-mdpi/tab_thumbnail_shadow.png \
res/drawable-mdpi/tabs_count.png \
res/drawable-mdpi/tabs_count_foreground.png \
+ res/drawable-mdpi/url_bar_bg_shadow.png \
+ res/drawable-mdpi/url_bar_entry_default.9.png \
+ res/drawable-mdpi/url_bar_entry_default_pb.9.png \
+ res/drawable-mdpi/url_bar_entry_pressed.9.png \
+ res/drawable-mdpi/url_bar_entry_pressed_pb.9.png \
res/drawable-mdpi/tip_addsearch.png \
res/drawable-mdpi/toast.9.png \
res/drawable-mdpi/toast_button_focused.9.png \
res/drawable-mdpi/toast_button_pressed.9.png \
res/drawable-mdpi/toast_divider.9.png \
- res/drawable-mdpi/address_bar_url_default.9.png \
- res/drawable-mdpi/address_bar_url_default_pb.9.png \
- res/drawable-mdpi/address_bar_url_pressed.9.png \
- res/drawable-mdpi/address_bar_url_pressed_pb.9.png \
res/drawable-mdpi/find_close.png \
res/drawable-mdpi/find_next.png \
res/drawable-mdpi/find_prev.png \
@@ -692,8 +715,10 @@ RES_DRAWABLE_MDPI = \
res/drawable-mdpi/tabs_normal.png \
res/drawable-mdpi/tabs_private.png \
res/drawable-mdpi/tabs_synced.png \
+ res/drawable-mdpi/top_bookmark_add.png \
res/drawable-mdpi/urlbar_stop.png \
res/drawable-mdpi/reader.png \
+ res/drawable-mdpi/reader_cropped.png \
res/drawable-mdpi/reader_active.png \
res/drawable-mdpi/reading_list.png \
res/drawable-mdpi/validation_arrow.png \
@@ -708,6 +733,7 @@ RES_DRAWABLE_MDPI = \
res/drawable-mdpi/shadow.png \
res/drawable-mdpi/start.png \
res/drawable-mdpi/marketplace.png \
+ res/drawable-mdpi/history_tabs_indicator_selected.9.png \
res/drawable-mdpi/warning.png \
res/drawable-mdpi/warning_doorhanger.png \
$(NULL)
@@ -723,35 +749,17 @@ RES_DRAWABLE_HDPI = \
res/drawable-hdpi/folder.png \
res/drawable-hdpi/home_bg.png \
res/drawable-hdpi/home_star.png \
- res/drawable-hdpi/abouthome_icon.png \
- res/drawable-hdpi/abouthome_logo_dark.png \
- res/drawable-hdpi/abouthome_logo_light.png \
- res/drawable-hdpi/abouthome_promo_box_bg.9.png \
- res/drawable-hdpi/abouthome_promo_box_pressed_bg.9.png \
- res/drawable-hdpi/abouthome_promo_logo_apps.png \
- res/drawable-hdpi/abouthome_promo_logo_sync.png \
res/drawable-hdpi/abouthome_thumbnail.png \
- res/drawable-hdpi/abouthome_thumbnail_bg.png \
- res/drawable-hdpi/abouthome_thumbnail_add.png \
- res/drawable-hdpi/address_bar_bg_shadow.png \
res/drawable-hdpi/alert_addon.png \
res/drawable-hdpi/alert_app.png \
res/drawable-hdpi/alert_download.png \
+ res/drawable-hdpi/bookmark_folder_closed.png \
+ res/drawable-hdpi/bookmark_folder_opened.png \
res/drawable-hdpi/alert_camera.png \
res/drawable-hdpi/alert_mic.png \
res/drawable-hdpi/alert_mic_camera.png \
res/drawable-hdpi/arrow_popup_bg.9.png \
- res/drawable-hdpi/awesomebar_tab_center.9.png \
- res/drawable-hdpi/awesomebar_tab_left.9.png \
- res/drawable-hdpi/awesomebar_tab_right.9.png \
- res/drawable-hdpi/awesomebar_sep_left.9.png \
- res/drawable-hdpi/awesomebar_sep_right.9.png \
- res/drawable-hdpi/ic_addons_empty.png \
- res/drawable-hdpi/ic_awesomebar_go.png \
- res/drawable-hdpi/ic_awesomebar_reader.png \
- res/drawable-hdpi/ic_awesomebar_search.png \
- res/drawable-hdpi/ic_awesomebar_star.png \
- res/drawable-hdpi/ic_awesomebar_tab.png \
+ res/drawable-hdpi/home_tab_menu_strip.9.png \
res/drawable-hdpi/ic_menu_addons_filler.png \
res/drawable-hdpi/ic_menu_bookmark_add.png \
res/drawable-hdpi/ic_menu_bookmark_remove.png \
@@ -763,7 +771,19 @@ RES_DRAWABLE_HDPI = \
res/drawable-hdpi/ic_menu_new_tab.png \
res/drawable-hdpi/ic_menu_reload.png \
res/drawable-hdpi/ic_status_logo.png \
+ res/drawable-hdpi/ic_url_bar_go.png \
+ res/drawable-hdpi/ic_url_bar_reader.png \
+ res/drawable-hdpi/ic_url_bar_search.png \
+ res/drawable-hdpi/ic_url_bar_star.png \
+ res/drawable-hdpi/ic_url_bar_tab.png \
+ res/drawable-hdpi/icon_last_tabs.png \
+ res/drawable-hdpi/icon_last_tabs_empty.png \
+ res/drawable-hdpi/icon_most_recent.png \
+ res/drawable-hdpi/icon_most_recent_empty.png \
+ res/drawable-hdpi/icon_most_visited.png \
+ res/drawable-hdpi/icon_most_visited_empty.png \
res/drawable-hdpi/icon_pageaction.png \
+ res/drawable-hdpi/icon_reading_list_empty.png \
res/drawable-hdpi/tab_indicator_divider.9.png \
res/drawable-hdpi/tab_indicator_selected.9.png \
res/drawable-hdpi/tab_indicator_selected_focused.9.png \
@@ -777,11 +797,12 @@ RES_DRAWABLE_HDPI = \
res/drawable-hdpi/tab_thumbnail_shadow.png \
res/drawable-hdpi/tabs_count.png \
res/drawable-hdpi/tabs_count_foreground.png \
+ res/drawable-hdpi/url_bar_bg_shadow.png \
+ res/drawable-hdpi/url_bar_entry_default.9.png \
+ res/drawable-hdpi/url_bar_entry_default_pb.9.png \
+ res/drawable-hdpi/url_bar_entry_pressed.9.png \
+ res/drawable-hdpi/url_bar_entry_pressed_pb.9.png \
res/drawable-hdpi/tip_addsearch.png \
- res/drawable-hdpi/address_bar_url_default.9.png \
- res/drawable-hdpi/address_bar_url_default_pb.9.png \
- res/drawable-hdpi/address_bar_url_pressed.9.png \
- res/drawable-hdpi/address_bar_url_pressed_pb.9.png \
res/drawable-hdpi/find_close.png \
res/drawable-hdpi/find_next.png \
res/drawable-hdpi/find_prev.png \
@@ -802,8 +823,10 @@ RES_DRAWABLE_HDPI = \
res/drawable-hdpi/tabs_normal.png \
res/drawable-hdpi/tabs_private.png \
res/drawable-hdpi/tabs_synced.png \
+ res/drawable-hdpi/top_bookmark_add.png \
res/drawable-hdpi/urlbar_stop.png \
res/drawable-hdpi/reader.png \
+ res/drawable-hdpi/reader_cropped.png \
res/drawable-hdpi/reader_active.png \
res/drawable-hdpi/reading_list.png \
res/drawable-hdpi/validation_arrow.png \
@@ -812,6 +835,7 @@ RES_DRAWABLE_HDPI = \
res/drawable-hdpi/handle_end.png \
res/drawable-hdpi/handle_middle.png \
res/drawable-hdpi/handle_start.png \
+ res/drawable-hdpi/history_tabs_indicator_selected.9.png \
res/drawable-hdpi/warning.png \
res/drawable-hdpi/warning_doorhanger.png \
$(NULL)
@@ -820,39 +844,22 @@ RES_DRAWABLE_XHDPI = \
res/drawable-xhdpi/blank.png \
res/drawable-xhdpi/favicon.png \
res/drawable-xhdpi/folder.png \
- res/drawable-xhdpi/abouthome_icon.png \
- res/drawable-xhdpi/abouthome_logo_dark.png \
- res/drawable-xhdpi/abouthome_logo_light.png \
- res/drawable-xhdpi/abouthome_promo_box_bg.9.png \
- res/drawable-xhdpi/abouthome_promo_box_pressed_bg.9.png \
- res/drawable-xhdpi/abouthome_promo_logo_apps.png \
- res/drawable-xhdpi/abouthome_promo_logo_sync.png \
res/drawable-xhdpi/abouthome_thumbnail.png \
- res/drawable-xhdpi/abouthome_thumbnail_bg.png \
- res/drawable-xhdpi/abouthome_thumbnail_add.png \
- res/drawable-xhdpi/address_bar_bg_shadow.png \
- res/drawable-xhdpi/address_bar_url_default.9.png \
- res/drawable-xhdpi/address_bar_url_default_pb.9.png \
- res/drawable-xhdpi/address_bar_url_pressed.9.png \
- res/drawable-xhdpi/address_bar_url_pressed_pb.9.png \
+ res/drawable-xhdpi/url_bar_bg_shadow.png \
+ res/drawable-xhdpi/url_bar_entry_default.9.png \
+ res/drawable-xhdpi/url_bar_entry_default_pb.9.png \
+ res/drawable-xhdpi/url_bar_entry_pressed.9.png \
+ res/drawable-xhdpi/url_bar_entry_pressed_pb.9.png \
res/drawable-xhdpi/alert_addon.png \
res/drawable-xhdpi/alert_app.png \
res/drawable-xhdpi/alert_download.png \
+ res/drawable-xhdpi/bookmark_folder_closed.png \
+ res/drawable-xhdpi/bookmark_folder_opened.png \
res/drawable-xhdpi/alert_camera.png \
res/drawable-xhdpi/alert_mic.png \
res/drawable-xhdpi/alert_mic_camera.png \
res/drawable-xhdpi/arrow_popup_bg.9.png \
- res/drawable-xhdpi/awesomebar_tab_center.9.png \
- res/drawable-xhdpi/awesomebar_tab_left.9.png \
- res/drawable-xhdpi/awesomebar_tab_right.9.png \
- res/drawable-xhdpi/awesomebar_sep_left.9.png \
- res/drawable-xhdpi/awesomebar_sep_right.9.png \
- res/drawable-xhdpi/ic_addons_empty.png \
- res/drawable-xhdpi/ic_awesomebar_go.png \
- res/drawable-xhdpi/ic_awesomebar_reader.png \
- res/drawable-xhdpi/ic_awesomebar_search.png \
- res/drawable-xhdpi/ic_awesomebar_star.png \
- res/drawable-xhdpi/ic_awesomebar_tab.png \
+ res/drawable-xhdpi/home_tab_menu_strip.9.png \
res/drawable-xhdpi/ic_menu_addons_filler.png \
res/drawable-xhdpi/ic_menu_bookmark_add.png \
res/drawable-xhdpi/ic_menu_bookmark_remove.png \
@@ -864,7 +871,19 @@ RES_DRAWABLE_XHDPI = \
res/drawable-xhdpi/ic_menu_new_tab.png \
res/drawable-xhdpi/ic_menu_reload.png \
res/drawable-xhdpi/ic_status_logo.png \
+ res/drawable-xhdpi/ic_url_bar_go.png \
+ res/drawable-xhdpi/ic_url_bar_reader.png \
+ res/drawable-xhdpi/ic_url_bar_search.png \
+ res/drawable-xhdpi/ic_url_bar_star.png \
+ res/drawable-xhdpi/ic_url_bar_tab.png \
+ res/drawable-xhdpi/icon_last_tabs.png \
+ res/drawable-xhdpi/icon_last_tabs_empty.png \
+ res/drawable-xhdpi/icon_most_recent.png \
+ res/drawable-xhdpi/icon_most_recent_empty.png \
+ res/drawable-xhdpi/icon_most_visited.png \
+ res/drawable-xhdpi/icon_most_visited_empty.png \
res/drawable-xhdpi/icon_pageaction.png \
+ res/drawable-xhdpi/icon_reading_list_empty.png \
res/drawable-xhdpi/spinner_default.9.png \
res/drawable-xhdpi/spinner_focused.9.png \
res/drawable-xhdpi/spinner_pressed.9.png \
@@ -879,8 +898,10 @@ RES_DRAWABLE_XHDPI = \
res/drawable-xhdpi/find_close.png \
res/drawable-xhdpi/find_next.png \
res/drawable-xhdpi/find_prev.png \
+ res/drawable-xhdpi/top_bookmark_add.png \
res/drawable-xhdpi/urlbar_stop.png \
res/drawable-xhdpi/reader.png \
+ res/drawable-xhdpi/reader_cropped.png \
res/drawable-xhdpi/reader_active.png \
res/drawable-xhdpi/reading_list.png \
res/drawable-xhdpi/larry.png \
@@ -909,6 +930,7 @@ RES_DRAWABLE_XHDPI = \
res/drawable-xhdpi/handle_end.png \
res/drawable-xhdpi/handle_middle.png \
res/drawable-xhdpi/handle_start.png \
+ res/drawable-xhdpi/history_tabs_indicator_selected.9.png \
res/drawable-xhdpi/warning.png \
res/drawable-xhdpi/warning_doorhanger.png \
$(NULL)
@@ -1000,6 +1022,10 @@ RES_DRAWABLE_XHDPI_V11 = \
res/drawable-xhdpi-v11/ic_status_logo.png \
$(NULL)
+RES_DRAWABLE_LARGE_LAND_V11 = \
+ res/drawable-large-land-v11/home_history_tabs_indicator.xml \
+ $(NULL)
+
RES_DRAWABLE_LARGE_MDPI_V11 = \
res/drawable-large-mdpi-v11/arrow_popup_bg.9.png \
res/drawable-large-mdpi-v11/ic_menu_reload.png \
@@ -1021,42 +1047,26 @@ RES_DRAWABLE_LARGE_XHDPI_V11 = \
res/drawable-large-xhdpi-v11/menu.png \
$(NULL)
+RES_DRAWABLE_XLARGE_V11 = \
+ res/drawable-xlarge-v11/home_history_tabs_indicator.xml \
+ $(NULL)
+
RES_DRAWABLE_XLARGE_MDPI_V11 = \
- res/drawable-xlarge-mdpi-v11/awesomebar_tab_center.9.png \
- res/drawable-xlarge-mdpi-v11/awesomebar_tab_left.9.png \
- res/drawable-xlarge-mdpi-v11/awesomebar_tab_right.9.png \
- res/drawable-xlarge-mdpi-v11/awesomebar_sep_left.9.png \
- res/drawable-xlarge-mdpi-v11/awesomebar_sep_right.9.png \
res/drawable-xlarge-mdpi-v11/ic_menu_bookmark_add.png \
res/drawable-xlarge-mdpi-v11/ic_menu_bookmark_remove.png \
$(NULL)
RES_DRAWABLE_XLARGE_HDPI_V11 = \
- res/drawable-xlarge-hdpi-v11/awesomebar_tab_center.9.png \
- res/drawable-xlarge-hdpi-v11/awesomebar_tab_left.9.png \
- res/drawable-xlarge-hdpi-v11/awesomebar_tab_right.9.png \
- res/drawable-xlarge-hdpi-v11/awesomebar_sep_left.9.png \
- res/drawable-xlarge-hdpi-v11/awesomebar_sep_right.9.png \
res/drawable-xlarge-hdpi-v11/ic_menu_bookmark_add.png \
res/drawable-xlarge-hdpi-v11/ic_menu_bookmark_remove.png \
$(NULL)
RES_DRAWABLE_XLARGE_XHDPI_V11 = \
- res/drawable-xlarge-xhdpi-v11/awesomebar_tab_center.9.png \
- res/drawable-xlarge-xhdpi-v11/awesomebar_tab_left.9.png \
- res/drawable-xlarge-xhdpi-v11/awesomebar_tab_right.9.png \
- res/drawable-xlarge-xhdpi-v11/awesomebar_sep_left.9.png \
- res/drawable-xlarge-xhdpi-v11/awesomebar_sep_right.9.png \
res/drawable-xlarge-xhdpi-v11/ic_menu_bookmark_add.png \
res/drawable-xlarge-xhdpi-v11/ic_menu_bookmark_remove.png \
$(NULL)
RES_COLOR = \
- res/color/abouthome_section_more_text.xml \
- res/color/abouthome_section_subtitle.xml \
- res/color/abouthome_section_title.xml \
- res/color/awesome_bar_title.xml \
- res/color/awesome_bar_title_hint.xml \
res/color/primary_text.xml \
res/color/primary_text_inverse.xml \
res/color/secondary_text.xml \
@@ -1064,14 +1074,17 @@ 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)
RES_MENU = \
- res/menu/abouthome_topsites_contextmenu.xml \
- res/menu/awesomebar_contextmenu.xml \
res/menu/browser_app_menu.xml \
res/menu/gecko_app_menu.xml \
+ res/menu/home_contextmenu.xml \
res/menu/titlebar_contextmenu.xml \
+ res/menu/top_bookmarks_contextmenu.xml \
res/menu-large-v11/browser_app_menu.xml \
res/menu-v11/browser_app_menu.xml \
res/menu-xlarge-v11/browser_app_menu.xml \
@@ -1086,25 +1099,23 @@ RES_LAYOUT += res/layout/crash_reporter.xml
endif
RES_DRAWABLE += \
- $(SYNC_RES_DRAWABLE) \
- res/drawable/abouthome_logo.xml \
- res/drawable/abouthome_promo_box.xml \
+ $(SYNC_RES_DRAWABLE) \
res/drawable/action_bar_button.xml \
res/drawable/action_bar_button_inverse.xml \
- res/drawable/address_bar_bg.xml \
- res/drawable/address_bar_bg_shadow_repeat.xml \
- res/drawable/address_bar_nav_button.xml \
- res/drawable/address_bar_right_edge.xml \
- res/drawable/address_bar_url.xml \
- res/drawable/awesomebar_listview_divider.xml \
- res/drawable/awesomebar_header_row.xml \
- res/drawable/awesomebar_tab_indicator.xml \
- res/drawable/awesomebar_tab_selected.xml \
- res/drawable/awesomebar_tab_unselected.xml \
+ res/drawable/bookmark_thumbnail_bg.xml \
+ res/drawable/url_bar_bg.xml \
+ res/drawable/url_bar_bg_shadow_repeat.xml \
+ res/drawable/url_bar_entry.xml \
+ res/drawable/url_bar_nav_button.xml \
+ res/drawable/url_bar_right_edge.xml \
+ res/drawable/bookmark_folder.xml \
+ res/drawable/divider_horizontal.xml \
res/drawable/divider_vertical.xml \
res/drawable/favicon_bg.xml \
res/drawable/handle_end_level.xml \
res/drawable/handle_start_level.xml \
+ res/drawable/home_history_tabs_indicator.xml \
+ res/drawable/home_page_title_background.xml \
res/drawable/ic_menu_back.xml \
res/drawable/ic_menu_desktop_mode_off.xml \
res/drawable/ic_menu_desktop_mode_on.xml \
@@ -1131,6 +1142,7 @@ RESOURCES = \
$(RES_DRAWABLE) \
$(RES_DRAWABLE_HDPI) \
$(RES_DRAWABLE_HDPI_V11) \
+ $(RES_DRAWABLE_LARGE_LAND_V11) \
$(RES_DRAWABLE_LARGE_HDPI_V11) \
$(RES_DRAWABLE_LARGE_MDPI_V11) \
$(RES_DRAWABLE_LARGE_XHDPI_V11) \
@@ -1139,6 +1151,7 @@ RESOURCES = \
$(RES_DRAWABLE_MDPI_V11) \
$(RES_DRAWABLE_XHDPI) \
$(RES_DRAWABLE_XHDPI_V11) \
+ $(RES_DRAWABLE_XLARGE_V11) \
$(RES_DRAWABLE_XLARGE_HDPI_V11) \
$(RES_DRAWABLE_XLARGE_MDPI_V11) \
$(RES_DRAWABLE_XLARGE_XHDPI_V11) \
@@ -1155,6 +1168,8 @@ RESOURCES = \
$(RES_VALUES_LARGE_V11) \
$(RES_VALUES_V11) \
$(RES_VALUES_V14) \
+ $(RES_VALUES_V16) \
+ $(RES_VALUES_XLARGE_LAND_V11) \
$(RES_VALUES_XLARGE_V11) \
$(RES_XML) \
$(RES_XML_V11) \
@@ -1165,12 +1180,13 @@ RES_DIRS= \
res/layout-large-v11 \
res/layout-large-land-v11 \
res/layout-xlarge-v11 \
- res/layout-xlarge-land-v11 \
res/values \
res/values-v11 \
res/values-large-v11 \
+ res/values-xlarge-land-v11 \
res/values-xlarge-v11 \
- res/values-land-v14 \
+ res/values-v14 \
+ res/values-v16 \
res/xml \
res/xml-v11 \
res/anim \
@@ -1182,9 +1198,11 @@ RES_DIRS= \
res/drawable-mdpi-v11 \
res/drawable-hdpi-v11 \
res/drawable-xhdpi-v11 \
+ res/drawable-large-land-v11 \
res/drawable-large-mdpi-v11 \
res/drawable-large-hdpi-v11 \
res/drawable-large-xhdpi-v11 \
+ res/drawable-xlarge-v11 \
res/drawable-xlarge-mdpi-v11 \
res/drawable-xlarge-hdpi-v11 \
res/drawable-xlarge-xhdpi-v11 \
diff --git a/mobile/android/base/PageActionLayout.java b/mobile/android/base/PageActionLayout.java
index 04fe8649a8f2..4bb7a8081b32 100644
--- a/mobile/android/base/PageActionLayout.java
+++ b/mobile/android/base/PageActionLayout.java
@@ -146,7 +146,7 @@ public class PageActionLayout extends LinearLayout implements GeckoEventListener
}
private ImageButton createImageButton() {
- ImageButton imageButton = new ImageButton(mContext, null, R.style.AddressBar_ImageButton_Icon);
+ ImageButton imageButton = new ImageButton(mContext, null, R.style.UrlBar_ImageButton_Icon);
imageButton.setLayoutParams(new LayoutParams(mContext.getResources().getDimensionPixelSize(R.dimen.page_action_button_width), LayoutParams.MATCH_PARENT));
imageButton.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
imageButton.setOnClickListener(this);
diff --git a/mobile/android/base/Tab.java b/mobile/android/base/Tab.java
index 8715612a65b9..5b9c7f8494e0 100644
--- a/mobile/android/base/Tab.java
+++ b/mobile/android/base/Tab.java
@@ -7,6 +7,7 @@ package org.mozilla.gecko;
import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.gfx.Layer;
+import org.mozilla.gecko.home.HomePager;
import org.mozilla.gecko.util.ThreadUtils;
import org.json.JSONException;
@@ -49,6 +50,7 @@ public class Tab {
private int mHistoryIndex;
private int mHistorySize;
private int mParentId;
+ private HomePager.Page mAboutHomePage;
private boolean mExternal;
private boolean mBookmark;
private boolean mReadingListItem;
@@ -73,10 +75,12 @@ public class Tab {
public static final int STATE_SUCCESS = 2;
public static final int STATE_ERROR = 3;
+ private static final int DEFAULT_BACKGROUND_COLOR = Color.WHITE;
+
public enum ErrorType {
CERT_ERROR, // Pages with certificate problems
BLOCKED, // Pages blocked for phishing or malware warnings
- NET_ERROR, // All other types of error
+ NET_ERROR, // All other types of error
NONE // Non error pages
}
@@ -89,6 +93,7 @@ public class Tab {
mUserSearch = "";
mExternal = external;
mParentId = parentId;
+ mAboutHomePage = HomePager.Page.BOOKMARKS;
mTitle = title == null ? "" : title;
mFavicon = null;
mFaviconUrl = null;
@@ -112,7 +117,7 @@ public class Tab {
// At startup, the background is set to a color specified by LayerView
// when the LayerView is created. Shortly after, this background color
// will be used before the tab's content is shown.
- mBackgroundColor = getBackgroundColorForUrl(url);
+ mBackgroundColor = DEFAULT_BACKGROUND_COLOR;
}
private ContentResolver getContentResolver() {
@@ -139,6 +144,15 @@ public class Tab {
return mParentId;
}
+ public HomePager.Page getAboutHomePage() {
+ return mAboutHomePage;
+ }
+
+ private void setAboutHomePage(HomePager.Page page) {
+ mAboutHomePage = page;
+ }
+
+
// may be null if user-entered query hasn't yet been resolved to a URI
public synchronized String getURL() {
return mUrl;
@@ -607,9 +621,14 @@ public class Tab {
setReaderEnabled(false);
setZoomConstraints(new ZoomConstraints(true));
setHasTouchListeners(false);
- setBackgroundColor(getBackgroundColorForUrl(uri));
+ setBackgroundColor(DEFAULT_BACKGROUND_COLOR);
setErrorType(ErrorType.NONE);
+ final String homePage = message.getString("aboutHomePage");
+ if (!TextUtils.isEmpty(homePage)) {
+ setAboutHomePage(HomePager.Page.valueOf(homePage));
+ }
+
Tabs.getInstance().notifyListeners(this, Tabs.TabEvents.LOCATION_CHANGE, uri);
}
@@ -617,13 +636,6 @@ public class Tab {
return "about:home".equals(url) || ReaderModeUtils.isAboutReader(url);
}
- private int getBackgroundColorForUrl(String url) {
- if ("about:home".equals(url)) {
- return mAppContext.getResources().getColor(R.color.background_normal);
- }
- return Color.WHITE;
- }
-
void handleDocumentStart(boolean showProgress, String url) {
setState(shouldShowProgress(url) ? STATE_SUCCESS : STATE_LOADING);
updateIdentityData(null);
diff --git a/mobile/android/base/Tabs.java b/mobile/android/base/Tabs.java
index 8506cf58cdfb..219ffbd45d4c 100644
--- a/mobile/android/base/Tabs.java
+++ b/mobile/android/base/Tabs.java
@@ -6,6 +6,8 @@
package org.mozilla.gecko;
import org.mozilla.gecko.db.BrowserDB;
+import org.mozilla.gecko.home.HomePager;
+import org.mozilla.gecko.ReaderModeUtils;
import org.mozilla.gecko.sync.setup.SyncAccounts;
import org.mozilla.gecko.util.GeckoEventListener;
import org.mozilla.gecko.util.ThreadUtils;
@@ -22,6 +24,7 @@ import android.database.ContentObserver;
import android.graphics.Color;
import android.net.Uri;
import android.os.Handler;
+import android.text.TextUtils;
import android.util.Log;
import java.util.ArrayList;
@@ -57,6 +60,7 @@ public class Tabs implements GeckoEventListener {
public static final int LOADURL_DESKTOP = 1 << 5;
public static final int LOADURL_BACKGROUND = 1 << 6;
public static final int LOADURL_EXTERNAL = 1 << 7;
+ public static final int LOADURL_READING_LIST = 1 << 8;
private static final long PERSIST_TABS_AFTER_MILLISECONDS = 1000 * 5;
@@ -581,6 +585,22 @@ public class Tabs implements GeckoEventListener {
GeckoAppShell.getEventDispatcher().registerEventListener(event, this);
}
+ /**
+ * Looks for an open tab with the given URL.
+ *
+ * @return id of an open tab with the given URL; -1 if the tab doesn't exist.
+ */
+ public int getTabIdForUrl(String url) {
+ for (Tab tab : mOrder) {
+ if (TextUtils.equals(tab.getURL(), url) ||
+ TextUtils.equals(ReaderModeUtils.getUrlFromAboutReader(tab.getURL()), url)) {
+ return tab.getId();
+ }
+ }
+
+ return -1;
+ }
+
/**
* Loads a tab with the given URL in the currently selected tab.
*
@@ -637,6 +657,7 @@ public class Tabs implements GeckoEventListener {
args.put("delayLoad", delayLoad);
args.put("desktopMode", desktopMode);
args.put("selected", !background);
+ args.put("aboutHomePage", (flags & LOADURL_READING_LIST) != 0 ? HomePager.Page.READING_LIST : "");
if ((flags & LOADURL_NEW_TAB) != 0) {
int tabId = getNextTabId();
diff --git a/mobile/android/base/TabsPanel.java b/mobile/android/base/TabsPanel.java
index a983af2e7d56..70976f268ee3 100644
--- a/mobile/android/base/TabsPanel.java
+++ b/mobile/android/base/TabsPanel.java
@@ -105,19 +105,11 @@ public class TabsPanel extends LinearLayout
}
});
- ImageButton button;
- Resources resources = getContext().getResources();
-
mTabWidget = (IconTabWidget) findViewById(R.id.tab_widget);
- button = mTabWidget.addTab(R.drawable.tabs_normal);
- button.setContentDescription(resources.getString(R.string.tabs_normal));
-
- button = mTabWidget.addTab(R.drawable.tabs_private);
- button.setContentDescription(resources.getString(R.string.tabs_private));
-
- button = mTabWidget.addTab(R.drawable.tabs_synced);
- button.setContentDescription(resources.getString(R.string.tabs_synced));
+ mTabWidget.addTab(R.drawable.tabs_normal, R.string.tabs_normal);
+ mTabWidget.addTab(R.drawable.tabs_private, R.string.tabs_private);
+ mTabWidget.addTab(R.drawable.tabs_synced, R.string.tabs_synced);
mTabWidget.setTabSelectionListener(this);
}
diff --git a/mobile/android/base/TabsTray.java b/mobile/android/base/TabsTray.java
index e1c840f47964..8464c5fa42e0 100644
--- a/mobile/android/base/TabsTray.java
+++ b/mobile/android/base/TabsTray.java
@@ -315,7 +315,7 @@ public class TabsTray extends TwoWayView
mCloseAnimationCount++;
mPendingClosedTabs.add(view);
- animator.setPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
+ animator.addPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
@Override
public void onPropertyAnimationStart() { }
@Override
@@ -353,7 +353,7 @@ public class TabsTray extends TwoWayView
if (mOriginalSize == 0)
mOriginalSize = (isVertical ? view.getHeight() : view.getWidth());
- animator.setPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
+ animator.addPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
@Override
public void onPropertyAnimationStart() { }
@Override
@@ -377,7 +377,7 @@ public class TabsTray extends TwoWayView
animator.attach(view, Property.TRANSLATION_Y, 0);
- animator.setPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
+ animator.addPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
@Override
public void onPropertyAnimationStart() { }
@Override
diff --git a/mobile/android/base/ThumbnailHelper.java b/mobile/android/base/ThumbnailHelper.java
index 3bd2c06724bc..fd57ddeb7885 100644
--- a/mobile/android/base/ThumbnailHelper.java
+++ b/mobile/android/base/ThumbnailHelper.java
@@ -29,7 +29,7 @@ import java.util.concurrent.atomic.AtomicInteger;
public final class ThumbnailHelper {
private static final String LOGTAG = "GeckoThumbnailHelper";
- public static final float THUMBNAIL_ASPECT_RATIO = 0.714f; // this is a 5:7 ratio (as per UX decision)
+ public static final float THUMBNAIL_ASPECT_RATIO = 0.571f; // this is a 4:7 ratio (as per UX decision)
// static singleton stuff
diff --git a/mobile/android/base/animation/PropertyAnimator.java b/mobile/android/base/animation/PropertyAnimator.java
index 4d3642dea9e6..5eb515166426 100644
--- a/mobile/android/base/animation/PropertyAnimator.java
+++ b/mobile/android/base/animation/PropertyAnimator.java
@@ -11,6 +11,7 @@ import android.os.Handler;
import android.view.Choreographer;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
import android.view.animation.AnimationUtils;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
@@ -49,7 +50,7 @@ public class PropertyAnimator implements Runnable {
private long mDuration;
private float mDurationReciprocal;
private List mElementsList;
- private PropertyAnimationListener mListener;
+ private List mListeners;
private FramePoster mFramePoster;
private boolean mUseHardwareLayer;
@@ -64,6 +65,7 @@ public class PropertyAnimator implements Runnable {
mElementsList = new ArrayList();
mFramePoster = FramePoster.create(this);
mUseHardwareLayer = true;
+ mListeners = null;
}
public void setUseHardwareLayer(boolean useHardwareLayer) {
@@ -81,8 +83,12 @@ public class PropertyAnimator implements Runnable {
mElementsList.add(element);
}
- public void setPropertyAnimationListener(PropertyAnimationListener listener) {
- mListener = listener;
+ public void addPropertyAnimationListener(PropertyAnimationListener listener) {
+ if (mListeners == null) {
+ mListeners = new ArrayList();
+ }
+
+ mListeners.add(listener);
}
public long getDuration() {
@@ -144,10 +150,35 @@ public class PropertyAnimator implements Runnable {
element.view.setDrawingCacheEnabled(true);
}
- mFramePoster.postFirstAnimationFrame();
+ // Get ViewTreeObserver from any of the participant views
+ // in the animation.
+ final ViewTreeObserver treeObserver;
+ if (mElementsList.size() > 0) {
+ treeObserver = mElementsList.get(0).view.getViewTreeObserver();
+ } else {
+ treeObserver = null;
+ }
- if (mListener != null)
- mListener.onPropertyAnimationStart();
+ // Try to start animation after any on-going layout round
+ // in the current view tree.
+ if (treeObserver != null && treeObserver.isAlive()) {
+ treeObserver.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ treeObserver.removeOnPreDrawListener(this);
+ mFramePoster.postFirstAnimationFrame();
+ return true;
+ }
+ });
+ } else {
+ mFramePoster.postFirstAnimationFrame();
+ }
+
+ if (mListeners != null) {
+ for (PropertyAnimationListener listener : mListeners) {
+ listener.onPropertyAnimationStart();
+ }
+ }
}
@@ -173,10 +204,15 @@ public class PropertyAnimator implements Runnable {
mElementsList.clear();
- if (mListener != null) {
- if (snapToEndPosition)
- mListener.onPropertyAnimationEnd();
- mListener = null;
+ if (mListeners != null) {
+ if (snapToEndPosition) {
+ for (PropertyAnimationListener listener : mListeners) {
+ listener.onPropertyAnimationEnd();
+ }
+ }
+
+ mListeners.clear();
+ mListeners = null;
}
}
diff --git a/mobile/android/base/awesomebar/AllPagesTab.java b/mobile/android/base/awesomebar/AllPagesTab.java
deleted file mode 100644
index 3e004dea26d7..000000000000
--- a/mobile/android/base/awesomebar/AllPagesTab.java
+++ /dev/null
@@ -1,962 +0,0 @@
-/* -*- 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;
-
-import org.mozilla.gecko.AwesomeBar.ContextMenuSubject;
-import org.mozilla.gecko.db.BrowserContract.Combined;
-import org.mozilla.gecko.db.BrowserDB;
-import org.mozilla.gecko.db.BrowserDB.URLColumns;
-import org.mozilla.gecko.gfx.BitmapUtils;
-import org.mozilla.gecko.util.GamepadUtils;
-import org.mozilla.gecko.util.GeckoEventListener;
-import org.mozilla.gecko.util.StringUtils;
-import org.mozilla.gecko.util.ThreadUtils;
-import org.mozilla.gecko.util.UiAsyncTask;
-import org.mozilla.gecko.widget.FaviconView;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import android.app.Activity;
-import android.content.Context;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Handler;
-import android.os.Message;
-import android.os.SystemClock;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.LayoutInflater;
-import android.view.MenuInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.View.OnLongClickListener;
-import android.view.ViewGroup;
-import android.view.ViewGroup.LayoutParams;
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.AlphaAnimation;
-import android.view.animation.Animation;
-import android.view.animation.TranslateAnimation;
-import android.widget.AdapterView;
-import android.widget.FilterQueryProvider;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.ListView;
-import android.widget.SimpleCursorAdapter;
-import android.widget.TextView;
-
-import java.io.ByteArrayOutputStream;
-import java.util.ArrayList;
-import java.util.List;
-
-public class AllPagesTab extends AwesomeBarTab implements GeckoEventListener {
- public static final String LOGTAG = "GeckoAllPagesTab";
- private static final String TAG = "allPages";
-
- private static final int SUGGESTION_TIMEOUT = 3000;
- private static final int SUGGESTION_MAX = 3;
- private static final int ANIMATION_DURATION = 250;
- // The maximum number of rows deep in a search we'll dig for an autocomplete result
- private static final int MAX_AUTOCOMPLETE_SEARCH = 20;
-
- private String mSearchTerm;
- private ArrayList mSearchEngines;
- private SuggestClient mSuggestClient;
- private boolean mSuggestionsEnabled;
- private AsyncTask> mSuggestTask;
- private AwesomeBarCursorAdapter mCursorAdapter = null;
- private boolean mTelemetrySent = false;
- private LinearLayout mAllPagesView;
- private boolean mAnimateSuggestions;
- private View mSuggestionsOptInPrompt;
- private Handler mHandler;
- private ListView mListView;
- private volatile AutocompleteHandler mAutocompleteHandler = null;
-
- private static final int MESSAGE_LOAD_FAVICONS = 1;
- private static final int MESSAGE_UPDATE_FAVICONS = 2;
- private static final int DELAY_SHOW_THUMBNAILS = 550;
-
- public AllPagesTab(Context context) {
- super(context);
- mSearchEngines = new ArrayList();
-
- registerEventListener("SearchEngines:Data");
- GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("SearchEngines:GetVisible", null));
-
- mHandler = new AllPagesHandler();
- }
-
- @Override
- public boolean onBackPressed() {
- return false;
- }
-
- @Override
- public int getTitleStringId() {
- return R.string.awesomebar_all_pages_title;
- }
-
- @Override
- public String getTag() {
- return TAG;
- }
-
- private ListView getListView() {
- if (mListView == null && mView != null) {
- mListView = (ListView) mView.findViewById(R.id.awesomebar_list);
- }
- return mListView;
- }
-
- @Override
- public View getView() {
- if (mView == null) {
- mView = (LinearLayout) (LayoutInflater.from(mContext).inflate(R.layout.awesomebar_allpages_list, null));
- mView.setTag(TAG);
-
- final ListView list = getListView();
- list.setTag(TAG);
- ((Activity)mContext).registerForContextMenu(list);
- list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView> parent, View view, int position, long id) {
- handleItemClick(parent, view, position, id);
- }
- });
-
- AwesomeBarCursorAdapter adapter = getCursorAdapter();
- list.setAdapter(adapter);
- list.setOnTouchListener(mListListener);
-
- final ListSelectionListener listener = new ListSelectionListener();
- list.setOnItemSelectedListener(listener);
- list.setOnFocusChangeListener(listener);
-
- list.setOnKeyListener(new View.OnKeyListener() {
- @Override
- public boolean onKey(View v, int keyCode, android.view.KeyEvent event) {
- View selected = list.getSelectedView();
-
- if (selected instanceof SearchEngineRow) {
- return ((SearchEngineRow) selected).onKeyDown(keyCode, event);
- }
- return false;
- }
- });
-
- }
-
- return mView;
- }
-
- @Override
- public void destroy() {
- super.destroy();
-
- unregisterEventListener("SearchEngines:Data");
-
- mHandler.removeMessages(MESSAGE_UPDATE_FAVICONS);
- mHandler.removeMessages(MESSAGE_LOAD_FAVICONS);
- mHandler = null;
-
- // Can't use getters for adapter or listview. They will create them if null.
- if (mCursorAdapter != null && mListView != null) {
- mListView.setAdapter(null);
- final Cursor cursor = mCursorAdapter.getCursor();
- // Gingerbread locks the DB when closing a cursor, so do it in the
- // background.
- ThreadUtils.postToBackgroundThread(new Runnable() {
- @Override
- public void run() {
- if (cursor != null && !cursor.isClosed())
- cursor.close();
- }
- });
- }
- }
-
- public void filter(String searchTerm, AutocompleteHandler handler) {
- mAutocompleteHandler = handler;
-
- AwesomeBarCursorAdapter adapter = getCursorAdapter();
- adapter.filter(searchTerm);
-
- filterSuggestions(searchTerm);
- if (mSuggestionsOptInPrompt != null) {
- int visibility = TextUtils.isEmpty(searchTerm) ? View.GONE : View.VISIBLE;
- if (mSuggestionsOptInPrompt.getVisibility() != visibility) {
- mSuggestionsOptInPrompt.setVisibility(visibility);
- }
- }
- }
-
- private void findAutocompleteFor(String searchTerm, Cursor cursor) {
- if (TextUtils.isEmpty(searchTerm) || cursor == null || mAutocompleteHandler == null)
- return;
-
- // avoid searching the path if we don't have to. Currently just decided by if there is
- // a '/' character in the string
- final String res = searchHosts(searchTerm, cursor, searchTerm.indexOf("/") > 0);
-
- if (res != null) {
- ThreadUtils.postToUiThread(new Runnable() {
- @Override
- public void run() {
- // Its possible that mAutocompleteHandler has been destroyed
- if (mAutocompleteHandler != null) {
- mAutocompleteHandler.onAutocomplete(res);
- mAutocompleteHandler = null;
- }
- }
- });
- }
- }
-
- private String searchHosts(String searchTerm, Cursor cursor, boolean searchPath) {
- int i = 0;
- if (cursor.moveToFirst()) {
- int urlIndex = cursor.getColumnIndexOrThrow(URLColumns.URL);
- do {
- final Uri url = Uri.parse(cursor.getString(urlIndex));
- String host = StringUtils.stripCommonSubdomains(url.getHost());
- // host may be null for about pages
- if (host == null)
- continue;
-
- StringBuilder hostBuilder = new StringBuilder(host);
- if (hostBuilder.indexOf(searchTerm) == 0) {
- return hostBuilder.append("/").toString();
- }
-
- if (searchPath) {
- List path = url.getPathSegments();
-
- for (String seg : path) {
- hostBuilder.append("/").append(seg);
- if (hostBuilder.indexOf(searchTerm) == 0) {
- return hostBuilder.append("/").toString();
- }
- }
- }
-
- i++;
- } while (i < MAX_AUTOCOMPLETE_SEARCH && cursor.moveToNext());
- }
- return null;
- }
-
- /**
- * Query for suggestions, but don't show them yet.
- */
- private void primeSuggestions() {
- ThreadUtils.postToBackgroundThread(new Runnable() {
- @Override
- public void run() {
- mSuggestClient.query(mSearchTerm);
- }
- });
- }
-
- private void filterSuggestions(String searchTerm) {
- // cancel previous query
- if (mSuggestTask != null) {
- mSuggestTask.cancel(true);
- }
-
- if (mSuggestClient != null && mSuggestionsEnabled) {
- mSuggestTask = new AsyncTask>() {
- @Override
- protected ArrayList doInBackground(String... query) {
- return mSuggestClient.query(query[0]);
- }
-
- @Override
- protected void onPostExecute(ArrayList suggestions) {
- setSuggestions(suggestions);
- }
- };
- mSuggestTask.execute(searchTerm);
- }
- }
-
- protected AwesomeBarCursorAdapter getCursorAdapter() {
- if (mCursorAdapter == null) {
- // Load the list using a custom adapter so we can create the bitmaps
- mCursorAdapter = new AwesomeBarCursorAdapter(mContext);
-
- mCursorAdapter.setFilterQueryProvider(new FilterQueryProvider() {
- @Override
- public Cursor runQuery(CharSequence constraint) {
- long start = SystemClock.uptimeMillis();
-
- Cursor c = BrowserDB.filter(getContentResolver(), constraint, MAX_RESULTS);
- c.getCount();
-
- postLoadFavicons();
-
- long end = SystemClock.uptimeMillis();
- if (!mTelemetrySent && TextUtils.isEmpty(constraint)) {
- int time = (int)(end - start);
- Telemetry.HistogramAdd("FENNEC_AWESOMEBAR_ALLPAGES_EMPTY_TIME", time);
- mTelemetrySent = true;
- }
-
- findAutocompleteFor(constraint.toString(), c);
- return c;
- }
- });
- }
- return mCursorAdapter;
- }
-
- private interface AwesomeBarItem {
- public void onClick();
- public ContextMenuSubject getSubject();
- }
-
- private class AwesomeBarCursorItem implements AwesomeBarItem {
- private Cursor mCursor;
-
- public AwesomeBarCursorItem(Cursor cursor) {
- mCursor = cursor;
- }
-
- @Override
- public void onClick() {
- String url = mCursor.getString(mCursor.getColumnIndexOrThrow(URLColumns.URL));
- String title = mCursor.getString(mCursor.getColumnIndexOrThrow(URLColumns.TITLE));
- sendToListener(url, title);
- }
-
- @Override
- public ContextMenuSubject getSubject() {
- // Use the history id in order to allow removing history entries
- int id = mCursor.getInt(mCursor.getColumnIndexOrThrow(Combined.HISTORY_ID));
-
- String keyword = null;
- int keywordCol = mCursor.getColumnIndex(URLColumns.KEYWORD);
- if (keywordCol != -1)
- keyword = mCursor.getString(keywordCol);
-
- final String url = mCursor.getString(mCursor.getColumnIndexOrThrow(URLColumns.URL));
-
- Bitmap bitmap = Favicons.getInstance().getFaviconFromMemCache(url);
- byte[] favicon = null;
-
- if (bitmap != null) {
- ByteArrayOutputStream stream = new ByteArrayOutputStream();
- if (bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream)) {
- favicon = stream.toByteArray();
- } else {
- Log.w(LOGTAG, "Favicon compression failed.");
- }
- }
-
- return new ContextMenuSubject(id, url, favicon,
- mCursor.getString(mCursor.getColumnIndexOrThrow(URLColumns.TITLE)),
- keyword,
- mCursor.getInt(mCursor.getColumnIndexOrThrow(Combined.DISPLAY)));
- }
- }
-
- private class AwesomeBarSearchEngineItem implements AwesomeBarItem {
- private SearchEngine mSearchEngine;
-
- public AwesomeBarSearchEngineItem(SearchEngine searchEngine) {
- mSearchEngine = searchEngine;
- }
-
- @Override
- public void onClick() {
- AwesomeBarTabs.OnUrlOpenListener listener = getUrlListener();
- if (listener != null)
- listener.onSearch(mSearchEngine, mSearchTerm);
- }
-
- @Override
- public ContextMenuSubject getSubject() {
- // Do not show context menu for search engine items
- return null;
- }
- }
-
- private class AwesomeBarCursorAdapter extends SimpleCursorAdapter {
- private static final int ROW_SEARCH = 0;
- private static final int ROW_STANDARD = 1;
- private static final int ROW_SUGGEST = 2;
-
- public AwesomeBarCursorAdapter(Context context) {
- super(context, -1, null, new String[] {}, new int[] {});
- mSearchTerm = "";
- }
-
- public void filter(String searchTerm) {
- boolean changed = !mSearchTerm.equals(searchTerm);
- mSearchTerm = searchTerm;
-
- if (changed)
- mCursorAdapter.notifyDataSetChanged();
-
- getFilter().filter(searchTerm);
- }
-
- private int getSuggestEngineCount() {
- return (mSearchTerm.length() == 0 || mSuggestClient == null || !mSuggestionsEnabled) ? 0 : 1;
- }
-
- // Add the search engines to the number of reported results.
- @Override
- public int getCount() {
- final int resultCount = super.getCount();
-
- // don't show search engines or suggestions if search field is empty
- if (mSearchTerm.length() == 0)
- return resultCount;
-
- return resultCount + mSearchEngines.size();
- }
-
- // If an item is part of the cursor result set, return that entry.
- // Otherwise, return the search engine data.
- @Override
- public Object getItem(int position) {
- int engineIndex = getEngineIndex(position);
-
- if (engineIndex == -1) {
- // return awesomebar result
- position -= getSuggestEngineCount();
- return new AwesomeBarCursorItem((Cursor) super.getItem(position));
- }
-
- // return search engine
- return new AwesomeBarSearchEngineItem(mSearchEngines.get(engineIndex));
- }
-
- private int getEngineIndex(int position) {
- final int resultCount = super.getCount();
- final int suggestEngineCount = getSuggestEngineCount();
-
- // return suggest engine index
- if (position < suggestEngineCount)
- return position;
-
- // not an engine
- if (position - suggestEngineCount < resultCount)
- return -1;
-
- // return search engine index
- return position - resultCount;
- }
-
- @Override
- public int getItemViewType(int position) {
- int engine = getEngineIndex(position);
- if (engine == -1) {
- return ROW_STANDARD;
- } else if (engine == 0 && mSuggestionsEnabled) {
- // Give suggestion views their own type to prevent them from
- // sharing other recycled search engine views. Using other
- // recycled views for the suggestion row can break animations
- // (bug 815937).
- return ROW_SUGGEST;
- }
- return ROW_SEARCH;
- }
-
- @Override
- public int getViewTypeCount() {
- // view can be either a standard awesomebar row, a search engine
- // row, or a suggestion row
- return 3;
- }
-
- @Override
- public boolean isEnabled(int position) {
- // If we're using a gamepad or keyboard, allow the row to be
- // focused so it can pass the focus to its child suggestion views.
- if (!getListView().isInTouchMode()) {
- return true;
- }
-
- // If the suggestion row only contains one item (the user-entered
- // query), allow the entire row to be clickable; clicking the row
- // has the same effect as clicking the single suggestion. If the
- // row contains multiple items, clicking the row will do nothing.
- int index = getEngineIndex(position);
- if (index != -1)
- return mSearchEngines.get(index).suggestions.isEmpty();
- return true;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- int type = getItemViewType(position);
- if (type == ROW_SEARCH || type == ROW_SUGGEST) {
- if (convertView == null || !(convertView instanceof SearchEngineRow)) {
- convertView = (SearchEngineRow) getInflater().inflate(R.layout.home_search_item_row, getListView(), false);
- ((SearchEngineRow) convertView).setOnUrlOpenListener(getUrlListener());
- }
-
- SearchEngineRow searchRow = (SearchEngineRow) convertView;
- searchRow.setSearchTerm(mSearchTerm);
-
- final SearchEngine engine = mSearchEngines.get(getEngineIndex(position));
- final boolean doAnimation = (mAnimateSuggestions && engine.suggestions.size() > 0);
- searchRow.updateFromSearchEngine(engine, doAnimation);
- if (doAnimation) {
- // Only animate suggestions the first time they are shown
- mAnimateSuggestions = false;
- }
- } else {
- AwesomeEntryViewHolder viewHolder = null;
-
- if (convertView == null || !(convertView.getTag() instanceof AwesomeEntryViewHolder)) {
- convertView = getInflater().inflate(R.layout.awesomebar_row, null);
-
- viewHolder = new AwesomeEntryViewHolder();
- viewHolder.titleView = (TextView) convertView.findViewById(R.id.title);
- viewHolder.urlView = (TextView) convertView.findViewById(R.id.url);
- viewHolder.faviconView = (FaviconView) convertView.findViewById(R.id.favicon);
- viewHolder.bookmarkIconView = (ImageView) convertView.findViewById(R.id.bookmark_icon);
-
- convertView.setTag(viewHolder);
- } else {
- viewHolder = (AwesomeEntryViewHolder) convertView.getTag();
- }
-
- position -= getSuggestEngineCount();
- Cursor cursor = getCursor();
- if (!cursor.moveToPosition(position))
- throw new IllegalStateException("Couldn't move cursor to position " + position);
-
- updateTitle(viewHolder.titleView, cursor);
- updateUrl(viewHolder, cursor);
- updateBookmarkIcon(viewHolder.bookmarkIconView, cursor);
- displayFavicon(viewHolder);
- }
-
- return convertView;
- }
- };
-
- /**
- * Sets suggestions associated with the current suggest engine.
- * If there is no suggest engine, this does nothing.
- */
- private void setSuggestions(final ArrayList suggestions) {
- if (mSuggestClient != null) {
- mSearchEngines.get(0).suggestions = suggestions;
- getCursorAdapter().notifyDataSetChanged();
- }
- }
-
- /**
- * Sets search engines to be shown for user-entered queries.
- */
- private void setSearchEngines(JSONObject data) {
- try {
- JSONObject suggest = data.getJSONObject("suggest");
- String suggestEngine = suggest.isNull("engine") ? null : suggest.getString("engine");
- String suggestTemplate = suggest.isNull("template") ? null : suggest.getString("template");
- mSuggestionsEnabled = suggest.getBoolean("enabled");
- boolean suggestionsPrompted = suggest.getBoolean("prompted");
- JSONArray engines = data.getJSONArray("searchEngines");
-
- ArrayList searchEngines = new ArrayList();
- for (int i = 0; i < engines.length(); i++) {
- JSONObject engineJSON = engines.getJSONObject(i);
- String name = engineJSON.getString("name");
- String identifier = engineJSON.getString("identifier");
- String iconURI = engineJSON.getString("iconURI");
- Bitmap icon = BitmapUtils.getBitmapFromDataURI(iconURI);
- if (name.equals(suggestEngine) && suggestTemplate != null) {
- // suggest engine should be at the front of the list
- searchEngines.add(0, new SearchEngine(name, identifier, icon));
-
- // The only time Tabs.getInstance().getSelectedTab() should
- // be null is when we're restoring after a crash. We should
- // never restore private tabs when that happens, so it
- // should be safe to assume that null means non-private.
- Tab tab = Tabs.getInstance().getSelectedTab();
- if (tab == null || !tab.isPrivate())
- mSuggestClient = new SuggestClient(getView().getContext(), suggestTemplate, SUGGESTION_TIMEOUT, SUGGESTION_MAX);
- } else {
- searchEngines.add(new SearchEngine(name, identifier, icon));
- }
- }
-
- mSearchEngines = searchEngines;
- mCursorAdapter.notifyDataSetChanged();
-
- // show suggestions opt-in if user hasn't been prompted
- if (!suggestionsPrompted && mSuggestClient != null) {
- showSuggestionsOptIn();
- }
- } catch (JSONException e) {
- Log.e(LOGTAG, "Error getting search engine JSON", e);
- }
-
- filterSuggestions(mSearchTerm);
- }
-
- private void showSuggestionsOptIn() {
- mSuggestionsOptInPrompt = LayoutInflater.from(mContext).inflate(R.layout.awesomebar_suggestion_prompt, (LinearLayout)getView(), false);
- GeckoTextView promptText = (GeckoTextView) mSuggestionsOptInPrompt.findViewById(R.id.suggestions_prompt_title);
- promptText.setText(getResources().getString(R.string.suggestions_prompt, mSearchEngines.get(0).name));
- Tab tab = Tabs.getInstance().getSelectedTab();
- if (tab != null)
- promptText.setPrivateMode(tab.isPrivate());
-
- final View yesButton = mSuggestionsOptInPrompt.findViewById(R.id.suggestions_prompt_yes);
- final View noButton = mSuggestionsOptInPrompt.findViewById(R.id.suggestions_prompt_no);
- OnClickListener listener = new OnClickListener() {
- @Override
- public void onClick(View v) {
- // Prevent the buttons from being clicked multiple times (bug 816902)
- yesButton.setOnClickListener(null);
- noButton.setOnClickListener(null);
-
- setSuggestionsEnabled(v == yesButton);
- }
- };
- yesButton.setOnClickListener(listener);
- noButton.setOnClickListener(listener);
-
- // If the prompt container gains focus, automatically pass focus to the
- // yes button in the prompt.
- final View promptContainer = mSuggestionsOptInPrompt.findViewById(R.id.prompt_container);
- promptContainer.setOnFocusChangeListener(new View.OnFocusChangeListener() {
- @Override
- public void onFocusChange(View v, boolean hasFocus) {
- if (hasFocus) {
- yesButton.requestFocus();
- }
- }
- });
-
- mSuggestionsOptInPrompt.setVisibility(View.GONE);
- ((LinearLayout)getView()).addView(mSuggestionsOptInPrompt, 0);
- }
-
- private void setSuggestionsEnabled(final boolean enabled) {
- // Clicking the yes/no buttons quickly can cause the click events be
- // queued before the listeners are removed above, so it's possible
- // setSuggestionsEnabled() can be called twice. mSuggestionsOptInPrompt
- // can be null if this happens (bug 828480).
- if (mSuggestionsOptInPrompt == null) {
- return;
- }
-
- // Make suggestions appear immediately after the user opts in
- primeSuggestions();
-
- // Pref observer in gecko will also set prompted = true
- PrefsHelper.setPref("browser.search.suggest.enabled", enabled);
-
- TranslateAnimation anim1 = new TranslateAnimation(0, mSuggestionsOptInPrompt.getWidth(), 0, 0);
- anim1.setDuration(ANIMATION_DURATION);
- anim1.setInterpolator(new AccelerateInterpolator());
- anim1.setFillAfter(true);
- final View promptContainer = mSuggestionsOptInPrompt.findViewById(R.id.prompt_container);
-
- TranslateAnimation anim2 = new TranslateAnimation(0, 0, 0, -1 * mSuggestionsOptInPrompt.getHeight());
- anim2.setDuration(ANIMATION_DURATION);
- anim2.setFillAfter(true);
- anim2.setStartOffset(anim1.getDuration());
- final LinearLayout view = (LinearLayout)getView();
- anim2.setAnimationListener(new Animation.AnimationListener() {
- @Override
- public void onAnimationStart(Animation a) {
- // Increase the height of the view so a gap isn't shown during animation
- view.getLayoutParams().height = view.getHeight() +
- mSuggestionsOptInPrompt.getHeight();
- view.requestLayout();
- }
- @Override
- public void onAnimationRepeat(Animation a) {}
- @Override
- public void onAnimationEnd(Animation a) {
- // Removing the view immediately results in a NPE in
- // dispatchDraw(), possibly because this callback executes
- // before drawing is finished. Posting this as a Runnable fixes
- // the issue.
- view.post(new Runnable() {
- @Override
- public void run() {
- view.removeView(mSuggestionsOptInPrompt);
- getListView().clearAnimation();
- mSuggestionsOptInPrompt = null;
-
- if (enabled) {
- // Reset the view height
- view.getLayoutParams().height = LayoutParams.FILL_PARENT;
-
- mSuggestionsEnabled = enabled;
- mAnimateSuggestions = true;
- getCursorAdapter().notifyDataSetChanged();
- filterSuggestions(mSearchTerm);
- }
- }
- });
- }
- });
-
- promptContainer.startAnimation(anim1);
- mSuggestionsOptInPrompt.startAnimation(anim2);
- getListView().startAnimation(anim2);
- }
-
- @Override
- public void handleMessage(String event, final JSONObject message) {
- if (event.equals("SearchEngines:Data")) {
- ThreadUtils.postToUiThread(new Runnable() {
- @Override
- public void run() {
- setSearchEngines(message);
- }
- });
- }
- }
-
- public void handleItemClick(AdapterView> parent, View view, int position, long id) {
- ListView listview = getListView();
- if (listview == null)
- return;
-
- AwesomeBarItem item = (AwesomeBarItem)listview.getItemAtPosition(position);
- item.onClick();
- }
-
- protected void updateBookmarkIcon(ImageView bookmarkIconView, Cursor cursor) {
- int bookmarkIdIndex = cursor.getColumnIndexOrThrow(Combined.BOOKMARK_ID);
- long id = cursor.getLong(bookmarkIdIndex);
-
- int displayIndex = cursor.getColumnIndexOrThrow(Combined.DISPLAY);
- int display = cursor.getInt(displayIndex);
-
- // The bookmark id will be 0 (null in database) when the url
- // is not a bookmark.
- int visibility = (id == 0 ? View.GONE : View.VISIBLE);
- bookmarkIconView.setVisibility(visibility);
-
- if (display == Combined.DISPLAY_READER) {
- bookmarkIconView.setImageResource(R.drawable.ic_awesomebar_reader);
- } else {
- bookmarkIconView.setImageResource(R.drawable.ic_awesomebar_star);
- }
- }
-
- @Override
- public ContextMenuSubject getSubject(ContextMenu menu, View view, ContextMenuInfo menuInfo) {
- ContextMenuSubject subject = null;
-
- if (!(menuInfo instanceof AdapterView.AdapterContextMenuInfo)) {
- Log.e(LOGTAG, "menuInfo is not AdapterContextMenuInfo");
- return subject;
- }
-
- ListView list = (ListView)view;
- AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
- subject = ((AwesomeBarItem) list.getItemAtPosition(info.position)).getSubject();
-
- if (subject == null)
- return subject;
-
- setupMenu(menu, subject);
-
- menu.findItem(R.id.remove_bookmark).setVisible(false);
- menu.findItem(R.id.edit_bookmark).setVisible(false);
- menu.findItem(R.id.open_in_reader).setVisible(subject.display == Combined.DISPLAY_READER);
-
- return subject;
- }
-
- private void registerEventListener(String event) {
- GeckoAppShell.getEventDispatcher().registerEventListener(event, this);
- }
-
- private void unregisterEventListener(String event) {
- GeckoAppShell.getEventDispatcher().unregisterEventListener(event, this);
- }
-
- private List getUrlsWithoutFavicon() {
- List urls = new ArrayList();
-
- Cursor c = mCursorAdapter.getCursor();
- if (c == null || !c.moveToFirst())
- return urls;
-
- do {
- final String url = c.getString(c.getColumnIndexOrThrow(URLColumns.URL));
-
- // We only want to load favicons from DB if they are not in the
- // memory cache yet.
- if (Favicons.getInstance().getFaviconFromMemCache(url) != null)
- continue;
-
- urls.add(url);
- } while (c.moveToNext());
-
- return urls;
- }
-
- public void storeFaviconsInMemCache(Cursor c) {
- if (c == null)
- return;
-
- try {
- if (!c.moveToFirst())
- return;
-
- do {
- final String url = c.getString(c.getColumnIndexOrThrow(Combined.URL));
- final byte[] b = c.getBlob(c.getColumnIndexOrThrow(Combined.FAVICON));
- if (b == null)
- continue;
-
- Bitmap favicon = BitmapUtils.decodeByteArray(b);
- if (favicon == null)
- continue;
-
- favicon = Favicons.getInstance().scaleImage(favicon);
- Favicons.getInstance().putFaviconInMemCache(url, favicon);
- } while (c.moveToNext());
- } finally {
- c.close();
- }
- }
-
- private void loadFaviconsForCurrentResults() {
- final List urls = getUrlsWithoutFavicon();
- if (urls.size() == 0)
- return;
-
- (new UiAsyncTask(ThreadUtils.getBackgroundHandler()) {
- @Override
- public Void doInBackground(Void... params) {
- Cursor cursor = BrowserDB.getFaviconsForUrls(getContentResolver(), urls);
- storeFaviconsInMemCache(cursor);
- return null;
- }
-
- @Override
- public void onPostExecute(Void result) {
- postUpdateFavicons();
- }
- }).execute();
- }
-
- private void displayFavicon(AwesomeEntryViewHolder viewHolder) {
- final String url = viewHolder.url;
- Bitmap bitmap = Favicons.getInstance().getFaviconFromMemCache(url);
- updateFavicon(viewHolder.faviconView, bitmap, url);
- }
-
- private void updateFavicons() {
- ListView listView = getListView();
- AwesomeBarCursorAdapter adapter = getCursorAdapter();
- Cursor cursor = adapter.getCursor();
- if (cursor == null)
- return;
-
- for (int i = 0; i < listView.getChildCount(); i++) {
- final View view = listView.getChildAt(i);
- final Object tag = view.getTag();
-
- if (tag == null || !(tag instanceof AwesomeEntryViewHolder))
- continue;
-
- final AwesomeEntryViewHolder viewHolder = (AwesomeEntryViewHolder) tag;
- displayFavicon(viewHolder);
- }
-
- mView.invalidate();
- }
-
- private void postUpdateFavicons() {
- if (mHandler == null)
- return;
-
- Message msg = mHandler.obtainMessage(MESSAGE_UPDATE_FAVICONS,
- AllPagesTab.this);
-
- mHandler.removeMessages(MESSAGE_UPDATE_FAVICONS);
- mHandler.sendMessage(msg);
- }
-
- private void postLoadFavicons() {
- if (mHandler == null)
- return;
-
- Message msg = mHandler.obtainMessage(MESSAGE_LOAD_FAVICONS,
- AllPagesTab.this);
-
- mHandler.removeMessages(MESSAGE_LOAD_FAVICONS);
- mHandler.sendMessageDelayed(msg, 200);
- }
-
- private class AllPagesHandler extends Handler {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MESSAGE_LOAD_FAVICONS:
- loadFaviconsForCurrentResults();
- break;
- case MESSAGE_UPDATE_FAVICONS:
- updateFavicons();
- break;
- }
- }
- }
-
- private static class ListSelectionListener implements View.OnFocusChangeListener,
- AdapterView.OnItemSelectedListener {
- private SearchEngineRow mSelectedEngineRow;
-
- @Override
- public void onFocusChange(View v, boolean hasFocus) {
- if (hasFocus) {
- View selectedRow = ((ListView) v).getSelectedView();
- if (selectedRow != null) {
- selectRow(selectedRow);
- }
- } else {
- deselectRow();
- }
- }
-
- @Override
- public void onItemSelected(AdapterView> parent, View view, int position, long id) {
- deselectRow();
- selectRow(view);
- }
-
- @Override
- public void onNothingSelected(AdapterView> parent) {
- deselectRow();
- }
-
- private void selectRow(View row) {
- if (row instanceof SearchEngineRow) {
- mSelectedEngineRow = (SearchEngineRow) row;
- mSelectedEngineRow.onSelected();
- }
- }
-
- private void deselectRow() {
- if (mSelectedEngineRow != null) {
- mSelectedEngineRow.onDeselected();
- mSelectedEngineRow = null;
- }
- }
- }
-}
diff --git a/mobile/android/base/awesomebar/AwesomeBarTab.java b/mobile/android/base/awesomebar/AwesomeBarTab.java
deleted file mode 100644
index f07e52e0a4b6..000000000000
--- a/mobile/android/base/awesomebar/AwesomeBarTab.java
+++ /dev/null
@@ -1,194 +0,0 @@
-/* -*- 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;
-
-import org.mozilla.gecko.AwesomeBar.ContextMenuSubject;
-import org.mozilla.gecko.db.BrowserDB.URLColumns;
-import org.mozilla.gecko.gfx.BitmapUtils;
-import org.mozilla.gecko.widget.FaviconView;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.text.TextUtils;
-import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.LayoutInflater;
-import android.view.MenuInflater;
-import android.view.View;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import java.util.HashMap;
-
-abstract public class AwesomeBarTab {
- abstract public String getTag();
- abstract public int getTitleStringId();
- abstract public boolean onBackPressed();
- abstract public ContextMenuSubject getSubject(ContextMenu menu, View view, ContextMenuInfo menuInfo);
- abstract public View getView();
-
- protected View mView = null;
- protected View.OnTouchListener mListListener;
- private AwesomeBarTabs.OnUrlOpenListener mListener;
- private LayoutInflater mInflater = null;
- private ContentResolver mContentResolver = null;
- private Resources mResources;
- // FIXME: This value should probably come from a prefs key
- public static final int MAX_RESULTS = 100;
- protected Context mContext = null;
- public static HashMap sOpenTabs;
-
- public AwesomeBarTab(Context context) {
- mContext = context;
- }
-
- public void destroy() {
- sOpenTabs = null;
- }
-
- public void setListTouchListener(View.OnTouchListener listener) {
- mListListener = listener;
- if (mView != null)
- mView.setOnTouchListener(mListListener);
- }
-
- protected class AwesomeEntryViewHolder {
- public TextView titleView;
- public String url;
- public TextView urlView;
- public FaviconView faviconView;
- public ImageView bookmarkIconView;
- }
-
- protected LayoutInflater getInflater() {
- if (mInflater == null) {
- mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- }
- return mInflater;
- }
-
- protected AwesomeBarTabs.OnUrlOpenListener getUrlListener() {
- return mListener;
- }
-
- protected void setUrlListener(AwesomeBarTabs.OnUrlOpenListener listener) {
- mListener = listener;
- }
-
- protected ContentResolver getContentResolver() {
- if (mContentResolver == null) {
- mContentResolver = mContext.getContentResolver();
- }
- return mContentResolver;
- }
-
- protected HashMap getOpenTabs() {
- if (sOpenTabs == null || sOpenTabs.isEmpty()) {
- Iterable tabs = Tabs.getInstance().getTabsInOrder();
- sOpenTabs = new HashMap();
- for (Tab tab : tabs) {
- sOpenTabs.put(tab.getURL(), tab.getId());
- }
- }
- return sOpenTabs;
- }
-
- protected Resources getResources() {
- if (mResources == null) {
- mResources = mContext.getResources();
- }
- return mResources;
- }
-
- protected void setupMenu(ContextMenu menu, AwesomeBar.ContextMenuSubject subject) {
- MenuInflater inflater = new MenuInflater(mContext);
- inflater.inflate(R.menu.awesomebar_contextmenu, menu);
-
- // Show Open Private Tab if we're in private mode, Open New Tab otherwise
- boolean isPrivate = false;
- Tab tab = Tabs.getInstance().getSelectedTab();
- if (tab != null) {
- isPrivate = tab.isPrivate();
- }
- menu.findItem(R.id.open_new_tab).setVisible(!isPrivate);
- menu.findItem(R.id.open_private_tab).setVisible(isPrivate);
-
- // Hide "Remove" item if there isn't a valid history ID
- if (subject.id < 0) {
- menu.findItem(R.id.remove_history).setVisible(false);
- }
- menu.setHeaderTitle(subject.title);
- }
-
- protected void updateFavicon(FaviconView faviconView, Bitmap bitmap, String key) {
- faviconView.updateImage(bitmap, key);
- }
-
- protected void updateTitle(TextView titleView, Cursor cursor) {
- int titleIndex = cursor.getColumnIndexOrThrow(URLColumns.TITLE);
- String title = cursor.getString(titleIndex);
- String url = "";
-
- // Use the URL instead of an empty title for consistency with the normal URL
- // bar view - this is the equivalent of getDisplayTitle() in Tab.java
- if (TextUtils.isEmpty(title)) {
- int urlIndex = cursor.getColumnIndexOrThrow(URLColumns.URL);
- url = cursor.getString(urlIndex);
- }
-
- updateTitle(titleView, title, url);
- }
-
- protected void updateTitle(TextView titleView, String title, String url) {
- if (TextUtils.isEmpty(title)) {
- titleView.setText(url);
- } else {
- titleView.setText(title);
- }
- }
-
- public void sendToListener(String url, String title) {
- AwesomeBarTabs.OnUrlOpenListener listener = getUrlListener();
- if (listener == null)
- return;
-
- Integer tabId = getOpenTabs().get(url);
- if (tabId != null) {
- listener.onSwitchToTab(tabId);
- } else {
- listener.onUrlOpen(url, title);
- }
- }
-
- protected void updateUrl(AwesomeEntryViewHolder holder, Cursor cursor) {
- int urlIndex = cursor.getColumnIndexOrThrow(URLColumns.URL);
- String url = cursor.getString(urlIndex);
- updateUrl(holder, url);
- }
-
- protected void updateUrl(AwesomeEntryViewHolder holder, String url) {
- Integer tabId = getOpenTabs().get(url);
- holder.url = url;
- if (tabId != null) {
- holder.urlView.setText(R.string.awesomebar_switch_to_tab);
- holder.urlView.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_awesomebar_tab, 0, 0, 0);
- } else {
- holder.urlView.setText(url);
- holder.urlView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
- }
- }
-
- protected boolean hideSoftInput(View view) {
- InputMethodManager imm =
- (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
-
- return imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
- }
-}
diff --git a/mobile/android/base/awesomebar/BookmarksTab.java b/mobile/android/base/awesomebar/BookmarksTab.java
deleted file mode 100644
index 6b49953b26f5..000000000000
--- a/mobile/android/base/awesomebar/BookmarksTab.java
+++ /dev/null
@@ -1,470 +0,0 @@
-/* -*- 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;
-
-import org.mozilla.gecko.AwesomeBar.ContextMenuSubject;
-import org.mozilla.gecko.db.BrowserContract.Bookmarks;
-import org.mozilla.gecko.db.BrowserContract.Combined;
-import org.mozilla.gecko.db.BrowserDB;
-import org.mozilla.gecko.db.BrowserDB.URLColumns;
-import org.mozilla.gecko.gfx.BitmapUtils;
-import org.mozilla.gecko.util.GamepadUtils;
-import org.mozilla.gecko.util.ThreadUtils;
-import org.mozilla.gecko.widget.FaviconView;
-
-import android.app.Activity;
-import android.content.Context;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.os.AsyncTask;
-import android.util.Log;
-import android.util.Pair;
-import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.LayoutInflater;
-import android.view.MenuInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.ListView;
-import android.widget.SimpleCursorAdapter;
-import android.widget.TextView;
-
-import java.util.LinkedList;
-
-public class BookmarksTab extends AwesomeBarTab {
- public static final String LOGTAG = "BOOKMARKS_TAB";
- public static final String TAG = "bookmarks";
- private int mFolderId;
- private String mFolderTitle;
- private BookmarksListAdapter mCursorAdapter = null;
- private BookmarksQueryTask mQueryTask = null;
- private boolean mShowReadingList = false;
-
- @Override
- public int getTitleStringId() {
- return R.string.awesomebar_bookmarks_title;
- }
-
- @Override
- public String getTag() {
- return TAG;
- }
-
- public BookmarksTab(Context context) {
- super(context);
- }
-
- @Override
- public View getView() {
- if (mView == null) {
- mView = new ListView(mContext, null);
- ((Activity)mContext).registerForContextMenu(mView);
- mView.setTag(TAG);
- mView.setOnTouchListener(mListListener);
-
- // We need to add the header before we set the adapter, hence make it null
- ListView list = (ListView)mView;
- list.setAdapter(null);
- list.setAdapter(getCursorAdapter());
- list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView> parent, View view, int position, long id) {
- handleItemClick(parent, view, position, id);
- }
- });
-
- if (mShowReadingList) {
- String title = getResources().getString(R.string.bookmarks_folder_reading_list);
- getCursorAdapter().moveToChildFolder(Bookmarks.FIXED_READING_LIST_ID, title);
- } else {
- BookmarksQueryTask task = getQueryTask();
- task.execute();
- }
- }
- return (ListView)mView;
- }
-
- public void setShowReadingList(boolean showReadingList) {
- mShowReadingList = showReadingList;
- }
-
- @Override
- public void destroy() {
- super.destroy();
- // Can't use getters for adapter. It will create one if null.
- if (mCursorAdapter != null && mView != null) {
- ListView list = (ListView)mView;
- list.setAdapter(null);
- final Cursor cursor = mCursorAdapter.getCursor();
- // Gingerbread locks the DB when closing a cursor, so do it in the
- // background.
- ThreadUtils.postToBackgroundThread(new Runnable() {
- @Override
- public void run() {
- if (cursor != null && !cursor.isClosed())
- cursor.close();
- }
- });
- }
- }
-
- @Override
- public boolean onBackPressed() {
- // If the soft keyboard is visible in the bookmarks or history tab, the user
- // must have explictly brought it up, so we should try hiding it instead of
- // exiting the activity or going up a bookmarks folder level.
- if (hideSoftInput(getView()))
- return true;
-
- return moveToParentFolder();
- }
-
- protected BookmarksListAdapter getCursorAdapter() {
- return getCursorAdapter(null);
- }
-
- protected BookmarksListAdapter getCursorAdapter(Cursor c) {
- if (mCursorAdapter == null) {
- mCursorAdapter = new BookmarksListAdapter(mContext, c);
- } else if (c != null) {
- mCursorAdapter.changeCursor(c);
- } else {
- // do a quick return if just asking for the cached adapter
- return mCursorAdapter;
- }
-
- TextView headerView = mCursorAdapter.getHeaderView();
- if (headerView == null) {
- headerView = (TextView) getInflater().inflate(R.layout.awesomebar_header_row, null);
- mCursorAdapter.setHeaderView(headerView);
- }
-
- // Add/Remove header based on the root folder
- if (mView != null) {
- ListView list = (ListView)mView;
- if (mFolderId == Bookmarks.FIXED_ROOT_ID) {
- if (list.getHeaderViewsCount() == 1) {
- list.removeHeaderView(headerView);
- }
- } else {
- if (list.getHeaderViewsCount() == 0) {
- list.addHeaderView(headerView, null, true);
- }
- headerView.setText(mFolderTitle);
- }
- }
-
- return mCursorAdapter;
- }
-
- protected BookmarksQueryTask getQueryTask() {
- if (mQueryTask == null) {
- mQueryTask = new BookmarksQueryTask();
- }
- return mQueryTask;
- }
-
- public void handleItemClick(AdapterView> parent, View view, int position, long id) {
- ListView list = (ListView)getView();
- if (list == null)
- return;
-
- int headerCount = list.getHeaderViewsCount();
- // If we tap on the header view, there's nothing to do
- if (headerCount == 1 && position == 0)
- return;
-
- BookmarksListAdapter adapter = getCursorAdapter();
- if (adapter == null)
- return;
-
- Cursor cursor = adapter.getCursor();
- if (cursor == null)
- return;
-
- // The header view takes up a spot in the list
- if (headerCount == 1)
- position--;
-
- cursor.moveToPosition(position);
-
- int type = cursor.getInt(cursor.getColumnIndexOrThrow(Bookmarks.TYPE));
- if (type == Bookmarks.TYPE_FOLDER) {
- // If we're clicking on a folder, update adapter to move to that folder
- int folderId = cursor.getInt(cursor.getColumnIndexOrThrow(Bookmarks._ID));
- String folderTitle = adapter.getFolderTitle(position);
-
- adapter.moveToChildFolder(folderId, folderTitle);
- return;
- }
-
- // Otherwise, just open the URL
- String url = cursor.getString(cursor.getColumnIndexOrThrow(URLColumns.URL));
- String title = cursor.getString(cursor.getColumnIndexOrThrow(URLColumns.TITLE));
- long parentId = cursor.getLong(cursor.getColumnIndexOrThrow(Bookmarks.PARENT));
- if (parentId == Bookmarks.FIXED_READING_LIST_ID) {
- url = ReaderModeUtils.getAboutReaderForUrl(url, true);
- }
- sendToListener(url, title);
- }
-
- private class BookmarksListAdapter extends SimpleCursorAdapter {
- private static final int VIEW_TYPE_ITEM = 0;
- private static final int VIEW_TYPE_FOLDER = 1;
- private static final int VIEW_TYPE_COUNT = 2;
-
- private LinkedList> mParentStack;
- private TextView mBookmarksTitleView;
-
- public BookmarksListAdapter(Context context, Cursor c) {
- super(context, -1, c, new String[] {}, new int[] {});
-
- // mParentStack holds folder id/title pairs that allow us to navigate
- // back up the folder heirarchy
- mParentStack = new LinkedList>();
-
- // Add the root folder to the stack
- Pair rootFolder = new Pair(Bookmarks.FIXED_ROOT_ID, "");
- mParentStack.addFirst(rootFolder);
- }
-
- public void refreshCurrentFolder() {
- // Cancel any pre-existing async refresh tasks
- if (mQueryTask != null)
- mQueryTask.cancel(false);
-
- Pair folderPair = mParentStack.getFirst();
- mQueryTask = new BookmarksQueryTask(folderPair.first, folderPair.second);
- mQueryTask.execute();
- }
-
- // Returns false if there is no parent folder to move to
- public boolean moveToParentFolder() {
- // If we're already at the root, we can't move to a parent folder
- if (mParentStack.size() == 1)
- return false;
-
- mParentStack.removeFirst();
- refreshCurrentFolder();
- return true;
- }
-
- public void moveToChildFolder(int folderId, String folderTitle) {
- Pair folderPair = new Pair(folderId, folderTitle);
- mParentStack.addFirst(folderPair);
- refreshCurrentFolder();
- }
-
- public boolean isInReadingList() {
- Pair folderPair = mParentStack.getFirst();
- return (folderPair.first == Bookmarks.FIXED_READING_LIST_ID);
- }
-
- @Override
- public int getItemViewType(int position) {
- Cursor c = getCursor();
-
- if (c.moveToPosition(position) &&
- c.getInt(c.getColumnIndexOrThrow(Bookmarks.TYPE)) == Bookmarks.TYPE_FOLDER)
- return VIEW_TYPE_FOLDER;
-
- // Default to retuning normal item type
- return VIEW_TYPE_ITEM;
- }
-
- @Override
- public int getViewTypeCount() {
- return VIEW_TYPE_COUNT;
- }
-
- public String getFolderTitle(int position) {
- Cursor c = getCursor();
- if (!c.moveToPosition(position))
- return "";
-
- String guid = c.getString(c.getColumnIndexOrThrow(Bookmarks.GUID));
-
- // If we don't have a special GUID, just return the folder title from the DB.
- if (guid == null || guid.length() == 12)
- return c.getString(c.getColumnIndexOrThrow(Bookmarks.TITLE));
-
- // Use localized strings for special folder names.
- if (guid.equals(Bookmarks.FAKE_DESKTOP_FOLDER_GUID))
- return getResources().getString(R.string.bookmarks_folder_desktop);
- else if (guid.equals(Bookmarks.MENU_FOLDER_GUID))
- return getResources().getString(R.string.bookmarks_folder_menu);
- else if (guid.equals(Bookmarks.TOOLBAR_FOLDER_GUID))
- return getResources().getString(R.string.bookmarks_folder_toolbar);
- else if (guid.equals(Bookmarks.UNFILED_FOLDER_GUID))
- return getResources().getString(R.string.bookmarks_folder_unfiled);
- else if (guid.equals(Bookmarks.READING_LIST_FOLDER_GUID))
- return getResources().getString(R.string.bookmarks_folder_reading_list);
-
- // If for some reason we have a folder with a special GUID, but it's not one of
- // the special folders we expect in the UI, just return the title from the DB.
- return c.getString(c.getColumnIndexOrThrow(Bookmarks.TITLE));
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- int viewType = getItemViewType(position);
- AwesomeEntryViewHolder viewHolder = null;
-
- if (convertView == null) {
- if (viewType == VIEW_TYPE_ITEM)
- convertView = getInflater().inflate(R.layout.awesomebar_row, null);
- else
- convertView = getInflater().inflate(R.layout.awesomebar_folder_row, null);
-
- viewHolder = new AwesomeEntryViewHolder();
- viewHolder.titleView = (TextView) convertView.findViewById(R.id.title);
- viewHolder.faviconView = (FaviconView) convertView.findViewById(R.id.favicon);
-
- if (viewType == VIEW_TYPE_ITEM)
- viewHolder.urlView = (TextView) convertView.findViewById(R.id.url);
-
- convertView.setTag(viewHolder);
- } else {
- viewHolder = (AwesomeEntryViewHolder) convertView.getTag();
- }
-
- Cursor cursor = getCursor();
- if (!cursor.moveToPosition(position))
- throw new IllegalStateException("Couldn't move cursor to position " + position);
-
- if (viewType == VIEW_TYPE_ITEM) {
- updateTitle(viewHolder.titleView, cursor);
- updateUrl(viewHolder, cursor);
-
- byte[] b = cursor.getBlob(cursor.getColumnIndexOrThrow(URLColumns.FAVICON));
- Bitmap favicon = null;
- if (b != null) {
- Bitmap bitmap = BitmapUtils.decodeByteArray(b);
- if (bitmap != null) {
- favicon = Favicons.getInstance().scaleImage(bitmap);
- }
- }
- String url = cursor.getString(cursor.getColumnIndexOrThrow(URLColumns.URL));
- updateFavicon(viewHolder.faviconView, favicon, url);
- } else {
- viewHolder.titleView.setText(getFolderTitle(position));
- }
-
- return convertView;
- }
-
- public TextView getHeaderView() {
- return mBookmarksTitleView;
- }
-
- public void setHeaderView(TextView titleView) {
- mBookmarksTitleView = titleView;
- }
- }
-
- private class BookmarksQueryTask extends AsyncTask {
- public BookmarksQueryTask() {
- mFolderId = Bookmarks.FIXED_ROOT_ID;
- mFolderTitle = "";
- }
-
- public BookmarksQueryTask(int folderId, String folderTitle) {
- mFolderId = folderId;
- mFolderTitle = folderTitle;
- }
-
- @Override
- protected Cursor doInBackground(Void... arg0) {
- return BrowserDB.getBookmarksInFolder(getContentResolver(), mFolderId);
- }
-
- @Override
- protected void onPostExecute(final Cursor cursor) {
- // Hack: force this to the main thread, even though it should already be on it
- ThreadUtils.postToUiThread(new Runnable() {
- @Override
- public void run() {
- // this will update the cursorAdapter to use the new one if it already exists
- // We need to add the header before we set the adapter, hence make it null
- ListView list = (ListView)mView;
- list.setAdapter(null);
- list.setAdapter(getCursorAdapter(cursor));
- }
- });
- mQueryTask = null;
- }
- }
-
- public boolean moveToParentFolder() {
- // If we're not in the bookmarks tab, we have nothing to do. We should
- // also return false if mBookmarksAdapter hasn't been initialized yet.
- BookmarksListAdapter adapter = getCursorAdapter();
- if (adapter == null)
- return false;
-
- return adapter.moveToParentFolder();
- }
-
- /**
- * Whether the user is in the Reading List bookmarks directory in the
- * AwesomeScreen UI.
- */
- public boolean isInReadingList() {
- if (mCursorAdapter == null)
- return false;
-
- return mCursorAdapter.isInReadingList();
- }
-
- @Override
- public ContextMenuSubject getSubject(ContextMenu menu, View view, ContextMenuInfo menuInfo) {
- ContextMenuSubject subject = null;
-
- if (!(menuInfo instanceof AdapterView.AdapterContextMenuInfo)) {
- Log.e(LOGTAG, "menuInfo is not AdapterContextMenuInfo");
- return subject;
- }
-
- ListView list = (ListView)view;
- AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
- Object selectedItem = list.getItemAtPosition(info.position);
-
- if (!(selectedItem instanceof Cursor)) {
- Log.e(LOGTAG, "item at " + info.position + " is not a Cursor");
- return subject;
- }
-
- Cursor cursor = (Cursor) selectedItem;
-
- // Don't show the context menu for folders
- if (!(cursor.getInt(cursor.getColumnIndexOrThrow(Bookmarks.TYPE)) == Bookmarks.TYPE_FOLDER)) {
- String keyword = null;
- int keywordCol = cursor.getColumnIndex(URLColumns.KEYWORD);
- if (keywordCol != -1)
- keyword = cursor.getString(keywordCol);
-
- int id = cursor.getInt(cursor.getColumnIndexOrThrow(Bookmarks._ID));
-
- subject = new ContextMenuSubject(id,
- cursor.getString(cursor.getColumnIndexOrThrow(URLColumns.URL)),
- cursor.getBlob(cursor.getColumnIndexOrThrow(URLColumns.FAVICON)),
- cursor.getString(cursor.getColumnIndexOrThrow(URLColumns.TITLE)),
- keyword,
- isInReadingList() ? Combined.DISPLAY_READER : Combined.DISPLAY_NORMAL);
- }
-
- if (subject == null)
- return subject;
-
- setupMenu(menu, subject);
-
- menu.findItem(R.id.remove_history).setVisible(false);
- menu.findItem(R.id.open_in_reader).setVisible(false);
-
- return subject;
- }
-}
diff --git a/mobile/android/base/awesomebar/HistoryTab.java b/mobile/android/base/awesomebar/HistoryTab.java
deleted file mode 100644
index 3d2620851360..000000000000
--- a/mobile/android/base/awesomebar/HistoryTab.java
+++ /dev/null
@@ -1,455 +0,0 @@
-/* -*- 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;
-
-import org.mozilla.gecko.AwesomeBar.ContextMenuSubject;
-import org.mozilla.gecko.db.BrowserContract.Combined;
-import org.mozilla.gecko.db.BrowserDB;
-import org.mozilla.gecko.db.BrowserDB.URLColumns;
-import org.mozilla.gecko.gfx.BitmapUtils;
-import org.mozilla.gecko.util.GamepadUtils;
-import org.mozilla.gecko.util.ThreadUtils;
-import org.mozilla.gecko.widget.FaviconView;
-
-import android.app.Activity;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.res.Resources;
-import android.database.ContentObserver;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.os.AsyncTask;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.Pair;
-import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.KeyEvent;
-import android.view.MenuInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ExpandableListView;
-import android.widget.ImageView;
-import android.widget.ListView;
-import android.widget.SimpleExpandableListAdapter;
-import android.widget.TextView;
-
-import java.util.Date;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-public class HistoryTab extends AwesomeBarTab {
- public static final String LOGTAG = "HISTORY_TAB";
- public static final String TAG = "history";
- private static enum HistorySection { TODAY, YESTERDAY, WEEK, OLDER };
- private ContentObserver mContentObserver;
- private ContentResolver mContentResolver;
- private HistoryQueryTask mQueryTask = null;
- private HistoryListAdapter mCursorAdapter = null;
-
- public HistoryTab(Context context) {
- super(context);
- mContentObserver = null;
- }
-
- @Override
- public int getTitleStringId() {
- return R.string.awesomebar_history_title;
- }
-
- @Override
- public String getTag() {
- return TAG;
- }
-
- @Override
- public ListView getView() {
- if (mView == null) {
- mView = new ExpandableListView(mContext, null);
- ((Activity)mContext).registerForContextMenu(mView);
- mView.setTag(TAG);
-
- ExpandableListView list = (ExpandableListView)mView;
- list.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
- @Override
- public boolean onChildClick(ExpandableListView parent, View view,
- int groupPosition, int childPosition, long id) {
- return handleItemClick(groupPosition, childPosition);
- }
- });
-
- // This is to disallow collapsing the expandable groups in the
- // history expandable list view to mimic simpler sections. We should
- // Remove this if we decide to allow expanding/collapsing groups.
- list.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
- @Override
- public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
- return true;
- }
- });
- list.setOnKeyListener(new View.OnKeyListener() {
- @Override public boolean onKey(View v, int keyCode, KeyEvent event) {
- if (GamepadUtils.isActionKeyDown(event)) {
- ExpandableListView expando = (ExpandableListView)v;
- long selected = expando.getSelectedPosition();
- switch (ExpandableListView.getPackedPositionType(selected)) {
- case ExpandableListView.PACKED_POSITION_TYPE_CHILD:
- return handleItemClick(ExpandableListView.getPackedPositionGroup(selected),
- ExpandableListView.getPackedPositionChild(selected));
- case ExpandableListView.PACKED_POSITION_TYPE_GROUP:
- int group = ExpandableListView.getPackedPositionGroup(selected);
- return (expando.isGroupExpanded(group)
- ? expando.collapseGroup(group)
- : expando.expandGroup(group));
- }
- }
- return false;
- }
- });
-
- mView.setOnTouchListener(mListListener);
-
- // We need to add the header before we set the adapter, hence make it null
- list.setAdapter(getCursorAdapter());
- HistoryQueryTask task = new HistoryQueryTask();
- task.execute();
- }
- return (ListView)mView;
- }
-
- @Override
- public void destroy() {
- super.destroy();
-
- if (mContentObserver != null)
- BrowserDB.unregisterContentObserver(getContentResolver(), mContentObserver);
- }
-
- @Override
- public boolean onBackPressed() {
- // If the soft keyboard is visible in the bookmarks or history tab, the user
- // must have explictly brought it up, so we should try hiding it instead of
- // exiting the activity or going up a bookmarks folder level.
- View view = getView();
- if (hideSoftInput(view))
- return true;
-
- return false;
- }
-
- protected HistoryListAdapter getCursorAdapter() {
- return mCursorAdapter;
- }
-
- private class HistoryListAdapter extends SimpleExpandableListAdapter {
- public HistoryListAdapter(Context context, List extends Map> groupData,
- int groupLayout, String[] groupFrom, int[] groupTo,
- List extends List extends Map>> childData) {
-
- super(context, groupData, groupLayout, groupFrom, groupTo,
- childData, -1, new String[] {}, new int[] {});
- }
-
- @Override
- public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
- View convertView, ViewGroup parent) {
- AwesomeEntryViewHolder viewHolder = null;
-
- if (convertView == null) {
- convertView = getInflater().inflate(R.layout.awesomebar_row, null);
-
- viewHolder = new AwesomeEntryViewHolder();
- viewHolder.titleView = (TextView) convertView.findViewById(R.id.title);
- viewHolder.urlView = (TextView) convertView.findViewById(R.id.url);
- viewHolder.faviconView = (FaviconView) convertView.findViewById(R.id.favicon);
- viewHolder.bookmarkIconView = (ImageView) convertView.findViewById(R.id.bookmark_icon);
-
- convertView.setTag(viewHolder);
- } else {
- viewHolder = (AwesomeEntryViewHolder) convertView.getTag();
- }
-
- HistoryListAdapter adapter = getCursorAdapter();
- if (adapter == null)
- return null;
-
- @SuppressWarnings("unchecked")
- Map historyItem =
- (Map) adapter.getChild(groupPosition, childPosition);
-
- String title = (String) historyItem.get(URLColumns.TITLE);
- String url = (String) historyItem.get(URLColumns.URL);
-
- updateTitle(viewHolder.titleView, title, url);
- updateUrl(viewHolder, url);
-
- byte[] b = (byte[]) historyItem.get(URLColumns.FAVICON);
- Bitmap favicon = null;
-
- if (b != null) {
- Bitmap bitmap = BitmapUtils.decodeByteArray(b);
- if (bitmap != null) {
- favicon = Favicons.getInstance().scaleImage(bitmap);
- }
- }
- updateFavicon(viewHolder.faviconView, favicon, url);
-
- Integer bookmarkId = (Integer) historyItem.get(Combined.BOOKMARK_ID);
- Integer display = (Integer) historyItem.get(Combined.DISPLAY);
-
- // The bookmark id will be 0 (null in database) when the url
- // is not a bookmark. Reading list items are irrelevant in history
- // tab. We should never show any sign or them.
- int visibility = (bookmarkId != 0 && display != Combined.DISPLAY_READER ?
- View.VISIBLE : View.GONE);
-
- viewHolder.bookmarkIconView.setVisibility(visibility);
- viewHolder.bookmarkIconView.setImageResource(R.drawable.ic_awesomebar_star);
-
- return convertView;
- }
- }
-
- private static class GroupList extends LinkedList