Import GingerCal 1.0 source
This commit is contained in:
commit
01f49852ab
116 files changed
+5079
No files matched your search
@@ -0,0 +1,233 @@
|
||||
package org.gingercal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ConnectException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.URI;
|
||||
import java.net.UnknownHostException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.net.ssl.SSLException;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlarmManager;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.gingercal.Model.Ev;
|
||||
|
||||
/** Shared helpers: settings, formatting, scheduling, dialogs. */
|
||||
public final class App {
|
||||
private App() {}
|
||||
|
||||
public static final int[] INTERVALS = {0, 1, 3, 6, 12, 24};
|
||||
public static final int[] ALARMS = {-1, 0, 5, 10, 15, 30, 60, 120, 1440};
|
||||
|
||||
public static SharedPreferences prefs(Context c) {
|
||||
return c.getSharedPreferences("gingercal", 0);
|
||||
}
|
||||
|
||||
public static String get(Context c, String k) {
|
||||
return prefs(c).getString(k, "");
|
||||
}
|
||||
|
||||
public static boolean configured(Context c) {
|
||||
return get(c, "url").length() > 0 && get(c, "user").length() > 0;
|
||||
}
|
||||
|
||||
public static int interval(Context c) {
|
||||
return prefs(c).getInt("interval", 3);
|
||||
}
|
||||
|
||||
public static int remind(Context c) {
|
||||
return prefs(c).getInt("remind", 15);
|
||||
}
|
||||
|
||||
public static int ahead(Context c) {
|
||||
return prefs(c).getInt("ahead", 60);
|
||||
}
|
||||
|
||||
public static Dav dav(Context c) throws Exception {
|
||||
return dav(get(c, "url"), get(c, "user"), get(c, "pass"), get(c, "pin"));
|
||||
}
|
||||
|
||||
public static Dav dav(String url, String user, String pass, String pin) throws Exception {
|
||||
return new Dav(new ApacheHttp(pin, 30000), url, user, pass);
|
||||
}
|
||||
|
||||
public static boolean online(Context c) {
|
||||
ConnectivityManager cm = (ConnectivityManager) c.getSystemService("connectivity");
|
||||
NetworkInfo ni = cm == null ? null : cm.getActiveNetworkInfo();
|
||||
return ni != null && ni.isConnected();
|
||||
}
|
||||
|
||||
public static void requestSync(Context c, boolean manual, boolean force) {
|
||||
Intent i = new Intent(c, SyncService.class);
|
||||
i.putExtra("manual", manual);
|
||||
i.putExtra("force", force);
|
||||
c.startService(i);
|
||||
}
|
||||
|
||||
/** (Re)arms the periodic background sync. */
|
||||
public static void scheduleSync(Context c) {
|
||||
AlarmManager am = (AlarmManager) c.getSystemService("alarm");
|
||||
Intent i = new Intent(c, AlarmReceiver.class);
|
||||
i.setAction(AlarmReceiver.SYNC);
|
||||
PendingIntent pi = PendingIntent.getBroadcast(c, 1, i, 0);
|
||||
am.cancel(pi);
|
||||
int h = interval(c);
|
||||
if (h > 0 && configured(c)) {
|
||||
long every = h * ICal.HOUR;
|
||||
am.setInexactRepeating(1 /* RTC: don't wake the phone just to sync */,
|
||||
System.currentTimeMillis() + every, every, pi);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isLan(String url) {
|
||||
try {
|
||||
String h = URI.create(Dav.normalize(url)).getHost();
|
||||
if (h == null) return false;
|
||||
h = h.toLowerCase(Locale.US);
|
||||
if (h.startsWith("10.") || h.startsWith("192.168.") || h.equals("localhost") || h.endsWith(".local")
|
||||
|| h.endsWith(".lan") || h.endsWith(".home.arpa")) return true;
|
||||
if (h.startsWith("172.")) {
|
||||
String[] p = h.split("\\.");
|
||||
int b = Integer.parseInt(p[1]);
|
||||
return b >= 16 && b <= 31;
|
||||
}
|
||||
if (h.startsWith("100.")) { // CGNAT / Tailscale-style ranges
|
||||
int b = Integer.parseInt(h.split("\\.")[1]);
|
||||
return b >= 64 && b <= 127;
|
||||
}
|
||||
} catch (RuntimeException ignored) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------ messages
|
||||
|
||||
public static String describe(Throwable t) {
|
||||
if (t instanceof DavException || t instanceof DavException.UntrustedCert) return t.getMessage();
|
||||
if (t instanceof UnknownHostException) {
|
||||
return "Can't resolve " + t.getMessage() + ". No connection, or a typo in the server address.";
|
||||
}
|
||||
if (t instanceof ConnectException) return "Can't connect to the server (" + t.getMessage() + "). Wrong port, or the bridge is down?";
|
||||
if (t instanceof SocketTimeoutException) return "The server took too long to answer.";
|
||||
if (t instanceof SSLException) return "TLS error: " + t.getMessage();
|
||||
if (t instanceof IOException) return "Network error: " + t;
|
||||
if (t instanceof OutOfMemoryError) return "Out of memory. Lower 'Days ahead' in Settings.";
|
||||
return "Error: " + t;
|
||||
}
|
||||
|
||||
public static void toast(Context c, String s) {
|
||||
Toast.makeText(c, s, 1).show();
|
||||
}
|
||||
|
||||
public interface Trusted {
|
||||
void trusted(String fingerprint);
|
||||
}
|
||||
|
||||
public static void askTrust(Activity a, final DavException.UntrustedCert u, final Trusted cb) {
|
||||
String msg = (u.pinMismatch
|
||||
? "WARNING: the server certificate changed since you trusted it. That happens when you "
|
||||
+ "regenerate the bridge certificate - or when someone is intercepting the connection.\n\n"
|
||||
: "This phone doesn't trust the server certificate (normal for the self-signed legacy bridge, "
|
||||
+ "or for Let's Encrypt on Android 2.3).\n\n")
|
||||
+ "Subject: " + u.subject + "\nIssuer: " + u.issuer + "\nExpires: " + u.expires
|
||||
+ "\n\nSHA-256:\n" + u.fingerprint
|
||||
+ "\n\nOnly trust it if this matches the fingerprint printed on your server.";
|
||||
new AlertDialog.Builder(a)
|
||||
.setTitle(u.pinMismatch ? "Certificate changed!" : "Trust this certificate?")
|
||||
.setMessage(msg)
|
||||
.setPositiveButton("Trust", new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface d, int w) {
|
||||
cb.trusted(u.fingerprint);
|
||||
}
|
||||
})
|
||||
.setNegativeButton("Cancel", null)
|
||||
.show();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------ formatting
|
||||
|
||||
public static String time(Context c, long t) {
|
||||
String p = android.text.format.DateFormat.is24HourFormat(c) ? "HH:mm" : "h:mma";
|
||||
return new SimpleDateFormat(p, Locale.getDefault()).format(new Date(t));
|
||||
}
|
||||
|
||||
public static String day(long t) {
|
||||
boolean thisYear = year(t) == year(System.currentTimeMillis());
|
||||
return new SimpleDateFormat(thisYear ? "EEE d MMM" : "EEE d MMM yyyy", Locale.getDefault()).format(new Date(t));
|
||||
}
|
||||
|
||||
static int year(long t) {
|
||||
Calendar c = Calendar.getInstance();
|
||||
c.setTimeInMillis(t);
|
||||
return c.get(Calendar.YEAR);
|
||||
}
|
||||
|
||||
public static String dayHeader(long dayStart) {
|
||||
long today = ICal.startOfDay(System.currentTimeMillis());
|
||||
if (dayStart == today) return "Today · " + day(dayStart);
|
||||
if (dayStart == ICal.addDays(today, 1)) return "Tomorrow · " + day(dayStart);
|
||||
return day(dayStart);
|
||||
}
|
||||
|
||||
public static String when(Context c, Ev e) {
|
||||
if (e.allDay) {
|
||||
long lastDay = ICal.addDays(e.end, -1);
|
||||
if (lastDay <= e.start) return "All day";
|
||||
return "All day, until " + day(lastDay);
|
||||
}
|
||||
String s = time(c, e.start);
|
||||
if (e.end <= e.start) return s;
|
||||
if (ICal.startOfDay(e.end - 1) != ICal.startOfDay(e.start)) {
|
||||
return s + " – " + day(e.end) + " " + time(c, e.end);
|
||||
}
|
||||
return s + " – " + time(c, e.end);
|
||||
}
|
||||
|
||||
public static String alarmLabel(int m) {
|
||||
if (m < 0) return "No reminder";
|
||||
if (m == 0) return "At start time";
|
||||
if (m < 60) return m + " min before";
|
||||
if (m < 1440) return (m / 60) + " h before";
|
||||
return (m / 1440) + " day before";
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------- views
|
||||
|
||||
public static int dp(Context c, float v) {
|
||||
return (int) (v * c.getResources().getDisplayMetrics().density + 0.5f);
|
||||
}
|
||||
|
||||
public static TextView text(Context c, String s, float sp, int color) {
|
||||
TextView t = new TextView(c);
|
||||
t.setText(s);
|
||||
t.setTextSize(sp);
|
||||
t.setTextColor(color);
|
||||
return t;
|
||||
}
|
||||
|
||||
public static LinearLayout vbox(Context c) {
|
||||
LinearLayout l = new LinearLayout(c);
|
||||
l.setOrientation(LinearLayout.VERTICAL);
|
||||
return l;
|
||||
}
|
||||
|
||||
public static int sysDrawable(Context c, String name) {
|
||||
return c.getResources().getIdentifier(name, "drawable", "android");
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user