From b3f8ac0a5bfe1f75bc3d2dc1e413f2bdfcb0aaff Mon Sep 17 00:00:00 2001 From: n8fr8 Date: Thu, 10 Sep 2015 14:44:59 -0400 Subject: [PATCH] related to #404 improvement to patterns to support close and discoverable You must, must, must close the BT sockets else you run out of them. This code tries to handle all the places where BT sockets may not get closed. It also tries to tweak user experience/UI integration pieces in a few areas, and handle some NPEs that can occur when BT fails. --- .../src/org/fdroid/fdroid/RepoUpdater.java | 4 ++++ .../fdroid/fdroid/localrepo/SwapService.java | 2 +- .../localrepo/peers/BluetoothFinder.java | 2 ++ .../fdroid/localrepo/type/BluetoothSwap.java | 8 +++++++ .../fdroid/localrepo/type/SwapType.java | 5 +++++ .../fdroid/net/BluetoothDownloader.java | 8 +++++++ .../src/org/fdroid/fdroid/net/Downloader.java | 1 + .../org/fdroid/fdroid/net/HttpDownloader.java | 4 ++++ .../org/fdroid/fdroid/net/IconDownloader.java | 21 ++++++++++++++++++- .../fdroid/net/bluetooth/BluetoothClient.java | 13 ++++++++++-- .../net/bluetooth/BluetoothConnection.java | 8 +------ .../fdroid/net/bluetooth/BluetoothServer.java | 2 ++ .../fdroid/views/swap/SwapAppsView.java | 10 +++++++-- .../views/swap/SwapWorkflowActivity.java | 3 ++- 14 files changed, 77 insertions(+), 14 deletions(-) diff --git a/F-Droid/src/org/fdroid/fdroid/RepoUpdater.java b/F-Droid/src/org/fdroid/fdroid/RepoUpdater.java index a3eb101d6..3c4fe6219 100644 --- a/F-Droid/src/org/fdroid/fdroid/RepoUpdater.java +++ b/F-Droid/src/org/fdroid/fdroid/RepoUpdater.java @@ -98,7 +98,9 @@ public class RepoUpdater { } catch (IOException e) { if (downloader != null && downloader.getFile() != null) { downloader.getFile().delete(); + downloader.close(); } + throw new UpdateException(repo, "Error getting index file from " + repo.address, e); } return downloader; @@ -121,6 +123,8 @@ public class RepoUpdater { // successful download, then we will have a file ready to use: processDownloadedFile(downloader.getFile(), downloader.getCacheTag()); } + + downloader.close(); } protected void processDownloadedFile(File downloadedFile, String cacheTag) throws UpdateException { diff --git a/F-Droid/src/org/fdroid/fdroid/localrepo/SwapService.java b/F-Droid/src/org/fdroid/fdroid/localrepo/SwapService.java index 0be6ac6ea..5b2072688 100644 --- a/F-Droid/src/org/fdroid/fdroid/localrepo/SwapService.java +++ b/F-Droid/src/org/fdroid/fdroid/localrepo/SwapService.java @@ -456,7 +456,7 @@ public class SwapService extends Service { } public boolean isBluetoothDiscoverable() { - return bluetoothSwap.isConnected(); + return bluetoothSwap.isDiscoverable(); } public boolean isBonjourDiscoverable() { diff --git a/F-Droid/src/org/fdroid/fdroid/localrepo/peers/BluetoothFinder.java b/F-Droid/src/org/fdroid/fdroid/localrepo/peers/BluetoothFinder.java index 2bc86a8bd..bfb91127b 100644 --- a/F-Droid/src/org/fdroid/fdroid/localrepo/peers/BluetoothFinder.java +++ b/F-Droid/src/org/fdroid/fdroid/localrepo/peers/BluetoothFinder.java @@ -15,6 +15,8 @@ public class BluetoothFinder extends PeerFinder { private static final String TAG = "BluetoothFinder"; + public final static int DISCOVERABLE_TIMEOUT = 3600; + private final BluetoothAdapter adapter; public BluetoothFinder(Context context) { diff --git a/F-Droid/src/org/fdroid/fdroid/localrepo/type/BluetoothSwap.java b/F-Droid/src/org/fdroid/fdroid/localrepo/type/BluetoothSwap.java index 333fca470..c66531cf2 100644 --- a/F-Droid/src/org/fdroid/fdroid/localrepo/type/BluetoothSwap.java +++ b/F-Droid/src/org/fdroid/fdroid/localrepo/type/BluetoothSwap.java @@ -23,6 +23,7 @@ public class BluetoothSwap extends SwapType { @NonNull private final BluetoothAdapter adapter; private BroadcastReceiver receiver; + private boolean isDiscoverable = false; @Nullable private BluetoothServer server; @@ -48,6 +49,11 @@ public class BluetoothSwap extends SwapType { } + @Override + public boolean isDiscoverable () { + return isDiscoverable; + } + @Override public boolean isConnected() { return server != null && server.isRunning() && super.isConnected(); @@ -68,6 +74,7 @@ public class BluetoothSwap extends SwapType { break; case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE: + isDiscoverable = true; if (server != null && server.isRunning()) { setConnected(true); } @@ -163,5 +170,6 @@ public class BluetoothSwap extends SwapType { protected String getBroadcastAction() { return null; } + } } diff --git a/F-Droid/src/org/fdroid/fdroid/localrepo/type/SwapType.java b/F-Droid/src/org/fdroid/fdroid/localrepo/type/SwapType.java index afb82b1a3..89e03a041 100644 --- a/F-Droid/src/org/fdroid/fdroid/localrepo/type/SwapType.java +++ b/F-Droid/src/org/fdroid/fdroid/localrepo/type/SwapType.java @@ -33,6 +33,11 @@ public abstract class SwapType { abstract protected String getBroadcastAction(); + public boolean isDiscoverable () + { + return isConnected(); + } + protected final void setConnected(boolean connected) { if (connected) { isConnected = true; diff --git a/F-Droid/src/org/fdroid/fdroid/net/BluetoothDownloader.java b/F-Droid/src/org/fdroid/fdroid/net/BluetoothDownloader.java index 610a30ee4..498b69214 100644 --- a/F-Droid/src/org/fdroid/fdroid/net/BluetoothDownloader.java +++ b/F-Droid/src/org/fdroid/fdroid/net/BluetoothDownloader.java @@ -48,6 +48,7 @@ public class BluetoothDownloader extends Downloader { // to us). BoundedInputStream stream = new BoundedInputStream(response.toContentStream(), fileDetails.getFileSize()); stream.setPropagateClose(false); + return stream; } @@ -95,4 +96,11 @@ public class BluetoothDownloader extends Downloader { ); } + @Override + public void close () + { + if (connection != null) + connection.closeQuietly(); + } + } diff --git a/F-Droid/src/org/fdroid/fdroid/net/Downloader.java b/F-Droid/src/org/fdroid/fdroid/net/Downloader.java index ffe250669..470dfd698 100644 --- a/F-Droid/src/org/fdroid/fdroid/net/Downloader.java +++ b/F-Droid/src/org/fdroid/fdroid/net/Downloader.java @@ -40,6 +40,7 @@ public abstract class Downloader { protected int totalBytes = 0; public abstract InputStream getInputStream() throws IOException; + public abstract void close(); Downloader(Context context, URL url, File destFile) throws FileNotFoundException, MalformedURLException { diff --git a/F-Droid/src/org/fdroid/fdroid/net/HttpDownloader.java b/F-Droid/src/org/fdroid/fdroid/net/HttpDownloader.java index 495827e6e..6aa5f857d 100644 --- a/F-Droid/src/org/fdroid/fdroid/net/HttpDownloader.java +++ b/F-Droid/src/org/fdroid/fdroid/net/HttpDownloader.java @@ -167,4 +167,8 @@ public class HttpDownloader extends Downloader { return statusCode; } + public void close () + { + connection.disconnect(); + } } diff --git a/F-Droid/src/org/fdroid/fdroid/net/IconDownloader.java b/F-Droid/src/org/fdroid/fdroid/net/IconDownloader.java index 334ceb314..3a20304e1 100644 --- a/F-Droid/src/org/fdroid/fdroid/net/IconDownloader.java +++ b/F-Droid/src/org/fdroid/fdroid/net/IconDownloader.java @@ -3,7 +3,10 @@ package org.fdroid.fdroid.net; import android.content.Context; import com.nostra13.universalimageloader.core.download.BaseImageDownloader; +import com.nostra13.universalimageloader.utils.IoUtils; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; @@ -33,11 +36,27 @@ public class IconDownloader extends BaseImageDownloader { if (imageUri.toLowerCase().startsWith("bluetooth")) { Downloader downloader = DownloaderFactory.create(context, imageUri); - return downloader.getInputStream(); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + InputStream is = downloader.getInputStream(); + + int b = -1; + + while ((b = is.read())!=-1) + baos.write(b); + + ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); + + downloader.close(); + + return bais; + } return super.getStream(imageUri, extra); } + + } diff --git a/F-Droid/src/org/fdroid/fdroid/net/bluetooth/BluetoothClient.java b/F-Droid/src/org/fdroid/fdroid/net/bluetooth/BluetoothClient.java index 831ed64f0..81a590195 100644 --- a/F-Droid/src/org/fdroid/fdroid/net/bluetooth/BluetoothClient.java +++ b/F-Droid/src/org/fdroid/fdroid/net/bluetooth/BluetoothClient.java @@ -28,12 +28,20 @@ public class BluetoothClient { BluetoothSocket socket = null; + BluetoothConnection connection = null; try { socket = device.createInsecureRfcommSocketToServiceRecord(BluetoothConstants.fdroidUuid()); - BluetoothConnection connection = new BluetoothConnection(socket); + connection = new BluetoothConnection(socket); connection.open(); return connection; } catch (IOException e1) { + + if (connection != null) + connection.closeQuietly(); + + throw e1; + + /* Log.e(TAG, "There was an error while establishing Bluetooth connection. Falling back to using reflection..."); Class clazz = socket.getRemoteDevice().getClass(); Class[] paramTypes = new Class[]{Integer.TYPE}; @@ -43,6 +51,7 @@ public class BluetoothClient { method = clazz.getMethod("createInsecureRfcommSocket", paramTypes); Object[] params = new Object[]{1}; BluetoothSocket sockFallback = (BluetoothSocket) method.invoke(socket.getRemoteDevice(), params); + BluetoothConnection connection = new BluetoothConnection(sockFallback); connection.open(); return connection; @@ -52,7 +61,7 @@ public class BluetoothClient { throw e1; } catch (InvocationTargetException e) { throw e1; - } + }*/ // Don't catch exceptions this time, let it bubble up as we did our best but don't // have anythign else to offer in terms of resolving the problem right now. diff --git a/F-Droid/src/org/fdroid/fdroid/net/bluetooth/BluetoothConnection.java b/F-Droid/src/org/fdroid/fdroid/net/bluetooth/BluetoothConnection.java index fec164087..ca6fef59a 100644 --- a/F-Droid/src/org/fdroid/fdroid/net/bluetooth/BluetoothConnection.java +++ b/F-Droid/src/org/fdroid/fdroid/net/bluetooth/BluetoothConnection.java @@ -53,12 +53,6 @@ public class BluetoothConnection { } public void close() throws IOException { - if (input == null || output == null) { - throw new RuntimeException("Cannot close() a BluetoothConnection before calling open()" ); - } - - input.close(); - output.close(); - socket.close(); + closeQuietly(); } } \ No newline at end of file diff --git a/F-Droid/src/org/fdroid/fdroid/net/bluetooth/BluetoothServer.java b/F-Droid/src/org/fdroid/fdroid/net/bluetooth/BluetoothServer.java index a895dfd98..71a8b0bab 100644 --- a/F-Droid/src/org/fdroid/fdroid/net/bluetooth/BluetoothServer.java +++ b/F-Droid/src/org/fdroid/fdroid/net/bluetooth/BluetoothServer.java @@ -137,6 +137,8 @@ public class BluetoothServer extends Thread { break; } + connection.closeQuietly(); + } private Response handleRequest(Request request) throws IOException { 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 87a577d1b..bb7161be2 100644 --- a/F-Droid/src/org/fdroid/fdroid/views/swap/SwapAppsView.java +++ b/F-Droid/src/org/fdroid/fdroid/views/swap/SwapAppsView.java @@ -283,7 +283,7 @@ public class SwapAppsView extends ListView implements Apk apk = getApkToInstall(); String broadcastUrl = intent.getStringExtra(Downloader.EXTRA_ADDRESS); - if (apk.repoAddress != null && (!TextUtils.equals(Utils.getApkUrl(apk.repoAddress, apk), broadcastUrl))) { + if (apk != null && apk.repoAddress != null && (!TextUtils.equals(Utils.getApkUrl(apk.repoAddress, apk), broadcastUrl))) { return; } @@ -374,9 +374,15 @@ public class SwapAppsView extends ListView implements private void resetView() { + if (app == null) + return; + progressView.setVisibility(View.GONE); progressView.setIndeterminate(true); - nameView.setText(app.name); + + if (app.name != null) + nameView.setText(app.name); + ImageLoader.getInstance().displayImage(app.iconUrl, iconView, displayImageOptions); btnInstall.setVisibility(View.GONE); 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 6b0cbca16..729d995e9 100644 --- a/F-Droid/src/org/fdroid/fdroid/views/swap/SwapWorkflowActivity.java +++ b/F-Droid/src/org/fdroid/fdroid/views/swap/SwapWorkflowActivity.java @@ -44,6 +44,7 @@ import org.fdroid.fdroid.data.NewRepoConfig; import org.fdroid.fdroid.installer.Installer; import org.fdroid.fdroid.localrepo.LocalRepoManager; import org.fdroid.fdroid.localrepo.SwapService; +import org.fdroid.fdroid.localrepo.peers.BluetoothFinder; import org.fdroid.fdroid.localrepo.peers.Peer; import org.fdroid.fdroid.net.ApkDownloader; @@ -625,7 +626,7 @@ public class SwapWorkflowActivity extends AppCompatActivity { Log.d(TAG, "Not currently in discoverable mode, so prompting user to enable."); Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); - intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 3600); // 3600 is new maximum! TODO: What about when this expires? What if user manually disables discovery? + intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, BluetoothFinder.DISCOVERABLE_TIMEOUT); // 3600 is new maximum! TODO: What about when this expires? What if user manually disables discovery? startActivityForResult(intent, REQUEST_BLUETOOTH_DISCOVERABLE); }