diff --git a/F-Droid/AndroidManifest.xml b/F-Droid/AndroidManifest.xml
index 6deda93e0..0f1036114 100644
--- a/F-Droid/AndroidManifest.xml
+++ b/F-Droid/AndroidManifest.xml
@@ -100,7 +100,7 @@
+ android:value=".FDroid" />
+
+
+
+
+
+
@@ -388,25 +396,6 @@
-
-
-
-
-
-
-
-
-
diff --git a/F-Droid/res/layout/available_app_list.xml b/F-Droid/res/layout/available_app_list.xml
index 1ff394163..e1b35d157 100644
--- a/F-Droid/res/layout/available_app_list.xml
+++ b/F-Droid/res/layout/available_app_list.xml
@@ -4,27 +4,35 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
-
+ android:layout_height="wrap_content"
+ android:id="@+id/category_wrapper"
+ android:layout_alignParentTop="true">
-
+
+
+
+
+
+ android:layout_below="@id/category_wrapper" />
diff --git a/F-Droid/src/org/fdroid/fdroid/FDroid.java b/F-Droid/src/org/fdroid/fdroid/FDroid.java
index d5eda5c4b..4a41f1b4b 100644
--- a/F-Droid/src/org/fdroid/fdroid/FDroid.java
+++ b/F-Droid/src/org/fdroid/fdroid/FDroid.java
@@ -29,10 +29,12 @@ import android.content.res.Configuration;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.support.v4.view.MenuItemCompat;
import android.support.v4.view.ViewPager;
-import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.AlertDialog;
+import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.SearchView;
import android.text.TextUtils;
import android.view.LayoutInflater;
@@ -43,6 +45,7 @@ import android.widget.TextView;
import android.widget.Toast;
import org.fdroid.fdroid.compat.TabManager;
+import org.fdroid.fdroid.compat.UriCompat;
import org.fdroid.fdroid.data.AppProvider;
import org.fdroid.fdroid.data.NewRepoConfig;
import org.fdroid.fdroid.privileged.install.InstallExtensionDialogActivity;
@@ -50,7 +53,7 @@ import org.fdroid.fdroid.views.AppListFragmentPagerAdapter;
import org.fdroid.fdroid.views.ManageReposActivity;
import org.fdroid.fdroid.views.swap.SwapWorkflowActivity;
-public class FDroid extends ActionBarActivity {
+public class FDroid extends AppCompatActivity implements SearchView.OnQueryTextListener {
private static final String TAG = "FDroid";
@@ -66,8 +69,17 @@ public class FDroid extends ActionBarActivity {
private ViewPager viewPager;
+ @Nullable
private TabManager tabManager;
+ private AppListFragmentPagerAdapter adapter;
+
+ @Nullable
+ private MenuItem searchMenuItem;
+
+ @Nullable
+ private String pendingSearchQuery;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -84,10 +96,7 @@ public class FDroid extends ActionBarActivity {
setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
Intent intent = getIntent();
-
- // If the intent can be handled via AppDetails or SearchResults, it
- // will call finish() and the rest of the code won't execute
- handleIntent(intent);
+ handleSearchOrAppViewIntent(intent);
if (intent.hasExtra(EXTRA_TAB_UPDATE)) {
boolean showUpdateTab = intent.getBooleanExtra(EXTRA_TAB_UPDATE, false);
@@ -109,6 +118,18 @@ public class FDroid extends ActionBarActivity {
// }
}
+ private void performSearch(String query) {
+ if (searchMenuItem == null) {
+ // Store this for later when we do actually have a search menu ready to use.
+ pendingSearchQuery = query;
+ return;
+ }
+
+ SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchMenuItem);
+ MenuItemCompat.expandActionView(searchMenuItem);
+ searchView.setQuery(query, true);
+ }
+
@Override
protected void onResume() {
super.onResume();
@@ -117,11 +138,24 @@ public class FDroid extends ActionBarActivity {
checkForAddRepoIntent();
}
- private void handleIntent(Intent intent) {
+ @Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ handleSearchOrAppViewIntent(intent);
+ }
+
+ private void handleSearchOrAppViewIntent(Intent intent) {
+ if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
+ String query = intent.getStringExtra(SearchManager.QUERY);
+ performSearch(query);
+ return;
+ }
+
final Uri data = intent.getData();
if (data == null) {
return;
}
+
final String scheme = data.getScheme();
final String path = data.getPath();
String appId = null;
@@ -133,11 +167,14 @@ public class FDroid extends ActionBarActivity {
}
switch (host) {
case "f-droid.org":
- // http://f-droid.org/app/app.id
if (path.startsWith("/repository/browse")) {
+ // http://f-droid.org/repository/browse?fdfilter=search+query
+ query = UriCompat.getQueryParameter(data, "fdfilter");
+
// http://f-droid.org/repository/browse?fdid=app.id
- appId = data.getQueryParameter("fdid");
+ appId = UriCompat.getQueryParameter(data, "fdid");
} else if (path.startsWith("/app")) {
+ // http://f-droid.org/app/app.id
appId = data.getLastPathSegment();
if ("app".equals(appId)) {
appId = null;
@@ -146,28 +183,28 @@ public class FDroid extends ActionBarActivity {
break;
case "details":
// market://details?id=app.id
- appId = data.getQueryParameter("id");
+ appId = UriCompat.getQueryParameter(data, "id");
break;
case "search":
// market://search?q=query
- query = data.getQueryParameter("q");
+ query = UriCompat.getQueryParameter(data, "q");
break;
case "play.google.com":
if (path.startsWith("/store/apps/details")) {
// http://play.google.com/store/apps/details?id=app.id
- appId = data.getQueryParameter("id");
+ appId = UriCompat.getQueryParameter(data, "id");
} else if (path.startsWith("/store/search")) {
// http://play.google.com/store/search?q=foo
- query = data.getQueryParameter("q");
+ query = UriCompat.getQueryParameter(data, "q");
}
break;
case "apps":
case "amazon.com":
case "www.amazon.com":
// amzn://apps/android?p=app.id
- // http://amazon.com/gp/mas/dl/android?p=app.id
- appId = data.getQueryParameter("p");
- query = data.getQueryParameter("s");
+ // http://amazon.com/gp/mas/dl/android?s=app.id
+ appId = UriCompat.getQueryParameter(data, "p");
+ query = UriCompat.getQueryParameter(data, "s");
break;
}
} else if ("fdroid.app".equals(scheme)) {
@@ -188,20 +225,14 @@ public class FDroid extends ActionBarActivity {
query = query.split(":")[1];
}
- Intent call = null;
if (!TextUtils.isEmpty(appId)) {
Utils.debugLog(TAG, "FDroid launched via app link for '" + appId + "'");
- call = new Intent(this, AppDetails.class);
- call.putExtra(AppDetails.EXTRA_APPID, appId);
+ Intent intentToInvoke = new Intent(this, AppDetails.class);
+ intentToInvoke.putExtra(AppDetails.EXTRA_APPID, appId);
+ startActivity(intentToInvoke);
} else if (!TextUtils.isEmpty(query)) {
Utils.debugLog(TAG, "FDroid launched via search link for '" + query + "'");
- call = new Intent(this, SearchResults.class);
- call.setAction(Intent.ACTION_SEARCH);
- call.putExtra(SearchManager.QUERY, query);
- }
- if (call != null) {
- startActivity(call);
- finish();
+ performSearch(query);
}
}
@@ -243,11 +274,19 @@ public class FDroid extends ActionBarActivity {
}
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
- MenuItem searchItem = menu.findItem(R.id.action_search);
- SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
+ searchMenuItem = menu.findItem(R.id.action_search);
+ SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchMenuItem);
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
// LayoutParams.MATCH_PARENT does not work, use a big value instead
searchView.setMaxWidth(1000000);
+ searchView.setOnQueryTextListener(this);
+
+ // If we were asked to execute a search before getting around to building the options
+ // menu, then we should deal with that now that the options menu is all sorted out.
+ if (pendingSearchQuery != null) {
+ performSearch(pendingSearchQuery);
+ pendingSearchQuery = null;
+ }
return super.onCreateOptionsMenu(menu);
}
@@ -335,8 +374,8 @@ public class FDroid extends ActionBarActivity {
private void createViews() {
viewPager = (ViewPager) findViewById(R.id.main_pager);
- AppListFragmentPagerAdapter viewPagerAdapter = new AppListFragmentPagerAdapter(this);
- viewPager.setAdapter(viewPagerAdapter);
+ adapter = new AppListFragmentPagerAdapter(this);
+ viewPager.setAdapter(adapter);
viewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
@@ -345,6 +384,7 @@ public class FDroid extends ActionBarActivity {
});
}
+ @NonNull
private TabManager getTabManager() {
if (tabManager == null) {
tabManager = new TabManager(this, viewPager);
@@ -363,6 +403,19 @@ public class FDroid extends ActionBarActivity {
nMgr.cancel(id);
}
+ @Override
+ public boolean onQueryTextSubmit(String query) {
+ // Do nothing, because we respond to the query being changed as it is updated
+ // via onQueryTextChange(...)
+ return true;
+ }
+
+ @Override
+ public boolean onQueryTextChange(String newText) {
+ adapter.updateSearchQuery(newText);
+ return true;
+ }
+
private class AppObserver extends ContentObserver {
AppObserver() {
diff --git a/F-Droid/src/org/fdroid/fdroid/compat/UriCompat.java b/F-Droid/src/org/fdroid/fdroid/compat/UriCompat.java
new file mode 100644
index 000000000..90ffff0ca
--- /dev/null
+++ b/F-Droid/src/org/fdroid/fdroid/compat/UriCompat.java
@@ -0,0 +1,21 @@
+package org.fdroid.fdroid.compat;
+
+import android.net.Uri;
+import android.os.Build;
+
+public class UriCompat {
+
+ /**
+ * Uri#getQueryParameter(String) has the following warning:
+ *
+ * > Prior to Ice Cream Sandwich, this decoded the '+' character as '+' rather than ' '.
+ */
+ public static String getQueryParameter(Uri uri, String key) {
+ String value = uri.getQueryParameter(key);
+ if (value != null && Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ value = value.replaceAll("\\+", " ");
+ }
+ return value;
+ }
+
+}
diff --git a/F-Droid/src/org/fdroid/fdroid/data/AppProvider.java b/F-Droid/src/org/fdroid/fdroid/data/AppProvider.java
index 79019be56..e30fcfb61 100644
--- a/F-Droid/src/org/fdroid/fdroid/data/AppProvider.java
+++ b/F-Droid/src/org/fdroid/fdroid/data/AppProvider.java
@@ -425,6 +425,8 @@ public class AppProvider extends FDroidProvider {
private static final String PATH_INSTALLED = "installed";
private static final String PATH_CAN_UPDATE = "canUpdate";
private static final String PATH_SEARCH = "search";
+ private static final String PATH_SEARCH_INSTALLED = "searchInstalled";
+ private static final String PATH_SEARCH_CAN_UPDATE = "searchCanUpdate";
private static final String PATH_SEARCH_REPO = "searchRepo";
private static final String PATH_NO_APKS = "noApks";
private static final String PATH_APPS = "apps";
@@ -435,18 +437,20 @@ public class AppProvider extends FDroidProvider {
private static final String PATH_CALC_APP_DETAILS_FROM_INDEX = "calcDetailsFromIndex";
private static final String PATH_REPO = "repo";
- private static final int CAN_UPDATE = CODE_SINGLE + 1;
- private static final int INSTALLED = CAN_UPDATE + 1;
- private static final int SEARCH = INSTALLED + 1;
- private static final int NO_APKS = SEARCH + 1;
- private static final int APPS = NO_APKS + 1;
+ private static final int CAN_UPDATE = CODE_SINGLE + 1;
+ private static final int INSTALLED = CAN_UPDATE + 1;
+ private static final int SEARCH = INSTALLED + 1;
+ private static final int NO_APKS = SEARCH + 1;
+ private static final int APPS = NO_APKS + 1;
private static final int RECENTLY_UPDATED = APPS + 1;
- private static final int NEWLY_ADDED = RECENTLY_UPDATED + 1;
- private static final int CATEGORY = NEWLY_ADDED + 1;
- private static final int IGNORED = CATEGORY + 1;
+ private static final int NEWLY_ADDED = RECENTLY_UPDATED + 1;
+ private static final int CATEGORY = NEWLY_ADDED + 1;
+ private static final int IGNORED = CATEGORY + 1;
private static final int CALC_APP_DETAILS_FROM_INDEX = IGNORED + 1;
- private static final int REPO = CALC_APP_DETAILS_FROM_INDEX + 1;
- private static final int SEARCH_REPO = REPO + 1;
+ private static final int REPO = CALC_APP_DETAILS_FROM_INDEX + 1;
+ private static final int SEARCH_REPO = REPO + 1;
+ private static final int SEARCH_INSTALLED = SEARCH_REPO + 1;
+ private static final int SEARCH_CAN_UPDATE = SEARCH_INSTALLED + 1;
static {
matcher.addURI(getAuthority(), null, CODE_LIST);
@@ -456,6 +460,8 @@ public class AppProvider extends FDroidProvider {
matcher.addURI(getAuthority(), PATH_NEWLY_ADDED, NEWLY_ADDED);
matcher.addURI(getAuthority(), PATH_CATEGORY + "/*", CATEGORY);
matcher.addURI(getAuthority(), PATH_SEARCH + "/*", SEARCH);
+ matcher.addURI(getAuthority(), PATH_SEARCH_INSTALLED + "/*", SEARCH_INSTALLED);
+ matcher.addURI(getAuthority(), PATH_SEARCH_CAN_UPDATE + "/*", SEARCH_CAN_UPDATE);
matcher.addURI(getAuthority(), PATH_SEARCH_REPO + "/*/*", SEARCH_REPO);
matcher.addURI(getAuthority(), PATH_REPO + "/#", REPO);
matcher.addURI(getAuthority(), PATH_CAN_UPDATE, CAN_UPDATE);
@@ -536,7 +542,23 @@ public class AppProvider extends FDroidProvider {
public static Uri getSearchUri(String query) {
return getContentUri().buildUpon()
.appendPath(PATH_SEARCH)
- .appendPath(query)
+ .appendEncodedPath(query)
+ .build();
+ }
+
+ public static Uri getSearchInstalledUri(String query) {
+ return getContentUri()
+ .buildUpon()
+ .appendPath(PATH_SEARCH_INSTALLED)
+ .appendEncodedPath(query)
+ .build();
+ }
+
+ public static Uri getSearchCanUpdateUri(String query) {
+ return getContentUri()
+ .buildUpon()
+ .appendPath(PATH_SEARCH_CAN_UPDATE)
+ .appendEncodedPath(query)
.build();
}
@@ -544,7 +566,7 @@ public class AppProvider extends FDroidProvider {
return getContentUri().buildUpon()
.appendPath(PATH_SEARCH_REPO)
.appendPath(repo.id + "")
- .appendPath(query)
+ .appendEncodedPath(query)
.build();
}
@@ -597,7 +619,7 @@ public class AppProvider extends FDroidProvider {
getTableName() + ".description",
};
- // Remove duplicates, surround in % for case insensitive searching
+ // Remove duplicates, surround in % for wildcard searching
final Set keywordSet = new HashSet<>(Arrays.asList(query.split("\\s")));
final String[] keywords = new String[keywordSet.size()];
int iKeyword = 0;
@@ -735,6 +757,16 @@ public class AppProvider extends FDroidProvider {
includeSwap = false;
break;
+ case SEARCH_INSTALLED:
+ selection = querySearch(uri.getLastPathSegment()).add(queryInstalled());
+ includeSwap = false;
+ break;
+
+ case SEARCH_CAN_UPDATE:
+ selection = querySearch(uri.getLastPathSegment()).add(queryCanUpdate());
+ includeSwap = false;
+ break;
+
case SEARCH_REPO:
selection = selection.add(querySearch(uri.getPathSegments().get(2)));
selection = selection.add(queryRepo(Long.parseLong(uri.getPathSegments().get(1))));
diff --git a/F-Droid/src/org/fdroid/fdroid/views/AppListFragmentPagerAdapter.java b/F-Droid/src/org/fdroid/fdroid/views/AppListFragmentPagerAdapter.java
index 43ac7b81f..7ce790d3c 100644
--- a/F-Droid/src/org/fdroid/fdroid/views/AppListFragmentPagerAdapter.java
+++ b/F-Droid/src/org/fdroid/fdroid/views/AppListFragmentPagerAdapter.java
@@ -1,5 +1,7 @@
package org.fdroid.fdroid.views;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentPagerAdapter;
@@ -7,6 +9,7 @@ import org.fdroid.fdroid.FDroid;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.compat.TabManager;
import org.fdroid.fdroid.data.AppProvider;
+import org.fdroid.fdroid.views.fragments.AppListFragment;
import org.fdroid.fdroid.views.fragments.AvailableAppsFragment;
import org.fdroid.fdroid.views.fragments.CanUpdateAppsFragment;
import org.fdroid.fdroid.views.fragments.InstalledAppsFragment;
@@ -17,11 +20,19 @@ import org.fdroid.fdroid.views.fragments.InstalledAppsFragment;
*/
public class AppListFragmentPagerAdapter extends FragmentPagerAdapter {
- private final FDroid parent;
+ @NonNull private final FDroid parent;
- public AppListFragmentPagerAdapter(FDroid parent) {
+ @NonNull private final AppListFragment availableFragment;
+ @NonNull private final AppListFragment installedFragment;
+ @NonNull private final AppListFragment canUpdateFragment;
+
+ public AppListFragmentPagerAdapter(@NonNull FDroid parent) {
super(parent.getSupportFragmentManager());
this.parent = parent;
+
+ availableFragment = new AvailableAppsFragment();
+ installedFragment = new InstalledAppsFragment();
+ canUpdateFragment = new CanUpdateAppsFragment();
}
private String getInstalledTabTitle() {
@@ -34,15 +45,21 @@ public class AppListFragmentPagerAdapter extends FragmentPagerAdapter {
return parent.getString(R.string.tab_updates_count, updateCount);
}
+ public void updateSearchQuery(@Nullable String query) {
+ availableFragment.updateSearchQuery(query);
+ installedFragment.updateSearchQuery(query);
+ canUpdateFragment.updateSearchQuery(query);
+ }
+
@Override
public Fragment getItem(int i) {
switch (i) {
case TabManager.INDEX_AVAILABLE:
- return new AvailableAppsFragment();
+ return availableFragment;
case TabManager.INDEX_INSTALLED:
- return new InstalledAppsFragment();
+ return installedFragment;
default:
- return new CanUpdateAppsFragment();
+ return canUpdateFragment;
}
}
diff --git a/F-Droid/src/org/fdroid/fdroid/views/fragments/AppListFragment.java b/F-Droid/src/org/fdroid/fdroid/views/fragments/AppListFragment.java
index 401c14120..b6efa0f14 100644
--- a/F-Droid/src/org/fdroid/fdroid/views/fragments/AppListFragment.java
+++ b/F-Droid/src/org/fdroid/fdroid/views/fragments/AppListFragment.java
@@ -6,10 +6,12 @@ import android.content.SharedPreferences;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
+import android.support.annotation.Nullable;
import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
+import android.text.TextUtils;
import android.view.View;
import android.widget.AdapterView;
@@ -52,12 +54,36 @@ public abstract class AppListFragment extends ListFragment implements
protected AppListAdapter appAdapter;
+ @Nullable private String searchQuery;
+
protected abstract AppListAdapter getAppListAdapter();
protected abstract String getFromTitle();
protected abstract Uri getDataUri();
+ protected abstract Uri getDataUri(String query);
+
+ /**
+ * Subclasses can choose to do different things based on when a user begins searching.
+ * For example, the "Available" tab chooses to hide its category spinner to make it clear
+ * that it is searching all apps, not the current category.
+ * NOTE: This will get called multiple times, every time the user changes the
+ * search query.
+ */
+ protected void onSearch() {
+ // Do nothing by default.
+ }
+
+ /**
+ * Alerts the child class that the user is no longer performing a search.
+ * This is triggered every time the search query is blank.
+ * @see AppListFragment#onSearch()
+ */
+ protected void onSearchStopped() {
+ // Do nothing by default.
+ }
+
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
@@ -144,9 +170,30 @@ public abstract class AppListFragment extends ListFragment implements
@Override
public Loader onCreateLoader(int id, Bundle args) {
- Uri uri = getDataUri();
+ Uri uri = updateSearchStatus() ? getDataUri(searchQuery) : getDataUri();
return new CursorLoader(
getActivity(), uri, APP_PROJECTION, null, null, APP_SORT);
}
+ /**
+ * Notifies the subclass via {@link AppListFragment#onSearch()} and {@link AppListFragment#onSearchStopped()}
+ * about whether or not a search is taking place.
+ * @return True if a user is searching.
+ */
+ private boolean updateSearchStatus() {
+ if (TextUtils.isEmpty(searchQuery)) {
+ onSearchStopped();
+ return false;
+ } else {
+ onSearch();
+ return true;
+ }
+ }
+
+ public void updateSearchQuery(@Nullable String query) {
+ searchQuery = query;
+ if (isAdded()) {
+ getLoaderManager().restartLoader(0, null, this);
+ }
+ }
}
diff --git a/F-Droid/src/org/fdroid/fdroid/views/fragments/AvailableAppsFragment.java b/F-Droid/src/org/fdroid/fdroid/views/fragments/AvailableAppsFragment.java
index ffb14c4e2..0b7aab7e5 100644
--- a/F-Droid/src/org/fdroid/fdroid/views/fragments/AvailableAppsFragment.java
+++ b/F-Droid/src/org/fdroid/fdroid/views/fragments/AvailableAppsFragment.java
@@ -8,6 +8,7 @@ import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
+import android.support.annotation.Nullable;
import android.support.v4.app.LoaderManager;
import android.view.LayoutInflater;
import android.view.View;
@@ -37,6 +38,11 @@ public class AvailableAppsFragment extends AppListFragment implements
private static String defaultCategory;
private List categories;
+
+ @Nullable
+ private View categoryWrapper;
+
+ @Nullable
private Spinner categorySpinner;
private String currentCategory;
private AppListAdapter adapter;
@@ -147,6 +153,7 @@ public class AvailableAppsFragment extends AppListFragment implements
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.available_app_list, container, false);
+ categoryWrapper = view.findViewById(R.id.category_wrapper);
setupCategorySpinner((Spinner) view.findViewById(R.id.category_spinner));
defaultCategory = AppProvider.Helper.getCategoryWhatsNew(getActivity());
@@ -164,6 +171,11 @@ public class AvailableAppsFragment extends AppListFragment implements
return AppProvider.getCategoryUri(currentCategory);
}
+ @Override
+ protected Uri getDataUri(String query) {
+ return AppProvider.getSearchUri(query);
+ }
+
private void setCurrentCategory(String category) {
currentCategory = category;
Utils.debugLog(TAG, "Category '" + currentCategory + "' selected.");
@@ -175,15 +187,18 @@ public class AvailableAppsFragment extends AppListFragment implements
super.onResume();
/* restore the saved Category Spinner position */
Activity activity = getActivity();
- SharedPreferences p = activity.getSharedPreferences(PREFERENCES_FILE,
- Context.MODE_PRIVATE);
+ SharedPreferences p = activity.getSharedPreferences(PREFERENCES_FILE, Context.MODE_PRIVATE);
currentCategory = p.getString(CATEGORY_KEY, defaultCategory);
- for (int i = 0; i < categorySpinner.getCount(); i++) {
- if (currentCategory.equals(categorySpinner.getItemAtPosition(i).toString())) {
- categorySpinner.setSelection(i);
- break;
+
+ if (categorySpinner != null) {
+ for (int i = 0; i < categorySpinner.getCount(); i++) {
+ if (currentCategory.equals(categorySpinner.getItemAtPosition(i).toString())) {
+ categorySpinner.setSelection(i);
+ break;
+ }
}
}
+
setCurrentCategory(currentCategory);
}
@@ -197,4 +212,18 @@ public class AvailableAppsFragment extends AppListFragment implements
e.putString(CATEGORY_KEY, currentCategory);
e.commit();
}
+
+ @Override
+ protected void onSearch() {
+ if (categoryWrapper != null) {
+ categoryWrapper.setVisibility(View.GONE);
+ }
+ }
+
+ @Override
+ protected void onSearchStopped() {
+ if (categoryWrapper != null) {
+ categoryWrapper.setVisibility(View.VISIBLE);
+ }
+ }
}
diff --git a/F-Droid/src/org/fdroid/fdroid/views/fragments/CanUpdateAppsFragment.java b/F-Droid/src/org/fdroid/fdroid/views/fragments/CanUpdateAppsFragment.java
index e767077b9..8b5954609 100644
--- a/F-Droid/src/org/fdroid/fdroid/views/fragments/CanUpdateAppsFragment.java
+++ b/F-Droid/src/org/fdroid/fdroid/views/fragments/CanUpdateAppsFragment.java
@@ -28,6 +28,10 @@ public class CanUpdateAppsFragment extends AppListFragment {
return AppProvider.getCanUpdateUri();
}
+ protected Uri getDataUri(String query) {
+ return AppProvider.getSearchCanUpdateUri(query);
+ }
+
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.can_update_app_list, container, false);
diff --git a/F-Droid/src/org/fdroid/fdroid/views/fragments/InstalledAppsFragment.java b/F-Droid/src/org/fdroid/fdroid/views/fragments/InstalledAppsFragment.java
index d5078b80f..7f7a77c01 100644
--- a/F-Droid/src/org/fdroid/fdroid/views/fragments/InstalledAppsFragment.java
+++ b/F-Droid/src/org/fdroid/fdroid/views/fragments/InstalledAppsFragment.java
@@ -28,6 +28,10 @@ public class InstalledAppsFragment extends AppListFragment {
return AppProvider.getInstalledUri();
}
+ protected Uri getDataUri(String query) {
+ return AppProvider.getSearchInstalledUri(query);
+ }
+
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.installed_app_list, container, false);
diff --git a/F-Droid/tools/test-search-intents.sh b/F-Droid/tools/test-search-intents.sh
new file mode 100755
index 000000000..172eaddde
--- /dev/null
+++ b/F-Droid/tools/test-search-intents.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+echo "A helper script to send all of the various intents that F-droid should be able to handle via ADB."
+echo "Use this to ensure that things which should trigger searches, do trigger searches, and those which should bring up the app details screen, do bring it up."
+echo ""
+
+function view {
+ DESCRIPTION=$1
+ DATA=$2
+ wait "$DESCRIPTION"
+ CMD="adb shell am start -a android.intent.action.VIEW -d $DATA"
+ $CMD
+ echo ""
+ sleep 1
+}
+
+function wait {
+ DESCRIPTION=$1
+ echo "$DESCRIPTION [Y/n]"
+
+ read -n 1 RESULT
+
+ # Lower case the result.
+ RESULT=`echo "$RESULT" | tr '[:upper:]' '[:lower:]'`
+
+ echo ""
+
+ if [ "$RESULT" != 'y' ]; then
+ exit;
+ fi
+}
+
+APP_TO_SHOW=org.fdroid.fdroid
+SEARCH_QUERY=book+reader
+
+view "Search for '$SEARCH_QUERY' (fdroid web)" http://f-droid.org/repository/browse?fdfilter=$SEARCH_QUERY
+view "Search for '$SEARCH_QUERY' (market)" market://search?q=$SEARCH_QUERY
+view "Search for '$SEARCH_QUERY' (play)" http://play.google.com/store/search?q=$SEARCH_QUERY
+view "Search for '$SEARCH_QUERY' (amazon)" http://amazon.com/gp/mas/dl/android?s=$SEARCH_QUERY
+view "Search for '$SEARCH_QUERY' (fdroid)" fdroid.search:$SEARCH_QUERY
+view "View '$APP_TO_SHOW' (fdroid web fdid)" http://f-droid.org/repository/browse?fdid=$APP_TO_SHOW
+view "View '$APP_TO_SHOW' (fdroid web /app/ path)" http://f-droid.org/app/$APP_TO_SHOW
+view "View '$APP_TO_SHOW' (market)" market://details?id=$APP_TO_SHOW
+view "View '$APP_TO_SHOW' (play)" http://play.google.com/store/apps/details?id=$APP_TO_SHOW
+view "View '$APP_TO_SHOW' (amazon)" amzn://apps/android?p=$APP_TO_SHOW
+view "View '$APP_TO_SHOW' (fdroid)" fdroid.app:$APP_TO_SHOW