First effort (untested) at doing scheduled repo updates

This commit is contained in:
Ciaran Gultnieks 2010-11-08 08:47:05 +00:00
parent 53a9e0e796
commit 9c193f237d
7 changed files with 250 additions and 110 deletions

View File

@ -15,9 +15,20 @@
<activity android:name="Settings" /> <activity android:name="Settings" />
<activity android:name="AppDetails" /> <activity android:name="AppDetails" />
<activity android:name="Preferences" /> <activity android:name="Preferences" />
<receiver android:name="StartupReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.HOME" />
</intent-filter>
</receiver>
<service android:name="UpdateService" />
</application> </application>
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
</manifest> </manifest>

View File

@ -404,6 +404,8 @@ public class DB {
// have 'updated' set to false at this point, and we will only set // have 'updated' set to false at this point, and we will only set
// it to true when we see the app/apk in a repository. Thus, at the // it to true when we see the app/apk in a repository. Thus, at the
// end, any that are still false can be removed. // end, any that are still false can be removed.
// TODO: Need to ensure that UI and UpdateService can't both be doing
// an update at the same time.
updateApps = getApps(null, null, true); updateApps = getApps(null, null, true);
Log.d("FDroid", "AppUpdate: " + updateApps.size() Log.d("FDroid", "AppUpdate: " + updateApps.size()
+ " apps before starting."); + " apps before starting.");

View File

@ -19,27 +19,11 @@
package org.fdroid.fdroid; package org.fdroid.fdroid;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File; import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Vector; import java.util.Vector;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import android.R.drawable; import android.R.drawable;
@ -144,7 +128,6 @@ public class FDroid extends TabActivity implements OnItemClickListener {
} }
private String LOCAL_PATH = "/sdcard/.fdroid"; private String LOCAL_PATH = "/sdcard/.fdroid";
private String XML_PATH = LOCAL_PATH + "/remapklst.xml";
private static final int REQUEST_APPDETAILS = 0; private static final int REQUEST_APPDETAILS = 0;
private static final int REQUEST_MANAGEREPOS = 1; private static final int REQUEST_MANAGEREPOS = 1;
@ -168,8 +151,6 @@ public class FDroid extends TabActivity implements OnItemClickListener {
private ProgressDialog pd; private ProgressDialog pd;
private Context mctx = this;
private static final String TAB_IN = "INST"; private static final String TAB_IN = "INST";
private static final String TAB_UN = "UNIN"; private static final String TAB_UN = "UNIN";
private static final String TAB_UP = "UPDT"; private static final String TAB_UP = "UPDT";
@ -405,20 +386,7 @@ public class FDroid extends TabActivity implements OnItemClickListener {
|| netstate.getNetworkInfo(0).getState() == NetworkInfo.State.CONNECTED) { || netstate.getNetworkInfo(0).getState() == NetworkInfo.State.CONNECTED) {
new Thread() { new Thread() {
public void run() { public void run() {
try { RepoXMLHandler.doUpdates(db);
db.beginUpdate();
Vector<DB.Repo> repos = db.getRepos();
for (DB.Repo repo : repos) {
if (repo.inuse) {
downloadRepoIndex(repo.address);
xmlPass(repo.address);
}
}
db.endUpdate();
} catch (Exception e) {
Log.d("FDroid", "Exception while updating - "
+ e.getMessage());
}
update_handler.sendEmptyMessage(0); update_handler.sendEmptyMessage(0);
} }
}.start(); }.start();
@ -431,60 +399,6 @@ public class FDroid extends TabActivity implements OnItemClickListener {
} }
} }
/*
* Pass XML info to BD a xml file must exists...
*/
private void xmlPass(String srv) {
SAXParserFactory spf = SAXParserFactory.newInstance();
try {
SAXParser sp = spf.newSAXParser();
XMLReader xr = sp.getXMLReader();
RepoXMLHandler handler = new RepoXMLHandler(this, srv, db);
xr.setContentHandler(handler);
InputStreamReader isr = new FileReader(new File(XML_PATH));
InputSource is = new InputSource(isr);
xr.parse(is);
File xml_file = new File(XML_PATH);
xml_file.delete();
} catch (IOException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
}
}
// Download a repo index to a temporary file on the SD card.
private void downloadRepoIndex(String srv) {
try {
BufferedInputStream getit = new BufferedInputStream(new URL(srv
+ "/index.xml").openStream());
File file_teste = new File(XML_PATH);
if (file_teste.exists())
file_teste.delete();
FileOutputStream saveit = new FileOutputStream(XML_PATH);
BufferedOutputStream bout = new BufferedOutputStream(saveit, 1024);
byte data[] = new byte[1024];
int readed = getit.read(data, 0, 1024);
while (readed != -1) {
bout.write(data, 0, readed);
readed = getit.read(data, 0, 1024);
}
bout.close();
getit.close();
saveit.close();
} catch (UnknownHostException e) {
Message msg = new Message();
msg.obj = new String(srv);
error_handler.sendMessage(msg);
} catch (Exception e) {
}
}
/* /*
* Handlers for thread functions that need to access GUI * Handlers for thread functions that need to access GUI
@ -498,25 +412,6 @@ public class FDroid extends TabActivity implements OnItemClickListener {
} }
}; };
private Handler error_handler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (pd.isShowing())
pd.dismiss();
AlertDialog p = new AlertDialog.Builder(mctx).create();
p.setTitle(getString(R.string.connection_timeout));
p.setIcon(android.R.drawable.ic_dialog_alert);
p.setMessage(getString(R.string.connection_error_msg) + ": < "
+ msg.obj.toString() + " >");
p.setButton(getString(R.string.ok),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
return;
}
});
p.show();
}
};
// Handler for a click on one of the items in an application list. Pops // Handler for a click on one of the items in an application list. Pops
// up a dialog that shows the details of the application and all its // up a dialog that shows the details of the application and all its

View File

@ -1,3 +1,21 @@
/*
* Copyright (C) 2010 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
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.fdroid.fdroid; package org.fdroid.fdroid;
import android.os.Bundle; import android.os.Bundle;

View File

@ -23,18 +23,24 @@ import java.io.BufferedInputStream;
import java.io.BufferedOutputStream; import java.io.BufferedOutputStream;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.net.URL; import java.net.URL;
import java.util.Vector;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes; import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.DefaultHandler;
import android.content.Context;
import android.util.Log; import android.util.Log;
public class RepoXMLHandler extends DefaultHandler { public class RepoXMLHandler extends DefaultHandler {
Context mctx;
String mserver; String mserver;
private DB db; private DB db;
@ -43,8 +49,7 @@ public class RepoXMLHandler extends DefaultHandler {
private DB.Apk curapk = null; private DB.Apk curapk = null;
private String curel = null; private String curel = null;
public RepoXMLHandler(Context ctx, String srv, DB db) { public RepoXMLHandler(String srv, DB db) {
mctx = ctx;
mserver = srv; mserver = srv;
this.db = db; this.db = db;
} }
@ -173,4 +178,61 @@ public class RepoXMLHandler extends DefaultHandler {
} }
} }
private static String LOCAL_PATH = "/sdcard/.fdroid";
private static String XML_PATH = LOCAL_PATH + "/repotemp.xml";
public static void doUpdates(DB db) {
db.beginUpdate();
Vector<DB.Repo> repos = db.getRepos();
for (DB.Repo repo : repos) {
if (repo.inuse) {
try {
File f = new File(XML_PATH);
if (f.exists())
f.delete();
// Download the index file from the repo...
BufferedInputStream getit = new BufferedInputStream(
new URL(repo.address + "/index.xml").openStream());
FileOutputStream saveit = new FileOutputStream(XML_PATH);
BufferedOutputStream bout = new BufferedOutputStream(
saveit, 1024);
byte data[] = new byte[1024];
int readed = getit.read(data, 0, 1024);
while (readed != -1) {
bout.write(data, 0, readed);
readed = getit.read(data, 0, 1024);
}
bout.close();
getit.close();
saveit.close();
// Process the index...
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
XMLReader xr = sp.getXMLReader();
RepoXMLHandler handler = new RepoXMLHandler(repo.address, db);
xr.setContentHandler(handler);
InputStreamReader isr = new FileReader(new File(XML_PATH));
InputSource is = new InputSource(isr);
xr.parse(is);
File xml_file = new File(XML_PATH);
xml_file.delete();
} catch (Exception e) {
Log.d("FDroid", "Exception updating from " + repo.address
+ " - " + e.getMessage());
}
}
}
db.endUpdate();
}
} }

View File

@ -0,0 +1,32 @@
/*
* Copyright (C) 2010 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
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.fdroid.fdroid;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class StartupReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context ctx, Intent intent) {
UpdateService.schedule(ctx);
}
}

View File

@ -0,0 +1,120 @@
/*
* Copyright (C) 2010 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
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.fdroid.fdroid;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.IBinder;
import android.os.SystemClock;
import android.preference.PreferenceManager;
import android.util.Log;
public class UpdateService extends Service {
// Schedule (or cancel schedule for) this service, according to the
// current preferences. Should be called a) at boot, or b) if the preference
// is changed.
// TODO: What if we get upgraded?
public static void schedule(Context ctx) {
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(ctx);
String sint = prefs.getString("updateInterval", "0");
int interval = Integer.parseInt(sint);
Intent intent = new Intent(ctx, UpdateService.class);
PendingIntent pending = PendingIntent.getService(ctx, 0, intent, 0);
AlarmManager alarm = (AlarmManager) ctx
.getSystemService(Context.ALARM_SERVICE);
alarm.cancel(pending);
if (interval > 0) {
alarm.setInexactRepeating(AlarmManager.ELAPSED_REALTIME,
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;
}
private void handleCommand() {
new Thread() {
public void run() {
// 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;
// Make sure we have a connection...
ConnectivityManager netstate = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
if (netstate.getNetworkInfo(1).getState() != NetworkInfo.State.CONNECTED
&& netstate.getNetworkInfo(0).getState() != NetworkInfo.State.CONNECTED)
return;
// Do the update...
DB db = null;
try {
db = new DB(getBaseContext());
RepoXMLHandler.doUpdates(db);
} catch(Exception e) {
Log.d("FDroid","Exception during handleCommand() - " + e.getMessage());
} finally {
if (db != null)
db.close();
stopSelf();
}
}
}.start();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}