Loading flags/system_service.aconfig +0 −7 Original line number Diff line number Diff line package: "com.android.bluetooth.flags" container: "com.android.btservices" flag { name: "airplane_ressources_in_app" namespace: "bluetooth" description: "User notification is done within app, not server" bug: "303552318" } flag { name: "auto_on_feature" is_exported: true Loading service/src/com/android/server/bluetooth/BluetoothAirplaneModeListener.java +6 −81 Original line number Diff line number Diff line Loading @@ -19,8 +19,6 @@ package com.android.server.bluetooth; import android.annotation.RequiresPermission; import android.app.ActivityManager; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Resources; import android.database.ContentObserver; import android.os.Binder; import android.os.Handler; Loading Loading @@ -93,7 +91,6 @@ class BluetoothAirplaneModeListener extends Handler { private final FeatureFlags mFeatureFlags; private final Context mContext; private BluetoothModeChangeHelper mAirplaneHelper; private final BluetoothNotificationManager mNotificationManager; private boolean mIsAirplaneModeOn; Loading @@ -103,13 +100,11 @@ class BluetoothAirplaneModeListener extends Handler { BluetoothManagerService service, Looper looper, Context context, BluetoothNotificationManager notificationManager, FeatureFlags featureFlags) { super(looper); mBluetoothManager = service; mFeatureFlags = featureFlags; mNotificationManager = notificationManager; mContext = context; String airplaneModeRadios = Loading Loading @@ -224,33 +219,11 @@ class BluetoothAirplaneModeListener extends Handler { } return; } else { if (mFeatureFlags.airplaneRessourcesInApp()) { if (isWifiEnabledOnApm()) { mBluetoothManager.sendToggleNotification(APM_WIFI_BT_NOTIFICATION); } else { mBluetoothManager.sendToggleNotification(APM_BT_NOTIFICATION); } return; } if (isWifiEnabledOnApm() && isFirstTimeNotification(APM_WIFI_BT_NOTIFICATION)) { try { sendApmNotification( "bluetooth_and_wifi_stays_on_title", "bluetooth_and_wifi_stays_on_message", APM_WIFI_BT_NOTIFICATION); } catch (Exception e) { Log.e(TAG, "APM enhancement BT and Wi-Fi stays on notification not shown"); } } else if (!isWifiEnabledOnApm() && isFirstTimeNotification(APM_BT_NOTIFICATION)) { try { sendApmNotification( "bluetooth_stays_on_title", "bluetooth_stays_on_message", APM_BT_NOTIFICATION); } catch (Exception e) { Log.e(TAG, "APM enhancement BT stays on notification not shown"); } } } } Loading Loading @@ -294,25 +267,6 @@ class BluetoothAirplaneModeListener extends Handler { && mAirplaneHelper.getSettingsSecureInt(WIFI_APM_STATE, 0) == 1; } /** Helper method to send APM notification */ public void sendApmNotification(String titleId, String messageId, String notificationState) throws PackageManager.NameNotFoundException { String btPackageName = mAirplaneHelper.getBluetoothPackageName(); if (btPackageName == null) { Log.e( TAG, "Unable to find Bluetooth package name with " + "APM notification resources"); return; } Resources resources = mContext.getPackageManager().getResourcesForApplication(btPackageName); int title = resources.getIdentifier(titleId, "string", btPackageName); int message = resources.getIdentifier(messageId, "string", btPackageName); mNotificationManager.sendApmNotification( resources.getString(title), resources.getString(message)); mAirplaneHelper.setSettingsSecureInt(notificationState, NOTIFICATION_SHOWN); } /** Helper method to update whether user toggled Bluetooth in airplane mode */ public void notifyUserToggledBluetooth(boolean isOn) { if (!mIsAirplaneModeOn) { Loading @@ -327,38 +281,9 @@ class BluetoothAirplaneModeListener extends Handler { if (isApmEnhancementEnabled()) { setSettingsSecureInt(BLUETOOTH_APM_STATE, isOn ? BLUETOOTH_ON_APM : BLUETOOTH_OFF_APM); setSettingsSecureInt(APM_USER_TOGGLED_BLUETOOTH, USED); if (mFeatureFlags.airplaneRessourcesInApp()) { if (isOn) { mBluetoothManager.sendToggleNotification(APM_BT_ENABLED_NOTIFICATION); } return; } if (isOn && isFirstTimeNotification(APM_BT_ENABLED_NOTIFICATION)) { // waive WRITE_SECURE_SETTINGS permission check final long callingIdentity = Binder.clearCallingIdentity(); try { sendApmNotification( "bluetooth_enabled_apm_title", "bluetooth_enabled_apm_message", APM_BT_ENABLED_NOTIFICATION); } catch (Exception e) { Log.e(TAG, "APM enhancement BT enabled notification not shown"); } finally { Binder.restoreCallingIdentity(callingIdentity); } } } } /** Return whether APM notification has been shown */ private boolean isFirstTimeNotification(String name) { // waive WRITE_SECURE_SETTINGS permission check final long callingIdentity = Binder.clearCallingIdentity(); try { return mAirplaneHelper.getSettingsSecureInt(name, NOTIFICATION_NOT_SHOWN) == NOTIFICATION_NOT_SHOWN; } finally { Binder.restoreCallingIdentity(callingIdentity); } } Loading service/src/com/android/server/bluetooth/BluetoothManagerService.java +1 −12 Original line number Diff line number Diff line Loading @@ -212,9 +212,6 @@ class BluetoothManagerService { // TODO(b/309033118): remove BluetoothAirplaneModeListener once use_new_airplane_mode ship private final BluetoothAirplaneModeListener mBluetoothAirplaneModeListener; // TODO(b/303552318): remove BluetoothNotificationManager once airplane_ressources_in_app ship private BluetoothNotificationManager mBluetoothNotificationManager; // TODO(b/289584302): remove BluetoothSatelliteModeListener once use_new_satellite_mode ship private BluetoothSatelliteModeListener mBluetoothSatelliteModeListener; Loading Loading @@ -665,10 +662,6 @@ class BluetoothManagerService { // Observe BLE scan only mode settings change. registerForBleScanModeChange(); if (!mFeatureFlags.airplaneRessourcesInApp() && !mFeatureFlags.useNewAirplaneMode()) { mBluetoothNotificationManager = new BluetoothNotificationManager(mContext); } // Disable ASHA if BLE is not supported, overriding any system property if (!isBleSupported(mContext)) { mIsHearingAidProfileSupported = false; Loading Loading @@ -733,8 +726,7 @@ class BluetoothManagerService { mBluetoothAirplaneModeListener = null; } else { mBluetoothAirplaneModeListener = new BluetoothAirplaneModeListener( this, mLooper, mContext, mBluetoothNotificationManager, mFeatureFlags); new BluetoothAirplaneModeListener(this, mLooper, mContext, mFeatureFlags); } // Caching is necessary to prevent caller requiring the READ_DEVICE_CONFIG permission Loading Loading @@ -1961,9 +1953,6 @@ class BluetoothManagerService { UserHandle userTo = (UserHandle) msg.obj; Log.d(TAG, "MESSAGE_USER_SWITCHED: userTo=" + userTo); mHandler.removeMessages(MESSAGE_USER_SWITCHED); if (!mFeatureFlags.airplaneRessourcesInApp() && !mUseNewAirplaneMode) { mBluetoothNotificationManager.createNotificationChannels(); } AutoOnFeature.pause(); Loading service/src/com/android/server/bluetooth/BluetoothModeChangeHelper.java +0 −32 Original line number Diff line number Diff line Loading @@ -21,9 +21,7 @@ import static com.android.server.bluetooth.BluetoothAirplaneModeListener.BLUETOO import android.app.ActivityManager; import android.bluetooth.BluetoothAdapter; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Resources; import android.os.Process; import android.os.UserHandle; import android.provider.Settings; import android.widget.Toast; Loading Loading @@ -103,34 +101,4 @@ public class BluetoothModeChangeHelper { return Settings.Secure.getInt(userContext.getContentResolver(), BLUETOOTH_APM_STATE, 0) == 1; } /** * Helper method to retrieve BT package name with APM resources */ public String getBluetoothPackageName() { if (mBluetoothPackageName != null) { return mBluetoothPackageName; } var allPackages = mContext.getPackageManager().getPackagesForUid(Process.BLUETOOTH_UID); for (String candidatePackage : allPackages) { Resources resources; try { resources = mContext.getPackageManager() .getResourcesForApplication(candidatePackage); } catch (PackageManager.NameNotFoundException e) { // ignore, try next package Log.e(TAG, "Could not find package " + candidatePackage); continue; } catch (Exception e) { Log.e(TAG, "Error while loading package" + e); continue; } if (resources.getIdentifier("bluetooth_and_wifi_stays_on_title", "string", candidatePackage) == 0) { continue; } mBluetoothPackageName = candidatePackage; } return mBluetoothPackageName; } } service/src/com/android/server/bluetooth/BluetoothNotificationManager.javadeleted 100644 → 0 +0 −175 Original line number Diff line number Diff line /* * Copyright 2022 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.server.bluetooth; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Binder; import android.os.UserHandle; import android.service.notification.StatusBarNotification; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import java.util.ArrayList; import java.util.List; /** * Notification manager for Bluetooth. All notification will be sent to the current user. */ public class BluetoothNotificationManager { private static final String TAG = "BluetoothNotificationManager"; private static final String NOTIFICATION_TAG = "com.android.bluetooth"; public static final String APM_NOTIFICATION_CHANNEL = "apm_notification_channel"; private static final String APM_NOTIFICATION_GROUP = "apm_notification_group"; private static final String HELP_PAGE_URL = "https://support.google.com/pixelphone/answer/12639358"; private final Context mContext; private NotificationManager mNotificationManager; private boolean mInitialized = false; /** * Constructor * * @param ctx The context to use to obtain access to the Notification Service */ BluetoothNotificationManager(Context ctx) { mContext = ctx; } private NotificationManager getNotificationManagerForCurrentUser() { final long callingIdentity = Binder.clearCallingIdentity(); try { return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, UserHandle.CURRENT).getSystemService(NotificationManager.class); } catch (PackageManager.NameNotFoundException e) { Log.e(TAG, "Failed to get NotificationManager for current user: " + e.getMessage()); } finally { Binder.restoreCallingIdentity(callingIdentity); } return null; } /** * Update to the notification manager fot current user and create notification channels. */ public void createNotificationChannels() { if (mNotificationManager != null) { // Cancel all active notification from Bluetooth Stack. cleanAllBtNotification(); } mNotificationManager = getNotificationManagerForCurrentUser(); if (mNotificationManager == null) { return; } List<NotificationChannel> channelsList = new ArrayList<>(); final NotificationChannel apmChannel = new NotificationChannel( APM_NOTIFICATION_CHANNEL, APM_NOTIFICATION_GROUP, NotificationManager.IMPORTANCE_HIGH); channelsList.add(apmChannel); final long callingIdentity = Binder.clearCallingIdentity(); try { mNotificationManager.createNotificationChannels(channelsList); } catch (Exception e) { Log.e(TAG, "Error Message: " + e.getMessage()); e.printStackTrace(); } finally { Binder.restoreCallingIdentity(callingIdentity); } } private void cleanAllBtNotification() { for (StatusBarNotification notification : getActiveNotifications()) { if (NOTIFICATION_TAG.equals(notification.getTag())) { cancel(notification.getId()); } } } /** * Send notification to the current user. */ public void notify(int id, Notification notification) { if (!mInitialized) { createNotificationChannels(); mInitialized = true; } if (mNotificationManager == null) { return; } mNotificationManager.notify(NOTIFICATION_TAG, id, notification); } /** * Build and send the APM notification. */ public void sendApmNotification(String title, String message) { if (!mInitialized) { createNotificationChannels(); mInitialized = true; } Intent openLinkIntent = new Intent(Intent.ACTION_VIEW) .setData(Uri.parse(HELP_PAGE_URL)) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); PendingIntent tapPendingIntent = PendingIntent.getActivity( mContext.createContextAsUser(UserHandle.CURRENT, 0), PendingIntent.FLAG_UPDATE_CURRENT, openLinkIntent, PendingIntent.FLAG_IMMUTABLE); Notification notification = new Notification.Builder(mContext, APM_NOTIFICATION_CHANNEL) .setAutoCancel(true) .setLocalOnly(true) .setContentTitle(title) .setContentText(message) .setContentIntent(tapPendingIntent) .setVisibility(Notification.VISIBILITY_PUBLIC) .setStyle(new Notification.BigTextStyle().bigText(message)) .setSmallIcon(android.R.drawable.stat_sys_data_bluetooth) .build(); notify(SystemMessage.NOTE_BT_APM_NOTIFICATION, notification); } /** * Cancel the notification fot current user. */ public void cancel(int id) { if (mNotificationManager == null) { return; } mNotificationManager.cancel(NOTIFICATION_TAG, id); } /** * Get active notifications for current user. */ public StatusBarNotification[] getActiveNotifications() { if (mNotificationManager == null) { return new StatusBarNotification[0]; } return mNotificationManager.getActiveNotifications(); } } Loading
flags/system_service.aconfig +0 −7 Original line number Diff line number Diff line package: "com.android.bluetooth.flags" container: "com.android.btservices" flag { name: "airplane_ressources_in_app" namespace: "bluetooth" description: "User notification is done within app, not server" bug: "303552318" } flag { name: "auto_on_feature" is_exported: true Loading
service/src/com/android/server/bluetooth/BluetoothAirplaneModeListener.java +6 −81 Original line number Diff line number Diff line Loading @@ -19,8 +19,6 @@ package com.android.server.bluetooth; import android.annotation.RequiresPermission; import android.app.ActivityManager; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Resources; import android.database.ContentObserver; import android.os.Binder; import android.os.Handler; Loading Loading @@ -93,7 +91,6 @@ class BluetoothAirplaneModeListener extends Handler { private final FeatureFlags mFeatureFlags; private final Context mContext; private BluetoothModeChangeHelper mAirplaneHelper; private final BluetoothNotificationManager mNotificationManager; private boolean mIsAirplaneModeOn; Loading @@ -103,13 +100,11 @@ class BluetoothAirplaneModeListener extends Handler { BluetoothManagerService service, Looper looper, Context context, BluetoothNotificationManager notificationManager, FeatureFlags featureFlags) { super(looper); mBluetoothManager = service; mFeatureFlags = featureFlags; mNotificationManager = notificationManager; mContext = context; String airplaneModeRadios = Loading Loading @@ -224,33 +219,11 @@ class BluetoothAirplaneModeListener extends Handler { } return; } else { if (mFeatureFlags.airplaneRessourcesInApp()) { if (isWifiEnabledOnApm()) { mBluetoothManager.sendToggleNotification(APM_WIFI_BT_NOTIFICATION); } else { mBluetoothManager.sendToggleNotification(APM_BT_NOTIFICATION); } return; } if (isWifiEnabledOnApm() && isFirstTimeNotification(APM_WIFI_BT_NOTIFICATION)) { try { sendApmNotification( "bluetooth_and_wifi_stays_on_title", "bluetooth_and_wifi_stays_on_message", APM_WIFI_BT_NOTIFICATION); } catch (Exception e) { Log.e(TAG, "APM enhancement BT and Wi-Fi stays on notification not shown"); } } else if (!isWifiEnabledOnApm() && isFirstTimeNotification(APM_BT_NOTIFICATION)) { try { sendApmNotification( "bluetooth_stays_on_title", "bluetooth_stays_on_message", APM_BT_NOTIFICATION); } catch (Exception e) { Log.e(TAG, "APM enhancement BT stays on notification not shown"); } } } } Loading Loading @@ -294,25 +267,6 @@ class BluetoothAirplaneModeListener extends Handler { && mAirplaneHelper.getSettingsSecureInt(WIFI_APM_STATE, 0) == 1; } /** Helper method to send APM notification */ public void sendApmNotification(String titleId, String messageId, String notificationState) throws PackageManager.NameNotFoundException { String btPackageName = mAirplaneHelper.getBluetoothPackageName(); if (btPackageName == null) { Log.e( TAG, "Unable to find Bluetooth package name with " + "APM notification resources"); return; } Resources resources = mContext.getPackageManager().getResourcesForApplication(btPackageName); int title = resources.getIdentifier(titleId, "string", btPackageName); int message = resources.getIdentifier(messageId, "string", btPackageName); mNotificationManager.sendApmNotification( resources.getString(title), resources.getString(message)); mAirplaneHelper.setSettingsSecureInt(notificationState, NOTIFICATION_SHOWN); } /** Helper method to update whether user toggled Bluetooth in airplane mode */ public void notifyUserToggledBluetooth(boolean isOn) { if (!mIsAirplaneModeOn) { Loading @@ -327,38 +281,9 @@ class BluetoothAirplaneModeListener extends Handler { if (isApmEnhancementEnabled()) { setSettingsSecureInt(BLUETOOTH_APM_STATE, isOn ? BLUETOOTH_ON_APM : BLUETOOTH_OFF_APM); setSettingsSecureInt(APM_USER_TOGGLED_BLUETOOTH, USED); if (mFeatureFlags.airplaneRessourcesInApp()) { if (isOn) { mBluetoothManager.sendToggleNotification(APM_BT_ENABLED_NOTIFICATION); } return; } if (isOn && isFirstTimeNotification(APM_BT_ENABLED_NOTIFICATION)) { // waive WRITE_SECURE_SETTINGS permission check final long callingIdentity = Binder.clearCallingIdentity(); try { sendApmNotification( "bluetooth_enabled_apm_title", "bluetooth_enabled_apm_message", APM_BT_ENABLED_NOTIFICATION); } catch (Exception e) { Log.e(TAG, "APM enhancement BT enabled notification not shown"); } finally { Binder.restoreCallingIdentity(callingIdentity); } } } } /** Return whether APM notification has been shown */ private boolean isFirstTimeNotification(String name) { // waive WRITE_SECURE_SETTINGS permission check final long callingIdentity = Binder.clearCallingIdentity(); try { return mAirplaneHelper.getSettingsSecureInt(name, NOTIFICATION_NOT_SHOWN) == NOTIFICATION_NOT_SHOWN; } finally { Binder.restoreCallingIdentity(callingIdentity); } } Loading
service/src/com/android/server/bluetooth/BluetoothManagerService.java +1 −12 Original line number Diff line number Diff line Loading @@ -212,9 +212,6 @@ class BluetoothManagerService { // TODO(b/309033118): remove BluetoothAirplaneModeListener once use_new_airplane_mode ship private final BluetoothAirplaneModeListener mBluetoothAirplaneModeListener; // TODO(b/303552318): remove BluetoothNotificationManager once airplane_ressources_in_app ship private BluetoothNotificationManager mBluetoothNotificationManager; // TODO(b/289584302): remove BluetoothSatelliteModeListener once use_new_satellite_mode ship private BluetoothSatelliteModeListener mBluetoothSatelliteModeListener; Loading Loading @@ -665,10 +662,6 @@ class BluetoothManagerService { // Observe BLE scan only mode settings change. registerForBleScanModeChange(); if (!mFeatureFlags.airplaneRessourcesInApp() && !mFeatureFlags.useNewAirplaneMode()) { mBluetoothNotificationManager = new BluetoothNotificationManager(mContext); } // Disable ASHA if BLE is not supported, overriding any system property if (!isBleSupported(mContext)) { mIsHearingAidProfileSupported = false; Loading Loading @@ -733,8 +726,7 @@ class BluetoothManagerService { mBluetoothAirplaneModeListener = null; } else { mBluetoothAirplaneModeListener = new BluetoothAirplaneModeListener( this, mLooper, mContext, mBluetoothNotificationManager, mFeatureFlags); new BluetoothAirplaneModeListener(this, mLooper, mContext, mFeatureFlags); } // Caching is necessary to prevent caller requiring the READ_DEVICE_CONFIG permission Loading Loading @@ -1961,9 +1953,6 @@ class BluetoothManagerService { UserHandle userTo = (UserHandle) msg.obj; Log.d(TAG, "MESSAGE_USER_SWITCHED: userTo=" + userTo); mHandler.removeMessages(MESSAGE_USER_SWITCHED); if (!mFeatureFlags.airplaneRessourcesInApp() && !mUseNewAirplaneMode) { mBluetoothNotificationManager.createNotificationChannels(); } AutoOnFeature.pause(); Loading
service/src/com/android/server/bluetooth/BluetoothModeChangeHelper.java +0 −32 Original line number Diff line number Diff line Loading @@ -21,9 +21,7 @@ import static com.android.server.bluetooth.BluetoothAirplaneModeListener.BLUETOO import android.app.ActivityManager; import android.bluetooth.BluetoothAdapter; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Resources; import android.os.Process; import android.os.UserHandle; import android.provider.Settings; import android.widget.Toast; Loading Loading @@ -103,34 +101,4 @@ public class BluetoothModeChangeHelper { return Settings.Secure.getInt(userContext.getContentResolver(), BLUETOOTH_APM_STATE, 0) == 1; } /** * Helper method to retrieve BT package name with APM resources */ public String getBluetoothPackageName() { if (mBluetoothPackageName != null) { return mBluetoothPackageName; } var allPackages = mContext.getPackageManager().getPackagesForUid(Process.BLUETOOTH_UID); for (String candidatePackage : allPackages) { Resources resources; try { resources = mContext.getPackageManager() .getResourcesForApplication(candidatePackage); } catch (PackageManager.NameNotFoundException e) { // ignore, try next package Log.e(TAG, "Could not find package " + candidatePackage); continue; } catch (Exception e) { Log.e(TAG, "Error while loading package" + e); continue; } if (resources.getIdentifier("bluetooth_and_wifi_stays_on_title", "string", candidatePackage) == 0) { continue; } mBluetoothPackageName = candidatePackage; } return mBluetoothPackageName; } }
service/src/com/android/server/bluetooth/BluetoothNotificationManager.javadeleted 100644 → 0 +0 −175 Original line number Diff line number Diff line /* * Copyright 2022 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.server.bluetooth; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Binder; import android.os.UserHandle; import android.service.notification.StatusBarNotification; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import java.util.ArrayList; import java.util.List; /** * Notification manager for Bluetooth. All notification will be sent to the current user. */ public class BluetoothNotificationManager { private static final String TAG = "BluetoothNotificationManager"; private static final String NOTIFICATION_TAG = "com.android.bluetooth"; public static final String APM_NOTIFICATION_CHANNEL = "apm_notification_channel"; private static final String APM_NOTIFICATION_GROUP = "apm_notification_group"; private static final String HELP_PAGE_URL = "https://support.google.com/pixelphone/answer/12639358"; private final Context mContext; private NotificationManager mNotificationManager; private boolean mInitialized = false; /** * Constructor * * @param ctx The context to use to obtain access to the Notification Service */ BluetoothNotificationManager(Context ctx) { mContext = ctx; } private NotificationManager getNotificationManagerForCurrentUser() { final long callingIdentity = Binder.clearCallingIdentity(); try { return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, UserHandle.CURRENT).getSystemService(NotificationManager.class); } catch (PackageManager.NameNotFoundException e) { Log.e(TAG, "Failed to get NotificationManager for current user: " + e.getMessage()); } finally { Binder.restoreCallingIdentity(callingIdentity); } return null; } /** * Update to the notification manager fot current user and create notification channels. */ public void createNotificationChannels() { if (mNotificationManager != null) { // Cancel all active notification from Bluetooth Stack. cleanAllBtNotification(); } mNotificationManager = getNotificationManagerForCurrentUser(); if (mNotificationManager == null) { return; } List<NotificationChannel> channelsList = new ArrayList<>(); final NotificationChannel apmChannel = new NotificationChannel( APM_NOTIFICATION_CHANNEL, APM_NOTIFICATION_GROUP, NotificationManager.IMPORTANCE_HIGH); channelsList.add(apmChannel); final long callingIdentity = Binder.clearCallingIdentity(); try { mNotificationManager.createNotificationChannels(channelsList); } catch (Exception e) { Log.e(TAG, "Error Message: " + e.getMessage()); e.printStackTrace(); } finally { Binder.restoreCallingIdentity(callingIdentity); } } private void cleanAllBtNotification() { for (StatusBarNotification notification : getActiveNotifications()) { if (NOTIFICATION_TAG.equals(notification.getTag())) { cancel(notification.getId()); } } } /** * Send notification to the current user. */ public void notify(int id, Notification notification) { if (!mInitialized) { createNotificationChannels(); mInitialized = true; } if (mNotificationManager == null) { return; } mNotificationManager.notify(NOTIFICATION_TAG, id, notification); } /** * Build and send the APM notification. */ public void sendApmNotification(String title, String message) { if (!mInitialized) { createNotificationChannels(); mInitialized = true; } Intent openLinkIntent = new Intent(Intent.ACTION_VIEW) .setData(Uri.parse(HELP_PAGE_URL)) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); PendingIntent tapPendingIntent = PendingIntent.getActivity( mContext.createContextAsUser(UserHandle.CURRENT, 0), PendingIntent.FLAG_UPDATE_CURRENT, openLinkIntent, PendingIntent.FLAG_IMMUTABLE); Notification notification = new Notification.Builder(mContext, APM_NOTIFICATION_CHANNEL) .setAutoCancel(true) .setLocalOnly(true) .setContentTitle(title) .setContentText(message) .setContentIntent(tapPendingIntent) .setVisibility(Notification.VISIBILITY_PUBLIC) .setStyle(new Notification.BigTextStyle().bigText(message)) .setSmallIcon(android.R.drawable.stat_sys_data_bluetooth) .build(); notify(SystemMessage.NOTE_BT_APM_NOTIFICATION, notification); } /** * Cancel the notification fot current user. */ public void cancel(int id) { if (mNotificationManager == null) { return; } mNotificationManager.cancel(NOTIFICATION_TAG, id); } /** * Get active notifications for current user. */ public StatusBarNotification[] getActiveNotifications() { if (mNotificationManager == null) { return new StatusBarNotification[0]; } return mNotificationManager.getActiveNotifications(); } }