diff --git a/WORKSPACE b/WORKSPACE
index a3158d2a8f3b8ec805ae291bf6d8d313ad4dd4b1..86dc7eeca222265afbba7790aece82b3f7183c03 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -183,6 +183,12 @@ maven_jar(
     sha1 = "949abe1460757b8dc9902c562f83e49675444572",
 )
 
+maven_jar(
+    name = "joda_time",
+    artifact = "joda-time:joda-time:2.9.9",
+    sha1 = "f7b520c458572890807d143670c9b24f4de90897",
+)
+
 maven_jar(
     name = "junit_junit_4",
     artifact = "junit:junit:jar:4.12",
diff --git a/apps/googlepayments/BUILD b/apps/googlepayments/BUILD
index bd5dcff956db777aab1463ecb0a8a0f53935d51c..5f3356f2fc8329df7cf5a06bf6bd3cbb3f5294b5 100644
--- a/apps/googlepayments/BUILD
+++ b/apps/googlepayments/BUILD
@@ -1,4 +1,4 @@
-package(default_visibility = ["//visibility:public"])
+package(default_visibility = ["//visibility:private"])
 
 licenses(["notice"])  # Apache 2.0
 
diff --git a/apps/googlepayments/src/main/java/com/google/payments/PaymentMethodTokenHybridDecrypt.java b/apps/googlepayments/src/main/java/com/google/payments/PaymentMethodTokenHybridDecrypt.java
index 86191af6941c51d9f5763e287a66a5703f8a2a96..ea97e56bd6fd8977ea92e2c9505c4d1dd755b1ee 100644
--- a/apps/googlepayments/src/main/java/com/google/payments/PaymentMethodTokenHybridDecrypt.java
+++ b/apps/googlepayments/src/main/java/com/google/payments/PaymentMethodTokenHybridDecrypt.java
@@ -44,7 +44,8 @@ class PaymentMethodTokenHybridDecrypt implements HybridDecrypt {
     try {
       JSONObject json = new JSONObject(new String(ciphertext, StandardCharsets.UTF_8));
       validate(json);
-      byte[] kem = PaymentMethodTokenUtil.BASE64.decode(json.getString(PaymentMethodTokenConstants.JSON_EPHEMERAL_PUBLIC_KEY));
+      byte[] kem = PaymentMethodTokenUtil.BASE64.decode(json.getString(
+          PaymentMethodTokenConstants.JSON_EPHEMERAL_PUBLIC_KEY));
       int symmetricKeySize = PaymentMethodTokenConstants.AES_CTR_KEY_SIZE
           + PaymentMethodTokenConstants.HMAC_SHA256_KEY_SIZE;
       byte[] demKey = recipientKem.generateKey(
@@ -60,7 +61,8 @@ class PaymentMethodTokenHybridDecrypt implements HybridDecrypt {
           json.getString(PaymentMethodTokenConstants.JSON_ENCRYPTED_MESSAGE_KEY));
       byte[] computedTag = PaymentMethodTokenUtil.hmacSha256(hmacSha256Key,
           encryptedMessage);
-      byte[] expectedTag = PaymentMethodTokenUtil.BASE64.decode(json.getString(PaymentMethodTokenConstants.JSON_TAG_KEY));
+      byte[] expectedTag = PaymentMethodTokenUtil.BASE64.decode(json.getString(
+          PaymentMethodTokenConstants.JSON_TAG_KEY));
       if (!SubtleUtil.arrayEquals(expectedTag, computedTag)) {
         throw new GeneralSecurityException("cannot decrypt; invalid MAC");
       }
@@ -68,7 +70,7 @@ class PaymentMethodTokenHybridDecrypt implements HybridDecrypt {
           PaymentMethodTokenConstants.AES_CTR_KEY_SIZE);
       return PaymentMethodTokenUtil.aesCtr(aesCtrKey, encryptedMessage);
     } catch (JSONException e) {
-      throw new GeneralSecurityException("cannot decrypt; failed to parse JSON", e);
+      throw new GeneralSecurityException("cannot decrypt; failed to parse JSON");
     }
   }
 
diff --git a/apps/googlepayments/src/main/java/com/google/payments/PaymentMethodTokenHybridEncrypt.java b/apps/googlepayments/src/main/java/com/google/payments/PaymentMethodTokenHybridEncrypt.java
index 0e8108cc9be15e5739a2286389e7bc4750764763..7aedfe4ffccd1a8d15a85954b7eeda53e84ab69f 100644
--- a/apps/googlepayments/src/main/java/com/google/payments/PaymentMethodTokenHybridEncrypt.java
+++ b/apps/googlepayments/src/main/java/com/google/payments/PaymentMethodTokenHybridEncrypt.java
@@ -23,6 +23,7 @@ import java.nio.charset.StandardCharsets;
 import java.security.GeneralSecurityException;
 import java.security.interfaces.ECPublicKey;
 import java.util.Arrays;
+import org.json.JSONException;
 import org.json.JSONObject;
 
 /**
@@ -56,13 +57,17 @@ class PaymentMethodTokenHybridEncrypt implements HybridEncrypt {
         kemKey.getSymmetricKey(), PaymentMethodTokenConstants.AES_CTR_KEY_SIZE, symmetricKeySize);
     byte[] tag = PaymentMethodTokenUtil.hmacSha256(hmacSha256Key, ciphertext);
     byte[] ephemeralPublicKey = kemKey.getKemBytes();
-    return new JSONObject()
-        .put(PaymentMethodTokenConstants.JSON_ENCRYPTED_MESSAGE_KEY,
-            PaymentMethodTokenUtil.BASE64.encode(ciphertext))
-        .put(PaymentMethodTokenConstants.JSON_TAG_KEY, PaymentMethodTokenUtil.BASE64.encode(tag))
-        .put(PaymentMethodTokenConstants.JSON_EPHEMERAL_PUBLIC_KEY,
-            PaymentMethodTokenUtil.BASE64.encode(ephemeralPublicKey))
-        .toString()
-        .getBytes(StandardCharsets.UTF_8);
+    try {
+      return new JSONObject()
+          .put(PaymentMethodTokenConstants.JSON_ENCRYPTED_MESSAGE_KEY,
+              PaymentMethodTokenUtil.BASE64.encode(ciphertext))
+          .put(PaymentMethodTokenConstants.JSON_TAG_KEY, PaymentMethodTokenUtil.BASE64.encode(tag))
+          .put(PaymentMethodTokenConstants.JSON_EPHEMERAL_PUBLIC_KEY,
+              PaymentMethodTokenUtil.BASE64.encode(ephemeralPublicKey))
+          .toString()
+          .getBytes(StandardCharsets.UTF_8);
+    } catch (JSONException e) {
+      throw new GeneralSecurityException("cannot encrypt; JSON error");
+    }
   }
 }
diff --git a/apps/googlepayments/src/main/java/com/google/payments/PaymentMethodTokenRecipient.java b/apps/googlepayments/src/main/java/com/google/payments/PaymentMethodTokenRecipient.java
index 477adaf537d3abff31d61eeb65468d7f57e59ab4..f436e13ad7d97926d5f9fa1b717a45220cc58739 100644
--- a/apps/googlepayments/src/main/java/com/google/payments/PaymentMethodTokenRecipient.java
+++ b/apps/googlepayments/src/main/java/com/google/payments/PaymentMethodTokenRecipient.java
@@ -213,7 +213,7 @@ public final class PaymentMethodTokenRecipient {
       }
       throw new IllegalArgumentException("unsupported version: " + protocolVersion);
     } catch (JSONException e) {
-      throw new GeneralSecurityException("cannot unseal; invalid JSON message", e);
+      throw new GeneralSecurityException("cannot unseal; invalid JSON message");
     }
   }
 
@@ -266,7 +266,8 @@ public final class PaymentMethodTokenRecipient {
     throw new GeneralSecurityException("cannot decrypt");
   }
 
-  private void validateV1(final JSONObject jsonMsg) throws GeneralSecurityException {
+  private void validateV1(final JSONObject jsonMsg)
+      throws GeneralSecurityException, JSONException {
     if (!jsonMsg.has(PaymentMethodTokenConstants.JSON_PROTOCOL_VERSION_KEY)
         || !jsonMsg.has(PaymentMethodTokenConstants.JSON_SIGNATURE_KEY)
         || !jsonMsg.has(PaymentMethodTokenConstants.JSON_SIGNED_MESSAGE_KEY)
diff --git a/apps/googlepayments/src/main/java/com/google/payments/PaymentMethodTokenSender.java b/apps/googlepayments/src/main/java/com/google/payments/PaymentMethodTokenSender.java
index 09aa242bc055bccf081cd16202c67b887057cf60..4360931d3ae7bdb1642e665eae740d0ea51cf487 100644
--- a/apps/googlepayments/src/main/java/com/google/payments/PaymentMethodTokenSender.java
+++ b/apps/googlepayments/src/main/java/com/google/payments/PaymentMethodTokenSender.java
@@ -23,6 +23,7 @@ import java.nio.charset.StandardCharsets;
 import java.security.GeneralSecurityException;
 import java.security.interfaces.ECPrivateKey;
 import java.security.interfaces.ECPublicKey;
+import org.json.JSONException;
 import org.json.JSONObject;
 
 /**
@@ -184,12 +185,16 @@ public final class PaymentMethodTokenSender {
         PaymentMethodTokenConstants.PROTOCOL_VERSION_EC_V1,
         signedMessage);
     byte[] signature = signer.sign(toSignBytes);
-    return new JSONObject()
-        .put(PaymentMethodTokenConstants.JSON_SIGNED_MESSAGE_KEY, signedMessage)
-        .put(PaymentMethodTokenConstants.JSON_PROTOCOL_VERSION_KEY,
-            PaymentMethodTokenConstants.PROTOCOL_VERSION_EC_V1)
-        .put(PaymentMethodTokenConstants.JSON_SIGNATURE_KEY,
-            PaymentMethodTokenUtil.BASE64.encode(signature))
-        .toString();
+    try {
+      return new JSONObject()
+          .put(PaymentMethodTokenConstants.JSON_SIGNED_MESSAGE_KEY, signedMessage)
+          .put(PaymentMethodTokenConstants.JSON_PROTOCOL_VERSION_KEY,
+              PaymentMethodTokenConstants.PROTOCOL_VERSION_EC_V1)
+          .put(PaymentMethodTokenConstants.JSON_SIGNATURE_KEY,
+              PaymentMethodTokenUtil.BASE64.encode(signature))
+          .toString();
+    } catch (JSONException e) {
+      throw new GeneralSecurityException("cannot seal; JSON error");
+    }
   }
 }
diff --git a/apps/googlepayments/src/test/java/com/google/payments/PaymentMethodTokenRecipientTest.java b/apps/googlepayments/src/test/java/com/google/payments/PaymentMethodTokenRecipientTest.java
index 5b4771bcaca2f134bf55141443f443702bb29a1b..c8b6dc96282e732681c8a0f7c708c4bf800009a2 100644
--- a/apps/googlepayments/src/test/java/com/google/payments/PaymentMethodTokenRecipientTest.java
+++ b/apps/googlepayments/src/test/java/com/google/payments/PaymentMethodTokenRecipientTest.java
@@ -211,7 +211,7 @@ public class PaymentMethodTokenRecipientTest {
     trustedKeysJson.put("keys", new JSONArray().put(key1).put(key2));
 
     try {
-      PaymentMethodTokenRecipient recipient = new PaymentMethodTokenRecipient.Builder()
+      PaymentMethodTokenRecipient unused = new PaymentMethodTokenRecipient.Builder()
           .senderVerifyingKeys(trustedKeysJson.toString())
           .recipientId(RECIPIENT_ID)
           .addRecipientPrivateKey(MERCHANT_PRIVATE_KEY_PKCS8_BASE64)
@@ -287,7 +287,7 @@ public class PaymentMethodTokenRecipientTest {
       recipient.unseal(payload.toString());
       fail("Expected GeneralSecurityException");
     } catch (GeneralSecurityException e) {
-      assertEquals("cannot unseal; invalid JSON message", e.getMessage());
+      // expected
     }
   }
 
@@ -305,7 +305,7 @@ public class PaymentMethodTokenRecipientTest {
       recipient.unseal(payload.toString());
       fail("Expected GeneralSecurityException");
     } catch (GeneralSecurityException e) {
-      assertEquals("cannot unseal; invalid JSON message", e.getMessage());
+      // expected
     }
   }
 }
diff --git a/doc/JAVA-HOWTO.md b/doc/JAVA-HOWTO.md
index 66932f93bee86f819460c247fc637f0c10c1e82b..c4a528ca03cfdd9501c9e5b4b70fb9f677991e38 100644
--- a/doc/JAVA-HOWTO.md
+++ b/doc/JAVA-HOWTO.md
@@ -42,7 +42,7 @@ For custom initialization the registration can proceed directly via `Registry`-c
 ```
 
 For more complex use cases, with multiple primitives and custom implementations,
-one can use Tink configuration tools from [`com.google.crypto.tink.config`](https://github.com/google/tink/blob/master/java/src/main/java/com/google/crypto/tink/config)-package, 
+one can use Tink configuration tools from [`com.google.crypto.tink.config`](https://github.com/google/tink/blob/master/java/src/main/java/com/google/crypto/tink/config)-package,
 which provides a configuration language for specifying key types and their key
 managers to be used by Tink at runtime, and utilities for handling the
 configurations.  This allows for customizable configuration without need of
@@ -208,7 +208,7 @@ To create a custom implementation of a primitive proceed as follows:
 2. Define protocol buffers that hold key material and parameters for the custom
    cryptographic scheme; the name of the key protocol buffer (a.k.a. type URL)
    determines the _key type_ for the custom implementation.
-3. Implement [`KeyManager`](https://github.com/google/tink/blob/master/java/src/main/java/com/google/crypto/tink/KeyManager.java) 
+3. Implement [`KeyManager`](https://github.com/google/tink/blob/master/java/src/main/java/com/google/crypto/tink/KeyManager.java)
    interface for the _primitive_ from step #1 and the _key type_ from step #2.
 
 To use a custom implementation of a primitive in an application, register with
diff --git a/java/BUILD b/java/BUILD
index 70039d44abd154f527ffe53cc2de227d2170fc51..ad470d6ac200016ffc1e46e968bf4ab4da9927df 100644
--- a/java/BUILD
+++ b/java/BUILD
@@ -57,6 +57,15 @@ java_library(
     ],
 )
 
+java_library(
+    name = "config_android",
+    visibility = ["//visibility:public"],
+    exports = [
+        "//java/src/main/java/com/google/crypto/tink/config:android",
+        "//java/src/main/java/com/google/crypto/tink/config:tink_catalogue_android",
+    ],
+)
+
 # RESTRICTED
 
 FULL_PROTOS = [
@@ -113,7 +122,6 @@ java_library(
 java_library(
     name = "cleartext_keyset_handle",
     visibility = [
-        "//tools/testing:__subpackages__",
         "//tools/tinkey:__pkg__",
     ],
     exports = [
@@ -123,10 +131,6 @@ java_library(
 
 java_library(
     name = "cleartext_keyset_handle_android",
-    visibility = [
-        "//tools/testing:__subpackages__",
-        "//tools/tinkey:__pkg__",
-    ],
     exports = [
         "//java/src/main/java/com/google/crypto/tink:cleartext_keyset_handle_android",
     ],
diff --git a/java/src/main/java/com/google/crypto/tink/config/BUILD b/java/src/main/java/com/google/crypto/tink/config/BUILD
index a8b07639f158d235b0cebeeda79d596635e9905e..6709d53e6d3e545422f437d0a6fae51aa417189e 100644
--- a/java/src/main/java/com/google/crypto/tink/config/BUILD
+++ b/java/src/main/java/com/google/crypto/tink/config/BUILD
@@ -29,7 +29,7 @@ java_library(
     javacopts = JAVACOPTS,
     deps = [
         "tink_catalogue_android",
-        "//java/src/main/java/com/google/crypto/tink",
+        "//java/src/main/java/com/google/crypto/tink:android",
         "//proto:config_java_proto_lite",
     ],
 )
diff --git a/java/src/main/java/com/google/crypto/tink/integration/BUILD b/java/src/main/java/com/google/crypto/tink/integration/BUILD
index 2afda198761aba0ffb32c7625ba5ba4c805b69c5..092d6bd281326ab7c8e097fef15c0829e6e7657a 100644
--- a/java/src/main/java/com/google/crypto/tink/integration/BUILD
+++ b/java/src/main/java/com/google/crypto/tink/integration/BUILD
@@ -26,13 +26,14 @@ java_library(
     runtime_deps = [
         "@com_fasterxml_jackson_annotations//jar",
         "@com_fasterxml_jackson_databind//jar",
+        "@com_google_code_gson_gson//jar",
+        "@joda_time//jar",
         "@org_apache_commons_logging//jar",
         "@org_apache_httpcomponents_httpclient//jar",
         "@org_apache_httpcomponents_httpcore//jar",
     ],
     deps = [
         "//java/src/main/java/com/google/crypto/tink",
-        "//java/src/main/java/com/google/crypto/tink/subtle:aead",
         "@com_amazonaws_sdk_core//jar",
         "@com_amazonaws_sdk_kms//jar",
         "@com_google_api_client//jar",
diff --git a/java/src/main/java/com/google/crypto/tink/subtle/BUILD b/java/src/main/java/com/google/crypto/tink/subtle/BUILD
index cc98c416866483512cde21ff35e5425fad15d319..dc9db938d2f45712cc6deba10ba0313b6bc29669 100644
--- a/java/src/main/java/com/google/crypto/tink/subtle/BUILD
+++ b/java/src/main/java/com/google/crypto/tink/subtle/BUILD
@@ -22,7 +22,6 @@ java_library(
     ],
     javacopts = JAVACOPTS,
     deps = [
-        "//java/src/main/java/com/google/crypto/tink:primitives",
         "@com_google_errorprone_error_prone_annotations//jar",
     ],
 )
diff --git a/java/src/test/java/com/google/crypto/tink/config/ConfigTest.java b/java/src/test/java/com/google/crypto/tink/config/ConfigTest.java
index 4ae7612aaa7c3519350ea3fc3c939630ddf9b5e4..459803bad8c511a8051bdfad144327e853f7a5c2 100644
--- a/java/src/test/java/com/google/crypto/tink/config/ConfigTest.java
+++ b/java/src/test/java/com/google/crypto/tink/config/ConfigTest.java
@@ -47,14 +47,14 @@ public class ConfigTest {
         .setNewKeyAllowed(true)
         .build();
     try {
-      KeyManager<Aead> keyManager = Registry.getKeyManager(typeUrl);
+      KeyManager<Aead> unused = Registry.getKeyManager(typeUrl);
       fail();
     } catch (GeneralSecurityException e) {
       // expected
     }
 
     Config.registerKeyType(entry);
-    KeyManager<Aead> keyManager = Registry.getKeyManager(typeUrl);
+    KeyManager<Aead> unused = Registry.getKeyManager(typeUrl);
   }
 
   @Test
@@ -74,7 +74,7 @@ public class ConfigTest {
       // Initially, there should be no key manager in the registry.
       for (KeyTypeEntry entry : tinkConfig.getEntryList()) {
         try {
-          KeyManager<?> keyManager = Registry.getKeyManager(entry.getTypeUrl());
+          KeyManager<?> unused = Registry.getKeyManager(entry.getTypeUrl());
           fail("Registry should contain no manager for " + entry.getTypeUrl());
         } catch (GeneralSecurityException e) {
           // expected
@@ -83,7 +83,7 @@ public class ConfigTest {
       // After registering the config the registry should contain the key managers.
       Config.register(tinkConfig);
       for (KeyTypeEntry entry : tinkConfig.getEntryList()) {
-        KeyManager<?> keyManager = Registry.getKeyManager(entry.getTypeUrl());
+        KeyManager<?> unused = Registry.getKeyManager(entry.getTypeUrl());
       }
       // Another register-attmpt should fail, as key managers already exist.
       try {
diff --git a/proto/config.proto b/proto/config.proto
index 92b98f11a64521cc8f0d031fc0315a8b99283db1..239d1a9d09b251a3fc37c67d552a3839bd7aaf9e 100644
--- a/proto/config.proto
+++ b/proto/config.proto
@@ -40,4 +40,4 @@ message KeyTypeEntry {
 message TinkConfig {
   string config_name = 1;
   repeated KeyTypeEntry entry = 2;
-}
\ No newline at end of file
+}
diff --git a/tools/testing/BUILD b/tools/testing/BUILD
index fe9accb9248168681af7c102e42de7e10ffca8c9..a9e5d84bb27becbdf5484cb88632e04e3c81f286 100644
--- a/tools/testing/BUILD
+++ b/tools/testing/BUILD
@@ -4,6 +4,7 @@ load("//java/build_defs:javac.bzl", "JAVACOPTS")
 
 java_binary(
     name = "hybrid_encrypt_cli_java",
+    testonly = 1,
     srcs = [
         "java/com/google/crypto/tink/testing/HybridEncryptCli.java",
     ],
@@ -11,14 +12,14 @@ java_binary(
     main_class = "com.google.crypto.tink.testing.HybridEncryptCli",
     visibility = ["//tools/testing:__subpackages__"],
     deps = [
-        "//java",
-        "//java:cleartext_keyset_handle",
         "//java:config",
+        "//java:testonly",
     ],
 )
 
 java_binary(
     name = "hybrid_decrypt_cli_java",
+    testonly = 1,
     srcs = [
         "java/com/google/crypto/tink/testing/HybridDecryptCli.java",
     ],
@@ -26,8 +27,7 @@ java_binary(
     main_class = "com.google.crypto.tink.testing.HybridDecryptCli",
     visibility = ["//tools/testing:__subpackages__"],
     deps = [
-        "//java",
-        "//java:cleartext_keyset_handle",
         "//java:config",
+        "//java:testonly",
     ],
 )
diff --git a/tools/tinkey/src/test/java/com/google/crypto/tink/tinkey/AddCommandTest.java b/tools/tinkey/src/test/java/com/google/crypto/tink/tinkey/AddCommandTest.java
index a96fcbef2fc87775bd66dc011e9b4bf80a86d6a8..9fdc52d8b392e15776c63353a38273e49911c662 100644
--- a/tools/tinkey/src/test/java/com/google/crypto/tink/tinkey/AddCommandTest.java
+++ b/tools/tinkey/src/test/java/com/google/crypto/tink/tinkey/AddCommandTest.java
@@ -17,6 +17,7 @@
 package com.google.crypto.tink.tinkey;
 
 import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
 
 import com.google.crypto.tink.KeysetReader;
 import com.google.crypto.tink.TestUtil;
@@ -92,6 +93,7 @@ public class AddCommandTest {
           outputStream, OUTPUT_FORMAT,
           emptyStream, INPUT_FORMAT,
           masterKeyUri, credentialPath, NEW_TEMPLATE);
+      fail("Expected GeneralSecurityException");
     } catch (GeneralSecurityException e) {
       TestUtil.assertExceptionContains(e, "empty keyset");
     }
diff --git a/tools/tinkey/src/test/java/com/google/crypto/tink/tinkey/RotateCommandTest.java b/tools/tinkey/src/test/java/com/google/crypto/tink/tinkey/RotateCommandTest.java
index 40752bd0c5b0dc60ff258b516c8662fac6a310fb..77bd87b098af3337312f6863b40439e4457e1c21 100644
--- a/tools/tinkey/src/test/java/com/google/crypto/tink/tinkey/RotateCommandTest.java
+++ b/tools/tinkey/src/test/java/com/google/crypto/tink/tinkey/RotateCommandTest.java
@@ -17,6 +17,7 @@
 package com.google.crypto.tink.tinkey;
 
 import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
 
 import com.google.crypto.tink.KeysetReader;
 import com.google.crypto.tink.TestUtil;
@@ -92,6 +93,7 @@ public class RotateCommandTest {
           outputStream, OUTPUT_FORMAT,
           emptyStream, INPUT_FORMAT,
           masterKeyUri, credentialPath, NEW_TEMPLATE);
+      fail("Expected GeneralSecurityException");
     } catch (GeneralSecurityException e) {
       TestUtil.assertExceptionContains(e, "empty keyset");
     }