Merge branch 'prep-for-InstalledAppProviderService' into 'master'
Prep for InstalledAppProviderService This is basically a collection of little fixes in preparations for !299 . See merge request !313
This commit is contained in:
commit
1bfd3425c9
@ -14,6 +14,7 @@ import junit.framework.AssertionFailedError;
|
||||
|
||||
import org.fdroid.fdroid.data.ApkProvider;
|
||||
import org.fdroid.fdroid.data.AppProvider;
|
||||
import org.fdroid.fdroid.data.FDroidProviderTest;
|
||||
import org.fdroid.fdroid.receiver.PackageAddedReceiver;
|
||||
import org.fdroid.fdroid.receiver.PackageRemovedReceiver;
|
||||
import org.fdroid.fdroid.receiver.PackageUpgradedReceiver;
|
||||
|
@ -1,11 +1,11 @@
|
||||
package org.fdroid.fdroid;
|
||||
package org.fdroid.fdroid.data;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
|
||||
import org.fdroid.fdroid.data.Apk;
|
||||
import org.fdroid.fdroid.data.ApkProvider;
|
||||
import org.fdroid.fdroid.TestUtils;
|
||||
import org.fdroid.fdroid.Utils;
|
||||
import org.fdroid.fdroid.mock.MockApk;
|
||||
|
||||
import java.util.ArrayList;
|
@ -1,12 +1,10 @@
|
||||
package org.fdroid.fdroid;
|
||||
package org.fdroid.fdroid.data;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
|
||||
import org.fdroid.fdroid.data.Apk;
|
||||
import org.fdroid.fdroid.data.ApkProvider;
|
||||
import org.fdroid.fdroid.data.RepoProvider;
|
||||
import org.fdroid.fdroid.TestUtils;
|
||||
import org.fdroid.fdroid.mock.MockApk;
|
||||
import org.fdroid.fdroid.mock.MockApp;
|
||||
import org.fdroid.fdroid.mock.MockRepo;
|
||||
@ -333,5 +331,4 @@ public class ApkProviderTest extends BaseApkProviderTest {
|
||||
assertEquals(1, apk.versionCode);
|
||||
assertEquals(10, apk.repo);
|
||||
}
|
||||
|
||||
}
|
@ -1,14 +1,12 @@
|
||||
package org.fdroid.fdroid;
|
||||
package org.fdroid.fdroid.data;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
|
||||
import org.fdroid.fdroid.data.ApkProvider;
|
||||
import org.fdroid.fdroid.data.App;
|
||||
import org.fdroid.fdroid.data.AppProvider;
|
||||
import org.fdroid.fdroid.data.InstalledAppCacheUpdater;
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.TestUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
@ -1,11 +1,10 @@
|
||||
package org.fdroid.fdroid;
|
||||
package org.fdroid.fdroid.data;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
|
||||
import org.fdroid.fdroid.data.Apk;
|
||||
import org.fdroid.fdroid.data.ApkProvider;
|
||||
import org.fdroid.fdroid.TestUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package org.fdroid.fdroid;
|
||||
package org.fdroid.fdroid.data;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.ContentValues;
|
||||
@ -10,12 +10,6 @@ import android.os.Build;
|
||||
import android.provider.ContactsContract;
|
||||
import android.test.ProviderTestCase2MockContext;
|
||||
|
||||
import org.fdroid.fdroid.data.ApkProvider;
|
||||
import org.fdroid.fdroid.data.AppProvider;
|
||||
import org.fdroid.fdroid.data.FDroidProvider;
|
||||
import org.fdroid.fdroid.data.InstalledAppProvider;
|
||||
import org.fdroid.fdroid.data.RepoProvider;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import mock.MockContextEmptyComponents;
|
@ -1,11 +1,9 @@
|
||||
package org.fdroid.fdroid;
|
||||
|
||||
import org.fdroid.fdroid.data.InstalledAppProvider;
|
||||
package org.fdroid.fdroid.data;
|
||||
|
||||
import mock.MockInstallablePackageManager;
|
||||
|
||||
/**
|
||||
* Tests the ability of the {@link org.fdroid.fdroid.data.InstalledAppCacheUpdater} to stay in sync with
|
||||
* Tests the ability of the {@link InstalledAppCacheUpdater} to stay in sync with
|
||||
* the {@link android.content.pm.PackageManager}.
|
||||
* For practical reasons, it extends FDroidProviderTest<InstalledAppProvider>, although there is also a
|
||||
* separate test for the InstalledAppProvider which tests the CRUD operations in more detail.
|
@ -1,11 +1,8 @@
|
||||
package org.fdroid.fdroid;
|
||||
package org.fdroid.fdroid.data;
|
||||
|
||||
import android.content.ContentValues;
|
||||
|
||||
import org.fdroid.fdroid.data.ApkProvider;
|
||||
import org.fdroid.fdroid.data.AppProvider;
|
||||
import org.fdroid.fdroid.data.InstalledAppProvider;
|
||||
import org.fdroid.fdroid.data.RepoProvider;
|
||||
import org.fdroid.fdroid.TestUtils;
|
||||
|
||||
import mock.MockInstallablePackageManager;
|
||||
|
@ -1571,9 +1571,6 @@ public class AppDetails extends AppCompatActivity {
|
||||
btMain.setText(R.string.menu_launch);
|
||||
} else {
|
||||
btMain.setText(R.string.menu_uninstall);
|
||||
if (!app.uninstallable) {
|
||||
btMain.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
btMain.setOnClickListener(mOnClickListener);
|
||||
|
@ -32,19 +32,25 @@ public class Apk extends ValueObject implements Comparable<Apk> {
|
||||
|
||||
public Utils.CommaSeparatedList nativecode; // null if empty or unknown
|
||||
|
||||
// ID (md5 sum of public key) of signature. Might be null, in the
|
||||
// transition to this field existing.
|
||||
/**
|
||||
* ID (md5 sum of public key) of signature. Might be null, in the
|
||||
* transition to this field existing.
|
||||
*/
|
||||
public String sig;
|
||||
|
||||
// True if compatible with the device.
|
||||
/**
|
||||
* True if compatible with the device.
|
||||
*/
|
||||
public boolean compatible;
|
||||
|
||||
public String apkName; // F-Droid style APK name
|
||||
public SanitizedFile installedFile; // the .apk file on this device's filesystem
|
||||
|
||||
// If not null, this is the name of the source tarball for the
|
||||
// application. Null indicates that it's a developer's binary
|
||||
// build - otherwise it's built from source.
|
||||
/**
|
||||
* If not null, this is the name of the source tarball for the
|
||||
* application. Null indicates that it's a developer's binary
|
||||
* build - otherwise it's built from source.
|
||||
*/
|
||||
public String srcname;
|
||||
|
||||
public int repoVersion;
|
||||
|
@ -37,7 +37,9 @@ public class App extends ValueObject implements Comparable<App> {
|
||||
|
||||
private static final String TAG = "App";
|
||||
|
||||
// True if compatible with the device (i.e. if at least one apk is)
|
||||
/**
|
||||
* True if compatible with the device (i.e. if at least one apk is)
|
||||
*/
|
||||
public boolean compatible;
|
||||
|
||||
public String packageName = "unknown";
|
||||
@ -84,27 +86,39 @@ public class App extends ValueObject implements Comparable<App> {
|
||||
public Date added;
|
||||
public Date lastUpdated;
|
||||
|
||||
// List of categories (as defined in the metadata
|
||||
// documentation) or null if there aren't any.
|
||||
/**
|
||||
* List of categories (as defined in the metadata documentation) or null if there aren't any.
|
||||
*/
|
||||
public Utils.CommaSeparatedList categories;
|
||||
|
||||
// List of anti-features (as defined in the metadata
|
||||
// documentation) or null if there aren't any.
|
||||
/**
|
||||
* List of anti-features (as defined in the metadata documentation) or null if there aren't any.
|
||||
*/
|
||||
public Utils.CommaSeparatedList antiFeatures;
|
||||
|
||||
// List of special requirements (such as root privileges) or
|
||||
// null if there aren't any.
|
||||
/**
|
||||
* List of special requirements (such as root privileges) or null if there aren't any.
|
||||
*/
|
||||
public Utils.CommaSeparatedList requirements;
|
||||
|
||||
// True if all updates for this app are to be ignored
|
||||
/**
|
||||
* True if all updates for this app are to be ignored
|
||||
*/
|
||||
public boolean ignoreAllUpdates;
|
||||
|
||||
// True if the current update for this app is to be ignored
|
||||
/**
|
||||
* True if the current update for this app is to be ignored
|
||||
*/
|
||||
public int ignoreThisUpdate;
|
||||
|
||||
// To be displayed at 48dp (x1.0)
|
||||
/**
|
||||
* To be displayed at 48dp (x1.0)
|
||||
*/
|
||||
public String iconUrl;
|
||||
// To be displayed at 72dp (x1.5)
|
||||
|
||||
/**
|
||||
* To be displayed at 72dp (x1.5)
|
||||
*/
|
||||
public String iconUrlLarge;
|
||||
|
||||
public String installedVersionName;
|
||||
@ -115,8 +129,6 @@ public class App extends ValueObject implements Comparable<App> {
|
||||
|
||||
public String installedSig;
|
||||
|
||||
public boolean uninstallable;
|
||||
|
||||
public static String getIconName(String packageName, int versionCode) {
|
||||
return packageName + "_" + versionCode + ".png";
|
||||
}
|
||||
@ -250,14 +262,21 @@ public class App extends ValueObject implements Comparable<App> {
|
||||
/**
|
||||
* Instantiate from a locally installed package.
|
||||
*/
|
||||
@TargetApi(9)
|
||||
public App(Context context, PackageManager pm, String packageName)
|
||||
throws CertificateEncodingException, IOException, PackageManager.NameNotFoundException {
|
||||
final ApplicationInfo appInfo = pm.getApplicationInfo(packageName,
|
||||
PackageManager.GET_META_DATA);
|
||||
final PackageInfo packageInfo = pm.getPackageInfo(packageName,
|
||||
PackageManager.GET_SIGNATURES | PackageManager.GET_PERMISSIONS);
|
||||
|
||||
PackageInfo packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS);
|
||||
setFromPackageInfo(pm, packageInfo);
|
||||
this.installedApk = new Apk();
|
||||
SanitizedFile apkFile = SanitizedFile.knownSanitized(packageInfo.applicationInfo.publicSourceDir);
|
||||
initApkFromApkFile(context, this.installedApk, packageInfo, apkFile);
|
||||
}
|
||||
|
||||
@TargetApi(9)
|
||||
private void setFromPackageInfo(PackageManager pm, PackageInfo packageInfo)
|
||||
throws CertificateEncodingException, IOException, PackageManager.NameNotFoundException {
|
||||
|
||||
this.packageName = packageInfo.packageName;
|
||||
final String installerPackageName = pm.getInstallerPackageName(packageName);
|
||||
CharSequence installerPackageLabel = null;
|
||||
if (!TextUtils.isEmpty(installerPackageName)) {
|
||||
@ -273,13 +292,13 @@ public class App extends ValueObject implements Comparable<App> {
|
||||
installerPackageLabel = installerPackageName;
|
||||
}
|
||||
|
||||
ApplicationInfo appInfo = packageInfo.applicationInfo;
|
||||
final CharSequence appDescription = appInfo.loadDescription(pm);
|
||||
if (TextUtils.isEmpty(appDescription)) {
|
||||
this.summary = "(installed by " + installerPackageLabel + ")";
|
||||
} else {
|
||||
this.summary = (String) appDescription.subSequence(0, 40);
|
||||
}
|
||||
this.packageName = appInfo.packageName;
|
||||
this.added = new Date(packageInfo.firstInstallTime);
|
||||
this.lastUpdated = new Date(packageInfo.lastUpdateTime);
|
||||
this.description = "<p>";
|
||||
@ -292,8 +311,20 @@ public class App extends ValueObject implements Comparable<App> {
|
||||
|
||||
this.name = (String) appInfo.loadLabel(pm);
|
||||
this.icon = getIconName(packageName, packageInfo.versionCode);
|
||||
this.compatible = true;
|
||||
}
|
||||
|
||||
final Apk apk = new Apk();
|
||||
private void initApkFromApkFile(Context context, Apk apk, PackageInfo packageInfo, SanitizedFile apkFile)
|
||||
throws IOException, CertificateEncodingException {
|
||||
// TODO include signature hash calculation here
|
||||
apk.hashType = "sha256";
|
||||
apk.hash = Utils.getBinaryHash(apkFile, apk.hashType);
|
||||
initInstalledApk(context, apk, packageInfo, apkFile);
|
||||
}
|
||||
|
||||
private void initInstalledApk(Context context, Apk apk, PackageInfo packageInfo, SanitizedFile apkFile)
|
||||
throws IOException, CertificateEncodingException {
|
||||
apk.compatible = true;
|
||||
apk.versionName = packageInfo.versionName;
|
||||
apk.versionCode = packageInfo.versionCode;
|
||||
apk.added = this.added;
|
||||
@ -303,16 +334,12 @@ public class App extends ValueObject implements Comparable<App> {
|
||||
apk.packageName = this.packageName;
|
||||
apk.permissions = Utils.CommaSeparatedList.make(packageInfo.requestedPermissions);
|
||||
apk.apkName = apk.packageName + "_" + apk.versionCode + ".apk";
|
||||
|
||||
final SanitizedFile apkFile = SanitizedFile.knownSanitized(appInfo.publicSourceDir);
|
||||
apk.hashType = "sha256";
|
||||
apk.hash = Utils.getBinaryHash(apkFile, apk.hashType);
|
||||
apk.installedFile = apkFile;
|
||||
|
||||
JarFile jarFile = new JarFile(apkFile);
|
||||
JarFile apkJar = new JarFile(apkFile);
|
||||
HashSet<String> abis = new HashSet<>(3);
|
||||
Pattern pattern = Pattern.compile("^lib/([a-z0-9-]+)/.*");
|
||||
for (Enumeration<JarEntry> jarEntries = jarFile.entries(); jarEntries.hasMoreElements();) {
|
||||
for (Enumeration<JarEntry> jarEntries = apkJar.entries(); jarEntries.hasMoreElements();) {
|
||||
JarEntry jarEntry = jarEntries.nextElement();
|
||||
Matcher matcher = pattern.matcher(jarEntry.getName());
|
||||
if (matcher.matches()) {
|
||||
@ -330,7 +357,6 @@ public class App extends ValueObject implements Comparable<App> {
|
||||
apk.features = Utils.CommaSeparatedList.make(featureNames);
|
||||
}
|
||||
|
||||
final JarFile apkJar = new JarFile(apkFile);
|
||||
final JarEntry aSignedEntry = (JarEntry) apkJar.getEntry("AndroidManifest.xml");
|
||||
|
||||
if (aSignedEntry == null) {
|
||||
@ -387,11 +413,6 @@ public class App extends ValueObject implements Comparable<App> {
|
||||
fdroidSig[j * 2 + 1] = (byte) (d >= 10 ? ('a' + d - 10) : ('0' + d));
|
||||
}
|
||||
apk.sig = Utils.hashBytes(fdroidSig, "md5");
|
||||
|
||||
this.installedApk = apk;
|
||||
boolean system = (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
|
||||
boolean updatedSystemApp = (appInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
|
||||
this.uninstallable = !system || updatedSystemApp;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
@ -464,16 +485,20 @@ public class App extends ValueObject implements Comparable<App> {
|
||||
return updates;
|
||||
}
|
||||
|
||||
// True if there are new versions (apks) available and the user wants
|
||||
// to be notified about them
|
||||
/**
|
||||
* True if there are new versions (apks) available and the user wants
|
||||
* to be notified about them
|
||||
*/
|
||||
public boolean canAndWantToUpdate() {
|
||||
boolean canUpdate = hasUpdates();
|
||||
boolean wantsUpdate = !ignoreAllUpdates && ignoreThisUpdate < suggestedVersionCode;
|
||||
return canUpdate && wantsUpdate && !isFiltered();
|
||||
}
|
||||
|
||||
// Whether the app is filtered or not based on AntiFeatures and root
|
||||
// permission (set in the Settings page)
|
||||
/**
|
||||
* Whether the app is filtered or not based on AntiFeatures and root
|
||||
* permission (set in the Settings page)
|
||||
*/
|
||||
public boolean isFiltered() {
|
||||
return new AppFilter().filter(this);
|
||||
}
|
||||
|
@ -121,8 +121,10 @@ public class Repo extends ValueObject {
|
||||
return !TextUtils.isEmpty(this.signingCertificate);
|
||||
}
|
||||
|
||||
// this happens when a repo is configed with a fingerprint, but the client
|
||||
// has not connected to it yet to download its signing certificate
|
||||
/**
|
||||
* This happens when a repo is configed with a fingerprint, but the client
|
||||
* has not connected to it yet to download its signing certificate
|
||||
*/
|
||||
public boolean isSignedButUnverified() {
|
||||
return TextUtils.isEmpty(this.signingCertificate) && !TextUtils.isEmpty(this.fingerprint);
|
||||
}
|
||||
|
@ -229,7 +229,7 @@ public class WifiStateChangeService extends IntentService {
|
||||
}
|
||||
}
|
||||
|
||||
private String formatIpAddress(int ipAddress) {
|
||||
static String formatIpAddress(int ipAddress) {
|
||||
if (ipAddress == 0) {
|
||||
return null;
|
||||
}
|
||||
|
@ -238,7 +238,6 @@ public class SwapAppsView extends ListView implements
|
||||
TextView nameView;
|
||||
ImageView iconView;
|
||||
Button btnInstall;
|
||||
TextView btnAttemptInstall;
|
||||
TextView statusInstalled;
|
||||
TextView statusIncompatible;
|
||||
|
||||
@ -343,22 +342,24 @@ public class SwapAppsView extends ListView implements
|
||||
|
||||
ImageLoader.getInstance().displayImage(app.iconUrl, iconView, displayImageOptions);
|
||||
|
||||
btnInstall.setVisibility(View.GONE);
|
||||
btnAttemptInstall.setVisibility(View.GONE);
|
||||
statusInstalled.setVisibility(View.GONE);
|
||||
statusIncompatible.setVisibility(View.GONE);
|
||||
|
||||
if (app.hasUpdates()) {
|
||||
btnInstall.setText(R.string.menu_upgrade);
|
||||
btnInstall.setVisibility(View.VISIBLE);
|
||||
statusIncompatible.setVisibility(View.GONE);
|
||||
statusInstalled.setVisibility(View.GONE);
|
||||
} else if (app.isInstalled()) {
|
||||
btnInstall.setVisibility(View.GONE);
|
||||
statusIncompatible.setVisibility(View.GONE);
|
||||
statusInstalled.setVisibility(View.VISIBLE);
|
||||
} else if (!app.compatible) {
|
||||
btnAttemptInstall.setVisibility(View.VISIBLE);
|
||||
btnInstall.setVisibility(View.GONE);
|
||||
statusIncompatible.setVisibility(View.VISIBLE);
|
||||
statusInstalled.setVisibility(View.GONE);
|
||||
} else {
|
||||
btnInstall.setText(R.string.menu_install);
|
||||
btnInstall.setVisibility(View.VISIBLE);
|
||||
statusIncompatible.setVisibility(View.GONE);
|
||||
statusInstalled.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
OnClickListener installListener = new OnClickListener() {
|
||||
@ -372,14 +373,11 @@ public class SwapAppsView extends ListView implements
|
||||
};
|
||||
|
||||
btnInstall.setOnClickListener(installListener);
|
||||
btnAttemptInstall.setOnClickListener(installListener);
|
||||
|
||||
}
|
||||
|
||||
private void showProgress() {
|
||||
progressView.setVisibility(View.VISIBLE);
|
||||
btnInstall.setVisibility(View.GONE);
|
||||
btnAttemptInstall.setVisibility(View.GONE);
|
||||
statusInstalled.setVisibility(View.GONE);
|
||||
statusIncompatible.setVisibility(View.GONE);
|
||||
}
|
||||
@ -410,7 +408,6 @@ public class SwapAppsView extends ListView implements
|
||||
holder.nameView = (TextView) view.findViewById(R.id.name);
|
||||
holder.iconView = (ImageView) view.findViewById(android.R.id.icon);
|
||||
holder.btnInstall = (Button) view.findViewById(R.id.btn_install);
|
||||
holder.btnAttemptInstall = (TextView) view.findViewById(R.id.btn_attempt_install);
|
||||
holder.statusInstalled = (TextView) view.findViewById(R.id.status_installed);
|
||||
holder.statusIncompatible = (TextView) view.findViewById(R.id.status_incompatible);
|
||||
|
||||
|
@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/header"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true">
|
||||
</RelativeLayout>
|
@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/header"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true">
|
||||
</RelativeLayout>
|
32
app/src/main/res/layout-sw480dp/start_swap_header.xml
Normal file
32
app/src/main/res/layout-sw480dp/start_swap_header.xml
Normal file
@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/header"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="130dp"
|
||||
android:layout_alignParentTop="true"
|
||||
tools:showIn="@layout/swap_blank">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scaleType="centerCrop"
|
||||
android:src="@drawable/swap_start_header" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:padding="20dp"
|
||||
android:paddingLeft="30dp"
|
||||
android:paddingRight="30dp"
|
||||
android:paddingEnd="30dp"
|
||||
android:gravity="center"
|
||||
android:textAlignment="center"
|
||||
android:text="@string/swap_intro"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="18sp"
|
||||
tools:ignore="UnusedAttribute" />
|
||||
|
||||
</RelativeLayout>
|
@ -1,32 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/header"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="130dp"
|
||||
android:layout_alignParentTop="true"
|
||||
tools:showIn="@layout/swap_blank">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scaleType="centerCrop"
|
||||
android:src="@drawable/swap_start_header" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:padding="20dp"
|
||||
android:paddingLeft="30dp"
|
||||
android:paddingRight="30dp"
|
||||
android:paddingEnd="30dp"
|
||||
android:gravity="center"
|
||||
android:textAlignment="center"
|
||||
android:text="@string/swap_intro"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="18sp"
|
||||
tools:ignore="UnusedAttribute" />
|
||||
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true">
|
||||
</RelativeLayout>
|
@ -55,13 +55,6 @@
|
||||
android:textColor="@color/swap_incompatible"
|
||||
android:text="@string/app_incompatible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/btn_attempt_install"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/swap_light_blue"
|
||||
android:text="@string/swap_attempt_install" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
|
@ -335,7 +335,6 @@
|
||||
<string name="bluetooth_unavailable">Bluetooth unavailable</string>
|
||||
<string name="swap_cant_send_no_bluetooth">Cannot send F-Droid, because Bluetooth is unavailable on this device.</string>
|
||||
<string name="loading">Loading…</string>
|
||||
<string name="swap_attempt_install">Try to install</string>
|
||||
<string name="swap_connection_misc_error">An error occurred while connecting to device, we can\'t seem to swap with it.</string>
|
||||
<string name="swap_not_enabled">Swapping not enabled</string>
|
||||
<string name="swap_not_enabled_description">Before swapping, your device must be made visible.</string>
|
||||
|
@ -5,11 +5,13 @@ import org.junit.Test;
|
||||
import java.io.File;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
public class SanitizedFileTest {
|
||||
|
||||
@Test
|
||||
public void testSanitizedFile() {
|
||||
assumeTrue("/".equals(System.getProperty("file.separator")));
|
||||
|
||||
File directory = new File("/tmp/blah");
|
||||
|
||||
|
@ -0,0 +1,20 @@
|
||||
package org.fdroid.fdroid.net;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
public class WifiStateChangeServiceTest {
|
||||
|
||||
@Test
|
||||
public void testFormatIpAddress() throws UnknownHostException {
|
||||
for (long i = Integer.MIN_VALUE; i <= Integer.MAX_VALUE; i += 98273) {
|
||||
String ip = WifiStateChangeService.formatIpAddress((int) i);
|
||||
InetAddress.getByName(ip);
|
||||
}
|
||||
InetAddress.getByName(WifiStateChangeService.formatIpAddress(Integer.MAX_VALUE));
|
||||
InetAddress.getByName(WifiStateChangeService.formatIpAddress(Integer.MIN_VALUE));
|
||||
InetAddress.getByName(WifiStateChangeService.formatIpAddress(0));
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user