Workaround 12/24 hour Android 5.1/6 bug

pull/155/head
M66B 5 years ago
parent 2f1c37445b
commit ad6c4cb7ad

@ -25,7 +25,7 @@ For authorizing:
* ~~A [bug in Android](https://issuetracker.google.com/issues/78495471) lets FairEmail occasionally crash on long pressing or swiping.~~
* A [bug in Android](https://issuetracker.google.com/issues/119872129) "*... Bad notification posted ...*" lets FairEmail crash on some devices after updating FairEmail and tapping on a notification.
* A [bug in Android 5.1 and 6](https://issuetracker.google.com/issues/37054851) causes apps to sometimes show a wrong time format. Toggling the Android setting *Use 24-hour format* might temporarily solve the issue.
* ~~A [bug in Android 5.1 and 6](https://issuetracker.google.com/issues/37054851) causes apps to sometimes show a wrong time format. Toggling the Android setting *Use 24-hour format* might temporarily solve the issue.~~
* A [bug in Android](https://issuetracker.google.com/issues/62427912) "*... ActivityRecord not found for ...*" sometimes causes a crash after updating FairEmail.
* ~~A [bug in Google Drive](https://issuetracker.google.com/issues/126362828) causes files exported to Google Drive to be empty.~~
* "*... Couldn't read row ...*" causes sometimes a crash. This could be caused by a bug in the [Room Persistence Library](https://developer.android.com/topic/libraries/architecture/room) but more likely indicates a corrupt database.

@ -25,7 +25,6 @@ import android.content.res.ColorStateList;
import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -108,7 +107,7 @@ public class AdapterContact extends RecyclerView.Adapter<AdapterContact.ViewHold
tvEmail.setText(contact.accountName + "/" + contact.email);
tvTimes.setText(nf.format(contact.times_contacted));
tvLast.setText(contact.last_contacted == null ? null
: DateUtils.getRelativeTimeSpanString(context, contact.last_contacted));
: Helper.getRelativeTimeSpanString(context, contact.last_contacted));
ivFavorite.setImageResource(contact.state == EntityContact.STATE_FAVORITE
? R.drawable.baseline_star_24 : R.drawable.baseline_star_border_24);

@ -41,7 +41,7 @@ public class AdapterLog extends RecyclerView.Adapter<AdapterLog.ViewHolder> {
private List<EntityLog> items = new ArrayList<>();
private DateFormat DF = SimpleDateFormat.getTimeInstance();
private DateFormat TF = SimpleDateFormat.getTimeInstance();
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView tvTime;
@ -55,7 +55,7 @@ public class AdapterLog extends RecyclerView.Adapter<AdapterLog.ViewHolder> {
}
private void bindTo(EntityLog log) {
tvTime.setText(DF.format(log.time));
tvTime.setText(TF.format(log.time));
tvData.setText(log.data);
}
}

@ -52,7 +52,6 @@ import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.text.method.ArrowKeyMovementMethod;
import android.text.style.ImageSpan;
import android.text.style.QuoteSpan;
@ -167,9 +166,9 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
enum ViewType {UNIFIED, FOLDER, THREAD, SEARCH}
private NumberFormat nf = NumberFormat.getNumberInstance();
private DateFormat tf = SimpleDateFormat.getTimeInstance(SimpleDateFormat.SHORT);
private DateFormat dtf = SimpleDateFormat.getDateTimeInstance(SimpleDateFormat.LONG, SimpleDateFormat.LONG);
private NumberFormat NF = NumberFormat.getNumberInstance();
private DateFormat TF;
private DateFormat DTF = SimpleDateFormat.getDateTimeInstance(SimpleDateFormat.LONG, SimpleDateFormat.LONG);
private static final List<String> PARANOID_QUERY = Collections.unmodifiableList(Arrays.asList(
"utm_source",
@ -543,8 +542,8 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
tvSize.setText(size == null ? null : Helper.humanReadableByteCount(size, true));
tvSize.setVisibility(size == null || (message.content && !"size".equals(sort)) ? View.GONE : View.VISIBLE);
tvTime.setText(date && "time".equals(sort)
? tf.format(message.received)
: DateUtils.getRelativeTimeSpanString(context, message.received));
? TF.format(message.received)
: Helper.getRelativeTimeSpanString(context, message.received));
// Line 2
tvSubject.setText(message.subject);
@ -574,7 +573,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
tvCount.setVisibility(View.GONE);
ivThread.setVisibility(View.GONE);
} else {
tvCount.setText(nf.format(message.visible));
tvCount.setText(NF.format(message.visible));
ivThread.setVisibility(View.VISIBLE);
}
@ -596,7 +595,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
if (debug) {
String text = "error=" + error +
"\nuid=" + message.uid + " id=" + message.id + " " + dtf.format(new Date(message.received)) +
"\nuid=" + message.uid + " id=" + message.id + " " + DTF.format(new Date(message.received)) +
"\n" + (message.ui_hide ? "HIDDEN " : "") +
"seen=" + message.seen + "/" + message.ui_seen +
" unseen=" + message.unseen +
@ -833,7 +832,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
tvTimeExTitle.setVisibility(show_addresses ? View.VISIBLE : View.GONE);
tvTimeEx.setVisibility(show_addresses ? View.VISIBLE : View.GONE);
tvTimeEx.setText(dtf.format(message.received));
tvTimeEx.setText(DTF.format(message.received));
if (!message.duplicate)
tvSizeEx.setAlpha(message.content ? 1.0f : Helper.LOW_LIGHT);
@ -3037,6 +3036,8 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
ViewType viewType, boolean compact, int zoom, String sort, boolean duplicates, IProperties properties) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
this.TF = Helper.getTimeInstance(context, SimpleDateFormat.SHORT);
this.context = context;
this.owner = owner;
this.inflater = LayoutInflater.from(context);

@ -23,7 +23,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.text.format.DateUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -99,7 +98,7 @@ public class AdapterOperation extends RecyclerView.Adapter<AdapterOperation.View
tvFolder.setText(folderName);
tvOperation.setText(sb.toString());
tvTime.setText(DateUtils.getRelativeTimeSpanString(context, operation.created));
tvTime.setText(Helper.getRelativeTimeSpanString(context, operation.created));
tvError.setText(operation.error);
tvError.setVisibility(operation.error == null ? View.GONE : View.VISIBLE);
}

@ -637,8 +637,8 @@ public class FragmentOptions extends FragmentBase implements SharedPreferences.O
swEnabled.setChecked(prefs.getBoolean("enabled", true));
swSchedule.setChecked(prefs.getBoolean("schedule", false));
tvScheduleStart.setText(formatHour(prefs.getInt("schedule_start", 0)));
tvScheduleEnd.setText(formatHour(prefs.getInt("schedule_end", 0)));
tvScheduleStart.setText(formatHour(getContext(), prefs.getInt("schedule_start", 0)));
tvScheduleEnd.setText(formatHour(getContext(), prefs.getInt("schedule_end", 0)));
swMetered.setChecked(prefs.getBoolean("metered", true));
@ -714,13 +714,13 @@ public class FragmentOptions extends FragmentBase implements SharedPreferences.O
grpNotification.setVisibility(Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.O ? View.VISIBLE : View.GONE);
}
private String formatHour(int minutes) {
private String formatHour(Context context, int minutes) {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, minutes / 60);
cal.set(Calendar.MINUTE, minutes % 60);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
return SimpleDateFormat.getTimeInstance(SimpleDateFormat.SHORT).format(cal.getTime());
return Helper.getTimeInstance(context, SimpleDateFormat.SHORT).format(cal.getTime());
}
public static class TimePickerFragment extends DialogFragment implements TimePickerDialog.OnTimeSetListener {
@ -819,8 +819,8 @@ public class FragmentOptions extends FragmentBase implements SharedPreferences.O
else if ("schedule".equals(key))
swSchedule.setChecked(prefs.getBoolean(key, false));
else if ("schedule_start".equals(key))
tvScheduleStart.setText(formatHour(prefs.getInt(key, 0)));
tvScheduleStart.setText(formatHour(getContext(), prefs.getInt(key, 0)));
else if ("schedule_end".equals(key))
tvScheduleEnd.setText(formatHour(prefs.getInt(key, 0)));
tvScheduleEnd.setText(formatHour(getContext(), prefs.getInt(key, 0)));
}
}

@ -45,6 +45,8 @@ import android.os.Bundle;
import android.os.Parcel;
import android.os.PowerManager;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.text.format.Time;
import android.view.Display;
import android.view.Menu;
import android.view.View;
@ -101,6 +103,7 @@ import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
@ -1163,4 +1166,32 @@ public class Helper {
bundle.writeToParcel(p, 0);
return p.dataSize();
}
static DateFormat getTimeInstance(Context context, int style) {
// https://issuetracker.google.com/issues/37054851
if (context != null &&
(style == SimpleDateFormat.SHORT || style == SimpleDateFormat.MEDIUM)) {
Locale locale = Locale.getDefault();
boolean is24Hour = android.text.format.DateFormat.is24HourFormat(context);
String skeleton = (is24Hour ? "Hm" : "hm");
if (style == SimpleDateFormat.MEDIUM)
skeleton += "s";
String pattern = android.text.format.DateFormat.getBestDateTimePattern(locale, skeleton);
return new SimpleDateFormat(pattern, locale);
} else
return SimpleDateFormat.getTimeInstance(style);
}
static CharSequence getRelativeTimeSpanString(Context context, long millis) {
long now = System.currentTimeMillis();
long span = Math.abs(now - millis);
Time nowTime = new Time();
Time thenTime = new Time();
nowTime.set(now);
thenTime.set(millis);
if (span < DateUtils.DAY_IN_MILLIS && nowTime.weekDay == thenTime.weekDay)
return getTimeInstance(context, SimpleDateFormat.SHORT).format(millis);
else
return DateUtils.getRelativeTimeSpanString(context, millis);
}
}

Loading…
Cancel
Save