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.
This commit is contained in:
n8fr8 2015-09-10 14:44:59 -04:00
parent 0a96d17dd1
commit b3f8ac0a5b
14 changed files with 77 additions and 14 deletions

View File

@ -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 {

View File

@ -456,7 +456,7 @@ public class SwapService extends Service {
}
public boolean isBluetoothDiscoverable() {
return bluetoothSwap.isConnected();
return bluetoothSwap.isDiscoverable();
}
public boolean isBonjourDiscoverable() {

View File

@ -15,6 +15,8 @@ public class BluetoothFinder extends PeerFinder<BluetoothPeer> {
private static final String TAG = "BluetoothFinder";
public final static int DISCOVERABLE_TIMEOUT = 3600;
private final BluetoothAdapter adapter;
public BluetoothFinder(Context context) {

View File

@ -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;
}
}
}

View File

@ -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;

View File

@ -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();
}
}

View File

@ -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 {

View File

@ -167,4 +167,8 @@ public class HttpDownloader extends Downloader {
return statusCode;
}
public void close ()
{
connection.disconnect();
}
}

View File

@ -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);
}
}

View File

@ -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.

View File

@ -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();
}
}

View File

@ -137,6 +137,8 @@ public class BluetoothServer extends Thread {
break;
}
connection.closeQuietly();
}
private Response handleRequest(Request request) throws IOException {

View File

@ -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);

View File

@ -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);
}