Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d5d4a683 authored by William Escande's avatar William Escande
Browse files

SystemServer: rm shipped flag - resources_in_app

Bug: 303552318
Fix: 303552318
Test: atest ServiceBluetoothTests
Change-Id: I52ffe9cb7a5ee8ff04aa3528aa611eae10045971
parent 66a4893a
Loading
Loading
Loading
Loading
+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
+6 −81
Original line number Diff line number Diff line
@@ -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;
@@ -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;

@@ -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 =
@@ -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");
                }
            }
        }
    }

@@ -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) {
@@ -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);
        }
    }

+1 −12
Original line number Diff line number Diff line
@@ -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;

@@ -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;
@@ -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
@@ -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();

+0 −32
Original line number Diff line number Diff line
@@ -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;
@@ -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;
    }
}
+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