1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.notification;
18 
19 import android.companion.ICompanionDeviceManager;
20 import android.content.ComponentName;
21 import android.content.Context;
22 import android.service.notification.StatusBarNotification;
23 
24 import androidx.annotation.Nullable;
25 
26 import com.android.internal.logging.InstanceIdSequence;
27 import com.android.server.notification.ManagedServices.ManagedServiceInfo;
28 
29 import java.util.HashSet;
30 import java.util.Set;
31 
32 public class TestableNotificationManagerService extends NotificationManagerService {
33     int countSystemChecks = 0;
34     boolean isSystemUid = true;
35     boolean isSystemAppId = true;
36     int countLogSmartSuggestionsVisible = 0;
37     Set<Integer> mChannelToastsSent = new HashSet<>();
38 
39     String stringArrayResourceValue;
40     @Nullable
41     NotificationAssistantAccessGrantedCallback mNotificationAssistantAccessGrantedCallback;
42 
43     @Nullable
44     Boolean mIsVisibleToListenerReturnValue = null;
45 
46     ComponentPermissionChecker permissionChecker;
47 
48     private static class SensitiveLog {
49         public boolean hasPosted;
50         public boolean hasSensitiveContent;
51         public long lifetime;
52     }
53     public SensitiveLog lastSensitiveLog = null;
54 
TestableNotificationManagerService(Context context, NotificationRecordLogger logger, InstanceIdSequence notificationInstanceIdSequence)55     TestableNotificationManagerService(Context context, NotificationRecordLogger logger,
56             InstanceIdSequence notificationInstanceIdSequence) {
57         super(context, logger, notificationInstanceIdSequence);
58     }
59 
getRankingHelper()60     RankingHelper getRankingHelper() {
61         return mRankingHelper;
62     }
63 
64     /**
65      * Sets {@link #isSystemUid} and {@link #isSystemAppId} to {@code false}, so that calls to NMS
66      * methods don't succeed {@link #isCallingUidSystem()} and similar checks.
67      */
setCallerIsNormalPackage()68     void setCallerIsNormalPackage() {
69         isSystemUid = false;
70         isSystemAppId = false;
71     }
72 
73     @Override
isCallingUidSystem()74     protected boolean isCallingUidSystem() {
75         countSystemChecks++;
76         return isSystemUid;
77     }
78 
79     @Override
isCallingAppIdSystem()80     protected boolean isCallingAppIdSystem() {
81         countSystemChecks++;
82         return isSystemUid || isSystemAppId;
83     }
84 
85     @Override
isCallerSystemOrPhone()86     protected boolean isCallerSystemOrPhone() {
87         countSystemChecks++;
88         return isSystemUid || isSystemAppId;
89     }
90 
91     @Override
isCallerSystemOrSystemUi()92     protected boolean isCallerSystemOrSystemUi() {
93         countSystemChecks++;
94         return isSystemUid || isSystemAppId;
95     }
96 
97     @Override
getCompanionManager()98     protected ICompanionDeviceManager getCompanionManager() {
99         return null;
100     }
101 
102     @Override
reportUserInteraction(NotificationRecord r)103     protected void reportUserInteraction(NotificationRecord r) {
104         return;
105     }
106 
107     @Override
handleSavePolicyFile()108     protected void handleSavePolicyFile() {
109         return;
110     }
111 
112     @Override
logSmartSuggestionsVisible(NotificationRecord r, int notificationLocation)113     void logSmartSuggestionsVisible(NotificationRecord r, int notificationLocation) {
114         super.logSmartSuggestionsVisible(r, notificationLocation);
115         countLogSmartSuggestionsVisible++;
116     }
117 
118     @Override
setNotificationAssistantAccessGrantedForUserInternal( ComponentName assistant, int userId, boolean granted, boolean userSet)119     protected void setNotificationAssistantAccessGrantedForUserInternal(
120             ComponentName assistant, int userId, boolean granted, boolean userSet) {
121         if (mNotificationAssistantAccessGrantedCallback != null) {
122             mNotificationAssistantAccessGrantedCallback.onGranted(assistant, userId, granted,
123                     userSet);
124             return;
125         }
126         super.setNotificationAssistantAccessGrantedForUserInternal(assistant, userId, granted,
127                 userSet);
128     }
129 
130     @Override
getStringArrayResource(int key)131     protected String[] getStringArrayResource(int key) {
132         return new String[] {stringArrayResourceValue};
133     }
134 
setStringArrayResourceValue(String value)135     protected void setStringArrayResourceValue(String value) {
136         stringArrayResourceValue = value;
137     }
138 
setNotificationAssistantAccessGrantedCallback( @ullable NotificationAssistantAccessGrantedCallback callback)139     void setNotificationAssistantAccessGrantedCallback(
140             @Nullable NotificationAssistantAccessGrantedCallback callback) {
141         this.mNotificationAssistantAccessGrantedCallback = callback;
142     }
143 
144     interface NotificationAssistantAccessGrantedCallback {
onGranted(ComponentName assistant, int userId, boolean granted, boolean userSet)145         void onGranted(ComponentName assistant, int userId, boolean granted, boolean userSet);
146     }
147 
148     @Override
doChannelWarningToast(int uid, CharSequence toastText)149     protected void doChannelWarningToast(int uid, CharSequence toastText) {
150         mChannelToastsSent.add(uid);
151     }
152 
153     // Helper method for testing behavior when turning on/off the review permissions notification.
setShowReviewPermissionsNotification(boolean setting)154     protected void setShowReviewPermissionsNotification(boolean setting) {
155         mShowReviewPermissionsNotification = setting;
156     }
157 
setIsVisibleToListenerReturnValue(boolean value)158     protected void setIsVisibleToListenerReturnValue(boolean value) {
159         mIsVisibleToListenerReturnValue = value;
160     }
161 
162     @Override
isVisibleToListener(StatusBarNotification sbn, int notificationType, ManagedServiceInfo listener)163     boolean isVisibleToListener(StatusBarNotification sbn, int notificationType,
164             ManagedServiceInfo listener) {
165         if (mIsVisibleToListenerReturnValue != null) {
166             return mIsVisibleToListenerReturnValue;
167         }
168         return super.isVisibleToListener(sbn, notificationType, listener);
169     }
170 
171     @Override
checkComponentPermission(String permission, int uid, int owningUid, boolean exported)172     protected int checkComponentPermission(String permission, int uid, int owningUid,
173             boolean exported) {
174         return permissionChecker.check(permission, uid, owningUid, exported);
175     }
176 
177     @Override
logSensitiveAdjustmentReceived(boolean hasPosted, boolean hasSensitiveContent, int lifetimeMs)178     protected void logSensitiveAdjustmentReceived(boolean hasPosted, boolean hasSensitiveContent,
179             int lifetimeMs) {
180         lastSensitiveLog = new SensitiveLog();
181         lastSensitiveLog.hasPosted = hasPosted;
182         lastSensitiveLog.hasSensitiveContent = hasSensitiveContent;
183         lastSensitiveLog.lifetime = lifetimeMs;
184     }
185 
186     public class StrongAuthTrackerFake extends NotificationManagerService.StrongAuthTracker {
187         private int mGetStrongAuthForUserReturnValue = 0;
StrongAuthTrackerFake(Context context)188         StrongAuthTrackerFake(Context context) {
189             super(context);
190         }
191 
setGetStrongAuthForUserReturnValue(int val)192         public void setGetStrongAuthForUserReturnValue(int val) {
193             mGetStrongAuthForUserReturnValue = val;
194         }
195 
196         @Override
getStrongAuthForUser(int userId)197         public int getStrongAuthForUser(int userId) {
198             return mGetStrongAuthForUserReturnValue;
199         }
200     }
201 
checkLastSensitiveLog(boolean hasPosted, boolean hasSensitive, int lifetime)202     public boolean checkLastSensitiveLog(boolean hasPosted, boolean hasSensitive, int lifetime) {
203         if (lastSensitiveLog == null) {
204             return false;
205         }
206         return hasPosted == lastSensitiveLog.hasPosted
207                 && hasSensitive == lastSensitiveLog.hasSensitiveContent
208                 && lifetime == lastSensitiveLog.lifetime;
209     }
210 
211     public interface ComponentPermissionChecker {
check(String permission, int uid, int owningUid, boolean exported)212         int check(String permission, int uid, int owningUid, boolean exported);
213     }
214 }
215