Messaging: Implement per conversation channels. Update API level to 28.

* Get rid of in-app settings for notifications, replaced by channels features
* Remove all the notification plumbing and dead code

Test: m, manual

Signed-off-by: Luca Stefani <luca.stefani.ge1@gmail.com>
Signed-off-by: Joey <joey@lineageos.org>
Signed-off-by: Danny Baumann <dannybaumann@web.de>
Signed-off-by: Arne Coucheron <arco68@gmail.com>
Signed-off-by: Lyubo <lyubodzhamov@gmail.com>
Change-Id: Idb39ca32751d40b3376934775d2119dd6cc7e297
This commit is contained in:
Luca Stefani
2024-09-09 05:46:38 +03:00
committed by Michael Bestas
parent 2fa1f81707
commit 4246987beb
66 changed files with 249 additions and 942 deletions
@@ -171,8 +171,7 @@ public class BugleDatabaseOperations {
final ArrayList<ParticipantData> participants =
getConversationParticipantsFromRecipients(recipients, refSubId);
return getOrCreateConversation(db, threadId, senderBlocked, participants, false, false,
null);
return getOrCreateConversation(db, threadId, senderBlocked, participants);
}
/**
@@ -190,7 +189,7 @@ public class BugleDatabaseOperations {
Assert.isNotMainThread();
final ArrayList<ParticipantData> recipients = new ArrayList<>(1);
recipients.add(recipient);
return getOrCreateConversation(db, threadId, senderBlocked, recipients, false, false, null);
return getOrCreateConversation(db, threadId, senderBlocked, recipients);
}
/**
@@ -200,15 +199,11 @@ public class BugleDatabaseOperations {
* @param threadId The message's thread
* @param archived Flag whether the conversation should be created archived
* @param participants list of conversation participants
* @param noNotification If notification should be disabled
* @param noVibrate If vibrate on notification should be disabled
* @param soundUri If there is custom sound URI
* @return a conversation id
*/
@DoesNotRunOnMainThread
public static String getOrCreateConversation(final DatabaseWrapper db, final long threadId,
final boolean archived, final ArrayList<ParticipantData> participants,
boolean noNotification, boolean noVibrate, String soundUri) {
final boolean archived, final ArrayList<ParticipantData> participants) {
Assert.isNotMainThread();
// Check to see if this conversation is already in out local db cache
@@ -231,8 +226,7 @@ public class BugleDatabaseOperations {
BugleDatabaseOperations.getOrCreateParticipantInTransaction(db, self);
// Create a new conversation
conversationId = BugleDatabaseOperations.createConversationInTransaction(
db, threadId, conversationName, selfId, participants, archived,
noNotification, noVibrate, soundUri);
db, threadId, conversationName, selfId, participants, archived);
db.setTransactionSuccessful();
} finally {
db.endTransaction();
@@ -357,15 +351,11 @@ public class BugleDatabaseOperations {
* @param threadId The message's thread
* @param selfId The selfId to make default for this conversation
* @param archived Flag whether the conversation should be created archived
* @param noNotification If notification should be disabled
* @param noVibrate If vibrate on notification should be disabled
* @param soundUri The customized sound
* @return The existing conversation id or new conversation id
*/
static String createConversationInTransaction(final DatabaseWrapper dbWrapper,
final long threadId, final String conversationName, final String selfId,
final List<ParticipantData> participants, final boolean archived,
boolean noNotification, boolean noVibrate, String soundUri) {
final List<ParticipantData> participants, final boolean archived) {
// We want conversation and participant creation to be atomic
Assert.isTrue(dbWrapper.getDatabase().inTransaction());
boolean hasEmailAddress = false;
@@ -389,15 +379,6 @@ public class BugleDatabaseOperations {
if (archived) {
values.put(ConversationColumns.ARCHIVE_STATUS, 1);
}
if (noNotification) {
values.put(ConversationColumns.NOTIFICATION_ENABLED, 0);
}
if (noVibrate) {
values.put(ConversationColumns.NOTIFICATION_VIBRATION, 0);
}
if (!TextUtils.isEmpty(soundUri)) {
values.put(ConversationColumns.NOTIFICATION_SOUND_URI, soundUri);
}
fillParticipantData(values, participants);
@@ -17,6 +17,8 @@
package com.android.messaging.datamodel;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
@@ -74,10 +76,10 @@ import com.android.messaging.util.ConversationIdSet;
import com.android.messaging.util.ImageUtils;
import com.android.messaging.util.LogUtil;
import com.android.messaging.util.NotificationPlayer;
import com.android.messaging.util.NotificationsUtil;
import com.android.messaging.util.OsUtil;
import com.android.messaging.util.PendingIntentConstants;
import com.android.messaging.util.PhoneUtils;
import com.android.messaging.util.RingtoneUtil;
import com.android.messaging.util.ThreadUtil;
import com.android.messaging.util.UriUtil;
@@ -173,18 +175,10 @@ public class BugleNotifications {
}
Assert.isNotMainThread();
checkInitialized();
if (!shouldNotify()) {
if (LogUtil.isLoggable(TAG, LogUtil.VERBOSE)) {
LogUtil.v(TAG, "Notifications disabled");
}
cancel(PendingIntentConstants.SMS_NOTIFICATION_ID);
return;
} else {
if ((coverage & UPDATE_MESSAGES) != 0) {
createMessageNotification(silent, conversationId);
}
if ((coverage & UPDATE_MESSAGES) != 0) {
createMessageNotification(silent, conversationId);
}
if ((coverage & UPDATE_ERRORS) != 0) {
MessageNotificationState.checkFailedMessages();
}
@@ -195,8 +189,7 @@ public class BugleNotifications {
*
*/
public static void playClassZeroNotification() {
final Uri ringtoneUri = RingtoneUtil.getNotificationRingtoneUri(null);
playObservableConversationNotificationSound(ringtoneUri);
playObservableConversationNotificationSound(null);
}
/**
@@ -297,56 +290,6 @@ public class BugleNotifications {
}
}
/**
* Returns {@code true} if incoming notifications should display a
* notification, {@code false} otherwise.
*
* @return true if the notification should occur
*/
private static boolean shouldNotify() {
// If we're not the default sms app, don't put up any notifications.
if (!PhoneUtils.getDefault().isDefaultSmsApp()) {
return false;
}
// Now check prefs (i.e. settings) to see if the user turned off notifications.
final BuglePrefs prefs = BuglePrefs.getApplicationPrefs();
final Context context = Factory.get().getApplicationContext();
final String prefKey = context.getString(R.string.notifications_enabled_pref_key);
final boolean defaultValue = context.getResources().getBoolean(
R.bool.notifications_enabled_pref_default);
return prefs.getBoolean(prefKey, defaultValue);
}
/**
* Returns {@code true} if incoming notifications for the given {@link NotificationState}
* should vibrate the device, {@code false} otherwise.
*
* @return true if vibration should be used
*/
public static boolean shouldVibrate(final NotificationState state) {
// The notification should vibrate if the global setting is turned on AND
// the per-conversation setting is turned on (default).
if (!state.getNotificationVibrate()) {
return false;
} else {
final BuglePrefs prefs = BuglePrefs.getApplicationPrefs();
final Context context = Factory.get().getApplicationContext();
final String prefKey = context.getString(R.string.notification_vibration_pref_key);
final boolean defaultValue = context.getResources().getBoolean(
R.bool.notification_vibration_pref_default);
return prefs.getBoolean(prefKey, defaultValue);
}
}
private static Uri getNotificationRingtoneUriForConversationId(final String conversationId) {
final DatabaseWrapper db = DataModel.get().getDatabase();
final ConversationListItemData convData =
ConversationListItemData.getExistingConversation(db, conversationId);
return RingtoneUtil.getNotificationRingtoneUri(
convData != null ? convData.getNotificationSoundUri() : null);
}
/**
* Returns a unique tag to identify a notification.
*
@@ -420,13 +363,15 @@ public class BugleNotifications {
private static void processAndSend(final NotificationState state, final boolean silent,
final boolean softSound) {
final Context context = Factory.get().getApplicationContext();
final NotificationCompat.Builder notifBuilder = new NotificationCompat.Builder(context);
notifBuilder.setCategory(Notification.CATEGORY_MESSAGE);
// TODO: Need to fix this for multi conversation notifications to rate limit dings.
final String conversationId = state.mConversationIds.first();
String id = NotificationsUtil.DEFAULT_CHANNEL_ID;
if (NotificationsUtil.getNotificationChannel(context, conversationId) != null) {
id = conversationId;
}
final NotificationCompat.Builder notifBuilder = new NotificationCompat.Builder(context, id);
notifBuilder.setCategory(Notification.CATEGORY_MESSAGE);
final Uri ringtoneUri = RingtoneUtil.getNotificationRingtoneUri(state.getRingtoneUri());
// If the notification's conversation is currently observable (focused or in the
// conversation list), then play a notification beep at a low volume and don't display an
// actual notification.
@@ -436,7 +381,7 @@ public class BugleNotifications {
"sCurrentlyDisplayedConversationId so NOT showing notification," +
" but playing soft sound. conversationId: " + conversationId);
}
playObservableConversationNotificationSound(ringtoneUri);
playObservableConversationNotificationSound(conversationId);
return;
}
state.mBaseRequestCode = state.mType;
@@ -449,7 +394,7 @@ public class BugleNotifications {
notifBuilder.setDeleteIntent(clearIntent);
}
updateBuilderAudioVibrate(state, notifBuilder, silent, ringtoneUri, conversationId);
updateBuilderAudioVibrate(state, notifBuilder, silent, conversationId);
// Set the content intent
PendingIntent destinationIntent;
@@ -607,8 +552,7 @@ public class BugleNotifications {
if (state == null) {
cancel(PendingIntentConstants.SMS_NOTIFICATION_ID);
if (softSound && !TextUtils.isEmpty(conversationId)) {
final Uri ringtoneUri = getNotificationRingtoneUriForConversationId(conversationId);
playObservableConversationNotificationSound(ringtoneUri);
playObservableConversationNotificationSound(conversationId);
}
return;
}
@@ -646,8 +590,8 @@ public class BugleNotifications {
private static void updateBuilderAudioVibrate(final NotificationState state,
final NotificationCompat.Builder notifBuilder, final boolean silent,
final Uri ringtoneUri, final String conversationId) {
int defaults = Notification.DEFAULT_LIGHTS;
final String conversationId) {
int defaults = Notification.DEFAULT_LIGHTS | Notification.DEFAULT_VIBRATE;
if (!silent) {
final BuglePrefs prefs = Factory.get().getApplicationPrefs();
final long latestNotificationTimestamp = prefs.getLong(
@@ -669,10 +613,6 @@ public class BugleNotifications {
if (lastTime == null
|| SystemClock.elapsedRealtime() - lastTime > sTimeBetweenDingsMs) {
sLastMessageDingTime.put(conversationId, SystemClock.elapsedRealtime());
notifBuilder.setSound(ringtoneUri);
if (shouldVibrate(state)) {
defaults |= Notification.DEFAULT_VIBRATE;
}
}
}
}
@@ -826,8 +766,14 @@ public class BugleNotifications {
notificationState.mNotificationBuilder.setLargeIcon(smallBitmap);
// Add a wearable page with no visible card so you can more easily see the photo.
String conversationId = notificationState.mConversationIds.first();
String id = NotificationsUtil.DEFAULT_CHANNEL_ID;
if (NotificationsUtil.getNotificationChannel(context, conversationId) != null) {
id = conversationId;
}
final NotificationCompat.Builder photoPageNotifBuilder =
new NotificationCompat.Builder(Factory.get().getApplicationContext());
new NotificationCompat.Builder(Factory.get().getApplicationContext(),
NotificationsUtil.DEFAULT_CHANNEL_ID);
final WearableExtender photoPageWearableExtender = new WearableExtender();
photoPageWearableExtender.setHintShowBackgroundOnly(true);
if (attachmentBitmap != null) {
@@ -982,6 +928,16 @@ public class BugleNotifications {
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notification.defaults |= Notification.DEFAULT_LIGHTS;
Context context = Factory.get().getApplicationContext();
NotificationsUtil.createNotificationChannelGroup(context,
NotificationsUtil.CONVERSATION_GROUP_NAME,
R.string.notification_channel_messages_title);
NotificationsUtil.createNotificationChannel(context,
NotificationsUtil.DEFAULT_CHANNEL_ID,
R.string.notification_channel_messages_title,
NotificationManager.IMPORTANCE_DEFAULT,
NotificationsUtil.CONVERSATION_GROUP_NAME);
notificationManager.notify(notificationTag, type, notification);
LogUtil.i(TAG, "Notifying for conversation " + conversationId + "; "
@@ -1105,7 +1061,7 @@ public class BugleNotifications {
* Play the observable conversation notification sound (it's the regular notification sound, but
* played at half-volume)
*/
private static void playObservableConversationNotificationSound(final Uri ringtoneUri) {
private static void playObservableConversationNotificationSound(final String conversationId) {
final Context context = Factory.get().getApplicationContext();
final AudioManager audioManager = (AudioManager) context
.getSystemService(Context.AUDIO_SERVICE);
@@ -1116,7 +1072,11 @@ public class BugleNotifications {
}
final NotificationPlayer player = new NotificationPlayer(LogUtil.BUGLE_TAG);
player.play(ringtoneUri, false,
NotificationChannel channel = NotificationsUtil.getNotificationChannel(context, conversationId);
if (channel == null) {
channel = NotificationsUtil.getNotificationChannel(context, NotificationsUtil.DEFAULT_CHANNEL_ID);
}
player.play(channel != null ? channel.getSound() : null, false,
AudioManager.STREAM_NOTIFICATION,
OBSERVABLE_CONVERSATION_NOTIFICATION_VOLUME);
@@ -1211,7 +1171,8 @@ public class BugleNotifications {
final PendingIntent destinationIntent = UIIntents.get()
.getPendingIntentForConversationActivity(context, conversationId, null /* draft */);
final NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
final NotificationCompat.Builder builder =
new NotificationCompat.Builder(context, NotificationsUtil.DEFAULT_CHANNEL_ID);
builder.setTicker(line1)
.setContentTitle(line1)
.setContentText(line2)
@@ -1221,6 +1182,15 @@ public class BugleNotifications {
.setSound(UriUtil.getUriForResourceId(context, R.raw.message_failure));
final String tag = context.getPackageName() + ":emergency_sms_error";
NotificationsUtil.createNotificationChannelGroup(context,
NotificationsUtil.CONVERSATION_GROUP_NAME,
R.string.notification_channel_messages_title);
NotificationsUtil.createNotificationChannel(context,
NotificationsUtil.DEFAULT_CHANNEL_ID,
R.string.notification_channel_messages_title,
NotificationManager.IMPORTANCE_HIGH,
null);
NotificationManagerCompat.from(context).notify(
tag,
PendingIntentConstants.MSG_SEND_ERROR,
@@ -136,15 +136,6 @@ public class DatabaseHelper extends SQLiteOpenHelper {
/* Participant count not including self (so will be 1 for 1:1 or bigger for group) */
public static final String PARTICIPANT_COUNT = "participant_count";
/* Should notifications be enabled for this conversation? */
public static final String NOTIFICATION_ENABLED = "notification_enabled";
/* Notification sound used for the conversation */
public static final String NOTIFICATION_SOUND_URI = "notification_sound_uri";
/* Should vibrations be enabled for the conversation's notification? */
public static final String NOTIFICATION_VIBRATION = "notification_vibration";
/* Conversation recipients include email address */
public static final String INCLUDE_EMAIL_ADDRESS = "include_email_addr";
@@ -184,9 +175,6 @@ public class DatabaseHelper extends SQLiteOpenHelper {
+ ConversationColumns.OTHER_PARTICIPANT_NORMALIZED_DESTINATION + " TEXT, "
+ ConversationColumns.CURRENT_SELF_ID + " TEXT, "
+ ConversationColumns.PARTICIPANT_COUNT + " INT DEFAULT(0), "
+ ConversationColumns.NOTIFICATION_ENABLED + " INT DEFAULT(1), "
+ ConversationColumns.NOTIFICATION_SOUND_URI + " TEXT, "
+ ConversationColumns.NOTIFICATION_VIBRATION + " INT DEFAULT(1), "
+ ConversationColumns.INCLUDE_EMAIL_ADDRESS + " INT DEFAULT(0), "
+ ConversationColumns.SMS_SERVICE_CENTER + " TEXT ,"
+ ConversationColumns.IS_ENTERPRISE + " INT DEFAULT(0)"
@@ -197,15 +197,6 @@ public abstract class MessageNotificationState extends NotificationState {
// line infos is capped.
int mTotalMessageCount;
// Custom ringtone if set
final String mRingtoneUri;
// Should notification be enabled for this conversation?
final boolean mNotificationEnabled;
// Should notifications vibrate for this conversation?
final boolean mNotificationVibrate;
// Avatar uri of sender
final Uri mAvatarUri;
@@ -224,9 +215,6 @@ public abstract class MessageNotificationState extends NotificationState {
final boolean includeEmailAddress,
final long receivedTimestamp,
final String selfParticipantId,
final String ringtoneUri,
final boolean notificationEnabled,
final boolean notificationVibrate,
final Uri avatarUri,
final Uri contactUri,
final int subId,
@@ -239,11 +227,8 @@ public abstract class MessageNotificationState extends NotificationState {
mSelfParticipantId = selfParticipantId;
mLineInfos = new ArrayList<NotificationLineInfo>();
mTotalMessageCount = 0;
mRingtoneUri = ringtoneUri;
mAvatarUri = avatarUri;
mContactUri = contactUri;
mNotificationEnabled = notificationEnabled;
mNotificationVibrate = notificationVibrate;
mSubId = subId;
mParticipantCount = participantCount;
}
@@ -870,10 +855,6 @@ public abstract class MessageNotificationState extends NotificationState {
if (currConvInfo == null) {
final ConversationListItemData convData =
ConversationListItemData.getExistingConversation(db, convId);
if (!convData.getNotificationEnabled()) {
// Skip conversations that have notifications disabled.
continue;
}
final int subId = BugleDatabaseOperations.getSelfSubscriptionId(db,
convData.getSelfId());
groupConversationName = convData.getName();
@@ -888,9 +869,6 @@ public abstract class MessageNotificationState extends NotificationState {
convData.getIncludeEmailAddress(),
convMessageData.getReceivedTimeStamp(),
convData.getSelfId(),
convData.getNotificationSoundUri(),
convData.getNotificationEnabled(),
convData.getNotifiationVibrate(),
avatarUri,
convMessageData.getSenderContactLookupUri(),
subId,
@@ -1103,22 +1081,6 @@ public abstract class MessageNotificationState extends NotificationState {
return BugleNotifications.LOCAL_SMS_NOTIFICATION;
}
@Override
public String getRingtoneUri() {
if (mConvList.mConvInfos.size() > 0) {
return mConvList.mConvInfos.get(0).mRingtoneUri;
}
return null;
}
@Override
public boolean getNotificationVibrate() {
if (mConvList.mConvInfos.size() > 0) {
return mConvList.mConvInfos.get(0).mNotificationVibrate;
}
return false;
}
protected CharSequence getTicker() {
return BugleNotifications.buildColonSeparatedMessage(
mTickerSender != null ? mTickerSender : mTitle,
@@ -134,15 +134,6 @@ public abstract class NotificationState {
*/
public abstract int getPriority();
/** @return custom ringtone URI or null if not set */
public String getRingtoneUri() {
return null;
}
public boolean getNotificationVibrate() {
return false;
}
public long getLatestReceivedTimestamp() {
return Long.MIN_VALUE;
}
@@ -51,33 +51,14 @@ public class SyncManager {
*/
public static class ConversationCustomization {
private final boolean mArchived;
private final boolean mMuted;
private final boolean mNoVibrate;
private final String mNotificationSoundUri;
public ConversationCustomization(final boolean archived, final boolean muted,
final boolean noVibrate, final String notificationSoundUri) {
public ConversationCustomization(final boolean archived) {
mArchived = archived;
mMuted = muted;
mNoVibrate = noVibrate;
mNotificationSoundUri = notificationSoundUri;
}
public boolean isArchived() {
return mArchived;
}
public boolean isMuted() {
return mMuted;
}
public boolean noVibrate() {
return mNoVibrate;
}
public String getNotificationSoundUri() {
return mNotificationSoundUri;
}
}
SyncManager() {
@@ -436,15 +417,13 @@ public class SyncManager {
if (customization != null) {
// There is user customization we need to recover
conversationId = BugleDatabaseOperations.getOrCreateConversation(db, threadId,
customization.isArchived(), participants, customization.isMuted(),
customization.noVibrate(), customization.getNotificationSoundUri());
customization.isArchived(), participants);
if (customization.isArchived()) {
mArchivedConversations.add(conversationId);
}
} else {
conversationId = BugleDatabaseOperations.getOrCreateConversation(db, threadId,
false/*archived*/, participants, false/*noNotification*/,
false/*noVibrate*/, null/*soundUri*/);
false/*archived*/, participants);
}
if (conversationId != null) {
@@ -35,6 +35,7 @@ import com.android.messaging.datamodel.MessagingContentProvider;
import com.android.messaging.sms.MmsUtils;
import com.android.messaging.util.Assert;
import com.android.messaging.util.LogUtil;
import com.android.messaging.util.NotificationsUtil;
import com.android.messaging.widget.WidgetConversationProvider;
import java.util.ArrayList;
@@ -118,6 +119,10 @@ public class DeleteConversationAction extends Action implements Parcelable {
+ " has an invalid telephony thread id; will delete messages individually");
deleteConversationMessagesFromTelephony();
}
// Finally, remove the conversation specific notification channel
NotificationsUtil.deleteNotificationChannel(Factory.get().getApplicationContext(),
conversationId);
} else {
LogUtil.e(TAG, "DeleteConversationAction: conversationId is empty");
}
@@ -110,7 +110,7 @@ public class GetOrCreateConversationAction extends Action implements Parcelable
}
final String conversationId = BugleDatabaseOperations.getOrCreateConversation(db, threadId,
false, participants, false, false, null);
false, participants);
return conversationId;
}
@@ -274,7 +274,7 @@ public class InsertNewMessageAction extends Action implements Parcelable {
}
final String conversationId = BugleDatabaseOperations.getOrCreateConversation(db, threadId,
false, participants, false, false, null);
false, participants);
final ParticipantData self = BugleDatabaseOperations.getOrCreateSelf(db, subId);
@@ -1,156 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.messaging.datamodel.action;
import android.content.ContentValues;
import android.os.Parcel;
import android.os.Parcelable;
import com.android.messaging.datamodel.BugleDatabaseOperations;
import com.android.messaging.datamodel.DataModel;
import com.android.messaging.datamodel.DatabaseHelper.ConversationColumns;
import com.android.messaging.datamodel.DatabaseWrapper;
import com.android.messaging.datamodel.MessagingContentProvider;
import com.android.messaging.util.Assert;
/**
* Action used to update conversation options such as notification settings.
*/
public class UpdateConversationOptionsAction extends Action
implements Parcelable {
/**
* Enable/disable conversation notifications.
*/
public static void enableConversationNotifications(final String conversationId,
final boolean enableNotification) {
Assert.notNull(conversationId);
final UpdateConversationOptionsAction action = new UpdateConversationOptionsAction(
conversationId, enableNotification, null, null);
action.start();
}
/**
* Sets conversation notification sound.
*/
public static void setConversationNotificationSound(final String conversationId,
final String ringtoneUri) {
Assert.notNull(conversationId);
final UpdateConversationOptionsAction action = new UpdateConversationOptionsAction(
conversationId, null, ringtoneUri, null);
action.start();
}
/**
* Enable/disable vibrations for conversation notification.
*/
public static void enableVibrationForConversationNotification(final String conversationId,
final boolean enableVibration) {
Assert.notNull(conversationId);
final UpdateConversationOptionsAction action = new UpdateConversationOptionsAction(
conversationId, null, null, enableVibration);
action.start();
}
private static final String KEY_CONVERSATION_ID = "conversation_id";
// Keys for all settable settings.
private static final String KEY_ENABLE_NOTIFICATION = "enable_notification";
private static final String KEY_RINGTONE_URI = "ringtone_uri";
private static final String KEY_ENABLE_VIBRATION = "enable_vibration";
protected UpdateConversationOptionsAction(final String conversationId,
final Boolean enableNotification, final String ringtoneUri,
final Boolean enableVibration) {
Assert.notNull(conversationId);
actionParameters.putString(KEY_CONVERSATION_ID, conversationId);
if (enableNotification != null) {
actionParameters.putBoolean(KEY_ENABLE_NOTIFICATION, enableNotification);
}
if (ringtoneUri != null) {
actionParameters.putString(KEY_RINGTONE_URI, ringtoneUri);
}
if (enableVibration != null) {
actionParameters.putBoolean(KEY_ENABLE_VIBRATION, enableVibration);
}
}
protected void putOptionValuesInTransaction(final ContentValues values,
final DatabaseWrapper dbWrapper) {
Assert.isTrue(dbWrapper.getDatabase().inTransaction());
if (actionParameters.containsKey(KEY_ENABLE_NOTIFICATION)) {
values.put(ConversationColumns.NOTIFICATION_ENABLED,
actionParameters.getBoolean(KEY_ENABLE_NOTIFICATION));
}
if (actionParameters.containsKey(KEY_RINGTONE_URI)) {
values.put(ConversationColumns.NOTIFICATION_SOUND_URI,
actionParameters.getString(KEY_RINGTONE_URI));
}
if (actionParameters.containsKey(KEY_ENABLE_VIBRATION)) {
values.put(ConversationColumns.NOTIFICATION_VIBRATION,
actionParameters.getBoolean(KEY_ENABLE_VIBRATION));
}
}
@Override
protected Object executeAction() {
final String conversationId = actionParameters.getString(KEY_CONVERSATION_ID);
final DatabaseWrapper db = DataModel.get().getDatabase();
db.beginTransaction();
try {
final ContentValues values = new ContentValues();
putOptionValuesInTransaction(values, db);
BugleDatabaseOperations.updateConversationRowIfExists(db, conversationId, values);
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
MessagingContentProvider.notifyConversationMetadataChanged(conversationId);
return null;
}
protected UpdateConversationOptionsAction(final Parcel in) {
super(in);
}
public static final Parcelable.Creator<UpdateConversationOptionsAction> CREATOR
= new Parcelable.Creator<UpdateConversationOptionsAction>() {
@Override
public UpdateConversationOptionsAction createFromParcel(final Parcel in) {
return new UpdateConversationOptionsAction(in);
}
@Override
public UpdateConversationOptionsAction[] newArray(final int size) {
return new UpdateConversationOptionsAction[size];
}
};
@Override
public void writeToParcel(final Parcel parcel, final int flags) {
writeActionToParcel(parcel, flags);
}
}
@@ -52,9 +52,6 @@ public class ConversationListItemData {
private String mOtherParticipantNormalizedDestination;
private String mSelfId;
private int mParticipantCount;
private boolean mNotificationEnabled;
private String mNotificationSoundUri;
private boolean mNotificationVibrate;
private boolean mIncludeEmailAddress;
private int mMessageStatus;
private int mMessageRawTelephonyStatus;
@@ -92,9 +89,6 @@ public class ConversationListItemData {
INDEX_OTHER_PARTICIPANT_NORMALIZED_DESTINATION);
mSelfId = cursor.getString(INDEX_SELF_ID);
mParticipantCount = cursor.getInt(INDEX_PARTICIPANT_COUNT);
mNotificationEnabled = cursor.getInt(INDEX_NOTIFICATION_ENABLED) == 1;
mNotificationSoundUri = cursor.getString(INDEX_NOTIFICATION_SOUND_URI);
mNotificationVibrate = cursor.getInt(INDEX_NOTIFICATION_VIBRATION) == 1;
mIncludeEmailAddress = cursor.getInt(INDEX_INCLUDE_EMAIL_ADDRESS) == 1;
mMessageStatus = cursor.getInt(INDEX_MESSAGE_STATUS);
mMessageRawTelephonyStatus = cursor.getInt(INDEX_MESSAGE_RAW_TELEPHONY_STATUS);
@@ -199,18 +193,6 @@ public class ConversationListItemData {
return mIncludeEmailAddress;
}
public boolean getNotificationEnabled() {
return mNotificationEnabled;
}
public String getNotificationSoundUri() {
return mNotificationSoundUri;
}
public boolean getNotifiationVibrate() {
return mNotificationVibrate;
}
public final boolean getIsFailedStatus() {
return (mMessageStatus == MessageData.BUGLE_STATUS_OUTGOING_FAILED ||
mMessageStatus == MessageData.BUGLE_STATUS_OUTGOING_FAILED_EMERGENCY_NUMBER ||
@@ -328,12 +310,6 @@ public class ConversationListItemData {
+ " as " + ConversationListViewColumns.PREVIEW_CONTENT_TYPE + ", "
+ DatabaseHelper.CONVERSATIONS_TABLE + '.' + ConversationColumns.PARTICIPANT_COUNT
+ " as " + ConversationListViewColumns.PARTICIPANT_COUNT + ", "
+ DatabaseHelper.CONVERSATIONS_TABLE + '.' + ConversationColumns.NOTIFICATION_ENABLED
+ " as " + ConversationListViewColumns.NOTIFICATION_ENABLED + ", "
+ DatabaseHelper.CONVERSATIONS_TABLE + '.' + ConversationColumns.NOTIFICATION_SOUND_URI
+ " as " + ConversationListViewColumns.NOTIFICATION_SOUND_URI + ", "
+ DatabaseHelper.CONVERSATIONS_TABLE + '.' + ConversationColumns.NOTIFICATION_VIBRATION
+ " as " + ConversationListViewColumns.NOTIFICATION_VIBRATION + ", "
+ DatabaseHelper.CONVERSATIONS_TABLE + '.' +
ConversationColumns.INCLUDE_EMAIL_ADDRESS
+ " as " + ConversationListViewColumns.INCLUDE_EMAIL_ADDRESS + ", "
@@ -396,9 +372,6 @@ public class ConversationListItemData {
ConversationColumns.OTHER_PARTICIPANT_NORMALIZED_DESTINATION;
static final String CURRENT_SELF_ID = ConversationColumns.CURRENT_SELF_ID;
static final String PARTICIPANT_COUNT = ConversationColumns.PARTICIPANT_COUNT;
static final String NOTIFICATION_ENABLED = ConversationColumns.NOTIFICATION_ENABLED;
static final String NOTIFICATION_SOUND_URI = ConversationColumns.NOTIFICATION_SOUND_URI;
static final String NOTIFICATION_VIBRATION = ConversationColumns.NOTIFICATION_VIBRATION;
static final String INCLUDE_EMAIL_ADDRESS =
ConversationColumns.INCLUDE_EMAIL_ADDRESS;
static final String MESSAGE_STATUS = MessageColumns.STATUS;
@@ -424,9 +397,6 @@ public class ConversationListItemData {
ConversationListViewColumns.OTHER_PARTICIPANT_NORMALIZED_DESTINATION,
ConversationListViewColumns.PARTICIPANT_COUNT,
ConversationListViewColumns.CURRENT_SELF_ID,
ConversationListViewColumns.NOTIFICATION_ENABLED,
ConversationListViewColumns.NOTIFICATION_SOUND_URI,
ConversationListViewColumns.NOTIFICATION_VIBRATION,
ConversationListViewColumns.INCLUDE_EMAIL_ADDRESS,
ConversationListViewColumns.MESSAGE_STATUS,
ConversationListViewColumns.SHOW_DRAFT,
@@ -456,23 +426,20 @@ public class ConversationListItemData {
private static final int INDEX_OTHER_PARTICIPANT_NORMALIZED_DESTINATION = 10;
private static final int INDEX_PARTICIPANT_COUNT = 11;
private static final int INDEX_SELF_ID = 12;
private static final int INDEX_NOTIFICATION_ENABLED = 13;
private static final int INDEX_NOTIFICATION_SOUND_URI = 14;
private static final int INDEX_NOTIFICATION_VIBRATION = 15;
private static final int INDEX_INCLUDE_EMAIL_ADDRESS = 16;
private static final int INDEX_MESSAGE_STATUS = 17;
private static final int INDEX_SHOW_DRAFT = 18;
private static final int INDEX_DRAFT_PREVIEW_URI = 19;
private static final int INDEX_DRAFT_PREVIEW_CONTENT_TYPE = 20;
private static final int INDEX_DRAFT_SNIPPET_TEXT = 21;
private static final int INDEX_ARCHIVE_STATUS = 22;
private static final int INDEX_MESSAGE_ID = 23;
private static final int INDEX_SUBJECT_TEXT = 24;
private static final int INDEX_DRAFT_SUBJECT_TEXT = 25;
private static final int INDEX_MESSAGE_RAW_TELEPHONY_STATUS = 26;
private static final int INDEX_SNIPPET_SENDER_FIRST_NAME = 27;
private static final int INDEX_SNIPPET_SENDER_DISPLAY_DESTINATION = 28;
private static final int INDEX_IS_ENTERPRISE = 29;
private static final int INDEX_INCLUDE_EMAIL_ADDRESS = 13;
private static final int INDEX_MESSAGE_STATUS = 14;
private static final int INDEX_SHOW_DRAFT = 15;
private static final int INDEX_DRAFT_PREVIEW_URI = 16;
private static final int INDEX_DRAFT_PREVIEW_CONTENT_TYPE = 17;
private static final int INDEX_DRAFT_SNIPPET_TEXT = 18;
private static final int INDEX_ARCHIVE_STATUS = 19;
private static final int INDEX_MESSAGE_ID = 20;
private static final int INDEX_SUBJECT_TEXT = 21;
private static final int INDEX_DRAFT_SUBJECT_TEXT = 22;
private static final int INDEX_MESSAGE_RAW_TELEPHONY_STATUS = 23;
private static final int INDEX_SNIPPET_SENDER_FIRST_NAME = 24;
private static final int INDEX_SNIPPET_SENDER_DISPLAY_DESTINATION = 25;
private static final int INDEX_IS_ENTERPRISE = 26;
private static final String DIVIDER_TEXT = ", ";
@@ -26,7 +26,6 @@ import android.os.Bundle;
import com.android.messaging.datamodel.BoundCursorLoader;
import com.android.messaging.datamodel.MessagingContentProvider;
import com.android.messaging.datamodel.action.BugleActionToasts;
import com.android.messaging.datamodel.action.UpdateConversationOptionsAction;
import com.android.messaging.datamodel.action.UpdateDestinationBlockedAction;
import com.android.messaging.datamodel.binding.BindableData;
import com.android.messaging.datamodel.binding.BindingBase;
@@ -74,7 +73,7 @@ public class PeopleAndOptionsData extends BindableData implements
final Uri uri =
MessagingContentProvider.buildConversationMetadataUri(mConversationId);
return new BoundCursorLoader(bindingId, mContext, uri,
PeopleOptionsItemData.PROJECTION, null, null, null);
new String[]{}, null, null, null);
}
case PARTICIPANT_LOADER: {
@@ -169,33 +168,6 @@ public class PeopleAndOptionsData extends BindableData implements
}
}
public void enableConversationNotifications(final BindingBase<PeopleAndOptionsData> binding,
final boolean enable) {
final String bindingId = binding.getBindingId();
if (isBound(bindingId)) {
UpdateConversationOptionsAction.enableConversationNotifications(
mConversationId, enable);
}
}
public void setConversationNotificationSound(final BindingBase<PeopleAndOptionsData> binding,
final String ringtoneUri) {
final String bindingId = binding.getBindingId();
if (isBound(bindingId)) {
UpdateConversationOptionsAction.setConversationNotificationSound(mConversationId,
ringtoneUri);
}
}
public void enableConversationNotificationVibration(
final BindingBase<PeopleAndOptionsData> binding, final boolean enable) {
final String bindingId = binding.getBindingId();
if (isBound(bindingId)) {
UpdateConversationOptionsAction.enableVibrationForConversationNotification(
mConversationId, enable);
}
}
public void setDestinationBlocked(final BindingBase<PeopleAndOptionsData> binding,
final boolean blocked) {
final String bindingId = binding.getBindingId();
@@ -207,4 +179,8 @@ public class PeopleAndOptionsData extends BindableData implements
BugleActionToasts.makeUpdateDestinationBlockedActionListener(mContext));
}
}
public String getConversationId() {
return mConversationId;
}
}
@@ -17,44 +17,19 @@ package com.android.messaging.datamodel.data;
import android.content.Context;
import android.database.Cursor;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import com.android.messaging.R;
import com.android.messaging.datamodel.data.ConversationListItemData.ConversationListViewColumns;
import com.android.messaging.util.Assert;
import com.android.messaging.util.RingtoneUtil;
public class PeopleOptionsItemData {
public static final String[] PROJECTION = {
ConversationListViewColumns.NOTIFICATION_ENABLED,
ConversationListViewColumns.NOTIFICATION_SOUND_URI,
ConversationListViewColumns.NOTIFICATION_VIBRATION,
};
// Column index for query projection.
private static final int INDEX_NOTIFICATION_ENABLED = 0;
private static final int INDEX_NOTIFICATION_SOUND_URI = 1;
private static final int INDEX_NOTIFICATION_VIBRATION = 2;
// Identification for each setting that's surfaced to the UI layer.
public static final int SETTING_NOTIFICATION_ENABLED = 0;
public static final int SETTING_NOTIFICATION_SOUND_URI = 1;
public static final int SETTING_NOTIFICATION_VIBRATION = 2;
public static final int SETTING_BLOCKED = 3;
public static final int SETTINGS_COUNT = 4;
// Type of UI switch to show for the toggle button.
public static final int TOGGLE_TYPE_CHECKBOX = 0;
public static final int TOGGLE_TYPE_SWITCH = 1;
public static final int SETTING_NOTIFICATION = 0;
public static final int SETTING_BLOCKED = 1;
public static final int SETTINGS_COUNT = 2;
private String mTitle;
private String mSubtitle;
private Uri mRingtoneUri;
private boolean mCheckable;
private boolean mChecked;
private boolean mEnabled;
private int mItemId;
private ParticipantData mOtherParticipant;
@@ -71,41 +46,12 @@ public class PeopleOptionsItemData {
*/
public void bind(
final Cursor cursor, final ParticipantData otherParticipant, final int settingType) {
mSubtitle = null;
mRingtoneUri = null;
mCheckable = true;
mEnabled = true;
mItemId = settingType;
mOtherParticipant = otherParticipant;
final boolean notificationEnabled = cursor.getInt(INDEX_NOTIFICATION_ENABLED) == 1;
switch (settingType) {
case SETTING_NOTIFICATION_ENABLED:
case SETTING_NOTIFICATION:
mTitle = mContext.getString(R.string.notifications_enabled_conversation_pref_title);
mChecked = notificationEnabled;
break;
case SETTING_NOTIFICATION_SOUND_URI:
mTitle = mContext.getString(R.string.notification_sound_pref_title);
final String ringtoneString = cursor.getString(INDEX_NOTIFICATION_SOUND_URI);
Uri ringtoneUri = RingtoneUtil.getNotificationRingtoneUri(ringtoneString);
mSubtitle = mContext.getString(R.string.silent_ringtone);
if (ringtoneUri != null) {
final Ringtone ringtone = RingtoneManager.getRingtone(mContext, ringtoneUri);
if (ringtone != null) {
mSubtitle = ringtone.getTitle(mContext);
}
}
mCheckable = false;
mRingtoneUri = ringtoneUri;
mEnabled = notificationEnabled;
break;
case SETTING_NOTIFICATION_VIBRATION:
mTitle = mContext.getString(R.string.notification_vibrate_pref_title);
mChecked = cursor.getInt(INDEX_NOTIFICATION_VIBRATION) == 1;
mEnabled = notificationEnabled;
break;
case SETTING_BLOCKED:
@@ -113,7 +59,6 @@ public class PeopleOptionsItemData {
final int resourceId = otherParticipant.isBlocked() ?
R.string.unblock_contact_title : R.string.block_contact_title;
mTitle = mContext.getString(resourceId, otherParticipant.getDisplayDestination());
mCheckable = false;
break;
default:
@@ -125,30 +70,10 @@ public class PeopleOptionsItemData {
return mTitle;
}
public String getSubtitle() {
return mSubtitle;
}
public boolean getCheckable() {
return mCheckable;
}
public boolean getChecked() {
return mChecked;
}
public boolean getEnabled() {
return mEnabled;
}
public int getItemId() {
return mItemId;
}
public Uri getRingtoneUri() {
return mRingtoneUri;
}
public ParticipantData getOtherParticipant() {
return mOtherParticipant;
}