From c0cd0d33bfdbec623cf0c31a83584d409106b141 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 14 Feb 2014 22:40:48 -0500 Subject: [PATCH] send the FDroid.apk via bluetooth on devices that support it This is another easy method to send FDroid to a device that doesn't have it yet. Unfortunately, stock Android blocks the receiving of APKs, but many ROMs and even some Samsung devices do not have this block. You can find the lengthy backstory on this work here: https://dev.guardianproject.info/issues/2084 --- AndroidManifest.xml | 4 ++ res/values/strings.xml | 3 ++ src/org/fdroid/fdroid/FDroid.java | 77 ++++++++++++++++++++++++++++++- 3 files changed, 83 insertions(+), 1 deletion(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 97fa4d86a..e39145c3a 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -26,10 +26,14 @@ + + diff --git a/res/values/strings.xml b/res/values/strings.xml index 0895ad430..680cd375d 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -76,6 +76,8 @@ Getting application from NFC is not enabled! Go to NFC Settings… + No Bluetooth send method found, choose one! + Choose Bluetooth send method Repository address Fingerprint (optional) @@ -92,6 +94,7 @@ Update Repos Repositories + Bluetooth FDroid.apk… Preferences About Search diff --git a/src/org/fdroid/fdroid/FDroid.java b/src/org/fdroid/fdroid/FDroid.java index eaf9db0ac..9156177b9 100644 --- a/src/org/fdroid/fdroid/FDroid.java +++ b/src/org/fdroid/fdroid/FDroid.java @@ -20,14 +20,18 @@ package org.fdroid.fdroid; import android.annotation.TargetApi; +import android.app.Activity; import android.app.AlertDialog; import android.app.AlertDialog.Builder; import android.app.NotificationManager; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothManager; import android.content.*; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.ResolveInfo; import android.content.res.Configuration; import android.database.ContentObserver; import android.net.Uri; @@ -44,6 +48,7 @@ import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.TextView; +import android.widget.Toast; import org.fdroid.fdroid.compat.TabManager; import org.fdroid.fdroid.data.AppProvider; @@ -54,6 +59,7 @@ public class FDroid extends FragmentActivity { public static final int REQUEST_APPDETAILS = 0; public static final int REQUEST_MANAGEREPOS = 1; public static final int REQUEST_PREFS = 2; + public static final int REQUEST_ENABLE_BLUETOOTH = 3; public static final String EXTRA_TAB_UPDATE = "extraTab"; @@ -61,6 +67,10 @@ public class FDroid extends FragmentActivity { private static final int PREFERENCES = Menu.FIRST + 1; private static final int ABOUT = Menu.FIRST + 2; private static final int SEARCH = Menu.FIRST + 3; + private static final int BLUETOOTH_APK = Menu.FIRST + 4; + + /* request codes for Bluetooth flows */ + private BluetoothAdapter mBluetoothAdapter = null; private ViewPager viewPager; @@ -101,6 +111,18 @@ public class FDroid extends FragmentActivity { Uri uri = AppProvider.getContentUri(); getContentResolver().registerContentObserver(uri, true, new AppObserver()); + + getBluetoothAdapter(); + } + + @TargetApi(18) + private void getBluetoothAdapter() { + // to use the new, recommended way of getting the adapter + // http://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html + if (Build.VERSION.SDK_INT < 18) + mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + else + mBluetoothAdapter = ((BluetoothManager) getSystemService(BLUETOOTH_SERVICE)).getAdapter(); } @Override @@ -125,6 +147,8 @@ public class FDroid extends FragmentActivity { android.R.drawable.ic_menu_agenda); MenuItem search = menu.add(Menu.NONE, SEARCH, 3, R.string.menu_search).setIcon( android.R.drawable.ic_menu_search); + if (mBluetoothAdapter != null) // ignore on devices without Bluetooth + menu.add(Menu.NONE, BLUETOOTH_APK, 3, R.string.menu_send_apk_bt); menu.add(Menu.NONE, PREFERENCES, 4, R.string.menu_preferences).setIcon( android.R.drawable.ic_menu_preferences); menu.add(Menu.NONE, ABOUT, 5, R.string.menu_about).setIcon( @@ -152,6 +176,17 @@ public class FDroid extends FragmentActivity { onSearchRequested(); return true; + case BLUETOOTH_APK: + /* + * If Bluetooth has not been enabled/turned on, then + * enabling device discoverability will automatically enable Bluetooth + */ + Intent discoverBt = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); + discoverBt.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 121); + startActivityForResult(discoverBt, REQUEST_ENABLE_BLUETOOTH); + // if this is successful, the Bluetooth transfer is started + return true; + case ABOUT: View view = null; if (Build.VERSION.SDK_INT >= 11) { @@ -259,7 +294,47 @@ public class FDroid extends FragmentActivity { overridePendingTransition(0, 0); startActivity(intent); } - + break; + case REQUEST_ENABLE_BLUETOOTH: + if (resultCode == Activity.RESULT_CANCELED) + break; + String packageName = null; + String className = null; + boolean found = false; + Intent sendBt = null; + try { + PackageManager pm = getPackageManager(); + ApplicationInfo appInfo = pm.getApplicationInfo("org.fdroid.fdroid", + PackageManager.GET_META_DATA); + sendBt = new Intent(Intent.ACTION_SEND); + // The APK type is blocked by stock Android, so use zip + // sendBt.setType("application/vnd.android.package-archive"); + sendBt.setType("application/zip"); + sendBt.putExtra(Intent.EXTRA_STREAM, + Uri.parse("file://" + appInfo.publicSourceDir)); + // not all devices have the same Bluetooth Activities, so + // let's find it + for (ResolveInfo info : pm.queryIntentActivities(sendBt, 0)) { + packageName = info.activityInfo.packageName; + if (packageName.equals("com.android.bluetooth") + || packageName.equals("com.mediatek.bluetooth")) { + className = info.activityInfo.name; + found = true; + break; + } + } + } catch (NameNotFoundException e1) { + e1.printStackTrace(); + found = false; + } + if (!found) { + Toast.makeText(this, R.string.bluetooth_activity_not_found, + Toast.LENGTH_SHORT).show(); + startActivity(Intent.createChooser(sendBt, getString(R.string.choose_bt_send))); + } else { + sendBt.setClassName(packageName, className); + startActivity(sendBt); + } break; } }