Notification settings UI on Oreo or later

* On devices with Android 8.0 (Oreo) or later, use system UI to change notification settings.
* Refactor sound selection code to cover differences between old (pre Oreo) and new devices.
* Always use the same notification channel for calls (Oreo or later).

Signed-off-by: Dariusz Olszewski <starypatyk@users.noreply.github.com>
This commit is contained in:
Dariusz Olszewski 2021-11-30 22:39:20 +01:00 committed by Marcel Hibbe
parent 4a5f6cf1fe
commit e9ac99c5df
No known key found for this signature in database
GPG Key ID: C793F8B59F43CE7B
7 changed files with 124 additions and 183 deletions

View File

@ -27,7 +27,6 @@ import android.media.AudioAttributes
import android.net.Uri
import android.os.Bundle
import android.os.Handler
import android.text.TextUtils
import android.util.Base64
import android.util.Log
import androidx.core.app.NotificationCompat
@ -48,7 +47,6 @@ import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedA
import com.nextcloud.talk.events.CallNotificationClick
import com.nextcloud.talk.jobs.NotificationWorker
import com.nextcloud.talk.jobs.PushRegistrationWorker
import com.nextcloud.talk.models.RingtoneSettings
import com.nextcloud.talk.models.SignatureVerification
import com.nextcloud.talk.models.json.participants.Participant
import com.nextcloud.talk.models.json.participants.ParticipantsOverall
@ -58,6 +56,7 @@ import com.nextcloud.talk.utils.NotificationUtils
import com.nextcloud.talk.utils.NotificationUtils.cancelAllNotificationsForAccount
import com.nextcloud.talk.utils.NotificationUtils.cancelExistingNotificationWithId
import com.nextcloud.talk.utils.NotificationUtils.createNotificationChannel
import com.nextcloud.talk.utils.NotificationUtils.getCallRingtoneUri
import com.nextcloud.talk.utils.PushUtils
import com.nextcloud.talk.utils.bundle.BundleKeys
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_FROM_NOTIFICATION_START_CALL
@ -73,7 +72,6 @@ import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import retrofit2.Retrofit
import java.io.IOException
import java.net.CookieManager
import java.security.InvalidKeyException
import java.security.NoSuchAlgorithmException
@ -206,39 +204,8 @@ class MagicFirebaseMessagingService : FirebaseMessagingService() {
AudioAttributes.Builder().setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
audioAttributesBuilder.setUsage(AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST)
val ringtonePreferencesString: String? = appPreferences!!.callRingtoneUri
val soundUri = if (TextUtils.isEmpty(ringtonePreferencesString)) {
Uri.parse(
"android.resource://" + applicationContext.packageName +
"/raw/librem_by_feandesign_call"
)
} else {
try {
val ringtoneSettings =
LoganSquare.parse(ringtonePreferencesString, RingtoneSettings::class.java)
ringtoneSettings.ringtoneUri
} catch (exception: IOException) {
Uri.parse(
"android.resource://" +
applicationContext.packageName +
"/raw/librem_by_feandesign_call"
)
}
}
val notificationChannelId = NotificationUtils.getNotificationChannelId(
applicationContext.resources
.getString(R.string.nc_notification_channel_calls),
applicationContext.resources
.getString(R.string.nc_notification_channel_calls_description),
true,
NotificationManagerCompat.IMPORTANCE_HIGH,
soundUri!!,
audioAttributesBuilder.build(),
null,
false
)
val soundUri = getCallRingtoneUri(applicationContext!!, appPreferences)
val notificationChannelId = NotificationUtils.NOTIFICATION_CHANNEL_CALLS_V4
createNotificationChannel(
applicationContext!!,
notificationChannelId,
@ -248,7 +215,7 @@ class MagicFirebaseMessagingService : FirebaseMessagingService() {
.getString(R.string.nc_notification_channel_calls_description),
true,
NotificationManagerCompat.IMPORTANCE_HIGH,
soundUri,
soundUri!!,
audioAttributesBuilder.build(),
null,
false

View File

@ -2295,8 +2295,7 @@ public class CallActivity extends CallBaseActivity {
stopCallingSound();
Uri ringtoneUri;
if (isIncomingCallFromNotification) {
ringtoneUri = Uri.parse("android.resource://" + getApplicationContext().getPackageName() +
"/raw/librem_by_feandesign_call");
ringtoneUri = NotificationUtils.INSTANCE.getCallRingtoneUri(getApplicationContext(), appPreferences);
} else {
ringtoneUri = Uri.parse("android.resource://" + getApplicationContext().getPackageName() + "/raw" +
"/tr110_1_kap8_3_freiton1");

View File

@ -32,11 +32,9 @@ import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import com.bluelinelabs.logansquare.LoganSquare;
import com.facebook.common.executors.UiThreadImmediateExecutorService;
import com.facebook.common.references.CloseableReference;
import com.facebook.datasource.DataSource;
@ -50,7 +48,6 @@ import com.nextcloud.talk.api.NcApi;
import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.databinding.CallNotificationActivityBinding;
import com.nextcloud.talk.events.CallNotificationClick;
import com.nextcloud.talk.models.RingtoneSettings;
import com.nextcloud.talk.models.database.CapabilitiesUtil;
import com.nextcloud.talk.models.database.UserEntity;
import com.nextcloud.talk.models.json.conversations.Conversation;
@ -60,6 +57,7 @@ import com.nextcloud.talk.models.json.participants.ParticipantsOverall;
import com.nextcloud.talk.utils.ApiUtils;
import com.nextcloud.talk.utils.DisplayUtils;
import com.nextcloud.talk.utils.DoNotDisturbUtils;
import com.nextcloud.talk.utils.NotificationUtils;
import com.nextcloud.talk.utils.bundle.BundleKeys;
import com.nextcloud.talk.utils.preferences.AppPreferences;
@ -390,25 +388,7 @@ public class CallNotificationActivity extends CallBaseActivity {
}
private void playRingtoneSound() {
String callRingtonePreferenceString = appPreferences.getCallRingtoneUri();
Uri ringtoneUri;
if (TextUtils.isEmpty(callRingtonePreferenceString)) {
// play default sound
ringtoneUri = Uri.parse("android.resource://" + getApplicationContext().getPackageName() +
"/raw/librem_by_feandesign_call");
} else {
try {
RingtoneSettings ringtoneSettings = LoganSquare.parse(
callRingtonePreferenceString, RingtoneSettings.class);
ringtoneUri = ringtoneSettings.getRingtoneUri();
} catch (IOException e) {
Log.e(TAG, "Failed to parse ringtone settings");
ringtoneUri = Uri.parse("android.resource://" + getApplicationContext().getPackageName() +
"/raw/librem_by_feandesign_call");
}
}
Uri ringtoneUri = NotificationUtils.INSTANCE.getCallRingtoneUri(getApplicationContext(), appPreferences);
if (ringtoneUri != null) {
mediaPlayer = new MediaPlayer();
try {

View File

@ -45,6 +45,7 @@ import com.nextcloud.talk.adapters.items.NotificationSoundItem;
import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.controllers.base.BaseController;
import com.nextcloud.talk.models.RingtoneSettings;
import com.nextcloud.talk.utils.NotificationUtils;
import com.nextcloud.talk.utils.bundle.BundleKeys;
import com.nextcloud.talk.utils.preferences.AppPreferences;
import eu.davidea.flexibleadapter.FlexibleAdapter;
@ -180,13 +181,10 @@ public class RingtoneSelectionController extends BaseController implements Flexi
private String getRingtoneString() {
if (callNotificationSounds) {
return ("android.resource://" + context.getPackageName() +
"/raw/librem_by_feandesign_call");
return NotificationUtils.INSTANCE.getDEFAULT_CALL_RINGTONE_URI();
} else {
return ("android.resource://" + context.getPackageName() + "/raw" +
"/librem_by_feandesign_message");
return NotificationUtils.INSTANCE.getDEFAULT_MESSAGE_RINGTONE_URI();
}
}
private void fetchNotificationSounds() {

View File

@ -33,9 +33,12 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.ColorStateList;
import android.graphics.PorterDuff;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.security.KeyChain;
import android.text.Editable;
import android.text.InputType;
@ -59,7 +62,6 @@ import com.bluelinelabs.conductor.Controller;
import com.bluelinelabs.conductor.RouterTransaction;
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler;
import com.bluelinelabs.logansquare.LoganSquare;
import com.facebook.drawee.view.SimpleDraweeView;
import com.google.android.material.card.MaterialCardView;
import com.google.android.material.textfield.TextInputLayout;
@ -70,7 +72,6 @@ import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.controllers.base.BaseController;
import com.nextcloud.talk.jobs.AccountRemovalWorker;
import com.nextcloud.talk.jobs.ContactAddressBookWorker;
import com.nextcloud.talk.models.RingtoneSettings;
import com.nextcloud.talk.models.database.CapabilitiesUtil;
import com.nextcloud.talk.models.database.UserEntity;
import com.nextcloud.talk.models.json.generic.GenericOverall;
@ -78,6 +79,7 @@ import com.nextcloud.talk.models.json.userprofile.UserProfileOverall;
import com.nextcloud.talk.utils.ApiUtils;
import com.nextcloud.talk.utils.DisplayUtils;
import com.nextcloud.talk.utils.LoggingUtils;
import com.nextcloud.talk.utils.NotificationUtils;
import com.nextcloud.talk.utils.SecurityUtils;
import com.nextcloud.talk.utils.bundle.BundleKeys;
import com.nextcloud.talk.utils.database.user.UserUtils;
@ -95,7 +97,6 @@ import com.yarolegovich.mp.MaterialSwitchPreference;
import net.orange_box.storebox.listeners.OnPreferenceValueChangedListener;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
@ -293,21 +294,43 @@ public class SettingsController extends BaseController {
versionInfo.setSummary("v" + BuildConfig.VERSION_NAME);
settingsCallSound.setOnClickListener(v -> {
Bundle bundle = new Bundle();
bundle.putBoolean(BundleKeys.INSTANCE.getKEY_ARE_CALL_SOUNDS(), true);
getRouter().pushController(RouterTransaction.with(new RingtoneSelectionController(bundle))
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler()));
});
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
settingsMessageSound.setOnClickListener(v -> {
Bundle bundle = new Bundle();
bundle.putBoolean(BundleKeys.INSTANCE.getKEY_ARE_CALL_SOUNDS(), false);
getRouter().pushController(RouterTransaction.with(new RingtoneSelectionController(bundle))
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler()));
});
settingsCallSound.setOnClickListener(v -> {
Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);
intent.putExtra(Settings.EXTRA_APP_PACKAGE, BuildConfig.APPLICATION_ID);
intent.putExtra(Settings.EXTRA_CHANNEL_ID,
NotificationUtils.INSTANCE.getNOTIFICATION_CHANNEL_CALLS_V4());
startActivity(intent);
});
settingsMessageSound.setOnClickListener(v -> {
Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);
intent.putExtra(Settings.EXTRA_APP_PACKAGE, BuildConfig.APPLICATION_ID);
intent.putExtra(Settings.EXTRA_CHANNEL_ID,
NotificationUtils.INSTANCE.getNOTIFICATION_CHANNEL_MESSAGES_V3());
startActivity(intent);
});
} else {
settingsCallSound.setOnClickListener(v -> {
Bundle bundle = new Bundle();
bundle.putBoolean(BundleKeys.INSTANCE.getKEY_ARE_CALL_SOUNDS(), true);
getRouter().pushController(RouterTransaction.with(new RingtoneSelectionController(bundle))
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler()));
});
settingsMessageSound.setOnClickListener(v -> {
Bundle bundle = new Bundle();
bundle.putBoolean(BundleKeys.INSTANCE.getKEY_ARE_CALL_SOUNDS(), false);
getRouter().pushController(RouterTransaction.with(new RingtoneSelectionController(bundle))
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler()));
});
}
if (CapabilitiesUtil.isPhoneBookIntegrationAvailable(userUtils.getCurrentUser())) {
phoneBookIntegrationPreference.setVisibility(View.VISIBLE);
@ -417,6 +440,18 @@ public class SettingsController extends BaseController {
}
}
private String getRingtoneName(Context context, Uri ringtoneUri) {
if (ringtoneUri == null) {
return getResources().getString(R.string.nc_settings_no_ringtone);
} else if (ringtoneUri.toString().equals(NotificationUtils.INSTANCE.getDEFAULT_CALL_RINGTONE_URI()) ||
ringtoneUri.toString().equals(NotificationUtils.INSTANCE.getDEFAULT_MESSAGE_RINGTONE_URI())) {
return getResources().getString(R.string.nc_settings_default_ringtone);
} else {
Ringtone r = RingtoneManager.getRingtone(context, ringtoneUri);
return r.getTitle(context);
}
}
@Override
protected void onAttach(@NonNull View view) {
super.onAttach(view);
@ -479,33 +514,11 @@ public class SettingsController extends BaseController {
}
}
String ringtoneName = "";
RingtoneSettings ringtoneSettings;
if (!TextUtils.isEmpty(appPreferences.getCallRingtoneUri())) {
try {
ringtoneSettings = LoganSquare.parse(appPreferences.getCallRingtoneUri(), RingtoneSettings.class);
ringtoneName = ringtoneSettings.getRingtoneName();
} catch (IOException e) {
Log.e(TAG, "Failed to parse ringtone name");
}
settingsCallSound.setSummary(ringtoneName);
} else {
settingsCallSound.setSummary(R.string.nc_settings_default_ringtone);
}
Uri callRingtoneUri = NotificationUtils.INSTANCE.getCallRingtoneUri(view.getContext(), appPreferences);
settingsCallSound.setSummary(getRingtoneName(view.getContext(), callRingtoneUri));
ringtoneName = "";
if (!TextUtils.isEmpty(appPreferences.getMessageRingtoneUri())) {
try {
ringtoneSettings = LoganSquare.parse(appPreferences.getMessageRingtoneUri(), RingtoneSettings.class);
ringtoneName = ringtoneSettings.getRingtoneName();
} catch (IOException e) {
Log.e(TAG, "Failed to parse ringtone name");
}
settingsMessageSound.setSummary(ringtoneName);
} else {
settingsMessageSound.setSummary(R.string.nc_settings_default_ringtone);
}
Uri messageRingtoneUri = NotificationUtils.INSTANCE.getMessageRingtoneUri(view.getContext(), appPreferences);
settingsMessageSound.setSummary(getRingtoneName(view.getContext(), messageRingtoneUri));
if ("No proxy".equals(appPreferences.getProxyType()) || appPreferences.getProxyType() == null) {
hideProxySettings();

View File

@ -52,7 +52,6 @@ import com.nextcloud.talk.activities.CallActivity;
import com.nextcloud.talk.activities.MainActivity;
import com.nextcloud.talk.api.NcApi;
import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.models.RingtoneSettings;
import com.nextcloud.talk.models.SignatureVerification;
import com.nextcloud.talk.models.database.ArbitraryStorageEntity;
import com.nextcloud.talk.models.database.UserEntity;
@ -342,25 +341,8 @@ public class NotificationWorker extends Worker {
AudioAttributes.Builder audioAttributesBuilder = new AudioAttributes.Builder().setContentType
(AudioAttributes.CONTENT_TYPE_SONIFICATION);
audioAttributesBuilder.setUsage(AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT);
String ringtonePreferencesString;
Uri soundUri;
ringtonePreferencesString = appPreferences.getMessageRingtoneUri();
if (TextUtils.isEmpty(ringtonePreferencesString)) {
soundUri = Uri.parse("android.resource://" + context.getPackageName() +
"/raw/librem_by_feandesign_message");
} else {
try {
RingtoneSettings ringtoneSettings = LoganSquare.parse
(ringtonePreferencesString, RingtoneSettings.class);
soundUri = ringtoneSettings.getRingtoneUri();
} catch (IOException exception) {
soundUri = Uri.parse("android.resource://" + context.getPackageName() +
"/raw/librem_by_feandesign_message");
}
}
Uri soundUri = NotificationUtils.INSTANCE.getMessageRingtoneUri(getApplicationContext(),
appPreferences);
NotificationUtils.INSTANCE.createNotificationChannel(context,
NotificationUtils.INSTANCE.getNOTIFICATION_CHANNEL_MESSAGES_V3(), context.getResources()
.getString(R.string.nc_notification_channel_messages), context.getResources()
@ -498,24 +480,8 @@ public class NotificationWorker extends Worker {
}
if (!notification.category.equals(Notification.CATEGORY_CALL) || !muteCall) {
String ringtonePreferencesString;
Uri soundUri;
ringtonePreferencesString = appPreferences.getMessageRingtoneUri();
if (TextUtils.isEmpty(ringtonePreferencesString)) {
soundUri = Uri.parse("android.resource://" + context.getPackageName() +
"/raw/librem_by_feandesign_message");
} else {
try {
RingtoneSettings ringtoneSettings = LoganSquare.parse
(ringtonePreferencesString, RingtoneSettings.class);
soundUri = ringtoneSettings.getRingtoneUri();
} catch (IOException exception) {
soundUri = Uri.parse("android.resource://" + context.getPackageName() +
"/raw/librem_by_feandesign_message");
}
}
Uri soundUri = NotificationUtils.INSTANCE.getMessageRingtoneUri(getApplicationContext(),
appPreferences);
if (soundUri != null && !ApplicationWideCurrentRoomHolder.getInstance().isInCall() &&
(DoNotDisturbUtils.INSTANCE.shouldPlaySound() || importantConversation)) {
AudioAttributes.Builder audioAttributesBuilder = new AudioAttributes.Builder().setContentType

View File

@ -23,17 +23,21 @@ package com.nextcloud.talk.utils
import android.annotation.TargetApi
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationChannelGroup
import android.app.NotificationManager
import android.content.Context
import android.media.AudioAttributes
import android.net.Uri
import android.os.Build
import android.service.notification.StatusBarNotification
import android.text.TextUtils
import com.bluelinelabs.logansquare.LoganSquare
import com.nextcloud.talk.BuildConfig
import com.nextcloud.talk.R
import com.nextcloud.talk.models.RingtoneSettings
import com.nextcloud.talk.models.database.UserEntity
import com.nextcloud.talk.utils.bundle.BundleKeys
import java.util.Objects
import com.nextcloud.talk.utils.preferences.AppPreferences
import java.io.IOException
object NotificationUtils {
val NOTIFICATION_CHANNEL_CALLS = "NOTIFICATION_CHANNEL_CALLS"
@ -42,32 +46,12 @@ object NotificationUtils {
val NOTIFICATION_CHANNEL_MESSAGES_V2 = "NOTIFICATION_CHANNEL_MESSAGES_V2"
val NOTIFICATION_CHANNEL_MESSAGES_V3 = "NOTIFICATION_CHANNEL_MESSAGES_V3"
val NOTIFICATION_CHANNEL_CALLS_V3 = "NOTIFICATION_CHANNEL_CALLS_V3"
val NOTIFICATION_CHANNEL_CALLS_V4 = "NOTIFICATION_CHANNEL_CALLS_V4"
fun getVibrationEffectForCalls(): LongArray {
return longArrayOf(0L, 400L, 800L, 600L, 800L, 800L, 800L, 1000L)
}
fun getNotificationChannelId(
channelName: String,
channelDescription: String,
enableLights: Boolean,
importance: Int,
sound: Uri,
audioAttributes: AudioAttributes,
vibrationPattern: LongArray?,
bypassDnd: Boolean
): String {
return Objects.hash(
channelName,
channelDescription,
enableLights,
importance,
sound,
audioAttributes,
vibrationPattern,
bypassDnd
).toString()
}
val DEFAULT_CALL_RINGTONE_URI =
"android.resource://" + BuildConfig.APPLICATION_ID + "/raw/librem_by_feandesign_call"
val DEFAULT_MESSAGE_RINGTONE_URI =
"android.resource://" + BuildConfig.APPLICATION_ID + "/raw/librem_by_feandesign_message"
@TargetApi(Build.VERSION_CODES.O)
fun createNotificationChannel(
@ -112,19 +96,15 @@ object NotificationUtils {
}
@TargetApi(Build.VERSION_CODES.O)
fun createNotificationChannelGroup(
fun getNotificationChannel(
context: Context,
groupId: String,
groupName: CharSequence
) {
channelId: String
): NotificationChannel? {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val notificationChannelGroup = NotificationChannelGroup(groupId, groupName)
if (!notificationManager.notificationChannelGroups.contains(notificationChannelGroup)) {
notificationManager.createNotificationChannelGroup(notificationChannelGroup)
}
return notificationManager.getNotificationChannel(channelId)
}
return null
}
fun cancelAllNotificationsForAccount(context: Context?, conversationUser: UserEntity) {
@ -228,4 +208,42 @@ object NotificationUtils {
}
}
}
private fun getRingtoneUri(
context: Context,
ringtonePreferencesString: String?,
defaultRingtoneUri: String,
channelId: String
): Uri? {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = getNotificationChannel(context, channelId)
return channel!!.sound
} else if (TextUtils.isEmpty(ringtonePreferencesString)) {
return Uri.parse(defaultRingtoneUri)
} else {
try {
val ringtoneSettings =
LoganSquare.parse(ringtonePreferencesString, RingtoneSettings::class.java)
return ringtoneSettings.ringtoneUri
} catch (exception: IOException) {
return Uri.parse(defaultRingtoneUri)
}
}
}
fun getCallRingtoneUri(
context: Context,
appPreferences: AppPreferences?
): Uri? {
return getRingtoneUri(context,
appPreferences!!.callRingtoneUri, DEFAULT_CALL_RINGTONE_URI, NOTIFICATION_CHANNEL_CALLS_V4)
}
fun getMessageRingtoneUri(
context: Context,
appPreferences: AppPreferences?
): Uri? {
return getRingtoneUri(context,
appPreferences!!.messageRingtoneUri, DEFAULT_MESSAGE_RINGTONE_URI, NOTIFICATION_CHANNEL_MESSAGES_V3)
}
}