"Select apps for swap" screen work on API <= 10.
* Provide CheckBox for selected items Newer API's highlight the background using the "activated" state. Older APIs need this to be implemented differently, so there are now checkboxes on the left of the list view items to provide this functionality. * Clean up IDE warnings Diamond operator for generics, remove unused imports and unused method. * Adapter class created for installed apps Cleaned up the code to do with binding views to the adapter in this view. Previously it made quite a few assumptions about the structure of the layout, e.g. "layout.getParent().getParent() is a LinearLayout", which would cause crashes if the layout changed slightly.
This commit is contained in:
parent
4711b50836
commit
23ed692436
@ -22,6 +22,7 @@
|
||||
android:paddingTop="2dip" >
|
||||
|
||||
<ImageView
|
||||
android:id="@android:id/icon"
|
||||
android:layout_width="48dip"
|
||||
android:layout_height="48dip"
|
||||
android:layout_marginLeft="?attr/listPreferredItemPaddingLeft"
|
||||
|
@ -20,7 +20,13 @@
|
||||
android:paddingBottom="2dip"
|
||||
android:paddingTop="2dip" >
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/checkbox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<ImageView
|
||||
android:id="@android:id/icon"
|
||||
android:layout_width="48dip"
|
||||
android:layout_height="48dip"
|
||||
android:layout_marginLeft="?attr/listPreferredItemPaddingLeft"
|
||||
|
@ -1,27 +1,23 @@
|
||||
package org.fdroid.fdroid.views.swap;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.content.CursorLoader;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.support.v4.view.MenuItemCompat;
|
||||
import android.support.v4.widget.CursorAdapter;
|
||||
import android.support.v4.widget.SimpleCursorAdapter;
|
||||
import android.support.v7.widget.SearchView;
|
||||
import android.text.TextUtils;
|
||||
import android.view.ActionMode;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import android.view.*;
|
||||
import android.widget.*;
|
||||
import org.fdroid.fdroid.FDroidApp;
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.data.InstalledAppProvider;
|
||||
@ -34,10 +30,8 @@ import java.util.Set;
|
||||
public class SelectAppsFragment extends ThemeableListFragment
|
||||
implements LoaderManager.LoaderCallbacks<Cursor>, SearchView.OnQueryTextListener {
|
||||
|
||||
private PackageManager packageManager;
|
||||
private Drawable defaultAppIcon;
|
||||
private String mCurrentFilterString;
|
||||
private Set<String> previouslySelectedApps = new HashSet<String>();
|
||||
private Set<String> previouslySelectedApps = new HashSet<>();
|
||||
|
||||
public Set<String> 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<String>();
|
||||
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<Cursor> 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<Cursor> 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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<NameValuePair> 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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user