diff --git a/F-Droid/AndroidManifest.xml b/F-Droid/AndroidManifest.xml
index 3ec830c8a..447d5d813 100644
--- a/F-Droid/AndroidManifest.xml
+++ b/F-Droid/AndroidManifest.xml
@@ -359,12 +359,12 @@
+ android:parentActivityName=".views.swap.SwapWorkflowActivity" >
+ android:value=".views.swap.SwapWorkflowActivity" />
-
-
-
-
+ android:text="@string/menu_install"/>
+ android:textStyle="italic"
+ android:text="@string/inst" />
-
+
+
+
+
+
#ff4b7195
#FFAAD024
+ #ff7900
#27aae1
#ff98cce1
#1c6bbc
diff --git a/F-Droid/res/values/strings.xml b/F-Droid/res/values/strings.xml
index 0d279f21f..ee671b2d2 100644
--- a/F-Droid/res/values/strings.xml
+++ b/F-Droid/res/values/strings.xml
@@ -348,4 +348,5 @@
Promising
Best bet
Loading...
+ TRY TO INSTALL
diff --git a/F-Droid/src/org/fdroid/fdroid/Utils.java b/F-Droid/src/org/fdroid/fdroid/Utils.java
index 1eab916e5..5da3aa3ae 100644
--- a/F-Droid/src/org/fdroid/fdroid/Utils.java
+++ b/F-Droid/src/org/fdroid/fdroid/Utils.java
@@ -23,6 +23,7 @@ import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
+import android.graphics.Bitmap;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@@ -32,6 +33,9 @@ import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
+import com.nostra13.universalimageloader.core.DisplayImageOptions;
+import com.nostra13.universalimageloader.core.assist.ImageScaleType;
+import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer;
import com.nostra13.universalimageloader.utils.StorageUtils;
import org.fdroid.fdroid.compat.FileCompat;
@@ -489,6 +493,17 @@ public final class Utils {
}
}
+ public static DisplayImageOptions.Builder getImageLoadingOptions() {
+ return new DisplayImageOptions.Builder()
+ .cacheInMemory(true)
+ .cacheOnDisk(true)
+ .imageScaleType(ImageScaleType.NONE)
+ .showImageOnLoading(R.drawable.ic_repo_app_default)
+ .showImageForEmptyUri(R.drawable.ic_repo_app_default)
+ .displayer(new FadeInBitmapDisplayer(200, true, true, false))
+ .bitmapConfig(Bitmap.Config.RGB_565);
+ }
+
// this is all new stuff being added
public static String hashBytes(byte[] input, String algo) {
try {
diff --git a/F-Droid/src/org/fdroid/fdroid/localrepo/SwapService.java b/F-Droid/src/org/fdroid/fdroid/localrepo/SwapService.java
index 42fa9c6aa..bee1d4ebd 100644
--- a/F-Droid/src/org/fdroid/fdroid/localrepo/SwapService.java
+++ b/F-Droid/src/org/fdroid/fdroid/localrepo/SwapService.java
@@ -159,7 +159,7 @@ public class SwapService extends Service {
// Only ask server to swap with us, if we are actually running a local repo service.
// It is possible to have a swap initiated without first starting a swap, in which
// case swapping back is pointless.
- if (isEnabled()) {
+ if (isEnabled() && requestSwapBack) {
askServerToSwapWithUs(peerRepo);
}
diff --git a/F-Droid/src/org/fdroid/fdroid/localrepo/peers/BluetoothPeer.java b/F-Droid/src/org/fdroid/fdroid/localrepo/peers/BluetoothPeer.java
index 2cee166f5..814e64cc1 100644
--- a/F-Droid/src/org/fdroid/fdroid/localrepo/peers/BluetoothPeer.java
+++ b/F-Droid/src/org/fdroid/fdroid/localrepo/peers/BluetoothPeer.java
@@ -45,6 +45,11 @@ public class BluetoothPeer implements Peer {
return "";
}
+ @Override
+ public boolean shouldPromptForSwapBack() {
+ return false;
+ }
+
@Override
public int describeContents() {
return 0;
diff --git a/F-Droid/src/org/fdroid/fdroid/localrepo/peers/BonjourPeer.java b/F-Droid/src/org/fdroid/fdroid/localrepo/peers/BonjourPeer.java
index 02bae516a..6ec9e3459 100644
--- a/F-Droid/src/org/fdroid/fdroid/localrepo/peers/BonjourPeer.java
+++ b/F-Droid/src/org/fdroid/fdroid/localrepo/peers/BonjourPeer.java
@@ -1,5 +1,6 @@
package org.fdroid.fdroid.localrepo.peers;
+import android.net.Uri;
import android.os.Parcel;
import javax.jmdns.impl.FDroidServiceInfo;
@@ -11,6 +12,8 @@ public class BonjourPeer extends WifiPeer {
public BonjourPeer(ServiceInfo serviceInfo) {
this.serviceInfo = new FDroidServiceInfo(serviceInfo);
+ this.name = serviceInfo.getDomain();
+ this.uri = Uri.parse(this.serviceInfo.getRepoAddress());
}
@Override
diff --git a/F-Droid/src/org/fdroid/fdroid/localrepo/peers/Peer.java b/F-Droid/src/org/fdroid/fdroid/localrepo/peers/Peer.java
index 022aaf282..c1481e297 100644
--- a/F-Droid/src/org/fdroid/fdroid/localrepo/peers/Peer.java
+++ b/F-Droid/src/org/fdroid/fdroid/localrepo/peers/Peer.java
@@ -14,4 +14,6 @@ public interface Peer extends Parcelable {
String getRepoAddress();
String getFingerprint();
+
+ boolean shouldPromptForSwapBack();
}
diff --git a/F-Droid/src/org/fdroid/fdroid/localrepo/peers/WifiPeer.java b/F-Droid/src/org/fdroid/fdroid/localrepo/peers/WifiPeer.java
index b1d596f0a..23e2db129 100644
--- a/F-Droid/src/org/fdroid/fdroid/localrepo/peers/WifiPeer.java
+++ b/F-Droid/src/org/fdroid/fdroid/localrepo/peers/WifiPeer.java
@@ -10,18 +10,20 @@ public class WifiPeer implements Peer {
protected String name;
protected Uri uri;
+ protected boolean shouldPromptForSwapBack;
public WifiPeer() {
}
public WifiPeer(NewRepoConfig config) {
- this(config.getRepoUri(), config.getHost());
+ this(config.getRepoUri(), config.getHost(), !config.preventFurtherSwaps());
}
- protected WifiPeer(Uri uri, String name) {
+ protected WifiPeer(Uri uri, String name, boolean shouldPromptForSwapBack) {
this.name = name;
this.uri = uri;
+ this.shouldPromptForSwapBack = shouldPromptForSwapBack;
}
@Override
@@ -44,6 +46,12 @@ public class WifiPeer implements Peer {
return uri.getQueryParameter("fingerprint");
}
+ @Override
+ public boolean shouldPromptForSwapBack() {
+ return shouldPromptForSwapBack;
+ }
+
+
@Override
public int describeContents() {
return 0;
@@ -53,10 +61,11 @@ public class WifiPeer implements Peer {
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeString(uri.toString());
+ dest.writeByte(shouldPromptForSwapBack ? (byte) 1 : (byte) 0);
}
protected WifiPeer(Parcel in) {
- this(Uri.parse(in.readString()), in.readString());
+ this(Uri.parse(in.readString()), in.readString(), in.readByte() == 1);
}
public static final Creator CREATOR = new Creator() {
diff --git a/F-Droid/src/org/fdroid/fdroid/views/AppListAdapter.java b/F-Droid/src/org/fdroid/fdroid/views/AppListAdapter.java
index fe1df03c2..3036c1b1c 100644
--- a/F-Droid/src/org/fdroid/fdroid/views/AppListAdapter.java
+++ b/F-Droid/src/org/fdroid/fdroid/views/AppListAdapter.java
@@ -18,6 +18,7 @@ import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer;
import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.R;
+import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.data.App;
abstract public class AppListAdapter extends CursorAdapter {
@@ -50,15 +51,7 @@ abstract public class AppListAdapter extends CursorAdapter {
mContext = context;
mInflater = (LayoutInflater) mContext.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
- displayImageOptions = new DisplayImageOptions.Builder()
- .cacheInMemory(true)
- .cacheOnDisk(true)
- .imageScaleType(ImageScaleType.NONE)
- .showImageOnLoading(R.drawable.ic_repo_app_default)
- .showImageForEmptyUri(R.drawable.ic_repo_app_default)
- .displayer(new FadeInBitmapDisplayer(200, true, true, false))
- .bitmapConfig(Bitmap.Config.RGB_565)
- .build();
+ displayImageOptions = Utils.getImageLoadingOptions().build();
}
diff --git a/F-Droid/src/org/fdroid/fdroid/views/swap/SwapAppListActivity.java b/F-Droid/src/org/fdroid/fdroid/views/swap/SwapAppListActivity.java
deleted file mode 100644
index 0406bb989..000000000
--- a/F-Droid/src/org/fdroid/fdroid/views/swap/SwapAppListActivity.java
+++ /dev/null
@@ -1,137 +0,0 @@
-package org.fdroid.fdroid.views.swap;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.support.annotation.Nullable;
-import android.support.v4.app.NavUtils;
-import android.support.v7.app.ActionBarActivity;
-import android.util.Log;
-
-import org.fdroid.fdroid.AppDetails;
-import org.fdroid.fdroid.R;
-import org.fdroid.fdroid.data.AppProvider;
-import org.fdroid.fdroid.data.Repo;
-import org.fdroid.fdroid.data.RepoProvider;
-import org.fdroid.fdroid.views.AppListAdapter;
-import org.fdroid.fdroid.views.AvailableAppListAdapter;
-import org.fdroid.fdroid.views.fragments.AppListFragment;
-
-public class SwapAppListActivity extends ActionBarActivity {
-
- private static final String TAG = "SwapAppListActivity";
-
- public static final String EXTRA_REPO_ID = "repoId";
-
- private Repo repo;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
-
- super.onCreate(savedInstanceState);
-
- if (savedInstanceState == null) {
-
- // Necessary to run on an Android 2.3.[something] device.
- new Handler().post(new Runnable() {
- @Override
- public void run() {
- getSupportFragmentManager()
- .beginTransaction()
- .add(android.R.id.content, new SwapAppListFragment())
- .commit();
- }
- });
- }
-
- }
-
- @Override
- protected void onResume() {
- super.onResume();
-
- long repoAddress = getIntent().getLongExtra(EXTRA_REPO_ID, -1);
- repo = RepoProvider.Helper.findById(this, repoAddress);
- if (repo == null) {
- Log.e(TAG, "Couldn't show swap app list for repo " + repoAddress);
- finish();
- }
- }
-
- public Repo getRepo() {
- return repo;
- }
-
- public static class SwapAppListFragment extends AppListFragment {
-
- private Repo repo;
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
- repo = ((SwapAppListActivity)activity).getRepo();
- }
-
- @Override
- protected int getHeaderLayout() {
- return R.layout.swap_success_header;
- }
-
- @Override
- protected AppListAdapter getAppListAdapter() {
- return new AvailableAppListAdapter(getActivity(), null);
- }
-
- @Nullable
- @Override
- protected String getEmptyMessage() {
- return getActivity().getString(R.string.empty_swap_app_list);
- }
-
- @Override
- protected String getFromTitle() {
- return getString(R.string.swap);
- }
-
- @Override
- protected Uri getDataUri() {
- return AppProvider.getRepoUri(repo);
- }
-
- protected Intent getAppDetailsIntent() {
- Intent intent = new Intent(getActivity(), SwapAppDetails.class);
- intent.putExtra(EXTRA_REPO_ID, repo.getId());
- return intent;
- }
-
- }
-
- /**
- * Only difference from base class is that it navigates up to a different task.
- * It will go to the {@link org.fdroid.fdroid.views.swap.SwapAppListActivity}
- * whereas the baseclass will go back to the main list of apps. Need to juggle
- * the repoId in order to be able to return to an appropriately configured swap
- * list (see {@link org.fdroid.fdroid.views.swap.SwapAppListActivity.SwapAppListFragment#getAppDetailsIntent()}).
- */
- public static class SwapAppDetails extends AppDetails {
-
- private long repoId;
-
- @Override
- protected void onResume() {
- super.onResume();
- repoId = getIntent().getLongExtra(EXTRA_REPO_ID, -1);
- }
-
- @Override
- protected void navigateUp() {
- Intent parentIntent = NavUtils.getParentActivityIntent(this);
- parentIntent.putExtra(EXTRA_REPO_ID, repoId);
- NavUtils.navigateUpTo(this, parentIntent);
- }
-
- }
-
-}
diff --git a/F-Droid/src/org/fdroid/fdroid/views/swap/SwapAppsView.java b/F-Droid/src/org/fdroid/fdroid/views/swap/SwapAppsView.java
index cadef72f6..6f91d4e78 100644
--- a/F-Droid/src/org/fdroid/fdroid/views/swap/SwapAppsView.java
+++ b/F-Droid/src/org/fdroid/fdroid/views/swap/SwapAppsView.java
@@ -32,9 +32,13 @@ import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
+import com.nostra13.universalimageloader.core.DisplayImageOptions;
+import com.nostra13.universalimageloader.core.ImageLoader;
+
import org.fdroid.fdroid.ProgressListener;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.UpdateService;
+import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.data.App;
import org.fdroid.fdroid.data.AppProvider;
import org.fdroid.fdroid.data.Repo;
@@ -48,6 +52,8 @@ public class SwapAppsView extends ListView implements
LoaderManager.LoaderCallbacks,
SearchView.OnQueryTextListener {
+ private DisplayImageOptions displayImageOptions;
+
public SwapAppsView(Context context) {
super(context);
}
@@ -104,6 +110,8 @@ public class SwapAppsView extends ListView implements
}
});
+ displayImageOptions = Utils.getImageLoadingOptions().build();
+
schedulePollForUpdates();
}
@@ -279,46 +287,45 @@ public class SwapAppsView extends ListView implements
TextView nameView = (TextView)view.findViewById(R.id.name);
ImageView iconView = (ImageView)view.findViewById(android.R.id.icon);
- Button button = (Button)view.findViewById(R.id.button);
- TextView status = (TextView)view.findViewById(R.id.status);
+ Button btnInstall = (Button)view.findViewById(R.id.btn_install);
+ TextView btnAttemptInstall = (TextView)view.findViewById(R.id.btn_attempt_install);
+ TextView statusInstalled = (TextView)view.findViewById(R.id.status_installed);
+ TextView statusIncompatible = (TextView)view.findViewById(R.id.status_incompatible);
final App app = new App(cursor);
nameView.setText(app.name);
- iconView.setImageDrawable(getDefaultAppIcon(context)); // TODO: Load icon from repo properly using UIL.
+ ImageLoader.getInstance().displayImage(app.iconUrl, iconView, displayImageOptions);
+
+ btnInstall.setVisibility(View.GONE);
+ btnAttemptInstall.setVisibility(View.GONE);
+ statusInstalled.setVisibility(View.GONE);
+ statusIncompatible.setVisibility(View.GONE);
if (app.hasUpdates()) {
- button.setText(R.string.menu_upgrade);
- button.setEnabled(true);
- button.setBackgroundColor(getResources().getColor(R.color.fdroid_blue));
- button.setVisibility(View.VISIBLE);
- status.setVisibility(View.GONE);
+ btnInstall.setText(R.string.menu_upgrade);
+ btnInstall.setVisibility(View.VISIBLE);
} else if (app.isInstalled()) {
- status.setText(R.string.inst);
- status.setTextColor(getResources().getColor(R.color.fdroid_green));
- status.setVisibility(View.VISIBLE);
- button.setVisibility(View.GONE);
+ statusInstalled.setVisibility(View.VISIBLE);
} else if (!app.compatible) {
- status.setText(R.string.incompatible);
- status.setTextColor(getResources().getColor(R.color.swap_light_grey_icon));
- status.setVisibility(View.VISIBLE);
- button.setVisibility(View.GONE);
+ btnAttemptInstall.setVisibility(View.VISIBLE);
+ statusIncompatible.setVisibility(View.VISIBLE);
} else {
- button.setText(R.string.menu_install);
- button.setEnabled(true);
- button.setBackgroundColor(getResources().getColor(R.color.fdroid_green));
- button.setVisibility(View.VISIBLE);
- status.setVisibility(View.GONE);
+ btnInstall.setText(R.string.menu_install);
+ btnInstall.setVisibility(View.VISIBLE);
}
- button.setOnClickListener(new OnClickListener() {
+ OnClickListener installListener = new OnClickListener() {
@Override
public void onClick(View v) {
if (app.hasUpdates() || app.compatible) {
getState().install(app);
}
}
- });
+ };
+
+ btnInstall.setOnClickListener(installListener);
+ btnAttemptInstall.setOnClickListener(installListener);
}
}
diff --git a/F-Droid/src/org/fdroid/fdroid/views/swap/SwapConnecting.java b/F-Droid/src/org/fdroid/fdroid/views/swap/SwapConnecting.java
index a594847fa..89820fc52 100644
--- a/F-Droid/src/org/fdroid/fdroid/views/swap/SwapConnecting.java
+++ b/F-Droid/src/org/fdroid/fdroid/views/swap/SwapConnecting.java
@@ -61,10 +61,10 @@ public class SwapConnecting extends LinearLayout implements SwapWorkflowActivity
return;
}
- String heading = getContext().getString(R.string.status_connecting_to_repo, getActivity().getState().getPeer().getName());
+ String heading = getContext().getString(R.string.status_connecting_to_repo, peer.getName());
((TextView) findViewById(R.id.heading)).setText(heading);
- UpdateService.UpdateReceiver receiver = getManager().connectTo(peer, true);
+ UpdateService.UpdateReceiver receiver = getManager().connectTo(peer, peer.shouldPromptForSwapBack());
receiver.hideDialog();
receiver.setListener(new ProgressListener() {
diff --git a/F-Droid/src/org/fdroid/fdroid/views/swap/SwapWorkflowActivity.java b/F-Droid/src/org/fdroid/fdroid/views/swap/SwapWorkflowActivity.java
index bbf774896..0eb3b1850 100644
--- a/F-Droid/src/org/fdroid/fdroid/views/swap/SwapWorkflowActivity.java
+++ b/F-Droid/src/org/fdroid/fdroid/views/swap/SwapWorkflowActivity.java
@@ -14,6 +14,7 @@ import android.support.annotation.ColorRes;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import android.support.v4.app.NavUtils;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
@@ -27,6 +28,7 @@ import android.widget.Toast;
import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;
+import org.fdroid.fdroid.AppDetails;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.NfcHelper;
import org.fdroid.fdroid.Preferences;
@@ -41,6 +43,11 @@ import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
+/**
+ * This activity will do its best to show the most relevant screen about swapping to the user.
+ * The problem comes when there are two competing goals - 1) Show the user a list of apps from another
+ * device to download and install, and 2) Prepare your own list of apps to share.
+ */
public class SwapWorkflowActivity extends AppCompatActivity {
/**
@@ -52,6 +59,7 @@ public class SwapWorkflowActivity extends AppCompatActivity {
*/
public static final String EXTRA_PREVENT_FURTHER_SWAP_REQUESTS = "preventFurtherSwap";
public static final String EXTRA_CONFIRM = "EXTRA_CONFIRM";
+ public static final String EXTRA_REPO_ID = "repoId";
private ViewGroup container;
@@ -213,6 +221,9 @@ public class SwapWorkflowActivity extends AppCompatActivity {
case SwapService.STEP_WIFI_QR:
showWifiQr();
break;
+ case SwapService.STEP_SUCCESS:
+ showSwapConnected();
+ break;
}
}
@@ -375,9 +386,7 @@ public class SwapWorkflowActivity extends AppCompatActivity {
*/
public void swapWith(NewRepoConfig repoConfig) {
getService().swapWith(repoConfig.toPeer());
- if (!repoConfig.preventFurtherSwaps()) {
- startSwappingWithPeer();
- }
+ startSwappingWithPeer();
}
public void denySwap() {
@@ -504,4 +513,30 @@ public class SwapWorkflowActivity extends AppCompatActivity {
}
}
+ /**
+ * Only difference from base class is that it navigates up to a different task.
+ * It will go to the {@link org.fdroid.fdroid.views.swap.SwapWorkflowActivity}
+ * whereas the base-class will go back to the main list of apps. Need to juggle
+ * the repoId in order to be able to return to an appropriately configured swap
+ * list.
+ */
+ public static class SwapAppDetails extends AppDetails {
+
+ private long repoId;
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ repoId = getIntent().getLongExtra(EXTRA_REPO_ID, -1);
+ }
+
+ @Override
+ protected void navigateUp() {
+ Intent parentIntent = NavUtils.getParentActivityIntent(this);
+ parentIntent.putExtra(EXTRA_REPO_ID, repoId);
+ NavUtils.navigateUpTo(this, parentIntent);
+ }
+
+ }
+
}