Android 12 foreground restrictions

pull/206/head
M66B 4 years ago
parent 0903fb77ea
commit 244b6df87e

@ -19,7 +19,7 @@ android {
defaultConfig { defaultConfig {
applicationId "eu.faircode.email" applicationId "eu.faircode.email"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 30 targetSdkVersion 31
versionCode getVersionCode() versionCode getVersionCode()
versionName "1." + getVersionCode() versionName "1." + getVersionCode()
archivesBaseName = "FairEmail-v$versionName" archivesBaseName = "FairEmail-v$versionName"

@ -44,7 +44,7 @@ public class AlarmManagerCompatEx {
AlarmManagerCompat.setAndAllowWhileIdle(am, type, trigger, pi); AlarmManagerCompat.setAndAllowWhileIdle(am, type, trigger, pi);
} }
static boolean hasExactAlarms(Context context){ static boolean hasExactAlarms(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean exact_alarms = prefs.getBoolean("exact_alarms", true); boolean exact_alarms = prefs.getBoolean("exact_alarms", true);
return (exact_alarms && canScheduleExactAlarms(context)); return (exact_alarms && canScheduleExactAlarms(context));
@ -53,10 +53,13 @@ public class AlarmManagerCompatEx {
static boolean canScheduleExactAlarms(Context context) { static boolean canScheduleExactAlarms(Context context) {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R)
return true; return true;
else { try {
// https://developer.android.com/about/versions/12/behavior-changes-12#exact-alarm-permission // https://developer.android.com/about/versions/12/behavior-changes-12#exact-alarm-permission
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
return am.canScheduleExactAlarms(); return am.canScheduleExactAlarms();
} catch (Throwable ex) {
Log.e(ex);
return false;
} }
} }
} }

@ -196,8 +196,10 @@ public class ApplicationEx extends Application
DisconnectBlacklist.init(this); DisconnectBlacklist.init(this);
ServiceSynchronize.watchdog(this); if (!Helper.isOptimizing12(this)) {
ServiceSend.watchdog(this); ServiceSynchronize.watchdog(this);
ServiceSend.watchdog(this);
}
ServiceSynchronize.scheduleWatchdog(this); ServiceSynchronize.scheduleWatchdog(this);
WorkManager.getInstance(this).cancelUniqueWork("WorkerWatchdog"); WorkManager.getInstance(this).cancelUniqueWork("WorkerWatchdog");
@ -519,6 +521,9 @@ public class ApplicationEx extends Application
} else if (version < 1721) { } else if (version < 1721) {
if (!prefs.contains("discard_delete")) if (!prefs.contains("discard_delete"))
editor.putBoolean("discard_delete", false); editor.putBoolean("discard_delete", false);
} else if (version < 1732) {
if (Helper.isOptimizing12(context))
editor.remove("setup_reminder");
} }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !BuildConfig.DEBUG) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !BuildConfig.DEBUG)

@ -174,12 +174,7 @@ public class EntityAccount extends EntityOrder implements Serializable {
} }
boolean isExempted(Context context) { boolean isExempted(Context context) {
if (Helper.isTarget(context, Build.VERSION_CODES.R)) { return (!Helper.isOptimizing12(context) && this.poll_exempted);
Boolean ignoring = Helper.isIgnoringOptimizations(context);
if (ignoring != null && !ignoring)
return false;
}
return this.poll_exempted;
} }
String getProtocol() { String getProtocol() {

@ -49,7 +49,7 @@ public class FragmentDialogStill extends FragmentDialogBase {
View dview = LayoutInflater.from(context).inflate(R.layout.dialog_setup, null); View dview = LayoutInflater.from(context).inflate(R.layout.dialog_setup, null);
TextView tvDozeDevice = dview.findViewById(R.id.tvDozeDevice); TextView tvDozeDevice = dview.findViewById(R.id.tvDozeDevice);
TextView tvDozeAndroid = dview.findViewById(R.id.tvDozeAndroid); TextView tvDozeAndroid = dview.findViewById(R.id.tvDozeAndroid);
ImageButton ibInfo = dview.findViewById(R.id.ibInfo); TextView tvInexact = dview.findViewById(R.id.tvInexact);
CheckBox cbNotAgain = dview.findViewById(R.id.cbNotAgain); CheckBox cbNotAgain = dview.findViewById(R.id.cbNotAgain);
Group grp2 = dview.findViewById(R.id.grp2); Group grp2 = dview.findViewById(R.id.grp2);
Group grp3 = dview.findViewById(R.id.grp3); Group grp3 = dview.findViewById(R.id.grp3);
@ -62,13 +62,6 @@ public class FragmentDialogStill extends FragmentDialogBase {
} }
}); });
ibInfo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Helper.view(v.getContext(), Uri.parse(Helper.DONTKILL_URI), true);
}
});
cbNotAgain.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { cbNotAgain.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override @Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
@ -80,11 +73,12 @@ public class FragmentDialogStill extends FragmentDialogBase {
boolean hasPermissions = Helper.hasPermission(context, Manifest.permission.READ_CONTACTS); boolean hasPermissions = Helper.hasPermission(context, Manifest.permission.READ_CONTACTS);
Boolean isIgnoring = Helper.isIgnoringOptimizations(context); Boolean isIgnoring = Helper.isIgnoringOptimizations(context);
boolean isKilling = Helper.isKilling() && !(isIgnoring == null || isIgnoring); boolean isKilling = Helper.isKilling() && !(isIgnoring == null || isIgnoring);
boolean isRequired = Helper.isDozeRequired() && !(isIgnoring == null || isIgnoring); boolean isOptimizing = Helper.isOptimizing12(context);
boolean canSchedule = AlarmManagerCompatEx.canScheduleExactAlarms(context);
tvDozeDevice.setVisibility(isKilling && !isRequired ? View.VISIBLE : View.GONE); tvDozeDevice.setVisibility(isKilling && !isOptimizing ? View.VISIBLE : View.GONE);
tvDozeAndroid.setVisibility(isRequired ? View.VISIBLE : View.GONE); tvDozeAndroid.setVisibility(isOptimizing ? View.VISIBLE : View.GONE);
cbNotAgain.setVisibility(isRequired ? View.GONE : View.VISIBLE); tvInexact.setVisibility(canSchedule ? View.GONE : View.VISIBLE);
grp2.setVisibility(hasPermissions ? View.GONE : View.VISIBLE); grp2.setVisibility(hasPermissions ? View.GONE : View.VISIBLE);
grp3.setVisibility(isIgnoring == null || isIgnoring ? View.GONE : View.VISIBLE); grp3.setVisibility(isIgnoring == null || isIgnoring ? View.GONE : View.VISIBLE);
@ -96,10 +90,8 @@ public class FragmentDialogStill extends FragmentDialogBase {
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
sendResult(Activity.RESULT_OK); sendResult(Activity.RESULT_OK);
} }
}); })
.setNegativeButton(android.R.string.cancel, null);
if (!isRequired)
builder.setNegativeButton(android.R.string.cancel, null);
return builder.create(); return builder.create();
} }

@ -4189,15 +4189,21 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
if (viewType != AdapterMessage.ViewType.UNIFIED) if (viewType != AdapterMessage.ViewType.UNIFIED)
return false; return false;
if (!Helper.isDozeRequired()) final Context context = getContext();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean setup_reminder = prefs.getBoolean("setup_reminder", true);
if (!setup_reminder)
return false; return false;
final Context context = getContext(); boolean isOptimizing = Helper.isOptimizing12(context);
Boolean isIgnoring = Helper.isIgnoringOptimizations(context); boolean canSchedule = AlarmManagerCompatEx.canScheduleExactAlarms(context);
if (isIgnoring == null || isIgnoring)
if (!isOptimizing && canSchedule)
return false; return false;
final Snackbar snackbar = Snackbar.make(view, R.string.title_setup_doze, Snackbar.LENGTH_INDEFINITE) final Snackbar snackbar = Snackbar.make(view,
canSchedule ? R.string.title_setup_doze_12 : R.string.title_setup_alarm_12,
Snackbar.LENGTH_INDEFINITE)
.setGestureInsetBottomIgnored(true); .setGestureInsetBottomIgnored(true);
snackbar.setAction(R.string.title_fix, new View.OnClickListener() { snackbar.setAction(R.string.title_fix, new View.OnClickListener() {
@Override @Override

@ -556,7 +556,8 @@ public class FragmentOptionsSynchronize extends FragmentBase implements SharedPr
} }
private void bindTo(EntityAccount account) { private void bindTo(EntityAccount account) {
cbExempted.setEnabled(!account.ondemand && account.protocol == EntityAccount.TYPE_IMAP); cbExempted.setEnabled(!Helper.isOptimizing12(context) &&
!account.ondemand && account.protocol == EntityAccount.TYPE_IMAP);
cbExempted.setChecked(account.poll_exempted); cbExempted.setChecked(account.poll_exempted);
cbExempted.setText(account.name); cbExempted.setText(account.name);
} }

@ -93,6 +93,7 @@ public class FragmentSetup extends FragmentBase {
private TextView tvDozeDone; private TextView tvDozeDone;
private Button btnDoze; private Button btnDoze;
private TextView tvDoze12;
private Button btnInexactAlarms; private Button btnInexactAlarms;
private Button btnBackgroundRestricted; private Button btnBackgroundRestricted;
@ -158,6 +159,7 @@ public class FragmentSetup extends FragmentBase {
tvDozeDone = view.findViewById(R.id.tvDozeDone); tvDozeDone = view.findViewById(R.id.tvDozeDone);
btnDoze = view.findViewById(R.id.btnDoze); btnDoze = view.findViewById(R.id.btnDoze);
tvDoze12 = view.findViewById(R.id.tvDoze12);
btnInexactAlarms = view.findViewById(R.id.btnInexactAlarms); btnInexactAlarms = view.findViewById(R.id.btnInexactAlarms);
btnBackgroundRestricted = view.findViewById(R.id.btnBackgroundRestricted); btnBackgroundRestricted = view.findViewById(R.id.btnBackgroundRestricted);
@ -534,6 +536,7 @@ public class FragmentSetup extends FragmentBase {
tvDozeDone.setText(null); tvDozeDone.setText(null);
tvDozeDone.setCompoundDrawables(null, null, null, null); tvDozeDone.setCompoundDrawables(null, null, null, null);
btnDoze.setEnabled(false); btnDoze.setEnabled(false);
tvDoze12.setVisibility(View.GONE);
btnInbox.setEnabled(false); btnInbox.setEnabled(false);
@ -660,9 +663,10 @@ public class FragmentSetup extends FragmentBase {
tvDozeDone.setTextColor(ignoring == null || ignoring ? textColorPrimary : colorWarning); tvDozeDone.setTextColor(ignoring == null || ignoring ? textColorPrimary : colorWarning);
tvDozeDone.setTypeface(null, ignoring == null || ignoring ? Typeface.NORMAL : Typeface.BOLD); tvDozeDone.setTypeface(null, ignoring == null || ignoring ? Typeface.NORMAL : Typeface.BOLD);
tvDozeDone.setCompoundDrawablesWithIntrinsicBounds(ignoring == null || ignoring ? check : null, null, null, null); tvDozeDone.setCompoundDrawablesWithIntrinsicBounds(ignoring == null || ignoring ? check : null, null, null, null);
tvDoze12.setVisibility(Helper.isOptimizing12(getContext()) ? View.VISIBLE : View.GONE);
grpInexactAlarms.setVisibility( grpInexactAlarms.setVisibility(
!AlarmManagerCompatEx.canScheduleExactAlarms(getContext()) !AlarmManagerCompatEx.canScheduleExactAlarms(getContext()) || BuildConfig.DEBUG
? View.VISIBLE : View.GONE); ? View.VISIBLE : View.GONE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {

@ -433,20 +433,12 @@ public class Helper {
return pm.isIgnoringBatteryOptimizations(BuildConfig.APPLICATION_ID); return pm.isIgnoringBatteryOptimizations(BuildConfig.APPLICATION_ID);
} }
private static Integer targetSdk = null; static boolean isOptimizing12(Context context) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S)
static boolean isTarget(Context context, int sdk) { return false;
if (targetSdk == null)
try {
PackageManager pm = context.getPackageManager();
ApplicationInfo ai = pm.getApplicationInfo(BuildConfig.APPLICATION_ID, 0);
targetSdk = ai.targetSdkVersion;
} catch (Throwable ex) {
Log.e(ex);
targetSdk = Build.VERSION.SDK_INT;
}
return (targetSdk >= sdk); Boolean ignoring = Helper.isIgnoringOptimizations(context);
return (ignoring != null && !ignoring);
} }
static Integer getBatteryLevel(Context context) { static Integer getBatteryLevel(Context context) {

@ -2721,11 +2721,8 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
} }
static int getPollInterval(Context context) { static int getPollInterval(Context context) {
if (Helper.isTarget(context, Build.VERSION_CODES.R)) { if (Helper.isOptimizing12(context))
Boolean ignoring = Helper.isIgnoringOptimizations(context); return (BuildConfig.DEBUG ? 2 : 15);
if (ignoring != null && !ignoring)
return 15;
}
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getInt("poll_interval", 0); // minutes return prefs.getInt("poll_interval", 0); // minutes

@ -89,7 +89,7 @@
android:id="@+id/tvDozeDevice" android:id="@+id/tvDozeDevice"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="6dp" android:layout_marginTop="12dp"
android:drawableEnd="@drawable/twotone_open_in_new_12" android:drawableEnd="@drawable/twotone_open_in_new_12"
android:drawablePadding="6dp" android:drawablePadding="6dp"
android:drawableTint="?attr/colorWarning" android:drawableTint="?attr/colorWarning"
@ -104,24 +104,25 @@
android:id="@+id/tvDozeAndroid" android:id="@+id/tvDozeAndroid"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="6dp" android:layout_marginTop="12dp"
android:text="@string/title_setup_doze_android" android:text="@string/title_setup_doze_12"
android:textAppearance="@style/TextAppearance.AppCompat.Small" android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:textColor="?attr/colorWarning" android:textColor="?attr/colorWarning"
android:textStyle="bold" android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvDozeDevice" /> app:layout_constraintTop_toBottomOf="@id/tvDozeDevice" />
<ImageButton <eu.faircode.email.FixedTextView
android:id="@+id/ibInfo" android:id="@+id/tvInexact"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="6dp" android:layout_marginTop="12dp"
android:contentDescription="@string/title_info" android:text="@string/title_setup_alarm_12"
android:tooltipText="@string/title_info" android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:textColor="?attr/colorWarning"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tvDozeAndroid" app:layout_constraintTop_toBottomOf="@id/tvDozeAndroid" />
app:srcCompat="@drawable/twotone_info_24" />
<CheckBox <CheckBox
android:id="@+id/cbNotAgain" android:id="@+id/cbNotAgain"
@ -131,7 +132,7 @@
android:text="@string/title_no_ask_again" android:text="@string/title_no_ask_again"
android:textAppearance="@style/TextAppearance.AppCompat.Small" android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/ibInfo" /> app:layout_constraintTop_toBottomOf="@id/tvInexact" />
<androidx.constraintlayout.widget.Group <androidx.constraintlayout.widget.Group
android:id="@+id/grp2" android:id="@+id/grp2"
@ -143,6 +144,6 @@
android:id="@+id/grp3" android:id="@+id/grp3"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
app:constraint_referenced_ids="three,title3,tvDoze,ibInfo" /> app:constraint_referenced_ids="three,title3,tvDoze" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</eu.faircode.email.ScrollViewEx> </eu.faircode.email.ScrollViewEx>

@ -703,17 +703,41 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btnDoze" /> app:layout_constraintTop_toBottomOf="@id/btnDoze" />
<eu.faircode.email.FixedTextView
android:id="@+id/tvDoze12"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_setup_doze_12"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:textColor="?attr/colorWarning"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvDozeHint" />
<eu.faircode.email.FixedTextView <eu.faircode.email.FixedTextView
android:id="@+id/tvInexactAlarms" android:id="@+id/tvInexactAlarms"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="12dp" android:layout_marginTop="12dp"
android:text="@string/title_setup_inexact" android:text="@string/title_setup_inexact"
android:textAppearance="@style/TextAppearance.AppCompat.Small" android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:textColor="?attr/colorWarning" android:textColor="?attr/colorWarning"
android:textStyle="bold" android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvDozeHint" /> app:layout_constraintTop_toBottomOf="@id/tvDoze12" />
<eu.faircode.email.FixedTextView
android:id="@+id/tvInexactAlarmsWarning"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:text="@string/title_setup_alarm_12"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:textColor="?attr/colorWarning"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvInexactAlarms" />
<Button <Button
android:id="@+id/btnInexactAlarms" android:id="@+id/btnInexactAlarms"
@ -726,7 +750,7 @@
android:drawablePadding="6dp" android:drawablePadding="6dp"
android:text="@string/title_setup_manage" android:text="@string/title_setup_manage"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvInexactAlarms" /> app:layout_constraintTop_toBottomOf="@id/tvInexactAlarmsWarning" />
<eu.faircode.email.FixedTextView <eu.faircode.email.FixedTextView
android:id="@+id/tvBackgroundRestricted" android:id="@+id/tvBackgroundRestricted"
@ -734,7 +758,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="12dp" android:layout_marginTop="12dp"
android:text="@string/title_setup_background" android:text="@string/title_setup_background"
android:textAppearance="@style/TextAppearance.AppCompat.Small" android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:textColor="?attr/colorWarning" android:textColor="?attr/colorWarning"
android:textStyle="bold" android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
@ -759,7 +783,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="12dp" android:layout_marginTop="12dp"
android:text="@string/title_setup_data" android:text="@string/title_setup_data"
android:textAppearance="@style/TextAppearance.AppCompat.Small" android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:textColor="?attr/colorWarning" android:textColor="?attr/colorWarning"
android:textStyle="bold" android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
@ -825,7 +849,7 @@
android:id="@+id/grpInexactAlarms" android:id="@+id/grpInexactAlarms"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
app:constraint_referenced_ids="tvInexactAlarms,btnInexactAlarms" /> app:constraint_referenced_ids="tvInexactAlarms,tvInexactAlarmsWarning,btnInexactAlarms" />
<androidx.constraintlayout.widget.Group <androidx.constraintlayout.widget.Group
android:id="@+id/grpBackgroundRestricted" android:id="@+id/grpBackgroundRestricted"

@ -226,7 +226,8 @@
<string name="title_setup_doze_battery">High battery usage?</string> <string name="title_setup_doze_battery">High battery usage?</string>
<string name="title_setup_doze_stopped">Sync stopped?</string> <string name="title_setup_doze_stopped">Sync stopped?</string>
<string name="title_setup_doze_device">This is probably required for this device</string> <string name="title_setup_doze_device">This is probably required for this device</string>
<string name="title_setup_doze_android">This is required for this Android version</string> <string name="title_setup_doze_12">Push messages are disabled</string>
<string name="title_setup_alarm_12">The app won\'t work</string>
<string name="title_setup_inexact">Alarms &amp; reminders are disabled</string> <string name="title_setup_inexact">Alarms &amp; reminders are disabled</string>
<string name="title_setup_background">Background restrictions are enabled</string> <string name="title_setup_background">Background restrictions are enabled</string>
<string name="title_setup_data">Data saver is enabled</string> <string name="title_setup_data">Data saver is enabled</string>

Loading…
Cancel
Save