summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/test/android/javatests/src/org/chromium/base/test/util/AdvancedMockContext.java103
-rw-r--r--base/test/android/javatests/src/org/chromium/base/test/util/InMemorySharedPreferences.java187
-rw-r--r--chrome/android/testshell/java/AndroidManifest.xml4
-rw-r--r--chrome/chrome.gyp1
-rw-r--r--chrome/chrome_tests.gypi5
-rw-r--r--sync/android/OWNERS3
-rw-r--r--sync/android/java/src/org/chromium/sync/internal_api/pub/base/ModelType.java46
-rw-r--r--sync/android/java/src/org/chromium/sync/notifier/InvalidationController.java179
-rw-r--r--sync/android/javatests/src/org/chromium/sync/notifier/InvalidationControllerTest.java154
-rw-r--r--sync/sync.gyp31
10 files changed, 711 insertions, 2 deletions
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/AdvancedMockContext.java b/base/test/android/javatests/src/org/chromium/base/test/util/AdvancedMockContext.java
new file mode 100644
index 0000000..a57a8b0
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/AdvancedMockContext.java
@@ -0,0 +1,103 @@
+// 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.base.test.util;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.SharedPreferences;
+import android.test.mock.MockContentResolver;
+import android.test.mock.MockContext;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * ContextWrapper that adds functionality for SharedPreferences and a way to set and retrieve flags.
+ */
+public class AdvancedMockContext extends ContextWrapper {
+
+ private final MockContentResolver mMockContentResolver = new MockContentResolver();
+
+ private final Map<String, SharedPreferences> mSharedPreferences =
+ new HashMap<String, SharedPreferences>();
+
+ private final Map<String, Boolean> flags = new HashMap<String, Boolean>();
+
+ public AdvancedMockContext(Context base) {
+ super(base);
+ }
+
+ public AdvancedMockContext() {
+ super(new MockContext());
+ }
+
+ @Override
+ public String getPackageName() {
+ return getBaseContext().getPackageName();
+ }
+
+ @Override
+ public Context getApplicationContext() {
+ return this;
+ }
+
+ @Override
+ public ContentResolver getContentResolver() {
+ return mMockContentResolver;
+ }
+
+ public MockContentResolver getMockContentResolver() {
+ return mMockContentResolver;
+ }
+
+ @Override
+ public SharedPreferences getSharedPreferences(String name, int mode) {
+ synchronized (mSharedPreferences) {
+ if (!mSharedPreferences.containsKey(name)) {
+ // Auto-create shared preferences to mimic Android Context behavior
+ mSharedPreferences.put(name, new InMemorySharedPreferences());
+ }
+ return mSharedPreferences.get(name);
+ }
+ }
+
+ public void addSharedPreferences(String name, Map<String, Object> data) {
+ synchronized (mSharedPreferences) {
+ mSharedPreferences.put(name, new InMemorySharedPreferences(data));
+ }
+ }
+
+ public void setFlag(String key) {
+ flags.put(key, true);
+ }
+
+ public void clearFlag(String key) {
+ flags.remove(key);
+ }
+
+ public boolean isFlagSet(String key) {
+ return flags.containsKey(key) && flags.get(key);
+ }
+
+ public static class MapBuilder {
+
+ private final Map<String, Object> mData = new HashMap<String, Object>();
+
+ public static MapBuilder create() {
+ return new MapBuilder();
+ }
+
+ public MapBuilder add(String key, Object value) {
+ mData.put(key, value);
+ return this;
+ }
+
+ public Map<String, Object> build() {
+ return mData;
+ }
+
+ }
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/InMemorySharedPreferences.java b/base/test/android/javatests/src/org/chromium/base/test/util/InMemorySharedPreferences.java
new file mode 100644
index 0000000..e42562b
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/InMemorySharedPreferences.java
@@ -0,0 +1,187 @@
+// 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.base.test.util;
+
+import android.content.SharedPreferences;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * An implementation of SharedPreferences that can be used in tests.
+ * <p/>
+ * It keeps all state in memory, and there is no difference between apply() and commit().
+ */
+public class InMemorySharedPreferences implements SharedPreferences {
+
+ private final Map<String, Object> mData;
+
+ private final SharedPreferences.Editor mEditor = new InMemoryEditor();
+
+ public InMemorySharedPreferences() {
+ mData = new HashMap<String, Object>();
+ }
+
+ public InMemorySharedPreferences(Map<String, Object> data) {
+ mData = data;
+ }
+
+ @Override
+ public Map<String, ?> getAll() {
+ return mData;
+ }
+
+ @Override
+ public String getString(String key, String defValue) {
+ if (mData.containsKey(key)) {
+ return (String) mData.get(key);
+ }
+ return defValue;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Set<String> getStringSet(String key, Set<String> defValues) {
+ if (mData.containsKey(key)) {
+ return (Set<String>) mData.get(key);
+ }
+ return defValues;
+ }
+
+ @Override
+ public int getInt(String key, int defValue) {
+ if (mData.containsKey(key)) {
+ return (Integer) mData.get(key);
+ }
+ return defValue;
+ }
+
+ @Override
+ public long getLong(String key, long defValue) {
+ if (mData.containsKey(key)) {
+ return (Long) mData.get(key);
+ }
+ return defValue;
+ }
+
+ @Override
+ public float getFloat(String key, float defValue) {
+ if (mData.containsKey(key)) {
+ return (Float) mData.get(key);
+ }
+ return defValue;
+ }
+
+ @Override
+ public boolean getBoolean(String key, boolean defValue) {
+ if (mData.containsKey(key)) {
+ return (Boolean) mData.get(key);
+ }
+ return defValue;
+ }
+
+ @Override
+ public boolean contains(String key) {
+ return mData.containsKey(key);
+ }
+
+ @Override
+ public SharedPreferences.Editor edit() {
+ return mEditor;
+ }
+
+ @Override
+ public void registerOnSharedPreferenceChangeListener(
+ SharedPreferences.OnSharedPreferenceChangeListener
+ listener) {
+ }
+
+ @Override
+ public void unregisterOnSharedPreferenceChangeListener(
+ SharedPreferences.OnSharedPreferenceChangeListener listener) {
+ }
+
+ private class InMemoryEditor implements SharedPreferences.Editor {
+
+ private boolean mClearCalled;
+
+ private final Map<String, Object> mChanges = new HashMap<String, Object>();
+
+ @Override
+ public SharedPreferences.Editor putString(String key, String value) {
+ mChanges.put(key, value);
+ return this;
+ }
+
+ @Override
+ public SharedPreferences.Editor putStringSet(String key, Set<String> values) {
+ mChanges.put(key, values);
+ return this;
+ }
+
+ @Override
+ public SharedPreferences.Editor putInt(String key, int value) {
+ mChanges.put(key, value);
+ return this;
+ }
+
+ @Override
+ public SharedPreferences.Editor putLong(String key, long value) {
+ mChanges.put(key, value);
+ return this;
+ }
+
+ @Override
+ public SharedPreferences.Editor putFloat(String key, float value) {
+ mChanges.put(key, value);
+ return this;
+ }
+
+ @Override
+ public SharedPreferences.Editor putBoolean(String key, boolean value) {
+ mChanges.put(key, value);
+ return this;
+ }
+
+ @Override
+ public SharedPreferences.Editor remove(String key) {
+ // Magic value for removes
+ mChanges.put(key, this);
+ return this;
+ }
+
+ @Override
+ public SharedPreferences.Editor clear() {
+ mClearCalled = true;
+ return this;
+ }
+
+ @Override
+ public boolean commit() {
+ apply();
+ return true;
+ }
+
+ @Override
+ public void apply() {
+ if (mClearCalled) {
+ mData.clear();
+ }
+ for (Map.Entry<String, Object> entry : mChanges.entrySet()) {
+ String key = entry.getKey();
+ Object value = entry.getValue();
+ if (value == this) {
+ // Special value for removal
+ mData.remove(key);
+ } else {
+ mData.put(key, value);
+ }
+ }
+ }
+
+ }
+
+}
diff --git a/chrome/android/testshell/java/AndroidManifest.xml b/chrome/android/testshell/java/AndroidManifest.xml
index 45f0e29..0da98141 100644
--- a/chrome/android/testshell/java/AndroidManifest.xml
+++ b/chrome/android/testshell/java/AndroidManifest.xml
@@ -60,6 +60,10 @@
android:permission="org.chromium.content_shell.permission.SANDBOX"
android:isolatedProcess="true"
android:exported="false" />
+
+ <!-- Name of the class implementing the invalidation client, for sync notifications. -->
+ <meta-data android:name="org.chromium.sync.notifier.IMPLEMENTING_CLASS_NAME"
+ android:value="org.chromium.sync.notifier.TEST_VALUE" />
</application>
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="17" />
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index 6e0cb29..2579fe6 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -1072,6 +1072,7 @@
'../content/content.gyp:content_java',
'../content/content.gyp:navigation_interception_java',
'../content/content.gyp:web_contents_delegate_android_java',
+ '../sync/sync.gyp:sync_java',
'../third_party/guava/guava.gyp:guava_javalib',
'../ui/ui.gyp:ui_java',
],
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 3bca828..ee7dfe8 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -2810,11 +2810,12 @@
'target_name': 'chromium_testshell_test_apk',
'type': 'none',
'dependencies': [
- '../base/base.gyp:base',
- '../base/base.gyp:base_java_test_support',
'chrome_java',
'chromium_testshell_java',
+ '../base/base.gyp:base',
+ '../base/base.gyp:base_java_test_support',
'../content/content.gyp:content_java_test_support',
+ '../sync/sync.gyp:sync_javatests',
'../tools/android/forwarder/forwarder.gyp:forwarder',
],
'variables': {
diff --git a/sync/android/OWNERS b/sync/android/OWNERS
new file mode 100644
index 0000000..72643ec
--- /dev/null
+++ b/sync/android/OWNERS
@@ -0,0 +1,3 @@
+nileshagrawal@chromium.org
+nyquist@chromium.org
+yfriedman@chromium.org
diff --git a/sync/android/java/src/org/chromium/sync/internal_api/pub/base/ModelType.java b/sync/android/java/src/org/chromium/sync/internal_api/pub/base/ModelType.java
new file mode 100644
index 0000000..4dbdab0
--- /dev/null
+++ b/sync/android/java/src/org/chromium/sync/internal_api/pub/base/ModelType.java
@@ -0,0 +1,46 @@
+// 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.internal_api.pub.base;
+
+import com.google.ipc.invalidation.external.client.types.ObjectId;
+import com.google.protos.ipc.invalidation.Types;
+
+/**
+ * The model types that are synced in Chrome for Android.
+ */
+public enum ModelType {
+
+ /**
+ * A bookmark folder or a bookmark URL object.
+ */
+ BOOKMARK("BOOKMARK"),
+ /**
+ * A typed_url folder or a typed_url object.
+ */
+ TYPED_URL("TYPED_URL"),
+ /**
+ * An object representing a browser session or tab.
+ */
+ SESSION("SESSION");
+
+ private final String mModelType;
+
+ ModelType(String modelType) {
+ mModelType = modelType;
+ }
+
+ public ObjectId toObjectId() {
+ return ObjectId.newInstance(Types.ObjectSource.Type.CHROME_SYNC.getNumber(),
+ mModelType.getBytes());
+ }
+
+ public static ModelType fromObjectId(ObjectId objectId) {
+ try {
+ return valueOf(new String(objectId.getName()));
+ } catch (IllegalArgumentException e) {
+ return null;
+ }
+ }
+}
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 0000000..71ac7b5
--- /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;
+ }
+}
diff --git a/sync/android/javatests/src/org/chromium/sync/notifier/InvalidationControllerTest.java b/sync/android/javatests/src/org/chromium/sync/notifier/InvalidationControllerTest.java
new file mode 100644
index 0000000..eee2bdf
--- /dev/null
+++ b/sync/android/javatests/src/org/chromium/sync/notifier/InvalidationControllerTest.java
@@ -0,0 +1,154 @@
+// 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.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+import org.chromium.base.test.util.AdvancedMockContext;
+import org.chromium.base.test.util.Feature;
+import org.chromium.sync.internal_api.pub.base.ModelType;
+import org.chromium.sync.notifier.InvalidationController.IntentProtocol;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Tests for the {@link InvalidationController}.
+ */
+public class InvalidationControllerTest extends InstrumentationTestCase {
+ private IntentSavingContext mContext;
+ private InvalidationController mController;
+
+ @Override
+ protected void setUp() throws Exception {
+ mContext = new IntentSavingContext(getInstrumentation().getTargetContext());
+ mController = InvalidationController.newInstance(mContext);
+ }
+
+ @SmallTest
+ @Feature({"Sync"})
+ public void testStart() throws Exception {
+ mController.start();
+ assertEquals(1, mContext.getNumStartedIntents());
+ Intent intent = mContext.getStartedIntent(0);
+ validateIntentComponent(intent);
+ assertNull(intent.getExtras());
+ }
+
+ @SmallTest
+ @Feature({"Sync"})
+ public void testStop() throws Exception {
+ mController.stop();
+ assertEquals(1, mContext.getNumStartedIntents());
+ Intent intent = mContext.getStartedIntent(0);
+ validateIntentComponent(intent);
+ assertEquals(1, intent.getExtras().size());
+ assertTrue(intent.hasExtra(IntentProtocol.EXTRA_STOP));
+ assertTrue(intent.getBooleanExtra(IntentProtocol.EXTRA_STOP, false));
+ }
+
+ @SmallTest
+ @Feature({"Sync"})
+ public void testRegisterForSpecificTypes() {
+ Account account = new Account("test@example.com", "bogus");
+ mController.setRegisteredTypes(account, false,
+ Sets.newHashSet(ModelType.BOOKMARK, ModelType.SESSION));
+ assertEquals(1, mContext.getNumStartedIntents());
+
+ // Validate destination.
+ Intent intent = mContext.getStartedIntent(0);
+ validateIntentComponent(intent);
+ assertEquals(IntentProtocol.ACTION_REGISTER, intent.getAction());
+
+ // Validate account.
+ Account intentAccount = intent.getParcelableExtra(IntentProtocol.EXTRA_ACCOUNT);
+ assertEquals(account, intentAccount);
+
+ // Validate registered types.
+ Set<String> expectedTypes =
+ Sets.newHashSet(ModelType.BOOKMARK.name(), ModelType.SESSION.name());
+ Set<String> actualTypes = Sets.newHashSet();
+ actualTypes.addAll(intent.getStringArrayListExtra(IntentProtocol.EXTRA_REGISTERED_TYPES));
+ assertEquals(expectedTypes, actualTypes);
+ }
+
+ @SmallTest
+ @Feature({"Sync"})
+ public void testRegisterForAllTypes() {
+ Account account = new Account("test@example.com", "bogus");
+ mController.setRegisteredTypes(account, true,
+ Sets.newHashSet(ModelType.BOOKMARK, ModelType.SESSION));
+ assertEquals(1, mContext.getNumStartedIntents());
+
+ // Validate destination.
+ Intent intent = mContext.getStartedIntent(0);
+ validateIntentComponent(intent);
+ assertEquals(IntentProtocol.ACTION_REGISTER, intent.getAction());
+
+ // Validate account.
+ Account intentAccount = intent.getParcelableExtra(IntentProtocol.EXTRA_ACCOUNT);
+ assertEquals(account, intentAccount);
+
+ // Validate registered types.
+ Set<String> expectedTypes = Sets.newHashSet(IntentProtocol.ALL_TYPES_TYPE);
+ Set<String> actualTypes = Sets.newHashSet();
+ actualTypes.addAll(intent.getStringArrayListExtra(IntentProtocol.EXTRA_REGISTERED_TYPES));
+ assertEquals(expectedTypes, actualTypes);
+ }
+
+ @SmallTest
+ @Feature({"Sync"})
+ public void testGetContractAuthority() throws Exception {
+ assertEquals(mContext.getPackageName(), mController.getContractAuthority());
+ }
+
+ /**
+ * Asserts that {@code intent} is destined for the correct component.
+ */
+ private static void validateIntentComponent(Intent intent) {
+ assertNotNull(intent.getComponent());
+ assertEquals("org.chromium.sync.notifier.TEST_VALUE",
+ intent.getComponent().getClassName());
+ }
+
+ /**
+ * Mock context that saves all intents given to {@code startService}.
+ */
+ private static class IntentSavingContext extends AdvancedMockContext {
+ private final List<Intent> startedIntents = Lists.newArrayList();
+
+ IntentSavingContext(Context targetContext) {
+ super(targetContext);
+ }
+
+ @Override
+ public ComponentName startService(Intent intent) {
+ startedIntents.add(intent);
+ return new ComponentName(this, getClass());
+ }
+
+ int getNumStartedIntents() {
+ return startedIntents.size();
+ }
+
+ Intent getStartedIntent(int idx) {
+ return startedIntents.get(idx);
+ }
+
+ @Override
+ public PackageManager getPackageManager() {
+ return getBaseContext().getPackageManager();
+ }
+ }
+}
diff --git a/sync/sync.gyp b/sync/sync.gyp
index c22fec1..7caf784 100644
--- a/sync/sync.gyp
+++ b/sync/sync.gyp
@@ -986,6 +986,37 @@
},
],
}],
+ ['OS == "android"', {
+ 'targets': [
+ {
+ 'target_name': 'sync_java',
+ 'type': 'none',
+ 'variables': {
+ 'package_name': 'sync',
+ 'java_in_dir': '../sync/android/java',
+ },
+ 'dependencies': [
+ '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_javalib',
+ '../third_party/guava/guava.gyp:guava_javalib',
+ '../third_party/jsr-305/jsr-305.gyp:jsr_305_javalib',
+ ],
+ 'includes': [ '../build/java.gypi' ],
+ },
+ {
+ 'target_name': 'sync_javatests',
+ 'type': 'none',
+ 'variables': {
+ 'package_name': 'sync_javatests',
+ 'java_in_dir': '../sync/android/javatests',
+ },
+ 'dependencies': [
+ 'sync_java',
+ '../base/base.gyp:base_java_test_support',
+ ],
+ 'includes': [ '../build/java.gypi' ],
+ },
+ ],
+ }],
# Special target to wrap a gtest_target_type==shared_library
# sync_unit_tests into an android apk for execution.