Merge changes Iadf7f15d,I74702938,Ib8a725cd into nyc-mr2-dev

* changes:
  DO NOT MERGE Network notifications: revamp keying scheme
  DO NOT MERGE Define Network notification proto constants.
  DO NOT MERGE Unit tests for NetworkNotificationManager
This commit is contained in:
Hugo Benichi
2016-12-19 08:25:25 +00:00
committed by Android (Google) Code Review
2 changed files with 203 additions and 15 deletions

View File

@@ -19,7 +19,6 @@ package com.android.server.connectivity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.widget.Toast;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
@@ -27,17 +26,40 @@ import android.net.NetworkCapabilities;
import android.os.UserHandle;
import android.telephony.TelephonyManager;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.widget.Toast;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import static android.net.NetworkCapabilities.*;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
public class NetworkNotificationManager {
public static enum NotificationType { SIGN_IN, NO_INTERNET, LOST_INTERNET, NETWORK_SWITCH };
public static enum NotificationType {
LOST_INTERNET(MetricsEvent.NOTIFICATION_NETWORK_LOST_INTERNET),
NETWORK_SWITCH(MetricsEvent.NOTIFICATION_NETWORK_SWITCH),
NO_INTERNET(MetricsEvent.NOTIFICATION_NETWORK_NO_INTERNET),
SIGN_IN(MetricsEvent.NOTIFICATION_NETWORK_SIGN_IN);
private static final String NOTIFICATION_ID = "Connectivity.Notification";
public final int eventId;
NotificationType(int eventId) {
this.eventId = eventId;
Holder.sIdToTypeMap.put(eventId, this);
}
private static class Holder {
private static SparseArray<NotificationType> sIdToTypeMap = new SparseArray<>();
}
public static NotificationType getFromId(int id) {
return Holder.sIdToTypeMap.get(id);
}
};
private static final String TAG = NetworkNotificationManager.class.getSimpleName();
private static final boolean DBG = true;
@@ -46,11 +68,14 @@ public class NetworkNotificationManager {
private final Context mContext;
private final TelephonyManager mTelephonyManager;
private final NotificationManager mNotificationManager;
// Tracks the types of notifications managed by this instance, from creation to cancellation.
private final SparseIntArray mNotificationTypeMap;
public NetworkNotificationManager(Context c, TelephonyManager t, NotificationManager n) {
mContext = c;
mTelephonyManager = t;
mNotificationManager = n;
mNotificationTypeMap = new SparseIntArray();
}
// TODO: deal more gracefully with multi-transport networks.
@@ -100,8 +125,10 @@ public class NetworkNotificationManager {
*/
public void showNotification(int id, NotificationType notifyType, NetworkAgentInfo nai,
NetworkAgentInfo switchToNai, PendingIntent intent, boolean highPriority) {
int transportType;
String extraInfo;
final String tag = tagFor(id);
final int eventId = notifyType.eventId;
final int transportType;
final String extraInfo;
if (nai != null) {
transportType = getFirstTransportType(nai);
extraInfo = nai.networkInfo.getExtraInfo();
@@ -114,9 +141,9 @@ public class NetworkNotificationManager {
}
if (DBG) {
Slog.d(TAG, "showNotification id=" + id + " " + notifyType
+ " transportType=" + getTransportName(transportType)
+ " extraInfo=" + extraInfo + " highPriority=" + highPriority);
Slog.d(TAG, String.format(
"showNotification tag=%s event=%s transport=%s extraInfo=%d highPrioriy=%s",
tag, nameOf(eventId), getTransportName(transportType), extraInfo, highPriority));
}
Resources r = Resources.getSystem();
@@ -184,22 +211,31 @@ public class NetworkNotificationManager {
Notification notification = builder.build();
mNotificationTypeMap.put(id, eventId);
try {
mNotificationManager.notifyAsUser(NOTIFICATION_ID, id, notification, UserHandle.ALL);
mNotificationManager.notifyAsUser(tag, eventId, notification, UserHandle.ALL);
} catch (NullPointerException npe) {
Slog.d(TAG, "setNotificationVisible: visible notificationManager error", npe);
}
}
public void clearNotification(int id) {
final String tag = tagFor(id);
if (mNotificationTypeMap.indexOfKey(id) < 0) {
Slog.e(TAG, "cannot clear unknown notification with tag=" + tag);
return;
}
final int eventId = mNotificationTypeMap.get(id);
if (DBG) {
Slog.d(TAG, "clearNotification id=" + id);
Slog.d(TAG, String.format("clearing notification tag=%s event=", tag, nameOf(eventId)));
}
try {
mNotificationManager.cancelAsUser(NOTIFICATION_ID, id, UserHandle.ALL);
mNotificationManager.cancelAsUser(tag, eventId, UserHandle.ALL);
} catch (NullPointerException npe) {
Slog.d(TAG, "setNotificationVisible: cancel notificationManager error", npe);
Slog.d(TAG, String.format(
"failed to clear notification tag=%s event=", tag, nameOf(eventId)), npe);
}
mNotificationTypeMap.delete(id);
}
/**
@@ -222,4 +258,15 @@ public class NetworkNotificationManager {
R.string.network_switch_metered_toast, fromTransport, toTransport);
Toast.makeText(mContext, text, Toast.LENGTH_LONG).show();
}
@VisibleForTesting
static String tagFor(int id) {
return String.format("ConnectivityNotification:%d", id);
}
@VisibleForTesting
static String nameOf(int eventId) {
NotificationType t = NotificationType.getFromId(eventId);
return (t != null) ? t.name() : "UNKNOWN";
}
}

View File

@@ -0,0 +1,141 @@
/*
* 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.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.telephony.TelephonyManager;
import android.test.suitebuilder.annotation.SmallTest;
import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import junit.framework.TestCase;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import static com.android.server.connectivity.NetworkNotificationManager.NotificationType.*;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class NetworkNotificationManagerTest extends TestCase {
static final NetworkCapabilities CELL_CAPABILITIES = new NetworkCapabilities();
static final NetworkCapabilities WIFI_CAPABILITIES = new NetworkCapabilities();
static {
CELL_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
CELL_CAPABILITIES.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
WIFI_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
WIFI_CAPABILITIES.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
}
@Mock Context mCtx;
@Mock Resources mResources;
@Mock PackageManager mPm;
@Mock TelephonyManager mTelephonyManager;
@Mock NotificationManager mNotificationManager;
@Mock NetworkAgentInfo mWifiNai;
@Mock NetworkAgentInfo mCellNai;
@Mock NetworkInfo mNetworkInfo;
ArgumentCaptor<Notification> mCaptor;
NetworkNotificationManager mManager;
public void setUp() {
MockitoAnnotations.initMocks(this);
mCaptor = ArgumentCaptor.forClass(Notification.class);
mWifiNai.networkCapabilities = WIFI_CAPABILITIES;
mWifiNai.networkInfo = mNetworkInfo;
mCellNai.networkCapabilities = CELL_CAPABILITIES;
mCellNai.networkInfo = mNetworkInfo;
when(mCtx.getResources()).thenReturn(mResources);
when(mCtx.getPackageManager()).thenReturn(mPm);
when(mCtx.getApplicationInfo()).thenReturn(new ApplicationInfo());
when(mResources.getColor(anyInt(), any())).thenReturn(0xFF607D8B);
mManager = new NetworkNotificationManager(mCtx, mTelephonyManager, mNotificationManager);
}
@SmallTest
public void testNotificationsShownAndCleared() {
final int NETWORK_ID_BASE = 100;
List<NotificationType> types = Arrays.asList(NotificationType.values());
List<Integer> ids = new ArrayList<>(types.size());
for (int i = 0; i < ids.size(); i++) {
ids.add(NETWORK_ID_BASE + i);
}
Collections.shuffle(ids);
Collections.shuffle(types);
for (int i = 0; i < ids.size(); i++) {
mManager.showNotification(ids.get(i), types.get(i), mWifiNai, mCellNai, null, false);
}
Collections.shuffle(ids);
for (int i = 0; i < ids.size(); i++) {
mManager.clearNotification(ids.get(i));
}
for (int i = 0; i < ids.size(); i++) {
final int id = ids.get(i);
final int eventId = types.get(i).eventId;
final String tag = NetworkNotificationManager.tagFor(id);
verify(mNotificationManager, times(1)).notifyAsUser(eq(tag), eq(eventId), any(), any());
verify(mNotificationManager, times(1)).cancelAsUser(eq(tag), eq(eventId), any());
}
}
@SmallTest
public void testNoInternetNotificationsNotShownForCellular() {
mManager.showNotification(100, NO_INTERNET, mCellNai, mWifiNai, null, false);
mManager.showNotification(101, LOST_INTERNET, mCellNai, mWifiNai, null, false);
verify(mNotificationManager, never()).notifyAsUser(any(), anyInt(), any(), any());
mManager.showNotification(102, NO_INTERNET, mWifiNai, mCellNai, null, false);
final int eventId = NO_INTERNET.eventId;
final String tag = NetworkNotificationManager.tagFor(102);
verify(mNotificationManager, times(1)).notifyAsUser(eq(tag), eq(eventId), any(), any());
}
@SmallTest
public void testNotificationsNotShownIfNoInternetCapability() {
mWifiNai.networkCapabilities = new NetworkCapabilities();
mWifiNai.networkCapabilities .addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
mManager.showNotification(102, NO_INTERNET, mWifiNai, mCellNai, null, false);
mManager.showNotification(103, LOST_INTERNET, mWifiNai, mCellNai, null, false);
mManager.showNotification(104, NETWORK_SWITCH, mWifiNai, mCellNai, null, false);
verify(mNotificationManager, never()).notifyAsUser(any(), anyInt(), any(), any());
}
}