Merge branch 'master' into 'master'
send any installed app via NFC/Beam or Bluetooth Building upon the NFC+Bluetooth sending of the FDroid.apk, these two commits allow the user to send any installed app via Bluetooth or NFC/Android Beam.
This commit is contained in:
commit
e3e726e56c
@ -96,9 +96,8 @@
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".ManageRepo"
|
||||
android:allowTaskReparenting="true"
|
||||
android:label="@string/menu_manage"
|
||||
android:launchMode="singleTop"
|
||||
android:launchMode="singleTask"
|
||||
android:parentActivityName=".FDroid" >
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
|
@ -78,6 +78,7 @@
|
||||
<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="send_via_bluetooth">Send via Bluetooth</string>
|
||||
|
||||
<string name="repo_add_url">Repository address</string>
|
||||
<string name="repo_add_fingerprint">Fingerprint (optional)</string>
|
||||
|
@ -19,11 +19,6 @@
|
||||
|
||||
package org.fdroid.fdroid;
|
||||
|
||||
import java.io.File;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import android.content.*;
|
||||
import android.widget.*;
|
||||
import org.fdroid.fdroid.data.*;
|
||||
@ -33,12 +28,17 @@ import android.annotation.TargetApi;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.ListActivity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.net.Uri;
|
||||
import android.nfc.NfcAdapter;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v4.app.NavUtils;
|
||||
import android.support.v4.view.MenuItemCompat;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.Signature;
|
||||
@ -58,26 +58,31 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
import android.support.v4.app.NavUtils;
|
||||
import android.support.v4.view.MenuItemCompat;
|
||||
|
||||
import org.fdroid.fdroid.compat.PackageManagerCompat;
|
||||
import org.fdroid.fdroid.compat.ActionBarCompat;
|
||||
import org.fdroid.fdroid.compat.MenuManager;
|
||||
import org.fdroid.fdroid.Utils.CommaSeparatedList;
|
||||
|
||||
import com.nostra13.universalimageloader.core.DisplayImageOptions;
|
||||
import com.nostra13.universalimageloader.core.ImageLoader;
|
||||
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
|
||||
|
||||
import org.fdroid.fdroid.Utils.CommaSeparatedList;
|
||||
import org.fdroid.fdroid.compat.ActionBarCompat;
|
||||
import org.fdroid.fdroid.compat.MenuManager;
|
||||
import org.fdroid.fdroid.compat.PackageManagerCompat;
|
||||
|
||||
import java.io.File;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public class AppDetails extends ListActivity {
|
||||
private static final String TAG = "AppDetails";
|
||||
|
||||
private static final int REQUEST_INSTALL = 0;
|
||||
private static final int REQUEST_UNINSTALL = 1;
|
||||
public static final int REQUEST_ENABLE_BLUETOOTH = 2;
|
||||
|
||||
public static final String EXTRA_APPID = "appid";
|
||||
public static final String EXTRA_FROM = "from";
|
||||
|
||||
private FDroidApp fdroidApp;
|
||||
private ApkListAdapter adapter;
|
||||
|
||||
private static class ViewHolder {
|
||||
@ -234,6 +239,7 @@ public class AppDetails extends ListActivity {
|
||||
private static final int DOGECOIN = Menu.FIRST + 12;
|
||||
private static final int FLATTR = Menu.FIRST + 13;
|
||||
private static final int DONATE_URL = Menu.FIRST + 14;
|
||||
private static final int SEND_VIA_BLUETOOTH = Menu.FIRST + 15;
|
||||
|
||||
private App app;
|
||||
private String appid;
|
||||
@ -253,7 +259,8 @@ public class AppDetails extends ListActivity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
|
||||
((FDroidApp) getApplication()).applyTheme(this);
|
||||
fdroidApp = ((FDroidApp) getApplication());
|
||||
fdroidApp.applyTheme(this);
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
@ -624,11 +631,14 @@ public class AppDetails extends ListActivity {
|
||||
adapter.notifyDataSetChanged();
|
||||
|
||||
TextView tv = (TextView) findViewById(R.id.status);
|
||||
if (!app.isInstalled())
|
||||
tv.setText(getString(R.string.details_notinstalled));
|
||||
else
|
||||
if (app.isInstalled()) {
|
||||
tv.setText(getString(R.string.details_installed,
|
||||
app.installedVersionName));
|
||||
NfcBeamManager.setAndroidBeam(this, app.id);
|
||||
} else {
|
||||
tv.setText(getString(R.string.details_notinstalled));
|
||||
NfcBeamManager.disableAndroidBeam(this);
|
||||
}
|
||||
|
||||
tv = (TextView) infoView.findViewById(R.id.signature);
|
||||
if (pref_expert && mInstalledSignature != null) {
|
||||
@ -755,6 +765,9 @@ public class AppDetails extends ListActivity {
|
||||
if (app.donateURL != null)
|
||||
donate.add(Menu.NONE, DONATE_URL, 10, R.string.menu_website);
|
||||
}
|
||||
if (app.isInstalled() && fdroidApp.bluetoothAdapter != null) { // ignore on devices without Bluetooth
|
||||
menu.add(Menu.NONE, SEND_VIA_BLUETOOTH, 6, R.string.send_via_bluetooth);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -845,6 +858,17 @@ public class AppDetails extends ListActivity {
|
||||
tryOpenUri(app.donateURL);
|
||||
return true;
|
||||
|
||||
case SEND_VIA_BLUETOOTH:
|
||||
/*
|
||||
* 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;
|
||||
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
@ -1099,7 +1123,8 @@ public class AppDetails extends ListActivity {
|
||||
case REQUEST_UNINSTALL:
|
||||
resetRequired = true;
|
||||
break;
|
||||
case REQUEST_ENABLE_BLUETOOTH:
|
||||
fdroidApp.sendViaBluetooth(this, resultCode, app.id);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -20,18 +20,15 @@
|
||||
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;
|
||||
@ -48,7 +45,6 @@ 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;
|
||||
@ -70,8 +66,7 @@ public class FDroid extends FragmentActivity {
|
||||
private static final int SEARCH = Menu.FIRST + 4;
|
||||
private static final int BLUETOOTH_APK = Menu.FIRST + 5;
|
||||
|
||||
/* request codes for Bluetooth flows */
|
||||
private BluetoothAdapter mBluetoothAdapter = null;
|
||||
private FDroidApp fdroidApp = null;
|
||||
|
||||
private ViewPager viewPager;
|
||||
|
||||
@ -80,7 +75,8 @@ public class FDroid extends FragmentActivity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
|
||||
((FDroidApp) getApplication()).applyTheme(this);
|
||||
fdroidApp = ((FDroidApp) getApplication());
|
||||
fdroidApp.applyTheme(this);
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.fdroid);
|
||||
@ -112,26 +108,13 @@ 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
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
// RepoDetailsActivity sets a different beam, so reset here
|
||||
if (Build.VERSION.SDK_INT >= 16)
|
||||
setupAndroidBeam();
|
||||
// AppDetails and RepoDetailsActivity set different NFC actions, so reset here
|
||||
NfcBeamManager.setAndroidBeam(this, getApplication().getPackageName());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -150,7 +133,7 @@ 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
|
||||
if (fdroidApp.bluetoothAdapter != 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);
|
||||
@ -299,45 +282,7 @@ public class FDroid extends FragmentActivity {
|
||||
}
|
||||
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);
|
||||
}
|
||||
fdroidApp.sendViaBluetooth(this, resultCode, "org.fdroid.fdroid");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -422,23 +367,4 @@ public class FDroid extends FragmentActivity {
|
||||
|
||||
}
|
||||
|
||||
@TargetApi(16)
|
||||
private void setupAndroidBeam() {
|
||||
PackageManager pm = getPackageManager();
|
||||
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
|
||||
if (nfcAdapter != null) {
|
||||
ApplicationInfo appInfo;
|
||||
try {
|
||||
appInfo = pm.getApplicationInfo("org.fdroid.fdroid",
|
||||
PackageManager.GET_META_DATA);
|
||||
// TODO can we send the repo here also, as a file?
|
||||
Uri uris[] = {
|
||||
Uri.parse("file://" + appInfo.publicSourceDir),
|
||||
};
|
||||
nfcAdapter.setBeamPushUris(uris, this);
|
||||
} catch (NameNotFoundException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,17 +18,31 @@
|
||||
|
||||
package org.fdroid.fdroid;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.app.Application;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothManager;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.nostra13.universalimageloader.cache.disc.impl.LimitedAgeDiscCache;
|
||||
import com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator;
|
||||
import com.nostra13.universalimageloader.core.ImageLoader;
|
||||
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
|
||||
import com.nostra13.universalimageloader.utils.StorageUtils;
|
||||
|
||||
import de.duenndns.ssl.MemorizingTrustManager;
|
||||
|
||||
import org.fdroid.fdroid.compat.PRNGFixes;
|
||||
import org.fdroid.fdroid.data.AppProvider;
|
||||
import org.fdroid.fdroid.data.InstalledAppCacheUpdater;
|
||||
@ -44,6 +58,8 @@ import java.security.NoSuchAlgorithmException;
|
||||
|
||||
public class FDroidApp extends Application {
|
||||
|
||||
BluetoothAdapter bluetoothAdapter = null;
|
||||
|
||||
private static enum Theme {
|
||||
dark, light
|
||||
}
|
||||
@ -121,6 +137,7 @@ public class FDroidApp extends Application {
|
||||
}
|
||||
|
||||
UpdateService.schedule(getApplicationContext());
|
||||
bluetoothAdapter = getBluetoothAdapter();
|
||||
|
||||
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())
|
||||
.discCache(new LimitedAgeDiscCache(
|
||||
@ -179,4 +196,55 @@ public class FDroidApp extends Application {
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(18)
|
||||
private BluetoothAdapter 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)
|
||||
return BluetoothAdapter.getDefaultAdapter();
|
||||
else
|
||||
return ((BluetoothManager) getSystemService(BLUETOOTH_SERVICE)).getAdapter();
|
||||
}
|
||||
|
||||
void sendViaBluetooth(Activity activity, int resultCode, String packageName) {
|
||||
if (resultCode == Activity.RESULT_CANCELED)
|
||||
return;
|
||||
String bluetoothPackageName = null;
|
||||
String className = null;
|
||||
boolean found = false;
|
||||
Intent sendBt = null;
|
||||
try {
|
||||
PackageManager pm = getPackageManager();
|
||||
ApplicationInfo appInfo = pm.getApplicationInfo(packageName,
|
||||
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)) {
|
||||
bluetoothPackageName = info.activityInfo.packageName;
|
||||
if (bluetoothPackageName.equals("com.android.bluetooth")
|
||||
|| bluetoothPackageName.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();
|
||||
activity.startActivity(Intent.createChooser(sendBt, getString(R.string.choose_bt_send)));
|
||||
} else {
|
||||
sendBt.setClassName(bluetoothPackageName, className);
|
||||
activity.startActivity(sendBt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
43
src/org/fdroid/fdroid/NfcBeamManager.java
Normal file
43
src/org/fdroid/fdroid/NfcBeamManager.java
Normal file
@ -0,0 +1,43 @@
|
||||
|
||||
package org.fdroid.fdroid;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.net.Uri;
|
||||
import android.nfc.NfcAdapter;
|
||||
import android.os.Build;
|
||||
|
||||
@TargetApi(16)
|
||||
public class NfcBeamManager {
|
||||
|
||||
static void setAndroidBeam(Activity activity, String packageName) {
|
||||
if (Build.VERSION.SDK_INT < 16)
|
||||
return;
|
||||
PackageManager pm = activity.getPackageManager();
|
||||
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(activity);
|
||||
if (nfcAdapter != null) {
|
||||
ApplicationInfo appInfo;
|
||||
try {
|
||||
appInfo = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
|
||||
Uri uris[] = {
|
||||
Uri.parse("file://" + appInfo.publicSourceDir),
|
||||
};
|
||||
nfcAdapter.setBeamPushUris(uris, activity);
|
||||
} catch (NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void disableAndroidBeam(Activity activity) {
|
||||
if (Build.VERSION.SDK_INT < 16)
|
||||
return;
|
||||
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(activity);
|
||||
if (nfcAdapter != null)
|
||||
nfcAdapter.setBeamPushUris(null, activity);
|
||||
}
|
||||
|
||||
}
|
@ -69,14 +69,12 @@ public class RepoDetailsActivity extends FragmentActivity {
|
||||
setTitle(repo.getName());
|
||||
|
||||
wifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
|
||||
|
||||
// required NFC support starts in android-14
|
||||
if (Build.VERSION.SDK_INT >= 14)
|
||||
setNfc();
|
||||
}
|
||||
|
||||
@TargetApi(14)
|
||||
private void setNfc() {
|
||||
if (Build.VERSION.SDK_INT < 14)
|
||||
return;
|
||||
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
|
||||
if (nfcAdapter == null) {
|
||||
return;
|
||||
@ -97,8 +95,9 @@ public class RepoDetailsActivity extends FragmentActivity {
|
||||
public void onResume() {
|
||||
Log.i(TAG, "onResume");
|
||||
super.onResume();
|
||||
if (Build.VERSION.SDK_INT >= 9)
|
||||
processIntent(getIntent());
|
||||
// FDroid.java and AppDetails set different NFC actions, so reset here
|
||||
setNfc();
|
||||
processIntent(getIntent());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -112,6 +111,8 @@ public class RepoDetailsActivity extends FragmentActivity {
|
||||
|
||||
@TargetApi(9)
|
||||
void processIntent(Intent i) {
|
||||
if (Build.VERSION.SDK_INT < 9)
|
||||
return;
|
||||
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(i.getAction())) {
|
||||
Log.i(TAG, "ACTION_NDEF_DISCOVERED");
|
||||
Parcelable[] rawMsgs =
|
||||
|
Loading…
x
Reference in New Issue
Block a user