1 /* 2 * Copyright (C) 2013 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 package com.android.cts.verifier.notifications; 17 18 import android.app.Activity; 19 import android.content.BroadcastReceiver; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.IntentFilter; 23 import android.os.Bundle; 24 import android.service.notification.NotificationListenerService; 25 import android.service.notification.StatusBarNotification; 26 import android.util.ArrayMap; 27 import android.util.Log; 28 29 import org.json.JSONException; 30 import org.json.JSONObject; 31 32 import java.lang.reflect.InvocationTargetException; 33 import java.util.ArrayList; 34 import java.util.HashSet; 35 import java.util.List; 36 import java.util.Set; 37 38 public class MockListener extends NotificationListenerService { 39 static final String TAG = "MockListener"; 40 41 static final String SERVICE_BASE = "android.service.notification.cts."; 42 static final String SERVICE_CHECK = SERVICE_BASE + "SERVICE_CHECK"; 43 static final String SERVICE_POSTED = SERVICE_BASE + "SERVICE_POSTED"; 44 static final String SERVICE_PAYLOADS = SERVICE_BASE + "SERVICE_PAYLOADS"; 45 static final String SERVICE_REMOVED = SERVICE_BASE + "SERVICE_REMOVED"; 46 static final String SERVICE_RESET = SERVICE_BASE + "SERVICE_RESET"; 47 static final String SERVICE_CLEAR_ONE = SERVICE_BASE + "SERVICE_CLEAR_ONE"; 48 static final String SERVICE_CLEAR_ALL = SERVICE_BASE + "SERVICE_CLEAR_ALL"; 49 public static final String SERVICE_ORDER = SERVICE_BASE + "SERVICE_ORDER"; 50 public static final String SERVICE_DND = SERVICE_BASE + "SERVICE_DND"; 51 52 static final String EXTRA_PAYLOAD = "PAYLOAD"; 53 static final String EXTRA_INT = "INT"; 54 static final String EXTRA_TAG = "TAG"; 55 static final String EXTRA_CODE = "CODE"; 56 57 static final int RESULT_TIMEOUT = Activity.RESULT_FIRST_USER; 58 static final int RESULT_NO_SERVER = Activity.RESULT_FIRST_USER + 1; 59 60 public static final String JSON_FLAGS = "flag"; 61 public static final String JSON_ICON = "icon"; 62 public static final String JSON_ID = "id"; 63 public static final String JSON_PACKAGE = "pkg"; 64 public static final String JSON_WHEN = "when"; 65 public static final String JSON_TAG = "tag"; 66 public static final String JSON_RANK = "rank"; 67 public static final String JSON_AMBIENT = "ambient"; 68 public static final String JSON_MATCHES_ZEN_FILTER = "matches_zen_filter"; 69 70 private ArrayList<String> mPosted = new ArrayList<String>(); 71 private ArrayMap<String, JSONObject> mNotifications = new ArrayMap<>(); 72 private ArrayMap<String, String> mNotificationKeys = new ArrayMap<>(); 73 private ArrayList<String> mRemoved = new ArrayList<String>(); 74 private ArrayList<String> mOrder = new ArrayList<>(); 75 private Set<String> mTestPackages = new HashSet<>(); 76 private BroadcastReceiver mReceiver; 77 private int mDND = -1; 78 79 @Override 80 public void onCreate() { 81 super.onCreate(); 82 Log.d(TAG, "created"); 83 84 mTestPackages.add("com.android.cts.verifier"); 85 86 mPosted = new ArrayList<String>(); 87 mRemoved = new ArrayList<String>(); 88 89 mReceiver = new BroadcastReceiver() { 90 @Override 91 public void onReceive(Context context, Intent intent) { 92 String action = intent.getAction(); 93 if (SERVICE_CHECK.equals(action)) { 94 Log.d(TAG, "SERVICE_CHECK"); 95 setResultCode(Activity.RESULT_OK); 96 } else if (SERVICE_POSTED.equals(action)) { 97 Log.d(TAG, "SERVICE_POSTED"); 98 Bundle bundle = new Bundle(); 99 bundle.putStringArrayList(EXTRA_PAYLOAD, mPosted); 100 setResultExtras(bundle); 101 setResultCode(Activity.RESULT_OK); 102 } else if (SERVICE_DND.equals(action)) { 103 Log.d(TAG, "SERVICE_DND"); 104 Bundle bundle = new Bundle(); 105 bundle.putInt(EXTRA_INT, mDND); 106 setResultExtras(bundle); 107 setResultCode(Activity.RESULT_OK); 108 } else if (SERVICE_ORDER.equals(action)) { 109 Log.d(TAG, "SERVICE_ORDER"); 110 Bundle bundle = new Bundle(); 111 bundle.putStringArrayList(EXTRA_PAYLOAD, mOrder); 112 setResultExtras(bundle); 113 setResultCode(Activity.RESULT_OK); 114 } else if (SERVICE_PAYLOADS.equals(action)) { 115 Log.d(TAG, "SERVICE_PAYLOADS"); 116 Bundle bundle = new Bundle(); 117 ArrayList<String> payloadData = new ArrayList<>(mNotifications.size()); 118 for (JSONObject payload: mNotifications.values()) { 119 payloadData.add(payload.toString()); 120 } 121 bundle.putStringArrayList(EXTRA_PAYLOAD, payloadData); 122 setResultExtras(bundle); 123 setResultCode(Activity.RESULT_OK); 124 } else if (SERVICE_REMOVED.equals(action)) { 125 Log.d(TAG, "SERVICE_REMOVED"); 126 Bundle bundle = new Bundle(); 127 bundle.putStringArrayList(EXTRA_PAYLOAD, mRemoved); 128 setResultExtras(bundle); 129 setResultCode(Activity.RESULT_OK); 130 } else if (SERVICE_CLEAR_ONE.equals(action)) { 131 Log.d(TAG, "SERVICE_CLEAR_ONE"); 132 String tag = intent.getStringExtra(EXTRA_TAG); 133 String key = mNotificationKeys.get(tag); 134 if (key != null) { 135 MockListener.this.cancelNotification(key); 136 } else { 137 Log.w(TAG, "Notification does not exist: " + tag); 138 } 139 } else if (SERVICE_CLEAR_ALL.equals(action)) { 140 Log.d(TAG, "SERVICE_CLEAR_ALL"); 141 MockListener.this.cancelAllNotifications(); 142 } else if (SERVICE_RESET.equals(action)) { 143 Log.d(TAG, "SERVICE_RESET"); 144 resetData(); 145 } else { 146 Log.w(TAG, "unknown action"); 147 setResultCode(Activity.RESULT_CANCELED); 148 } 149 } 150 }; 151 IntentFilter filter = new IntentFilter(); 152 filter.addAction(SERVICE_CHECK); 153 filter.addAction(SERVICE_DND); 154 filter.addAction(SERVICE_POSTED); 155 filter.addAction(SERVICE_ORDER); 156 filter.addAction(SERVICE_PAYLOADS); 157 filter.addAction(SERVICE_REMOVED); 158 filter.addAction(SERVICE_CLEAR_ONE); 159 filter.addAction(SERVICE_CLEAR_ALL); 160 filter.addAction(SERVICE_RESET); 161 registerReceiver(mReceiver, filter); 162 } 163 164 @Override 165 public void onDestroy() { 166 super.onDestroy(); 167 unregisterReceiver(mReceiver); 168 mReceiver = null; 169 Log.d(TAG, "destroyed"); 170 } 171 172 @Override 173 public void onListenerConnected() { 174 super.onListenerConnected(); 175 mDND = getCurrentInterruptionFilter(); 176 Log.d(TAG, "initial value of CurrentInterruptionFilter is " + mDND); 177 } 178 179 @Override 180 public void onInterruptionFilterChanged(int interruptionFilter) { 181 super.onInterruptionFilterChanged(interruptionFilter); 182 mDND = interruptionFilter; 183 Log.d(TAG, "value of CurrentInterruptionFilter changed to " + mDND); 184 } 185 186 public void resetData() { 187 mPosted.clear(); 188 mNotifications.clear(); 189 mRemoved.clear(); 190 mOrder.clear(); 191 } 192 193 @Override 194 public void onNotificationRankingUpdate(RankingMap rankingMap) { 195 String[] orderedKeys = rankingMap.getOrderedKeys(); 196 mOrder.clear(); 197 Ranking rank = new Ranking(); 198 for( int i = 0; i < orderedKeys.length; i++) { 199 String key = orderedKeys[i]; 200 mOrder.add(key); 201 rankingMap.getRanking(key, rank); 202 JSONObject note = mNotifications.get(key); 203 if (note != null) { 204 try { 205 note.put(JSON_RANK, rank.getRank()); 206 note.put(JSON_AMBIENT, rank.isAmbient()); 207 note.put(JSON_MATCHES_ZEN_FILTER, rank.matchesInterruptionFilter()); 208 } catch (JSONException e) { 209 Log.e(TAG, "failed to pack up notification payload", e); 210 } 211 } 212 } 213 } 214 215 @Override 216 public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) { 217 if (!mTestPackages.contains(sbn.getPackageName())) { return; } 218 Log.d(TAG, "posted: " + sbn.getTag()); 219 mPosted.add(sbn.getTag()); 220 JSONObject notification = new JSONObject(); 221 try { 222 notification.put(JSON_TAG, sbn.getTag()); 223 notification.put(JSON_ID, sbn.getId()); 224 notification.put(JSON_PACKAGE, sbn.getPackageName()); 225 notification.put(JSON_WHEN, sbn.getNotification().when); 226 notification.put(JSON_ICON, sbn.getNotification().icon); 227 notification.put(JSON_FLAGS, sbn.getNotification().flags); 228 mNotifications.put(sbn.getKey(), notification); 229 mNotificationKeys.put(sbn.getTag(), sbn.getKey()); 230 } catch (JSONException e) { 231 Log.e(TAG, "failed to pack up notification payload", e); 232 } 233 onNotificationRankingUpdate(rankingMap); 234 } 235 236 @Override 237 public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap) { 238 Log.d(TAG, "removed: " + sbn.getTag()); 239 mRemoved.add(sbn.getTag()); 240 mNotifications.remove(sbn.getKey()); 241 onNotificationRankingUpdate(rankingMap); 242 mNotificationKeys.remove(sbn.getTag()); 243 } 244 245 public static void resetListenerData(Context context) { 246 sendCommand(context, SERVICE_RESET, null, 0); 247 } 248 249 public static void probeListenerStatus(Context context, StatusCatcher catcher) { 250 requestStatus(context, SERVICE_CHECK, catcher); 251 } 252 253 public static void probeFilter(Context context, IntegerResultCatcher catcher) { 254 requestIntegerResult(context, SERVICE_DND, catcher); 255 } 256 257 public static void probeListenerPosted(Context context, StringListResultCatcher catcher) { 258 requestStringListResult(context, SERVICE_POSTED, catcher); 259 } 260 261 public static void probeListenerOrder(Context context, StringListResultCatcher catcher) { 262 requestStringListResult(context, SERVICE_ORDER, catcher); 263 } 264 265 public static void probeListenerPayloads(Context context, StringListResultCatcher catcher) { 266 requestStringListResult(context, SERVICE_PAYLOADS, catcher); 267 } 268 269 public static void probeListenerRemoved(Context context, StringListResultCatcher catcher) { 270 requestStringListResult(context, SERVICE_REMOVED, catcher); 271 } 272 273 public static void clearOne(Context context, String tag, int code) { 274 sendCommand(context, SERVICE_CLEAR_ONE, tag, code); 275 } 276 277 public static void clearAll(Context context) { 278 sendCommand(context, SERVICE_CLEAR_ALL, null, 0); 279 } 280 281 private static void sendCommand(Context context, String action, String tag, int code) { 282 Intent broadcast = new Intent(action); 283 if (tag != null) { 284 broadcast.putExtra(EXTRA_TAG, tag); 285 broadcast.putExtra(EXTRA_CODE, code); 286 } 287 context.sendBroadcast(broadcast); 288 } 289 290 public abstract static class StatusCatcher extends BroadcastReceiver { 291 @Override 292 public void onReceive(Context context, Intent intent) { 293 accept(Integer.valueOf(getResultCode())); 294 } 295 296 abstract public void accept(int result); 297 } 298 299 private static void requestStatus(Context context, String action, 300 StatusCatcher catcher) { 301 Intent broadcast = new Intent(action); 302 context.sendOrderedBroadcast(broadcast, null, catcher, null, RESULT_NO_SERVER, null, null); 303 } 304 305 public abstract static class IntegerResultCatcher extends BroadcastReceiver { 306 @Override 307 public void onReceive(Context context, Intent intent) { 308 accept(getResultExtras(true).getInt(EXTRA_INT, -1)); 309 } 310 311 abstract public void accept(int result); 312 } 313 314 private static void requestIntegerResult(Context context, String action, 315 IntegerResultCatcher catcher) { 316 Intent broadcast = new Intent(action); 317 context.sendOrderedBroadcast(broadcast, null, catcher, null, RESULT_NO_SERVER, null, null); 318 } 319 320 public abstract static class StringListResultCatcher extends BroadcastReceiver { 321 @Override 322 public void onReceive(Context context, Intent intent) { 323 accept(getResultExtras(true).getStringArrayList(EXTRA_PAYLOAD)); 324 } 325 326 abstract public void accept(List<String> result); 327 } 328 329 private static void requestStringListResult(Context context, String action, 330 StringListResultCatcher catcher) { 331 Intent broadcast = new Intent(action); 332 context.sendOrderedBroadcast(broadcast, null, catcher, null, RESULT_NO_SERVER, null, null); 333 } 334 } 335