mirror of
https://github.com/M66B/FairEmail.git
synced 2025-03-04 02:28:18 +00:00
Added rule action to play sound
This commit is contained in:
parent
bcbb79014d
commit
afa6ac887b
11 changed files with 215 additions and 16 deletions
|
@ -4,6 +4,12 @@
|
||||||
|
|
||||||
### [Draconyx](https://en.wikipedia.org/wiki/Draconyx)
|
### [Draconyx](https://en.wikipedia.org/wiki/Draconyx)
|
||||||
|
|
||||||
|
### Next version
|
||||||
|
|
||||||
|
* Added rule action to play (alarm) sound
|
||||||
|
* Small improvements and minor bug fixes
|
||||||
|
* Updated translations
|
||||||
|
|
||||||
### 1.1802 - 2022-01-03
|
### 1.1802 - 2022-01-03
|
||||||
|
|
||||||
* Improved original message view scrolling
|
* Improved original message view scrolling
|
||||||
|
|
13
FAQ.md
13
FAQ.md
|
@ -294,7 +294,7 @@ Fonts, sizes, colors, etc should be material design whenever possible.
|
||||||
* [(142) How can I store sent messages in the inbox?](#user-content-faq142)
|
* [(142) How can I store sent messages in the inbox?](#user-content-faq142)
|
||||||
* [~~(143) Can you add a trash folder for POP3 accounts?~~](#user-content-faq143)
|
* [~~(143) Can you add a trash folder for POP3 accounts?~~](#user-content-faq143)
|
||||||
* [(144) How can I record voice notes?](#user-content-faq144)
|
* [(144) How can I record voice notes?](#user-content-faq144)
|
||||||
* [(145) How can I set a notification sound for an account, folder or sender?](#user-content-faq145)
|
* [(145) How can I set a notification sound for an account, folder, sender or condition?](#user-content-faq145)
|
||||||
* [(146) How can I fix incorrect message times?](#user-content-faq146)
|
* [(146) How can I fix incorrect message times?](#user-content-faq146)
|
||||||
* [(147) What should I know about third party versions?](#user-content-faq147)
|
* [(147) What should I know about third party versions?](#user-content-faq147)
|
||||||
* [(148) How can I use an Apple iCloud account?](#user-content-faq148)
|
* [(148) How can I use an Apple iCloud account?](#user-content-faq148)
|
||||||
|
@ -3799,7 +3799,7 @@ Voice notes will automatically be attached.
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
<a name="faq145"></a>
|
<a name="faq145"></a>
|
||||||
**(145) How can I set a notification sound for an account, folder or sender?**
|
**(145) How can I set a notification sound for an account, folder, sender or condition?**
|
||||||
|
|
||||||
🌎 [Google Translate](https://translate.google.com/translate?sl=en&u=https://github.com/M66B/FairEmail/blob/master/FAQ.md%23user-content-faq145)
|
🌎 [Google Translate](https://translate.google.com/translate?sl=en&u=https://github.com/M66B/FairEmail/blob/master/FAQ.md%23user-content-faq145)
|
||||||
|
|
||||||
|
@ -3819,7 +3819,14 @@ Sender:
|
||||||
* Expand the addresses section by tapping on the down arrow
|
* Expand the addresses section by tapping on the down arrow
|
||||||
* Tap on the bell icon to create or edit a notification channel and to change the notification sound
|
* Tap on the bell icon to create or edit a notification channel and to change the notification sound
|
||||||
|
|
||||||
The order of precendence is: sender sound, folder sound, account sound and default sound.
|
Conditional: (since version 1.1803)
|
||||||
|
|
||||||
|
* Long press the folder (inbox) in the folder list and select *Edit rules*
|
||||||
|
* Add a rule with the big 'plus' button at the bottom right
|
||||||
|
* Configure a rule condition, select *Play sound* as rule action and select a sound
|
||||||
|
* For more information about filter rules, please [see here](#user-content-faq71)
|
||||||
|
|
||||||
|
The order of precendence is: conditional sound, sender sound, folder sound, account sound and (default) notification sound.
|
||||||
|
|
||||||
Setting a notification sound for an account, folder or sender requires Android 8 Oreo or later and is a pro feature.
|
Setting a notification sound for an account, folder or sender requires Android 8 Oreo or later and is a pro feature.
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,12 @@
|
||||||
|
|
||||||
### [Draconyx](https://en.wikipedia.org/wiki/Draconyx)
|
### [Draconyx](https://en.wikipedia.org/wiki/Draconyx)
|
||||||
|
|
||||||
|
### Next version
|
||||||
|
|
||||||
|
* Added rule action to play (alarm) sound
|
||||||
|
* Small improvements and minor bug fixes
|
||||||
|
* Updated translations
|
||||||
|
|
||||||
### 1.1802 - 2022-01-03
|
### 1.1802 - 2022-01-03
|
||||||
|
|
||||||
* Improved original message view scrolling
|
* Improved original message view scrolling
|
||||||
|
|
|
@ -186,6 +186,9 @@ public class AdapterRule extends RecyclerView.Adapter<AdapterRule.ViewHolder> {
|
||||||
case EntityRule.TYPE_DELETE:
|
case EntityRule.TYPE_DELETE:
|
||||||
tvAction.setText(R.string.title_rule_delete);
|
tvAction.setText(R.string.title_rule_delete);
|
||||||
break;
|
break;
|
||||||
|
case EntityRule.TYPE_SOUND:
|
||||||
|
tvAction.setText(R.string.title_rule_sound);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Unknown action type=" + type);
|
throw new IllegalArgumentException("Unknown action type=" + type);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,6 @@ import android.content.SharedPreferences;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.telephony.TelephonyManager;
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
@ -114,6 +113,7 @@ public class EntityRule {
|
||||||
static final int TYPE_IMPORTANCE = 13;
|
static final int TYPE_IMPORTANCE = 13;
|
||||||
static final int TYPE_TTS = 14;
|
static final int TYPE_TTS = 14;
|
||||||
static final int TYPE_DELETE = 15;
|
static final int TYPE_DELETE = 15;
|
||||||
|
static final int TYPE_SOUND = 16;
|
||||||
|
|
||||||
static final String ACTION_AUTOMATION = BuildConfig.APPLICATION_ID + ".AUTOMATION";
|
static final String ACTION_AUTOMATION = BuildConfig.APPLICATION_ID + ".AUTOMATION";
|
||||||
static final String EXTRA_RULE = "rule";
|
static final String EXTRA_RULE = "rule";
|
||||||
|
@ -467,6 +467,8 @@ public class EntityRule {
|
||||||
return onActionAutomation(context, message, jaction);
|
return onActionAutomation(context, message, jaction);
|
||||||
case TYPE_DELETE:
|
case TYPE_DELETE:
|
||||||
return onActionDelete(context, message, jaction);
|
return onActionDelete(context, message, jaction);
|
||||||
|
case TYPE_SOUND:
|
||||||
|
return onActionSound(context, message, jaction);
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Unknown rule type=" + type + " name=" + name);
|
throw new IllegalArgumentException("Unknown rule type=" + type + " name=" + name);
|
||||||
}
|
}
|
||||||
|
@ -533,6 +535,11 @@ public class EntityRule {
|
||||||
return;
|
return;
|
||||||
case TYPE_DELETE:
|
case TYPE_DELETE:
|
||||||
return;
|
return;
|
||||||
|
case TYPE_SOUND:
|
||||||
|
String uri = jargs.optString("uri");
|
||||||
|
if (TextUtils.isEmpty(uri))
|
||||||
|
throw new IllegalArgumentException(context.getString(R.string.title_rule_select_sound));
|
||||||
|
return;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Unknown rule type=" + type);
|
throw new IllegalArgumentException("Unknown rule type=" + type);
|
||||||
}
|
}
|
||||||
|
@ -830,13 +837,8 @@ public class EntityRule {
|
||||||
private static void speak(Context context, EntityRule rule, EntityMessage message) throws IOException {
|
private static void speak(Context context, EntityRule rule, EntityMessage message) throws IOException {
|
||||||
Log.i("Speaking name=" + rule.name);
|
Log.i("Speaking name=" + rule.name);
|
||||||
|
|
||||||
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
|
if (message.ui_seen)
|
||||||
int callState = tm.getCallState();
|
|
||||||
if (callState != TelephonyManager.CALL_STATE_IDLE) {
|
|
||||||
EntityLog.log(context, EntityLog.Type.Rules, message,
|
|
||||||
"Call state=" + callState + " rule=" + rule.name);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
Locale locale = (message.language == null ? Locale.getDefault() : new Locale(message.language));
|
Locale locale = (message.language == null ? Locale.getDefault() : new Locale(message.language));
|
||||||
|
|
||||||
|
@ -946,6 +948,34 @@ public class EntityRule {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean onActionSound(Context context, EntityMessage message, JSONObject jargs) throws JSONException {
|
||||||
|
Log.i("Speaking name=" + name);
|
||||||
|
|
||||||
|
if (message.ui_seen)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Uri uri = Uri.parse(jargs.getString("uri"));
|
||||||
|
boolean alarm = jargs.getBoolean("alarm");
|
||||||
|
|
||||||
|
DB db = DB.getInstance(context);
|
||||||
|
|
||||||
|
message.ui_silent = true;
|
||||||
|
db.message().setMessageUiSilent(message.id, message.ui_silent);
|
||||||
|
|
||||||
|
executor.submit(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
MediaPlayerHelper.play(context, uri, alarm);
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
Log.e(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private static Calendar getRelativeCalendar(int minutes, long reference) {
|
private static Calendar getRelativeCalendar(int minutes, long reference) {
|
||||||
int d = minutes / (24 * 60);
|
int d = minutes / (24 * 60);
|
||||||
int h = minutes / 60 % 24;
|
int h = minutes / 60 % 24;
|
||||||
|
|
|
@ -25,6 +25,7 @@ import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
|
import android.media.RingtoneManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.provider.ContactsContract;
|
import android.provider.ContactsContract;
|
||||||
|
@ -146,6 +147,9 @@ public class FragmentRule extends FragmentBase {
|
||||||
private Button btnTtsSetup;
|
private Button btnTtsSetup;
|
||||||
private Button btnTtsData;
|
private Button btnTtsData;
|
||||||
|
|
||||||
|
private Button btnSound;
|
||||||
|
private CheckBox cbAlarm;
|
||||||
|
|
||||||
private TextView tvAutomation;
|
private TextView tvAutomation;
|
||||||
|
|
||||||
private BottomNavigationView bottom_navigation;
|
private BottomNavigationView bottom_navigation;
|
||||||
|
@ -160,6 +164,7 @@ public class FragmentRule extends FragmentBase {
|
||||||
private Group grpMoveProp;
|
private Group grpMoveProp;
|
||||||
private Group grpAnswer;
|
private Group grpAnswer;
|
||||||
private Group grpTts;
|
private Group grpTts;
|
||||||
|
private Group grpSound;
|
||||||
private Group grpAutomation;
|
private Group grpAutomation;
|
||||||
private Group grpDelete;
|
private Group grpDelete;
|
||||||
|
|
||||||
|
@ -174,6 +179,7 @@ public class FragmentRule extends FragmentBase {
|
||||||
private long account = -1;
|
private long account = -1;
|
||||||
private int protocol = -1;
|
private int protocol = -1;
|
||||||
private long folder = -1;
|
private long folder = -1;
|
||||||
|
private Uri sound = null;
|
||||||
|
|
||||||
private DateFormat DF;
|
private DateFormat DF;
|
||||||
|
|
||||||
|
@ -188,8 +194,9 @@ public class FragmentRule extends FragmentBase {
|
||||||
private static final int REQUEST_TO = 7;
|
private static final int REQUEST_TO = 7;
|
||||||
private final static int REQUEST_TTS_CHECK = 8;
|
private final static int REQUEST_TTS_CHECK = 8;
|
||||||
private final static int REQUEST_TTS_DATA = 9;
|
private final static int REQUEST_TTS_DATA = 9;
|
||||||
private final static int REQUEST_DATE_AFTER = 10;
|
private final static int REQUEST_SOUND = 10;
|
||||||
private final static int REQUEST_DATE_BEFORE = 11;
|
private final static int REQUEST_DATE_AFTER = 11;
|
||||||
|
private final static int REQUEST_DATE_BEFORE = 12;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
@ -205,6 +212,9 @@ public class FragmentRule extends FragmentBase {
|
||||||
protocol = args.getInt("protocol", EntityAccount.TYPE_IMAP);
|
protocol = args.getInt("protocol", EntityAccount.TYPE_IMAP);
|
||||||
folder = args.getLong("folder", -1);
|
folder = args.getLong("folder", -1);
|
||||||
|
|
||||||
|
if (savedInstanceState != null)
|
||||||
|
sound = savedInstanceState.getParcelable("fair:sound");
|
||||||
|
|
||||||
DF = Helper.getDateTimeInstance(getContext(), DateFormat.SHORT, DateFormat.SHORT);
|
DF = Helper.getDateTimeInstance(getContext(), DateFormat.SHORT, DateFormat.SHORT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,6 +294,10 @@ public class FragmentRule extends FragmentBase {
|
||||||
|
|
||||||
btnTtsSetup = view.findViewById(R.id.btnTtsSetup);
|
btnTtsSetup = view.findViewById(R.id.btnTtsSetup);
|
||||||
btnTtsData = view.findViewById(R.id.btnTtsData);
|
btnTtsData = view.findViewById(R.id.btnTtsData);
|
||||||
|
|
||||||
|
btnSound = view.findViewById(R.id.btnSound);
|
||||||
|
cbAlarm = view.findViewById(R.id.cbAlarm);
|
||||||
|
|
||||||
tvAutomation = view.findViewById(R.id.tvAutomation);
|
tvAutomation = view.findViewById(R.id.tvAutomation);
|
||||||
|
|
||||||
bottom_navigation = view.findViewById(R.id.bottom_navigation);
|
bottom_navigation = view.findViewById(R.id.bottom_navigation);
|
||||||
|
@ -299,6 +313,7 @@ public class FragmentRule extends FragmentBase {
|
||||||
grpMoveProp = view.findViewById(R.id.grpMoveProp);
|
grpMoveProp = view.findViewById(R.id.grpMoveProp);
|
||||||
grpAnswer = view.findViewById(R.id.grpAnswer);
|
grpAnswer = view.findViewById(R.id.grpAnswer);
|
||||||
grpTts = view.findViewById(R.id.grpTts);
|
grpTts = view.findViewById(R.id.grpTts);
|
||||||
|
grpSound = view.findViewById(R.id.grpSound);
|
||||||
grpAutomation = view.findViewById(R.id.grpAutomation);
|
grpAutomation = view.findViewById(R.id.grpAutomation);
|
||||||
grpDelete = view.findViewById(R.id.grpDelete);
|
grpDelete = view.findViewById(R.id.grpDelete);
|
||||||
|
|
||||||
|
@ -461,6 +476,7 @@ public class FragmentRule extends FragmentBase {
|
||||||
actions.add(new Action(EntityRule.TYPE_DELETE, getString(R.string.title_rule_delete)));
|
actions.add(new Action(EntityRule.TYPE_DELETE, getString(R.string.title_rule_delete)));
|
||||||
actions.add(new Action(EntityRule.TYPE_ANSWER, getString(R.string.title_rule_answer)));
|
actions.add(new Action(EntityRule.TYPE_ANSWER, getString(R.string.title_rule_answer)));
|
||||||
actions.add(new Action(EntityRule.TYPE_TTS, getString(R.string.title_rule_tts)));
|
actions.add(new Action(EntityRule.TYPE_TTS, getString(R.string.title_rule_tts)));
|
||||||
|
actions.add(new Action(EntityRule.TYPE_SOUND, getString(R.string.title_rule_sound)));
|
||||||
actions.add(new Action(EntityRule.TYPE_AUTOMATION, getString(R.string.title_rule_automation)));
|
actions.add(new Action(EntityRule.TYPE_AUTOMATION, getString(R.string.title_rule_automation)));
|
||||||
adapterAction.addAll(actions);
|
adapterAction.addAll(actions);
|
||||||
|
|
||||||
|
@ -552,6 +568,17 @@ public class FragmentRule extends FragmentBase {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
btnSound.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
|
||||||
|
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_ALL);
|
||||||
|
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TITLE, getString(R.string.title_advanced_sound));
|
||||||
|
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, sound);
|
||||||
|
startActivityForResult(Helper.getChooser(getContext(), intent), REQUEST_SOUND);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
tvAutomation.setText(getString(R.string.title_rule_automation_hint,
|
tvAutomation.setText(getString(R.string.title_rule_automation_hint,
|
||||||
EntityRule.ACTION_AUTOMATION,
|
EntityRule.ACTION_AUTOMATION,
|
||||||
TextUtils.join(",", new String[]{
|
TextUtils.join(",", new String[]{
|
||||||
|
@ -589,6 +616,7 @@ public class FragmentRule extends FragmentBase {
|
||||||
grpMoveProp.setVisibility(View.GONE);
|
grpMoveProp.setVisibility(View.GONE);
|
||||||
grpAnswer.setVisibility(View.GONE);
|
grpAnswer.setVisibility(View.GONE);
|
||||||
grpTts.setVisibility(View.GONE);
|
grpTts.setVisibility(View.GONE);
|
||||||
|
grpSound.setVisibility(View.GONE);
|
||||||
grpAutomation.setVisibility(View.GONE);
|
grpAutomation.setVisibility(View.GONE);
|
||||||
grpDelete.setVisibility(View.GONE);
|
grpDelete.setVisibility(View.GONE);
|
||||||
|
|
||||||
|
@ -695,6 +723,7 @@ public class FragmentRule extends FragmentBase {
|
||||||
outState.putInt("fair:target", spTarget.getSelectedItemPosition());
|
outState.putInt("fair:target", spTarget.getSelectedItemPosition());
|
||||||
outState.putInt("fair:identity", spIdent.getSelectedItemPosition());
|
outState.putInt("fair:identity", spIdent.getSelectedItemPosition());
|
||||||
outState.putInt("fair:answer", spAnswer.getSelectedItemPosition());
|
outState.putInt("fair:answer", spAnswer.getSelectedItemPosition());
|
||||||
|
outState.putParcelable("fair:sound", sound);
|
||||||
|
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
}
|
}
|
||||||
|
@ -751,6 +780,10 @@ public class FragmentRule extends FragmentBase {
|
||||||
break;
|
break;
|
||||||
case REQUEST_TTS_DATA:
|
case REQUEST_TTS_DATA:
|
||||||
break;
|
break;
|
||||||
|
case REQUEST_SOUND:
|
||||||
|
if (resultCode == RESULT_OK && data != null)
|
||||||
|
onSelectSound(data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI));
|
||||||
|
break;
|
||||||
case REQUEST_DATE_AFTER:
|
case REQUEST_DATE_AFTER:
|
||||||
if (resultCode == RESULT_OK && data != null)
|
if (resultCode == RESULT_OK && data != null)
|
||||||
onDateAfter(data.getBundleExtra("args"));
|
onDateAfter(data.getBundleExtra("args"));
|
||||||
|
@ -781,6 +814,10 @@ public class FragmentRule extends FragmentBase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onSelectSound(Uri uri) {
|
||||||
|
this.sound = uri;
|
||||||
|
}
|
||||||
|
|
||||||
private void onDelete() {
|
private void onDelete() {
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putLong("id", id);
|
args.putLong("id", id);
|
||||||
|
@ -1002,6 +1039,12 @@ public class FragmentRule extends FragmentBase {
|
||||||
cbCc.setChecked(jaction.optBoolean("cc"));
|
cbCc.setChecked(jaction.optBoolean("cc"));
|
||||||
cbWithAttachments.setChecked(jaction.optBoolean("attachments"));
|
cbWithAttachments.setChecked(jaction.optBoolean("attachments"));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case EntityRule.TYPE_SOUND:
|
||||||
|
if (jaction.has("uri"))
|
||||||
|
FragmentRule.this.sound = Uri.parse(jaction.getString("uri"));
|
||||||
|
cbAlarm.setChecked(jaction.optBoolean("alarm"));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int pos = 0; pos < adapterAction.getCount(); pos++)
|
for (int pos = 0; pos < adapterAction.getCount(); pos++)
|
||||||
|
@ -1053,6 +1096,7 @@ public class FragmentRule extends FragmentBase {
|
||||||
grpMoveProp.setVisibility(type == EntityRule.TYPE_MOVE ? View.VISIBLE : View.GONE);
|
grpMoveProp.setVisibility(type == EntityRule.TYPE_MOVE ? View.VISIBLE : View.GONE);
|
||||||
grpAnswer.setVisibility(type == EntityRule.TYPE_ANSWER ? View.VISIBLE : View.GONE);
|
grpAnswer.setVisibility(type == EntityRule.TYPE_ANSWER ? View.VISIBLE : View.GONE);
|
||||||
grpTts.setVisibility(type == EntityRule.TYPE_TTS ? View.VISIBLE : View.GONE);
|
grpTts.setVisibility(type == EntityRule.TYPE_TTS ? View.VISIBLE : View.GONE);
|
||||||
|
grpSound.setVisibility(type == EntityRule.TYPE_SOUND ? View.VISIBLE : View.GONE);
|
||||||
grpAutomation.setVisibility(type == EntityRule.TYPE_AUTOMATION ? View.VISIBLE : View.GONE);
|
grpAutomation.setVisibility(type == EntityRule.TYPE_AUTOMATION ? View.VISIBLE : View.GONE);
|
||||||
grpDelete.setVisibility(type == EntityRule.TYPE_DELETE ? View.VISIBLE : View.GONE);
|
grpDelete.setVisibility(type == EntityRule.TYPE_DELETE ? View.VISIBLE : View.GONE);
|
||||||
}
|
}
|
||||||
|
@ -1329,6 +1373,11 @@ public class FragmentRule extends FragmentBase {
|
||||||
jaction.put("cc", cbCc.isChecked());
|
jaction.put("cc", cbCc.isChecked());
|
||||||
jaction.put("attachments", cbWithAttachments.isChecked());
|
jaction.put("attachments", cbWithAttachments.isChecked());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case EntityRule.TYPE_SOUND:
|
||||||
|
jaction.put("uri", sound);
|
||||||
|
jaction.put("alarm", cbAlarm.isChecked());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,6 @@ import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.pm.ApplicationInfo;
|
|
||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.PackageInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.ResolveInfo;
|
import android.content.pm.ResolveInfo;
|
||||||
|
@ -58,6 +57,7 @@ import android.provider.Settings;
|
||||||
import android.security.KeyChain;
|
import android.security.KeyChain;
|
||||||
import android.security.KeyChainAliasCallback;
|
import android.security.KeyChainAliasCallback;
|
||||||
import android.security.KeyChainException;
|
import android.security.KeyChainException;
|
||||||
|
import android.telephony.TelephonyManager;
|
||||||
import android.text.Html;
|
import android.text.Html;
|
||||||
import android.text.Layout;
|
import android.text.Layout;
|
||||||
import android.text.Spannable;
|
import android.text.Spannable;
|
||||||
|
@ -73,7 +73,6 @@ import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.ViewParent;
|
import android.view.ViewParent;
|
||||||
import android.view.ViewTreeObserver;
|
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
import android.view.accessibility.AccessibilityManager;
|
import android.view.accessibility.AccessibilityManager;
|
||||||
import android.view.inputmethod.EditorInfo;
|
import android.view.inputmethod.EditorInfo;
|
||||||
|
@ -112,7 +111,6 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
||||||
|
|
||||||
import org.jsoup.helper.HttpConnection;
|
|
||||||
import org.openintents.openpgp.util.OpenPgpApi;
|
import org.openintents.openpgp.util.OpenPgpApi;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
|
52
app/src/main/java/eu/faircode/email/MediaPlayerHelper.java
Normal file
52
app/src/main/java/eu/faircode/email/MediaPlayerHelper.java
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
package eu.faircode.email;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.media.AudioAttributes;
|
||||||
|
import android.media.MediaPlayer;
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.Semaphore;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
public class MediaPlayerHelper {
|
||||||
|
private static final int MAX_DURATION = 30; // seconds
|
||||||
|
|
||||||
|
static void play(Context context, Uri uri, boolean alarm) throws IOException {
|
||||||
|
Semaphore sem = new Semaphore(0);
|
||||||
|
|
||||||
|
AudioAttributes attrs = new AudioAttributes.Builder()
|
||||||
|
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
|
||||||
|
.setUsage(alarm ? AudioAttributes.USAGE_ALARM : AudioAttributes.USAGE_NOTIFICATION)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
MediaPlayer mediaPlayer = new MediaPlayer();
|
||||||
|
mediaPlayer.setAudioAttributes(attrs);
|
||||||
|
mediaPlayer.setDataSource(context.getApplicationContext(), uri);
|
||||||
|
mediaPlayer.setLooping(false);
|
||||||
|
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
|
||||||
|
@Override
|
||||||
|
public void onPrepared(MediaPlayer mp) {
|
||||||
|
mp.start();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
|
||||||
|
@Override
|
||||||
|
public void onCompletion(MediaPlayer mp) {
|
||||||
|
mp.stop();
|
||||||
|
mp.release();
|
||||||
|
sem.release();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
mediaPlayer.prepareAsync();
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!sem.tryAcquire(MAX_DURATION, TimeUnit.SECONDS)) {
|
||||||
|
mediaPlayer.stop();
|
||||||
|
mediaPlayer.release();
|
||||||
|
}
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
Log.w(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -916,6 +916,37 @@
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/btnTtsSetup" />
|
app:layout_constraintTop_toBottomOf="@id/btnTtsSetup" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btnSound"
|
||||||
|
style="?android:attr/buttonStyleSmall"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:drawableEnd="@drawable/twotone_audiotrack_24"
|
||||||
|
android:drawablePadding="6dp"
|
||||||
|
android:text="@string/title_rule_select_sound"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/btnTtsData" />
|
||||||
|
|
||||||
|
<CheckBox
|
||||||
|
android:id="@+id/cbAlarm"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:text="@string/title_rule_use_as_alarm"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/btnSound" />
|
||||||
|
|
||||||
|
<eu.faircode.email.FixedTextView
|
||||||
|
android:id="@+id/tvAlarm"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="6dp"
|
||||||
|
android:text="@string/title_rule_alarm_hint"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/cbAlarm" />
|
||||||
|
|
||||||
<eu.faircode.email.FixedTextView
|
<eu.faircode.email.FixedTextView
|
||||||
android:id="@+id/tvAutomation"
|
android:id="@+id/tvAutomation"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
@ -924,7 +955,7 @@
|
||||||
android:text="@string/title_rule_automation_hint"
|
android:text="@string/title_rule_automation_hint"
|
||||||
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/btnTtsData" />
|
app:layout_constraintTop_toBottomOf="@+id/tvAlarm" />
|
||||||
|
|
||||||
<eu.faircode.email.FixedTextView
|
<eu.faircode.email.FixedTextView
|
||||||
android:id="@+id/tvDelete"
|
android:id="@+id/tvDelete"
|
||||||
|
@ -1003,6 +1034,12 @@
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
app:constraint_referenced_ids="btnTtsSetup,btnTtsData" />
|
app:constraint_referenced_ids="btnTtsSetup,btnTtsData" />
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.Group
|
||||||
|
android:id="@+id/grpSound"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
app:constraint_referenced_ids="btnSound,cbAlarm,tvAlarm" />
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.Group
|
<androidx.constraintlayout.widget.Group
|
||||||
android:id="@+id/grpAutomation"
|
android:id="@+id/grpAutomation"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
|
|
|
@ -1483,6 +1483,7 @@
|
||||||
<string name="title_rule_tts">Text to speech</string>
|
<string name="title_rule_tts">Text to speech</string>
|
||||||
<string name="title_rule_automation">Automation</string>
|
<string name="title_rule_automation">Automation</string>
|
||||||
<string name="title_rule_delete">Delete permanently</string>
|
<string name="title_rule_delete">Delete permanently</string>
|
||||||
|
<string name="title_rule_sound">Play sound</string>
|
||||||
|
|
||||||
<string name="title_rule_caption">Edit rule</string>
|
<string name="title_rule_caption">Edit rule</string>
|
||||||
<string name="title_rule_title">Rule applies to</string>
|
<string name="title_rule_title">Rule applies to</string>
|
||||||
|
@ -1543,6 +1544,10 @@
|
||||||
<string name="title_rule_tts_subject">Subject</string>
|
<string name="title_rule_tts_subject">Subject</string>
|
||||||
<string name="title_rule_tts_content">Text</string>
|
<string name="title_rule_tts_content">Text</string>
|
||||||
|
|
||||||
|
<string name="title_rule_select_sound">Select sound</string>
|
||||||
|
<string name="title_rule_use_as_alarm">Use as alarm</string>
|
||||||
|
<string name="title_rule_alarm_hint">This will ignore "do not disturb" rules</string>
|
||||||
|
|
||||||
<string name="title_legend_section_synchronize">Synchronize</string>
|
<string name="title_legend_section_synchronize">Synchronize</string>
|
||||||
<string name="title_legend_section_folders">Folders</string>
|
<string name="title_legend_section_folders">Folders</string>
|
||||||
<string name="title_legend_section_messages">Messages</string>
|
<string name="title_legend_section_messages">Messages</string>
|
||||||
|
|
|
@ -4,6 +4,12 @@
|
||||||
|
|
||||||
### [Draconyx](https://en.wikipedia.org/wiki/Draconyx)
|
### [Draconyx](https://en.wikipedia.org/wiki/Draconyx)
|
||||||
|
|
||||||
|
### Next version
|
||||||
|
|
||||||
|
* Added rule action to play (alarm) sound
|
||||||
|
* Small improvements and minor bug fixes
|
||||||
|
* Updated translations
|
||||||
|
|
||||||
### 1.1802 - 2022-01-03
|
### 1.1802 - 2022-01-03
|
||||||
|
|
||||||
* Improved original message view scrolling
|
* Improved original message view scrolling
|
||||||
|
|
Loading…
Add table
Reference in a new issue