/* * 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.android2; import com.google.common.base.Preconditions; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import java.util.HashMap; import java.util.Map; /** * Interface to the {@code AndroidManifest.xml} that provides access to the configuration data * required by the Android Ticl. * */ public class AndroidTiclManifest { /** * Cache of {@link ApplicationMetadata} to avoid repeatedly scanning manifest. The key is the * package name for the context. */ private static final Map<String, ApplicationMetadata> applicationMetadataCache = new HashMap<String, ApplicationMetadata>(); /** Application metadata from the Android manifest. */ private final ApplicationMetadata metadata; public AndroidTiclManifest(Context context) { metadata = createApplicationMetadata(Preconditions.checkNotNull(context)); } /** Returns the name of the class implementing the Ticl service. */ public String getTiclServiceClass() { return metadata.ticlServiceClass; } /** Returns the name of the class on which listener events will be invoked. */ String getListenerClass() { return metadata.listenerClass; } /** Returns the name of the class implementing the invalidation listener intent service. */ public String getListenerServiceClass() { return metadata.listenerServiceClass; } /** * If it has not already been cached for the given {@code context}, creates and caches application * metadata from the manifest. */ private static ApplicationMetadata createApplicationMetadata(Context context) { synchronized (applicationMetadataCache) { String packageName = context.getPackageName(); ApplicationMetadata metadata = applicationMetadataCache.get(packageName); if (metadata == null) { metadata = new ApplicationMetadata(context); applicationMetadataCache.put(packageName, metadata); } return metadata; } } /** Application metadata for a specific context. */ private static final class ApplicationMetadata { /** * Name of the {@code <application>} metadata element whose value gives the Java class that * implements the application {@code InvalidationListener}. Must be set if * {@link #LISTENER_SERVICE_NAME_KEY} is not set. */ private static final String LISTENER_NAME_KEY = "ipc.invalidation.ticl.listener_class"; /** * Name of the {@code <application>} metadata element whose value gives the Java class that * implements the Ticl service. Should only be set in tests. */ private static final String TICL_SERVICE_NAME_KEY = "ipc.invalidation.ticl.service_class"; /** * Name of the {@code <application>} metadata element whose value gives the Java class that * implements the application's invalidation listener intent service. */ private static final String LISTENER_SERVICE_NAME_KEY = "ipc.invalidation.ticl.listener_service_class"; /** Default values returned if not overriden by the manifest file. */ private static final Map<String, String> DEFAULTS = new HashMap<String, String>(); static { DEFAULTS.put(TICL_SERVICE_NAME_KEY, "com.google.ipc.invalidation.ticl.android2.TiclService"); DEFAULTS.put(LISTENER_NAME_KEY, ""); DEFAULTS.put(LISTENER_SERVICE_NAME_KEY, "com.google.ipc.invalidation.ticl.android2.AndroidInvalidationListenerStub"); } private final String ticlServiceClass; private final String listenerClass; private final String listenerServiceClass; ApplicationMetadata(Context context) { ApplicationInfo appInfo; try { // Read metadata from manifest.xml appInfo = context.getPackageManager() .getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA); } catch (NameNotFoundException exception) { throw new RuntimeException("Cannot read own application info", exception); } ticlServiceClass = readApplicationMetadata(appInfo, TICL_SERVICE_NAME_KEY); listenerClass = readApplicationMetadata(appInfo, LISTENER_NAME_KEY); listenerServiceClass = readApplicationMetadata(appInfo, LISTENER_SERVICE_NAME_KEY); } /** * Returns the metadata-provided value for {@code key} in {@code appInfo} if one * exists, or the value from {@link #DEFAULTS} if one does not. */ private static String readApplicationMetadata(ApplicationInfo appInfo, String key) { String value = null; if (appInfo.metaData != null) { value = appInfo.metaData.getString(key); } // Return the manifest value if present or the default value if not. return (value != null) ? value : Preconditions.checkNotNull(DEFAULTS.get(key), "No default value for %s", key); } } }