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
+1 -1
View File
@@ -18,7 +18,7 @@
package="com.android.messaging" package="com.android.messaging"
android:installLocation="internalOnly"> android:installLocation="internalOnly">
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="24" /> <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="28" />
<!-- Application holds CPU wakelock while working in background --> <!-- Application holds CPU wakelock while working in background -->
<uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WAKE_LOCK" />
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 839 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 914 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 820 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 613 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 946 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 880 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

@@ -121,17 +121,6 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:background="@android:color/transparent"> android:background="@android:color/transparent">
<ImageView
android:id="@+id/conversation_notification_bell"
style="@style/ConversationListNotificationBellPaddingStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_notifications_off_small_light"
android:visibility="gone"
android:importantForAccessibility="no"
android:contentDescription="@null"
android:layout_gravity="center_vertical"
android:background="@android:color/transparent" />
<TextView <TextView
android:id="@+id/conversation_name" android:id="@+id/conversation_name"
style="@style/ConversationListItemViewConversationNameStyle" style="@style/ConversationListItemViewConversationNameStyle"
-20
View File
@@ -40,25 +40,5 @@
android:ellipsize="end" android:ellipsize="end"
style="@style/ParticipantListItem" style="@style/ParticipantListItem"
android:layout_gravity="center_vertical" /> android:layout_gravity="center_vertical" />
<TextView
android:id="@+id/subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:maxLines="1"
android:ellipsize="end"
style="@style/ParticipantListItemDetail"
android:layout_gravity="center_vertical" />
</LinearLayout> </LinearLayout>
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/switch_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="false"
android:clickable="false"
android:visibility="gone" />
</com.android.messaging.ui.conversationsettings.PeopleOptionsItemView> </com.android.messaging.ui.conversationsettings.PeopleOptionsItemView>
@@ -67,18 +67,6 @@
android:layout_alignParentTop="true" android:layout_alignParentTop="true"
android:gravity="center_vertical" android:gravity="center_vertical"
android:background="@android:color/transparent"> android:background="@android:color/transparent">
<ImageView
android:id="@+id/conversation_notification_bell"
style="@style/ConversationListNotificationBellPaddingStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_notifications_off_small_light"
android:visibility="gone"
android:importantForAccessibility="no"
android:contentDescription="@null"
android:layout_gravity="center_vertical"
android:background="@android:color/transparent" />
<TextView android:id="@+id/from" <TextView android:id="@+id/from"
style="@style/WidgetConversationListItemFrom" style="@style/WidgetConversationListItemFrom"
android:layout_width="0dp" android:layout_width="0dp"
@@ -36,18 +36,6 @@
android:orderInCategory="60" android:orderInCategory="60"
android:title="@string/action_delete" android:title="@string/action_delete"
appcompat:showAsAction="collapseActionView|always"/> appcompat:showAsAction="collapseActionView|always"/>
<item
android:id="@+id/action_notification_off"
android:icon="@drawable/ic_notifications_off_dark"
android:orderInCategory="70"
android:title="@string/action_notification_off"
appcompat:showAsAction="collapseActionView|always"/>
<item
android:id="@+id/action_notification_on"
android:icon="@drawable/ic_notifications_on_dark"
android:orderInCategory="80"
android:title="@string/action_notification_on"
appcompat:showAsAction="collapseActionView|always"/>
<item <item
android:id="@+id/action_add_contact" android:id="@+id/action_add_contact"
android:icon="@drawable/ic_person_add_dark" android:icon="@drawable/ic_person_add_dark"
-4
View File
@@ -74,10 +74,6 @@
<item name="android:textColor">@color/conversation_list_name</item> <item name="android:textColor">@color/conversation_list_name</item>
</style> </style>
<style name="ConversationListNotificationBellPaddingStyle">
<item name="android:paddingEnd">@dimen/conversation_list_notification_bell_padding</item>
</style>
<style name="ComposeMessageViewFrameLayoutStyle"> <style name="ComposeMessageViewFrameLayoutStyle">
<item name="android:paddingEnd">@dimen/compose_message_send_button_padding_right</item> <item name="android:paddingEnd">@dimen/compose_message_send_button_padding_right</item>
</style> </style>
-1
View File
@@ -122,7 +122,6 @@
<color name="notification_subject_color">#99aaaaaa</color> <color name="notification_subject_color">#99aaaaaa</color>
<color name="participant_list_text_primary">#4d4d4d</color> <color name="participant_list_text_primary">#4d4d4d</color>
<color name="participant_list_text_secondary">#6d6d6d</color>
<color name="people_and_options_header_text">#6d6d6d</color> <color name="people_and_options_header_text">#6d6d6d</color>
<color name="people_and_options_list_divider">#cccccc</color> <color name="people_and_options_list_divider">#cccccc</color>
+1 -2
View File
@@ -21,8 +21,7 @@
<string name="notifications_category_pref_key" translatable="false">notifications_category</string> <string name="notifications_category_pref_key" translatable="false">notifications_category</string>
<string name="mms_messaging_category_pref_key" translatable="false">mms_messaging_category</string> <string name="mms_messaging_category_pref_key" translatable="false">mms_messaging_category</string>
<string name="advanced_category_pref_key" translatable="false">advanced_category</string> <string name="advanced_category_pref_key" translatable="false">advanced_category</string>
<string name="notifications_enabled_pref_key" translatable="false">notifications_enabled</string> <string name="notifications_pref_key" translatable="false">notifications_enabled</string>
<bool name="notifications_enabled_pref_default" translatable="false">true</bool>
<string name="notification_sound_pref_key" translatable="false">notification_sound</string> <string name="notification_sound_pref_key" translatable="false">notification_sound</string>
<string name="notification_vibration_pref_key" translatable="false">notification_vibration</string> <string name="notification_vibration_pref_key" translatable="false">notification_vibration</string>
<bool name="notification_vibration_pref_default" translatable="false">true</bool> <bool name="notification_vibration_pref_default" translatable="false">true</bool>
-2
View File
@@ -34,7 +34,6 @@
<dimen name="conversation_list_contact_icon_size">56dp</dimen> <dimen name="conversation_list_contact_icon_size">56dp</dimen>
<dimen name="conversation_message_contact_icon_size">42dp</dimen> <dimen name="conversation_message_contact_icon_size">42dp</dimen>
<dimen name="conversation_message_photo_min_size">96dp</dimen> <dimen name="conversation_message_photo_min_size">96dp</dimen>
<dimen name="conversation_list_notification_bell_padding">4dp</dimen>
<dimen name="conversation_list_empty_text_bottom_margin">30dp</dimen> <dimen name="conversation_list_empty_text_bottom_margin">30dp</dimen>
<dimen name="blocked_participant_list_item_view_padding">16dp</dimen> <dimen name="blocked_participant_list_item_view_padding">16dp</dimen>
@@ -109,7 +108,6 @@
<dimen name="progress_indicator_default_stroke_width">2dp</dimen> <dimen name="progress_indicator_default_stroke_width">2dp</dimen>
<dimen name="progress_indicator_default_radius">12dp</dimen> <dimen name="progress_indicator_default_radius">12dp</dimen>
<dimen name="participant_list_text_size">18sp</dimen> <dimen name="participant_list_text_size">18sp</dimen>
<dimen name="participant_list_detail_text_size">14sp</dimen>
<dimen name="people_and_options_header_text_size">16sp</dimen> <dimen name="people_and_options_header_text_size">16sp</dimen>
<dimen name="image_attachment_fallback_width">240dp</dimen> <dimen name="image_attachment_fallback_width">240dp</dimen>
<dimen name="image_attachment_fallback_height">240dp</dimen> <dimen name="image_attachment_fallback_height">240dp</dimen>
+4 -9
View File
@@ -257,10 +257,6 @@
<string name="action_archive">Archive</string> <string name="action_archive">Archive</string>
<!-- Action menu title for unarchiving selected conversations in conversation list --> <!-- Action menu title for unarchiving selected conversations in conversation list -->
<string name="action_unarchive">Unarchive</string> <string name="action_unarchive">Unarchive</string>
<!-- Action menu title for turning off notification for the selected conversations in conversation list -->
<string name="action_notification_off">Turn off notifications</string>
<!-- Action menu title for turning on notification for the selected conversations in conversation list -->
<string name="action_notification_on">Turn on notifications</string>
<!-- Action menu title for adding the contacts for the selected conversations in conversation list --> <!-- Action menu title for adding the contacts for the selected conversations in conversation list -->
<string name="action_add_contact">Add contact</string> <string name="action_add_contact">Add contact</string>
<!-- Action menu title for downloading failed message selected in conversation --> <!-- Action menu title for downloading failed message selected in conversation -->
@@ -440,13 +436,9 @@
<!-- Preference category: Debug --> <!-- Preference category: Debug -->
<string name="debug_category_pref_title">Debug</string> <string name="debug_category_pref_title">Debug</string>
<!-- Title for the preference for whether or to notify the user of new messages --> <!-- Title for the preference for whether or to notify the user of new messages -->
<string name="notifications_enabled_pref_title">Notifications</string> <string name="notifications_pref_title">Notifications</string>
<!-- Title for the notification sound preference --> <!-- Title for the notification sound preference -->
<string name="notification_sound_pref_title">Sound</string>
<!-- What to display in the settings screen for Ringtone when the user chooses "silent" [CHAR LIMIT=100]-->
<string name="silent_ringtone">Silent</string> <string name="silent_ringtone">Silent</string>
<!-- Title for the preference for whether or not to vibrate with notifications -->
<string name="notification_vibrate_pref_title">Vibrate</string>
<string name="blocked_pref_title">Blocked</string> <string name="blocked_pref_title">Blocked</string>
<!-- Title for the preference for whether or not to request/show delivery reports for SMS --> <!-- Title for the preference for whether or not to request/show delivery reports for SMS -->
<string name="delivery_reports_pref_title">SMS delivery reports</string> <string name="delivery_reports_pref_title">SMS delivery reports</string>
@@ -982,4 +974,7 @@
<!-- When making a call to emergency numbers, show this toast --> <!-- When making a call to emergency numbers, show this toast -->
<string name="disallow_emergency_call">Can\'t make a voice call to emergency services here.</string> <string name="disallow_emergency_call">Can\'t make a voice call to emergency services here.</string>
<!-- Notification channel -->
<string name="notification_channel_messages_title">Messages</string>
</resources> </resources>
-10
View File
@@ -291,10 +291,6 @@
<item name="android:textColor">@color/conversation_list_name</item> <item name="android:textColor">@color/conversation_list_name</item>
</style> </style>
<style name="ConversationListNotificationBellPaddingStyle">
<item name="android:paddingRight">@dimen/conversation_list_notification_bell_padding</item>
</style>
<style name="ComposeMessageViewFrameLayoutStyle"> <style name="ComposeMessageViewFrameLayoutStyle">
<item name="android:paddingRight">@dimen/compose_message_send_button_padding_right</item> <item name="android:paddingRight">@dimen/compose_message_send_button_padding_right</item>
</style> </style>
@@ -347,12 +343,6 @@
<item name="android:paddingRight">@dimen/copy_contact_dialog_right_padding</item> <item name="android:paddingRight">@dimen/copy_contact_dialog_right_padding</item>
</style> </style>
<style name="ParticipantListItemDetail">
<item name="android:textSize">@dimen/participant_list_detail_text_size</item>
<item name="android:textColor">@color/participant_list_text_secondary</item>
<item name="android:background">@null</item>
</style>
<style name="PeopleListItemViewStyle"> <style name="PeopleListItemViewStyle">
<item name="android:paddingLeft">16dp</item> <item name="android:paddingLeft">16dp</item>
</style> </style>
+4 -23
View File
@@ -42,29 +42,10 @@
android:defaultValue="@bool/send_sound_pref_default" android:defaultValue="@bool/send_sound_pref_default"
android:persistent="true" /> android:persistent="true" />
<SwitchPreference <Preference
android:key="@string/notifications_enabled_pref_key" android:key="@string/notifications_pref_key"
android:title="@string/notifications_enabled_pref_title" android:title="@string/notifications_pref_title"
android:defaultValue="@bool/notifications_enabled_pref_default" android:persistent="true" />
android:persistent="true"
android:disableDependentsState="false" />
<RingtonePreference
android:key="@string/notification_sound_pref_key"
android:title="@string/notification_sound_pref_title"
android:ringtoneType="notification"
android:showSilent="true"
android:showDefault="true"
android:persistent="true"
android:defaultValue=""
android:dependency="@string/notifications_enabled_pref_key" />
<SwitchPreference
android:key="@string/notification_vibration_pref_key"
android:title="@string/notification_vibrate_pref_title"
android:defaultValue="@bool/notification_vibration_pref_default"
android:persistent="true"
android:dependency="@string/notifications_enabled_pref_key" />
<SwitchPreference <SwitchPreference
android:key="@string/swipe_right_deletes_conversation_key" android:key="@string/swipe_right_deletes_conversation_key"
+4 -23
View File
@@ -43,29 +43,10 @@
android:defaultValue="@bool/send_sound_pref_default" android:defaultValue="@bool/send_sound_pref_default"
android:persistent="true" /> android:persistent="true" />
<SwitchPreference <Preference
android:key="@string/notifications_enabled_pref_key" android:key="@string/notifications_pref_key"
android:title="@string/notifications_enabled_pref_title" android:title="@string/notifications_pref_title"
android:defaultValue="@bool/notifications_enabled_pref_default" android:persistent="true" />
android:persistent="true"
android:disableDependentsState="false" />
<RingtonePreference
android:key="@string/notification_sound_pref_key"
android:title="@string/notification_sound_pref_title"
android:ringtoneType="notification"
android:showSilent="true"
android:showDefault="true"
android:persistent="true"
android:defaultValue=""
android:dependency="@string/notifications_enabled_pref_key" />
<SwitchPreference
android:key="@string/notification_vibration_pref_key"
android:title="@string/notification_vibrate_pref_title"
android:defaultValue="@bool/notification_vibration_pref_default"
android:persistent="true"
android:dependency="@string/notifications_enabled_pref_key" />
<SwitchPreference <SwitchPreference
android:key="@string/swipe_right_deletes_conversation_key" android:key="@string/swipe_right_deletes_conversation_key"
+4 -23
View File
@@ -42,29 +42,10 @@
android:defaultValue="@bool/send_sound_pref_default" android:defaultValue="@bool/send_sound_pref_default"
android:persistent="true" /> android:persistent="true" />
<CheckBoxPreference <Preference
android:key="@string/notifications_enabled_pref_key" android:key="@string/notifications_pref_key"
android:title="@string/notifications_enabled_pref_title" android:title="@string/notifications_pref_title"
android:defaultValue="@bool/notifications_enabled_pref_default" android:persistent="true" />
android:persistent="true"
android:disableDependentsState="false" />
<RingtonePreference
android:key="@string/notification_sound_pref_key"
android:title="@string/notification_sound_pref_title"
android:ringtoneType="notification"
android:showSilent="true"
android:showDefault="true"
android:persistent="true"
android:defaultValue=""
android:dependency="@string/notifications_enabled_pref_key" />
<CheckBoxPreference
android:key="@string/notification_vibration_pref_key"
android:title="@string/notification_vibrate_pref_title"
android:defaultValue="@bool/notification_vibration_pref_default"
android:persistent="true"
android:dependency="@string/notifications_enabled_pref_key" />
<SwitchPreference <SwitchPreference
android:key="@string/swipe_right_deletes_conversation_key" android:key="@string/swipe_right_deletes_conversation_key"
@@ -171,8 +171,7 @@ public class BugleDatabaseOperations {
final ArrayList<ParticipantData> participants = final ArrayList<ParticipantData> participants =
getConversationParticipantsFromRecipients(recipients, refSubId); getConversationParticipantsFromRecipients(recipients, refSubId);
return getOrCreateConversation(db, threadId, senderBlocked, participants, false, false, return getOrCreateConversation(db, threadId, senderBlocked, participants);
null);
} }
/** /**
@@ -190,7 +189,7 @@ public class BugleDatabaseOperations {
Assert.isNotMainThread(); Assert.isNotMainThread();
final ArrayList<ParticipantData> recipients = new ArrayList<>(1); final ArrayList<ParticipantData> recipients = new ArrayList<>(1);
recipients.add(recipient); 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 threadId The message's thread
* @param archived Flag whether the conversation should be created archived * @param archived Flag whether the conversation should be created archived
* @param participants list of conversation participants * @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 * @return a conversation id
*/ */
@DoesNotRunOnMainThread @DoesNotRunOnMainThread
public static String getOrCreateConversation(final DatabaseWrapper db, final long threadId, public static String getOrCreateConversation(final DatabaseWrapper db, final long threadId,
final boolean archived, final ArrayList<ParticipantData> participants, final boolean archived, final ArrayList<ParticipantData> participants) {
boolean noNotification, boolean noVibrate, String soundUri) {
Assert.isNotMainThread(); Assert.isNotMainThread();
// Check to see if this conversation is already in out local db cache // Check to see if this conversation is already in out local db cache
@@ -231,8 +226,7 @@ public class BugleDatabaseOperations {
BugleDatabaseOperations.getOrCreateParticipantInTransaction(db, self); BugleDatabaseOperations.getOrCreateParticipantInTransaction(db, self);
// Create a new conversation // Create a new conversation
conversationId = BugleDatabaseOperations.createConversationInTransaction( conversationId = BugleDatabaseOperations.createConversationInTransaction(
db, threadId, conversationName, selfId, participants, archived, db, threadId, conversationName, selfId, participants, archived);
noNotification, noVibrate, soundUri);
db.setTransactionSuccessful(); db.setTransactionSuccessful();
} finally { } finally {
db.endTransaction(); db.endTransaction();
@@ -357,15 +351,11 @@ public class BugleDatabaseOperations {
* @param threadId The message's thread * @param threadId The message's thread
* @param selfId The selfId to make default for this conversation * @param selfId The selfId to make default for this conversation
* @param archived Flag whether the conversation should be created archived * @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 * @return The existing conversation id or new conversation id
*/ */
static String createConversationInTransaction(final DatabaseWrapper dbWrapper, static String createConversationInTransaction(final DatabaseWrapper dbWrapper,
final long threadId, final String conversationName, final String selfId, final long threadId, final String conversationName, final String selfId,
final List<ParticipantData> participants, final boolean archived, final List<ParticipantData> participants, final boolean archived) {
boolean noNotification, boolean noVibrate, String soundUri) {
// We want conversation and participant creation to be atomic // We want conversation and participant creation to be atomic
Assert.isTrue(dbWrapper.getDatabase().inTransaction()); Assert.isTrue(dbWrapper.getDatabase().inTransaction());
boolean hasEmailAddress = false; boolean hasEmailAddress = false;
@@ -389,15 +379,6 @@ public class BugleDatabaseOperations {
if (archived) { if (archived) {
values.put(ConversationColumns.ARCHIVE_STATUS, 1); 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); fillParticipantData(values, participants);
@@ -17,6 +17,8 @@
package com.android.messaging.datamodel; package com.android.messaging.datamodel;
import android.app.Notification; import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
import android.content.Intent; 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.ImageUtils;
import com.android.messaging.util.LogUtil; import com.android.messaging.util.LogUtil;
import com.android.messaging.util.NotificationPlayer; import com.android.messaging.util.NotificationPlayer;
import com.android.messaging.util.NotificationsUtil;
import com.android.messaging.util.OsUtil; import com.android.messaging.util.OsUtil;
import com.android.messaging.util.PendingIntentConstants; import com.android.messaging.util.PendingIntentConstants;
import com.android.messaging.util.PhoneUtils; import com.android.messaging.util.PhoneUtils;
import com.android.messaging.util.RingtoneUtil;
import com.android.messaging.util.ThreadUtil; import com.android.messaging.util.ThreadUtil;
import com.android.messaging.util.UriUtil; import com.android.messaging.util.UriUtil;
@@ -173,18 +175,10 @@ public class BugleNotifications {
} }
Assert.isNotMainThread(); Assert.isNotMainThread();
checkInitialized(); checkInitialized();
if ((coverage & UPDATE_MESSAGES) != 0) {
if (!shouldNotify()) { createMessageNotification(silent, conversationId);
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_ERRORS) != 0) { if ((coverage & UPDATE_ERRORS) != 0) {
MessageNotificationState.checkFailedMessages(); MessageNotificationState.checkFailedMessages();
} }
@@ -195,8 +189,7 @@ public class BugleNotifications {
* *
*/ */
public static void playClassZeroNotification() { public static void playClassZeroNotification() {
final Uri ringtoneUri = RingtoneUtil.getNotificationRingtoneUri(null); playObservableConversationNotificationSound(null);
playObservableConversationNotificationSound(ringtoneUri);
} }
/** /**
@@ -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. * 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, private static void processAndSend(final NotificationState state, final boolean silent,
final boolean softSound) { final boolean softSound) {
final Context context = Factory.get().getApplicationContext(); 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. // TODO: Need to fix this for multi conversation notifications to rate limit dings.
final String conversationId = state.mConversationIds.first(); 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 // 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 // conversation list), then play a notification beep at a low volume and don't display an
// actual notification. // actual notification.
@@ -436,7 +381,7 @@ public class BugleNotifications {
"sCurrentlyDisplayedConversationId so NOT showing notification," + "sCurrentlyDisplayedConversationId so NOT showing notification," +
" but playing soft sound. conversationId: " + conversationId); " but playing soft sound. conversationId: " + conversationId);
} }
playObservableConversationNotificationSound(ringtoneUri); playObservableConversationNotificationSound(conversationId);
return; return;
} }
state.mBaseRequestCode = state.mType; state.mBaseRequestCode = state.mType;
@@ -449,7 +394,7 @@ public class BugleNotifications {
notifBuilder.setDeleteIntent(clearIntent); notifBuilder.setDeleteIntent(clearIntent);
} }
updateBuilderAudioVibrate(state, notifBuilder, silent, ringtoneUri, conversationId); updateBuilderAudioVibrate(state, notifBuilder, silent, conversationId);
// Set the content intent // Set the content intent
PendingIntent destinationIntent; PendingIntent destinationIntent;
@@ -607,8 +552,7 @@ public class BugleNotifications {
if (state == null) { if (state == null) {
cancel(PendingIntentConstants.SMS_NOTIFICATION_ID); cancel(PendingIntentConstants.SMS_NOTIFICATION_ID);
if (softSound && !TextUtils.isEmpty(conversationId)) { if (softSound && !TextUtils.isEmpty(conversationId)) {
final Uri ringtoneUri = getNotificationRingtoneUriForConversationId(conversationId); playObservableConversationNotificationSound(conversationId);
playObservableConversationNotificationSound(ringtoneUri);
} }
return; return;
} }
@@ -646,8 +590,8 @@ public class BugleNotifications {
private static void updateBuilderAudioVibrate(final NotificationState state, private static void updateBuilderAudioVibrate(final NotificationState state,
final NotificationCompat.Builder notifBuilder, final boolean silent, final NotificationCompat.Builder notifBuilder, final boolean silent,
final Uri ringtoneUri, final String conversationId) { final String conversationId) {
int defaults = Notification.DEFAULT_LIGHTS; int defaults = Notification.DEFAULT_LIGHTS | Notification.DEFAULT_VIBRATE;
if (!silent) { if (!silent) {
final BuglePrefs prefs = Factory.get().getApplicationPrefs(); final BuglePrefs prefs = Factory.get().getApplicationPrefs();
final long latestNotificationTimestamp = prefs.getLong( final long latestNotificationTimestamp = prefs.getLong(
@@ -669,10 +613,6 @@ public class BugleNotifications {
if (lastTime == null if (lastTime == null
|| SystemClock.elapsedRealtime() - lastTime > sTimeBetweenDingsMs) { || SystemClock.elapsedRealtime() - lastTime > sTimeBetweenDingsMs) {
sLastMessageDingTime.put(conversationId, SystemClock.elapsedRealtime()); 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); notificationState.mNotificationBuilder.setLargeIcon(smallBitmap);
// Add a wearable page with no visible card so you can more easily see the photo. // 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 = 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(); final WearableExtender photoPageWearableExtender = new WearableExtender();
photoPageWearableExtender.setHintShowBackgroundOnly(true); photoPageWearableExtender.setHintShowBackgroundOnly(true);
if (attachmentBitmap != null) { if (attachmentBitmap != null) {
@@ -982,6 +928,16 @@ public class BugleNotifications {
notification.flags |= Notification.FLAG_AUTO_CANCEL; notification.flags |= Notification.FLAG_AUTO_CANCEL;
notification.defaults |= Notification.DEFAULT_LIGHTS; 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); notificationManager.notify(notificationTag, type, notification);
LogUtil.i(TAG, "Notifying for conversation " + conversationId + "; " 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 * Play the observable conversation notification sound (it's the regular notification sound, but
* played at half-volume) * 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 Context context = Factory.get().getApplicationContext();
final AudioManager audioManager = (AudioManager) context final AudioManager audioManager = (AudioManager) context
.getSystemService(Context.AUDIO_SERVICE); .getSystemService(Context.AUDIO_SERVICE);
@@ -1116,7 +1072,11 @@ public class BugleNotifications {
} }
final NotificationPlayer player = new NotificationPlayer(LogUtil.BUGLE_TAG); 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, AudioManager.STREAM_NOTIFICATION,
OBSERVABLE_CONVERSATION_NOTIFICATION_VOLUME); OBSERVABLE_CONVERSATION_NOTIFICATION_VOLUME);
@@ -1211,7 +1171,8 @@ public class BugleNotifications {
final PendingIntent destinationIntent = UIIntents.get() final PendingIntent destinationIntent = UIIntents.get()
.getPendingIntentForConversationActivity(context, conversationId, null /* draft */); .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) builder.setTicker(line1)
.setContentTitle(line1) .setContentTitle(line1)
.setContentText(line2) .setContentText(line2)
@@ -1221,6 +1182,15 @@ public class BugleNotifications {
.setSound(UriUtil.getUriForResourceId(context, R.raw.message_failure)); .setSound(UriUtil.getUriForResourceId(context, R.raw.message_failure));
final String tag = context.getPackageName() + ":emergency_sms_error"; 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( NotificationManagerCompat.from(context).notify(
tag, tag,
PendingIntentConstants.MSG_SEND_ERROR, 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) */ /* Participant count not including self (so will be 1 for 1:1 or bigger for group) */
public static final String PARTICIPANT_COUNT = "participant_count"; 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 */ /* Conversation recipients include email address */
public static final String INCLUDE_EMAIL_ADDRESS = "include_email_addr"; 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.OTHER_PARTICIPANT_NORMALIZED_DESTINATION + " TEXT, "
+ ConversationColumns.CURRENT_SELF_ID + " TEXT, " + ConversationColumns.CURRENT_SELF_ID + " TEXT, "
+ ConversationColumns.PARTICIPANT_COUNT + " INT DEFAULT(0), " + 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.INCLUDE_EMAIL_ADDRESS + " INT DEFAULT(0), "
+ ConversationColumns.SMS_SERVICE_CENTER + " TEXT ," + ConversationColumns.SMS_SERVICE_CENTER + " TEXT ,"
+ ConversationColumns.IS_ENTERPRISE + " INT DEFAULT(0)" + ConversationColumns.IS_ENTERPRISE + " INT DEFAULT(0)"
@@ -197,15 +197,6 @@ public abstract class MessageNotificationState extends NotificationState {
// line infos is capped. // line infos is capped.
int mTotalMessageCount; 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 // Avatar uri of sender
final Uri mAvatarUri; final Uri mAvatarUri;
@@ -224,9 +215,6 @@ public abstract class MessageNotificationState extends NotificationState {
final boolean includeEmailAddress, final boolean includeEmailAddress,
final long receivedTimestamp, final long receivedTimestamp,
final String selfParticipantId, final String selfParticipantId,
final String ringtoneUri,
final boolean notificationEnabled,
final boolean notificationVibrate,
final Uri avatarUri, final Uri avatarUri,
final Uri contactUri, final Uri contactUri,
final int subId, final int subId,
@@ -239,11 +227,8 @@ public abstract class MessageNotificationState extends NotificationState {
mSelfParticipantId = selfParticipantId; mSelfParticipantId = selfParticipantId;
mLineInfos = new ArrayList<NotificationLineInfo>(); mLineInfos = new ArrayList<NotificationLineInfo>();
mTotalMessageCount = 0; mTotalMessageCount = 0;
mRingtoneUri = ringtoneUri;
mAvatarUri = avatarUri; mAvatarUri = avatarUri;
mContactUri = contactUri; mContactUri = contactUri;
mNotificationEnabled = notificationEnabled;
mNotificationVibrate = notificationVibrate;
mSubId = subId; mSubId = subId;
mParticipantCount = participantCount; mParticipantCount = participantCount;
} }
@@ -870,10 +855,6 @@ public abstract class MessageNotificationState extends NotificationState {
if (currConvInfo == null) { if (currConvInfo == null) {
final ConversationListItemData convData = final ConversationListItemData convData =
ConversationListItemData.getExistingConversation(db, convId); ConversationListItemData.getExistingConversation(db, convId);
if (!convData.getNotificationEnabled()) {
// Skip conversations that have notifications disabled.
continue;
}
final int subId = BugleDatabaseOperations.getSelfSubscriptionId(db, final int subId = BugleDatabaseOperations.getSelfSubscriptionId(db,
convData.getSelfId()); convData.getSelfId());
groupConversationName = convData.getName(); groupConversationName = convData.getName();
@@ -888,9 +869,6 @@ public abstract class MessageNotificationState extends NotificationState {
convData.getIncludeEmailAddress(), convData.getIncludeEmailAddress(),
convMessageData.getReceivedTimeStamp(), convMessageData.getReceivedTimeStamp(),
convData.getSelfId(), convData.getSelfId(),
convData.getNotificationSoundUri(),
convData.getNotificationEnabled(),
convData.getNotifiationVibrate(),
avatarUri, avatarUri,
convMessageData.getSenderContactLookupUri(), convMessageData.getSenderContactLookupUri(),
subId, subId,
@@ -1103,22 +1081,6 @@ public abstract class MessageNotificationState extends NotificationState {
return BugleNotifications.LOCAL_SMS_NOTIFICATION; 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() { protected CharSequence getTicker() {
return BugleNotifications.buildColonSeparatedMessage( return BugleNotifications.buildColonSeparatedMessage(
mTickerSender != null ? mTickerSender : mTitle, mTickerSender != null ? mTickerSender : mTitle,
@@ -134,15 +134,6 @@ public abstract class NotificationState {
*/ */
public abstract int getPriority(); 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() { public long getLatestReceivedTimestamp() {
return Long.MIN_VALUE; return Long.MIN_VALUE;
} }
@@ -51,33 +51,14 @@ public class SyncManager {
*/ */
public static class ConversationCustomization { public static class ConversationCustomization {
private final boolean mArchived; private final boolean mArchived;
private final boolean mMuted;
private final boolean mNoVibrate;
private final String mNotificationSoundUri;
public ConversationCustomization(final boolean archived, final boolean muted, public ConversationCustomization(final boolean archived) {
final boolean noVibrate, final String notificationSoundUri) {
mArchived = archived; mArchived = archived;
mMuted = muted;
mNoVibrate = noVibrate;
mNotificationSoundUri = notificationSoundUri;
} }
public boolean isArchived() { public boolean isArchived() {
return mArchived; return mArchived;
} }
public boolean isMuted() {
return mMuted;
}
public boolean noVibrate() {
return mNoVibrate;
}
public String getNotificationSoundUri() {
return mNotificationSoundUri;
}
} }
SyncManager() { SyncManager() {
@@ -436,15 +417,13 @@ public class SyncManager {
if (customization != null) { if (customization != null) {
// There is user customization we need to recover // There is user customization we need to recover
conversationId = BugleDatabaseOperations.getOrCreateConversation(db, threadId, conversationId = BugleDatabaseOperations.getOrCreateConversation(db, threadId,
customization.isArchived(), participants, customization.isMuted(), customization.isArchived(), participants);
customization.noVibrate(), customization.getNotificationSoundUri());
if (customization.isArchived()) { if (customization.isArchived()) {
mArchivedConversations.add(conversationId); mArchivedConversations.add(conversationId);
} }
} else { } else {
conversationId = BugleDatabaseOperations.getOrCreateConversation(db, threadId, conversationId = BugleDatabaseOperations.getOrCreateConversation(db, threadId,
false/*archived*/, participants, false/*noNotification*/, false/*archived*/, participants);
false/*noVibrate*/, null/*soundUri*/);
} }
if (conversationId != null) { if (conversationId != null) {
@@ -35,6 +35,7 @@ import com.android.messaging.datamodel.MessagingContentProvider;
import com.android.messaging.sms.MmsUtils; import com.android.messaging.sms.MmsUtils;
import com.android.messaging.util.Assert; import com.android.messaging.util.Assert;
import com.android.messaging.util.LogUtil; import com.android.messaging.util.LogUtil;
import com.android.messaging.util.NotificationsUtil;
import com.android.messaging.widget.WidgetConversationProvider; import com.android.messaging.widget.WidgetConversationProvider;
import java.util.ArrayList; 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"); + " has an invalid telephony thread id; will delete messages individually");
deleteConversationMessagesFromTelephony(); deleteConversationMessagesFromTelephony();
} }
// Finally, remove the conversation specific notification channel
NotificationsUtil.deleteNotificationChannel(Factory.get().getApplicationContext(),
conversationId);
} else { } else {
LogUtil.e(TAG, "DeleteConversationAction: conversationId is empty"); 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, final String conversationId = BugleDatabaseOperations.getOrCreateConversation(db, threadId,
false, participants, false, false, null); false, participants);
return conversationId; return conversationId;
} }
@@ -274,7 +274,7 @@ public class InsertNewMessageAction extends Action implements Parcelable {
} }
final String conversationId = BugleDatabaseOperations.getOrCreateConversation(db, threadId, final String conversationId = BugleDatabaseOperations.getOrCreateConversation(db, threadId,
false, participants, false, false, null); false, participants);
final ParticipantData self = BugleDatabaseOperations.getOrCreateSelf(db, subId); 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 mOtherParticipantNormalizedDestination;
private String mSelfId; private String mSelfId;
private int mParticipantCount; private int mParticipantCount;
private boolean mNotificationEnabled;
private String mNotificationSoundUri;
private boolean mNotificationVibrate;
private boolean mIncludeEmailAddress; private boolean mIncludeEmailAddress;
private int mMessageStatus; private int mMessageStatus;
private int mMessageRawTelephonyStatus; private int mMessageRawTelephonyStatus;
@@ -92,9 +89,6 @@ public class ConversationListItemData {
INDEX_OTHER_PARTICIPANT_NORMALIZED_DESTINATION); INDEX_OTHER_PARTICIPANT_NORMALIZED_DESTINATION);
mSelfId = cursor.getString(INDEX_SELF_ID); mSelfId = cursor.getString(INDEX_SELF_ID);
mParticipantCount = cursor.getInt(INDEX_PARTICIPANT_COUNT); 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; mIncludeEmailAddress = cursor.getInt(INDEX_INCLUDE_EMAIL_ADDRESS) == 1;
mMessageStatus = cursor.getInt(INDEX_MESSAGE_STATUS); mMessageStatus = cursor.getInt(INDEX_MESSAGE_STATUS);
mMessageRawTelephonyStatus = cursor.getInt(INDEX_MESSAGE_RAW_TELEPHONY_STATUS); mMessageRawTelephonyStatus = cursor.getInt(INDEX_MESSAGE_RAW_TELEPHONY_STATUS);
@@ -199,18 +193,6 @@ public class ConversationListItemData {
return mIncludeEmailAddress; return mIncludeEmailAddress;
} }
public boolean getNotificationEnabled() {
return mNotificationEnabled;
}
public String getNotificationSoundUri() {
return mNotificationSoundUri;
}
public boolean getNotifiationVibrate() {
return mNotificationVibrate;
}
public final boolean getIsFailedStatus() { public final boolean getIsFailedStatus() {
return (mMessageStatus == MessageData.BUGLE_STATUS_OUTGOING_FAILED || return (mMessageStatus == MessageData.BUGLE_STATUS_OUTGOING_FAILED ||
mMessageStatus == MessageData.BUGLE_STATUS_OUTGOING_FAILED_EMERGENCY_NUMBER || mMessageStatus == MessageData.BUGLE_STATUS_OUTGOING_FAILED_EMERGENCY_NUMBER ||
@@ -328,12 +310,6 @@ public class ConversationListItemData {
+ " as " + ConversationListViewColumns.PREVIEW_CONTENT_TYPE + ", " + " as " + ConversationListViewColumns.PREVIEW_CONTENT_TYPE + ", "
+ DatabaseHelper.CONVERSATIONS_TABLE + '.' + ConversationColumns.PARTICIPANT_COUNT + DatabaseHelper.CONVERSATIONS_TABLE + '.' + ConversationColumns.PARTICIPANT_COUNT
+ " as " + ConversationListViewColumns.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 + '.' + + DatabaseHelper.CONVERSATIONS_TABLE + '.' +
ConversationColumns.INCLUDE_EMAIL_ADDRESS ConversationColumns.INCLUDE_EMAIL_ADDRESS
+ " as " + ConversationListViewColumns.INCLUDE_EMAIL_ADDRESS + ", " + " as " + ConversationListViewColumns.INCLUDE_EMAIL_ADDRESS + ", "
@@ -396,9 +372,6 @@ public class ConversationListItemData {
ConversationColumns.OTHER_PARTICIPANT_NORMALIZED_DESTINATION; ConversationColumns.OTHER_PARTICIPANT_NORMALIZED_DESTINATION;
static final String CURRENT_SELF_ID = ConversationColumns.CURRENT_SELF_ID; static final String CURRENT_SELF_ID = ConversationColumns.CURRENT_SELF_ID;
static final String PARTICIPANT_COUNT = ConversationColumns.PARTICIPANT_COUNT; 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 = static final String INCLUDE_EMAIL_ADDRESS =
ConversationColumns.INCLUDE_EMAIL_ADDRESS; ConversationColumns.INCLUDE_EMAIL_ADDRESS;
static final String MESSAGE_STATUS = MessageColumns.STATUS; static final String MESSAGE_STATUS = MessageColumns.STATUS;
@@ -424,9 +397,6 @@ public class ConversationListItemData {
ConversationListViewColumns.OTHER_PARTICIPANT_NORMALIZED_DESTINATION, ConversationListViewColumns.OTHER_PARTICIPANT_NORMALIZED_DESTINATION,
ConversationListViewColumns.PARTICIPANT_COUNT, ConversationListViewColumns.PARTICIPANT_COUNT,
ConversationListViewColumns.CURRENT_SELF_ID, ConversationListViewColumns.CURRENT_SELF_ID,
ConversationListViewColumns.NOTIFICATION_ENABLED,
ConversationListViewColumns.NOTIFICATION_SOUND_URI,
ConversationListViewColumns.NOTIFICATION_VIBRATION,
ConversationListViewColumns.INCLUDE_EMAIL_ADDRESS, ConversationListViewColumns.INCLUDE_EMAIL_ADDRESS,
ConversationListViewColumns.MESSAGE_STATUS, ConversationListViewColumns.MESSAGE_STATUS,
ConversationListViewColumns.SHOW_DRAFT, 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_OTHER_PARTICIPANT_NORMALIZED_DESTINATION = 10;
private static final int INDEX_PARTICIPANT_COUNT = 11; private static final int INDEX_PARTICIPANT_COUNT = 11;
private static final int INDEX_SELF_ID = 12; private static final int INDEX_SELF_ID = 12;
private static final int INDEX_NOTIFICATION_ENABLED = 13; private static final int INDEX_INCLUDE_EMAIL_ADDRESS = 13;
private static final int INDEX_NOTIFICATION_SOUND_URI = 14; private static final int INDEX_MESSAGE_STATUS = 14;
private static final int INDEX_NOTIFICATION_VIBRATION = 15; private static final int INDEX_SHOW_DRAFT = 15;
private static final int INDEX_INCLUDE_EMAIL_ADDRESS = 16; private static final int INDEX_DRAFT_PREVIEW_URI = 16;
private static final int INDEX_MESSAGE_STATUS = 17; private static final int INDEX_DRAFT_PREVIEW_CONTENT_TYPE = 17;
private static final int INDEX_SHOW_DRAFT = 18; private static final int INDEX_DRAFT_SNIPPET_TEXT = 18;
private static final int INDEX_DRAFT_PREVIEW_URI = 19; private static final int INDEX_ARCHIVE_STATUS = 19;
private static final int INDEX_DRAFT_PREVIEW_CONTENT_TYPE = 20; private static final int INDEX_MESSAGE_ID = 20;
private static final int INDEX_DRAFT_SNIPPET_TEXT = 21; private static final int INDEX_SUBJECT_TEXT = 21;
private static final int INDEX_ARCHIVE_STATUS = 22; private static final int INDEX_DRAFT_SUBJECT_TEXT = 22;
private static final int INDEX_MESSAGE_ID = 23; private static final int INDEX_MESSAGE_RAW_TELEPHONY_STATUS = 23;
private static final int INDEX_SUBJECT_TEXT = 24; private static final int INDEX_SNIPPET_SENDER_FIRST_NAME = 24;
private static final int INDEX_DRAFT_SUBJECT_TEXT = 25; private static final int INDEX_SNIPPET_SENDER_DISPLAY_DESTINATION = 25;
private static final int INDEX_MESSAGE_RAW_TELEPHONY_STATUS = 26; private static final int INDEX_IS_ENTERPRISE = 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 String DIVIDER_TEXT = ", "; 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.BoundCursorLoader;
import com.android.messaging.datamodel.MessagingContentProvider; import com.android.messaging.datamodel.MessagingContentProvider;
import com.android.messaging.datamodel.action.BugleActionToasts; 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.action.UpdateDestinationBlockedAction;
import com.android.messaging.datamodel.binding.BindableData; import com.android.messaging.datamodel.binding.BindableData;
import com.android.messaging.datamodel.binding.BindingBase; import com.android.messaging.datamodel.binding.BindingBase;
@@ -74,7 +73,7 @@ public class PeopleAndOptionsData extends BindableData implements
final Uri uri = final Uri uri =
MessagingContentProvider.buildConversationMetadataUri(mConversationId); MessagingContentProvider.buildConversationMetadataUri(mConversationId);
return new BoundCursorLoader(bindingId, mContext, uri, return new BoundCursorLoader(bindingId, mContext, uri,
PeopleOptionsItemData.PROJECTION, null, null, null); new String[]{}, null, null, null);
} }
case PARTICIPANT_LOADER: { 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, public void setDestinationBlocked(final BindingBase<PeopleAndOptionsData> binding,
final boolean blocked) { final boolean blocked) {
final String bindingId = binding.getBindingId(); final String bindingId = binding.getBindingId();
@@ -207,4 +179,8 @@ public class PeopleAndOptionsData extends BindableData implements
BugleActionToasts.makeUpdateDestinationBlockedActionListener(mContext)); BugleActionToasts.makeUpdateDestinationBlockedActionListener(mContext));
} }
} }
public String getConversationId() {
return mConversationId;
}
} }
@@ -17,44 +17,19 @@ package com.android.messaging.datamodel.data;
import android.content.Context; import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri; import android.net.Uri;
import com.android.messaging.R; import com.android.messaging.R;
import com.android.messaging.datamodel.data.ConversationListItemData.ConversationListViewColumns; import com.android.messaging.datamodel.data.ConversationListItemData.ConversationListViewColumns;
import com.android.messaging.util.Assert; import com.android.messaging.util.Assert;
import com.android.messaging.util.RingtoneUtil;
public class PeopleOptionsItemData { 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. // 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 = 0;
public static final int SETTING_NOTIFICATION_SOUND_URI = 1; public static final int SETTING_BLOCKED = 1;
public static final int SETTING_NOTIFICATION_VIBRATION = 2; public static final int SETTINGS_COUNT = 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;
private String mTitle; private String mTitle;
private String mSubtitle;
private Uri mRingtoneUri;
private boolean mCheckable;
private boolean mChecked;
private boolean mEnabled;
private int mItemId; private int mItemId;
private ParticipantData mOtherParticipant; private ParticipantData mOtherParticipant;
@@ -71,41 +46,12 @@ public class PeopleOptionsItemData {
*/ */
public void bind( public void bind(
final Cursor cursor, final ParticipantData otherParticipant, final int settingType) { final Cursor cursor, final ParticipantData otherParticipant, final int settingType) {
mSubtitle = null;
mRingtoneUri = null;
mCheckable = true;
mEnabled = true;
mItemId = settingType; mItemId = settingType;
mOtherParticipant = otherParticipant; mOtherParticipant = otherParticipant;
final boolean notificationEnabled = cursor.getInt(INDEX_NOTIFICATION_ENABLED) == 1;
switch (settingType) { switch (settingType) {
case SETTING_NOTIFICATION_ENABLED: case SETTING_NOTIFICATION:
mTitle = mContext.getString(R.string.notifications_enabled_conversation_pref_title); 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; break;
case SETTING_BLOCKED: case SETTING_BLOCKED:
@@ -113,7 +59,6 @@ public class PeopleOptionsItemData {
final int resourceId = otherParticipant.isBlocked() ? final int resourceId = otherParticipant.isBlocked() ?
R.string.unblock_contact_title : R.string.block_contact_title; R.string.unblock_contact_title : R.string.block_contact_title;
mTitle = mContext.getString(resourceId, otherParticipant.getDisplayDestination()); mTitle = mContext.getString(resourceId, otherParticipant.getDisplayDestination());
mCheckable = false;
break; break;
default: default:
@@ -125,30 +70,10 @@ public class PeopleOptionsItemData {
return mTitle; 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() { public int getItemId() {
return mItemId; return mItemId;
} }
public Uri getRingtoneUri() {
return mRingtoneUri;
}
public ParticipantData getOtherParticipant() { public ParticipantData getOtherParticipant() {
return mOtherParticipant; return mOtherParticipant;
} }
@@ -252,11 +252,6 @@ public final class SmsReceiver extends BroadcastReceiver {
protected Style build(Builder builder) { protected Style build(Builder builder) {
return null; return null;
} }
@Override
public boolean getNotificationVibrate() {
return true;
}
} }
public static void postNewMessageSecondaryUserNotification() { public static void postNewMessageSecondaryUserNotification() {
@@ -282,10 +277,7 @@ public final class SmsReceiver extends BroadcastReceiver {
final NotificationManagerCompat notificationManager = final NotificationManagerCompat notificationManager =
NotificationManagerCompat.from(Factory.get().getApplicationContext()); NotificationManagerCompat.from(Factory.get().getApplicationContext());
int defaults = Notification.DEFAULT_LIGHTS; int defaults = Notification.DEFAULT_LIGHTS | Notification.DEFAULT_VIBRATE;
if (BugleNotifications.shouldVibrate(new SecondaryUserNotificationState())) {
defaults |= Notification.DEFAULT_VIBRATE;
}
notification.defaults = defaults; notification.defaults = defaults;
notificationManager.notify(getNotificationTag(), notificationManager.notify(getNotificationTag(),
@@ -264,16 +264,6 @@ public abstract class UIIntents {
*/ */
public abstract Intent getViewUrlIntent(final String url); public abstract Intent getViewUrlIntent(final String url);
/**
* Get an intent to launch the ringtone picker
* @param title the title to show in the ringtone picker
* @param existingUri the currently set uri
* @param defaultUri the default uri if none is currently set
* @param toneType type of ringtone to pick, maybe any of RingtoneManager.TYPE_*
*/
public abstract Intent getRingtonePickerIntent(final String title, final Uri existingUri,
final Uri defaultUri, final int toneType);
/** /**
* Get an intent to launch the wireless alert viewer. * Get an intent to launch the wireless alert viewer.
*/ */
@@ -27,7 +27,6 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.graphics.Point; import android.graphics.Point;
import android.graphics.Rect; import android.graphics.Rect;
import android.media.RingtoneManager;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.provider.ContactsContract.Contacts; import android.provider.ContactsContract.Contacts;
@@ -450,16 +449,6 @@ public class UIIntentsImpl extends UIIntents {
return resultPendingIntent; return resultPendingIntent;
} }
@Override
public Intent getRingtonePickerIntent(final String title, final Uri existingUri,
final Uri defaultUri, final int toneType) {
return new Intent(RingtoneManager.ACTION_RINGTONE_PICKER)
.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, toneType)
.putExtra(RingtoneManager.EXTRA_RINGTONE_TITLE, title)
.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, existingUri)
.putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI, defaultUri);
}
@Override @Override
public PendingIntent getPendingIntentForLowStorageNotifications(final Context context) { public PendingIntent getPendingIntentForLowStorageNotifications(final Context context) {
final TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(context); final TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(context);
@@ -18,18 +18,12 @@ package com.android.messaging.ui.appsettings;
import android.app.FragmentTransaction; import android.app.FragmentTransaction;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.preference.Preference; import android.preference.Preference;
import android.preference.PreferenceFragment; import android.preference.PreferenceFragment;
import android.preference.PreferenceScreen; import android.preference.PreferenceScreen;
import android.preference.RingtonePreference;
import android.preference.SwitchPreference; import android.preference.SwitchPreference;
import android.preference.TwoStatePreference;
import android.provider.Settings; import android.provider.Settings;
import androidx.core.app.NavUtils; import androidx.core.app.NavUtils;
import android.text.TextUtils; import android.text.TextUtils;
@@ -85,14 +79,10 @@ public class ApplicationSettingsActivity extends BugleActionBarActivity {
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
public static class ApplicationSettingsFragment extends PreferenceFragment implements public static class ApplicationSettingsFragment extends PreferenceFragment {
OnSharedPreferenceChangeListener {
private String mNotificationsEnabledPreferenceKey; private String mNotificationsPreferenceKey;
private TwoStatePreference mNotificationsEnabledPreference; private Preference mNotificationsPreference;
private String mRingtonePreferenceKey;
private RingtonePreference mRingtonePreference;
private Preference mVibratePreference;
private String mSmsDisabledPrefKey; private String mSmsDisabledPrefKey;
private Preference mSmsDisabledPreference; private Preference mSmsDisabledPreference;
private String mSmsEnabledPrefKey; private String mSmsEnabledPrefKey;
@@ -112,14 +102,9 @@ public class ApplicationSettingsActivity extends BugleActionBarActivity {
getPreferenceManager().setSharedPreferencesName(BuglePrefs.SHARED_PREFERENCES_NAME); getPreferenceManager().setSharedPreferencesName(BuglePrefs.SHARED_PREFERENCES_NAME);
addPreferencesFromResource(R.xml.preferences_application); addPreferencesFromResource(R.xml.preferences_application);
mNotificationsEnabledPreferenceKey = mNotificationsPreferenceKey =
getString(R.string.notifications_enabled_pref_key); getString(R.string.notifications_pref_key);
mNotificationsEnabledPreference = (TwoStatePreference) findPreference( mNotificationsPreference = findPreference(mNotificationsPreferenceKey);
mNotificationsEnabledPreferenceKey);
mRingtonePreferenceKey = getString(R.string.notification_sound_pref_key);
mRingtonePreference = (RingtonePreference) findPreference(mRingtonePreferenceKey);
mVibratePreference = findPreference(
getString(R.string.notification_vibration_pref_key));
mSmsDisabledPrefKey = getString(R.string.sms_disabled_pref_key); mSmsDisabledPrefKey = getString(R.string.sms_disabled_pref_key);
mSmsDisabledPreference = findPreference(mSmsDisabledPrefKey); mSmsDisabledPreference = findPreference(mSmsDisabledPrefKey);
mSmsEnabledPrefKey = getString(R.string.sms_enabled_pref_key); mSmsEnabledPrefKey = getString(R.string.sms_enabled_pref_key);
@@ -130,9 +115,6 @@ public class ApplicationSettingsActivity extends BugleActionBarActivity {
(SwitchPreference) findPreference(mSwipeRightToDeleteConversationkey); (SwitchPreference) findPreference(mSwipeRightToDeleteConversationkey);
mIsSmsPreferenceClicked = false; mIsSmsPreferenceClicked = false;
final SharedPreferences prefs = getPreferenceScreen().getSharedPreferences();
updateSoundSummary(prefs);
if (!DebugUtils.isDebugEnabled()) { if (!DebugUtils.isDebugEnabled()) {
final Preference debugCategory = findPreference(getString( final Preference debugCategory = findPreference(getString(
R.string.debug_pref_key)); R.string.debug_pref_key));
@@ -154,8 +136,13 @@ public class ApplicationSettingsActivity extends BugleActionBarActivity {
} }
@Override @Override
public boolean onPreferenceTreeClick (PreferenceScreen preferenceScreen, public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
Preference preference) { Preference preference) {
if (preference.getKey() == mNotificationsPreferenceKey) {
Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
intent.putExtra(Settings.EXTRA_APP_PACKAGE, getContext().getPackageName());
startActivity(intent);
}
if (preference.getKey() == mSmsDisabledPrefKey || if (preference.getKey() == mSmsDisabledPrefKey ||
preference.getKey() == mSmsEnabledPrefKey) { preference.getKey() == mSmsEnabledPrefKey) {
mIsSmsPreferenceClicked = true; mIsSmsPreferenceClicked = true;
@@ -163,35 +150,6 @@ public class ApplicationSettingsActivity extends BugleActionBarActivity {
return super.onPreferenceTreeClick(preferenceScreen, preference); return super.onPreferenceTreeClick(preferenceScreen, preference);
} }
private void updateSoundSummary(final SharedPreferences sharedPreferences) {
// The silent ringtone just returns an empty string
String ringtoneName = mRingtonePreference.getContext().getString(
R.string.silent_ringtone);
String ringtoneString = sharedPreferences.getString(mRingtonePreferenceKey, null);
// Bootstrap the default setting in the preferences so that we have a valid selection
// in the dialog the first time that the user opens it.
if (ringtoneString == null) {
ringtoneString = Settings.System.DEFAULT_NOTIFICATION_URI.toString();
final SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(mRingtonePreferenceKey, ringtoneString);
editor.apply();
}
if (!TextUtils.isEmpty(ringtoneString)) {
final Uri ringtoneUri = Uri.parse(ringtoneString);
final Ringtone tone = RingtoneManager.getRingtone(mRingtonePreference.getContext(),
ringtoneUri);
if (tone != null) {
ringtoneName = tone.getTitle(mRingtonePreference.getContext());
}
}
mRingtonePreference.setSummary(ringtoneName);
}
private void updateSmsEnabledPreferences() { private void updateSmsEnabledPreferences() {
if (!OsUtil.isAtLeastKLP()) { if (!OsUtil.isAtLeastKLP()) {
getPreferenceScreen().removePreference(mSmsDisabledPreference); getPreferenceScreen().removePreference(mSmsDisabledPreference);
@@ -222,48 +180,14 @@ public class ApplicationSettingsActivity extends BugleActionBarActivity {
getPreferenceScreen().removePreference(mSmsEnabledPreference); getPreferenceScreen().removePreference(mSmsEnabledPreference);
mSmsDisabledPreference.setSummary(defaultSmsAppLabel); mSmsDisabledPreference.setSummary(defaultSmsAppLabel);
} }
updateNotificationsPreferences();
} }
mIsSmsPreferenceClicked = false; mIsSmsPreferenceClicked = false;
} }
private void updateNotificationsPreferences() {
final boolean canNotify = !OsUtil.isAtLeastKLP()
|| PhoneUtils.getDefault().isDefaultSmsApp();
mNotificationsEnabledPreference.setEnabled(canNotify);
}
@Override
public void onStart() {
super.onStart();
// We do this on start rather than on resume because the sound picker is in a
// separate activity.
getPreferenceScreen().getSharedPreferences()
.registerOnSharedPreferenceChangeListener(this);
}
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
updateSmsEnabledPreferences(); updateSmsEnabledPreferences();
updateNotificationsPreferences();
}
@Override
public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences,
final String key) {
if (key.equals(mNotificationsEnabledPreferenceKey)) {
updateNotificationsPreferences();
} else if (key.equals(mRingtonePreferenceKey)) {
updateSoundSummary(sharedPreferences);
}
}
@Override
public void onStop() {
super.onStop();
getPreferenceScreen().getSharedPreferences()
.unregisterOnSharedPreferenceChangeListener(this);
} }
} }
} }
@@ -30,7 +30,6 @@ import android.view.View;
import com.android.messaging.R; import com.android.messaging.R;
import com.android.messaging.datamodel.action.DeleteConversationAction; import com.android.messaging.datamodel.action.DeleteConversationAction;
import com.android.messaging.datamodel.action.UpdateConversationArchiveStatusAction; import com.android.messaging.datamodel.action.UpdateConversationArchiveStatusAction;
import com.android.messaging.datamodel.action.UpdateConversationOptionsAction;
import com.android.messaging.datamodel.action.UpdateDestinationBlockedAction; import com.android.messaging.datamodel.action.UpdateDestinationBlockedAction;
import com.android.messaging.datamodel.data.ConversationListData; import com.android.messaging.datamodel.data.ConversationListData;
import com.android.messaging.datamodel.data.ConversationListItemData; import com.android.messaging.datamodel.data.ConversationListItemData;
@@ -190,23 +189,6 @@ public abstract class AbstractConversationListActivity extends BugleActionBarAc
exitMultiSelectState(); exitMultiSelectState();
} }
@Override
public void onActionBarNotification(final Iterable<SelectedConversation> conversations,
final boolean isNotificationOn) {
for (final SelectedConversation conversation : conversations) {
UpdateConversationOptionsAction.enableConversationNotifications(
conversation.conversationId, isNotificationOn);
}
final int textId = isNotificationOn ?
R.string.notification_on_toast_message : R.string.notification_off_toast_message;
final String message = getResources().getString(textId, 1);
UiUtils.showSnackBar(this, findViewById(android.R.id.list), message,
null /* undoRunnable */,
SnackBar.Action.SNACK_BAR_UNDO, mConversationListFragment.getSnackBarInteractions());
exitMultiSelectState();
}
@Override @Override
public void onActionBarAddContact(final SelectedConversation conversation) { public void onActionBarAddContact(final SelectedConversation conversation) {
final Uri avatarUri; final Uri avatarUri;
@@ -127,7 +127,6 @@ public class ConversationListItemView extends FrameLayout implements OnClickList
private TextView mTimestampTextView; private TextView mTimestampTextView;
private ContactIconView mContactIconView; private ContactIconView mContactIconView;
private ImageView mContactCheckmarkView; private ImageView mContactCheckmarkView;
private ImageView mNotificationBellView;
private ImageView mFailedStatusIconView; private ImageView mFailedStatusIconView;
private ImageView mCrossSwipeArchiveLeftImageView; private ImageView mCrossSwipeArchiveLeftImageView;
private ImageView mCrossSwipeArchiveRightImageView; private ImageView mCrossSwipeArchiveRightImageView;
@@ -153,7 +152,6 @@ public class ConversationListItemView extends FrameLayout implements OnClickList
mTimestampTextView = (TextView) findViewById(R.id.conversation_timestamp); mTimestampTextView = (TextView) findViewById(R.id.conversation_timestamp);
mContactIconView = (ContactIconView) findViewById(R.id.conversation_icon); mContactIconView = (ContactIconView) findViewById(R.id.conversation_icon);
mContactCheckmarkView = (ImageView) findViewById(R.id.conversation_checkmark); mContactCheckmarkView = (ImageView) findViewById(R.id.conversation_checkmark);
mNotificationBellView = (ImageView) findViewById(R.id.conversation_notification_bell);
mFailedStatusIconView = (ImageView) findViewById(R.id.conversation_failed_status_icon); mFailedStatusIconView = (ImageView) findViewById(R.id.conversation_failed_status_icon);
mCrossSwipeArchiveLeftImageView = (ImageView) findViewById(R.id.crossSwipeArchiveIconLeft); mCrossSwipeArchiveLeftImageView = (ImageView) findViewById(R.id.crossSwipeArchiveIconLeft);
mCrossSwipeArchiveRightImageView = mCrossSwipeArchiveRightImageView =
@@ -503,9 +501,6 @@ public class ConversationListItemView extends FrameLayout implements OnClickList
mAudioAttachmentView.setOnLongClickListener(this); mAudioAttachmentView.setOnLongClickListener(this);
mAudioAttachmentView.setVisibility(audioPreviewVisiblity); mAudioAttachmentView.setVisibility(audioPreviewVisiblity);
final int notificationBellVisiblity = mData.getNotificationEnabled() ? GONE : VISIBLE;
mNotificationBellView.setVisibility(notificationBellVisiblity);
if (PrefsUtils.isSwipeRightToDeleteEnabled()) { if (PrefsUtils.isSwipeRightToDeleteEnabled()) {
mCrossSwipeArchiveLeftImageView.setImageDrawable(getResources() mCrossSwipeArchiveLeftImageView.setImageDrawable(getResources()
.getDrawable(R.drawable.ic_delete_small_dark)); .getDrawable(R.drawable.ic_delete_small_dark));
@@ -37,8 +37,6 @@ public class MultiSelectActionModeCallback implements Callback {
void onActionBarDelete(Collection<SelectedConversation> conversations); void onActionBarDelete(Collection<SelectedConversation> conversations);
void onActionBarArchive(Iterable<SelectedConversation> conversations, void onActionBarArchive(Iterable<SelectedConversation> conversations,
boolean isToArchive); boolean isToArchive);
void onActionBarNotification(Iterable<SelectedConversation> conversations,
boolean isNotificationOn);
void onActionBarAddContact(final SelectedConversation conversation); void onActionBarAddContact(final SelectedConversation conversation);
void onActionBarBlock(final SelectedConversation conversation); void onActionBarBlock(final SelectedConversation conversation);
void onActionBarHome(); void onActionBarHome();
@@ -52,7 +50,6 @@ public class MultiSelectActionModeCallback implements Callback {
public final CharSequence participantLookupKey; public final CharSequence participantLookupKey;
public final boolean isGroup; public final boolean isGroup;
public final boolean isArchived; public final boolean isArchived;
public final boolean notificationEnabled;
public SelectedConversation(ConversationListItemData data) { public SelectedConversation(ConversationListItemData data) {
conversationId = data.getConversationId(); conversationId = data.getConversationId();
timestamp = data.getTimestamp(); timestamp = data.getTimestamp();
@@ -61,7 +58,6 @@ public class MultiSelectActionModeCallback implements Callback {
participantLookupKey = data.getParticipantLookupKey(); participantLookupKey = data.getParticipantLookupKey();
isGroup = data.getIsGroup(); isGroup = data.getIsGroup();
isArchived = data.getIsArchived(); isArchived = data.getIsArchived();
notificationEnabled = data.getNotificationEnabled();
} }
} }
@@ -72,8 +68,6 @@ public class MultiSelectActionModeCallback implements Callback {
private MenuItem mUnarchiveMenuItem; private MenuItem mUnarchiveMenuItem;
private MenuItem mAddContactMenuItem; private MenuItem mAddContactMenuItem;
private MenuItem mBlockMenuItem; private MenuItem mBlockMenuItem;
private MenuItem mNotificationOnMenuItem;
private MenuItem mNotificationOffMenuItem;
private boolean mHasInflated; private boolean mHasInflated;
public MultiSelectActionModeCallback(final Listener listener) { public MultiSelectActionModeCallback(final Listener listener) {
@@ -89,8 +83,6 @@ public class MultiSelectActionModeCallback implements Callback {
mUnarchiveMenuItem = menu.findItem(R.id.action_unarchive); mUnarchiveMenuItem = menu.findItem(R.id.action_unarchive);
mAddContactMenuItem = menu.findItem(R.id.action_add_contact); mAddContactMenuItem = menu.findItem(R.id.action_add_contact);
mBlockMenuItem = menu.findItem(R.id.action_block); mBlockMenuItem = menu.findItem(R.id.action_block);
mNotificationOffMenuItem = menu.findItem(R.id.action_notification_off);
mNotificationOnMenuItem = menu.findItem(R.id.action_notification_on);
mHasInflated = true; mHasInflated = true;
updateActionIconsVisiblity(); updateActionIconsVisiblity();
return true; return true;
@@ -113,12 +105,6 @@ public class MultiSelectActionModeCallback implements Callback {
case R.id.action_unarchive: case R.id.action_unarchive:
mListener.onActionBarArchive(mSelectedConversations.values(), false); mListener.onActionBarArchive(mSelectedConversations.values(), false);
return true; return true;
case R.id.action_notification_off:
mListener.onActionBarNotification(mSelectedConversations.values(), false);
return true;
case R.id.action_notification_on:
mListener.onActionBarNotification(mSelectedConversations.values(), true);
return true;
case R.id.action_add_contact: case R.id.action_add_contact:
Assert.isTrue(mSelectedConversations.size() == 1); Assert.isTrue(mSelectedConversations.size() == 1);
mListener.onActionBarAddContact(mSelectedConversations.valueAt(0)); mListener.onActionBarAddContact(mSelectedConversations.valueAt(0));
@@ -186,16 +172,8 @@ public class MultiSelectActionModeCallback implements Callback {
boolean hasCurrentlyArchived = false; boolean hasCurrentlyArchived = false;
boolean hasCurrentlyUnarchived = false; boolean hasCurrentlyUnarchived = false;
boolean hasCurrentlyOnNotification = false;
boolean hasCurrentlyOffNotification = false;
final Iterable<SelectedConversation> conversations = mSelectedConversations.values(); final Iterable<SelectedConversation> conversations = mSelectedConversations.values();
for (final SelectedConversation conversation : conversations) { for (final SelectedConversation conversation : conversations) {
if (conversation.notificationEnabled) {
hasCurrentlyOnNotification = true;
} else {
hasCurrentlyOffNotification = true;
}
if (conversation.isArchived) { if (conversation.isArchived) {
hasCurrentlyArchived = true; hasCurrentlyArchived = true;
} else { } else {
@@ -203,15 +181,10 @@ public class MultiSelectActionModeCallback implements Callback {
} }
// If we found at least one of each example we don't need to keep looping. // If we found at least one of each example we don't need to keep looping.
if (hasCurrentlyOffNotification && hasCurrentlyOnNotification && if (hasCurrentlyArchived && hasCurrentlyUnarchived) {
hasCurrentlyArchived && hasCurrentlyUnarchived) {
break; break;
} }
} }
// If we have notification off conversations we show on button, if we have notification on
// conversation we show off button. We can show both if we have a mixture.
mNotificationOffMenuItem.setVisible(hasCurrentlyOnNotification);
mNotificationOnMenuItem.setVisible(hasCurrentlyOffNotification);
mArchiveMenuItem.setVisible(hasCurrentlyUnarchived); mArchiveMenuItem.setVisible(hasCurrentlyUnarchived);
mUnarchiveMenuItem.setVisible(hasCurrentlyArchived); mUnarchiveMenuItem.setVisible(hasCurrentlyArchived);
@@ -18,12 +18,12 @@ package com.android.messaging.ui.conversationsettings;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Fragment; import android.app.Fragment;
import android.app.NotificationManager;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.res.Resources; import android.content.res.Resources;
import android.database.Cursor; import android.database.Cursor;
import android.media.RingtoneManager;
import android.os.Bundle; import android.os.Bundle;
import android.os.Parcelable; import android.os.Parcelable;
import android.provider.Settings; import android.provider.Settings;
@@ -49,6 +49,7 @@ import com.android.messaging.ui.CompositeAdapter;
import com.android.messaging.ui.PersonItemView; import com.android.messaging.ui.PersonItemView;
import com.android.messaging.ui.UIIntents; import com.android.messaging.ui.UIIntents;
import com.android.messaging.ui.conversation.ConversationActivity; import com.android.messaging.ui.conversation.ConversationActivity;
import com.android.messaging.util.NotificationsUtil;
import com.android.messaging.util.Assert; import com.android.messaging.util.Assert;
import java.util.ArrayList; import java.util.ArrayList;
@@ -62,11 +63,10 @@ public class PeopleAndOptionsFragment extends Fragment
private ListView mListView; private ListView mListView;
private OptionsListAdapter mOptionsListAdapter; private OptionsListAdapter mOptionsListAdapter;
private PeopleListAdapter mPeopleListAdapter; private PeopleListAdapter mPeopleListAdapter;
private List<ParticipantData> mOtherParticipants;
private final Binding<PeopleAndOptionsData> mBinding = private final Binding<PeopleAndOptionsData> mBinding =
BindingBase.createBinding(this); BindingBase.createBinding(this);
private static final int REQUEST_CODE_RINGTONE_PICKER = 1000;
@Override @Override
public void onCreate(final Bundle savedInstanceState) { public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@@ -89,17 +89,6 @@ public class PeopleAndOptionsFragment extends Fragment
return view; return view;
} }
@Override
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK && requestCode == REQUEST_CODE_RINGTONE_PICKER) {
final Parcelable pick = data.getParcelableExtra(
RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
final String pickedUri = pick == null ? "" : pick.toString();
mBinding.getData().setConversationNotificationSound(mBinding, pickedUri);
}
}
@Override @Override
public void onDestroy() { public void onDestroy() {
super.onDestroy(); super.onDestroy();
@@ -125,30 +114,31 @@ public class PeopleAndOptionsFragment extends Fragment
final List<ParticipantData> participants) { final List<ParticipantData> participants) {
mBinding.ensureBound(data); mBinding.ensureBound(data);
mPeopleListAdapter.updateParticipants(participants); mPeopleListAdapter.updateParticipants(participants);
mOtherParticipants = participants;
final ParticipantData otherParticipant = participants.size() == 1 ? final ParticipantData otherParticipant = participants.size() == 1 ?
participants.get(0) : null; participants.get(0) : null;
mOptionsListAdapter.setOtherParticipant(otherParticipant); mOptionsListAdapter.setOtherParticipant(otherParticipant);
} }
@Override @Override
public void onOptionsItemViewClicked(final PeopleOptionsItemData item, public void onOptionsItemViewClicked(final PeopleOptionsItemData item) {
final boolean isChecked) {
switch (item.getItemId()) { switch (item.getItemId()) {
case PeopleOptionsItemData.SETTING_NOTIFICATION_ENABLED: case PeopleOptionsItemData.SETTING_NOTIFICATION:
mBinding.getData().enableConversationNotifications(mBinding, isChecked); ArrayList<String> participantsNames = new ArrayList<String>();
break; for (ParticipantData participant : mOtherParticipants) {
participantsNames.add(participant.getDisplayName(true));
case PeopleOptionsItemData.SETTING_NOTIFICATION_SOUND_URI: }
final Intent ringtonePickerIntent = UIIntents.get().getRingtonePickerIntent( NotificationsUtil.createNotificationChannelGroup(getActivity(),
getString(R.string.notification_sound_pref_title), NotificationsUtil.CONVERSATION_GROUP_NAME,
item.getRingtoneUri(), Settings.System.DEFAULT_NOTIFICATION_URI, R.string.notification_channel_messages_title);
RingtoneManager.TYPE_NOTIFICATION); NotificationsUtil.createNotificationChannel(getActivity(),
startActivityForResult(ringtonePickerIntent, REQUEST_CODE_RINGTONE_PICKER); mBinding.getData().getConversationId(),
break; String.join(", ", participantsNames),
NotificationManager.IMPORTANCE_DEFAULT,
case PeopleOptionsItemData.SETTING_NOTIFICATION_VIBRATION: NotificationsUtil.CONVERSATION_GROUP_NAME);
mBinding.getData().enableConversationNotificationVibration(mBinding, Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
isChecked); intent.putExtra(Settings.EXTRA_APP_PACKAGE, getContext().getPackageName());
startActivity(intent);
break; break;
case PeopleOptionsItemData.SETTING_BLOCKED: case PeopleOptionsItemData.SETTING_BLOCKED:
@@ -38,7 +38,7 @@ public class PeopleOptionsItemView extends LinearLayout {
* Implemented by the host of this view that handles options click event. * Implemented by the host of this view that handles options click event.
*/ */
public interface HostInterface { public interface HostInterface {
void onOptionsItemViewClicked(PeopleOptionsItemData item, boolean isChecked); void onOptionsItemViewClicked(PeopleOptionsItemData item);
} }
private TextView mTitle; private TextView mTitle;
@@ -55,12 +55,10 @@ public class PeopleOptionsItemView extends LinearLayout {
@Override @Override
protected void onFinishInflate () { protected void onFinishInflate () {
mTitle = (TextView) findViewById(R.id.title); mTitle = (TextView) findViewById(R.id.title);
mSubtitle = (TextView) findViewById(R.id.subtitle);
mSwitch = (SwitchCompat) findViewById(R.id.switch_button);
setOnClickListener(new OnClickListener() { setOnClickListener(new OnClickListener() {
@Override @Override
public void onClick(final View v) { public void onClick(final View v) {
mHostInterface.onOptionsItemViewClicked(mData, !mData.getChecked()); mHostInterface.onOptionsItemViewClicked(mData);
} }
}); });
} }
@@ -72,28 +70,5 @@ public class PeopleOptionsItemView extends LinearLayout {
mHostInterface = hostInterface; mHostInterface = hostInterface;
mTitle.setText(mData.getTitle()); mTitle.setText(mData.getTitle());
final String subtitle = mData.getSubtitle();
if (TextUtils.isEmpty(subtitle)) {
mSubtitle.setVisibility(GONE);
} else {
mSubtitle.setVisibility(VISIBLE);
mSubtitle.setText(subtitle);
}
if (mData.getCheckable()) {
mSwitch.setVisibility(VISIBLE);
mSwitch.setChecked(mData.getChecked());
} else {
mSwitch.setVisibility(GONE);
}
final boolean enabled = mData.getEnabled();
if (enabled != isEnabled()) {
mTitle.setEnabled(enabled);
mSubtitle.setEnabled(enabled);
mSwitch.setEnabled(enabled);
setAlpha(enabled ? 1.0f : 0.5f);
setEnabled(enabled);
}
} }
} }
@@ -0,0 +1,101 @@
/*
* Copyright (C) 2019 The LineageOS 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.util;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
import android.app.NotificationManager;
import android.content.Context;
import android.os.Build;
public final class NotificationsUtil {
public static final String DEFAULT_CHANNEL_ID = "messaging_channel";
public static final String CONVERSATION_GROUP_NAME = "conversation_group";
private NotificationsUtil() {
}
public static void createNotificationChannel(Context context, String id,
int titleResId, int priority, String groupId) {
String title = context.getString(titleResId);
createNotificationChannel(context, id, title, priority, groupId);
}
public static void createNotificationChannel(Context context, String id,
String title, int priority, String groupId) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
return;
}
NotificationManager manager = context.getSystemService(NotificationManager.class);
NotificationChannel existing = manager.getNotificationChannel(id);
if (existing != null) {
return;
}
NotificationChannel newChannel = new NotificationChannel(id, title, priority);
newChannel.enableLights(true);
if (groupId != null) {
newChannel.setGroup(groupId);
}
manager.createNotificationChannel(newChannel);
}
public static void deleteNotificationChannel(Context context, String id) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
return;
}
NotificationManager manager = context.getSystemService(NotificationManager.class);
manager.deleteNotificationChannel(id);
}
public static void createNotificationChannelGroup(Context context, String id,
int titleResId) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
return;
}
NotificationManager manager = context.getSystemService(NotificationManager.class);
NotificationChannelGroup existing = manager.getNotificationChannelGroup(id);
if (existing != null) {
return;
}
String title = context.getString(titleResId);
NotificationChannelGroup newChannelGroup = new NotificationChannelGroup(id, title);
manager.createNotificationChannelGroup(newChannelGroup);
}
public static NotificationChannel getNotificationChannel(Context context, String id) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
return null;
}
NotificationManager manager = context.getSystemService(NotificationManager.class);
return manager.getNotificationChannel(id);
}
public static NotificationChannelGroup getNotificationChannelGroup(Context context, String id) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
return null;
}
NotificationManager manager = context.getSystemService(NotificationManager.class);
return manager.getNotificationChannelGroup(id);
}
}
@@ -1,53 +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.util;
import android.content.Context;
import android.net.Uri;
import android.provider.Settings;
import android.text.TextUtils;
import com.android.messaging.Factory;
import com.android.messaging.R;
public class RingtoneUtil {
/**
* Return a ringtone Uri for the string representation passed in. Use the app
* and system defaults as fallbacks
* @param ringtoneString is the ringtone to resolve
* @return the Uri of the ringtone or the fallback ringtone
*/
public static Uri getNotificationRingtoneUri(String ringtoneString) {
if (ringtoneString == null) {
// No override specified, fall back to system-wide setting.
final BuglePrefs prefs = BuglePrefs.getApplicationPrefs();
final Context context = Factory.get().getApplicationContext();
final String prefKey = context.getString(R.string.notification_sound_pref_key);
ringtoneString = prefs.getString(prefKey, null);
}
if (!TextUtils.isEmpty(ringtoneString)) {
// We have set a value, even if it is the default Uri at some point
return Uri.parse(ringtoneString);
} else if (ringtoneString == null) {
// We have no setting specified (== null), so we default to the system default
return Settings.System.DEFAULT_NOTIFICATION_URI;
} else {
// An empty string (== "") here is the result of selecting "None" as the ringtone
return null;
}
}
}
@@ -120,10 +120,6 @@ public class WidgetConversationListService extends RemoteViewsService {
remoteViews.setTextViewText(R.id.from, remoteViews.setTextViewText(R.id.from,
boldifyIfUnread(conv.getName(), hasUnreadMessages)); boldifyIfUnread(conv.getName(), hasUnreadMessages));
// Notifications turned off mini-bell icon
remoteViews.setViewVisibility(R.id.conversation_notification_bell,
conv.getNotificationEnabled() ? View.GONE : View.VISIBLE);
// On click intent. // On click intent.
final Intent intent = UIIntents.get().getIntentForConversationActivity(mContext, final Intent intent = UIIntents.get().getIntentForConversationActivity(mContext,
conv.getConversationId(), null /* draft */); conv.getConversationId(), null /* draft */);
+1 -1
View File
@@ -17,7 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.messaging.test" > package="com.android.messaging.test" >
<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="24"/> <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="28"/>
<application android:label="Messaging Tests" > <application android:label="Messaging Tests" >
<uses-library android:name="android.test.runner" /> <uses-library android:name="android.test.runner" />
@@ -113,7 +113,7 @@ public class ReadWriteDraftMessageActionTest extends BugleTestCase {
participants.add(ParticipantData.getFromRawPhoneBySystemLocale(participantNumber)); participants.add(ParticipantData.getFromRawPhoneBySystemLocale(participantNumber));
final String conversationId = BugleDatabaseOperations.getOrCreateConversation(db, threadId, final String conversationId = BugleDatabaseOperations.getOrCreateConversation(db, threadId,
senderBlocked, participants, false, false, null); senderBlocked, participants);
assertNotNull("No conversation", conversationId); assertNotNull("No conversation", conversationId);
return conversationId; return conversationId;
} }
@@ -189,7 +189,7 @@ public class ReadWriteDraftMessageActionTest extends BugleTestCase {
participants.add(ParticipantData.getFromRawPhoneBySystemLocale(Long.toString(phoneNumber))); participants.add(ParticipantData.getFromRawPhoneBySystemLocale(Long.toString(phoneNumber)));
conversationId = BugleDatabaseOperations.getOrCreateConversation(db, threadId, conversationId = BugleDatabaseOperations.getOrCreateConversation(db, threadId,
senderBlocked, participants, false, false, null); senderBlocked, participants);
assertNotNull("No conversation", conversationId); assertNotNull("No conversation", conversationId);
final MessageData actual = BugleDatabaseOperations.readDraftMessageData(db, conversationId, final MessageData actual = BugleDatabaseOperations.readDraftMessageData(db, conversationId,