278 lines
10 KiB
Java
278 lines
10 KiB
Java
package ru.vfilippov.electronreminder;
|
|
|
|
import android.app.IntentService;
|
|
import android.app.NotificationManager;
|
|
import android.app.PendingIntent;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.support.v4.app.NotificationCompat;
|
|
import android.support.v4.content.LocalBroadcastManager;
|
|
import android.util.Log;
|
|
import android.widget.Toast;
|
|
|
|
import org.xmlpull.v1.XmlPullParserException;
|
|
|
|
import java.io.ByteArrayInputStream;
|
|
import java.io.ByteArrayOutputStream;
|
|
import java.io.File;
|
|
import java.io.FileInputStream;
|
|
import java.io.FileOutputStream;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.io.OutputStream;
|
|
import java.net.HttpURLConnection;
|
|
import java.net.URL;
|
|
import java.text.SimpleDateFormat;
|
|
import java.util.Date;
|
|
import java.util.List;
|
|
|
|
import simple.SimpleXml;
|
|
import simple.SimpleXmlNode;
|
|
|
|
/**
|
|
* This {@code IntentService} does the app's actual work.
|
|
* {@code RecheckAlarmReceiver} (a {@code WakefulBroadcastReceiver}) holds a
|
|
* partial wake lock for this service while the service does its work. When the
|
|
* service is finished, it calls {@code completeWakefulIntent()} to release the
|
|
* wake lock.
|
|
*/
|
|
public class ElectronReminderService extends IntentService
|
|
{
|
|
public ElectronReminderService()
|
|
{
|
|
super("ElectronReminderService");
|
|
}
|
|
|
|
public static final String TAG = "Electron Reminder";
|
|
|
|
private String token = null;
|
|
private NotificationManager mNotificationManager;
|
|
NotificationCompat.Builder builder;
|
|
|
|
@Override
|
|
protected void onHandleIntent(Intent intent)
|
|
{
|
|
String action = intent.getAction();
|
|
FileOutputStream fs = null;
|
|
InputStream is = null;
|
|
try
|
|
{
|
|
if (action.equals("load_cities"))
|
|
{
|
|
File file = new File(getFilesDir(), "suburban_cities.xml");
|
|
if (!file.exists() || file.lastModified() < System.currentTimeMillis()-86400*7*1000)
|
|
{
|
|
is = downloadUrl("http://static.rasp.yandex.net/data/export/suburban_cities.xml");
|
|
fs = new FileOutputStream(file);
|
|
copyStream(is, fs);
|
|
}
|
|
Intent i = new Intent("cities_loaded");
|
|
LocalBroadcastManager.getInstance(this).sendBroadcast(i);
|
|
}
|
|
else if (action == "load_stations")
|
|
{
|
|
int cityId = intent.getIntExtra("city_id", 0);
|
|
is = downloadUrl("http://mobile.rasp.yandex.net/export/suburban/city/"+cityId+"/stations?uuid="+token);
|
|
File file = new File(getFilesDir(), "stations_"+cityId+".xml");
|
|
fs = new FileOutputStream(file);
|
|
copyStream(is, fs);
|
|
Intent i = new Intent("stations_loaded");
|
|
LocalBroadcastManager.getInstance(this).sendBroadcast(i);
|
|
}
|
|
else if (action == "load_trips")
|
|
{
|
|
int from = intent.getIntExtra("from", 0);
|
|
int to = intent.getIntExtra("to", 0);
|
|
String date = intent.getStringExtra("date");
|
|
getTrips(from, to, date, false);
|
|
Intent i = new Intent("trips_loaded");
|
|
LocalBroadcastManager.getInstance(this).sendBroadcast(i);
|
|
}
|
|
else if (action == "refresh_all")
|
|
{
|
|
File file = new File(getFilesDir(), "reminders.xml");
|
|
if (file.exists())
|
|
{
|
|
FileInputStream fis = new FileInputStream(file);
|
|
SimpleXmlNode remindersRoot = SimpleXml.parse(fis);
|
|
fis.close();
|
|
int i = 0;
|
|
Date d = new Date();
|
|
String curTime = new SimpleDateFormat("hh:mm").format(d);
|
|
SimpleDateFormat ymd = new SimpleDateFormat("yyyy-MM-dd");
|
|
for (SimpleXmlNode reminder: remindersRoot.childrenByName.get("reminder"))
|
|
{
|
|
int from = Integer.valueOf(reminder.attributes.get("from"));
|
|
int to = Integer.valueOf(reminder.attributes.get("to"));
|
|
String time = reminder.attributes.get("time");
|
|
String date;
|
|
// FIXME Check for different date?
|
|
if (time.compareTo(curTime) >= 0)
|
|
date = ymd.format(new Date(d.getTime()+86400000));
|
|
else
|
|
date = ymd.format(d);
|
|
List<SimpleXmlNode> segments = getTrips(from, to, date, true);
|
|
boolean found = false;
|
|
for (SimpleXmlNode seg: segments)
|
|
{
|
|
if (String.valueOf(from).equals(seg.attributes.get("from")) &&
|
|
String.valueOf(to).equals(seg.attributes.get("to")) &&
|
|
(date+" "+time).equals(seg.attributes.get("departure")))
|
|
{
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!found)
|
|
sendNotification(i, from, to, reminder.attributes.get("fromName"), reminder.attributes.get("toName"), time);
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch(IOException e)
|
|
{
|
|
Toast.makeText(getApplicationContext(), "Network error: "+e.getMessage(), Toast.LENGTH_LONG).show();
|
|
}
|
|
catch (XmlPullParserException e)
|
|
{
|
|
Toast.makeText(getApplicationContext(), "Error parsing XML: "+e.getMessage(), Toast.LENGTH_LONG).show();
|
|
}
|
|
finally
|
|
{
|
|
try
|
|
{
|
|
if (is != null)
|
|
is.close();
|
|
if (fs != null)
|
|
fs.close();
|
|
}
|
|
catch(IOException e)
|
|
{
|
|
}
|
|
}
|
|
// Release the wake lock provided by the BroadcastReceiver.
|
|
RecheckAlarmReceiver.completeWakefulIntent(intent);
|
|
}
|
|
|
|
private List<SimpleXmlNode> getTrips(int from, int to, String date, boolean decode) throws IOException, XmlPullParserException
|
|
{
|
|
if (token == null)
|
|
initToken();
|
|
FileOutputStream fs = null;
|
|
try
|
|
{
|
|
byte[] trips = loadFromNetwork(
|
|
"http://mobile.rasp.yandex.net/export/suburban/trip/"+from+"/"+to+
|
|
"/?date="+date+"&tomorrow_upto=12&uuid="+token
|
|
);
|
|
File file = new File(getFilesDir(), "trips_"+from+"_"+to+".xml");
|
|
fs = new FileOutputStream(file);
|
|
fs.write(trips);
|
|
if (decode)
|
|
{
|
|
ByteArrayInputStream bis = new ByteArrayInputStream(trips);
|
|
SimpleXmlNode node = SimpleXml.parse(bis);
|
|
bis.close();
|
|
return node.childrenByName.get("segment");
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
if (fs != null)
|
|
fs.close();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private void copyStream(InputStream is, OutputStream os) throws IOException
|
|
{
|
|
byte[] buf = new byte[0x10000];
|
|
int r;
|
|
while ((r = is.read(buf)) > 0)
|
|
os.write(buf, 0, r);
|
|
}
|
|
|
|
private boolean initToken() throws IOException, XmlPullParserException
|
|
{
|
|
// FIXME Store token?
|
|
SimpleXmlNode node = SimpleXml.parse(downloadUrl("http://mobile.rasp.yandex.net/rasp/startup?app_platform=android&app_version=200"));
|
|
List<SimpleXmlNode> l = node.childrenByName.get("uuid");
|
|
if (l != null)
|
|
{
|
|
token = l.get(0).value;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Post a notification indicating suburban changes
|
|
private void sendNotification(int notificationId, int from, int to, String fromName, String toName, String time)
|
|
{
|
|
mNotificationManager = (NotificationManager)
|
|
this.getSystemService(Context.NOTIFICATION_SERVICE);
|
|
|
|
Intent i = new Intent(this, MainActivity.class);
|
|
i.putExtra("from", from);
|
|
i.putExtra("to", to);
|
|
i.putExtra("time", time);
|
|
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
|
|
new Intent(this, MainActivity.class), 0);
|
|
|
|
String msg = getString(R.string.changes_details, fromName, toName, time);
|
|
NotificationCompat.Builder mBuilder =
|
|
new NotificationCompat.Builder(this)
|
|
.setSmallIcon(R.mipmap.ic_launcher)
|
|
.setContentTitle(getString(R.string.changes_detected))
|
|
.setStyle(new NotificationCompat.BigTextStyle().bigText(msg))
|
|
.setContentText(msg);
|
|
|
|
mBuilder.setContentIntent(contentIntent);
|
|
mNotificationManager.notify(notificationId, mBuilder.build());
|
|
}
|
|
|
|
// Given a URL string, initiate a fetch operation.
|
|
private byte[] loadFromNetwork(String urlString) throws IOException
|
|
{
|
|
InputStream stream = null;
|
|
try
|
|
{
|
|
stream = downloadUrl(urlString);
|
|
return readStream(stream);
|
|
}
|
|
finally
|
|
{
|
|
if (stream != null)
|
|
stream.close();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Given a string representation of a URL, sets up a connection and gets
|
|
* an input stream.
|
|
* @param urlString A string representation of a URL.
|
|
* @return An InputStream retrieved from a successful HttpURLConnection.
|
|
* @throws IOException
|
|
*/
|
|
private InputStream downloadUrl(String urlString) throws IOException
|
|
{
|
|
URL url = new URL(urlString);
|
|
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
|
conn.setReadTimeout(10000 /* milliseconds */);
|
|
conn.setConnectTimeout(15000 /* milliseconds */);
|
|
conn.setRequestMethod("GET");
|
|
conn.setDoInput(true);
|
|
// Start the query
|
|
conn.connect();
|
|
InputStream stream = conn.getInputStream();
|
|
return stream;
|
|
}
|
|
|
|
private byte[] readStream(InputStream is) throws IOException
|
|
{
|
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
|
copyStream(is, bos);
|
|
return bos.toByteArray();
|
|
}
|
|
}
|