mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-31 14:15:30 +00:00
Bug 876712 - Kill AweseomeBar/AwesomeBarTabs. r=sriram,wesj
This commit is contained in:
parent
14cdb91bd3
commit
9f79c4d6f0
@ -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);
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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 \
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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"/>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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"/>
|
@ -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>
|
@ -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">
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user