diff --git a/AndroidManifest.xml b/AndroidManifest.xml index f9782bf9d..519f2504e 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -15,9 +15,20 @@ + + + + + + + + + + + diff --git a/src/org/fdroid/fdroid/DB.java b/src/org/fdroid/fdroid/DB.java index 83069f7a2..888bce4c4 100644 --- a/src/org/fdroid/fdroid/DB.java +++ b/src/org/fdroid/fdroid/DB.java @@ -404,6 +404,8 @@ public class DB { // 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 // 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); Log.d("FDroid", "AppUpdate: " + updateApps.size() + " apps before starting."); diff --git a/src/org/fdroid/fdroid/FDroid.java b/src/org/fdroid/fdroid/FDroid.java index ff1fde03f..fd0d8c482 100644 --- a/src/org/fdroid/fdroid/FDroid.java +++ b/src/org/fdroid/fdroid/FDroid.java @@ -19,27 +19,11 @@ package org.fdroid.fdroid; -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; 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.List; 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 android.R.drawable; @@ -144,7 +128,6 @@ public class FDroid extends TabActivity implements OnItemClickListener { } 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_MANAGEREPOS = 1; @@ -168,8 +151,6 @@ public class FDroid extends TabActivity implements OnItemClickListener { private ProgressDialog pd; - private Context mctx = this; - private static final String TAB_IN = "INST"; private static final String TAB_UN = "UNIN"; 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) { new Thread() { public void run() { - try { - db.beginUpdate(); - Vector 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()); - } + RepoXMLHandler.doUpdates(db); update_handler.sendEmptyMessage(0); } }.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 @@ -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 // up a dialog that shows the details of the application and all its diff --git a/src/org/fdroid/fdroid/Preferences.java b/src/org/fdroid/fdroid/Preferences.java index cc24264cd..56dfebfaf 100644 --- a/src/org/fdroid/fdroid/Preferences.java +++ b/src/org/fdroid/fdroid/Preferences.java @@ -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; import android.os.Bundle; diff --git a/src/org/fdroid/fdroid/RepoXMLHandler.java b/src/org/fdroid/fdroid/RepoXMLHandler.java index b89107b8d..3e6a8a6e3 100644 --- a/src/org/fdroid/fdroid/RepoXMLHandler.java +++ b/src/org/fdroid/fdroid/RepoXMLHandler.java @@ -23,18 +23,24 @@ import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.InputStreamReader; 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.InputSource; import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; -import android.content.Context; import android.util.Log; public class RepoXMLHandler extends DefaultHandler { - Context mctx; String mserver; private DB db; @@ -43,8 +49,7 @@ public class RepoXMLHandler extends DefaultHandler { private DB.Apk curapk = null; private String curel = null; - public RepoXMLHandler(Context ctx, String srv, DB db) { - mctx = ctx; + public RepoXMLHandler(String srv, DB db) { mserver = srv; 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 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(); + + } + } diff --git a/src/org/fdroid/fdroid/StartupReceiver.java b/src/org/fdroid/fdroid/StartupReceiver.java new file mode 100644 index 000000000..19b44e295 --- /dev/null +++ b/src/org/fdroid/fdroid/StartupReceiver.java @@ -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); + } + +} diff --git a/src/org/fdroid/fdroid/UpdateService.java b/src/org/fdroid/fdroid/UpdateService.java new file mode 100644 index 000000000..91686db83 --- /dev/null +++ b/src/org/fdroid/fdroid/UpdateService.java @@ -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; + } + +}