/* * Copyright 2011 Google Inc. * * 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.google.ipc.invalidation.ticl.android.c2dm; import com.google.common.base.Preconditions; import com.google.ipc.invalidation.external.client.SystemResources.Logger; import com.google.ipc.invalidation.external.client.android.service.AndroidLogger; import android.app.Service; import android.content.Intent; import org.json.JSONException; import org.json.JSONObject; /** * Represents a C2DM observer that gets notifications whenever the * application receives a C2DM message or something changes regarding C2DM registration status. * * An observer may have its own unique filter so that not all messages are dispatched to all * observers. */ public class C2DMObserver { /** Logger */ private static final Logger logger = AndroidLogger.forTag("C2DMObserver"); /** JSON key name for the observer class name string value */ private static final String KEY_CLASS = "class"; /** JSON key name for the filter field name string value */ private static final String KEY_FILTER_KEY = "filterKey"; /** JSON key name for the value field string value */ private static final String KEY_FILTER_VALUE = "filterValue"; /** JSON kye name for the handle wake lock boolean field */ private static final String KEY_HANDLE_WAKE_LOCK = "handleWakeLock"; /** Service class that handles messages for this observer */ private final Class<? extends Service> messageService; /** Select field name (or {@code null} if none) */ private final String selectKey; /** Select field value (or {@code null} if none) */ private final String selectValue; /** {@code true} if the observer handles the wake lock */ private final boolean handleWakeLock; /** * Creates a new observer using the state stored within the provided JSON object (normally * created by {@link #toJSON()}. */ static C2DMObserver createFromJSON(JSONObject json) { try { // Extract instance state value from the appropriate JSON fields. String canonicalClassString = json.getString(KEY_CLASS); Class<? extends Service> clazz = Class.forName(canonicalClassString).asSubclass(Service.class); String filterKey = json.has(KEY_FILTER_KEY) ? json.getString(KEY_FILTER_KEY) : null; String filterValue = json.has(KEY_FILTER_VALUE) ? json.getString(KEY_FILTER_VALUE) : null; Boolean handleWakeLock = json.has(KEY_HANDLE_WAKE_LOCK) && json.getBoolean(KEY_HANDLE_WAKE_LOCK); return new C2DMObserver(clazz, filterKey, filterValue, handleWakeLock); } catch (JSONException e) { logger.severe("Unable to parse observer. Source: %s", json); } catch (ClassNotFoundException e) { logger.severe("Unable to parse observer. Class not found. Source: %s", json); } return null; } /** * Creates a new observer from the extra values contained in the provided intent. */ static C2DMObserver createFromIntent(Intent intent) { String canonicalClassString = intent.getStringExtra(C2DMessaging.EXTRA_CANONICAL_CLASS); try { // Extract observer state from the intent built by the C2DM manager. Class<? extends Service> clazz = Class.forName(canonicalClassString).asSubclass(Service.class); String filterKey = intent.getStringExtra(C2DMessaging.EXTRA_FILTER_KEY); String filterValue = intent.getStringExtra(C2DMessaging.EXTRA_FILTER_VALUE); boolean handleWakeLock = intent.getBooleanExtra(C2DMessaging.EXTRA_HANDLE_WAKELOCK, false); return new C2DMObserver(clazz, filterKey, filterValue, handleWakeLock); } catch (ClassNotFoundException e) { logger.severe("Unable to register observer class %s", canonicalClassString); return null; } } /** * Creates a new observer for the provided service, selection criteria, and wake lock behavior. */ C2DMObserver(Class<? extends Service> messageService, String selectKey, String selectValue, boolean handleWakeLock) { Preconditions.checkNotNull(messageService); this.messageService = messageService; this.selectKey = selectKey; this.selectValue = selectValue; this.handleWakeLock = handleWakeLock; } /** * Returns the JSON object representation of the observer state. */ JSONObject toJSON() { try { JSONObject json = new JSONObject(); json.put(KEY_CLASS, messageService.getCanonicalName()); json.put(KEY_FILTER_KEY, selectKey); json.put(KEY_FILTER_VALUE, selectValue); json.put(KEY_HANDLE_WAKE_LOCK, handleWakeLock); return json; } catch (JSONException e) { logger.severe("Unable to create JSON object from observer %s", toString()); return null; } } /** * Returns {@code true} if the provided intent matches the selection criteria for this * observer. */ boolean matches(Intent intent) { if (selectKey == null) { return true; } if (intent.hasExtra(selectKey)) { return selectValue == null || selectValue.equals(intent.getStringExtra(selectKey)); } return false; } Class<?> getObserverClass() { return messageService; } String getFilterKey() { return selectKey; } String getFilterValue() { return selectValue; } boolean isHandleWakeLock() { return handleWakeLock; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } C2DMObserver that = (C2DMObserver) o; if (!messageService.equals(that.messageService)) { return false; } if (selectKey != null ? !selectKey.equals(that.selectKey) : that.selectKey != null) { return false; } if (selectValue != null ? !selectValue.equals(that.selectValue) : that.selectValue != null) { return false; } return handleWakeLock == that.handleWakeLock; } @Override public int hashCode() { int result = messageService.hashCode(); result = 31 * result + (selectKey != null ? selectKey.hashCode() : 0); result = 31 * result + (selectValue != null ? selectValue.hashCode() : 0); result = 31 * result + (handleWakeLock ? 1 : 0); return result; } @Override public String toString() { return "C2DMObserver{" + "mClass=" + messageService + ", mFilterKey='" + selectKey + '\'' + ", mFilterValue='" + selectValue + '\'' + ", mHandleWakeLock=" + handleWakeLock + '}'; } }