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

View File

@ -31,6 +31,7 @@ import android.app.AlertDialog;
import android.app.ProgressDialog; import android.app.ProgressDialog;
import android.app.TabActivity; import android.app.TabActivity;
import android.app.AlertDialog.Builder; import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
@ -39,6 +40,7 @@ import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Message; import android.os.Message;
import android.os.ResultReceiver;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
@ -135,7 +137,6 @@ public class FDroid extends TabActivity implements OnItemClickListener,
@Override @Override
protected void onStart() { protected void onStart() {
super.onStart(); super.onStart();
((FDroidApp) getApplication()).inActivity++;
db = new DB(this); db = new DB(this);
triedEmptyUpdate = false; triedEmptyUpdate = false;
populateLists(true); populateLists(true);
@ -144,7 +145,6 @@ public class FDroid extends TabActivity implements OnItemClickListener,
@Override @Override
protected void onStop() { protected void onStop() {
db.close(); db.close();
((FDroidApp) getApplication()).inActivity--;
super.onStop(); super.onStop();
} }
@ -415,26 +415,15 @@ public class FDroid extends TabActivity implements OnItemClickListener,
} }
private void updateRepos() { // For receiving results from the UpdateService when we've told it to
pd = ProgressDialog.show(this, getString(R.string.process_wait_title), // update in response to a user request.
getString(R.string.process_update_msg), true); private class UpdateReceiver extends ResultReceiver {
pd.setIcon(android.R.drawable.ic_dialog_info); public UpdateReceiver(Handler handler) {
super(handler);
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() {
@Override @Override
public void handleMessage(Message msg) { protected void onReceiveResult (int resultCode, Bundle resultData) {
if (msg.what == 1) { if (resultCode == 1) {
Toast.makeText(FDroid.this, Toast.makeText(FDroid.this,
getString(R.string.connection_error_msg), getString(R.string.connection_error_msg),
Toast.LENGTH_LONG).show(); Toast.LENGTH_LONG).show();
@ -444,7 +433,22 @@ public class FDroid extends TabActivity implements OnItemClickListener,
if (pd.isShowing()) if (pd.isShowing())
pd.dismiss(); 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, public void onItemSelected(AdapterView<?> parent, View view, int pos,
long id) { 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 * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -22,10 +22,5 @@ import android.app.Application;
public class FDroidApp extends 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 * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -19,6 +19,7 @@
package org.fdroid.fdroid; package org.fdroid.fdroid;
import android.app.AlarmManager; import android.app.AlarmManager;
import android.app.IntentService;
import android.app.Notification; import android.app.Notification;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.app.PendingIntent; import android.app.PendingIntent;
@ -26,12 +27,19 @@ import android.app.Service;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
import android.os.ResultReceiver;
import android.os.SystemClock; import android.os.SystemClock;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.util.Log; 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 // Schedule (or cancel schedule for) this service, according to the
// current preferences. Should be called a) at boot, or b) if the preference // 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, SystemClock.elapsedRealtime() + 5000,
AlarmManager.INTERVAL_HOUR, pending); AlarmManager.INTERVAL_HOUR, pending);
} }
} }
// For API levels <5
@Override
public void onStart(Intent intent, int startId) {
handleCommand();
}
// For API levels >=5 protected void onHandleIntent(Intent intent) {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
handleCommand();
return START_REDELIVER_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");
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(getBaseContext());
new Thread() { // See if it's time to actually do anything yet...
public void run() { 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;
}
// If we're in one of our list activities, we don't want // Do the update...
// to run an update because the database will be out of DB db = null;
// sync with the display. try {
if (((FDroidApp) getApplication()).inActivity != 0) db = new DB(getBaseContext());
return; boolean notify = prefs.getBoolean("updateNotify", false);
// See if it's time to actually do anything yet... // Get the number of updates available before we
SharedPreferences prefs = PreferenceManager // start, so we can notify if there are new ones.
.getDefaultSharedPreferences(getBaseContext()); // (But avoid doing it if the user doesn't want
long lastUpdate = prefs.getLong("lastUpdateCheck", 0); // notifications, since it may be time consuming)
String sint = prefs.getString("updateInterval", "0"); int prevUpdates = 0;
int interval = Integer.parseInt(sint); if (notify)
if (interval == 0) prevUpdates = db.getNumUpdates();
return;
if (lastUpdate + (interval * 60 * 60) > System
.currentTimeMillis())
return;
// Do the update... boolean success = RepoXMLHandler.doUpdates(
DB db = null; getBaseContext(), db);
try {
db = new DB(getBaseContext());
boolean notify = prefs.getBoolean("updateNotify", false);
// Get the number of updates available before we if (success && notify) {
// start, so we can notify if there are new ones. int newUpdates = db.getNumUpdates();
// (But avoid doing it if the user doesn't want Log.d("FDroid", "Updates before:" + prevUpdates + ", after: " +newUpdates);
// notifications, since it may be time consuming) if (newUpdates > prevUpdates) {
int prevUpdates = 0; NotificationManager n = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (notify) Notification notification = new Notification(
prevUpdates = db.getNumUpdates(); R.drawable.icon,
"FDroid Updates Available", System
boolean success = RepoXMLHandler.doUpdates( .currentTimeMillis());
getBaseContext(), db); Context context = getApplicationContext();
CharSequence contentTitle = "FDroid";
if (success && notify) { CharSequence contentText = "Updates are available.";
int newUpdates = db.getNumUpdates(); Intent notificationIntent = new Intent(
Log.d("FDroid", "Updates before:" + prevUpdates + ", after: " +newUpdates); UpdateService.this, FDroid.class);
if (newUpdates > prevUpdates) { PendingIntent contentIntent = PendingIntent
NotificationManager n = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); .getActivity(UpdateService.this, 0,
Notification notification = new Notification( notificationIntent, 0);
R.drawable.icon, notification.setLatestEventInfo(context,
"FDroid Updates Available", System contentTitle, contentText, contentIntent);
.currentTimeMillis()); notification.flags |= Notification.FLAG_AUTO_CANCEL;
Context context = getApplicationContext(); n.notify(1, notification);
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();
} }
} }
}.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;
} }
} }