From 08346b9b184a79b524a39ecb1b78a619f8241235 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 5 May 2014 19:47:21 -0400 Subject: [PATCH] add Activity to choose which installed apps are in the local repo This gets the data about which apps are installed from the ContentProvider that pserwylo recently added for data about "Installed Apps" and presents a list view for the user to select from by touching each line. Then if the user chooses "Update Repo", it will regenerate the local repo based on the current selection. It will always include FDroid in the local repo. fixes #3232 https://dev.guardianproject.info/issues/3232 refs #3204 https://dev.guardianproject.info/issues/3204 --- AndroidManifest.xml | 8 ++ res/layout/select_local_apps_activity.xml | 12 ++ res/menu/select_local_apps_action_mode.xml | 9 ++ res/menu/select_local_apps_activity.xml | 10 ++ res/values/strings.xml | 3 + src/org/fdroid/fdroid/FDroidApp.java | 2 +- .../fdroid/views/LocalRepoActivity.java | 11 +- .../fdroid/views/SelectLocalAppsActivity.java | 89 ++++++++++++ .../fragments/SelectLocalAppsFragment.java | 134 ++++++++++++++++++ 9 files changed, 272 insertions(+), 6 deletions(-) create mode 100644 res/layout/select_local_apps_activity.xml create mode 100644 res/menu/select_local_apps_action_mode.xml create mode 100644 res/menu/select_local_apps_activity.xml create mode 100644 src/org/fdroid/fdroid/views/SelectLocalAppsActivity.java create mode 100644 src/org/fdroid/fdroid/views/fragments/SelectLocalAppsFragment.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 9c9a599c4..61014ce33 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -197,6 +197,14 @@ + + + + + + + \ No newline at end of file diff --git a/res/menu/select_local_apps_action_mode.xml b/res/menu/select_local_apps_action_mode.xml new file mode 100644 index 000000000..2550ebcfe --- /dev/null +++ b/res/menu/select_local_apps_action_mode.xml @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/res/menu/select_local_apps_activity.xml b/res/menu/select_local_apps_activity.xml new file mode 100644 index 000000000..0d2d96089 --- /dev/null +++ b/res/menu/select_local_apps_activity.xml @@ -0,0 +1,10 @@ + + + + + \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index bc21277de..ae4f18a66 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -157,12 +157,15 @@ Setup Local Repo Touch to setup your local repo. Updating… + Update Repo Deleting current repo… Adding %s to repo… Writing raw index file (index.xml)… Linking APKs into the repo… Copying app icons into the repo… Finished updating local repo + No applications found + icon Fingerprint: WiFi Network: Enable WiFi diff --git a/src/org/fdroid/fdroid/FDroidApp.java b/src/org/fdroid/fdroid/FDroidApp.java index 1b5bfcf35..d88aae18c 100644 --- a/src/org/fdroid/fdroid/FDroidApp.java +++ b/src/org/fdroid/fdroid/FDroidApp.java @@ -85,7 +85,7 @@ public class FDroidApp extends Application { public static String bssid = ""; public static Repo repo = new Repo(); public static LocalRepoManager localRepo = null; - static Set selectedApps = new HashSet(); + public static Set selectedApps = new HashSet(); private static Messenger localRepoServiceMessenger = null; private static boolean localRepoServiceIsBound = false; diff --git a/src/org/fdroid/fdroid/views/LocalRepoActivity.java b/src/org/fdroid/fdroid/views/LocalRepoActivity.java index 498fd000d..4b87f4d39 100644 --- a/src/org/fdroid/fdroid/views/LocalRepoActivity.java +++ b/src/org/fdroid/fdroid/views/LocalRepoActivity.java @@ -36,6 +36,7 @@ public class LocalRepoActivity extends Activity { private ToggleButton repoSwitch; private int SET_IP_ADDRESS = 7345; + private int UPDATE_REPO = 7346; /** Called when the activity is first created. */ @Override @@ -106,11 +107,7 @@ public class LocalRepoActivity extends Activity { public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menu_setup_repo: - setUIFromWifi(); - String[] packages = new String[2]; - packages[0] = getPackageName(); - packages[1] = "com.android.bluetooth"; - new UpdateAsyncTask(this, packages).execute(); + startActivityForResult(new Intent(this, SelectLocalAppsActivity.class), UPDATE_REPO); return true; case R.id.menu_send_fdroid_via_wifi: startActivity(new Intent(this, QrWizardWifiNetworkActivity.class)); @@ -128,6 +125,10 @@ public class LocalRepoActivity extends Activity { return; if (requestCode == SET_IP_ADDRESS) { setUIFromWifi(); + } else if (requestCode == UPDATE_REPO) { + setUIFromWifi(); + new UpdateAsyncTask(this, FDroidApp.selectedApps.toArray(new String[0])) + .execute(); } } diff --git a/src/org/fdroid/fdroid/views/SelectLocalAppsActivity.java b/src/org/fdroid/fdroid/views/SelectLocalAppsActivity.java new file mode 100644 index 000000000..ff0ad5445 --- /dev/null +++ b/src/org/fdroid/fdroid/views/SelectLocalAppsActivity.java @@ -0,0 +1,89 @@ + +package org.fdroid.fdroid.views; + +import android.annotation.TargetApi; +import android.content.Intent; +import android.os.Bundle; +import android.support.v4.app.FragmentActivity; +import android.view.ActionMode; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; + +import org.fdroid.fdroid.PreferencesActivity; +import org.fdroid.fdroid.R; +import org.fdroid.fdroid.views.fragments.SelectLocalAppsFragment; + +@TargetApi(11) +// TODO replace with appcompat-v7 +public class SelectLocalAppsActivity extends FragmentActivity { + private static final String TAG = "SelectLocalAppsActivity"; + private SelectLocalAppsFragment selectLocalAppsFragment = null; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.select_local_apps_activity); + } + + @Override + protected void onResume() { + super.onResume(); + if (selectLocalAppsFragment == null) + selectLocalAppsFragment = (SelectLocalAppsFragment) getSupportFragmentManager().findFragmentById( + R.id.fragment_app_list); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.select_local_apps_activity, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + setResult(RESULT_CANCELED); + finish(); + return true; + case R.id.action_settings: + startActivity(new Intent(this, PreferencesActivity.class)); + return true; + } + return super.onOptionsItemSelected(item); + } + + public ActionMode.Callback mActionModeCallback = new ActionMode.Callback() { + + @Override + public boolean onCreateActionMode(ActionMode mode, Menu menu) { + MenuInflater inflater = mode.getMenuInflater(); + inflater.inflate(R.menu.select_local_apps_action_mode, menu); + return true; + } + + @Override + public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + return false; // Return false if nothing is done + } + + @Override + public boolean onActionItemClicked(final ActionMode mode, MenuItem item) { + switch (item.getItemId()) { + case R.id.action_update_repo: + setResult(RESULT_OK); + finish(); + return true; + default: + return false; + } + } + + @Override + public void onDestroyActionMode(ActionMode mode) { + setResult(RESULT_CANCELED); + finish(); + } + }; +} diff --git a/src/org/fdroid/fdroid/views/fragments/SelectLocalAppsFragment.java b/src/org/fdroid/fdroid/views/fragments/SelectLocalAppsFragment.java new file mode 100644 index 000000000..9eff92157 --- /dev/null +++ b/src/org/fdroid/fdroid/views/fragments/SelectLocalAppsFragment.java @@ -0,0 +1,134 @@ +/* + 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.fdroid.fdroid.views.fragments; + +import android.annotation.TargetApi; +import android.database.Cursor; +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.view.ActionMode; +import android.view.View; +import android.widget.ListView; + +import org.fdroid.fdroid.FDroidApp; +import org.fdroid.fdroid.R; +import org.fdroid.fdroid.data.InstalledAppProvider; +import org.fdroid.fdroid.data.InstalledAppProvider.DataColumns; +import org.fdroid.fdroid.views.SelectLocalAppsActivity; + +public class SelectLocalAppsFragment extends ListFragment implements LoaderCallbacks { + + private SelectLocalAppsActivity selectLocalAppsActivity; + private ActionMode mActionMode = null; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @TargetApi(11) + // TODO replace with appcompat-v7 + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + setEmptyText(getString(R.string.no_applications_found)); + + selectLocalAppsActivity = (SelectLocalAppsActivity) getActivity(); + ListView listView = getListView(); + listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); + SimpleCursorAdapter adapter = new SimpleCursorAdapter(getActivity(), + android.R.layout.simple_list_item_activated_1, + null, + new String[] { + InstalledAppProvider.DataColumns.APP_ID, + }, + new int[] { + android.R.id.text1, + }, + 0); + setListAdapter(adapter); + setListShown(false); + + // either reconnect with an existing loader or start a new one + getLoaderManager().initLoader(0, null, this); + } + + @TargetApi(11) + // TODO replace with appcompat-v7 + @Override + public void onListItemClick(ListView l, View v, int position, long id) { + if (mActionMode == null) + mActionMode = selectLocalAppsActivity + .startActionMode(selectLocalAppsActivity.mActionModeCallback); + Cursor cursor = (Cursor) l.getAdapter().getItem(position); + String packageName = cursor.getString(1); + if (FDroidApp.selectedApps.contains(packageName)) { + FDroidApp.selectedApps.remove(packageName); + } else { + FDroidApp.selectedApps.add(packageName); + } + } + + @Override + public CursorLoader onCreateLoader(int id, Bundle args) { + CursorLoader loader = new CursorLoader( + this.getActivity(), + InstalledAppProvider.getContentUri(), + InstalledAppProvider.DataColumns.ALL, + null, + null, + InstalledAppProvider.DataColumns.APP_ID); + return loader; + } + + @Override + public void onLoadFinished(Loader loader, Cursor cursor) { + ((SimpleCursorAdapter) this.getListAdapter()).swapCursor(cursor); + + ListView listView = getListView(); + int count = listView.getCount(); + String fdroid = loader.getContext().getPackageName(); + for (int i = 0; i < count; i++) { + Cursor c = ((Cursor) listView.getItemAtPosition(i)); + String packageName = c.getString(c.getColumnIndex(DataColumns.APP_ID)); + if (TextUtils.equals(packageName, fdroid)) { + listView.setItemChecked(i, true); + } else { + for (String selected : FDroidApp.selectedApps) { + if (TextUtils.equals(packageName, selected)) { + listView.setItemChecked(i, true); + } + } + } + } + + if (isResumed()) { + setListShown(true); + } else { + setListShownNoAnimation(true); + } + } + + @Override + public void onLoaderReset(Loader loader) { + ((SimpleCursorAdapter) this.getListAdapter()).swapCursor(null); + } +}