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

Commit 8c15f85a authored by William Escande's avatar William Escande Committed by Gerrit Code Review
Browse files

Merge "Send airplane notification from app" into main

parents 5d74c817 1e6fe49f
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -206,6 +206,7 @@ android_app {
    srcs: [
        ":statslog-bluetooth-java-gen",
        ":statslog-bt-restricted-java-gen",
        ":system-messages-proto-src",
        "proto/keystore.proto",
        "src/**/*.java",
    ],
+10 −0
Original line number Diff line number Diff line
@@ -103,6 +103,16 @@
            </intent-filter>
        </service>

        <service android:process="@string/process"
             android:name="com.android.bluetooth.airplane.NotificationHelperService"
             android:label="Airplane Notification Helper"
             android:exported="true"
             android:permission="android.permission.BLUETOOTH_PRIVILEGED">
            <intent-filter>
                <action android:name="android.bluetooth.airplane.action.SEND_NOTIFICATION"/>
            </intent-filter>
        </service>

        <!--  Advanced Audio Distribution Profile (A2DP) source Profile Service  -->
        <service android:process="@string/process"
             android:name="com.android.bluetooth.a2dp.A2dpService"
+142 −0
Original line number Diff line number Diff line
/*
 * Copyright 2023 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.bluetooth.airplane;

import static java.util.Objects.requireNonNull;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.net.Uri;
import android.os.IBinder;
import android.provider.Settings;
import android.service.notification.StatusBarNotification;
import android.util.Log;
import android.util.Pair;

import com.android.bluetooth.R;
import com.android.internal.messages.SystemMessageProto.SystemMessage;

import java.util.Map;

public class NotificationHelperService extends Service {
    private static final String TAG = NotificationHelperService.class.getSimpleName();

    // Keeps track of whether wifi and bt remains on notification was shown
    private static final String APM_WIFI_BT_NOTIFICATION = "apm_wifi_bt_notification";
    // Keeps track of whether bt remains on notification was shown
    private static final String APM_BT_NOTIFICATION = "apm_bt_notification";
    // Keeps track of whether user enabling bt notification was shown
    private static final String APM_BT_ENABLED_NOTIFICATION = "apm_bt_enabled_notification";

    private static final String NOTIFICATION_TAG = "com.android.bluetooth";
    private 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 static final Map<String, Pair<Integer /* titleId */, Integer /* messageId */>>
            NOTIFICATION_MAP =
                    Map.of(
                            APM_WIFI_BT_NOTIFICATION,
                            Pair.create(
                                    R.string.bluetooth_and_wifi_stays_on_title,
                                    R.string.bluetooth_and_wifi_stays_on_message),
                            APM_BT_NOTIFICATION,
                            Pair.create(
                                    R.string.bluetooth_stays_on_title,
                                    R.string.bluetooth_stays_on_message),
                            APM_BT_ENABLED_NOTIFICATION,
                            Pair.create(
                                    R.string.bluetooth_enabled_apm_title,
                                    R.string.bluetooth_enabled_apm_message));

    @Override
    public IBinder onBind(Intent intent) {
        return null; // This is not a bound service
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        sendAirplaneModeNotification(
                intent.getStringExtra("android.bluetooth.airplane.extra.NOTIFICATION_STATE"));
        return Service.START_NOT_STICKY;
    }

    private void sendAirplaneModeNotification(String notificationState) {
        String logHeader = "sendAirplaneModeNotification(" + notificationState + "): ";
        Pair<Integer, Integer> notificationContent = NOTIFICATION_MAP.get(notificationState);
        if (notificationContent == null) {
            Log.e(TAG, logHeader + "unknown action");
            return;
        }

        if (!isFirstTimeNotification(notificationState)) {
            Log.d(TAG, logHeader + "already displayed");
            return;
        }
        Settings.Secure.putInt(getContentResolver(), notificationState, 1);

        Log.d(TAG, logHeader + "sending");

        NotificationManager notificationManager =
                requireNonNull(getSystemService(NotificationManager.class));
        for (StatusBarNotification notification : notificationManager.getActiveNotifications()) {
            if (NOTIFICATION_TAG.equals(notification.getTag())) {
                notificationManager.cancel(NOTIFICATION_TAG, notification.getId());
            }
        }

        notificationManager.createNotificationChannel(
                new NotificationChannel(
                        APM_NOTIFICATION_CHANNEL,
                        APM_NOTIFICATION_GROUP,
                        NotificationManager.IMPORTANCE_HIGH));

        String title = getString(notificationContent.first);
        String message = getString(notificationContent.second);

        notificationManager.notify(
                NOTIFICATION_TAG,
                SystemMessage.ID.NOTE_BT_APM_NOTIFICATION_VALUE,
                new Notification.Builder(this, APM_NOTIFICATION_CHANNEL)
                        .setAutoCancel(true)
                        .setLocalOnly(true)
                        .setContentTitle(title)
                        .setContentText(message)
                        .setContentIntent(
                                PendingIntent.getActivity(
                                        this,
                                        PendingIntent.FLAG_UPDATE_CURRENT,
                                        new Intent(Intent.ACTION_VIEW)
                                                .setData(Uri.parse(HELP_PAGE_URL))
                                                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
                                        PendingIntent.FLAG_IMMUTABLE))
                        .setVisibility(Notification.VISIBILITY_PUBLIC)
                        .setStyle(new Notification.BigTextStyle().bigText(message))
                        .setSmallIcon(android.R.drawable.stat_sys_data_bluetooth)
                        .build());
    }

    /** Return whether the notification has been shown */
    private boolean isFirstTimeNotification(String name) {
        return Settings.Secure.getInt(getContentResolver(), name, 0) == 0;
    }
}
+8 −0
Original line number Diff line number Diff line
package: "com.android.bluetooth.flags"

flag {
    name: "airplane_ressources_in_app"
    namespace: "bluetooth"
    description: "User notification is done within app, not server"
    bug: "303552318"
}

flag {
    name: "use_new_satellite_mode"
    namespace: "bluetooth"
    description: "Use the new implemention of satellite mode"
    bug: "289584302"
}
+19 −1
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import android.provider.Settings;
import android.util.Log;

import com.android.bluetooth.BluetoothStatsLog;
import com.android.bluetooth.flags.FeatureFlags;
import com.android.internal.annotations.VisibleForTesting;

/**
@@ -91,6 +92,7 @@ class BluetoothAirplaneModeListener extends Handler {
    private long mApmEnabledTime = 0;

    private final BluetoothManagerService mBluetoothManager;
    private final FeatureFlags mFeatureFlags;
    private final Context mContext;
    private BluetoothModeChangeHelper mAirplaneHelper;
    private final BluetoothNotificationManager mNotificationManager;
@@ -103,10 +105,12 @@ class BluetoothAirplaneModeListener extends Handler {
            BluetoothManagerService service,
            Looper looper,
            Context context,
            BluetoothNotificationManager notificationManager) {
            BluetoothNotificationManager notificationManager,
            FeatureFlags featureFlags) {
        super(looper);

        mBluetoothManager = service;
        mFeatureFlags = featureFlags;
        mNotificationManager = notificationManager;
        mContext = context;

@@ -222,6 +226,14 @@ class BluetoothAirplaneModeListener extends Handler {
            }
            return;
        } else {
            if (mFeatureFlags.airplaneRessourcesInApp()) {
                if (isWifiEnabledOnApm()) {
                    mBluetoothManager.sendAirplaneModeNotification(APM_WIFI_BT_NOTIFICATION);
                } else {
                    mBluetoothManager.sendAirplaneModeNotification(APM_BT_NOTIFICATION);
                }
                return;
            }
            if (isWifiEnabledOnApm() && isFirstTimeNotification(APM_WIFI_BT_NOTIFICATION)) {
                try {
                    sendApmNotification(
@@ -317,6 +329,12 @@ 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.sendAirplaneModeNotification(APM_BT_ENABLED_NOTIFICATION);
                }
                return;
            }
            if (isOn && isFirstTimeNotification(APM_BT_ENABLED_NOTIFICATION)) {
                // waive WRITE_SECURE_SETTINGS permission check
                final long callingIdentity = Binder.clearCallingIdentity();
Loading