Merge "Listener in createNotificationChannel"
This commit is contained in:
committed by
Android (Google) Code Review
commit
aac3cba531
@@ -79,6 +79,7 @@ LOCAL_SRC_FILES += \
|
||||
core/java/android/app/IBackupAgent.aidl \
|
||||
core/java/android/app/IEphemeralResolver.aidl \
|
||||
core/java/android/app/IInstrumentationWatcher.aidl \
|
||||
core/java/android/app/IOnNotificationChannelCreatedListener.aidl \
|
||||
core/java/android/app/INotificationManager.aidl \
|
||||
core/java/android/app/IProcessObserver.aidl \
|
||||
core/java/android/app/ISearchManager.aidl \
|
||||
|
||||
@@ -5395,7 +5395,7 @@ package android.app {
|
||||
method public void cancel(int);
|
||||
method public void cancel(java.lang.String, int);
|
||||
method public void cancelAll();
|
||||
method public void createNotificationChannel(android.app.NotificationChannel);
|
||||
method public void createNotificationChannel(android.app.NotificationChannel, android.app.NotificationManager.OnNotificationChannelCreatedListener, android.os.Handler);
|
||||
method public void deleteNotificationChannel(java.lang.String);
|
||||
method public android.service.notification.StatusBarNotification[] getActiveNotifications();
|
||||
method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
|
||||
@@ -5429,6 +5429,10 @@ package android.app {
|
||||
field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
|
||||
}
|
||||
|
||||
public static abstract interface NotificationManager.OnNotificationChannelCreatedListener {
|
||||
method public abstract void onNotificationChannelCreated(android.app.NotificationChannel);
|
||||
}
|
||||
|
||||
public static class NotificationManager.Policy implements android.os.Parcelable {
|
||||
ctor public NotificationManager.Policy(int, int, int);
|
||||
ctor public NotificationManager.Policy(int, int, int, int);
|
||||
|
||||
@@ -5562,7 +5562,7 @@ package android.app {
|
||||
method public void cancel(int);
|
||||
method public void cancel(java.lang.String, int);
|
||||
method public void cancelAll();
|
||||
method public void createNotificationChannel(android.app.NotificationChannel);
|
||||
method public void createNotificationChannel(android.app.NotificationChannel, android.app.NotificationManager.OnNotificationChannelCreatedListener, android.os.Handler);
|
||||
method public void deleteNotificationChannel(java.lang.String);
|
||||
method public android.service.notification.StatusBarNotification[] getActiveNotifications();
|
||||
method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
|
||||
@@ -5596,6 +5596,10 @@ package android.app {
|
||||
field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
|
||||
}
|
||||
|
||||
public static abstract interface NotificationManager.OnNotificationChannelCreatedListener {
|
||||
method public abstract void onNotificationChannelCreated(android.app.NotificationChannel);
|
||||
}
|
||||
|
||||
public static class NotificationManager.Policy implements android.os.Parcelable {
|
||||
ctor public NotificationManager.Policy(int, int, int);
|
||||
ctor public NotificationManager.Policy(int, int, int, int);
|
||||
|
||||
@@ -5405,7 +5405,7 @@ package android.app {
|
||||
method public void cancel(int);
|
||||
method public void cancel(java.lang.String, int);
|
||||
method public void cancelAll();
|
||||
method public void createNotificationChannel(android.app.NotificationChannel);
|
||||
method public void createNotificationChannel(android.app.NotificationChannel, android.app.NotificationManager.OnNotificationChannelCreatedListener, android.os.Handler);
|
||||
method public void deleteNotificationChannel(java.lang.String);
|
||||
method public android.service.notification.StatusBarNotification[] getActiveNotifications();
|
||||
method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
|
||||
@@ -5440,6 +5440,10 @@ package android.app {
|
||||
field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
|
||||
}
|
||||
|
||||
public static abstract interface NotificationManager.OnNotificationChannelCreatedListener {
|
||||
method public abstract void onNotificationChannelCreated(android.app.NotificationChannel);
|
||||
}
|
||||
|
||||
public static class NotificationManager.Policy implements android.os.Parcelable {
|
||||
ctor public NotificationManager.Policy(int, int, int);
|
||||
ctor public NotificationManager.Policy(int, int, int, int);
|
||||
|
||||
@@ -2,21 +2,22 @@
|
||||
**
|
||||
** Copyright 2007, 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
|
||||
** 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
|
||||
** 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
|
||||
** 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 android.app;
|
||||
|
||||
import android.app.IOnNotificationChannelCreatedListener;
|
||||
import android.app.ITransientNotification;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
@@ -58,7 +59,8 @@ interface INotificationManager
|
||||
int getImportance(String pkg, int uid);
|
||||
int getPackageImportance(String pkg);
|
||||
|
||||
void createNotificationChannel(String pkg, in NotificationChannel channel);
|
||||
void createNotificationChannel(String pkg, in NotificationChannel channel,
|
||||
in IOnNotificationChannelCreatedListener listener);
|
||||
void updateNotificationChannelForPackage(String pkg, int uid, in NotificationChannel channel);
|
||||
NotificationChannel getNotificationChannel(String pkg, String channelId);
|
||||
NotificationChannel getNotificationChannelForPackage(String pkg, int uid, String channelId);
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
**
|
||||
** Copyright 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 android.app;
|
||||
|
||||
import android.app.NotificationChannel;
|
||||
|
||||
/** {@hide} */
|
||||
oneway interface IOnNotificationChannelCreatedListener {
|
||||
void onNotificationChannelCreated(in NotificationChannel channel);
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package android.app;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SdkConstant;
|
||||
import android.annotation.TestApi;
|
||||
import android.app.Notification.Builder;
|
||||
@@ -30,6 +31,7 @@ import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.RemoteException;
|
||||
@@ -379,12 +381,42 @@ public class NotificationManager
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a notification channel that notifications can be posted to.
|
||||
* Listener passed to {@link NotificationManager#createNotificationChannel} to notify
|
||||
* caller of result.
|
||||
*/
|
||||
public void createNotificationChannel(NotificationChannel channel) {
|
||||
public interface OnNotificationChannelCreatedListener {
|
||||
/**
|
||||
* @param createdChannel NotificationChannel created by the system. Value is null iff an
|
||||
* exception was thrown during channel creation.
|
||||
*/
|
||||
public void onNotificationChannelCreated(NotificationChannel createdChannel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a notification channel that notifications can be posted to.
|
||||
*
|
||||
* @param channel the channel to attempt to create. Note that the created channel may differ
|
||||
* from this value.
|
||||
* @param listener Called when operation is finished.
|
||||
* @param handler The handler to invoke the listener on, or {@code null} to use the main
|
||||
* handler.
|
||||
*/
|
||||
public void createNotificationChannel(
|
||||
@NonNull NotificationChannel channel,
|
||||
@NonNull OnNotificationChannelCreatedListener listener,
|
||||
@Nullable Handler handler) {
|
||||
INotificationManager service = getService();
|
||||
try {
|
||||
service.createNotificationChannel(mContext.getPackageName(), channel);
|
||||
final Handler actualHandler =
|
||||
handler != null ? handler : new Handler(Looper.getMainLooper());
|
||||
service.createNotificationChannel(mContext.getPackageName(), channel,
|
||||
new IOnNotificationChannelCreatedListener.Stub() {
|
||||
@Override public void onNotificationChannelCreated(
|
||||
NotificationChannel channel) {
|
||||
actualHandler.post(
|
||||
() -> { listener.onNotificationChannelCreated(channel); });
|
||||
}
|
||||
});
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
@@ -583,7 +615,7 @@ public class NotificationManager
|
||||
* <p>
|
||||
* Callers can only update rules that they own. See {@link AutomaticZenRule#getOwner}.
|
||||
* @param id The id of the rule to update
|
||||
* @param automaticZenRule the rule to update.
|
||||
* @param automaticZenRule the rule to update.
|
||||
* @return Whether the rule was successfully updated.
|
||||
*/
|
||||
public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule) {
|
||||
|
||||
@@ -53,16 +53,17 @@ import android.app.ActivityManagerInternal;
|
||||
import android.app.AppGlobals;
|
||||
import android.app.AppOpsManager;
|
||||
import android.app.AutomaticZenRule;
|
||||
import android.app.backup.BackupManager;
|
||||
import android.app.IActivityManager;
|
||||
import android.app.IOnNotificationChannelCreatedListener;
|
||||
import android.app.INotificationManager;
|
||||
import android.app.ITransientNotification;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.NotificationManager.Policy;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.StatusBarManager;
|
||||
import android.app.backup.BackupManager;
|
||||
import android.app.usage.UsageEvents;
|
||||
import android.app.usage.UsageStatsManagerInternal;
|
||||
import android.content.BroadcastReceiver;
|
||||
@@ -224,6 +225,7 @@ public class NotificationManagerService extends SystemService {
|
||||
private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
|
||||
|
||||
private IActivityManager mAm;
|
||||
private IPackageManager mPackageManager;
|
||||
AudioManager mAudioManager;
|
||||
AudioManagerInternal mAudioManagerInternal;
|
||||
@Nullable StatusBarManagerInternal mStatusBar;
|
||||
@@ -718,10 +720,10 @@ public class NotificationManagerService extends SystemService {
|
||||
if (packageChanged) {
|
||||
// We cancel notifications for packages which have just been disabled
|
||||
try {
|
||||
final IPackageManager pm = AppGlobals.getPackageManager();
|
||||
final int enabled = pm.getApplicationEnabledSetting(pkgName,
|
||||
final int enabled = mPackageManager.getApplicationEnabledSetting(
|
||||
pkgName,
|
||||
changeUserId != UserHandle.USER_ALL ? changeUserId :
|
||||
UserHandle.USER_SYSTEM);
|
||||
UserHandle.USER_SYSTEM);
|
||||
if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
|
||||
|| enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
|
||||
cancelNotifications = false;
|
||||
@@ -884,6 +886,7 @@ public class NotificationManagerService extends SystemService {
|
||||
super(context);
|
||||
}
|
||||
|
||||
// TODO - replace these methods with a single VisibleForTesting constructor
|
||||
@VisibleForTesting
|
||||
void setAudioManager(AudioManager audioMananger) {
|
||||
mAudioManager = audioMananger;
|
||||
@@ -931,6 +934,17 @@ public class NotificationManagerService extends SystemService {
|
||||
mFallbackVibrationPattern = vibrationPattern;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setPackageManager(IPackageManager packageManager) {
|
||||
mPackageManager = packageManager;
|
||||
}
|
||||
|
||||
// TODO: This probably should not be mocked, it's an implementation detail.
|
||||
@VisibleForTesting
|
||||
void setRankingHelper(RankingHelper rankingHelper) {
|
||||
mRankingHelper = rankingHelper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
Resources resources = getContext().getResources();
|
||||
@@ -940,6 +954,7 @@ public class NotificationManagerService extends SystemService {
|
||||
DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
|
||||
|
||||
mAm = ActivityManager.getService();
|
||||
mPackageManager = AppGlobals.getPackageManager();
|
||||
mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
|
||||
mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
|
||||
mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
|
||||
@@ -1312,6 +1327,11 @@ public class NotificationManagerService extends SystemService {
|
||||
scheduleInterruptionFilterChanged(interruptionFilter);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
INotificationManager getBinderService() {
|
||||
return INotificationManager.Stub.asInterface(mService);
|
||||
}
|
||||
|
||||
private final IBinder mService = new INotificationManager.Stub() {
|
||||
// Toasts
|
||||
// ============================================================================
|
||||
@@ -1529,13 +1549,15 @@ public class NotificationManagerService extends SystemService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createNotificationChannel(String pkg, NotificationChannel channel) {
|
||||
public void createNotificationChannel(String pkg, NotificationChannel channel,
|
||||
IOnNotificationChannelCreatedListener listener) throws RemoteException {
|
||||
Preconditions.checkNotNull(channel);
|
||||
Preconditions.checkNotNull(channel.getId());
|
||||
Preconditions.checkNotNull(channel.getName());
|
||||
checkCallerIsSystemOrSameApp(pkg);
|
||||
mRankingHelper.createNotificationChannel(pkg, Binder.getCallingUid(), channel);
|
||||
savePolicyFile();
|
||||
listener.onNotificationChannelCreated(channel);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -3906,23 +3928,23 @@ public class NotificationManagerService extends SystemService {
|
||||
throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
|
||||
}
|
||||
|
||||
private static void checkCallerIsSystemOrSameApp(String pkg) {
|
||||
private void checkCallerIsSystemOrSameApp(String pkg) {
|
||||
if (isCallerSystem()) {
|
||||
return;
|
||||
}
|
||||
checkCallerIsSameApp(pkg);
|
||||
}
|
||||
|
||||
private static void checkCallerIsSameApp(String pkg) {
|
||||
private void checkCallerIsSameApp(String pkg) {
|
||||
final int uid = Binder.getCallingUid();
|
||||
try {
|
||||
ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
|
||||
ApplicationInfo ai = mPackageManager.getApplicationInfo(
|
||||
pkg, 0, UserHandle.getCallingUserId());
|
||||
if (ai == null) {
|
||||
throw new SecurityException("Unknown package " + pkg);
|
||||
}
|
||||
if (!UserHandle.isSameApp(ai.uid, uid)) {
|
||||
throw new SecurityException("Calling uid " + uid + " gave package"
|
||||
throw new SecurityException("Calling uid " + uid + " gave package "
|
||||
+ pkg + " which is owned by uid " + ai.uid);
|
||||
}
|
||||
} catch (RemoteException re) {
|
||||
@@ -4009,7 +4031,7 @@ public class NotificationManagerService extends SystemService {
|
||||
private boolean isPackageSuspendedForUser(String pkg, int uid) {
|
||||
int userId = UserHandle.getUserId(uid);
|
||||
try {
|
||||
return AppGlobals.getPackageManager().isPackageSuspendedForUser(pkg, userId);
|
||||
return mPackageManager.isPackageSuspendedForUser(pkg, userId);
|
||||
} catch (RemoteException re) {
|
||||
throw new SecurityException("Could not talk to package manager service");
|
||||
} catch (IllegalArgumentException ex) {
|
||||
@@ -4510,7 +4532,7 @@ public class NotificationManagerService extends SystemService {
|
||||
}
|
||||
|
||||
public String[] getRequestingPackages() throws RemoteException {
|
||||
final ParceledListSlice list = AppGlobals.getPackageManager()
|
||||
final ParceledListSlice list = mPackageManager
|
||||
.getPackagesHoldingPermissions(PERM, 0 /*flags*/,
|
||||
ActivityManager.getCurrentUser());
|
||||
final List<PackageInfo> pkgs = list.getList();
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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.notification;
|
||||
|
||||
import static junit.framework.Assert.fail;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.anyInt;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.INotificationManager;
|
||||
import android.app.IOnNotificationChannelCreatedListener;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.IPackageManager;
|
||||
import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class NotificationManagerServiceTest {
|
||||
private NotificationManagerService mNotificationManagerService;
|
||||
private INotificationManager mBinderService;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
final Context context = InstrumentationRegistry.getTargetContext();
|
||||
mNotificationManagerService = new NotificationManagerService(context);
|
||||
|
||||
// MockPackageManager - default returns ApplicationInfo with matching calling UID
|
||||
final IPackageManager mockPackageManager = mock(IPackageManager.class);
|
||||
final ApplicationInfo applicationInfo = new ApplicationInfo();
|
||||
applicationInfo.uid = Binder.getCallingUid();
|
||||
when(mockPackageManager.getApplicationInfo(any(), anyInt(), anyInt()))
|
||||
.thenReturn(applicationInfo);
|
||||
mNotificationManagerService.setPackageManager(mockPackageManager);
|
||||
|
||||
mNotificationManagerService.setRankingHelper(mock(RankingHelper.class));
|
||||
mNotificationManagerService.setHandler(new Handler(context.getMainLooper()));
|
||||
|
||||
// Tests call directly into the Binder.
|
||||
mBinderService = mNotificationManagerService.getBinderService();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateNotificationChannel_SuccessCallsListener() throws Exception {
|
||||
final NotificationChannel channel =
|
||||
new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT);
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
mBinderService.createNotificationChannel("test_pkg", channel,
|
||||
new IOnNotificationChannelCreatedListener.Stub() {
|
||||
@Override public void onNotificationChannelCreated(
|
||||
NotificationChannel channel) {
|
||||
latch.countDown();
|
||||
}});
|
||||
latch.await();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateNotificationChannel_FailureDoesNotCallListener() throws Exception {
|
||||
try {
|
||||
mBinderService.createNotificationChannel("test_pkg", null,
|
||||
new IOnNotificationChannelCreatedListener.Stub() {
|
||||
@Override public void onNotificationChannelCreated(
|
||||
NotificationChannel channel) {
|
||||
fail("Listener was triggered from failure.");
|
||||
}});
|
||||
fail("Exception should be thrown immediately.");
|
||||
} catch (NullPointerException e) {
|
||||
// pass
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user