live filtering of InstalledApps for setting up Local Repo

This implements live filtering in a SearchView so that it is easy to search
for the apps you want to include in your Local Repo.  This requires some
newer stuff, so I switched it to the android-11 Activity until appcompat-v7
is included.  All this functionality will work fine with appcompat-v7.
This commit is contained in:
Hans-Christoph Steiner 2014-05-07 20:48:02 -04:00
parent a6de6b2932
commit 914149aad2
4 changed files with 70 additions and 22 deletions

View File

@ -1,5 +1,10 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android" > <menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/action_search"
android:icon="@android:drawable/ic_menu_search"
android:showAsAction="ifRoom"
android:title="@string/menu_search"/>
<item <item
android:id="@+id/action_update_repo" android:id="@+id/action_update_repo"
android:icon="@android:drawable/ic_input_add" android:icon="@android:drawable/ic_input_add"

View File

@ -1,10 +1,15 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android" > <menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/action_search"
android:actionViewClass="android.widget.SearchView"
android:icon="@android:drawable/ic_menu_search"
android:showAsAction="collapseActionView|ifRoom"
android:title="@string/menu_search"/>
<item <item
android:id="@+id/action_settings" android:id="@+id/action_settings"
android:orderInCategory="100"
android:showAsAction="never"
android:icon="@android:drawable/ic_menu_preferences" android:icon="@android:drawable/ic_menu_preferences"
android:showAsAction="never"
android:title="@string/menu_preferences"/> android:title="@string/menu_preferences"/>
</menu> </menu>

View File

@ -2,13 +2,11 @@
package org.fdroid.fdroid.views; package org.fdroid.fdroid.views;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.FragmentActivity; import android.view.*;
import android.view.ActionMode; import android.widget.SearchView;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import org.fdroid.fdroid.PreferencesActivity; import org.fdroid.fdroid.PreferencesActivity;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
@ -16,9 +14,10 @@ import org.fdroid.fdroid.views.fragments.SelectLocalAppsFragment;
@TargetApi(11) @TargetApi(11)
// TODO replace with appcompat-v7 // TODO replace with appcompat-v7
public class SelectLocalAppsActivity extends FragmentActivity { public class SelectLocalAppsActivity extends Activity {
private static final String TAG = "SelectLocalAppsActivity"; private static final String TAG = "SelectLocalAppsActivity";
private SelectLocalAppsFragment selectLocalAppsFragment = null; private SelectLocalAppsFragment selectLocalAppsFragment = null;
private SearchView searchView;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@ -30,13 +29,15 @@ public class SelectLocalAppsActivity extends FragmentActivity {
protected void onResume() { protected void onResume() {
super.onResume(); super.onResume();
if (selectLocalAppsFragment == null) if (selectLocalAppsFragment == null)
selectLocalAppsFragment = (SelectLocalAppsFragment) getSupportFragmentManager().findFragmentById( selectLocalAppsFragment = (SelectLocalAppsFragment) getFragmentManager()
R.id.fragment_app_list); .findFragmentById(R.id.fragment_app_list);
} }
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.select_local_apps_activity, menu); getMenuInflater().inflate(R.menu.select_local_apps_activity, menu);
searchView = (SearchView) menu.findItem(R.id.action_search).getActionView();
searchView.setOnQueryTextListener(selectLocalAppsFragment);
return true; return true;
} }
@ -47,6 +48,10 @@ public class SelectLocalAppsActivity extends FragmentActivity {
setResult(RESULT_CANCELED); setResult(RESULT_CANCELED);
finish(); finish();
return true; return true;
case R.id.action_search:
SearchView searchView = (SearchView) item.getActionView();
searchView.setIconified(false);
return true;
case R.id.action_settings: case R.id.action_settings:
startActivity(new Intent(this, PreferencesActivity.class)); startActivity(new Intent(this, PreferencesActivity.class));
return true; return true;
@ -60,6 +65,7 @@ public class SelectLocalAppsActivity extends FragmentActivity {
public boolean onCreateActionMode(ActionMode mode, Menu menu) { public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = mode.getMenuInflater(); MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.select_local_apps_action_mode, menu); inflater.inflate(R.menu.select_local_apps_action_mode, menu);
menu.findItem(R.id.action_search).setActionView(searchView);
return true; return true;
} }

View File

@ -15,17 +15,19 @@ limitations under the License.
package org.fdroid.fdroid.views.fragments; package org.fdroid.fdroid.views.fragments;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.app.ListFragment;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.CursorLoader;
import android.content.Loader;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.widget.SimpleCursorAdapter;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.ActionMode; import android.view.ActionMode;
import android.view.View; import android.view.View;
import android.widget.ListView; import android.widget.ListView;
import android.widget.SearchView.OnQueryTextListener;
import android.widget.SimpleCursorAdapter;
import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
@ -35,18 +37,20 @@ import org.fdroid.fdroid.views.SelectLocalAppsActivity;
import java.util.HashSet; import java.util.HashSet;
public class SelectLocalAppsFragment extends ListFragment implements LoaderCallbacks<Cursor> { //TODO replace with appcompat-v7
@TargetApi(11)
public class SelectLocalAppsFragment extends ListFragment
implements LoaderCallbacks<Cursor>, OnQueryTextListener {
private SelectLocalAppsActivity selectLocalAppsActivity; private SelectLocalAppsActivity selectLocalAppsActivity;
private ActionMode mActionMode = null; private ActionMode mActionMode = null;
private String mCurrentFilterString;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
} }
@TargetApi(11)
// TODO replace with appcompat-v7
@Override @Override
public void onActivityCreated(Bundle savedInstanceState) { public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState); super.onActivityCreated(savedInstanceState);
@ -69,7 +73,7 @@ public class SelectLocalAppsFragment extends ListFragment implements LoaderCallb
}, },
0); 0);
setListAdapter(adapter); setListAdapter(adapter);
setListShown(false); setListShown(false); // start out with a progress indicator
// either reconnect with an existing loader or start a new one // either reconnect with an existing loader or start a new one
getLoaderManager().initLoader(0, null, this); getLoaderManager().initLoader(0, null, this);
@ -86,8 +90,6 @@ public class SelectLocalAppsFragment extends ListFragment implements LoaderCallb
} }
} }
@TargetApi(11)
// TODO replace with appcompat-v7
@Override @Override
public void onListItemClick(ListView l, View v, int position, long id) { public void onListItemClick(ListView l, View v, int position, long id) {
if (mActionMode == null) if (mActionMode == null)
@ -104,9 +106,15 @@ public class SelectLocalAppsFragment extends ListFragment implements LoaderCallb
@Override @Override
public CursorLoader onCreateLoader(int id, Bundle args) { public CursorLoader onCreateLoader(int id, Bundle args) {
Uri baseUri;
if (TextUtils.isEmpty(mCurrentFilterString)) {
baseUri = InstalledAppProvider.getContentUri();
} else {
baseUri = InstalledAppProvider.getSearchUri(mCurrentFilterString);
}
CursorLoader loader = new CursorLoader( CursorLoader loader = new CursorLoader(
this.getActivity(), this.getActivity(),
InstalledAppProvider.getContentUri(), baseUri,
InstalledAppProvider.DataColumns.ALL, InstalledAppProvider.DataColumns.ALL,
null, null,
null, null,
@ -146,4 +154,28 @@ public class SelectLocalAppsFragment extends ListFragment implements LoaderCallb
public void onLoaderReset(Loader<Cursor> loader) { public void onLoaderReset(Loader<Cursor> loader) {
((SimpleCursorAdapter) this.getListAdapter()).swapCursor(null); ((SimpleCursorAdapter) this.getListAdapter()).swapCursor(null);
} }
@Override
public boolean onQueryTextChange(String newText) {
String newFilter = !TextUtils.isEmpty(newText) ? newText : null;
if (mCurrentFilterString == null && newFilter == null) {
return true;
}
if (mCurrentFilterString != null && mCurrentFilterString.equals(newFilter)) {
return true;
}
mCurrentFilterString = newFilter;
getLoaderManager().restartLoader(0, null, this);
return true;
}
@Override
public boolean onQueryTextSubmit(String query) {
// this is not needed since we respond to every change in text
return true;
}
public String getCurrentFilterString() {
return mCurrentFilterString;
}
} }