diff options
Diffstat (limited to 'java/com/android/dialer/notification/NotificationChannelManager.java')
-rw-r--r-- | java/com/android/dialer/notification/NotificationChannelManager.java | 141 |
1 files changed, 135 insertions, 6 deletions
diff --git a/java/com/android/dialer/notification/NotificationChannelManager.java b/java/com/android/dialer/notification/NotificationChannelManager.java index db7ded781..ef0f5f17a 100644 --- a/java/com/android/dialer/notification/NotificationChannelManager.java +++ b/java/com/android/dialer/notification/NotificationChannelManager.java @@ -16,15 +16,21 @@ package com.android.dialer.notification; +import android.annotation.TargetApi; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationChannelGroup; import android.app.NotificationManager; import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; import android.media.AudioAttributes; import android.net.Uri; +import android.os.Build.VERSION_CODES; +import android.provider.Settings; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.annotation.RequiresApi; import android.support.annotation.StringDef; import android.support.v4.os.BuildCompat; import android.telecom.PhoneAccount; @@ -34,12 +40,18 @@ import android.telephony.TelephonyManager; import com.android.contacts.common.compat.TelephonyManagerCompat; import com.android.dialer.buildtype.BuildType; import com.android.dialer.common.LogUtil; +import com.android.dialer.common.concurrent.DialerExecutors; +import com.android.dialer.telecom.TelecomUtil; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.List; +import java.util.Objects; /** Contains info on how to create {@link NotificationChannel NotificationChannels} */ public class NotificationChannelManager { + private static final String PREFS_FILENAME = "NotificationChannelManager"; + private static final String PREF_NEED_FIRST_INIT = "needFirstInit"; private static NotificationChannelManager instance; public static NotificationChannelManager getInstance() { @@ -53,9 +65,10 @@ public class NotificationChannelManager { * Set the channel of notification appropriately. Will create the channel if it does not already * exist. Safe to call pre-O (will no-op). * - * <p>phoneAccount should only be null if channelName is {@link Channel#MISC} or {@link + * <p>phoneAccount should only be null if channelName is {@link Channel#DEFAULT} or {@link * Channel#MISSED_CALL} since these do not have account-specific settings. */ + @TargetApi(26) public static void applyChannel( @NonNull Notification.Builder notification, @NonNull Context context, @@ -89,7 +102,7 @@ public class NotificationChannelManager { private static boolean channelAllowsNullPhoneAccountHandle(@Channel String channelName) { switch (channelName) { - case Channel.MISC: + case Channel.DEFAULT: case Channel.MISSED_CALL: return true; default: @@ -102,22 +115,122 @@ public class NotificationChannelManager { @StringDef({ Channel.INCOMING_CALL, Channel.ONGOING_CALL, + Channel.ONGOING_CALL_OLD, Channel.MISSED_CALL, Channel.VOICEMAIL, Channel.EXTERNAL_CALL, - Channel.MISC + Channel.DEFAULT }) public @interface Channel { + @Deprecated String ONGOING_CALL_OLD = "ongoingCall"; String INCOMING_CALL = "incomingCall"; - String ONGOING_CALL = "ongoingCall"; + String ONGOING_CALL = "ongoingCall2"; String MISSED_CALL = "missedCall"; String VOICEMAIL = "voicemail"; String EXTERNAL_CALL = "externalCall"; - String MISC = "miscellaneous"; + String DEFAULT = "default"; } + @Channel + private static final String[] prepopulatedAccountChannels = + new String[] {Channel.INCOMING_CALL, Channel.ONGOING_CALL, Channel.VOICEMAIL}; + + @Channel + private static final String[] prepopulatedGlobalChannels = + new String[] {Channel.MISSED_CALL, Channel.DEFAULT}; + private NotificationChannelManager() {} + public void firstInitIfNeeded(@NonNull Context context) { + if (BuildCompat.isAtLeastO()) { + DialerExecutors.createNonUiTaskBuilder(this::firstInitIfNeededSync) + .build() + .executeSerial(context); + } + } + + private boolean firstInitIfNeededSync(@NonNull Context context) { + if (needsFirstInit(context)) { + initChannels(context); + return true; + } + return false; + } + + public boolean needsFirstInit(@NonNull Context context) { + return (BuildCompat.isAtLeastO() + && getSharedPreferences(context).getBoolean(PREF_NEED_FIRST_INIT, true)); + } + + @RequiresApi(VERSION_CODES.N) + private SharedPreferences getSharedPreferences(@NonNull Context context) { + // Use device protected storage since in some cases this will need to be accessed while device + // is locked + context = context.createDeviceProtectedStorageContext(); + return context.getSharedPreferences(PREFS_FILENAME, Context.MODE_PRIVATE); + } + + @RequiresApi(26) + public Intent getSettingsIntentForChannel( + @NonNull Context context, @Channel String channelName, PhoneAccountHandle accountHandle) { + checkNullity(channelName, accountHandle); + Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS); + intent.putExtra( + Settings.EXTRA_CHANNEL_ID, getChannel(context, channelName, accountHandle).getId()); + intent.putExtra(Settings.EXTRA_APP_PACKAGE, context.getPackageName()); + return intent; + } + + @TargetApi(26) + @SuppressWarnings("AndroidApiChecker") + public void initChannels(@NonNull Context context) { + if (!BuildCompat.isAtLeastO()) { + return; + } + LogUtil.enterBlock("NotificationChannelManager.initChannels"); + List<PhoneAccountHandle> phoneAccounts = TelecomUtil.getCallCapablePhoneAccounts(context); + + // Remove notification channels for PhoneAccounts that don't exist anymore + NotificationManager notificationManager = context.getSystemService(NotificationManager.class); + List<NotificationChannelGroup> notificationChannelGroups = + notificationManager.getNotificationChannelGroups(); + notificationChannelGroups + .stream() + .filter(group -> !idExists(group.getId(), phoneAccounts)) + .forEach(group -> deleteGroup(notificationManager, group)); + + for (PhoneAccountHandle phoneAccountHandle : phoneAccounts) { + for (@Channel String channel : prepopulatedAccountChannels) { + getChannel(context, channel, phoneAccountHandle); + } + } + + for (@Channel String channel : prepopulatedGlobalChannels) { + getChannel(context, channel, null); + } + getSharedPreferences(context).edit().putBoolean(PREF_NEED_FIRST_INIT, false).apply(); + } + + @TargetApi(26) + private void deleteGroup( + @NonNull NotificationManager notificationManager, @NonNull NotificationChannelGroup group) { + for (NotificationChannel channel : group.getChannels()) { + notificationManager.deleteNotificationChannel(channel.getId()); + } + notificationManager.deleteNotificationChannelGroup(group.getId()); + } + + private boolean idExists(String id, List<PhoneAccountHandle> phoneAccountHandles) { + for (PhoneAccountHandle handle : phoneAccountHandles) { + if (Objects.equals(handle.getId(), id)) { + return true; + } + } + return false; + } + + @NonNull + @RequiresApi(26) private NotificationChannel getChannel( @NonNull Context context, @Channel String channelName, @@ -139,6 +252,7 @@ public class NotificationChannelManager { } } + @RequiresApi(26) private NotificationChannel createChannel( Context context, @Channel String channelName, @@ -191,6 +305,7 @@ public class NotificationChannelManager { lights = false; vibration = false; sound = silentRingtone; + deleteOldOngoingCallChannelIfNeeded(context, phoneAccountHandle); break; case Channel.VOICEMAIL: name = context.getText(R.string.notification_channel_voicemail); @@ -210,7 +325,7 @@ public class NotificationChannelManager { vibration = true; sound = null; break; - case Channel.MISC: + case Channel.DEFAULT: name = context.getText(R.string.notification_channel_misc); importance = NotificationManager.IMPORTANCE_DEFAULT; canShowBadge = false; @@ -235,6 +350,20 @@ public class NotificationChannelManager { return channel; } + @RequiresApi(26) + private void deleteOldOngoingCallChannelIfNeeded( + @NonNull Context context, PhoneAccountHandle phoneAccountHandle) { + String channelId = channelNameToId(Channel.ONGOING_CALL_OLD, phoneAccountHandle); + NotificationManager notificationManager = getNotificationManager(context); + NotificationChannel channel = notificationManager.getNotificationChannel(channelId); + if (channel != null) { + LogUtil.i( + "NotificationManager.deleteOldOngoingCallChannelIfNeeded", + "Old ongoing channel found. Deleting to create new channel"); + notificationManager.deleteNotificationChannel(channel.getId()); + } + } + private static NotificationManager getNotificationManager(@NonNull Context context) { return context.getSystemService(NotificationManager.class); } |