Overhauled repository update to resolve multiple problems

This commit is contained in:
Ciaran Gultnieks 2012-08-31 16:33:51 +01:00
parent 7647cc2594
commit c98aa9f6dc
4 changed files with 107 additions and 116 deletions

View File

@ -200,7 +200,6 @@ public class AppDetails extends ListActivity {
db = new DB(this);
compatChecker = db.getCompatibilityChecker();
mPm = getPackageManager();
((FDroidApp) getApplication()).inActivity++;
// Get the preferences we're going to use in this Activity...
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(getBaseContext());
@ -238,7 +237,6 @@ public class AppDetails extends ListActivity {
protected void onStop() {
db.close();
db = null;
((FDroidApp) getApplication()).inActivity--;
super.onStop();
}

View File

@ -31,6 +31,7 @@ import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.app.TabActivity;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageInfo;
@ -39,6 +40,7 @@ import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.ResultReceiver;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
@ -135,7 +137,6 @@ public class FDroid extends TabActivity implements OnItemClickListener,
@Override
protected void onStart() {
super.onStart();
((FDroidApp) getApplication()).inActivity++;
db = new DB(this);
triedEmptyUpdate = false;
populateLists(true);
@ -144,7 +145,6 @@ public class FDroid extends TabActivity implements OnItemClickListener,
@Override
protected void onStop() {
db.close();
((FDroidApp) getApplication()).inActivity--;
super.onStop();
}
@ -415,26 +415,15 @@ public class FDroid extends TabActivity implements OnItemClickListener,
}
private void updateRepos() {
pd = ProgressDialog.show(this, getString(R.string.process_wait_title),
getString(R.string.process_update_msg), true);
pd.setIcon(android.R.drawable.ic_dialog_info);
new Thread() {
public void run() {
boolean success = RepoXMLHandler.doUpdates(FDroid.this, db);
update_handler.sendEmptyMessage(success ? 0 : 1);
}
}.start();
}
/*
* Handlers for thread functions that need to access GUI
*/
private Handler update_handler = new Handler() {
// For receiving results from the UpdateService when we've told it to
// update in response to a user request.
private class UpdateReceiver extends ResultReceiver {
public UpdateReceiver(Handler handler) {
super(handler);
}
@Override
public void handleMessage(Message msg) {
if (msg.what == 1) {
protected void onReceiveResult (int resultCode, Bundle resultData) {
if (resultCode == 1) {
Toast.makeText(FDroid.this,
getString(R.string.connection_error_msg),
Toast.LENGTH_LONG).show();
@ -444,7 +433,22 @@ public class FDroid extends TabActivity implements OnItemClickListener,
if (pd.isShowing())
pd.dismiss();
}
};
}
private UpdateReceiver mUpdateReceiver;
// Force a repo update now. A progress dialog is shown and the UpdateService
// is told to do the update, which will result in the database changing. The
// UpdateReceiver class should get told when this is finished.
private void updateRepos() {
pd = ProgressDialog.show(this, getString(R.string.process_wait_title),
getString(R.string.process_update_msg), true, true);
pd.setIcon(android.R.drawable.ic_dialog_info);
Intent intent = new Intent(this, UpdateService.class);
mUpdateReceiver = new UpdateReceiver(new Handler());
intent.putExtra("receiver", mUpdateReceiver);
startService(intent);
}
public void onItemSelected(AdapterView<?> parent, View view, int pos,
long id) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2010 Ciaran Gultnieks, ciaran@ciarang.com
* Copyright (C) 2010-12 Ciaran Gultnieks, ciaran@ciarang.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -22,10 +22,5 @@ import android.app.Application;
public class FDroidApp extends Application {
// Keeps track of when we are in one of our activities where we
// don't want a database update to run. Incremented when entering
// one, and decremented when leaving, so if it's 0 it ought to be
// ok!
public int inActivity = 0;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2010 Ciaran Gultnieks, ciaran@ciarang.com
* Copyright (C) 2010-12 Ciaran Gultnieks, ciaran@ciarang.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -19,6 +19,7 @@
package org.fdroid.fdroid;
import android.app.AlarmManager;
import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@ -26,12 +27,19 @@ import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.IBinder;
import android.os.ResultReceiver;
import android.os.SystemClock;
import android.preference.PreferenceManager;
import android.util.Log;
public class UpdateService extends Service {
public class UpdateService extends IntentService {
public UpdateService() {
super("UpdateService");
}
// Schedule (or cancel schedule for) this service, according to the
// current preferences. Should be called a) at boot, or b) if the preference
@ -55,103 +63,89 @@ public class UpdateService extends Service {
SystemClock.elapsedRealtime() + 5000,
AlarmManager.INTERVAL_HOUR, pending);
}
}
// For API levels <5
@Override
public void onStart(Intent intent, int startId) {
handleCommand();
}
// For API levels >=5
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
handleCommand();
return START_REDELIVER_INTENT;
}
protected void onHandleIntent(Intent intent) {
private void handleCommand() {
// We might be doing a scheduled run, or we might have been launched by
// the app in response to a user's request. If we get this receiver, it's
// the latter...
ResultReceiver receiver = intent.getParcelableExtra("receiver");
new Thread() {
public void run() {
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(getBaseContext());
// If we're in one of our list activities, we don't want
// to run an update because the database will be out of
// sync with the display.
if (((FDroidApp) getApplication()).inActivity != 0)
return;
// See if it's time to actually do anything yet...
if(receiver == null) {
long lastUpdate = prefs.getLong("lastUpdateCheck", 0);
String sint = prefs.getString("updateInterval", "0");
int interval = Integer.parseInt(sint);
if (interval == 0)
return;
if (lastUpdate + (interval * 60 * 60) > System
.currentTimeMillis())
return;
}
// See if it's time to actually do anything yet...
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(getBaseContext());
long lastUpdate = prefs.getLong("lastUpdateCheck", 0);
String sint = prefs.getString("updateInterval", "0");
int interval = Integer.parseInt(sint);
if (interval == 0)
return;
if (lastUpdate + (interval * 60 * 60) > System
.currentTimeMillis())
return;
// Do the update...
DB db = null;
try {
db = new DB(getBaseContext());
boolean notify = prefs.getBoolean("updateNotify", false);
// Do the update...
DB db = null;
try {
db = new DB(getBaseContext());
boolean notify = prefs.getBoolean("updateNotify", false);
// Get the number of updates available before we
// start, so we can notify if there are new ones.
// (But avoid doing it if the user doesn't want
// notifications, since it may be time consuming)
int prevUpdates = 0;
if (notify)
prevUpdates = db.getNumUpdates();
// Get the number of updates available before we
// start, so we can notify if there are new ones.
// (But avoid doing it if the user doesn't want
// notifications, since it may be time consuming)
int prevUpdates = 0;
if (notify)
prevUpdates = db.getNumUpdates();
boolean success = RepoXMLHandler.doUpdates(
getBaseContext(), db);
boolean success = RepoXMLHandler.doUpdates(
getBaseContext(), db);
if (success && notify) {
int newUpdates = db.getNumUpdates();
Log.d("FDroid", "Updates before:" + prevUpdates + ", after: " +newUpdates);
if (newUpdates > prevUpdates) {
NotificationManager n = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification(
R.drawable.icon,
"FDroid Updates Available", System
.currentTimeMillis());
Context context = getApplicationContext();
CharSequence contentTitle = "FDroid";
CharSequence contentText = "Updates are available.";
Intent notificationIntent = new Intent(
UpdateService.this, FDroid.class);
PendingIntent contentIntent = PendingIntent
.getActivity(UpdateService.this, 0,
notificationIntent, 0);
notification.setLatestEventInfo(context,
contentTitle, contentText, contentIntent);
notification.flags |= Notification.FLAG_AUTO_CANCEL;
n.notify(1, notification);
}
}
} catch (Exception e) {
Log.e("FDroid", "Exception during handleCommand():\n"
+ Log.getStackTraceString(e));
} finally {
if (db != null)
db.close();
stopSelf();
if (success && notify) {
int newUpdates = db.getNumUpdates();
Log.d("FDroid", "Updates before:" + prevUpdates + ", after: " +newUpdates);
if (newUpdates > prevUpdates) {
NotificationManager n = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification(
R.drawable.icon,
"FDroid Updates Available", System
.currentTimeMillis());
Context context = getApplicationContext();
CharSequence contentTitle = "FDroid";
CharSequence contentText = "Updates are available.";
Intent notificationIntent = new Intent(
UpdateService.this, FDroid.class);
PendingIntent contentIntent = PendingIntent
.getActivity(UpdateService.this, 0,
notificationIntent, 0);
notification.setLatestEventInfo(context,
contentTitle, contentText, contentIntent);
notification.flags |= Notification.FLAG_AUTO_CANCEL;
n.notify(1, notification);
}
}
}.start();
}
if(receiver != null) {
Bundle resultData = new Bundle();
receiver.send(0, resultData);
}
} catch (Exception e) {
Log.e("FDroid", "Exception during handleCommand():\n"
+ Log.getStackTraceString(e));
if(receiver != null) {
Bundle resultData = new Bundle();
receiver.send(1, resultData);
}
} finally {
if (db != null)
db.close();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}