diff --git a/app/src/full/res/layout/main_tab_swap.xml b/app/src/full/res/layout/main_tab_swap.xml index 03c35548e..3db7d5eee 100644 --- a/app/src/full/res/layout/main_tab_swap.xml +++ b/app/src/full/res/layout/main_tab_swap.xml @@ -42,6 +42,7 @@ android:id="@+id/find_people_button" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:maxEms="16" android:text="@string/nearby_splash__find_people_button" style="@style/DetailsSecondaryButtonStyle" app:layout_constraintTop_toBottomOf="@+id/title" @@ -85,6 +86,7 @@ android:id="@+id/request_read_external_storage_button" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:maxEms="16" android:text="@string/nearby_splash__request_permission" style="@style/DetailsSecondaryButtonStyle" app:layout_constraintEnd_toEndOf="parent" diff --git a/app/src/full/res/layout/swap_app_list_item.xml b/app/src/full/res/layout/swap_app_list_item.xml index f4d1b069d..84aedf51c 100644 --- a/app/src/full/res/layout/swap_app_list_item.xml +++ b/app/src/full/res/layout/swap_app_list_item.xml @@ -37,6 +37,9 @@ android:layout_height="wrap_content" android:backgroundTint="@color/swap_light_blue" android:textColor="@android:color/white" + android:maxEms="10" + android:ellipsize="end" + android:singleLine="true" android:text="@string/menu_install" tools:ignore="UnusedAttribute" /> diff --git a/app/src/main/java/org/fdroid/fdroid/DeleteCacheService.java b/app/src/main/java/org/fdroid/fdroid/DeleteCacheService.java index 9e05f5d89..eec11f260 100644 --- a/app/src/main/java/org/fdroid/fdroid/DeleteCacheService.java +++ b/app/src/main/java/org/fdroid/fdroid/DeleteCacheService.java @@ -28,13 +28,11 @@ public class DeleteCacheService extends JobIntentService { Log.w(TAG, "Deleting all cached contents!"); try { File cacheDir = getCacheDir(); - if (cacheDir != null) { - FileUtils.deleteDirectory(cacheDir); - } + FileUtils.deleteDirectory(cacheDir); for (File dir : ContextCompat.getExternalCacheDirs(this)) { FileUtils.deleteDirectory(dir); } - } catch (Exception e) { + } catch (Throwable e) { // NOPMD // ignored } } diff --git a/app/src/main/java/org/fdroid/fdroid/IndexUpdater.java b/app/src/main/java/org/fdroid/fdroid/IndexUpdater.java index 3a267144a..dabb03a1c 100644 --- a/app/src/main/java/org/fdroid/fdroid/IndexUpdater.java +++ b/app/src/main/java/org/fdroid/fdroid/IndexUpdater.java @@ -414,7 +414,7 @@ public class IndexUpdater { Utils.debugLog(TAG, "Saving new signing certificate in the database for " + repo.address); ContentValues values = new ContentValues(2); - values.put(RepoTable.Cols.LAST_UPDATED, Utils.formatDate(new Date(), "")); + values.put(RepoTable.Cols.LAST_UPDATED, Utils.formatTime(new Date(), "")); values.put(RepoTable.Cols.SIGNING_CERT, Hasher.hex(rawCertFromJar)); RepoProvider.Helper.update(context, repo, values); } diff --git a/app/src/main/java/org/fdroid/fdroid/IndexV1Updater.java b/app/src/main/java/org/fdroid/fdroid/IndexV1Updater.java index 5f6d3273a..fcc9eeac1 100644 --- a/app/src/main/java/org/fdroid/fdroid/IndexV1Updater.java +++ b/app/src/main/java/org/fdroid/fdroid/IndexV1Updater.java @@ -470,7 +470,7 @@ public class IndexV1Updater extends IndexUpdater { } Utils.debugLog(TAG, "Saving new signing certificate to database for " + repo.address); ContentValues values = new ContentValues(2); - values.put(Schema.RepoTable.Cols.LAST_UPDATED, Utils.formatDate(new Date(), "")); + values.put(Schema.RepoTable.Cols.LAST_UPDATED, Utils.formatTime(new Date(), "")); values.put(Schema.RepoTable.Cols.SIGNING_CERT, Hasher.hex(rawCertFromJar)); RepoProvider.Helper.update(context, repo, values); repo.signingCertificate = certFromJar; diff --git a/app/src/main/java/org/fdroid/fdroid/UpdateService.java b/app/src/main/java/org/fdroid/fdroid/UpdateService.java index 980dc8dc8..dfbfcac9a 100644 --- a/app/src/main/java/org/fdroid/fdroid/UpdateService.java +++ b/app/src/main/java/org/fdroid/fdroid/UpdateService.java @@ -236,7 +236,7 @@ public class UpdateService extends JobIntentService { Utils.debugLog(TAG, "scheduling update because there is good internet"); schedule(context); } - } catch (Exception e) { + } catch (Throwable e) { // NOPMD Utils.debugLog(TAG, e.getMessage()); } isScheduleIfStillOnWifiRunning = false; diff --git a/app/src/main/java/org/fdroid/fdroid/Utils.java b/app/src/main/java/org/fdroid/fdroid/Utils.java index 34bbc664c..b6121dd08 100644 --- a/app/src/main/java/org/fdroid/fdroid/Utils.java +++ b/app/src/main/java/org/fdroid/fdroid/Utils.java @@ -79,6 +79,7 @@ import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.TimeZone; import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; @@ -96,6 +97,8 @@ public final class Utils { private static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss", Locale.ENGLISH); + private static final TimeZone UTC = TimeZone.getTimeZone("Etc/GMT"); + private static final String[] FRIENDLY_SIZE_FORMAT = { "%.0f B", "%.0f KiB", "%.1f MiB", "%.2f GiB", }; @@ -384,7 +387,7 @@ public final class Utils { } ret = formatter.toString(); formatter.close(); - } catch (Exception e) { + } catch (Throwable e) { // NOPMD Log.w(TAG, "Unable to get certificate fingerprint", e); } return ret; @@ -583,6 +586,7 @@ public final class Utils { } Date result; try { + format.setTimeZone(UTC); result = format.parse(str); } catch (ArrayIndexOutOfBoundsException | NumberFormatException | ParseException e) { e.printStackTrace(); @@ -595,21 +599,34 @@ public final class Utils { if (date == null) { return fallback; } + format.setTimeZone(UTC); return format.format(date); } + /** + * Parses a date string into UTC time + */ public static Date parseDate(String str, Date fallback) { return parseDateFormat(DATE_FORMAT, str, fallback); } + /** + * Formats UTC time into a date string + */ public static String formatDate(Date date, String fallback) { return formatDateFormat(DATE_FORMAT, date, fallback); } + /** + * Parses a date/time string into UTC time + */ public static Date parseTime(String str, Date fallback) { return parseDateFormat(TIME_FORMAT, str, fallback); } + /** + * Formats UTC time into a date/time string + */ public static String formatTime(Date date, String fallback) { return formatDateFormat(TIME_FORMAT, date, fallback); } 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 fa92350ca..73faf88ad 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/Repo.java +++ b/app/src/main/java/org/fdroid/fdroid/data/Repo.java @@ -165,7 +165,8 @@ public class Repo extends ValueObject { inuse = cursor.getInt(i) == 1; break; case Cols.LAST_UPDATED: - lastUpdated = Utils.parseTime(cursor.getString(i), null); + String dateString = cursor.getString(i); + lastUpdated = Utils.parseTime(dateString, Utils.parseDate(dateString, null)); break; case Cols.MAX_AGE: maxage = cursor.getInt(i); @@ -296,7 +297,7 @@ public class Repo extends ValueObject { if (values.containsKey(Cols.LAST_UPDATED)) { final String dateString = values.getAsString(Cols.LAST_UPDATED); - lastUpdated = Utils.parseTime(dateString, null); + lastUpdated = Utils.parseTime(dateString, Utils.parseDate(dateString, null)); } if (values.containsKey(Cols.MAX_AGE)) { diff --git a/app/src/main/java/org/fdroid/fdroid/data/RepoProvider.java b/app/src/main/java/org/fdroid/fdroid/data/RepoProvider.java index dac4da741..9e769d4e8 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/RepoProvider.java +++ b/app/src/main/java/org/fdroid/fdroid/data/RepoProvider.java @@ -11,7 +11,6 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.text.TextUtils; import android.util.Log; - import org.fdroid.fdroid.AppUpdateStatusManager; import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.data.Schema.RepoTable; @@ -278,7 +277,8 @@ public class RepoProvider extends FDroidProvider { if (cursor != null) { if (cursor.getCount() > 0) { cursor.moveToFirst(); - lastUpdate = Utils.parseDate(cursor.getString(0), null); + String dateString = cursor.getString(0); + lastUpdate = Utils.parseTime(dateString, Utils.parseDate(dateString, null)); } cursor.close(); } diff --git a/app/src/main/java/org/fdroid/fdroid/installer/PrivilegedInstaller.java b/app/src/main/java/org/fdroid/fdroid/installer/PrivilegedInstaller.java index 51e5ee8f4..46d6f7c7f 100644 --- a/app/src/main/java/org/fdroid/fdroid/installer/PrivilegedInstaller.java +++ b/app/src/main/java/org/fdroid/fdroid/installer/PrivilegedInstaller.java @@ -265,7 +265,7 @@ public class PrivilegedInstaller extends Installer { PackageManager pm = context.getPackageManager(); try { pm.getPackageInfo(PRIVILEGED_EXTENSION_PACKAGE_NAME, PackageManager.GET_ACTIVITIES); - return true; + return pm.getApplicationInfo(PRIVILEGED_EXTENSION_PACKAGE_NAME, 0).enabled; } catch (PackageManager.NameNotFoundException e) { return false; } diff --git a/app/src/main/java/org/fdroid/fdroid/views/AppDetailsRecyclerViewAdapter.java b/app/src/main/java/org/fdroid/fdroid/views/AppDetailsRecyclerViewAdapter.java index fc6800115..219be5e11 100644 --- a/app/src/main/java/org/fdroid/fdroid/views/AppDetailsRecyclerViewAdapter.java +++ b/app/src/main/java/org/fdroid/fdroid/views/AppDetailsRecyclerViewAdapter.java @@ -555,11 +555,16 @@ public class AppDetailsRecyclerViewAdapter } updateAntiFeaturesWarning(); - buttonSecondaryView.setText(R.string.menu_uninstall); - buttonSecondaryView.setVisibility(app.isUninstallable(context) ? View.VISIBLE : View.INVISIBLE); - buttonSecondaryView.setOnClickListener(onUnInstallClickListener); buttonPrimaryView.setText(R.string.menu_install); buttonPrimaryView.setVisibility(versions.size() > 0 ? View.VISIBLE : View.GONE); + buttonSecondaryView.setText(R.string.menu_uninstall); + buttonSecondaryView.setVisibility(app.isUninstallable(context) ? View.VISIBLE : View.INVISIBLE); + buttonSecondaryView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + callbacks.uninstallApk(); + } + }); if (callbacks.isAppDownloading()) { buttonPrimaryView.setText(R.string.downloading); buttonPrimaryView.setEnabled(false); @@ -568,22 +573,37 @@ public class AppDetailsRecyclerViewAdapter } else if (!app.isInstalled(context) && suggestedApk != null) { // Check count > 0 due to incompatible apps resulting in an empty list. callbacks.disableAndroidBeam(); + progressLayout.setVisibility(View.GONE); // Set Install button and hide second button buttonPrimaryView.setText(R.string.menu_install); - buttonPrimaryView.setOnClickListener(onInstallClickListener); buttonPrimaryView.setEnabled(true); buttonLayout.setVisibility(View.VISIBLE); - progressLayout.setVisibility(View.GONE); + buttonPrimaryView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + callbacks.installApk(); + } + }); } else if (app.isInstalled(context)) { callbacks.enableAndroidBeam(); if (app.canAndWantToUpdate(context) && suggestedApk != null) { buttonPrimaryView.setText(R.string.menu_upgrade); - buttonPrimaryView.setOnClickListener(onUpgradeClickListener); + buttonPrimaryView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + callbacks.installApk(); + } + }); } else { Apk mediaApk = app.getMediaApkifInstalled(context); if (context.getPackageManager().getLaunchIntentForPackage(app.packageName) != null) { buttonPrimaryView.setText(R.string.menu_launch); - buttonPrimaryView.setOnClickListener(onLaunchClickListener); + buttonPrimaryView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + callbacks.launchApk(); + } + }); } else if (!app.isApk && mediaApk != null) { final File installedFile = new File(mediaApk.getMediaInstallPath(context), mediaApk.apkName); if (!installedFile.toString().startsWith(context.getApplicationInfo().dataDir)) { @@ -1324,34 +1344,6 @@ public class AppDetailsRecyclerViewAdapter } } - private final View.OnClickListener onInstallClickListener = new View.OnClickListener() { - @Override - public void onClick(View v) { - callbacks.installApk(); - } - }; - - private final View.OnClickListener onUnInstallClickListener = new View.OnClickListener() { - @Override - public void onClick(View v) { - callbacks.uninstallApk(); - } - }; - - private final View.OnClickListener onUpgradeClickListener = new View.OnClickListener() { - @Override - public void onClick(View v) { - callbacks.installApk(); - } - }; - - private final View.OnClickListener onLaunchClickListener = new View.OnClickListener() { - @Override - public void onClick(View v) { - callbacks.launchApk(); - } - }; - private boolean uriIsSetAndCanBeOpened(String s) { if (TextUtils.isEmpty(s)) { return false; diff --git a/app/src/main/res/layout/app_details2_version_item.xml b/app/src/main/res/layout/app_details2_version_item.xml index 935c03b35..194a08489 100644 --- a/app/src/main/res/layout/app_details2_version_item.xml +++ b/app/src/main/res/layout/app_details2_version_item.xml @@ -143,6 +143,9 @@ android:layout_marginTop="5dp" android:layout_marginRight="4dp" android:layout_marginEnd="4dp" + android:maxEms="10" + android:ellipsize="end" + android:singleLine="true" tools:text="@string/menu_install"/>