Merge branch '1.2-polish' into 'master'
1.2 polish See merge request fdroid/fdroidclient!670
This commit is contained in:
commit
f181e41338
@ -471,6 +471,8 @@
|
||||
<data android:pathPattern="/.*/.*/fdroid/repo/*"/>
|
||||
<data android:pathPattern="/.*/.*/.*/fdroid/repo"/>
|
||||
<data android:pathPattern="/.*/.*/.*/fdroid/repo/*"/>
|
||||
<data android:pathPattern="/.*/.*/.*/.*/fdroid/repo"/>
|
||||
<data android:pathPattern="/.*/.*/.*/.*/fdroid/repo/*"/>
|
||||
<data android:path="/fdroid/archive"/>
|
||||
<data android:pathPattern="/fdroid/archive/*"/>
|
||||
<data android:pathPattern="/.*/fdroid/archive"/>
|
||||
@ -479,6 +481,8 @@
|
||||
<data android:pathPattern="/.*/.*/fdroid/archive/*"/>
|
||||
<data android:pathPattern="/.*/.*/.*/fdroid/archive"/>
|
||||
<data android:pathPattern="/.*/.*/.*/fdroid/archive/*"/>
|
||||
<data android:pathPattern="/.*/.*/.*/.*/fdroid/archive"/>
|
||||
<data android:pathPattern="/.*/.*/.*/.*/fdroid/archive/*"/>
|
||||
<!--
|
||||
Some QR Code scanners don't respect custom schemes like fdroidrepo://,
|
||||
so this is a workaround, since the local repo URL is all uppercase in
|
||||
|
@ -56,7 +56,6 @@ public class AppUpdateStatusService extends IntentService {
|
||||
if (cacheDirList == null) {
|
||||
return;
|
||||
}
|
||||
PackageManager packageManager = getPackageManager();
|
||||
List<Apk> apksReadyToInstall = new ArrayList<>();
|
||||
for (String repoDirName : cacheDirList) {
|
||||
File repoDir = new File(cacheDir, repoDirName);
|
||||
@ -67,12 +66,7 @@ public class AppUpdateStatusService extends IntentService {
|
||||
for (String apkFileName : apks) {
|
||||
Apk apk = processDownloadedApk(new File(repoDir, apkFileName));
|
||||
if (apk != null) {
|
||||
PackageInfo packageInfo = null;
|
||||
try {
|
||||
packageInfo = packageManager.getPackageInfo(apk.packageName, 0);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
// ignored
|
||||
}
|
||||
PackageInfo packageInfo = Utils.getPackageInfo(this, apk.packageName);
|
||||
if (packageInfo == null || packageInfo.versionCode != apk.versionCode) {
|
||||
Utils.debugLog(TAG, "Marking downloaded apk " + apk.apkName + " as ReadyToInstall");
|
||||
apksReadyToInstall.add(apk);
|
||||
@ -134,8 +128,8 @@ public class AppUpdateStatusService extends IntentService {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
PackageInfo info = getPackageManager().getPackageInfo(downloadedApk.packageName, 0);
|
||||
PackageInfo info = Utils.getPackageInfo(this, downloadedApk.packageName);
|
||||
if (info != null) {
|
||||
File pathToInstalled = InstalledAppProviderService.getPathToInstalledApk(info);
|
||||
if (pathToInstalled != null && pathToInstalled.canRead() &&
|
||||
pathToInstalled.length() == downloadedApk.size && // Check size before hash for performance.
|
||||
@ -145,7 +139,6 @@ public class AppUpdateStatusService extends IntentService {
|
||||
AppUpdateStatusManager.getInstance(this).markAsNoLongerPendingInstall(downloadedApk.getUrl());
|
||||
return null;
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException ignored) {
|
||||
}
|
||||
|
||||
Utils.debugLog(TAG, downloadedApk.packageName + ':' + downloadedApk.versionCode
|
||||
|
@ -26,7 +26,6 @@ import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
@ -450,16 +449,9 @@ public class RepoUpdater {
|
||||
* per repo basis.
|
||||
*/
|
||||
void processRepoPushRequests() {
|
||||
PackageManager pm = context.getPackageManager();
|
||||
|
||||
for (RepoPushRequest repoPushRequest : repoPushRequestList) {
|
||||
String packageName = repoPushRequest.packageName;
|
||||
PackageInfo packageInfo = null;
|
||||
try {
|
||||
packageInfo = pm.getPackageInfo(packageName, 0);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
// ignored
|
||||
}
|
||||
PackageInfo packageInfo = Utils.getPackageInfo(context, packageName);
|
||||
if (RepoPushRequest.INSTALL.equals(repoPushRequest.request)) {
|
||||
ContentResolver cr = context.getContentResolver();
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
package org.fdroid.fdroid;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
@ -668,7 +669,12 @@ public final class Utils {
|
||||
}
|
||||
}
|
||||
|
||||
// Try to get the version name of the client. Return null on failure.
|
||||
/**
|
||||
* Try to get the {@link PackageInfo#versionName} of the
|
||||
* client.
|
||||
*
|
||||
* @return null on failure
|
||||
*/
|
||||
public static String getVersionName(Context context) {
|
||||
String versionName = null;
|
||||
try {
|
||||
@ -680,6 +686,20 @@ public final class Utils {
|
||||
return versionName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to get the {@link PackageInfo} for the {@code packageName} provided.
|
||||
*
|
||||
* @return null on failure
|
||||
*/
|
||||
public static PackageInfo getPackageInfo(Context context, String packageName) {
|
||||
try {
|
||||
return context.getPackageManager().getPackageInfo(packageName, 0);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
debugLog(TAG, "Could not get PackageInfo: ", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Useful for debugging during development, so that arbitrary queries can be made, and their
|
||||
* results inspected in the debugger.
|
||||
|
@ -4,10 +4,8 @@ import android.app.Activity;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
|
||||
import org.fdroid.fdroid.Utils;
|
||||
|
||||
/**
|
||||
@ -38,12 +36,9 @@ public class ObbUrlActivity extends Activity {
|
||||
String packageName = componentName.getPackageName();
|
||||
Apk apk = null;
|
||||
|
||||
try {
|
||||
PackageManager pm = getPackageManager();
|
||||
PackageInfo packageInfo = pm.getPackageInfo(packageName, 0);
|
||||
PackageInfo packageInfo = Utils.getPackageInfo(this, packageName);
|
||||
if (packageInfo != null) {
|
||||
apk = ApkProvider.Helper.findApkFromAnyRepo(this, packageName, packageInfo.versionCode);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Utils.debugLog(TAG, e.getLocalizedMessage());
|
||||
}
|
||||
|
||||
if (apk == null) {
|
||||
|
@ -7,11 +7,12 @@ import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.net.Uri;
|
||||
import android.os.IBinder;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import android.util.Log;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.filefilter.WildcardFileFilter;
|
||||
import org.fdroid.fdroid.AppUpdateStatusManager;
|
||||
@ -127,6 +128,19 @@ public class InstallManagerService extends Service {
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* This goes through a series of checks to make sure that the incoming
|
||||
* {@link Intent} is still valid. The default {@link Intent#getAction() action}
|
||||
* in the logic is {@link #ACTION_INSTALL} since it is the most complicate
|
||||
* case. Since the {@code Intent} will be redelivered by Android if the
|
||||
* app was killed, this needs to check that it still makes sense to handle.
|
||||
* <p>
|
||||
* For example, if F-Droid is killed while installing, it might not receive
|
||||
* the message that the install completed successfully. The checks need to be
|
||||
* as specific as possible so as not to block things like installing updates
|
||||
* with the same {@link PackageInfo#versionCode}, which happens sometimes,
|
||||
* and is allowed by Android.
|
||||
*/
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
Utils.debugLog(TAG, "onStartCommand " + intent);
|
||||
@ -155,7 +169,7 @@ public class InstallManagerService extends Service {
|
||||
appUpdateStatusManager.removeApk(urlString);
|
||||
return START_NOT_STICKY;
|
||||
} else if (!ACTION_INSTALL.equals(action)) {
|
||||
Utils.debugLog(TAG, "Ignoring " + intent + " as it is not an " + ACTION_INSTALL + " intent");
|
||||
Log.i(TAG, "Ignoring unknown intent action: " + intent);
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
|
||||
@ -166,7 +180,6 @@ public class InstallManagerService extends Service {
|
||||
|
||||
if ((flags & START_FLAG_REDELIVERY) == START_FLAG_REDELIVERY
|
||||
&& !DownloaderService.isQueuedOrActive(urlString)) {
|
||||
// TODO is there a case where we should allow an active urlString to pass through?
|
||||
Utils.debugLog(TAG, urlString + " finished downloading while InstallManagerService was killed.");
|
||||
appUpdateStatusManager.removeApk(urlString);
|
||||
return START_NOT_STICKY;
|
||||
@ -179,6 +192,14 @@ public class InstallManagerService extends Service {
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
|
||||
PackageInfo packageInfo = Utils.getPackageInfo(this, apk.packageName);
|
||||
if ((flags & START_FLAG_REDELIVERY) == START_FLAG_REDELIVERY
|
||||
&& packageInfo != null && packageInfo.versionCode == apk.versionCode
|
||||
&& TextUtils.equals(packageInfo.versionName, apk.versionName)) {
|
||||
Log.i(TAG, "INSTALL Intent no longer valid since its installed, ignoring: " + intent);
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
|
||||
FDroidApp.resetMirrorVars();
|
||||
DownloaderService.setTimeout(FDroidApp.getTimeout());
|
||||
|
||||
|
@ -5,7 +5,6 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.fdroid.fdroid.FDroidApp;
|
||||
import org.fdroid.fdroid.Utils;
|
||||
|
@ -2,7 +2,7 @@ package org.fdroid.fdroid.localrepo;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import kellinwood.security.zipsigner.ZipSigner;
|
||||
import org.fdroid.fdroid.FDroidApp;
|
||||
import org.fdroid.fdroid.Utils;
|
||||
import org.spongycastle.asn1.ASN1Sequence;
|
||||
@ -19,6 +19,9 @@ import org.spongycastle.operator.ContentSigner;
|
||||
import org.spongycastle.operator.OperatorCreationException;
|
||||
import org.spongycastle.operator.jcajce.JcaContentSignerBuilder;
|
||||
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.X509KeyManager;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
@ -46,12 +49,6 @@ import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.X509KeyManager;
|
||||
|
||||
import kellinwood.security.zipsigner.ZipSigner;
|
||||
|
||||
// TODO Address exception handling in a uniform way throughout
|
||||
|
||||
@SuppressWarnings("LineLength")
|
||||
@ -162,8 +159,8 @@ public final class LocalRepoKeyStore {
|
||||
KeyManager defaultKeyManager = keyManagerFactory.getKeyManagers()[0];
|
||||
KeyManager wrappedKeyManager = new KerplappKeyManager(
|
||||
(X509KeyManager) defaultKeyManager);
|
||||
keyManagers = new KeyManager[] {
|
||||
wrappedKeyManager,
|
||||
keyManagers = new KeyManager[]{
|
||||
wrappedKeyManager,
|
||||
};
|
||||
} catch (UnrecoverableKeyException | KeyStoreException | NoSuchAlgorithmException | CertificateException | OperatorCreationException | IOException e) {
|
||||
Log.e(TAG, "Error loading keystore", e);
|
||||
@ -254,7 +251,7 @@ public final class LocalRepoKeyStore {
|
||||
private void addToStore(String alias, KeyPair kp, Certificate cert) throws KeyStoreException,
|
||||
NoSuchAlgorithmException, CertificateException, IOException, UnrecoverableKeyException {
|
||||
Certificate[] chain = {
|
||||
cert,
|
||||
cert,
|
||||
};
|
||||
keyStore.setKeyEntry(alias, kp.getPrivate(),
|
||||
"".toCharArray(), chain);
|
||||
@ -272,8 +269,8 @@ public final class LocalRepoKeyStore {
|
||||
keyManagerFactory.init(keyStore, "".toCharArray());
|
||||
KeyManager defaultKeyManager = keyManagerFactory.getKeyManagers()[0];
|
||||
KeyManager wrappedKeyManager = new KerplappKeyManager((X509KeyManager) defaultKeyManager);
|
||||
keyManagers = new KeyManager[] {
|
||||
wrappedKeyManager,
|
||||
keyManagers = new KeyManager[]{
|
||||
wrappedKeyManager,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,6 @@ import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import org.fdroid.fdroid.FDroidApp;
|
||||
import org.fdroid.fdroid.Hasher;
|
||||
import org.fdroid.fdroid.Preferences;
|
||||
|
@ -20,7 +20,6 @@ import android.support.v4.app.NotificationCompat;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
@ -42,6 +41,10 @@ import org.fdroid.fdroid.localrepo.type.SwapType;
|
||||
import org.fdroid.fdroid.localrepo.type.WifiSwap;
|
||||
import org.fdroid.fdroid.net.WifiStateChangeService;
|
||||
import org.fdroid.fdroid.views.swap.SwapWorkflowActivity;
|
||||
import rx.Observable;
|
||||
import rx.Subscription;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.schedulers.Schedulers;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
@ -56,11 +59,6 @@ import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import rx.Observable;
|
||||
import rx.Subscription;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.schedulers.Schedulers;
|
||||
|
||||
/**
|
||||
* Central service which manages all of the different moving parts of swap which are required
|
||||
* to enable p2p swapping of apps.
|
||||
@ -115,10 +113,10 @@ public class SwapService extends Service {
|
||||
* Call {@link Observable#subscribe()} on this in order to be notified of peers
|
||||
* which are found. Call {@link Subscription#unsubscribe()} on the resulting
|
||||
* subscription when finished and you no longer want to scan for peers.
|
||||
*
|
||||
* <p>
|
||||
* The returned object will scan for peers on a background thread, and emit
|
||||
* found peers on the mian thread.
|
||||
*
|
||||
* <p>
|
||||
* Invoking this in multiple places will return the same, cached, peer finder.
|
||||
* That is, if in the past it already found some peers, then you subscribe
|
||||
* to it in the future, the future subscriber will still receive the peers
|
||||
@ -129,9 +127,9 @@ public class SwapService extends Service {
|
||||
Utils.debugLog(TAG, "Scanning for nearby devices to swap with...");
|
||||
if (peerFinder == null) {
|
||||
peerFinder = PeerFinder.createObservable(getApplicationContext())
|
||||
.subscribeOn(Schedulers.newThread())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.distinct();
|
||||
.subscribeOn(Schedulers.newThread())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.distinct();
|
||||
}
|
||||
return peerFinder;
|
||||
}
|
||||
@ -141,14 +139,14 @@ public class SwapService extends Service {
|
||||
// ("Step" refers to the current view being shown in the UI)
|
||||
// ==========================================================
|
||||
|
||||
public static final int STEP_INTRO = 1;
|
||||
public static final int STEP_SELECT_APPS = 2;
|
||||
public static final int STEP_JOIN_WIFI = 3;
|
||||
public static final int STEP_SHOW_NFC = 4;
|
||||
public static final int STEP_WIFI_QR = 5;
|
||||
public static final int STEP_CONNECTING = 6;
|
||||
public static final int STEP_SUCCESS = 7;
|
||||
public static final int STEP_CONFIRM_SWAP = 8;
|
||||
public static final int STEP_INTRO = 1;
|
||||
public static final int STEP_SELECT_APPS = 2;
|
||||
public static final int STEP_JOIN_WIFI = 3;
|
||||
public static final int STEP_SHOW_NFC = 4;
|
||||
public static final int STEP_WIFI_QR = 5;
|
||||
public static final int STEP_CONNECTING = 6;
|
||||
public static final int STEP_SUCCESS = 7;
|
||||
public static final int STEP_CONFIRM_SWAP = 8;
|
||||
|
||||
/**
|
||||
* Special view, that we don't really want to actually store against the
|
||||
@ -158,7 +156,8 @@ public class SwapService extends Service {
|
||||
*/
|
||||
public static final int STEP_INITIAL_LOADING = 9;
|
||||
|
||||
@SwapStep private int step = STEP_INTRO;
|
||||
@SwapStep
|
||||
private int step = STEP_INTRO;
|
||||
|
||||
/**
|
||||
* Current screen that the swap process is up to.
|
||||
@ -174,7 +173,8 @@ public class SwapService extends Service {
|
||||
return this;
|
||||
}
|
||||
|
||||
@NonNull public Set<String> getAppsToSwap() {
|
||||
@NonNull
|
||||
public Set<String> getAppsToSwap() {
|
||||
return appsToSwap;
|
||||
}
|
||||
|
||||
@ -299,9 +299,10 @@ public class SwapService extends Service {
|
||||
* This is the same as, e.g. {@link Context#getSystemService(String)}
|
||||
*/
|
||||
@IntDef({STEP_INTRO, STEP_SELECT_APPS, STEP_JOIN_WIFI, STEP_SHOW_NFC, STEP_WIFI_QR,
|
||||
STEP_CONNECTING, STEP_SUCCESS, STEP_CONFIRM_SWAP, STEP_INITIAL_LOADING})
|
||||
STEP_CONNECTING, STEP_SUCCESS, STEP_CONFIRM_SWAP, STEP_INITIAL_LOADING})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface SwapStep { }
|
||||
public @interface SwapStep {
|
||||
}
|
||||
|
||||
// =================================================
|
||||
// Have selected a specific peer to swap with
|
||||
@ -340,6 +341,7 @@ public class SwapService extends Service {
|
||||
* which is only available in API >= 11.
|
||||
* Package names are reverse-DNS-style, so they should only have alpha numeric values. Thus,
|
||||
* this uses a comma as the separator.
|
||||
*
|
||||
* @see SwapService#deserializePackages(String)
|
||||
*/
|
||||
private static String serializePackages(Set<String> packages) {
|
||||
|
@ -4,7 +4,6 @@ import android.annotation.TargetApi;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
import com.nostra13.universalimageloader.core.download.BaseImageDownloader;
|
||||
import info.guardianproject.netcipher.NetCipher;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.fdroid.fdroid.BuildConfig;
|
||||
@ -23,6 +22,13 @@ import java.net.MalformedURLException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* Download files over HTTP, with support for proxies, {@code .onion} addresses,
|
||||
* HTTP Basic Auth, etc. This is not a full HTTP client! This is only using
|
||||
* the bits of HTTP that F-Droid needs to operate. It does not support things
|
||||
* like redirects or other HTTP tricks. This keeps the security model and code
|
||||
* a lot simpler.
|
||||
*/
|
||||
public class HttpDownloader extends Downloader {
|
||||
private static final String TAG = "HttpDownloader";
|
||||
|
||||
@ -58,15 +64,6 @@ public class HttpDownloader extends Downloader {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: Doesn't follow redirects (as far as I'm aware).
|
||||
* {@link BaseImageDownloader#getStreamFromNetwork(String, Object)} has an implementation worth
|
||||
* checking out that follows redirects up to a certain point. I guess though the correct way
|
||||
* is probably to check for a loop (keep a list of all URLs redirected to and if you hit the
|
||||
* same one twice, bail with an exception).
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
protected InputStream getDownloadersInputStream() throws IOException {
|
||||
setupConnection(false);
|
||||
|
Loading…
x
Reference in New Issue
Block a user