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