Merge branch 'bug-fixes-1.7' into 'master'
Bug fixes 1.7 Closes #1678 and #1757 See merge request fdroid/fdroidclient!820
This commit is contained in:
commit
fac36457ea
@ -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"
|
||||
|
@ -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" />
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
for (File dir : ContextCompat.getExternalCacheDirs(this)) {
|
||||
FileUtils.deleteDirectory(dir);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) { // NOPMD
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)) {
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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"/>
|
||||
|
||||
<Button
|
||||
|
@ -42,6 +42,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:maxEms="10"
|
||||
android:text="@string/update_all"
|
||||
style="@style/DetailsPrimaryButtonStyle"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
@ -54,6 +55,8 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:ellipsize="middle"
|
||||
android:singleLine="true"
|
||||
tools:text="Show apps"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
@ -10,6 +10,8 @@ import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
@ -192,4 +194,25 @@ public class UtilsTest {
|
||||
}
|
||||
// TODO write tests that work with a Certificate
|
||||
|
||||
@Test
|
||||
public void testIndexDatesWithTimeZones() {
|
||||
for (int h = 0; h < 12; h++) {
|
||||
for (int m = 0; m < 60; m = m + 15) {
|
||||
TimeZone.setDefault(TimeZone.getTimeZone(String.format("GMT+%d%02d", h, m)));
|
||||
|
||||
String timeString = "2017-11-27_20:13:24";
|
||||
Date time = Utils.parseTime(timeString, null);
|
||||
assertEquals("The String representation must match", timeString, Utils.formatTime(time, null));
|
||||
assertEquals(timeString + " failed to parse", 1511813604000L, time.getTime());
|
||||
assertEquals("time zones should match", -((h * 60) + m), time.getTimezoneOffset());
|
||||
|
||||
TimeZone.setDefault(TimeZone.getTimeZone(String.format("GMT+%d%02d", h, m)));
|
||||
String dateString = "2017-11-27";
|
||||
Date date = Utils.parseDate(dateString, null);
|
||||
assertEquals("The String representation must match", dateString, Utils.formatDate(date, null));
|
||||
assertEquals(dateString + " failed to parse", 1511740800000L, date.getTime());
|
||||
assertEquals("time zones should match", -((h * 60) + m), date.getTimezoneOffset());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,10 +7,12 @@ import android.net.Uri;
|
||||
import org.fdroid.fdroid.Assert;
|
||||
import org.fdroid.fdroid.BuildConfig;
|
||||
import org.fdroid.fdroid.TestUtils;
|
||||
import org.fdroid.fdroid.Utils;
|
||||
import org.fdroid.fdroid.data.Schema.ApkTable.Cols;
|
||||
import org.fdroid.fdroid.data.Schema.RepoTable;
|
||||
import org.fdroid.fdroid.mock.MockApk;
|
||||
import org.fdroid.fdroid.mock.MockRepo;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
@ -18,6 +20,7 @@ import org.robolectric.annotation.Config;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import static org.fdroid.fdroid.Assert.assertCantDelete;
|
||||
import static org.fdroid.fdroid.Assert.assertResultCount;
|
||||
@ -34,6 +37,13 @@ public class ApkProviderTest extends FDroidProviderTest {
|
||||
|
||||
private static final String[] PROJ = Cols.ALL;
|
||||
|
||||
@BeforeClass
|
||||
public static void setRandomTimeZone() {
|
||||
TimeZone.setDefault(TimeZone.getTimeZone(String.format("GMT-%d:%02d",
|
||||
System.currentTimeMillis() % 12, System.currentTimeMillis() % 60)));
|
||||
System.out.println("TIME ZONE for this test: " + TimeZone.getDefault());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAppApks() {
|
||||
App fdroidApp = insertApp(context, "org.fdroid.fdroid", "F-Droid");
|
||||
@ -317,10 +327,11 @@ public class ApkProviderTest extends FDroidProviderTest {
|
||||
|
||||
apk.antiFeatures = new String[]{"KnownVuln", "Other anti feature"};
|
||||
apk.features = new String[]{"one", "two", "three"};
|
||||
long dateTimestamp = System.currentTimeMillis();
|
||||
apk.added = new Date(dateTimestamp);
|
||||
apk.hashType = "i'm a hash type";
|
||||
|
||||
Date testTime = Utils.parseDate(Utils.formatTime(new Date(System.currentTimeMillis()), null), null);
|
||||
apk.added = testTime;
|
||||
|
||||
ApkProvider.Helper.update(context, apk);
|
||||
|
||||
// Should not have inserted anything else, just updated the already existing apk.
|
||||
@ -340,9 +351,10 @@ public class ApkProviderTest extends FDroidProviderTest {
|
||||
|
||||
assertArrayEquals(new String[]{"KnownVuln", "Other anti feature"}, updatedApk.antiFeatures);
|
||||
assertArrayEquals(new String[]{"one", "two", "three"}, updatedApk.features);
|
||||
assertEquals(new Date(dateTimestamp).getYear(), updatedApk.added.getYear());
|
||||
assertEquals(new Date(dateTimestamp).getMonth(), updatedApk.added.getMonth());
|
||||
assertEquals(new Date(dateTimestamp).getDay(), updatedApk.added.getDay());
|
||||
assertEquals(testTime.getYear(), updatedApk.added.getYear());
|
||||
assertEquals(testTime.getYear(), updatedApk.added.getYear());
|
||||
assertEquals(testTime.getMonth(), updatedApk.added.getMonth());
|
||||
assertEquals(testTime.getDay(), updatedApk.added.getDay());
|
||||
assertEquals("i'm a hash type", updatedApk.hashType);
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@ import org.fdroid.fdroid.Preferences;
|
||||
import org.fdroid.fdroid.TestUtils;
|
||||
import org.fdroid.fdroid.data.Schema.AppMetadataTable.Cols;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
@ -19,6 +20,7 @@ import org.robolectric.shadows.ShadowContentResolver;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import static org.fdroid.fdroid.Assert.assertContainsOnly;
|
||||
import static org.fdroid.fdroid.Assert.assertResultCount;
|
||||
@ -36,6 +38,13 @@ public class AppProviderTest extends FDroidProviderTest {
|
||||
|
||||
private static final String[] PROJ = Cols.ALL;
|
||||
|
||||
@BeforeClass
|
||||
public static void setRandomTimeZone() {
|
||||
TimeZone.setDefault(TimeZone.getTimeZone(String.format("GMT-%d:%02d",
|
||||
System.currentTimeMillis() % 12, System.currentTimeMillis() % 60)));
|
||||
System.out.println("TIME ZONE for this test: " + TimeZone.getDefault());
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
TestUtils.registerContentProvider(AppProvider.getAuthority(), AppProvider.class);
|
||||
|
@ -30,6 +30,7 @@ import org.fdroid.fdroid.BuildConfig;
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.Utils;
|
||||
import org.fdroid.fdroid.data.Schema.RepoTable;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
@ -37,6 +38,7 @@ import org.robolectric.annotation.Config;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
@ -48,6 +50,16 @@ public class RepoProviderTest extends FDroidProviderTest {
|
||||
|
||||
private static final String[] COLS = RepoTable.Cols.ALL;
|
||||
|
||||
/**
|
||||
* Set to random time zone to make sure that the dates are properly parsed.
|
||||
*/
|
||||
@BeforeClass
|
||||
public static void setRandomTimeZone() {
|
||||
TimeZone.setDefault(TimeZone.getTimeZone(String.format("GMT-%d:%02d",
|
||||
System.currentTimeMillis() % 12, System.currentTimeMillis() % 60)));
|
||||
System.out.println("TIME ZONE for this test: " + TimeZone.getDefault());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void countEnabledRepos() {
|
||||
|
||||
@ -95,7 +107,7 @@ public class RepoProviderTest extends FDroidProviderTest {
|
||||
|
||||
private Repo setLastUpdate(Repo repo, Date date) {
|
||||
ContentValues values = new ContentValues(1);
|
||||
values.put(RepoTable.Cols.LAST_UPDATED, Utils.formatDate(date, null));
|
||||
values.put(RepoTable.Cols.LAST_UPDATED, Utils.formatTime(date, null));
|
||||
RepoProvider.Helper.update(context, repo, values);
|
||||
return RepoProvider.Helper.findByAddress(context, repo.address);
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ import org.apache.commons.io.FileUtils;
|
||||
import org.fdroid.fdroid.BuildConfig;
|
||||
import org.fdroid.fdroid.mock.MockRepo;
|
||||
import org.fdroid.fdroid.mock.RepoDetails;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
@ -48,6 +49,7 @@ import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
@ -63,6 +65,16 @@ public class RepoXMLHandlerTest {
|
||||
|
||||
private static final String FAKE_SIGNING_CERT = "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345"; // NOCHECKSTYLE LineLength
|
||||
|
||||
/**
|
||||
* Set to random time zone to make sure that the dates are properly parsed.
|
||||
*/
|
||||
@BeforeClass
|
||||
public static void setRandomTimeZone() {
|
||||
TimeZone.setDefault(TimeZone.getTimeZone(String.format("GMT-%d:%02d",
|
||||
System.currentTimeMillis() % 12, System.currentTimeMillis() % 60)));
|
||||
System.out.println("TIME ZONE for this test: " + TimeZone.getDefault());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtendedPerms() throws IOException {
|
||||
Repo expectedRepo = new Repo();
|
||||
@ -129,6 +141,12 @@ public class RepoXMLHandlerTest {
|
||||
"org.gege.caldavsyncadapter",
|
||||
"info.guardianproject.checkey",
|
||||
});
|
||||
for (App app : actualDetails.apps) {
|
||||
if ("org.mozilla.firefox".equals(app.packageName)) {
|
||||
assertEquals(1411776000000L, app.added.getTime());
|
||||
assertEquals(1411862400000L, app.lastUpdated.getTime());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
@ -897,6 +915,10 @@ public class RepoXMLHandlerTest {
|
||||
List<App> apps = actualDetails.apps;
|
||||
assertNotNull(apps);
|
||||
assertEquals(apps.size(), appCount);
|
||||
for (App app : apps) {
|
||||
assertTrue("Added should have been set", app.added.getTime() > 0);
|
||||
assertTrue("Last Updated should have been set", app.lastUpdated.getTime() > 0);
|
||||
}
|
||||
|
||||
List<Apk> apks = actualDetails.apks;
|
||||
assertNotNull(apks);
|
||||
|
File diff suppressed because one or more lines are too long
48
tools/check-string-maxlength.py
Executable file
48
tools/check-string-maxlength.py
Executable file
@ -0,0 +1,48 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Remove extra translations
|
||||
|
||||
import glob
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
from xml.etree import ElementTree
|
||||
|
||||
maxlengths = {
|
||||
"menu_install": 20,
|
||||
"menu_uninstall": 20,
|
||||
"nearby_splash__find_people_button": 30,
|
||||
"nearby_splash__request_permission": 30,
|
||||
"update_all": 20,
|
||||
"updates__hide_updateable_apps": 35,
|
||||
"updates__show_updateable_apps": 35,
|
||||
}
|
||||
|
||||
|
||||
resdir = os.path.join(os.path.dirname(__file__), '..', 'app', 'src', 'main', 'res')
|
||||
|
||||
count = 0
|
||||
|
||||
for d in sorted(glob.glob(os.path.join(resdir, 'values-*'))):
|
||||
locale = d.split('/')[-1][7:]
|
||||
|
||||
str_path = os.path.join(d, 'strings.xml')
|
||||
if not os.path.exists(str_path):
|
||||
continue
|
||||
|
||||
with open(str_path, encoding='utf-8') as fp:
|
||||
fulltext = fp.read()
|
||||
|
||||
tree = ElementTree.parse(str_path)
|
||||
root = tree.getroot()
|
||||
|
||||
for e in root.findall('.//string'):
|
||||
|
||||
if maxlengths.get(e.attrib['name']) is not None \
|
||||
and len(e.text) > maxlengths.get(e.attrib['name']):
|
||||
print(e.attrib['name'], locale, str(len(e.text)) + ':\t\t"' + e.text + '"')
|
||||
|
||||
if count > 0:
|
||||
print("%d over-long strings found!" % count)
|
||||
sys.exit(count)
|
||||
|
82
tools/pick-complete-translations.py
Executable file
82
tools/pick-complete-translations.py
Executable file
@ -0,0 +1,82 @@
|
||||
#!/usr/bin/python3
|
||||
#
|
||||
# cherry-pick complete translations from weblate
|
||||
|
||||
import git
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import requests
|
||||
import sys
|
||||
|
||||
|
||||
def get_paths_tuple(locale):
|
||||
return (
|
||||
'metadata/%s/*.txt' % locale,
|
||||
'metadata/%s/changelogs/*.txt' % locale,
|
||||
'app/src/main/res/values-%s/strings.xml' % re.sub(r'-', r'-r', locale),
|
||||
)
|
||||
|
||||
projectbasedir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
print(projectbasedir)
|
||||
|
||||
repo = git.Repo(projectbasedir)
|
||||
weblate = repo.remotes.weblate
|
||||
weblate.fetch()
|
||||
upstream = repo.remotes.upstream
|
||||
upstream.fetch()
|
||||
|
||||
url = 'https://hosted.weblate.org/exports/stats/f-droid/f-droid/?format=json'
|
||||
r = requests.get(url)
|
||||
r.raise_for_status()
|
||||
app = r.json()
|
||||
|
||||
url = 'https://hosted.weblate.org/exports/stats/f-droid/f-droid-metadata/?format=json'
|
||||
r = requests.get(url)
|
||||
r.raise_for_status()
|
||||
metadata = r.json()
|
||||
|
||||
|
||||
#with open('f-droid-metadata.json') as fp:
|
||||
# metadata = json.load(fp)
|
||||
|
||||
app_locales = dict()
|
||||
metadata_locales = dict()
|
||||
|
||||
merge_locales = []
|
||||
for locale in app:
|
||||
app_locales[locale['code']] = locale
|
||||
for locale in metadata:
|
||||
metadata_locales[locale['code']] = locale
|
||||
|
||||
for locale in sorted(app_locales.keys(), reverse=True):
|
||||
a = app_locales.get(locale)
|
||||
m = metadata_locales.get(locale)
|
||||
if a is not None and a['translated_percent'] == 100 and a['failing'] == 0 \
|
||||
and m is not None and m['translated_percent'] == 100 and m['failing'] == 0:
|
||||
print(locale)
|
||||
merge_locales.append(locale)
|
||||
|
||||
if not merge_locales:
|
||||
sys.exit()
|
||||
|
||||
if 'merge_weblate' in repo.heads:
|
||||
merge_weblate = repo.heads['merge_weblate']
|
||||
repo.create_tag('previous_merge_weblate', ref=merge_weblate,
|
||||
message=('Automatically created by %s' % __file__))
|
||||
else:
|
||||
merge_weblate = repo.create_head('merge_weblate')
|
||||
merge_weblate.set_commit(upstream.refs.master)
|
||||
merge_weblate.checkout()
|
||||
|
||||
email_pattern = re.compile(r'by (.*?) <(.*)>$')
|
||||
|
||||
for locale in sorted(merge_locales):
|
||||
commits = list(repo.iter_commits(
|
||||
str(weblate.refs.master) + '...' + str(upstream.refs.master),
|
||||
paths=get_paths_tuple(locale), max_count=10))
|
||||
for commit in reversed(commits):
|
||||
repo.git.cherry_pick(str(commit))
|
||||
m = email_pattern.search(commit.summary)
|
||||
if m:
|
||||
email = m.group(1) + ' <' + m.group(2) + '>'
|
Loading…
x
Reference in New Issue
Block a user