Merge branch 'first-run-index-update' into 'master'

First run index update

See merge request fdroid/fdroidclient!714
This commit is contained in:
Hans-Christoph Steiner 2018-07-20 11:23:22 +00:00
commit e374a3da5a
8 changed files with 72 additions and 52 deletions

View File

@ -70,8 +70,7 @@ errorprone:
- ./gradlew connectedCheck || (adb -e logcat -d '*:E' > logcat.txt; exit 1) - ./gradlew connectedCheck || (adb -e logcat -d '*:E' > logcat.txt; exit 1)
connected24: connected24:
only: retry: 1
- fdroid/fdroidclient@master
<<: *test-template <<: *test-template
variables: variables:
AVD_SDK: "24" AVD_SDK: "24"
@ -79,10 +78,6 @@ connected24:
AVD_PACKAGE: "system-images;android-${AVD_SDK};${AVD_TAG};armeabi-v7a" AVD_PACKAGE: "system-images;android-${AVD_SDK};${AVD_TAG};armeabi-v7a"
<<: *connected-template <<: *connected-template
connected25:
<<: *test-template
<<: *connected-template
deploy_nightly: deploy_nightly:
stage: deploy stage: deploy
only: only:

View File

@ -13,8 +13,9 @@ import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.view.View; import android.view.View;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.UpdateService; import org.fdroid.fdroid.UpdateService;
@ -40,6 +41,8 @@ class WhatsNewViewBinder implements LoaderManager.LoaderCallbacks<Cursor> {
private final TextView emptyState; private final TextView emptyState;
private final RecyclerView appList; private final RecyclerView appList;
private ProgressBar progressBar;
WhatsNewViewBinder(final AppCompatActivity activity, FrameLayout parent) { WhatsNewViewBinder(final AppCompatActivity activity, FrameLayout parent) {
this.activity = activity; this.activity = activity;
@ -124,6 +127,19 @@ class WhatsNewViewBinder implements LoaderManager.LoaderCallbacks<Cursor> {
} }
private void explainEmptyStateToUser() { private void explainEmptyStateToUser() {
if (Preferences.get().isIndexNeverUpdated() && UpdateService.isUpdating()) {
if (progressBar != null) {
return;
}
LinearLayout linearLayout = (LinearLayout) appList.getParent();
progressBar = new ProgressBar(activity, null, android.R.attr.progressBarStyleLarge);
progressBar.setId(R.id.progress_bar);
linearLayout.addView(progressBar);
emptyState.setVisibility(View.GONE);
appList.setVisibility(View.GONE);
return;
}
StringBuilder emptyStateText = new StringBuilder(); StringBuilder emptyStateText = new StringBuilder();
emptyStateText.append(activity.getString(R.string.latest__empty_state__no_recent_apps)); emptyStateText.append(activity.getString(R.string.latest__empty_state__no_recent_apps));
emptyStateText.append("\n\n"); emptyStateText.append("\n\n");

View File

@ -349,8 +349,9 @@ public class FDroidApp extends Application {
} }
Preferences.setup(this); Preferences.setup(this);
Languages.setLanguage(this); Languages.setLanguage(this);
Preferences preferences = Preferences.get();
if (Preferences.get().promptToSendCrashReports()) { if (preferences.promptToSendCrashReports()) {
ACRA.init(this); ACRA.init(this);
if (isAcraProcess() || HidingManager.isHidden(this)) { if (isAcraProcess() || HidingManager.isHidden(this)) {
return; return;
@ -359,16 +360,15 @@ public class FDroidApp extends Application {
PRNGFixes.apply(); PRNGFixes.apply();
curTheme = Preferences.get().getTheme(); curTheme = preferences.getTheme();
Preferences.get().configureProxy(); preferences.configureProxy();
// bug specific to exactly 5.0 makes it only work with the old index // bug specific to exactly 5.0 makes it only work with the old index
// which includes an ugly, hacky workaround // which includes an ugly, hacky workaround
// https://gitlab.com/fdroid/fdroidclient/issues/1014 // https://gitlab.com/fdroid/fdroidclient/issues/1014
if (Build.VERSION.SDK_INT == 21) { if (Build.VERSION.SDK_INT == 21) {
Preferences p = Preferences.get(); preferences.setExpertMode(true);
p.setExpertMode(true); preferences.setForceOldIndex(true);
p.setForceOldIndex(true);
} }
InstalledAppProviderService.compareToPackageManager(this); InstalledAppProviderService.compareToPackageManager(this);
@ -376,7 +376,7 @@ public class FDroidApp extends Application {
// If the user changes the preference to do with filtering rooted apps, // If the user changes the preference to do with filtering rooted apps,
// it is easier to just notify a change in the app provider, // it is easier to just notify a change in the app provider,
// so that the newly updated list will correctly filter relevant apps. // so that the newly updated list will correctly filter relevant apps.
Preferences.get().registerAppsRequiringRootChangeListener(new Preferences.ChangeListener() { preferences.registerAppsRequiringRootChangeListener(new Preferences.ChangeListener() {
@Override @Override
public void onPreferenceChange() { public void onPreferenceChange() {
getContentResolver().notifyChange(AppProvider.getContentUri(), null); getContentResolver().notifyChange(AppProvider.getContentUri(), null);
@ -386,14 +386,14 @@ public class FDroidApp extends Application {
// If the user changes the preference to do with filtering anti-feature apps, // If the user changes the preference to do with filtering anti-feature apps,
// it is easier to just notify a change in the app provider, // it is easier to just notify a change in the app provider,
// so that the newly updated list will correctly filter relevant apps. // so that the newly updated list will correctly filter relevant apps.
Preferences.get().registerAppsRequiringAntiFeaturesChangeListener(new Preferences.ChangeListener() { preferences.registerAppsRequiringAntiFeaturesChangeListener(new Preferences.ChangeListener() {
@Override @Override
public void onPreferenceChange() { public void onPreferenceChange() {
getContentResolver().notifyChange(AppProvider.getContentUri(), null); getContentResolver().notifyChange(AppProvider.getContentUri(), null);
} }
}); });
Preferences.get().registerUnstableUpdatesChangeListener(new Preferences.ChangeListener() { preferences.registerUnstableUpdatesChangeListener(new Preferences.ChangeListener() {
@Override @Override
public void onPreferenceChange() { public void onPreferenceChange() {
AppProvider.Helper.calcSuggestedApks(FDroidApp.this); AppProvider.Helper.calcSuggestedApks(FDroidApp.this);
@ -403,7 +403,6 @@ public class FDroidApp extends Application {
CleanCacheService.schedule(this); CleanCacheService.schedule(this);
notificationHelper = new NotificationHelper(getApplicationContext()); notificationHelper = new NotificationHelper(getApplicationContext());
UpdateService.schedule(getApplicationContext());
bluetoothAdapter = getBluetoothAdapter(); bluetoothAdapter = getBluetoothAdapter();
// There are a couple things to pay attention to with this config: memory usage, // There are a couple things to pay attention to with this config: memory usage,
@ -452,21 +451,26 @@ public class FDroidApp extends Application {
.build(); .build();
ImageLoader.getInstance().init(config); ImageLoader.getInstance().init(config);
if (preferences.isIndexNeverUpdated()) {
// force this check to ensure it starts fetching the index on initial runs
networkState = ConnectivityMonitorService.getNetworkState(this);
}
ConnectivityMonitorService.registerAndStart(this); ConnectivityMonitorService.registerAndStart(this);
UpdateService.schedule(getApplicationContext());
FDroidApp.initWifiSettings(); FDroidApp.initWifiSettings();
WifiStateChangeService.start(this, null); WifiStateChangeService.start(this, null);
// if the HTTPS pref changes, then update all affected things // if the HTTPS pref changes, then update all affected things
Preferences.get().registerLocalRepoHttpsListeners(new ChangeListener() { preferences.registerLocalRepoHttpsListeners(new ChangeListener() {
@Override @Override
public void onPreferenceChange() { public void onPreferenceChange() {
WifiStateChangeService.start(getApplicationContext(), null); WifiStateChangeService.start(getApplicationContext(), null);
} }
}); });
configureTor(Preferences.get().isTorEnabled()); configureTor(preferences.isTorEnabled());
if (Preferences.get().isKeepingInstallHistory()) { if (preferences.isKeepingInstallHistory()) {
InstallHistoryService.register(this); InstallHistoryService.register(this);
} }
@ -492,7 +496,7 @@ public class FDroidApp extends Application {
atStartTime.edit().putInt("build-version", Build.VERSION.SDK_INT).apply(); atStartTime.edit().putInt("build-version", Build.VERSION.SDK_INT).apply();
final String queryStringKey = "http-downloader-query-string"; final String queryStringKey = "http-downloader-query-string";
if (Preferences.get().sendVersionAndUUIDToServers()) { if (preferences.sendVersionAndUUIDToServers()) {
HttpDownloader.queryString = atStartTime.getString(queryStringKey, null); HttpDownloader.queryString = atStartTime.getString(queryStringKey, null);
if (HttpDownloader.queryString == null) { if (HttpDownloader.queryString == null) {
UUID uuid = UUID.randomUUID(); UUID uuid = UUID.randomUUID();

View File

@ -101,7 +101,6 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh
public static final String PREF_PROXY_PORT = "proxyPort"; public static final String PREF_PROXY_PORT = "proxyPort";
public static final String PREF_SHOW_NFC_DURING_SWAP = "showNfcDuringSwap"; public static final String PREF_SHOW_NFC_DURING_SWAP = "showNfcDuringSwap";
public static final String PREF_POST_PRIVILEGED_INSTALL = "postPrivilegedInstall"; public static final String PREF_POST_PRIVILEGED_INSTALL = "postPrivilegedInstall";
public static final String PREF_TRIED_EMPTY_UPDATE = "triedEmptyUpdate";
public static final String PREF_PREVENT_SCREENSHOTS = "preventScreenshots"; public static final String PREF_PREVENT_SCREENSHOTS = "preventScreenshots";
public static final String PREF_PANIC_EXIT = "pref_panic_exit"; public static final String PREF_PANIC_EXIT = "pref_panic_exit";
public static final String PREF_PANIC_HIDE = "pref_panic_hide"; public static final String PREF_PANIC_HIDE = "pref_panic_hide";
@ -114,10 +113,14 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh
public static final int OVER_NETWORK_ON_DEMAND = 1; public static final int OVER_NETWORK_ON_DEMAND = 1;
public static final int OVER_NETWORK_ALWAYS = 2; public static final int OVER_NETWORK_ALWAYS = 2;
// not shown in Settings
private static final String PREF_LAST_UPDATE_CHECK = "lastUpdateCheck";
// these preferences are not listed in preferences.xml so the defaults are set here // these preferences are not listed in preferences.xml so the defaults are set here
@SuppressWarnings("PMD.AvoidUsingHardCodedIP") @SuppressWarnings("PMD.AvoidUsingHardCodedIP")
public static final String DEFAULT_PROXY_HOST = "127.0.0.1"; // TODO move to preferences.xml public static final String DEFAULT_PROXY_HOST = "127.0.0.1"; // TODO move to preferences.xml
public static final int DEFAULT_PROXY_PORT = 8118; // TODO move to preferences.xml public static final int DEFAULT_PROXY_PORT = 8118; // TODO move to preferences.xml
private static final int DEFAULT_LAST_UPDATE_CHECK = -1;
private static final boolean DEFAULT_SHOW_NFC_DURING_SWAP = true; private static final boolean DEFAULT_SHOW_NFC_DURING_SWAP = true;
private static final boolean DEFAULT_POST_PRIVILEGED_INSTALL = false; private static final boolean DEFAULT_POST_PRIVILEGED_INSTALL = false;
private static final boolean DEFAULT_PANIC_EXIT = true; private static final boolean DEFAULT_PANIC_EXIT = true;
@ -321,18 +324,23 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh
} }
} }
/** public long getLastUpdateCheck() {
* Used the first time F-Droid is installed to flag whether or not we have tried to request return preferences.getLong(PREF_LAST_UPDATE_CHECK, DEFAULT_LAST_UPDATE_CHECK);
* apps from the repo. This is used so that when there is no apps available, we can differentiate
* between whether the repos actually have no apps (in which case we don't need to continue
* asking), or whether there is no apps because we have never actually asked to update the repos.
*/
public boolean hasTriedEmptyUpdate() {
return preferences.getBoolean(PREF_TRIED_EMPTY_UPDATE, IGNORED_B);
} }
public void setTriedEmptyUpdate(boolean value) { public void setLastUpdateCheck(long lastUpdateCheck) {
preferences.edit().putBoolean(PREF_TRIED_EMPTY_UPDATE, value).apply(); preferences.edit().putLong(PREF_LAST_UPDATE_CHECK, lastUpdateCheck).apply();
}
public void resetLastUpdateCheck() {
setLastUpdateCheck(DEFAULT_LAST_UPDATE_CHECK);
}
/**
* The first time the app has been run since fresh install or clearing all data.
*/
public boolean isIndexNeverUpdated() {
return getLastUpdateCheck() == DEFAULT_LAST_UPDATE_CHECK;
} }
public boolean getUnstableUpdates() { public boolean getUnstableUpdates() {

View File

@ -29,7 +29,6 @@ import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Build; import android.os.Build;
@ -41,7 +40,6 @@ import android.support.annotation.NonNull;
import android.support.v4.app.JobIntentService; import android.support.v4.app.JobIntentService;
import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationCompat;
import android.support.v4.content.LocalBroadcastManager; import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.preference.PreferenceManager;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.widget.Toast; import android.widget.Toast;
@ -82,11 +80,11 @@ public class UpdateService extends JobIntentService {
public static final int STATUS_ERROR_LOCAL_SMALL = 4; public static final int STATUS_ERROR_LOCAL_SMALL = 4;
public static final int STATUS_INFO = 5; public static final int STATUS_INFO = 5;
private static final String STATE_LAST_UPDATED = "lastUpdateCheck";
private static final int JOB_ID = 0xfedcba; private static final int JOB_ID = 0xfedcba;
private static final int NOTIFY_ID_UPDATING = 0; private static final int NOTIFY_ID_UPDATING = 0;
private static UpdateService updateService;
private static Handler toastHandler; private static Handler toastHandler;
private NotificationManager notificationManager; private NotificationManager notificationManager;
@ -118,11 +116,19 @@ public class UpdateService extends JobIntentService {
} }
/** /**
* Add work to the queue for processing now * Add work to the queue for processing now.
* <p>
* This also shows a {@link Toast} if the Data/WiFi Settings make it so the
* update process is not allowed to run and the device is attached to a
* network (e.g. is not offline or in Airplane Mode).
* *
* @see JobIntentService#enqueueWork(Context, Class, int, Intent) * @see JobIntentService#enqueueWork(Context, Class, int, Intent)
*/ */
private static void enqueueWork(Context context, @NonNull Intent intent) { private static void enqueueWork(Context context, @NonNull Intent intent) {
if (FDroidApp.networkState > 0 && !Preferences.get().isOnDemandDownloadAllowed()) {
Toast.makeText(context, R.string.updates_disabled_by_settings, Toast.LENGTH_LONG).show();
}
enqueueWork(context, UpdateService.class, JOB_ID, intent); enqueueWork(context, UpdateService.class, JOB_ID, intent);
} }
@ -188,6 +194,8 @@ public class UpdateService extends JobIntentService {
/** /**
* Whether or not a repo update is currently in progress. Used to show feedback throughout * Whether or not a repo update is currently in progress. Used to show feedback throughout
* the app to users, so they know something is happening. * the app to users, so they know something is happening.
*
* @see <a href="https://stackoverflow.com/a/608600">set a global variable when it is running that your client can check</a>
*/ */
public static boolean isUpdating() { public static boolean isUpdating() {
return updateService != null; return updateService != null;
@ -239,8 +247,6 @@ public class UpdateService extends JobIntentService {
} }
private static UpdateService updateService;
public static void stopNow(Context context) { public static void stopNow(Context context) {
if (updateService != null) { if (updateService != null) {
updateService.stopSelf(JOB_ID); updateService.stopSelf(JOB_ID);
@ -494,10 +500,7 @@ public class UpdateService extends JobIntentService {
} }
} }
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext()); fdroidPrefs.setLastUpdateCheck(System.currentTimeMillis());
SharedPreferences.Editor e = prefs.edit();
e.putLong(STATE_LAST_UPDATED, System.currentTimeMillis());
e.apply();
if (errorRepos == 0) { if (errorRepos == 0) {
if (changes) { if (changes) {

View File

@ -1095,7 +1095,7 @@ public class DBHelper extends SQLiteOpenHelper {
private static void resetTransient(SQLiteDatabase db) { private static void resetTransient(SQLiteDatabase db) {
Utils.debugLog(TAG, "Removing all index tables, they will be recreated next time F-Droid updates."); Utils.debugLog(TAG, "Removing all index tables, they will be recreated next time F-Droid updates.");
Preferences.get().setTriedEmptyUpdate(false); Preferences.get().resetLastUpdateCheck();
db.beginTransaction(); db.beginTransaction();
try { try {
@ -1147,7 +1147,7 @@ public class DBHelper extends SQLiteOpenHelper {
return; return;
} }
Preferences.get().setTriedEmptyUpdate(false); Preferences.get().resetLastUpdateCheck();
db.execSQL("drop table " + AppMetadataTable.NAME); db.execSQL("drop table " + AppMetadataTable.NAME);
db.execSQL("drop table " + ApkTable.NAME); db.execSQL("drop table " + ApkTable.NAME);

View File

@ -158,16 +158,9 @@ public class MainActivity extends AppCompatActivity implements BottomNavigationB
bottomNavigation.selectTab(adapter.adapterPositionFromItemId(selectedMenuId)); bottomNavigation.selectTab(adapter.adapterPositionFromItemId(selectedMenuId));
} }
/**
* The first time the app is run, we will have an empty app list. To deal with this, we will
* attempt to update with the default repo. However, if we have tried this at least once, then
* don't try to do it automatically again.
*/
private void initialRepoUpdateIfRequired() { private void initialRepoUpdateIfRequired() {
Preferences prefs = Preferences.get(); if (Preferences.get().isIndexNeverUpdated() && !UpdateService.isUpdating()) {
if (!prefs.hasTriedEmptyUpdate()) {
Utils.debugLog(TAG, "We haven't done an update yet. Forcing repo update."); Utils.debugLog(TAG, "We haven't done an update yet. Forcing repo update.");
prefs.setTriedEmptyUpdate(true);
UpdateService.updateNow(this); UpdateService.updateNow(this);
} }
} }

View File

@ -129,6 +129,7 @@ This often occurs with apps installed via Google Play or other sources, if they
<item quantity="one">Download update for %1$d app.</item> <item quantity="one">Download update for %1$d app.</item>
<item quantity="other">Download updates for %1$d apps.</item> <item quantity="other">Download updates for %1$d apps.</item>
</plurals> </plurals>
<string name="updates_disabled_by_settings">All updates disabled by Data/WiFi Settings</string>
<string name="ok">OK</string> <string name="ok">OK</string>