diff --git a/F-Droid/res/layout-v11/select_local_apps_list_item.xml b/F-Droid/res/layout-v11/select_local_apps_list_item.xml index a95e22db0..5ac585492 100644 --- a/F-Droid/res/layout-v11/select_local_apps_list_item.xml +++ b/F-Droid/res/layout-v11/select_local_apps_list_item.xml @@ -22,6 +22,7 @@ android:paddingTop="2dip" > + + , SearchView.OnQueryTextListener { - private PackageManager packageManager; - private Drawable defaultAppIcon; private String mCurrentFilterString; - private Set previouslySelectedApps = new HashSet(); + private Set previouslySelectedApps = new HashSet<>(); public Set getSelectedApps() { return FDroidApp.selectedApps; @@ -103,46 +97,10 @@ public class SelectAppsFragment extends ThemeableListFragment setEmptyText(getString(R.string.no_applications_found)); - packageManager = getActivity().getPackageManager(); - defaultAppIcon = getResources().getDrawable(android.R.drawable.sym_def_app_icon); - ListView listView = getListView(); listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); - SimpleCursorAdapter adapter = new SimpleCursorAdapter( - new ContextThemeWrapper(getActivity(), R.style.SwapTheme_AppList_ListItem), - R.layout.select_local_apps_list_item, - null, - new String[] { - InstalledAppProvider.DataColumns.APPLICATION_LABEL, - InstalledAppProvider.DataColumns.APP_ID, - }, - new int[] { - R.id.application_label, - R.id.package_name, - }); - adapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() { - @Override - public boolean setViewValue(View view, Cursor cursor, int columnIndex) { - if (columnIndex == cursor.getColumnIndex(InstalledAppProvider.DataColumns.APP_ID)) { - String packageName = cursor.getString(columnIndex); - TextView textView = (TextView) view.findViewById(R.id.package_name); - textView.setText(packageName); - LinearLayout ll = (LinearLayout) view.getParent().getParent(); - ImageView iconView = (ImageView) ll.getChildAt(0); - Drawable icon; - try { - icon = packageManager.getApplicationIcon(packageName); - } catch (PackageManager.NameNotFoundException e) { - icon = defaultAppIcon; - } - iconView.setImageDrawable(icon); - return true; - } - return false; - } - }); - setListAdapter(adapter); + setListAdapter(new AppListAdapter(listView, getActivity(), null)); setListShown(false); // start out with a progress indicator // either reconnect with an existing loader or start a new one @@ -150,7 +108,7 @@ public class SelectAppsFragment extends ThemeableListFragment // build list of existing apps from what is on the file system if (FDroidApp.selectedApps == null) { - FDroidApp.selectedApps = new HashSet(); + FDroidApp.selectedApps = new HashSet<>(); for (String filename : LocalRepoManager.get(getActivity()).repoDir.list()) { if (filename.matches(".*\\.apk")) { String packageName = filename.substring(0, filename.indexOf("_")); @@ -190,7 +148,7 @@ public class SelectAppsFragment extends ThemeableListFragment @Override public void onLoadFinished(Loader loader, Cursor cursor) { - ((SimpleCursorAdapter) this.getListAdapter()).swapCursor(cursor); + ((AppListAdapter)getListAdapter()).swapCursor(cursor); ListView listView = getListView(); String fdroid = loader.getContext().getPackageName(); @@ -217,7 +175,7 @@ public class SelectAppsFragment extends ThemeableListFragment @Override public void onLoaderReset(Loader loader) { - ((SimpleCursorAdapter) this.getListAdapter()).swapCursor(null); + ((AppListAdapter)getListAdapter()).swapCursor(null); } @Override @@ -240,10 +198,6 @@ public class SelectAppsFragment extends ThemeableListFragment return true; } - public String getCurrentFilterString() { - return mCurrentFilterString; - } - @Override protected int getThemeStyle() { return R.style.SwapTheme_StartSwap; @@ -253,4 +207,85 @@ public class SelectAppsFragment extends ThemeableListFragment protected int getHeaderLayout() { return R.layout.swap_create_header; } + + private static class AppListAdapter extends CursorAdapter { + + @Nullable + private LayoutInflater inflater; + + @Nullable + private Drawable defaultAppIcon; + + @NonNull + private final ListView listView; + + public AppListAdapter(@NonNull ListView listView, @NonNull Context context, @Nullable Cursor c) { + super(context, c, FLAG_REGISTER_CONTENT_OBSERVER); + this.listView = listView; + } + + @NonNull + private LayoutInflater getInflater(Context context) { + if (inflater == null) { + Context themedContext = new ContextThemeWrapper(context, R.style.SwapTheme_AppList_ListItem); + inflater = (LayoutInflater)themedContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + } + return inflater; + } + + @NonNull + private Drawable getDefaultAppIcon(Context context) { + if (defaultAppIcon == null) { + defaultAppIcon = context.getResources().getDrawable(android.R.drawable.sym_def_app_icon); + } + return defaultAppIcon; + } + + @Override + public View newView(Context context, Cursor cursor, ViewGroup parent) { + View view = getInflater(context).inflate(R.layout.select_local_apps_list_item, null); + bindView(view, context, cursor); + return view; + } + + @Override + public void bindView(final View view, final Context context, final Cursor cursor) { + + TextView packageView = (TextView)view.findViewById(R.id.package_name); + TextView labelView = (TextView)view.findViewById(R.id.application_label); + ImageView iconView = (ImageView)view.findViewById(android.R.id.icon); + + String packageName = cursor.getString(cursor.getColumnIndex(InstalledAppProvider.DataColumns.APP_ID)); + String appLabel = cursor.getString(cursor.getColumnIndex(InstalledAppProvider.DataColumns.APPLICATION_LABEL)); + + Drawable icon; + try { + icon = context.getPackageManager().getApplicationIcon(packageName); + } catch (PackageManager.NameNotFoundException e) { + icon = getDefaultAppIcon(context); + } + + packageView.setText(packageName); + labelView.setText(appLabel); + iconView.setImageDrawable(icon); + + // Since v11, the Android SDK provided the ability to show selected list items + // by highlighting their background. Prior to this, we need to handle this ourselves + // by adding a checkbox which can toggle selected items. + View checkBoxView = view.findViewById(R.id.checkbox); + if (checkBoxView != null) { + CheckBox checkBox = (CheckBox)checkBoxView; + checkBox.setOnCheckedChangeListener(null); + checkBox.setChecked(listView.isItemChecked(cursor.getPosition())); + final int position = cursor.getPosition(); + checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + listView.setItemChecked(position, isChecked); + } + }); + } + } + } + } diff --git a/F-Droid/src/org/fdroid/fdroid/views/swap/WifiQrFragment.java b/F-Droid/src/org/fdroid/fdroid/views/swap/WifiQrFragment.java index 9453af6ad..a71db32eb 100644 --- a/F-Droid/src/org/fdroid/fdroid/views/swap/WifiQrFragment.java +++ b/F-Droid/src/org/fdroid/fdroid/views/swap/WifiQrFragment.java @@ -1,6 +1,5 @@ package org.fdroid.fdroid.views.swap; -import android.annotation.TargetApi; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; @@ -23,6 +22,8 @@ import android.widget.TextView; import android.widget.Toast; import com.google.zxing.integration.android.IntentIntegrator; import com.google.zxing.integration.android.IntentResult; +import org.apache.http.NameValuePair; +import org.apache.http.client.utils.URLEncodedUtils; import org.fdroid.fdroid.FDroid; import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.Preferences; @@ -32,12 +33,16 @@ import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.data.NewRepoConfig; import org.fdroid.fdroid.net.WifiStateChangeService; +import java.net.URI; +import java.util.List; import java.util.Locale; public class WifiQrFragment extends Fragment { private static final int CONNECT_TO_SWAP = 1; + private static final String TAG = "org.fdroid.fdroid.views.swap.WifiQrFragment"; + private BroadcastReceiver onWifiChange = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent i) { @@ -105,7 +110,6 @@ public class WifiQrFragment extends Fragment { new IntentFilter(WifiStateChangeService.BROADCAST)); } - @TargetApi(14) private void setUIFromWifi() { if (TextUtils.isEmpty(FDroidApp.repo.address)) @@ -132,19 +136,26 @@ public class WifiQrFragment extends Fragment { } qrUriString += sharingUri.getPath().toUpperCase(Locale.ENGLISH); boolean first = true; - for (String parameterName : sharingUri.getQueryParameterNames()) { - if (!parameterName.equals("ssid")) { + + // Andorid provides an API for getting the query parameters and iterating over them: + // Uri.getQueryParameterNames() + // But it is only available on later Android versions. As such we URLEncodedUtils instead. + List parameters = URLEncodedUtils.parse(URI.create(sharingUri.toString()), "UTF-8"); + for (NameValuePair parameter : parameters) { + if (!parameter.getName().equals("ssid")) { if (first) { qrUriString += "?"; first = false; } else { qrUriString += "&"; } - qrUriString += parameterName.toUpperCase(Locale.ENGLISH) + "=" + - sharingUri.getQueryParameter(parameterName).toUpperCase(Locale.ENGLISH); + qrUriString += parameter.getName().toUpperCase(Locale.ENGLISH) + "=" + + parameter.getValue().toUpperCase(Locale.ENGLISH); } } + Log.i(TAG, "Encoded swap URI in QR Code: " + qrUriString); + // zxing requires >= 8 // TODO: What about 7? I don't feel comfortable bumping the min version for this... // I would suggest show some alternate info, with directions for how to add a new repository manually.