@Override public boolean onStartJob(final JobParameters job) { PLog.d(ParseFCM.TAG, "Updating FCM token"); ParseInstallation installation = ParseInstallation.getCurrentInstallation(); String token = FirebaseInstanceId.getInstance().getToken(); if (installation != null && token != null) { installation.setDeviceToken(token); //even though this is FCM, calling it gcm will work on the backend installation.setPushType(PUSH_TYPE); installation.saveInBackground(new SaveCallback() { @Override public void done(ParseException e) { if (e == null) { PLog.d(ParseFCM.TAG, "FCM token saved to installation"); jobFinished(job, false); } else { PLog.e(ParseFCM.TAG, "FCM token upload failed", e); jobFinished(job, true); } } }); return true; } return false; // Answers the question: "Is there still work going on?" }
/* package */ void updateDeviceInfo(InstallationId installationId) { /* * If we don't have an installationId, use the one that comes from the installationId file on * disk. This should be impossible since we set the installationId in setDefaultValues. */ if (!has(KEY_INSTALLATION_ID)) { performPut(KEY_INSTALLATION_ID, installationId.get()); } String deviceType = "android"; if (!deviceType.equals(get(KEY_DEVICE_TYPE))) { performPut(KEY_DEVICE_TYPE, deviceType); } }
/** * Returns the unique ID of this installation. * * @return A UUID that represents this device. */ public String getInstallationId() { return getString(KEY_INSTALLATION_ID); }
private void updateTimezone() { String zone = TimeZone.getDefault().getID(); if ((zone.indexOf('/') > 0 || zone.equals("GMT")) && !zone.equals(get(KEY_TIME_ZONE))) { performPut(KEY_TIME_ZONE, zone); } }
@Override public Task<Void> then(Task<ParseInstallation> task) { ParseInstallation installation = task.getResult(); List<String> channels = installation.getList(ParseInstallation.KEY_CHANNELS); if (channels == null || installation.isDirty(ParseInstallation.KEY_CHANNELS) || !channels.contains(channel)) { installation.addUnique(ParseInstallation.KEY_CHANNELS, channel); return installation.saveInBackground(); } else { return Task.forResult(null); } } });
@Override public Void call() { try { InstanceID instanceID = InstanceID.getInstance(getApplicationContext()); String senderId = job.getExtras().getString(KEY_GCM_SENDER_ID); String token = instanceID.getToken(senderId, GoogleCloudMessaging.INSTANCE_ID_SCOPE, null); ParseInstallation installation = ParseInstallation.getCurrentInstallation(); installation.setDeviceToken(token); //even though this is FCM, calling it gcm will work on the backend installation.setPushType(PUSH_TYPE); installation.save(); PLog.d(ParseGCM.TAG, "GCM registration success"); } catch (Exception e) { PLog.e(ParseGCM.TAG, "GCM registration failed", e); jobFinished(job, true); } return null; } });
.put("deviceToken", "deviceToken") .build(); ParseInstallation installation = ParseInstallation.getCurrentInstallation(); assertNotNull(installation); installation.setState(state); installation.put("key", "value"); ParseTaskUtils.wait(installation.saveAsync(sessionToken, toAwait));
@Test public void testDeviceToken() { ParseInstallation installation = new ParseInstallation(); installation.setDeviceToken("deviceToken"); assertEquals("deviceToken", installation.getDeviceToken()); installation.removeDeviceToken(); assertNull(installation.getDeviceToken()); // Make sure we add the pushType to operationSetQueue instead of serverData assertEquals(1, installation.operationSetQueue.getLast().size()); }
@Test public void testHandleSaveResultAsync() throws Exception { // Mock currentInstallationController to make setAsync work ParseCurrentInstallationController controller = mock(ParseCurrentInstallationController.class); when(controller.setAsync(any(ParseInstallation.class))).thenReturn(Task.<Void>forResult(null)); ParseCorePlugins.getInstance().registerCurrentInstallationController(controller); // Mock return state ParseInstallation.State state = new ParseInstallation.State.Builder("_Installation") .put("key", "value") .build(); ParseInstallation installation = new ParseInstallation(); installation.put("keyAgain", "valueAgain"); ParseOperationSet operationSet = installation.startSave(); ParseTaskUtils.wait(installation.handleSaveResultAsync(state, operationSet)); // Make sure the installation data is correct assertEquals("value", installation.get("key")); assertEquals("valueAgain", installation.get("keyAgain")); // Make sure we set the currentInstallation verify(controller, times(1)).setAsync(installation); }
@Test public void testMissingRequiredFieldWhenSaveAsync() throws Exception { String sessionToken = "sessionToken"; Task<Void> toAwait = Task.forResult(null); ParseCurrentInstallationController controller = mockCurrentInstallationController(); ParseObjectController objController = mock(ParseObjectController.class); // mock return task when Installation was deleted on the server Task<ParseObject.State> taskError = Task.forError(new ParseException(ParseException.MISSING_REQUIRED_FIELD_ERROR, "")); // mock return task when Installation was re-saved to the server Task<ParseObject.State> task = Task.forResult(null); when(objController.saveAsync( any(ParseObject.State.class), any(ParseOperationSet.class), eq(sessionToken), any(ParseDecoder.class))) .thenReturn(taskError) .thenReturn(task); ParseCorePlugins.getInstance() .registerObjectController(objController); ParseInstallation installation = ParseInstallation.getCurrentInstallation(); assertNotNull(installation); installation.put("key", "value"); ParseTaskUtils.wait(installation.saveAsync(sessionToken, toAwait)); verify(controller).getAsync(); verify(objController, times(2)).saveAsync( any(ParseObject.State.class), any(ParseOperationSet.class), eq(sessionToken), any(ParseDecoder.class)); }
@Override public Task<Void> then(Task<ParseInstallation> task) { ParseInstallation installation = task.getResult(); List<String> channels = installation.getList(ParseInstallation.KEY_CHANNELS); if (channels != null && channels.contains(channel)) { installation.removeAll( ParseInstallation.KEY_CHANNELS, Collections.singletonList(channel)); return installation.saveInBackground(); } else { return Task.forResult(null); } } });
@Test public void testDeviceTokenWithNullDeviceToken() { ParseInstallation installation = new ParseInstallation(); installation.setDeviceToken("deviceToken"); assertEquals("deviceToken", installation.getDeviceToken()); installation.setDeviceToken(null); assertEquals("deviceToken", installation.getDeviceToken()); }
@Override public Task<Void> then(Task<Void> task) { // Retry the fetch as a save operation because this Installation was deleted on the server. if (task.getError() != null && task.getError() instanceof ParseException) { int errCode = ((ParseException) task.getError()).getCode(); if (errCode == ParseException.OBJECT_NOT_FOUND || (errCode == ParseException.MISSING_REQUIRED_FIELD_ERROR && getObjectId() == null)) { synchronized (mutex) { setState(new State.Builder(getState()).objectId(null).build()); markAllFieldsDirty(); return ParseInstallation.super.saveAsync(sessionToken, toAwait); } } } return task; } });
@Test public void testLocaleIdentifierSpecialCases() { mocksForUpdateBeforeSave(); ParseInstallation installation = new ParseInstallation(); // Deprecated two-letter codes (Java issue). Locale.setDefault(new Locale("iw", "US")); installation.updateBeforeSave(); assertEquals("he-US", installation.getString(KEY_LOCALE_IDENTIFIER)); Locale.setDefault(new Locale("in", "US")); installation.updateBeforeSave(); assertEquals("id-US", installation.getString(KEY_LOCALE_IDENTIFIER)); Locale.setDefault(new Locale("ji", "US")); installation.updateBeforeSave(); assertEquals("yi-US", installation.getString(KEY_LOCALE_IDENTIFIER)); // No country code. Locale.setDefault(new Locale("en")); installation.updateBeforeSave(); assertEquals("en", installation.getString(KEY_LOCALE_IDENTIFIER)); }
}; ParseInstallation installation = new ParseInstallation(); installation.put("foo", "bar"); installation.put(immutableKey, "blah"); } catch (IllegalArgumentException e) { assertTrue(e.getMessage().contains("Cannot modify")); installation.remove(immutableKey); } catch (IllegalArgumentException e) { assertTrue(e.getMessage().contains("Cannot modify")); installation.removeAll(immutableKey, Collections.emptyList()); } catch (IllegalArgumentException e) { assertTrue(e.getMessage().contains("Cannot modify"));
@Test public void testGetCurrentInstallation() { // Mock currentInstallationController to make setAsync work ParseCurrentInstallationController controller = mock(ParseCurrentInstallationController.class); ParseInstallation currentInstallation = new ParseInstallation(); when(controller.getAsync()).thenReturn(Task.forResult(currentInstallation)); ParseCorePlugins.getInstance().registerCurrentInstallationController(controller); ParseInstallation installation = ParseInstallation.getCurrentInstallation(); assertEquals(currentInstallation, installation); verify(controller, times(1)).getAsync(); }
@Test public void testGetAsyncWithNoInstallation() throws Exception { // Mock installationId InstallationId installationId = mock(InstallationId.class); when(installationId.get()).thenReturn("testInstallationId"); //noinspection unchecked ParseObjectStore<ParseInstallation> store = mock(ParseObjectStore.class); when(store.getAsync()).thenReturn(Task.<ParseInstallation>forResult(null)); // Create test controller CachedCurrentInstallationController controller = new CachedCurrentInstallationController(store, installationId); ParseInstallation currentInstallation = ParseTaskUtils.wait(controller.getAsync()); verify(store, times(1)).getAsync(); // Make sure controller state is update to date assertSame(controller.currentInstallation, currentInstallation); // Make sure device info is updated assertEquals("testInstallationId", currentInstallation.getInstallationId()); assertEquals("android", currentInstallation.get(KEY_DEVICE_TYPE)); }
@Test public void testHandleFetchResultAsync() throws Exception { // Mock currentInstallationController to make setAsync work ParseCurrentInstallationController controller = mock(ParseCurrentInstallationController.class); when(controller.setAsync(any(ParseInstallation.class))).thenReturn(Task.<Void>forResult(null)); ParseCorePlugins.getInstance().registerCurrentInstallationController(controller); // Mock return state ParseInstallation.State state = new ParseInstallation.State.Builder("_Installation") .put("key", "value") .isComplete(true) .build(); ParseInstallation installation = new ParseInstallation(); ParseTaskUtils.wait(installation.handleFetchResultAsync(state)); // Make sure the installation data is correct assertEquals("value", installation.get("key")); // Make sure we set the currentInstallation verify(controller, times(1)).setAsync(installation); }
@Override /* package */ <T extends ParseObject> Task<T> fetchAsync( final String sessionToken, final Task<Void> toAwait) { synchronized (mutex) { // Because the Service and the global currentInstallation are different objects, we may not // have the same ObjectID (we never will at bootstrap). The server has a special hack for // _Installation where save with an existing InstallationID will merge Object IDs Task<Void> result; if (getObjectId() == null) { result = saveAsync(sessionToken, toAwait); } else { result = Task.forResult(null); } return result.onSuccessTask(new Continuation<Void, Task<T>>() { @Override public Task<T> then(Task<Void> task) { return ParseInstallation.super.fetchAsync(sessionToken, toAwait); } }); } }
ParseInstallation installation = new ParseInstallation(); installation.updateBeforeSave(); String zone = installation.getString(KEY_TIME_ZONE); String deviceZone = TimeZone.getDefault().getID(); if (zone != null) { String appVersion = pkgInfo.versionName; String appName = pm.getApplicationLabel(pm.getApplicationInfo(packageName, 0)).toString(); assertEquals(packageName, installation.getString(KEY_APP_IDENTIFIER)); assertEquals(appName, installation.getString(KEY_APP_NAME)); assertEquals(appVersion, installation.getString(KEY_APP_VERSION)); assertEquals("android", installation.getString(KEY_DEVICE_TYPE)); assertEquals("installationId", installation.getString(KEY_INSTALLATION_ID)); assertEquals("en-US", installation.getString(KEY_LOCALE_IDENTIFIER));