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
This commit is contained in:
Hans-Christoph Steiner 2014-02-14 22:40:48 -05:00
parent 0c06b67f3d
commit c0cd0d33bf
3 changed files with 83 additions and 1 deletions

View File

@ -26,10 +26,14 @@
<uses-feature <uses-feature
android:name="android.hardware.nfc" android:name="android.hardware.nfc"
android:required="false" /> android:required="false" />
<uses-feature
android:name="android.hardware.bluetooth"
android:required="false" />
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.NFC" /> <uses-permission android:name="android.permission.NFC" />

View File

@ -76,6 +76,8 @@
<string name="download_server">Getting application from</string> <string name="download_server">Getting application from</string>
<string name="nfc_is_not_enabled">NFC is not enabled!</string> <string name="nfc_is_not_enabled">NFC is not enabled!</string>
<string name="go_to_nfc_settings">Go to NFC Settings…</string> <string name="go_to_nfc_settings">Go to NFC Settings…</string>
<string name="bluetooth_activity_not_found">No Bluetooth send method found, choose one!</string>
<string name="choose_bt_send">Choose Bluetooth send method</string>
<string name="repo_add_url">Repository address</string> <string name="repo_add_url">Repository address</string>
<string name="repo_add_fingerprint">Fingerprint (optional)</string> <string name="repo_add_fingerprint">Fingerprint (optional)</string>
@ -92,6 +94,7 @@
<string name="menu_update_repo">Update Repos</string> <string name="menu_update_repo">Update Repos</string>
<string name="menu_manage">Repositories</string> <string name="menu_manage">Repositories</string>
<string name="menu_send_apk_bt">Bluetooth FDroid.apk…</string>
<string name="menu_preferences">Preferences</string> <string name="menu_preferences">Preferences</string>
<string name="menu_about">About</string> <string name="menu_about">About</string>
<string name="menu_search">Search</string> <string name="menu_search">Search</string>

View File

@ -20,14 +20,18 @@
package org.fdroid.fdroid; package org.fdroid.fdroid;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.AlertDialog.Builder; import android.app.AlertDialog.Builder;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothManager;
import android.content.*; import android.content.*;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.database.ContentObserver; import android.database.ContentObserver;
import android.net.Uri; import android.net.Uri;
@ -44,6 +48,7 @@ import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast;
import org.fdroid.fdroid.compat.TabManager; import org.fdroid.fdroid.compat.TabManager;
import org.fdroid.fdroid.data.AppProvider; 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_APPDETAILS = 0;
public static final int REQUEST_MANAGEREPOS = 1; public static final int REQUEST_MANAGEREPOS = 1;
public static final int REQUEST_PREFS = 2; public static final int REQUEST_PREFS = 2;
public static final int REQUEST_ENABLE_BLUETOOTH = 3;
public static final String EXTRA_TAB_UPDATE = "extraTab"; 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 PREFERENCES = Menu.FIRST + 1;
private static final int ABOUT = Menu.FIRST + 2; private static final int ABOUT = Menu.FIRST + 2;
private static final int SEARCH = Menu.FIRST + 3; 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; private ViewPager viewPager;
@ -101,6 +111,18 @@ public class FDroid extends FragmentActivity {
Uri uri = AppProvider.getContentUri(); Uri uri = AppProvider.getContentUri();
getContentResolver().registerContentObserver(uri, true, new AppObserver()); 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 @Override
@ -125,6 +147,8 @@ public class FDroid extends FragmentActivity {
android.R.drawable.ic_menu_agenda); android.R.drawable.ic_menu_agenda);
MenuItem search = menu.add(Menu.NONE, SEARCH, 3, R.string.menu_search).setIcon( MenuItem search = menu.add(Menu.NONE, SEARCH, 3, R.string.menu_search).setIcon(
android.R.drawable.ic_menu_search); 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( menu.add(Menu.NONE, PREFERENCES, 4, R.string.menu_preferences).setIcon(
android.R.drawable.ic_menu_preferences); android.R.drawable.ic_menu_preferences);
menu.add(Menu.NONE, ABOUT, 5, R.string.menu_about).setIcon( menu.add(Menu.NONE, ABOUT, 5, R.string.menu_about).setIcon(
@ -152,6 +176,17 @@ public class FDroid extends FragmentActivity {
onSearchRequested(); onSearchRequested();
return true; 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: case ABOUT:
View view = null; View view = null;
if (Build.VERSION.SDK_INT >= 11) { if (Build.VERSION.SDK_INT >= 11) {
@ -259,7 +294,47 @@ public class FDroid extends FragmentActivity {
overridePendingTransition(0, 0); overridePendingTransition(0, 0);
startActivity(intent); 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; break;
} }
} }