Loading core/java/android/app/INotificationManager.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -44,6 +44,8 @@ interface INotificationManager void cancelAllNotifications(String pkg, int userId); void clearData(String pkg, int uid, boolean fromApp); // TODO: Replace parameter (ITransientNotification callback) with (CharSequence text) void enqueueTextToast(String pkg, ITransientNotification callback, int duration, int displayId); @UnsupportedAppUsage void enqueueToast(String pkg, ITransientNotification callback, int duration, int displayId); @UnsupportedAppUsage Loading core/java/android/widget/Toast.java +9 −1 Original line number Diff line number Diff line Loading @@ -100,6 +100,8 @@ public class Toast { @UnsupportedAppUsage int mDuration; View mNextView; // TODO(b/128611929): Remove this and check for null view when toast creation is in the system boolean mIsCustomToast = false; /** * Construct an empty Toast object. You must call {@link #setView} before you Loading Loading @@ -140,7 +142,11 @@ public class Toast { final int displayId = mContext.getDisplayId(); try { if (mIsCustomToast) { service.enqueueToast(pkg, tn, mDuration, displayId); } else { service.enqueueTextToast(pkg, tn, mDuration, displayId); } } catch (RemoteException e) { // Empty } Loading @@ -160,6 +166,7 @@ public class Toast { * @see #getView */ public void setView(View view) { mIsCustomToast = true; mNextView = view; } Loading @@ -168,6 +175,7 @@ public class Toast { * @see #setView */ public View getView() { mIsCustomToast = true; return mNextView; } Loading services/core/Android.bp +4 −0 Original line number Diff line number Diff line Loading @@ -118,6 +118,10 @@ java_library_static { "dnsresolver_aidl_interface-V2-java", "netd_event_listener_interface-java", ], plugins: [ "compat-changeid-annotation-processor", ], } java_genrule { Loading services/core/java/com/android/server/notification/NotificationManagerService.java +64 −10 Original line number Diff line number Diff line Loading @@ -131,6 +131,7 @@ import android.app.role.RoleManager; import android.app.usage.UsageEvents; import android.app.usage.UsageStatsManagerInternal; import android.companion.ICompanionDeviceManager; import android.compat.annotation.ChangeId; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentProvider; Loading Loading @@ -216,6 +217,7 @@ import android.widget.Toast; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.compat.IPlatformCompat; import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; Loading @@ -236,6 +238,7 @@ import com.android.server.EventLogTags; import com.android.server.IoThread; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.UiThread; import com.android.server.lights.Light; import com.android.server.lights.LightsManager; import com.android.server.notification.ManagedServices.ManagedServiceInfo; Loading Loading @@ -355,6 +358,15 @@ public class NotificationManagerService extends SystemService { private static final int REQUEST_CODE_TIMEOUT = 1; private static final String SCHEME_TIMEOUT = "timeout"; private static final String EXTRA_KEY = "key"; /** * Apps targeting R+ that post custom toasts in the background will have those blocked. Apps can * still post toasts created with {@link Toast#makeText(Context, CharSequence, int)} and its * variants while in the background. */ @ChangeId private static final long CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK = 128611929L; private IActivityManager mAm; private ActivityManager mActivityManager; private IPackageManager mPackageManager; Loading @@ -372,9 +384,11 @@ public class NotificationManagerService extends SystemService { private UriGrantsManagerInternal mUgmInternal; private RoleObserver mRoleObserver; private UserManager mUm; private IPlatformCompat mPlatformCompat; final IBinder mForegroundToken = new Binder(); private WorkerHandler mHandler; private Handler mUiHandler; private final HandlerThread mRankingThread = new HandlerThread("ranker", Process.THREAD_PRIORITY_BACKGROUND); Loading Loading @@ -1782,8 +1796,11 @@ public class NotificationManagerService extends SystemService { ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER)); mDpm = dpm; mUm = userManager; mPlatformCompat = IPlatformCompat.Stub.asInterface( ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); mHandler = new WorkerHandler(looper); mUiHandler = new Handler(UiThread.get().getLooper()); String[] extractorNames; try { extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors); Loading Loading @@ -2449,10 +2466,20 @@ public class NotificationManagerService extends SystemService { // Toasts // ============================================================================ @Override public void enqueueTextToast(String pkg, ITransientNotification callback, int duration, int displayId) { enqueueToast(pkg, callback, duration, displayId, false); } @Override public void enqueueToast(String pkg, ITransientNotification callback, int duration, int displayId) { int displayId) { enqueueToast(pkg, callback, duration, displayId, true); } private void enqueueToast(String pkg, ITransientNotification callback, int duration, int displayId, boolean isCustomToast) { if (DBG) { Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback + " duration=" + duration + " displayId=" + displayId); Loading @@ -2464,16 +2491,22 @@ public class NotificationManagerService extends SystemService { } final int callingUid = Binder.getCallingUid(); final UserHandle callingUser = Binder.getCallingUserHandle(); final boolean isSystemToast = isCallerSystemOrPhone() || PackageManagerService.PLATFORM_PACKAGE_NAME.equals(pkg); final boolean isPackageSuspended = isPackagePaused(pkg); final boolean notificationsDisabledForPackage = !areNotificationsEnabledForPackage(pkg, callingUid); final boolean appIsForeground; long callingIdentity = Binder.clearCallingIdentity(); try { final boolean appIsForeground = mActivityManager.getUidImportance(callingUid) appIsForeground = mActivityManager.getUidImportance(callingUid) == IMPORTANCE_FOREGROUND; } finally { Binder.restoreCallingIdentity(callingIdentity); } if (ENABLE_BLOCKED_TOASTS && !isSystemToast && ((notificationsDisabledForPackage && !appIsForeground) || isPackageSuspended)) { Slog.e(TAG, "Suppressing toast from package " + pkg Loading @@ -2481,8 +2514,29 @@ public class NotificationManagerService extends SystemService { : " by user request.")); return; } } finally { Binder.restoreCallingIdentity(callingIdentity); if (isCustomToast && !appIsForeground && !isSystemToast) { boolean block; try { block = mPlatformCompat.isChangeEnabledByPackageName( CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK, pkg, callingUser.getIdentifier()); } catch (RemoteException e) { // Shouldn't happen have since it's a local local Slog.e(TAG, "Unexpected exception while checking block background custom toasts" + " change", e); block = false; } if (block) { // TODO(b/144152069): Remove informative toast mUiHandler.post(() -> Toast.makeText(getContext(), "Background custom toast blocked for package " + pkg + ".\n" + "See go/r-toast-block.", Toast.LENGTH_SHORT).show()); Slog.w(TAG, "Blocking custom toast from package " + pkg + " due to package not in the foreground"); return; } } synchronized (mToastQueue) { Loading Loading
core/java/android/app/INotificationManager.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -44,6 +44,8 @@ interface INotificationManager void cancelAllNotifications(String pkg, int userId); void clearData(String pkg, int uid, boolean fromApp); // TODO: Replace parameter (ITransientNotification callback) with (CharSequence text) void enqueueTextToast(String pkg, ITransientNotification callback, int duration, int displayId); @UnsupportedAppUsage void enqueueToast(String pkg, ITransientNotification callback, int duration, int displayId); @UnsupportedAppUsage Loading
core/java/android/widget/Toast.java +9 −1 Original line number Diff line number Diff line Loading @@ -100,6 +100,8 @@ public class Toast { @UnsupportedAppUsage int mDuration; View mNextView; // TODO(b/128611929): Remove this and check for null view when toast creation is in the system boolean mIsCustomToast = false; /** * Construct an empty Toast object. You must call {@link #setView} before you Loading Loading @@ -140,7 +142,11 @@ public class Toast { final int displayId = mContext.getDisplayId(); try { if (mIsCustomToast) { service.enqueueToast(pkg, tn, mDuration, displayId); } else { service.enqueueTextToast(pkg, tn, mDuration, displayId); } } catch (RemoteException e) { // Empty } Loading @@ -160,6 +166,7 @@ public class Toast { * @see #getView */ public void setView(View view) { mIsCustomToast = true; mNextView = view; } Loading @@ -168,6 +175,7 @@ public class Toast { * @see #setView */ public View getView() { mIsCustomToast = true; return mNextView; } Loading
services/core/Android.bp +4 −0 Original line number Diff line number Diff line Loading @@ -118,6 +118,10 @@ java_library_static { "dnsresolver_aidl_interface-V2-java", "netd_event_listener_interface-java", ], plugins: [ "compat-changeid-annotation-processor", ], } java_genrule { Loading
services/core/java/com/android/server/notification/NotificationManagerService.java +64 −10 Original line number Diff line number Diff line Loading @@ -131,6 +131,7 @@ import android.app.role.RoleManager; import android.app.usage.UsageEvents; import android.app.usage.UsageStatsManagerInternal; import android.companion.ICompanionDeviceManager; import android.compat.annotation.ChangeId; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentProvider; Loading Loading @@ -216,6 +217,7 @@ import android.widget.Toast; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.compat.IPlatformCompat; import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; Loading @@ -236,6 +238,7 @@ import com.android.server.EventLogTags; import com.android.server.IoThread; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.UiThread; import com.android.server.lights.Light; import com.android.server.lights.LightsManager; import com.android.server.notification.ManagedServices.ManagedServiceInfo; Loading Loading @@ -355,6 +358,15 @@ public class NotificationManagerService extends SystemService { private static final int REQUEST_CODE_TIMEOUT = 1; private static final String SCHEME_TIMEOUT = "timeout"; private static final String EXTRA_KEY = "key"; /** * Apps targeting R+ that post custom toasts in the background will have those blocked. Apps can * still post toasts created with {@link Toast#makeText(Context, CharSequence, int)} and its * variants while in the background. */ @ChangeId private static final long CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK = 128611929L; private IActivityManager mAm; private ActivityManager mActivityManager; private IPackageManager mPackageManager; Loading @@ -372,9 +384,11 @@ public class NotificationManagerService extends SystemService { private UriGrantsManagerInternal mUgmInternal; private RoleObserver mRoleObserver; private UserManager mUm; private IPlatformCompat mPlatformCompat; final IBinder mForegroundToken = new Binder(); private WorkerHandler mHandler; private Handler mUiHandler; private final HandlerThread mRankingThread = new HandlerThread("ranker", Process.THREAD_PRIORITY_BACKGROUND); Loading Loading @@ -1782,8 +1796,11 @@ public class NotificationManagerService extends SystemService { ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER)); mDpm = dpm; mUm = userManager; mPlatformCompat = IPlatformCompat.Stub.asInterface( ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); mHandler = new WorkerHandler(looper); mUiHandler = new Handler(UiThread.get().getLooper()); String[] extractorNames; try { extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors); Loading Loading @@ -2449,10 +2466,20 @@ public class NotificationManagerService extends SystemService { // Toasts // ============================================================================ @Override public void enqueueTextToast(String pkg, ITransientNotification callback, int duration, int displayId) { enqueueToast(pkg, callback, duration, displayId, false); } @Override public void enqueueToast(String pkg, ITransientNotification callback, int duration, int displayId) { int displayId) { enqueueToast(pkg, callback, duration, displayId, true); } private void enqueueToast(String pkg, ITransientNotification callback, int duration, int displayId, boolean isCustomToast) { if (DBG) { Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback + " duration=" + duration + " displayId=" + displayId); Loading @@ -2464,16 +2491,22 @@ public class NotificationManagerService extends SystemService { } final int callingUid = Binder.getCallingUid(); final UserHandle callingUser = Binder.getCallingUserHandle(); final boolean isSystemToast = isCallerSystemOrPhone() || PackageManagerService.PLATFORM_PACKAGE_NAME.equals(pkg); final boolean isPackageSuspended = isPackagePaused(pkg); final boolean notificationsDisabledForPackage = !areNotificationsEnabledForPackage(pkg, callingUid); final boolean appIsForeground; long callingIdentity = Binder.clearCallingIdentity(); try { final boolean appIsForeground = mActivityManager.getUidImportance(callingUid) appIsForeground = mActivityManager.getUidImportance(callingUid) == IMPORTANCE_FOREGROUND; } finally { Binder.restoreCallingIdentity(callingIdentity); } if (ENABLE_BLOCKED_TOASTS && !isSystemToast && ((notificationsDisabledForPackage && !appIsForeground) || isPackageSuspended)) { Slog.e(TAG, "Suppressing toast from package " + pkg Loading @@ -2481,8 +2514,29 @@ public class NotificationManagerService extends SystemService { : " by user request.")); return; } } finally { Binder.restoreCallingIdentity(callingIdentity); if (isCustomToast && !appIsForeground && !isSystemToast) { boolean block; try { block = mPlatformCompat.isChangeEnabledByPackageName( CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK, pkg, callingUser.getIdentifier()); } catch (RemoteException e) { // Shouldn't happen have since it's a local local Slog.e(TAG, "Unexpected exception while checking block background custom toasts" + " change", e); block = false; } if (block) { // TODO(b/144152069): Remove informative toast mUiHandler.post(() -> Toast.makeText(getContext(), "Background custom toast blocked for package " + pkg + ".\n" + "See go/r-toast-block.", Toast.LENGTH_SHORT).show()); Slog.w(TAG, "Blocking custom toast from package " + pkg + " due to package not in the foreground"); return; } } synchronized (mToastQueue) { Loading