mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 877870 - Initial implementation of new browser search fragment (r=bnicholson)
This commit is contained in:
parent
6c792631d5
commit
0b49d16137
@ -74,6 +74,7 @@ abstract public class BrowserApp extends GeckoApp
|
||||
PropertyAnimator.PropertyAnimationListener,
|
||||
View.OnKeyListener,
|
||||
GeckoLayerClient.OnMetricsChangedListener,
|
||||
BrowserSearch.OnUrlOpenListener,
|
||||
HomePager.OnUrlOpenListener {
|
||||
private static final String LOGTAG = "GeckoBrowserApp";
|
||||
|
||||
@ -89,6 +90,10 @@ abstract public class BrowserApp extends GeckoApp
|
||||
|
||||
private static final String STATE_DYNAMIC_TOOLBAR_ENABLED = "dynamic_toolbar";
|
||||
|
||||
private static final String BROWSER_SEARCH_TAG = "browser_search";
|
||||
private BrowserSearch mBrowserSearch;
|
||||
private View mBrowserSearchContainer;
|
||||
|
||||
public static BrowserToolbar mBrowserToolbar;
|
||||
private HomePager mHomePager;
|
||||
protected Telemetry.Timer mAboutHomeStartupTimer = null;
|
||||
@ -381,6 +386,13 @@ abstract public class BrowserApp extends GeckoApp
|
||||
|
||||
mHomePager = (HomePager) findViewById(R.id.home_pager);
|
||||
|
||||
mBrowserSearchContainer = findViewById(R.id.search_container);
|
||||
mBrowserSearch = (BrowserSearch) getSupportFragmentManager().findFragmentByTag(BROWSER_SEARCH_TAG);
|
||||
if (mBrowserSearch == null) {
|
||||
mBrowserSearch = BrowserSearch.newInstance();
|
||||
mBrowserSearch.setUserVisibleHint(false);
|
||||
}
|
||||
|
||||
mBrowserToolbar = new BrowserToolbar(this);
|
||||
mBrowserToolbar.from(actionBar);
|
||||
|
||||
@ -1125,6 +1137,8 @@ abstract public class BrowserApp extends GeckoApp
|
||||
}
|
||||
|
||||
Tabs.getInstance().loadUrl(url, flags);
|
||||
|
||||
hideBrowserSearch();
|
||||
mBrowserToolbar.cancelEdit();
|
||||
}
|
||||
|
||||
@ -1207,6 +1221,7 @@ abstract public class BrowserApp extends GeckoApp
|
||||
|
||||
final String url = mBrowserToolbar.commitEdit();
|
||||
animateHideHomePager();
|
||||
hideBrowserSearch();
|
||||
|
||||
int flags = Tabs.LOADURL_USER_ENTERED;
|
||||
if (target == EditingTarget.NEW_TAB) {
|
||||
@ -1225,12 +1240,18 @@ abstract public class BrowserApp extends GeckoApp
|
||||
|
||||
mBrowserToolbar.cancelEdit();
|
||||
animateHideHomePager();
|
||||
hideBrowserSearch();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void filterEditingMode(String searchTerm, AutocompleteHandler handler) {
|
||||
// FIXME: implement actual awesomebar search
|
||||
if (TextUtils.isEmpty(searchTerm)) {
|
||||
hideBrowserSearch();
|
||||
} else {
|
||||
showBrowserSearch();
|
||||
mBrowserSearch.filter(searchTerm);
|
||||
}
|
||||
}
|
||||
|
||||
private void animateShowHomePager() {
|
||||
@ -1289,6 +1310,30 @@ abstract public class BrowserApp extends GeckoApp
|
||||
refreshToolbarHeight();
|
||||
}
|
||||
|
||||
private void showBrowserSearch() {
|
||||
if (mBrowserSearch.getUserVisibleHint()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mBrowserSearchContainer.setVisibility(View.VISIBLE);
|
||||
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.add(R.id.search_container, mBrowserSearch, BROWSER_SEARCH_TAG).commitAllowingStateLoss();
|
||||
mBrowserSearch.setUserVisibleHint(true);
|
||||
}
|
||||
|
||||
private void hideBrowserSearch() {
|
||||
if (!mBrowserSearch.getUserVisibleHint()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mBrowserSearchContainer.setVisibility(View.INVISIBLE);
|
||||
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.remove(mBrowserSearch).commitAllowingStateLoss();
|
||||
mBrowserSearch.setUserVisibleHint(false);
|
||||
}
|
||||
|
||||
private class HideTabsTouchListener implements TouchEventInterceptor {
|
||||
private boolean mIsHidingTabs = false;
|
||||
|
||||
@ -1773,7 +1818,7 @@ abstract public class BrowserApp extends GeckoApp
|
||||
}).execute();
|
||||
}
|
||||
|
||||
// HomePager.OnUrlOpenListener
|
||||
// (HomePager|BrowserSearch).OnUrlOpenListener
|
||||
@Override
|
||||
public void onUrlOpen(String url) {
|
||||
openUrl(url);
|
||||
|
202
mobile/android/base/BrowserSearch.java
Normal file
202
mobile/android/base/BrowserSearch.java
Normal file
@ -0,0 +1,202 @@
|
||||
/* -*- 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.BrowserDB;
|
||||
import org.mozilla.gecko.db.BrowserDB.URLColumns;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
import org.mozilla.gecko.home.TwoLinePageRow;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.os.Bundle;
|
||||
import android.content.res.Configuration;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.app.LoaderManager.LoaderCallbacks;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.LayoutInflater;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.SimpleCursorAdapter;
|
||||
|
||||
/**
|
||||
* Fragment that displays frecency search results in a ListView.
|
||||
*/
|
||||
public class BrowserSearch extends Fragment implements LoaderCallbacks<Cursor>,
|
||||
AdapterView.OnItemClickListener {
|
||||
// Cursor loader ID for search query
|
||||
private static final int SEARCH_LOADER_ID = 0;
|
||||
|
||||
// Holds the current search term to use in the query
|
||||
private String mSearchTerm;
|
||||
|
||||
// Adapter for the list of search results
|
||||
private SearchAdapter mAdapter;
|
||||
|
||||
// The view shown by the fragment.
|
||||
private ListView mList;
|
||||
|
||||
// On URL open listener
|
||||
private OnUrlOpenListener mUrlOpenListener;
|
||||
|
||||
public interface OnUrlOpenListener {
|
||||
public void onUrlOpen(String url);
|
||||
}
|
||||
|
||||
public static BrowserSearch newInstance() {
|
||||
return new BrowserSearch();
|
||||
}
|
||||
|
||||
public BrowserSearch() {
|
||||
mSearchTerm = "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity) {
|
||||
super.onAttach(activity);
|
||||
|
||||
try {
|
||||
mUrlOpenListener = (OnUrlOpenListener) activity;
|
||||
} catch (ClassCastException e) {
|
||||
throw new ClassCastException(activity.toString()
|
||||
+ " must implement BrowserSearch.OnUrlOpenListener");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach() {
|
||||
super.onDetach();
|
||||
|
||||
mUrlOpenListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
// All list views are styled to look the same with a global activity theme.
|
||||
// If the style of the list changes, inflate it from an XML.
|
||||
mList = new ListView(container.getContext());
|
||||
return mList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
mList.setOnItemClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
|
||||
// Intialize the search adapter
|
||||
mAdapter = new SearchAdapter(getActivity());
|
||||
mList.setAdapter(mAdapter);
|
||||
|
||||
// Reconnect to the loader only if present
|
||||
getLoaderManager().initLoader(SEARCH_LOADER_ID, null, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
||||
return new SearchCursorLoader(getActivity(), mSearchTerm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(Loader<Cursor> loader, Cursor c) {
|
||||
mAdapter.swapCursor(c);
|
||||
|
||||
// FIXME: do extra UI bits here
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(Loader<Cursor> loader) {
|
||||
mAdapter.swapCursor(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
final Cursor c = mAdapter.getCursor();
|
||||
if (c == null || !c.moveToPosition(position)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final String url = c.getString(c.getColumnIndexOrThrow(URLColumns.URL));
|
||||
mUrlOpenListener.onUrlOpen(url);
|
||||
}
|
||||
|
||||
public void filter(String searchTerm) {
|
||||
if (TextUtils.isEmpty(searchTerm)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (TextUtils.equals(mSearchTerm, searchTerm)) {
|
||||
return;
|
||||
}
|
||||
|
||||
mSearchTerm = searchTerm;
|
||||
|
||||
if (isVisible()) {
|
||||
getLoaderManager().restartLoader(SEARCH_LOADER_ID, null, this);
|
||||
}
|
||||
}
|
||||
|
||||
private static class SearchCursorLoader extends SimpleCursorLoader {
|
||||
// Max number of search results
|
||||
private static final int SEARCH_LIMIT = 100;
|
||||
|
||||
// The target search term associated with the loader
|
||||
private final String mSearchTerm;
|
||||
|
||||
public SearchCursorLoader(Context context, String searchTerm) {
|
||||
super(context);
|
||||
mSearchTerm = searchTerm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor loadCursor() {
|
||||
if (TextUtils.isEmpty(mSearchTerm)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final ContentResolver cr = getContext().getContentResolver();
|
||||
return BrowserDB.filter(cr, mSearchTerm, SEARCH_LIMIT);
|
||||
}
|
||||
}
|
||||
|
||||
private class SearchAdapter extends SimpleCursorAdapter {
|
||||
public SearchAdapter(Context context) {
|
||||
super(context, -1, null, new String[] {}, new int[] {});
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
final TwoLinePageRow row;
|
||||
if (convertView == null) {
|
||||
row = (TwoLinePageRow) LayoutInflater.from(getActivity()).inflate(R.layout.home_item_row, null);
|
||||
} else {
|
||||
row = (TwoLinePageRow) convertView;
|
||||
}
|
||||
|
||||
final Cursor c = getCursor();
|
||||
if (!c.moveToPosition(position)) {
|
||||
throw new IllegalStateException("Couldn't move cursor to position " + position);
|
||||
}
|
||||
|
||||
row.updateFromCursor(c);
|
||||
|
||||
// FIXME: show bookmark icon
|
||||
|
||||
return row;
|
||||
}
|
||||
}
|
||||
}
|
@ -66,6 +66,7 @@ FENNEC_JAVA_FILES = \
|
||||
awesomebar/HistoryTab.java \
|
||||
BackButton.java \
|
||||
BrowserApp.java \
|
||||
BrowserSearch.java \
|
||||
BrowserToolbar.java \
|
||||
BrowserToolbarBackground.java \
|
||||
BrowserToolbarLayout.java \
|
||||
@ -148,6 +149,7 @@ FENNEC_JAVA_FILES = \
|
||||
SetupScreen.java \
|
||||
ShapedButton.java \
|
||||
SharedPreferencesHelper.java \
|
||||
SimpleCursorLoader.java \
|
||||
SiteIdentityPopup.java \
|
||||
SmsManager.java \
|
||||
SuggestClient.java \
|
||||
|
131
mobile/android/base/SimpleCursorLoader.java
Normal file
131
mobile/android/base/SimpleCursorLoader.java
Normal file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* This is an adapted version of Android's original CursorLoader
|
||||
* without all the ContentProvider-specific bits.
|
||||
*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mozilla.gecko;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.ContentObserver;
|
||||
import android.database.Cursor;
|
||||
import android.support.v4.content.AsyncTaskLoader;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Arrays;
|
||||
|
||||
public abstract class SimpleCursorLoader extends AsyncTaskLoader<Cursor> {
|
||||
final ForceLoadContentObserver mObserver;
|
||||
Cursor mCursor;
|
||||
|
||||
public SimpleCursorLoader(Context context) {
|
||||
super(context);
|
||||
mObserver = new ForceLoadContentObserver();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the target cursor for this loader. This method is called
|
||||
* on a worker thread.
|
||||
*/
|
||||
protected abstract Cursor loadCursor();
|
||||
|
||||
/* Runs on a worker thread */
|
||||
@Override
|
||||
public Cursor loadInBackground() {
|
||||
Cursor cursor = loadCursor();
|
||||
|
||||
if (cursor != null) {
|
||||
// Ensure the cursor window is filled
|
||||
cursor.getCount();
|
||||
cursor.registerContentObserver(mObserver);
|
||||
}
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
/* Runs on the UI thread */
|
||||
@Override
|
||||
public void deliverResult(Cursor cursor) {
|
||||
if (isReset()) {
|
||||
// An async query came in while the loader is stopped
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Cursor oldCursor = mCursor;
|
||||
mCursor = cursor;
|
||||
|
||||
if (isStarted()) {
|
||||
super.deliverResult(cursor);
|
||||
}
|
||||
|
||||
if (oldCursor != null && oldCursor != cursor && !oldCursor.isClosed()) {
|
||||
oldCursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts an asynchronous load of the list data. When the result is ready the callbacks
|
||||
* will be called on the UI thread. If a previous load has been completed and is still valid
|
||||
* the result may be passed to the callbacks immediately.
|
||||
*
|
||||
* Must be called from the UI thread
|
||||
*/
|
||||
@Override
|
||||
protected void onStartLoading() {
|
||||
if (mCursor != null) {
|
||||
deliverResult(mCursor);
|
||||
}
|
||||
|
||||
if (takeContentChanged() || mCursor == null) {
|
||||
forceLoad();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Must be called from the UI thread
|
||||
*/
|
||||
@Override
|
||||
protected void onStopLoading() {
|
||||
// Attempt to cancel the current load task if possible.
|
||||
cancelLoad();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCanceled(Cursor cursor) {
|
||||
if (cursor != null && !cursor.isClosed()) {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onReset() {
|
||||
super.onReset();
|
||||
|
||||
// Ensure the loader is stopped
|
||||
onStopLoading();
|
||||
|
||||
if (mCursor != null && !mCursor.isClosed()) {
|
||||
mCursor.close();
|
||||
}
|
||||
|
||||
mCursor = null;
|
||||
}
|
||||
}
|
@ -1,9 +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.home.TwoLinePageRow xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="@dimen/page_row_height"
|
||||
android:minHeight="@dimen/page_row_height"/>
|
@ -55,6 +55,14 @@
|
||||
<include layout="@layout/browser_toolbar"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="@dimen/browser_toolbar_height"/>
|
||||
|
||||
<FrameLayout android:id="@+id/search_container"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_below="@id/browser_toolbar"
|
||||
android:background="@android:color/white"
|
||||
android:visibility="invisible"/>
|
||||
|
||||
</view>
|
||||
|
||||
</RelativeLayout>
|
||||
|
Loading…
Reference in New Issue
Block a user