From 15005372a24905dbdbfb1984f9b143eddf990506 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Wed, 18 May 2016 14:46:07 +0200 Subject: [PATCH 1/9] mark as compatible when App/Apk instances are from installed apps By definition, an app that is already installed is compatible. --- app/src/main/java/org/fdroid/fdroid/data/App.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/org/fdroid/fdroid/data/App.java b/app/src/main/java/org/fdroid/fdroid/data/App.java index 5e68d540b..a9183c8a0 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/App.java +++ b/app/src/main/java/org/fdroid/fdroid/data/App.java @@ -292,8 +292,10 @@ public class App extends ValueObject implements Comparable { this.name = (String) appInfo.loadLabel(pm); this.icon = getIconName(packageName, packageInfo.versionCode); + this.compatible = true; final Apk apk = new Apk(); + apk.compatible = true; apk.versionName = packageInfo.versionName; apk.versionCode = packageInfo.versionCode; apk.added = this.added; From 159185127309dedf408fe999665e4f80bb17e926 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Wed, 18 May 2016 13:52:23 +0200 Subject: [PATCH 2/9] remove "Try to install" from swap UI This should no longer be necessary since the local swap repo metadata now includes the nativecode tag. #30 https://gitlab.com/fdroid/fdroidclient/issues/30 --- .../fdroid/views/swap/SwapAppsView.java | 19 ++++++++----------- .../main/res/layout/swap_app_list_item.xml | 7 ------- app/src/main/res/values/strings.xml | 1 - 3 files changed, 8 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/org/fdroid/fdroid/views/swap/SwapAppsView.java b/app/src/main/java/org/fdroid/fdroid/views/swap/SwapAppsView.java index e40d6c09f..305035e4d 100644 --- a/app/src/main/java/org/fdroid/fdroid/views/swap/SwapAppsView.java +++ b/app/src/main/java/org/fdroid/fdroid/views/swap/SwapAppsView.java @@ -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); diff --git a/app/src/main/res/layout/swap_app_list_item.xml b/app/src/main/res/layout/swap_app_list_item.xml index 2219f2f96..f4d1b069d 100644 --- a/app/src/main/res/layout/swap_app_list_item.xml +++ b/app/src/main/res/layout/swap_app_list_item.xml @@ -55,13 +55,6 @@ android:textColor="@color/swap_incompatible" android:text="@string/app_incompatible" /> - - Bluetooth unavailable Cannot send F-Droid, because Bluetooth is unavailable on this device. Loading… - Try to install An error occurred while connecting to device, we can\'t seem to swap with it. Swapping not enabled Before swapping, your device must be made visible. From 68375163f57ba3b2adebca3f320478309a48f7ef Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 23 May 2016 22:18:13 +0200 Subject: [PATCH 3/9] only use swap header image on large screens The previous logic was putting the header on some 4" screens while not putting it on a 7" tablet. Tested with: * Samsung Galaxy Tab 3 7" * Azpen A727 7" * Xiaomi 4.5" * Lenovo 4" * emulators... --- .../res/layout-ldpi/start_swap_header.xml | 7 ---- .../res/layout-small/start_swap_header.xml | 7 ---- .../res/layout-sw480dp/start_swap_header.xml | 32 +++++++++++++++++++ app/src/main/res/layout/start_swap_header.xml | 29 ++--------------- 4 files changed, 34 insertions(+), 41 deletions(-) delete mode 100644 app/src/main/res/layout-ldpi/start_swap_header.xml delete mode 100644 app/src/main/res/layout-small/start_swap_header.xml create mode 100644 app/src/main/res/layout-sw480dp/start_swap_header.xml diff --git a/app/src/main/res/layout-ldpi/start_swap_header.xml b/app/src/main/res/layout-ldpi/start_swap_header.xml deleted file mode 100644 index 2f8a78fdc..000000000 --- a/app/src/main/res/layout-ldpi/start_swap_header.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - \ No newline at end of file diff --git a/app/src/main/res/layout-small/start_swap_header.xml b/app/src/main/res/layout-small/start_swap_header.xml deleted file mode 100644 index 2f8a78fdc..000000000 --- a/app/src/main/res/layout-small/start_swap_header.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - \ No newline at end of file diff --git a/app/src/main/res/layout-sw480dp/start_swap_header.xml b/app/src/main/res/layout-sw480dp/start_swap_header.xml new file mode 100644 index 000000000..a3163d65f --- /dev/null +++ b/app/src/main/res/layout-sw480dp/start_swap_header.xml @@ -0,0 +1,32 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/start_swap_header.xml b/app/src/main/res/layout/start_swap_header.xml index a3163d65f..2f8a78fdc 100644 --- a/app/src/main/res/layout/start_swap_header.xml +++ b/app/src/main/res/layout/start_swap_header.xml @@ -1,32 +1,7 @@ - - - - - + android:layout_height="wrap_content" + android:layout_alignParentTop="true"> \ No newline at end of file From c947f24495839e5c348aa89d987e900034495c3d Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 24 May 2016 22:46:07 +0200 Subject: [PATCH 4/9] simple test for WifiStateChangeService.formatIpAddress() 94f79a6438c7021db9c02003865c17f3a0da1718 made me want to be sure --- .../fdroid/net/WifiStateChangeService.java | 2 +- .../net/WifiStateChangeServiceTest.java | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 app/src/test/java/org/fdroid/fdroid/net/WifiStateChangeServiceTest.java diff --git a/app/src/main/java/org/fdroid/fdroid/net/WifiStateChangeService.java b/app/src/main/java/org/fdroid/fdroid/net/WifiStateChangeService.java index d0560a052..75d76c5eb 100644 --- a/app/src/main/java/org/fdroid/fdroid/net/WifiStateChangeService.java +++ b/app/src/main/java/org/fdroid/fdroid/net/WifiStateChangeService.java @@ -229,7 +229,7 @@ public class WifiStateChangeService extends IntentService { } } - private String formatIpAddress(int ipAddress) { + static String formatIpAddress(int ipAddress) { if (ipAddress == 0) { return null; } diff --git a/app/src/test/java/org/fdroid/fdroid/net/WifiStateChangeServiceTest.java b/app/src/test/java/org/fdroid/fdroid/net/WifiStateChangeServiceTest.java new file mode 100644 index 000000000..365b81ffc --- /dev/null +++ b/app/src/test/java/org/fdroid/fdroid/net/WifiStateChangeServiceTest.java @@ -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)); + } +} From aca94bcb68dff22157cff89e8efd13e7b26e7a4c Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 27 May 2016 12:25:28 +0200 Subject: [PATCH 5/9] move Provider tests into same java package the Providers This allows the tests to call more methods directly without having to use `public` visibility. --- app/src/androidTest/java/org/fdroid/fdroid/TestUtils.java | 1 + .../fdroid/fdroid/{ => data}/ApkProviderHelperTest.java | 6 +++--- .../org/fdroid/fdroid/{ => data}/ApkProviderTest.java | 7 ++----- .../org/fdroid/fdroid/{ => data}/AppProviderTest.java | 8 +++----- .../org/fdroid/fdroid/{ => data}/BaseApkProviderTest.java | 5 ++--- .../org/fdroid/fdroid/{ => data}/FDroidProviderTest.java | 8 +------- .../fdroid/fdroid/{ => data}/InstalledAppCacheTest.java | 6 ++---- .../fdroid/{ => data}/InstalledAppProviderTest.java | 7 ++----- 8 files changed, 16 insertions(+), 32 deletions(-) rename app/src/androidTest/java/org/fdroid/fdroid/{ => data}/ApkProviderHelperTest.java (98%) rename app/src/androidTest/java/org/fdroid/fdroid/{ => data}/ApkProviderTest.java (98%) rename app/src/androidTest/java/org/fdroid/fdroid/{ => data}/AppProviderTest.java (98%) rename app/src/androidTest/java/org/fdroid/fdroid/{ => data}/BaseApkProviderTest.java (95%) rename app/src/androidTest/java/org/fdroid/fdroid/{ => data}/FDroidProviderTest.java (96%) rename app/src/androidTest/java/org/fdroid/fdroid/{ => data}/InstalledAppCacheTest.java (97%) rename app/src/androidTest/java/org/fdroid/fdroid/{ => data}/InstalledAppProviderTest.java (96%) diff --git a/app/src/androidTest/java/org/fdroid/fdroid/TestUtils.java b/app/src/androidTest/java/org/fdroid/fdroid/TestUtils.java index 62e90189b..21a49518c 100644 --- a/app/src/androidTest/java/org/fdroid/fdroid/TestUtils.java +++ b/app/src/androidTest/java/org/fdroid/fdroid/TestUtils.java @@ -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; diff --git a/app/src/androidTest/java/org/fdroid/fdroid/ApkProviderHelperTest.java b/app/src/androidTest/java/org/fdroid/fdroid/data/ApkProviderHelperTest.java similarity index 98% rename from app/src/androidTest/java/org/fdroid/fdroid/ApkProviderHelperTest.java rename to app/src/androidTest/java/org/fdroid/fdroid/data/ApkProviderHelperTest.java index 846f7194f..307655a72 100644 --- a/app/src/androidTest/java/org/fdroid/fdroid/ApkProviderHelperTest.java +++ b/app/src/androidTest/java/org/fdroid/fdroid/data/ApkProviderHelperTest.java @@ -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; diff --git a/app/src/androidTest/java/org/fdroid/fdroid/ApkProviderTest.java b/app/src/androidTest/java/org/fdroid/fdroid/data/ApkProviderTest.java similarity index 98% rename from app/src/androidTest/java/org/fdroid/fdroid/ApkProviderTest.java rename to app/src/androidTest/java/org/fdroid/fdroid/data/ApkProviderTest.java index 814d90f57..4dced204f 100644 --- a/app/src/androidTest/java/org/fdroid/fdroid/ApkProviderTest.java +++ b/app/src/androidTest/java/org/fdroid/fdroid/data/ApkProviderTest.java @@ -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); } - } diff --git a/app/src/androidTest/java/org/fdroid/fdroid/AppProviderTest.java b/app/src/androidTest/java/org/fdroid/fdroid/data/AppProviderTest.java similarity index 98% rename from app/src/androidTest/java/org/fdroid/fdroid/AppProviderTest.java rename to app/src/androidTest/java/org/fdroid/fdroid/data/AppProviderTest.java index 81f0e5a22..b19c1d819 100644 --- a/app/src/androidTest/java/org/fdroid/fdroid/AppProviderTest.java +++ b/app/src/androidTest/java/org/fdroid/fdroid/data/AppProviderTest.java @@ -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; diff --git a/app/src/androidTest/java/org/fdroid/fdroid/BaseApkProviderTest.java b/app/src/androidTest/java/org/fdroid/fdroid/data/BaseApkProviderTest.java similarity index 95% rename from app/src/androidTest/java/org/fdroid/fdroid/BaseApkProviderTest.java rename to app/src/androidTest/java/org/fdroid/fdroid/data/BaseApkProviderTest.java index acaf3e12d..f5a73197c 100644 --- a/app/src/androidTest/java/org/fdroid/fdroid/BaseApkProviderTest.java +++ b/app/src/androidTest/java/org/fdroid/fdroid/data/BaseApkProviderTest.java @@ -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; diff --git a/app/src/androidTest/java/org/fdroid/fdroid/FDroidProviderTest.java b/app/src/androidTest/java/org/fdroid/fdroid/data/FDroidProviderTest.java similarity index 96% rename from app/src/androidTest/java/org/fdroid/fdroid/FDroidProviderTest.java rename to app/src/androidTest/java/org/fdroid/fdroid/data/FDroidProviderTest.java index e9f9e9517..d424ecbee 100644 --- a/app/src/androidTest/java/org/fdroid/fdroid/FDroidProviderTest.java +++ b/app/src/androidTest/java/org/fdroid/fdroid/data/FDroidProviderTest.java @@ -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; diff --git a/app/src/androidTest/java/org/fdroid/fdroid/InstalledAppCacheTest.java b/app/src/androidTest/java/org/fdroid/fdroid/data/InstalledAppCacheTest.java similarity index 97% rename from app/src/androidTest/java/org/fdroid/fdroid/InstalledAppCacheTest.java rename to app/src/androidTest/java/org/fdroid/fdroid/data/InstalledAppCacheTest.java index 0af7acde9..cb63f631a 100644 --- a/app/src/androidTest/java/org/fdroid/fdroid/InstalledAppCacheTest.java +++ b/app/src/androidTest/java/org/fdroid/fdroid/data/InstalledAppCacheTest.java @@ -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, although there is also a * separate test for the InstalledAppProvider which tests the CRUD operations in more detail. diff --git a/app/src/androidTest/java/org/fdroid/fdroid/InstalledAppProviderTest.java b/app/src/androidTest/java/org/fdroid/fdroid/data/InstalledAppProviderTest.java similarity index 96% rename from app/src/androidTest/java/org/fdroid/fdroid/InstalledAppProviderTest.java rename to app/src/androidTest/java/org/fdroid/fdroid/data/InstalledAppProviderTest.java index 1613eecb5..f36fcfed3 100644 --- a/app/src/androidTest/java/org/fdroid/fdroid/InstalledAppProviderTest.java +++ b/app/src/androidTest/java/org/fdroid/fdroid/data/InstalledAppProviderTest.java @@ -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; From 1410a720c803201cb767abd2bea2d7dd9c495daf Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Wed, 25 May 2016 10:41:37 +0200 Subject: [PATCH 6/9] reorganize swap's App() constructor to prepare for database caching To generate swap's index.jar, lots of information about all the installed APKs needs to be parsed. That can take a long time. Some of that can be stored in InstalledAppProvider. This prepares for those changes. Also, turns out that packageInfo.applicationInfo provides enough info, so there is no need to use pm.getApplicationInfo(). And the metadata from GET_META_DATA was not even being used. --- .../main/java/org/fdroid/fdroid/data/App.java | 48 +++++++++++-------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/org/fdroid/fdroid/data/App.java b/app/src/main/java/org/fdroid/fdroid/data/App.java index a9183c8a0..2cb24a05c 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/App.java +++ b/app/src/main/java/org/fdroid/fdroid/data/App.java @@ -250,14 +250,21 @@ public class App extends ValueObject implements Comparable { /** * 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 +280,13 @@ public class App extends ValueObject implements Comparable { 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 = "

"; @@ -293,8 +300,21 @@ public class App extends ValueObject implements Comparable { this.name = (String) appInfo.loadLabel(pm); this.icon = getIconName(packageName, packageInfo.versionCode); this.compatible = true; + boolean system = (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; + boolean updatedSystemApp = (appInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; + this.uninstallable = !system || updatedSystemApp; + } - 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; @@ -305,16 +325,12 @@ public class App extends ValueObject implements Comparable { 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 abis = new HashSet<>(3); Pattern pattern = Pattern.compile("^lib/([a-z0-9-]+)/.*"); - for (Enumeration jarEntries = jarFile.entries(); jarEntries.hasMoreElements();) { + for (Enumeration jarEntries = apkJar.entries(); jarEntries.hasMoreElements();) { JarEntry jarEntry = jarEntries.nextElement(); Matcher matcher = pattern.matcher(jarEntry.getName()); if (matcher.matches()) { @@ -332,7 +348,6 @@ public class App extends ValueObject implements Comparable { apk.features = Utils.CommaSeparatedList.make(featureNames); } - final JarFile apkJar = new JarFile(apkFile); final JarEntry aSignedEntry = (JarEntry) apkJar.getEntry("AndroidManifest.xml"); if (aSignedEntry == null) { @@ -389,11 +404,6 @@ public class App extends ValueObject implements Comparable { 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() { From f7688d7f9a459eda76954e2bf1a8eda530d7bdf1 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 27 May 2016 20:48:09 +0200 Subject: [PATCH 7/9] convert App comments to javadoc so they can be read in popups, etc. Decent Java editors have all sorts of nice ways to show javadoc comments, whether they are for public or private APIs. So comments should be in that format whenever possible. --- .../main/java/org/fdroid/fdroid/data/Apk.java | 18 ++++--- .../main/java/org/fdroid/fdroid/data/App.java | 48 +++++++++++++------ .../java/org/fdroid/fdroid/data/Repo.java | 6 ++- 3 files changed, 49 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/org/fdroid/fdroid/data/Apk.java b/app/src/main/java/org/fdroid/fdroid/data/Apk.java index 98844f15b..1f6b92220 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/Apk.java +++ b/app/src/main/java/org/fdroid/fdroid/data/Apk.java @@ -32,19 +32,25 @@ public class Apk extends ValueObject implements Comparable { 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; diff --git a/app/src/main/java/org/fdroid/fdroid/data/App.java b/app/src/main/java/org/fdroid/fdroid/data/App.java index 2cb24a05c..9cb4b4463 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/App.java +++ b/app/src/main/java/org/fdroid/fdroid/data/App.java @@ -37,7 +37,9 @@ public class App extends ValueObject implements Comparable { 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 { 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; @@ -476,16 +490,20 @@ public class App extends ValueObject implements Comparable { 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); } diff --git a/app/src/main/java/org/fdroid/fdroid/data/Repo.java b/app/src/main/java/org/fdroid/fdroid/data/Repo.java index 481ce9045..df8f7ef4e 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/Repo.java +++ b/app/src/main/java/org/fdroid/fdroid/data/Repo.java @@ -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); } From 1914f5f3e11455d41a7ef64308032870ef825f3e Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 27 May 2016 21:40:10 +0200 Subject: [PATCH 8/9] remove unused app.uninstallable app.uninstallable is only used in AppDetails. It is only set when generating App instances from installed APKs for the swap stuff. Since it is initialized to false and used as !app.uninstallable, it is always true when used. So it was doing nothing. This needs to be thought out more so this is not entirely complete for #628. AppDetails needs to know whether its a system app to provide proper feedback and swap needs to know whether its a system app with an update installed, otherwise it should ignore it. --- app/src/main/java/org/fdroid/fdroid/AppDetails.java | 3 --- app/src/main/java/org/fdroid/fdroid/data/App.java | 5 ----- 2 files changed, 8 deletions(-) diff --git a/app/src/main/java/org/fdroid/fdroid/AppDetails.java b/app/src/main/java/org/fdroid/fdroid/AppDetails.java index 903b60264..41641751b 100644 --- a/app/src/main/java/org/fdroid/fdroid/AppDetails.java +++ b/app/src/main/java/org/fdroid/fdroid/AppDetails.java @@ -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); diff --git a/app/src/main/java/org/fdroid/fdroid/data/App.java b/app/src/main/java/org/fdroid/fdroid/data/App.java index 9cb4b4463..c15ddd9ee 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/App.java +++ b/app/src/main/java/org/fdroid/fdroid/data/App.java @@ -129,8 +129,6 @@ public class App extends ValueObject implements Comparable { public String installedSig; - public boolean uninstallable; - public static String getIconName(String packageName, int versionCode) { return packageName + "_" + versionCode + ".png"; } @@ -314,9 +312,6 @@ public class App extends ValueObject implements Comparable { this.name = (String) appInfo.loadLabel(pm); this.icon = getIconName(packageName, packageInfo.versionCode); this.compatible = true; - boolean system = (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; - boolean updatedSystemApp = (appInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; - this.uninstallable = !system || updatedSystemApp; } private void initApkFromApkFile(Context context, Apk apk, PackageInfo packageInfo, SanitizedFile apkFile) From a03629d29dcf9fb315c653aa4b042a9589d8ad08 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 27 May 2016 21:40:51 +0200 Subject: [PATCH 9/9] SanitizedFileTest requires systems with "/" for a path separator closes #622 https://gitlab.com/fdroid/fdroidclient/issues/622 --- app/src/test/java/org/fdroid/fdroid/data/SanitizedFileTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/test/java/org/fdroid/fdroid/data/SanitizedFileTest.java b/app/src/test/java/org/fdroid/fdroid/data/SanitizedFileTest.java index f64c74a1a..bdec2339c 100644 --- a/app/src/test/java/org/fdroid/fdroid/data/SanitizedFileTest.java +++ b/app/src/test/java/org/fdroid/fdroid/data/SanitizedFileTest.java @@ -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");