Bug 876712 - Kill AweseomeBar/AwesomeBarTabs. r=sriram,wesj

This commit is contained in:
Margaret Leibovic 2013-06-12 13:33:13 -07:00
parent 39a2a15e56
commit 251ea42e65
37 changed files with 1 additions and 4213 deletions

View File

@ -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);
}

View File

@ -223,11 +223,6 @@
</intent-filter>
</activity>
<activity android:name="org.mozilla.gecko.AwesomeBar"
android:theme="@style/Gecko.AwesomeBar"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysVisible|adjustResize"/>
<activity android:name="org.mozilla.gecko.GeckoPreferences"
android:theme="@style/Gecko.Preferences"
android:label="@string/settings_title"

View File

@ -1,874 +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.db.BrowserContract.Combined;
import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.gfx.BitmapUtils;
import org.mozilla.gecko.health.BrowserHealthRecorder;
import org.mozilla.gecko.util.GamepadUtils;
import org.mozilla.gecko.util.StringUtils;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.util.UiAsyncTask;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.text.Editable;
import android.text.InputType;
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.ContextMenu.ContextMenuInfo;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.MenuInflater;
import android.view.View;
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.TabWidget;
import android.widget.Toast;
import org.json.JSONObject;
import java.net.URLEncoder;
public class AwesomeBar extends GeckoActivity
implements AutocompleteHandler,
TextWatcher {
private static final String LOGTAG = "GeckoAwesomeBar";
public static final String URL_KEY = "url";
public static final String TAB_KEY = "tab";
public static final String CURRENT_URL_KEY = "currenturl";
public static final String TARGET_KEY = "target";
public static final String SEARCH_KEY = "search";
public static final String TITLE_KEY = "title";
public static final String USER_ENTERED_KEY = "user_entered";
public static final String READING_LIST_KEY = "reading_list";
public static enum Target { NEW_TAB, CURRENT_TAB, PICK_SITE };
private String mTarget;
private AwesomeBarTabs mAwesomeTabs;
private CustomEditText mText;
private ImageButton mGoButton;
private ContextMenuSubject mContextMenuSubject;
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;
@Override
public void onCreate(Bundle savedInstanceState) {
LayoutInflater.from(this).setFactory(this);
super.onCreate(savedInstanceState);
Log.d(LOGTAG, "creating awesomebar");
setContentView(R.layout.awesomebar);
mGoButton = (ImageButton) findViewById(R.id.awesomebar_button);
mText = (CustomEditText) findViewById(R.id.awesomebar_text);
TabWidget tabWidget = (TabWidget) findViewById(android.R.id.tabs);
tabWidget.setDividerDrawable(null);
mAwesomeTabs = (AwesomeBarTabs) findViewById(R.id.awesomebar_tabs);
mAwesomeTabs.setOnUrlOpenListener(new AwesomeBarTabs.OnUrlOpenListener() {
@Override
public void onUrlOpen(String url, String title) {
openUrlAndFinish(url, title, false);
}
@Override
public void onSearch(SearchEngine engine, String text) {
Intent resultIntent = new Intent();
resultIntent.putExtra(URL_KEY, text);
resultIntent.putExtra(TARGET_KEY, mTarget);
resultIntent.putExtra(SEARCH_KEY, engine.name);
recordSearch(engine.identifier, "barsuggest");
finishWithResult(resultIntent);
}
@Override
public void onEditSuggestion(final String text) {
ThreadUtils.postToUiThread(new Runnable() {
@Override
public void run() {
mText.setText(text);
mText.setSelection(mText.getText().length());
mText.requestFocus();
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(mText, InputMethodManager.SHOW_IMPLICIT);
}
});
}
@Override
public void onSwitchToTab(final int tabId) {
Intent resultIntent = new Intent();
resultIntent.putExtra(TAB_KEY, Integer.toString(tabId));
finishWithResult(resultIntent);
}
});
mGoButton.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick(View v) {
openUserEnteredAndFinish(mText.getText().toString());
}
});
Intent intent = getIntent();
String currentUrl = intent.getStringExtra(CURRENT_URL_KEY);
if (currentUrl != null) {
mText.setText(currentUrl);
mText.selectAll();
}
mTarget = intent.getStringExtra(TARGET_KEY);
if (mTarget.equals(Target.CURRENT_TAB.name())) {
Tab tab = Tabs.getInstance().getSelectedTab();
if (tab != null && tab.isPrivate()) {
BrowserToolbarBackground mAddressBarBg = (BrowserToolbarBackground) findViewById(R.id.url_bar_bg);
mAddressBarBg.setPrivateMode(true);
ShapedButton mTabs = (ShapedButton) findViewById(R.id.dummy_tab);
if (mTabs != null)
mTabs.setPrivateMode(true);
mText.setPrivateMode(true);
}
}
mAwesomeTabs.setTarget(mTarget);
mText.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 AwesomeBar has a composition string, don't submit the text yet.
// ENTER is needed to commit the composition string.
Editable content = mText.getText();
if (!hasCompositionString(content)) {
openUserEnteredAndFinish(content.toString());
return true;
}
}
// If input method is in fullscreen mode, we want to dismiss
// it instead of closing awesomebar straight away.
InputMethodManager imm =
(InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
if (keyCode == KeyEvent.KEYCODE_BACK && !imm.isFullscreenMode()) {
return handleBackKey();
}
return false;
}
});
mText.addTextChangedListener(this);
mText.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;
openUserEnteredAndFinish(mText.getText().toString());
return true;
} else if (GamepadUtils.isBackKey(event)) {
return handleBackKey();
} else {
return false;
}
}
});
mText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (v == null || hasFocus) {
return;
}
InputMethodManager imm = (InputMethodManager) 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);
}
}
});
mText.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;
getActionBar().show();
return false;
}
return false;
}
});
mText.setOnSelectionChangedListener(new CustomEditText.OnSelectionChangedListener() {
@Override
public void onSelectionChanged(int selStart, int selEnd) {
if (Build.VERSION.SDK_INT >= 11 && selStart == selEnd) {
getActionBar().hide();
}
}
});
boolean showReadingList = intent.getBooleanExtra(READING_LIST_KEY, false);
if (showReadingList) {
BookmarksTab bookmarksTab = mAwesomeTabs.getBookmarksTab();
bookmarksTab.setShowReadingList(true);
mAwesomeTabs.setCurrentItemByTag(bookmarksTab.getTag());
}
}
/*
* Only one factory can be set on the inflater; however, we want to use two
* factories (GeckoViewsFactory and the FragmentActivity factory).
* Overriding onCreateView() here allows us to dispatch view creation to
* both factories.
*/
@Override
public View onCreateView(String name, Context context, AttributeSet attrs) {
View view = GeckoViewsFactory.getInstance().onCreateView(name, context, attrs);
if (view == null) {
view = super.onCreateView(name, context, attrs);
}
return view;
}
private boolean handleBackKey() {
// Let mAwesomeTabs try to handle the back press, since we may be in a
// bookmarks sub-folder.
if (mAwesomeTabs.onBackPressed())
return true;
// If mAwesomeTabs.onBackPressed() returned false, we didn't move up
// a folder level, so just exit the activity.
cancelAndFinish();
return true;
}
@Override
public void onConfigurationChanged(Configuration newConfiguration) {
super.onConfigurationChanged(newConfiguration);
}
@Override
public boolean onSearchRequested() {
cancelAndFinish();
return true;
}
private void updateGoButton(String text) {
if (text.length() == 0) {
mGoButton.setVisibility(View.GONE);
return;
}
mGoButton.setVisibility(View.VISIBLE);
int imageResource = R.drawable.ic_url_bar_go;
String contentDescription = getString(R.string.go);
int imeAction = EditorInfo.IME_ACTION_GO;
int actionBits = mText.getImeOptions() & EditorInfo.IME_MASK_ACTION;
if (StringUtils.isSearchQuery(text, actionBits == EditorInfo.IME_ACTION_SEARCH)) {
imageResource = R.drawable.ic_url_bar_search;
contentDescription = getString(R.string.search);
imeAction = EditorInfo.IME_ACTION_SEARCH;
}
InputMethodManager imm = InputMethods.getInputMethodManager(mText.getContext());
if (imm == null) {
return;
}
boolean restartInput = false;
if (actionBits != imeAction) {
int optionBits = mText.getImeOptions() & ~EditorInfo.IME_MASK_ACTION;
mText.setImeOptions(optionBits | imeAction);
mDelayRestartInput = (imeAction == EditorInfo.IME_ACTION_GO) &&
(InputMethods.shouldDelayUrlBarUpdate(mText.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(mText);
mGoButton.setImageResource(imageResource);
mGoButton.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 = mText.getText().toString();
int currentInputType = mText.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) {
mText.setRawInputType(newInputType);
}
}
private void cancelAndFinish() {
setResult(Activity.RESULT_CANCELED);
finish();
overridePendingTransition(R.anim.awesomebar_hold_still, R.anim.awesomebar_fade_out);
}
private void finishWithResult(Intent intent) {
setResult(Activity.RESULT_OK, intent);
finish();
overridePendingTransition(R.anim.awesomebar_hold_still, R.anim.awesomebar_fade_out);
}
private void openUrlAndFinish(String url) {
openUrlAndFinish(url, null, false);
}
private void openUrlAndFinish(String url, String title, boolean userEntered) {
Intent resultIntent = new Intent();
resultIntent.putExtra(URL_KEY, url);
if (title != null && !TextUtils.isEmpty(title))
resultIntent.putExtra(TITLE_KEY, title);
if (userEntered)
resultIntent.putExtra(USER_ENTERED_KEY, userEntered);
resultIntent.putExtra(TARGET_KEY, mTarget);
finishWithResult(resultIntent);
}
/**
* Record in Health Report that a search has occurred.
*
* @param identifier
* a search identifier, such as "partnername". Can be null.
* @param where
* where the search was initialized; one of the values in
* {@link BrowserHealthRecorder#SEARCH_LOCATIONS}.
*/
private static void recordSearch(String identifier, String where) {
Log.i(LOGTAG, "Recording search: " + identifier + ", " + where);
try {
JSONObject message = new JSONObject();
message.put("type", BrowserHealthRecorder.EVENT_SEARCH);
message.put("location", where);
message.put("identifier", identifier);
GeckoAppShell.getEventDispatcher().dispatchEvent(message);
} catch (Exception e) {
Log.w(LOGTAG, "Error recording search.", e);
}
}
private void openUserEnteredAndFinish(final String url) {
final int index = url.indexOf(' ');
// Check for a keyword if the URL looks like a search query
if (!StringUtils.isSearchQuery(url, true)) {
openUrlAndFinish(url, "", true);
return;
}
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
final String keyword;
final String keywordSearch;
if (index == -1) {
keyword = url;
keywordSearch = "";
} else {
keyword = url.substring(0, index);
keywordSearch = url.substring(index + 1);
}
final String keywordUrl = BrowserDB.getUrlForKeyword(getContentResolver(), keyword);
final String searchUrl = (keywordUrl != null)
? keywordUrl.replace("%s", URLEncoder.encode(keywordSearch))
: url;
if (keywordUrl != null) {
recordSearch(null, "barkeyword");
}
openUrlAndFinish(searchUrl, "", true);
}
});
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// 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 super.onKeyDown(keyCode, event);
} else if (keyCode == KeyEvent.KEYCODE_SEARCH) {
mText.setText("");
mText.requestFocus();
InputMethodManager imm = (InputMethodManager) mText.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(mText, InputMethodManager.SHOW_IMPLICIT);
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);
}
private abstract class EditBookmarkTextWatcher implements TextWatcher {
protected AlertDialog mDialog;
protected EditBookmarkTextWatcher mPairedTextWatcher;
protected boolean mEnabled = true;
public EditBookmarkTextWatcher(AlertDialog aDialog) {
mDialog = aDialog;
}
public void setPairedTextWatcher(EditBookmarkTextWatcher aTextWatcher) {
mPairedTextWatcher = aTextWatcher;
}
public boolean isEnabled() {
return mEnabled;
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// Disable if the we're disabled or paired partner is disabled
boolean enabled = mEnabled && (mPairedTextWatcher == null || mPairedTextWatcher.isEnabled());
mDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(enabled);
}
@Override
public void afterTextChanged(Editable s) {}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
}
private class LocationTextWatcher extends EditBookmarkTextWatcher implements TextWatcher {
public LocationTextWatcher(AlertDialog aDialog) {
super(aDialog);
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// Disable if the location is empty
mEnabled = (s.toString().trim().length() > 0);
super.onTextChanged(s, start, before, count);
}
}
private class KeywordTextWatcher extends EditBookmarkTextWatcher implements TextWatcher {
public KeywordTextWatcher(AlertDialog aDialog) {
super(aDialog);
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// Disable if the keyword contains spaces
mEnabled = (s.toString().trim().indexOf(' ') == -1);
super.onTextChanged(s, start, before, count);
}
}
@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;
switch (item.getItemId()) {
case R.id.open_private_tab:
case R.id.open_new_tab: {
if (url == null) {
Log.e(LOGTAG, "Can't open in new tab because URL is null");
break;
}
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();
break;
}
case R.id.open_in_reader: {
if (url == null) {
Log.e(LOGTAG, "Can't open in reader mode because URL is null");
break;
}
openUrlAndFinish(ReaderModeUtils.getAboutReaderForUrl(url, true));
break;
}
case R.id.edit_bookmark: {
AlertDialog.Builder editPrompt = new AlertDialog.Builder(this);
final View editView = getLayoutInflater().inflate(R.layout.bookmark_edit, null);
editPrompt.setTitle(R.string.bookmark_edit_title);
editPrompt.setView(editView);
final EditText nameText = ((EditText) editView.findViewById(R.id.edit_bookmark_name));
final EditText locationText = ((EditText) editView.findViewById(R.id.edit_bookmark_location));
final EditText keywordText = ((EditText) editView.findViewById(R.id.edit_bookmark_keyword));
nameText.setText(title);
locationText.setText(url);
keywordText.setText(keyword);
editPrompt.setPositiveButton(R.string.button_ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int whichButton) {
(new UiAsyncTask<Void, Void, Void>(ThreadUtils.getBackgroundHandler()) {
@Override
public Void doInBackground(Void... params) {
String newUrl = locationText.getText().toString().trim();
String newKeyword = keywordText.getText().toString().trim();
BrowserDB.updateBookmark(getContentResolver(), id, newUrl, nameText.getText().toString(), newKeyword);
return null;
}
@Override
public void onPostExecute(Void result) {
Toast.makeText(AwesomeBar.this, R.string.bookmark_updated, Toast.LENGTH_SHORT).show();
}
}).execute();
}
});
editPrompt.setNegativeButton(R.string.button_cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int whichButton) {
// do nothing
}
});
final AlertDialog dialog = editPrompt.create();
// Create our TextWatchers
LocationTextWatcher locationTextWatcher = new LocationTextWatcher(dialog);
KeywordTextWatcher keywordTextWatcher = new KeywordTextWatcher(dialog);
// Cross reference the TextWatchers
locationTextWatcher.setPairedTextWatcher(keywordTextWatcher);
keywordTextWatcher.setPairedTextWatcher(locationTextWatcher);
// Add the TextWatcher Listeners
locationText.addTextChangedListener(locationTextWatcher);
keywordText.addTextChangedListener(keywordTextWatcher);
dialog.show();
break;
}
case R.id.remove_bookmark: {
(new UiAsyncTask<Void, Void, Void>(ThreadUtils.getBackgroundHandler()) {
private boolean mInReadingList;
@Override
public void onPreExecute() {
mInReadingList = mAwesomeTabs.isInReadingList();
}
@Override
public Void doInBackground(Void... params) {
BrowserDB.removeBookmark(getContentResolver(), id);
return null;
}
@Override
public void onPostExecute(Void result) {
int messageId = R.string.bookmark_removed;
if (mInReadingList) {
messageId = R.string.reading_list_removed;
GeckoEvent e = GeckoEvent.createBroadcastEvent("Reader:Remove", url);
GeckoAppShell.sendEventToGecko(e);
}
Toast.makeText(AwesomeBar.this, messageId, Toast.LENGTH_SHORT).show();
}
}).execute();
break;
}
case R.id.remove_history: {
(new UiAsyncTask<Void, Void, Void>(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();
break;
}
case R.id.add_to_launcher: {
if (url == null) {
Log.e(LOGTAG, "Can't add to home screen because URL is null");
break;
}
Bitmap bitmap = null;
if (b != null && b.length > 0) {
bitmap = BitmapUtils.decodeByteArray(b);
}
String shortcutTitle = TextUtils.isEmpty(title) ? url.replaceAll("^([a-z]+://)?(www\\.)?", "") : title;
GeckoAppShell.createShortcut(shortcutTitle, url, bitmap, "");
break;
}
case R.id.share: {
if (url == null) {
Log.e(LOGTAG, "Can't share because URL is null");
break;
}
GeckoAppShell.openUriExternal(url, "text/plain", "", "",
Intent.ACTION_SEND, title);
break;
}
default: {
return super.onContextItemSelected(item);
}
}
return true;
}
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)) {
updateGoButton(text);
}
if (Build.VERSION.SDK_INT >= 11) {
getActionBar().hide();
}
}
@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
}
}

View File

@ -1,382 +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.view.inputmethod.InputMethodManager;
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.url_bar_bg);
setPadding(padding[0], padding[1], padding[2], padding[3]);
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -2060,13 +2060,7 @@ abstract public class GeckoApp
}
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);
// FIXME: bug 862798 (also, this probably belong in BrowserApp)
}
@Override

View File

@ -57,8 +57,6 @@ public final class GeckoViewsFactory implements LayoutInflater.Factory {
mFactoryMap.put("PromoBox", PromoBox.class.getConstructor(arg1Class, arg2Class));
mFactoryMap.put("RemoteTabsSection", RemoteTabsSection.class.getConstructor(arg1Class, arg2Class));
mFactoryMap.put("TopSitesView", TopSitesView.class.getConstructor(arg1Class, arg2Class));
mFactoryMap.put("AwesomeBarTabs", AwesomeBarTabs.class.getConstructor(arg1Class, arg2Class));
mFactoryMap.put("AwesomeBarTabs$BackgroundLayout", AwesomeBarTabs.BackgroundLayout.class.getConstructor(arg1Class, arg2Class));
mFactoryMap.put("BackButton", BackButton.class.getConstructor(arg1Class, arg2Class));
mFactoryMap.put("BrowserToolbarBackground", BrowserToolbarBackground.class.getConstructor(arg1Class, arg2Class));
mFactoryMap.put("CheckableLinearLayout", CheckableLinearLayout.class.getConstructor(arg1Class, arg2Class));

View File

@ -52,18 +52,11 @@ FENNEC_JAVA_FILES = \
AnimatedHeightLayout.java \
AppNotificationClient.java \
AutocompleteHandler.java \
AwesomeBar.java \
AwesomebarResultHandler.java \
AwesomeBarTabs.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 \
BrowserSearch.java \
@ -434,18 +427,7 @@ RES_LAYOUT = \
res/layout/abouthome_content.xml \
res/layout/autocomplete_list.xml \
res/layout/autocomplete_list_item.xml \
res/layout/awesomebar.xml \
res/layout/awesomebar_actionbar.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_row.xml \
res/layout/awesomebar_suggestion_item.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/browser_toolbar.xml \
@ -497,7 +479,6 @@ RES_LAYOUT = \
$(NULL)
RES_LAYOUT_LARGE_V11 = \
res/layout-large-v11/awesomebar_search.xml \
res/layout-large-v11/browser_toolbar.xml \
$(NULL)
@ -508,7 +489,6 @@ RES_LAYOUT_LARGE_LAND_V11 = \
$(NULL)
RES_LAYOUT_XLARGE_V11 = \
res/layout-xlarge-v11/awesomebar_search.xml \
res/layout-xlarge-v11/font_size_preference.xml \
res/layout-xlarge-v11/remote_tabs_child.xml \
res/layout-xlarge-v11/remote_tabs_group.xml \
@ -584,11 +564,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/shrink_fade_out.xml \
@ -612,11 +589,6 @@ RES_DRAWABLE_MDPI = \
res/drawable-mdpi/alert_app.png \
res/drawable-mdpi/alert_download.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 \
@ -728,11 +700,6 @@ RES_DRAWABLE_HDPI = \
res/drawable-hdpi/alert_addon.png \
res/drawable-hdpi/alert_app.png \
res/drawable-hdpi/alert_download.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/bookmark_folder_closed.png \
res/drawable-hdpi/bookmark_folder_opened.png \
res/drawable-hdpi/ic_addons_empty.png \
@ -824,11 +791,6 @@ RES_DRAWABLE_XHDPI = \
res/drawable-xhdpi/alert_addon.png \
res/drawable-xhdpi/alert_app.png \
res/drawable-xhdpi/alert_download.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/bookmark_folder_closed.png \
res/drawable-xhdpi/bookmark_folder_opened.png \
res/drawable-xhdpi/ic_addons_empty.png \
@ -992,31 +954,16 @@ RES_DRAWABLE_LARGE_XHDPI_V11 = \
$(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)
@ -1067,11 +1014,6 @@ MOZ_ANDROID_DRAWABLES += \
mobile/android/base/resources/drawable/url_bar_entry.xml \
mobile/android/base/resources/drawable/url_bar_nav_button.xml \
mobile/android/base/resources/drawable/url_bar_right_edge.xml \
mobile/android/base/resources/drawable/awesomebar_listview_divider.xml \
mobile/android/base/resources/drawable/awesomebar_header_row.xml \
mobile/android/base/resources/drawable/awesomebar_tab_indicator.xml \
mobile/android/base/resources/drawable/awesomebar_tab_selected.xml \
mobile/android/base/resources/drawable/awesomebar_tab_unselected.xml \
mobile/android/base/resources/drawable/bookmark_folder.xml \
mobile/android/base/resources/drawable/favicon_bg.xml \
mobile/android/base/resources/drawable/handle_end_level.xml \

View File

@ -1,975 +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<SearchEngine> mSearchEngines;
private SuggestClient mSuggestClient;
private boolean mSuggestionsEnabled;
private AsyncTask<String, Void, ArrayList<String>> 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;
private class SearchEntryViewHolder {
public FlowLayout suggestionView;
public FaviconView iconView;
public LinearLayout userEnteredView;
public TextView userEnteredTextView;
}
public AllPagesTab(Context context) {
super(context);
mSearchEngines = new ArrayList<SearchEngine>();
registerEventListener("SearchEngines:Data");
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("SearchEngines:Get", null));
mHandler = new AllPagesHandler();
}
@Override
public boolean onBackPressed() {
return false;
}
@Override
public int getTitleStringId() {
return R.string.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);
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);
}
});
list.setOnKeyListener(GamepadUtils.getListItemClickDispatcher());
AwesomeBarCursorAdapter adapter = getCursorAdapter();
list.setAdapter(adapter);
list.setOnTouchListener(mListListener);
}
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<String> 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<String, Void, ArrayList<String>>() {
@Override
protected ArrayList<String> doInBackground(String... query) {
return mSuggestClient.query(query[0]);
}
@Override
protected void onPostExecute(ArrayList<String> 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();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
favicon = stream.toByteArray();
}
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 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) {
SearchEntryViewHolder viewHolder = null;
if (convertView == null || !(convertView.getTag() instanceof SearchEntryViewHolder)) {
convertView = getInflater().inflate(R.layout.awesomebar_suggestion_row, getListView(), false);
viewHolder = new SearchEntryViewHolder();
viewHolder.suggestionView = (FlowLayout) convertView.findViewById(R.id.suggestion_layout);
viewHolder.iconView = (FaviconView) convertView.findViewById(R.id.suggestion_icon);
viewHolder.userEnteredView = (LinearLayout) convertView.findViewById(R.id.suggestion_user_entered);
viewHolder.userEnteredTextView = (TextView) convertView.findViewById(R.id.suggestion_text);
convertView.setTag(viewHolder);
} else {
viewHolder = (SearchEntryViewHolder) convertView.getTag();
}
bindSearchEngineView(mSearchEngines.get(getEngineIndex(position)), viewHolder);
} 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;
}
private void bindSearchEngineView(final SearchEngine engine, final SearchEntryViewHolder viewHolder) {
// when a suggestion is clicked, do a search
OnClickListener clickListener = new OnClickListener() {
@Override
public void onClick(View v) {
AwesomeBarTabs.OnUrlOpenListener listener = getUrlListener();
if (listener != null) {
String suggestion = ((TextView) v.findViewById(R.id.suggestion_text)).getText().toString();
// If we're not clicking the user-entered view (the
// first suggestion item) and the search matches a URL
// pattern, go to that URL. Otherwise, do a search for
// the term.
if (v != viewHolder.userEnteredView && !StringUtils.isSearchQuery(suggestion, false)) {
listener.onUrlOpen(suggestion, null);
} else {
listener.onSearch(engine, suggestion);
}
}
}
};
// when a suggestion is long-clicked, copy the suggestion into the URL EditText
OnLongClickListener longClickListener = new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
AwesomeBarTabs.OnUrlOpenListener listener = getUrlListener();
if (listener != null) {
String suggestion = ((TextView) v.findViewById(R.id.suggestion_text)).getText().toString();
listener.onEditSuggestion(suggestion);
return true;
}
return false;
}
};
// set the search engine icon (e.g., Google) for the row
FlowLayout suggestionView = viewHolder.suggestionView;
updateFavicon(viewHolder.iconView, engine.icon, engine.name);
// user-entered search term is first suggestion
viewHolder.userEnteredTextView.setText(mSearchTerm);
viewHolder.userEnteredView.setOnClickListener(clickListener);
// add additional suggestions given by this engine
int recycledSuggestionCount = suggestionView.getChildCount();
int suggestionCount = engine.suggestions.size();
boolean showedSuggestions = false;
for (int i = 0; i < suggestionCount; i++) {
String suggestion = engine.suggestions.get(i);
View suggestionItem = null;
// reuse suggestion views from recycled view, if possible
if (i+1 < recycledSuggestionCount) {
suggestionItem = suggestionView.getChildAt(i+1);
suggestionItem.setVisibility(View.VISIBLE);
} else {
suggestionItem = getInflater().inflate(R.layout.awesomebar_suggestion_item, null);
((ImageView) suggestionItem.findViewById(R.id.suggestion_magnifier)).setVisibility(View.GONE);
suggestionView.addView(suggestionItem);
}
((TextView) suggestionItem.findViewById(R.id.suggestion_text)).setText(suggestion);
suggestionItem.setOnClickListener(clickListener);
suggestionItem.setOnLongClickListener(longClickListener);
if (mAnimateSuggestions) {
showedSuggestions = true;
AlphaAnimation anim = new AlphaAnimation(0, 1);
anim.setDuration(ANIMATION_DURATION);
anim.setStartOffset(i * ANIMATION_DURATION);
suggestionItem.startAnimation(anim);
}
}
// hide extra suggestions that have been recycled
for (int i = suggestionCount + 1; i < recycledSuggestionCount; i++) {
suggestionView.getChildAt(i).setVisibility(View.GONE);
}
if (showedSuggestions)
mAnimateSuggestions = false;
}
};
/**
* Sets suggestions associated with the current suggest engine.
* If there is no suggest engine, this does nothing.
*/
private void setSuggestions(final ArrayList<String> 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<SearchEngine> searchEngines = new ArrayList<SearchEngine>();
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);
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_url_bar_reader);
} else {
bookmarkIconView.setImageResource(R.drawable.ic_url_bar_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<String> getUrlsWithoutFavicon() {
List<String> urls = new ArrayList<String>();
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) {
try {
if (c == null || !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 || b.length == 0)
continue;
Bitmap favicon = BitmapUtils.decodeByteArray(b);
if (favicon == null)
continue;
favicon = Favicons.getInstance().scaleImage(favicon);
Favicons.getInstance().putFaviconInMemCache(url, favicon);
} while (c.moveToNext());
} finally {
if (c != null)
c.close();
}
}
private void loadFaviconsForCurrentResults() {
final List<String> urls = getUrlsWithoutFavicon();
if (urls.size() == 0)
return;
(new UiAsyncTask<Void, Void, Void>(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;
}
}
}
}

View File

@ -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<String, Integer> 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<String, Integer> getOpenTabs() {
if (sOpenTabs == null || sOpenTabs.isEmpty()) {
Iterable<Tab> tabs = Tabs.getInstance().getTabsInOrder();
sOpenTabs = new HashMap<String, Integer>();
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.switch_to_tab);
holder.urlView.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_url_bar_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);
}
}

View File

@ -1,471 +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.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);
}
});
list.setOnKeyListener(GamepadUtils.getListItemClickDispatcher());
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<Pair<Integer, String>> 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<Pair<Integer, String>>();
// Add the root folder to the stack
Pair<Integer, String> rootFolder = new Pair<Integer, String>(Bookmarks.FIXED_ROOT_ID, "");
mParentStack.addFirst(rootFolder);
}
public void refreshCurrentFolder() {
// Cancel any pre-existing async refresh tasks
if (mQueryTask != null)
mQueryTask.cancel(false);
Pair<Integer, String> 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<Integer, String> folderPair = new Pair<Integer, String>(folderId, folderTitle);
mParentStack.addFirst(folderPair);
refreshCurrentFolder();
}
public boolean isInReadingList() {
Pair<Integer, String> 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 && b.length > 0) {
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<Void, Void, Cursor> {
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;
}
}

View File

@ -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.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<String, ?>> groupData,
int groupLayout, String[] groupFrom, int[] groupTo,
List<? extends List<? extends Map<String, ?>>> 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<String,Object> historyItem =
(Map<String,Object>) 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 && b.length > 0) {
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_url_bar_star);
return convertView;
}
}
private static class GroupList extends LinkedList<Map<String,String>> {
private static final long serialVersionUID = 0L;
}
private static class ChildrenList extends LinkedList<Map<String,Object>> {
private static final long serialVersionUID = 0L;
}
private class HistoryQueryTask extends AsyncTask<Void, Void, Pair<GroupList,List<ChildrenList>>> {
private static final long MS_PER_DAY = 86400000;
private static final long MS_PER_WEEK = MS_PER_DAY * 7;
@Override
protected Pair<GroupList,List<ChildrenList>> doInBackground(Void... arg0) {
Cursor cursor = BrowserDB.getRecentHistory(getContentResolver(), MAX_RESULTS);
Date now = new Date();
now.setHours(0);
now.setMinutes(0);
now.setSeconds(0);
long today = now.getTime();
// Split the list of urls into separate date range groups
// and show it in an expandable list view.
List<ChildrenList> childrenLists = new LinkedList<ChildrenList>();
ChildrenList children = null;
GroupList groups = new GroupList();
HistorySection section = null;
// Move cursor before the first row in preparation
// for the iteration.
cursor.moveToPosition(-1);
// Split the history query results into adapters per time
// section (today, yesterday, week, older). Queries on content
// Browser content provider don't support limitting the number
// of returned rows so we limit it here.
while (cursor.moveToNext()) {
long time = cursor.getLong(cursor.getColumnIndexOrThrow(URLColumns.DATE_LAST_VISITED));
HistorySection itemSection = getSectionForTime(time, today);
if (section != itemSection) {
if (section != null) {
groups.add(createGroupItem(section));
childrenLists.add(children);
}
section = itemSection;
children = new ChildrenList();
}
children.add(createHistoryItem(cursor));
}
// Add any remaining section to the list if it hasn't
// been added to the list after the loop.
if (section != null && children != null) {
groups.add(createGroupItem(section));
childrenLists.add(children);
}
// Close the query cursor as we won't use it anymore
cursor.close();
// groups and childrenLists will be empty lists if there's no history
return Pair.<GroupList,List<ChildrenList>>create(groups, childrenLists);
}
public Map<String,Object> createHistoryItem(Cursor cursor) {
Map<String,Object> historyItem = new HashMap<String,Object>();
String url = cursor.getString(cursor.getColumnIndexOrThrow(URLColumns.URL));
String title = cursor.getString(cursor.getColumnIndexOrThrow(URLColumns.TITLE));
byte[] favicon = cursor.getBlob(cursor.getColumnIndexOrThrow(URLColumns.FAVICON));
Integer bookmarkId = cursor.getInt(cursor.getColumnIndexOrThrow(Combined.BOOKMARK_ID));
Integer historyId = cursor.getInt(cursor.getColumnIndexOrThrow(Combined.HISTORY_ID));
Integer display = cursor.getInt(cursor.getColumnIndexOrThrow(Combined.DISPLAY));
// 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 (title == null || title.length() == 0)
title = url;
historyItem.put(URLColumns.URL, url);
historyItem.put(URLColumns.TITLE, title);
if (favicon != null)
historyItem.put(URLColumns.FAVICON, favicon);
historyItem.put(Combined.BOOKMARK_ID, bookmarkId);
historyItem.put(Combined.HISTORY_ID, historyId);
historyItem.put(Combined.DISPLAY, display);
return historyItem;
}
public Map<String,String> createGroupItem(HistorySection section) {
Map<String,String> groupItem = new HashMap<String,String>();
groupItem.put(URLColumns.TITLE, getSectionName(section));
return groupItem;
}
private String getSectionName(HistorySection section) {
Resources resources = mContext.getResources();
switch (section) {
case TODAY:
return resources.getString(R.string.history_today_section);
case YESTERDAY:
return resources.getString(R.string.history_yesterday_section);
case WEEK:
return resources.getString(R.string.history_week_section);
case OLDER:
return resources.getString(R.string.history_older_section);
}
return null;
}
private void expandAllGroups(ExpandableListView historyList) {
int groupCount = mCursorAdapter.getGroupCount();
for (int i = 0; i < groupCount; i++) {
historyList.expandGroup(i);
}
}
private HistorySection getSectionForTime(long time, long today) {
long delta = today - time;
if (delta < 0) {
return HistorySection.TODAY;
}
if (delta < MS_PER_DAY) {
return HistorySection.YESTERDAY;
}
if (delta < MS_PER_WEEK) {
return HistorySection.WEEK;
}
return HistorySection.OLDER;
}
@Override
protected void onPostExecute(Pair<GroupList,List<ChildrenList>> result) {
mCursorAdapter = new HistoryListAdapter(
mContext,
result.first,
R.layout.awesomebar_header_row,
new String[] { URLColumns.TITLE },
new int[] { R.id.title },
result.second
);
if (mContentObserver == null) {
// Register an observer to update the history tab contents if they change.
mContentObserver = new ContentObserver(ThreadUtils.getBackgroundHandler()) {
@Override
public void onChange(boolean selfChange) {
mQueryTask = new HistoryQueryTask();
mQueryTask.execute();
}
};
BrowserDB.registerHistoryObserver(getContentResolver(), mContentObserver);
}
final ExpandableListView historyList = (ExpandableListView)getView();
// Hack: force this to the main thread, even though it should already be on it
ThreadUtils.postToUiThread(new Runnable() {
@Override
public void run() {
historyList.setAdapter(mCursorAdapter);
expandAllGroups(historyList);
}
});
mQueryTask = null;
}
}
public boolean handleItemClick(int groupPosition, int childPosition) {
HistoryListAdapter adapter = getCursorAdapter();
if (adapter == null)
return false;
@SuppressWarnings("unchecked")
Map<String,Object> historyItem = (Map<String,Object>) adapter.getChild(groupPosition, childPosition);
String url = (String) historyItem.get(URLColumns.URL);
String title = (String) historyItem.get(URLColumns.TITLE);
sendToListener(url, title);
return true;
}
@Override
public ContextMenuSubject getSubject(ContextMenu menu, View view, ContextMenuInfo menuInfo) {
ContextMenuSubject subject = null;
if (!(menuInfo instanceof ExpandableListView.ExpandableListContextMenuInfo)) {
Log.e(LOGTAG, "menuInfo is not ExpandableListContextMenuInfo");
return subject;
}
ExpandableListView.ExpandableListContextMenuInfo info = (ExpandableListView.ExpandableListContextMenuInfo) menuInfo;
int childPosition = ExpandableListView.getPackedPositionChild(info.packedPosition);
int groupPosition = ExpandableListView.getPackedPositionGroup(info.packedPosition);
// Check if long tap is on a header row
if (groupPosition < 0 || childPosition < 0)
return subject;
ExpandableListView exList = (ExpandableListView) view;
// The history list is backed by a SimpleExpandableListAdapter
@SuppressWarnings("rawtypes")
Map map = (Map) exList.getExpandableListAdapter().getChild(groupPosition, childPosition);
subject = new AwesomeBar.ContextMenuSubject((Integer) map.get(Combined.HISTORY_ID),
(String) map.get(URLColumns.URL),
(byte[]) map.get(URLColumns.FAVICON),
(String) map.get(URLColumns.TITLE),
null);
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(false);
return subject;
}
}

View File

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

View File

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

View File

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:top="@dimen/awesomebar_tab_transparency_height">
<shape android:shape="rectangle">
<solid android:color="#EEF1F5"/>
</shape>
</item>
<item android:bottom="2dip"
android:drawable="@drawable/awesomebar_tab_center"/>
</layer-list>

View File

@ -1,70 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:maxLevel="0">
<layer-list>
<item android:top="@dimen/awesomebar_tab_transparency_height">
<shape android:shape="rectangle">
<solid android:color="#EEF1F5"/>
</shape>
</item>
</layer-list>
</item>
<item android:maxLevel="1">
<layer-list>
<item android:top="@dimen/awesomebar_tab_transparency_height">
<shape android:shape="rectangle">
<solid android:color="#EEF1F5"/>
</shape>
</item>
<item android:bottom="2dip"
android:drawable="@drawable/awesomebar_tab_left"/>
</layer-list>
</item>
<item android:maxLevel="2">
<layer-list>
<item android:top="@dimen/awesomebar_tab_transparency_height">
<shape android:shape="rectangle">
<solid android:color="#EEF1F5"/>
</shape>
</item>
<item android:bottom="2dip"
android:drawable="@drawable/awesomebar_tab_right"/>
</layer-list>
</item>
<item android:maxLevel="3">
<layer-list>
<item android:top="@dimen/awesomebar_tab_transparency_height">
<shape android:shape="rectangle">
<solid android:color="#EEF1F5"/>
</shape>
</item>
<item android:bottom="2dip"
android:drawable="@drawable/awesomebar_sep_right"/>
</layer-list>
</item>
<item android:maxLevel="4">
<layer-list>
<item android:top="@dimen/awesomebar_tab_transparency_height">
<shape android:shape="rectangle">
<solid android:color="#EEF1F5"/>
</shape>
</item>
<item android:bottom="2dip"
android:drawable="@drawable/awesomebar_sep_left"/>
</layer-list>
</item>
</level-list>

View File

@ -1,57 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:gecko="http://schemas.android.com/apk/res-auto"
style="@style/AwesomeBar">
<org.mozilla.gecko.BrowserToolbarBackground android:id="@+id/url_bar_bg"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
gecko:curveTowards="none"
android:background="@drawable/url_bar_bg"/>
<view class="org.mozilla.gecko.CustomEditText"
android:id="@+id/awesomebar_text"
style="@style/UrlBar.Button"
android:background="@drawable/url_bar_entry"
android:layout_marginLeft="6dip"
android:layout_marginRight="6dip"
android:layout_marginTop="7dip"
android:layout_marginBottom="7dip"
android:layout_alignParentBottom="true"
android:layout_centerVertical="true"
android:paddingLeft="15dip"
android:paddingRight="40dip"
android:hint="@string/url_bar_default_text"
android:textColor="@color/url_bar_title"
android:textColorHint="@color/url_bar_title_hint"
android:textColorHighlight="@color/url_bar_text_highlight"
android:textCursorDrawable="@null"
android:inputType="textUri|textNoSuggestions"
android:imeOptions="actionSearch|flagNoExtractUi|flagNoFullscreen"
android:selectAllOnFocus="true"
android:singleLine="true"
android:gravity="center_vertical|left"
gecko:autoUpdateTheme="false">
<requestFocus/>
</view>
<LinearLayout android:layout_width="4dp"
android:layout_height="fill_parent"
android:orientation="vertical"
android:layout_alignParentRight="true"/>
<ImageButton android:id="@+id/awesomebar_button"
style="@style/UrlBar.ImageButton.Icon"
android:padding="14dip"
android:layout_centerVertical="true"
android:layout_alignRight="@id/awesomebar_text"
android:visibility="gone"
android:src="@drawable/ic_url_bar_go"/>
</RelativeLayout>

View File

@ -1,65 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:gecko="http://schemas.android.com/apk/res-auto"
style="@style/AwesomeBar">
<org.mozilla.gecko.BrowserToolbarBackground android:id="@+id/url_bar_bg"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
gecko:curveTowards="none"
android:background="@drawable/url_bar_bg"/>
<Gecko.ShapedButton android:id="@+id/dummy_tab"
style="@style/UrlBar.ImageButton"
android:layout_width="84dip"
android:layout_alignParentLeft="true"
gecko:curveTowards="left"
android:background="@drawable/shaped_button"
android:gravity="center_vertical"/>
<view class="org.mozilla.gecko.CustomEditText"
android:id="@+id/awesomebar_text"
style="@style/UrlBar.Button"
android:background="@drawable/url_bar_entry"
android:layout_marginLeft="0dip"
android:layout_marginRight="56dip"
android:layout_marginTop="7dip"
android:layout_marginBottom="7dip"
android:layout_toRightOf="@id/dummy_tab"
android:layout_alignParentBottom="true"
android:layout_centerVertical="true"
android:paddingLeft="15dip"
android:paddingRight="40dip"
android:hint="@string/url_bar_default_text"
android:textColor="@color/url_bar_title"
android:textColorHint="@color/url_bar_title_hint"
android:textColorHighlight="@color/url_bar_text_highlight"
android:textCursorDrawable="@null"
android:inputType="textUri|textNoSuggestions"
android:imeOptions="actionSearch|flagNoExtractUi|flagNoFullscreen"
android:selectAllOnFocus="true"
android:singleLine="true"
android:gravity="center_vertical|left">
<requestFocus/>
</view>
<LinearLayout android:layout_width="4dp"
android:layout_height="fill_parent"
android:orientation="vertical"
android:layout_alignParentRight="true"/>
<ImageButton android:id="@+id/awesomebar_button"
style="@style/UrlBar.ImageButton.Icon"
android:padding="14dip"
android:layout_centerVertical="true"
android:layout_alignRight="@id/awesomebar_text"
android:visibility="gone"
android:src="@drawable/ic_url_bar_go"/>
</RelativeLayout>

View File

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/awesome_screen"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:background="@android:color/transparent">
<include layout="@layout/awesomebar_search"/>
<include layout="@layout/awesomebar_tabs"/>
</LinearLayout>

View File

@ -1,15 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<ListView android:id="@+id/awesomebar_list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</LinearLayout>

View File

@ -1,32 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="@dimen/awesomebar_row_height"
android:padding="6dip">
<Gecko.FaviconView android:id="@+id/favicon"
android:src="@drawable/folder"
android:layout_width="@dimen/favicon_bg"
android:layout_height="@dimen/favicon_bg"
android:layout_marginRight="6dip"
android:layout_centerVertical="true"
android:minWidth="@dimen/favicon_bg"
android:minHeight="@dimen/favicon_bg"/>
<TextView android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="6dip"
android:layout_marginRight="6dip"
android:layout_centerVertical="true"
android:textColor="#222222"
android:textSize="18sp"
android:layout_toRightOf="@id/favicon"
android:singleLine="true"
android:ellipsize="middle"/>
</RelativeLayout>

View File

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/title"
android:layout_width="fill_parent"
android:layout_height="@dimen/awesomebar_header_row_height"
android:background="@drawable/awesomebar_header_row"
android:textColor="#222222"
android:textSize="14sp"
android:textStyle="bold"
android:gravity="center_vertical"
android:paddingLeft="6dip"
android:singleLine="true"
android:ellipsize="middle"/>

View File

@ -1,55 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="@dimen/awesomebar_row_height"
android:padding="6dip">
<Gecko.FaviconView android:id="@+id/favicon"
android:layout_width="@dimen/favicon_bg"
android:layout_height="@dimen/favicon_bg"
android:layout_marginLeft="6dip"
android:layout_marginRight="6dip"
android:layout_centerVertical="true"
android:minWidth="@dimen/favicon_bg"
android:minHeight="@dimen/favicon_bg"/>
<ImageView android:id="@+id/bookmark_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:visibility="gone"
android:minHeight="32dip"
android:scaleType="fitStart"/>
<TextView android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="6dip"
android:layout_marginRight="6dip"
android:textColor="#222222"
android:textSize="18sp"
android:layout_toRightOf="@id/favicon"
android:layout_toLeftOf="@id/bookmark_icon"
android:singleLine="true"
android:ellipsize="middle"/>
<TextView android:id="@+id/url"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="6dip"
android:layout_marginRight="6dip"
android:textColor="#9198A1"
android:textSize="14sp"
android:layout_below="@id/title"
android:layout_toRightOf="@id/favicon"
android:layout_toLeftOf="@id/bookmark_icon"
android:includeFontPadding="false"
android:singleLine="true"
android:ellipsize="middle"/>
</RelativeLayout>

View File

@ -1,60 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:gecko="http://schemas.android.com/apk/res-auto"
style="@style/AwesomeBar">
<org.mozilla.gecko.BrowserToolbarBackground android:id="@+id/url_bar_bg"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
gecko:curveTowards="none"
android:background="@drawable/url_bar_bg"/>
<view class="org.mozilla.gecko.CustomEditText"
android:id="@+id/awesomebar_text"
style="@style/UrlBar.Button"
android:background="@drawable/url_bar_entry"
android:layout_marginLeft="4dip"
android:layout_marginRight="4dip"
android:layout_marginTop="5dip"
android:layout_marginBottom="5dip"
android:layout_alignParentBottom="true"
android:layout_centerVertical="true"
android:paddingLeft="15dip"
android:paddingRight="40dip"
android:hint="@string/url_bar_default_text"
android:textColor="@color/url_bar_title"
android:textColorHint="@color/url_bar_title_hint"
android:textColorHighlight="@color/url_bar_text_highlight"
android:textSelectHandle="@drawable/handle_middle"
android:textSelectHandleLeft="@drawable/handle_start"
android:textSelectHandleRight="@drawable/handle_end"
android:textCursorDrawable="@null"
android:inputType="textUri|textNoSuggestions"
android:imeOptions="actionSearch|flagNoExtractUi|flagNoFullscreen"
android:selectAllOnFocus="true"
android:singleLine="true"
android:gravity="center_vertical|left"
gecko:autoUpdateTheme="false">
<requestFocus/>
</view>
<LinearLayout android:layout_width="4dp"
android:layout_height="fill_parent"
android:orientation="vertical"
android:layout_alignParentRight="true"/>
<ImageButton android:id="@+id/awesomebar_button"
style="@style/UrlBar.ImageButton.Icon"
android:padding="12dip"
android:layout_centerVertical="true"
android:layout_alignRight="@id/awesomebar_text"
android:visibility="gone"
android:src="@drawable/ic_url_bar_go"/>
</RelativeLayout>

View File

@ -1,56 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<view xmlns:android="http://schemas.android.com/apk/res/android"
class="org.mozilla.gecko.AwesomeBarTabs$BackgroundLayout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/url_bar_bg">
<LinearLayout android:id="@+id/prompt_container"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:minHeight="@dimen/awesomebar_row_height"
android:gravity="center_vertical"
android:padding="10dip">
<Gecko.TextView android:id="@+id/suggestions_prompt_title"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:textColor="@color/url_bar_title"
android:layout_marginLeft="6dip"
android:textSize="14sp"
android:layout_weight="1" />
<TextView android:id="@+id/suggestions_prompt_yes"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:textSize="14sp"
android:layout_marginLeft="15dip"
android:background="@drawable/suggestion_selector"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:paddingTop="7dp"
android:paddingBottom="7dp"
android:clickable="true"
android:text="@string/button_yes" />
<TextView android:id="@+id/suggestions_prompt_no"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:textSize="14sp"
android:layout_marginLeft="6dip"
android:background="@drawable/suggestion_selector"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:paddingTop="7dp"
android:paddingBottom="7dp"
android:clickable="true"
android:text="@string/button_no" />
</LinearLayout>
</view>

View File

@ -1,31 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<org.mozilla.gecko.AnimatedHeightLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:minHeight="@dimen/awesomebar_row_height"
android:padding="7dip">
<Gecko.FaviconView android:id="@+id/suggestion_icon"
android:layout_width="@dimen/favicon_bg"
android:layout_height="@dimen/favicon_bg"
android:layout_marginLeft="6dip"
android:layout_marginRight="6dip"
android:layout_centerVertical="true"
android:minWidth="@dimen/favicon_bg"
android:minHeight="@dimen/favicon_bg"/>
<org.mozilla.gecko.FlowLayout android:id="@+id/suggestion_layout"
android:layout_toRightOf="@id/suggestion_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<include layout="@layout/awesomebar_suggestion_item"
android:id="@+id/suggestion_user_entered"/>
</org.mozilla.gecko.FlowLayout>
</org.mozilla.gecko.AnimatedHeightLayout>

View File

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<Gecko.TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:gecko="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_weight="1.0"
android:gravity="center"
android:background="@drawable/awesomebar_tab_indicator"
android:padding="10dp"
android:singleLine="true"
android:ellipsize="marquee"
android:textSize="14sp"
android:textColor="@color/url_bar_title"
gecko:autoUpdateTheme="false"/>

View File

@ -1,51 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<org.mozilla.gecko.AwesomeBarTabs xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/awesomebar_tabs"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:focusable="true"
android:focusableInTouchMode="true">
<LinearLayout android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<view class="org.mozilla.gecko.AwesomeBarTabs$BackgroundLayout"
android:id="@+id/tab_widget_container"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/url_bar_bg"
android:focusable="false"
android:descendantFocusability="blocksDescendants">
<View android:id="@+id/tab_widget_left"
style="@style/AwesomeBarTabIndicatorCurve.Left"/>
<TabWidget android:id="@android:id/tabs"
style="@style/TabWidget"/>
<View android:id="@+id/tab_widget_right"
style="@style/AwesomeBarTabIndicatorCurve.Right"/>
</view>
<FrameLayout android:id="@android:id/tabcontent"
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<android.support.v4.view.ViewPager
android:id="@+id/tabviewpager"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#EEF1F5"
android:paddingLeft="@dimen/awesomebar_list_padding"
android:paddingRight="@dimen/awesomebar_list_padding"/>
</LinearLayout>
</org.mozilla.gecko.AwesomeBarTabs>

View File

@ -39,22 +39,8 @@
<item name="android:ellipsize">marquee</item>
</style>
<!-- AwesomeBar -->
<style name="AwesomeBar">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">@dimen/browser_toolbar_height</item>
<item name="android:orientation">horizontal</item>
</style>
<!-- ActionBar -->
<style name="ActionBar" parent="android:style/Widget.Holo.ActionBar" />
<!-- AwesomeBar ActionBar -->
<style name="ActionBar.AwesomeBar">
<item name="android:displayOptions">showCustom</item>
<item name="android:customNavigationLayout">@layout/awesomebar_actionbar</item>
<item name="android:visibility">gone</item>
</style>
<!-- GeckoPreferences ActionBar -->
<style name="ActionBar.GeckoPreferences">

View File

@ -22,13 +22,6 @@
<item name="android:windowNoTitle">true</item>
</style>
<style name="GeckoAwesomeBarBase" parent="GeckoBase">
<item name="android:windowBackground">@color/background_normal</item>
<item name="android:windowActionBar">true</item>
<item name="android:windowNoTitle">false</item>
<item name="android:actionBarStyle">@style/ActionBar.AwesomeBar</item>
</style>
<style name="GeckoPreferencesBase" parent="GeckoBase">
<item name="android:windowActionBar">true</item>
<item name="android:windowNoTitle">false</item>

View File

@ -8,13 +8,6 @@
<dimen name="abouthome_gutter_small">20dp</dimen>
<dimen name="abouthome_gutter_large">40dp</dimen>
<dimen name="abouthome_icon_crop">0dp</dimen>
<dimen name="awesomebar_header_row_height">24dp</dimen>
<!-- Padding on either side of the lists in AwesomeBar -->
<dimen name="awesomebar_list_padding">52dp</dimen>
<dimen name="awesomebar_row_height">66dp</dimen>
<dimen name="awesomebar_tab_transparency_height">46dp</dimen>
<dimen name="browser_toolbar_height">56dp</dimen>
<dimen name="remote_tab_child_row_height">56dp</dimen>
<dimen name="remote_tab_group_row_height">34dp</dimen>

View File

@ -10,16 +10,6 @@
Please refer to values/styles.xml for default styles.
-->
<!-- AwesomeBar Tab Indicator Curve Left -->
<style name="AwesomeBarTabIndicatorCurve.Left">
<item name="android:layout_width">86dp</item>
</style>
<!-- AwesomeBar Tab Indicator Curve Right -->
<style name="AwesomeBarTabIndicatorCurve.Right">
<item name="android:layout_width">fill_parent</item>
</style>
<!-- TabWidget -->
<style name="TabWidget">
<item name="android:layout_width">300dip</item>

View File

@ -4,8 +4,6 @@
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<resources>
<color name="awesomebar_header_row">#FFD2DAE2</color>
<color name="awesomebar_header_row_focused">#FFA2AAB2</color>
<color name="background_normal">#FFCED7DE</color>
<color name="background_private">#FF292C29</color>
<color name="background_tabs">#FF363B40</color>

View File

@ -18,12 +18,6 @@
<dimen name="autocomplete_min_width">200dp</dimen>
<dimen name="autocomplete_row_height">32dp</dimen>
<!-- Padding on either side of the lists in AwesomeBar -->
<dimen name="awesomebar_list_padding">0dp</dimen>
<dimen name="awesomebar_header_row_height">20dp</dimen>
<dimen name="awesomebar_row_height">48dp</dimen>
<dimen name="awesomebar_tab_transparency_height">38dp</dimen>
<dimen name="browser_toolbar_height">48dp</dimen>
<dimen name="browser_toolbar_button_padding">12dp</dimen>
<dimen name="browser_toolbar_icon_width">48dp</dimen>

View File

@ -49,10 +49,6 @@
<style name="Widget.ExpandableListView" parent="Widget.ListView">
<item name="android:groupIndicator">@android:color/transparent</item>
<!-- Using a color for the childDivider is broken for Froyo and GB
phones (see bug 862761), so we use a drawable instead. -->
<item name="android:childDivider">@drawable/awesomebar_listview_divider</item>
</style>
<style name="Widget.ListItem">
@ -249,31 +245,6 @@
<item name="android:layout_weight">0.0</item>
</style>
<!-- AwesomeBar -->
<style name="AwesomeBar">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">48dip</item>
<item name="android:orientation">horizontal</item>
</style>
<!-- AwesomeBar Tab Indicator Curve -->
<style name="AwesomeBarTabIndicatorCurve">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">fill_parent</item>
<item name="android:background">@drawable/awesomebar_tab_unselected</item>
</style>
<!-- AwesomeBar Tab Indicator Curve Left -->
<style name="AwesomeBarTabIndicatorCurve.Left">
<item name="android:layout_width">20dp</item>
</style>
<!-- AwesomeBar Tab Indicator Curve Right -->
<style name="AwesomeBarTabIndicatorCurve.Right">
<item name="android:layout_width">20dp</item>
</style>
<!-- TabsTray List -->
<style name="TabsListBase">
<item name="android:background">@android:color/transparent</item>

View File

@ -20,12 +20,6 @@
<item name="android:windowContentOverlay">@null</item>
</style>
<style name="GeckoAwesomeBarBase" parent="GeckoBase">
<item name="android:windowNoTitle">true</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowBackground">@null</item>
</style>
<style name="GeckoPreferencesBase" parent="GeckoBase">
<item name="android:windowNoTitle">false</item>
</style>
@ -85,11 +79,6 @@
<item name="android:spinnerItemStyle">@style/Widget.TextView.SpinnerItem</item>
</style>
<style name="Gecko.AwesomeBar" parent="GeckoAwesomeBarBase">
<item name="android:listViewStyle">@style/Widget.ListView</item>
<item name="android:expandableListViewStyle">@style/Widget.ExpandableListView</item>
</style>
<style name="Gecko.Preferences" parent="GeckoPreferencesBase"/>
</resources>

View File

@ -5,7 +5,6 @@
package org.mozilla.gecko.widget;
import org.mozilla.gecko.AwesomeBar;
import org.mozilla.gecko.BrowserApp;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.R;
@ -602,77 +601,6 @@ public class TopSitesView extends GridView {
// Edit the site at position. Provide a url to start editing with
public void editSite(String url, final int position) {
Intent intent = new Intent(mContext, AwesomeBar.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
intent.putExtra(AwesomeBar.TARGET_KEY, AwesomeBar.Target.PICK_SITE.toString());
if (url != null && !TextUtils.isEmpty(url)) {
intent.putExtra(AwesomeBar.CURRENT_URL_KEY, url);
}
int requestCode = GeckoAppShell.sActivityHelper.makeRequestCode(new ActivityResultHandler() {
@Override
public void onActivityResult(int resultCode, Intent data) {
if (resultCode == Activity.RESULT_CANCELED || data == null)
return;
final View v = getChildAt(position);
final TopSitesViewHolder holder = (TopSitesViewHolder) v.getTag();
String title = data.getStringExtra(AwesomeBar.TITLE_KEY);
String url = data.getStringExtra(AwesomeBar.URL_KEY);
// Bail if the user entered an empty string.
if (TextUtils.isEmpty(url)) {
return;
}
// If the user manually entered a search term or URL, wrap the value in
// a special URI until we can get a valid URL for this bookmark.
if (data.getBooleanExtra(AwesomeBar.USER_ENTERED_KEY, false)) {
// Store what the user typed as the bookmark's title.
title = url;
url = encodeUserEnteredUrl(url);
}
clearThumbnailsWithUrl(url);
holder.setUrl(url);
holder.setTitle(title);
holder.setPinned(true);
// update the database on a background thread
(new UiAsyncTask<Void, Void, Bitmap>(ThreadUtils.getBackgroundHandler()) {
@Override
public Bitmap doInBackground(Void... params) {
final ContentResolver resolver = mContext.getContentResolver();
BrowserDB.pinSite(resolver, holder.getUrl(), holder.getTitle(), position);
List<String> urls = new ArrayList<String>();
urls.add(holder.getUrl());
Cursor c = BrowserDB.getThumbnailsForUrls(resolver, urls);
if (c == null || !c.moveToFirst()) {
return null;
}
final byte[] b = c.getBlob(c.getColumnIndexOrThrow(Thumbnails.DATA));
Bitmap bitmap = null;
if (b != null && b.length > 0) {
bitmap = BitmapUtils.decodeByteArray(b);
}
c.close();
return bitmap;
}
@Override
public void onPostExecute(Bitmap b) {
displayThumbnail(v, b);
}
}).execute();
}
});
mActivity.startActivityForResult(intent, requestCode);
}
}