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

Commit f3ae2eea authored by Lorenzo Colitti's avatar Lorenzo Colitti
Browse files

Move notification code out of ConnectivityService.

Bug: 31025214
Change-Id: I4190be6b57f92298b79bea8868f1876ecbfd2d75
parent 044cd35a
Loading
Loading
Loading
Loading
+12 −119
Original line number Diff line number Diff line
@@ -38,8 +38,6 @@ import static android.net.NetworkPolicyManager.uidRulesToString;

import android.annotation.Nullable;
import android.app.BroadcastOptions;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -135,6 +133,8 @@ import com.android.server.connectivity.Nat464Xlat;
import com.android.server.connectivity.NetworkAgentInfo;
import com.android.server.connectivity.NetworkDiagnostics;
import com.android.server.connectivity.NetworkMonitor;
import com.android.server.connectivity.NetworkNotificationManager;
import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
import com.android.server.connectivity.PacManager;
import com.android.server.connectivity.PermissionMonitor;
import com.android.server.connectivity.Tethering;
@@ -436,6 +436,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
    TelephonyManager mTelephonyManager;

    private KeepaliveTracker mKeepaliveTracker;
    private NetworkNotificationManager mNotifier;

    // sequence number for Networks; keep in sync with system/netd/NetworkController.cpp
    private final static int MIN_NET_ID = 100; // some reserved marks
@@ -832,6 +833,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);

        mKeepaliveTracker = new KeepaliveTracker(mHandler);
        mNotifier = new NetworkNotificationManager(mContext, mTelephonyManager);
    }

    private NetworkRequest createInternetRequestForTransport(int transportType) {
@@ -2230,14 +2232,16 @@ public class ConnectivityService extends IConnectivityManager.Stub
                        updateCapabilities(nai, nai.networkCapabilities);
                    }
                    if (!visible) {
                        setProvNotificationVisibleIntent(false, netId, null, 0, null, null, false);
                        mNotifier.setProvNotificationVisibleIntent(false, netId, null, 0, null,
                                null, false);
                    } else {
                        if (nai == null) {
                            loge("EVENT_PROVISIONING_NOTIFICATION from unknown NetworkMonitor");
                            break;
                        }
                        if (!nai.networkMisc.provisioningNotificationDisabled) {
                            setProvNotificationVisibleIntent(true, netId, NotificationType.SIGN_IN,
                            mNotifier.setProvNotificationVisibleIntent(true, netId,
                                    NotificationType.SIGN_IN,
                                    nai.networkInfo.getType(), nai.networkInfo.getExtraInfo(),
                                    (PendingIntent)msg.obj, nai.networkMisc.explicitlySelected);
                        }
@@ -2710,8 +2714,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
        PendingIntent pendingIntent = PendingIntent.getActivityAsUser(
                mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);

        setProvNotificationVisibleIntent(true, nai.network.netId, NotificationType.NO_INTERNET,
                nai.networkInfo.getType(), nai.networkInfo.getExtraInfo(), pendingIntent, true);
        mNotifier.setProvNotificationVisibleIntent(true, nai.network.netId,
                NotificationType.NO_INTERNET, nai.networkInfo.getType(),
                nai.networkInfo.getExtraInfo(), pendingIntent, true);
    }

    private class InternalHandler extends Handler {
@@ -3617,118 +3622,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
        return -1;
    }

    private static final String NOTIFICATION_ID = "CaptivePortal.Notification";
    private static enum NotificationType { SIGN_IN, NO_INTERNET; };

    private void setProvNotificationVisible(boolean visible, int networkType, String action) {
        Intent intent = new Intent(action);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
        // Concatenate the range of types onto the range of NetIDs.
        int id = MAX_NET_ID + 1 + (networkType - ConnectivityManager.TYPE_NONE);
        setProvNotificationVisibleIntent(visible, id, NotificationType.SIGN_IN,
                networkType, null, pendingIntent, false);
    }

    /**
     * Show or hide network provisioning notifications.
     *
     * We use notifications for two purposes: to notify that a network requires sign in
     * (NotificationType.SIGN_IN), or to notify that a network does not have Internet access
     * (NotificationType.NO_INTERNET). We display at most one notification per ID, so on a
     * particular network we can display the notification type that was most recently requested.
     * So for example if a captive portal fails to reply within a few seconds of connecting, we
     * might first display NO_INTERNET, and then when the captive portal check completes, display
     * SIGN_IN.
     *
     * @param id an identifier that uniquely identifies this notification.  This must match
     *         between show and hide calls.  We use the NetID value but for legacy callers
     *         we concatenate the range of types with the range of NetIDs.
     */
    private void setProvNotificationVisibleIntent(boolean visible, int id,
            NotificationType notifyType, int networkType, String extraInfo, PendingIntent intent,
            boolean highPriority) {
        if (VDBG || (DBG && visible)) {
            log("setProvNotificationVisibleIntent " + notifyType + " visible=" + visible
                    + " networkType=" + getNetworkTypeName(networkType)
                    + " extraInfo=" + extraInfo + " highPriority=" + highPriority);
        }

        Resources r = Resources.getSystem();
        NotificationManager notificationManager = (NotificationManager) mContext
            .getSystemService(Context.NOTIFICATION_SERVICE);

        if (visible) {
            CharSequence title;
            CharSequence details;
            int icon;
            if (notifyType == NotificationType.NO_INTERNET &&
                    networkType == ConnectivityManager.TYPE_WIFI) {
                title = r.getString(R.string.wifi_no_internet, 0);
                details = r.getString(R.string.wifi_no_internet_detailed);
                icon = R.drawable.stat_notify_wifi_in_range;  // TODO: Need new icon.
            } else if (notifyType == NotificationType.SIGN_IN) {
                switch (networkType) {
                    case ConnectivityManager.TYPE_WIFI:
                        title = r.getString(R.string.wifi_available_sign_in, 0);
                        details = r.getString(R.string.network_available_sign_in_detailed,
                                extraInfo);
                        icon = R.drawable.stat_notify_wifi_in_range;
                        break;
                    case ConnectivityManager.TYPE_MOBILE:
                    case ConnectivityManager.TYPE_MOBILE_HIPRI:
                        title = r.getString(R.string.network_available_sign_in, 0);
                        // TODO: Change this to pull from NetworkInfo once a printable
                        // name has been added to it
                        details = mTelephonyManager.getNetworkOperatorName();
                        icon = R.drawable.stat_notify_rssi_in_range;
                        break;
                    default:
                        title = r.getString(R.string.network_available_sign_in, 0);
                        details = r.getString(R.string.network_available_sign_in_detailed,
                                extraInfo);
                        icon = R.drawable.stat_notify_rssi_in_range;
                        break;
                }
            } else {
                Slog.wtf(TAG, "Unknown notification type " + notifyType + "on network type "
                        + getNetworkTypeName(networkType));
                return;
            }

            Notification notification = new Notification.Builder(mContext)
                    .setWhen(0)
                    .setSmallIcon(icon)
                    .setAutoCancel(true)
                    .setTicker(title)
                    .setColor(mContext.getColor(
                            com.android.internal.R.color.system_notification_accent_color))
                    .setContentTitle(title)
                    .setContentText(details)
                    .setContentIntent(intent)
                    .setLocalOnly(true)
                    .setPriority(highPriority ?
                            Notification.PRIORITY_HIGH :
                            Notification.PRIORITY_DEFAULT)
                    .setDefaults(highPriority ? Notification.DEFAULT_ALL : 0)
                    .setOnlyAlertOnce(true)
                    .build();

            try {
                notificationManager.notifyAsUser(NOTIFICATION_ID, id, notification, UserHandle.ALL);
            } catch (NullPointerException npe) {
                loge("setNotificationVisible: visible notificationManager npe=" + npe);
                npe.printStackTrace();
            }
        } else {
            try {
                notificationManager.cancelAsUser(NOTIFICATION_ID, id, UserHandle.ALL);
            } catch (NullPointerException npe) {
                loge("setNotificationVisible: cancel notificationManager npe=" + npe);
                npe.printStackTrace();
            }
        }
    }

    /** Location to an updatable file listing carrier provisioning urls.
     *  An example:
     *
@@ -3832,7 +3725,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
        enforceConnectivityInternalPermission();
        final long ident = Binder.clearCallingIdentity();
        try {
            setProvNotificationVisible(visible, networkType, action);
            mNotifier.setProvNotificationVisible(visible, networkType, action);
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
+161 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 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.connectivity;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.os.UserHandle;
import android.telephony.TelephonyManager;
import android.util.Slog;

import com.android.internal.R;

import static android.net.ConnectivityManager.getNetworkTypeName;


public class NetworkNotificationManager {

    public static enum NotificationType { SIGN_IN, NO_INTERNET; };

    private static final String NOTIFICATION_ID = "CaptivePortal.Notification";

    private static final String TAG = NetworkNotificationManager.class.getSimpleName();
    private static final boolean DBG = true;
    private static final boolean VDBG = false;

    private final Context mContext;
    private final TelephonyManager mTelephonyManager;

    public NetworkNotificationManager(Context context, TelephonyManager telephonyManager) {
        mContext = context;
        mTelephonyManager = telephonyManager;
    }

    /**
     * Show or hide network provisioning notifications.
     *
     * We use notifications for two purposes: to notify that a network requires sign in
     * (NotificationType.SIGN_IN), or to notify that a network does not have Internet access
     * (NotificationType.NO_INTERNET). We display at most one notification per ID, so on a
     * particular network we can display the notification type that was most recently requested.
     * So for example if a captive portal fails to reply within a few seconds of connecting, we
     * might first display NO_INTERNET, and then when the captive portal check completes, display
     * SIGN_IN.
     *
     * @param id an identifier that uniquely identifies this notification.  This must match
     *         between show and hide calls.  We use the NetID value but for legacy callers
     *         we concatenate the range of types with the range of NetIDs.
     */
    public void setProvNotificationVisibleIntent(boolean visible, int id,
            NotificationType notifyType, int networkType, String extraInfo, PendingIntent intent,
            boolean highPriority) {
        if (VDBG || (DBG && visible)) {
            Slog.d(TAG, "setProvNotificationVisibleIntent " + notifyType + " visible=" + visible
                    + " networkType=" + getNetworkTypeName(networkType)
                    + " extraInfo=" + extraInfo + " highPriority=" + highPriority);
        }

        Resources r = Resources.getSystem();
        NotificationManager notificationManager = (NotificationManager) mContext
            .getSystemService(Context.NOTIFICATION_SERVICE);

        if (visible) {
            CharSequence title;
            CharSequence details;
            int icon;
            if (notifyType == NotificationType.NO_INTERNET &&
                    networkType == ConnectivityManager.TYPE_WIFI) {
                title = r.getString(R.string.wifi_no_internet, 0);
                details = r.getString(R.string.wifi_no_internet_detailed);
                icon = R.drawable.stat_notify_wifi_in_range;  // TODO: Need new icon.
            } else if (notifyType == NotificationType.SIGN_IN) {
                switch (networkType) {
                    case ConnectivityManager.TYPE_WIFI:
                        title = r.getString(R.string.wifi_available_sign_in, 0);
                        details = r.getString(R.string.network_available_sign_in_detailed,
                                extraInfo);
                        icon = R.drawable.stat_notify_wifi_in_range;
                        break;
                    case ConnectivityManager.TYPE_MOBILE:
                    case ConnectivityManager.TYPE_MOBILE_HIPRI:
                        title = r.getString(R.string.network_available_sign_in, 0);
                        // TODO: Change this to pull from NetworkInfo once a printable
                        // name has been added to it
                        details = mTelephonyManager.getNetworkOperatorName();
                        icon = R.drawable.stat_notify_rssi_in_range;
                        break;
                    default:
                        title = r.getString(R.string.network_available_sign_in, 0);
                        details = r.getString(R.string.network_available_sign_in_detailed,
                                extraInfo);
                        icon = R.drawable.stat_notify_rssi_in_range;
                        break;
                }
            } else {
                Slog.wtf(TAG, "Unknown notification type " + notifyType + "on network type "
                        + getNetworkTypeName(networkType));
                return;
            }

            Notification notification = new Notification.Builder(mContext)
                    .setWhen(0)
                    .setSmallIcon(icon)
                    .setAutoCancel(true)
                    .setTicker(title)
                    .setColor(mContext.getColor(
                            com.android.internal.R.color.system_notification_accent_color))
                    .setContentTitle(title)
                    .setContentText(details)
                    .setContentIntent(intent)
                    .setLocalOnly(true)
                    .setPriority(highPriority ?
                            Notification.PRIORITY_HIGH :
                            Notification.PRIORITY_DEFAULT)
                    .setDefaults(highPriority ? Notification.DEFAULT_ALL : 0)
                    .setOnlyAlertOnce(true)
                    .build();

            try {
                notificationManager.notifyAsUser(NOTIFICATION_ID, id, notification, UserHandle.ALL);
            } catch (NullPointerException npe) {
                Slog.d(TAG, "setNotificationVisible: visible notificationManager npe=" + npe);
            }
        } else {
            try {
                notificationManager.cancelAsUser(NOTIFICATION_ID, id, UserHandle.ALL);
            } catch (NullPointerException npe) {
                Slog.d(TAG, "setNotificationVisible: cancel notificationManager npe=" + npe);
            }
        }
    }

    /**
     * Legacy provisioning notifications coming directly from DcTracker.
     */
    public void setProvNotificationVisible(boolean visible, int networkType, String action) {
        Intent intent = new Intent(action);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
        // Concatenate the range of types onto the range of NetIDs.
        int id = MAX_NET_ID + 1 + (networkType - ConnectivityManager.TYPE_NONE);
        mNotifier.setProvNotificationVisibleIntent(visible, id, NotificationType.SIGN_IN,
                networkType, null, pendingIntent, false);
    }
}