Index: sync/android/java/src/org/chromium/sync/notifier/InvalidationController.java |
diff --git a/sync/android/java/src/org/chromium/sync/notifier/InvalidationController.java b/sync/android/java/src/org/chromium/sync/notifier/InvalidationController.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..71ac7b512090612df17a813411881e62ac61cf04 |
--- /dev/null |
+++ b/sync/android/java/src/org/chromium/sync/notifier/InvalidationController.java |
@@ -0,0 +1,179 @@ |
+// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+package org.chromium.sync.notifier; |
+ |
+import android.accounts.Account; |
+import android.content.Context; |
+import android.content.Intent; |
+import android.content.pm.ApplicationInfo; |
+import android.content.pm.PackageManager; |
+import android.content.pm.PackageManager.NameNotFoundException; |
+import android.util.Log; |
+ |
+import com.google.common.base.Preconditions; |
+import com.google.common.collect.Lists; |
+ |
+import org.chromium.sync.internal_api.pub.base.ModelType; |
+ |
+import java.util.Set; |
+ |
+/** |
+ * Controller used to send start, stop, and registration-change commands to the invalidation |
+ * client library used by Sync. |
+ */ |
+public class InvalidationController { |
+ /** |
+ * Constants and utility methods to create the intents used to communicate between the |
+ * controller and the invalidation client library. |
+ */ |
+ public static class IntentProtocol { |
+ /** |
+ * Action set on register intents. |
+ */ |
+ public static final String ACTION_REGISTER = |
+ "org.chromium.sync.notifier.ACTION_REGISTER_TYPES"; |
+ |
+ /** |
+ * Special syncable type that lets us know to sync all types. |
+ */ |
+ public static final String ALL_TYPES_TYPE = "ALL_TYPES"; |
+ |
+ /** |
+ * Parcelable-valued intent extra containing the account of the user. |
+ */ |
+ public static final String EXTRA_ACCOUNT = "account"; |
+ |
+ /** |
+ * String-list-valued intent extra of the syncable types to sync. |
+ */ |
+ public static final String EXTRA_REGISTERED_TYPES = "registered_types"; |
+ |
+ /** |
+ * Boolean-valued intent extra indicating that the service should be stopped. |
+ */ |
+ public static final String EXTRA_STOP = "stop"; |
+ |
+ /** |
+ * Create an Intent that will start the invalidation listener service and |
+ * register for the specified types. |
+ */ |
+ public static Intent createRegisterIntent(Account account, |
+ boolean allTypes, Set<ModelType> types) { |
+ Intent registerIntent = new Intent(ACTION_REGISTER); |
+ String[] selectedTypesArray; |
+ if (allTypes) { |
+ selectedTypesArray = new String[]{ALL_TYPES_TYPE}; |
+ } else { |
+ selectedTypesArray = new String[types.size()]; |
+ int pos = 0; |
+ for (ModelType type : types) { |
+ selectedTypesArray[pos++] = type.name(); |
+ } |
+ } |
+ registerIntent.putStringArrayListExtra(EXTRA_REGISTERED_TYPES, |
+ Lists.newArrayList(selectedTypesArray)); |
+ registerIntent.putExtra(EXTRA_ACCOUNT, account); |
+ return registerIntent; |
+ } |
+ |
+ private IntentProtocol() { |
+ // Disallow instantiation. |
+ } |
+ } |
+ |
+ /** |
+ * Name of the manifest application metadata property specifying the name of the class |
+ * implementing the invalidation client. |
+ */ |
+ private static final String IMPLEMENTING_CLASS_MANIFEST_PROPERTY = |
+ "org.chromium.sync.notifier.IMPLEMENTING_CLASS_NAME"; |
+ |
+ /** |
+ * Logging tag. |
+ */ |
+ private static final String TAG = InvalidationController.class.getSimpleName(); |
+ |
+ private final Context context; |
+ |
+ /** |
+ * Sets the types for which the client should register for notifications. |
+ * |
+ * @param account Account of the user. |
+ * @param allTypes If {@code true}, registers for all types, and {@code types} is ignored |
+ * @param types Set of types for which to register. Ignored if {@code allTypes == true}. |
+ */ |
+ public void setRegisteredTypes(Account account, boolean allTypes, Set<ModelType> types) { |
+ Intent registerIntent = IntentProtocol.createRegisterIntent(account, allTypes, types); |
+ setDestinationClassName(registerIntent); |
+ context.startService(registerIntent); |
+ } |
+ |
+ /** |
+ * Starts the invalidation client. |
+ */ |
+ public void start() { |
+ Intent intent = setDestinationClassName(new Intent()); |
+ context.startService(intent); |
+ } |
+ |
+ /** |
+ * Stops the invalidation client. |
+ */ |
+ public void stop() { |
+ Intent intent = setDestinationClassName(new Intent()); |
+ intent.putExtra(IntentProtocol.EXTRA_STOP, true); |
+ context.startService(intent); |
+ } |
+ |
+ /** |
+ * Returns the contract authority to use when requesting sync. |
+ */ |
+ public String getContractAuthority() { |
+ return context.getPackageName(); |
+ } |
+ |
+ /** |
+ * Returns a new instance that will use {@code context} to issue intents. |
+ */ |
+ public static InvalidationController newInstance(Context context) { |
+ return new InvalidationController(context); |
+ } |
+ |
+ /** |
+ * Creates an instance using {@code context} to send intents. |
+ */ |
+ private InvalidationController(Context context) { |
+ this.context = Preconditions.checkNotNull(context.getApplicationContext()); |
+ } |
+ |
+ /** |
+ * Sets the destination class name of {@code intent} to the value given by the manifest |
+ * property named {@link #IMPLEMENTING_CLASS_MANIFEST_PROPERTY}. If no such property exists or |
+ * its value is null, takes no action. |
+ * |
+ * @return {@code intent} |
+ */ |
+ private Intent setDestinationClassName(Intent intent) { |
+ ApplicationInfo appInfo; |
+ try { |
+ // Fetch application info and read the appropriate metadata element. |
+ appInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(), |
+ PackageManager.GET_META_DATA); |
+ String className = null; |
+ if (appInfo.metaData != null) { |
+ className = appInfo.metaData.getString(IMPLEMENTING_CLASS_MANIFEST_PROPERTY); |
+ } |
+ if (className == null) { |
+ Log.wtf(TAG, "No value for " + IMPLEMENTING_CLASS_MANIFEST_PROPERTY |
+ + " in manifest; sync notifications will not work"); |
+ } else { |
+ intent.setClassName(context, className); |
+ } |
+ } catch (NameNotFoundException exception) { |
+ Log.wtf(TAG, "Cannot read own application info", exception); |
+ } |
+ return intent; |
+ } |
+} |