From 5655a783e8bc92560795e9d2094203c156234347 Mon Sep 17 00:00:00 2001 From: patloew Date: Tue, 25 Oct 2016 18:29:01 +0200 Subject: [PATCH] Add Goals API. --- CHANGELOG.md | 5 + README.md | 2 +- build.gradle | 4 +- library/build.gradle | 16 +-- .../main/java/com/patloew/rxfit/Goals.java | 57 ++++++++++ .../patloew/rxfit/GoalsReadCurrentSingle.java | 52 +++++++++ .../main/java/com/patloew/rxfit/RxFit.java | 5 + .../patloew/rxfit/BaseOnSubscribeTest.java | 3 + .../patloew/rxfit/GoalsOnSubscribeTest.java | 104 ++++++++++++++++++ .../java/com/patloew/rxfit/GoalsTest.java | 69 ++++++++++++ sample/build.gradle | 20 ++-- 11 files changed, 316 insertions(+), 21 deletions(-) create mode 100644 library/src/main/java/com/patloew/rxfit/Goals.java create mode 100644 library/src/main/java/com/patloew/rxfit/GoalsReadCurrentSingle.java create mode 100644 library/src/test/java/com/patloew/rxfit/GoalsOnSubscribeTest.java create mode 100644 library/src/test/java/com/patloew/rxfit/GoalsTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 9af9b4d..c2782f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## Version 1.5.0 + +* Updated Play Services (9.8.0) and RxJava (1.2.1). +* Added support for Goals API. + ## Version 1.4.0 * Updated Play Services (9.6.1) and RxJava (1.2.0). diff --git a/README.md b/README.md index d714b61..b7eb00c 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ A basic sample app is available in the `sample` project. You need to create an O The lib is available on jCenter. Add the following to your `build.gradle`: dependencies { - compile 'com.patloew.rxfit:rxfit:1.4.0' + compile 'com.patloew.rxfit:rxfit:1.5.0' } # Testing diff --git a/build.gradle b/build.gradle index c1fc253..179af08 100644 --- a/build.gradle +++ b/build.gradle @@ -5,9 +5,9 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.2.1' + classpath 'com.android.tools.build:gradle:2.2.2' - classpath 'me.tatarka:gradle-retrolambda:3.3.0' + classpath 'me.tatarka:gradle-retrolambda:3.3.1' classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.1' classpath "com.github.dcendents:android-maven-gradle-plugin:1.5" diff --git a/library/build.gradle b/library/build.gradle index 124036f..d92095c 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -4,18 +4,18 @@ apply plugin: 'com.jfrog.bintray' apply plugin: 'com.github.dcendents.android-maven' group = 'com.patloew.rxfit' -version = '1.4.0' +version = '1.5.0' project.archivesBaseName = 'rxfit' android { - compileSdkVersion 24 - buildToolsVersion "24.0.2" + compileSdkVersion 25 + buildToolsVersion "25.0.0" defaultConfig { minSdkVersion 9 - targetSdkVersion 24 - versionCode 7 - versionName "1.4.0" + targetSdkVersion 25 + versionCode 8 + versionName "1.5.0" } buildTypes { release { @@ -33,8 +33,8 @@ android { dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) - compile 'io.reactivex:rxjava:1.2.0' - compile 'com.google.android.gms:play-services-fitness:9.6.1' + compile 'io.reactivex:rxjava:1.2.1' + compile 'com.google.android.gms:play-services-fitness:9.8.0' testCompile 'junit:junit:4.12' testCompile 'org.mockito:mockito-core:1.10.19' diff --git a/library/src/main/java/com/patloew/rxfit/Goals.java b/library/src/main/java/com/patloew/rxfit/Goals.java new file mode 100644 index 0000000..194937f --- /dev/null +++ b/library/src/main/java/com/patloew/rxfit/Goals.java @@ -0,0 +1,57 @@ +package com.patloew.rxfit; + +import android.support.annotation.NonNull; + +import com.google.android.gms.fitness.data.Goal; +import com.google.android.gms.fitness.request.GoalsReadRequest; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +import rx.Observable; +import rx.Single; +import rx.functions.Func1; + +/* Copyright 2016 Patrick Löwenstein + * + * 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. */ +public class Goals { + + private final RxFit rxFit; + + Goals(RxFit rxFit) { + this.rxFit = rxFit; + } + + + // read current + + public Observable readCurrent(@NonNull GoalsReadRequest goalsReadRequest) { + return readCurrentInternal(goalsReadRequest, null, null); + } + + public Observable readCurrent(@NonNull GoalsReadRequest goalsReadRequest, long timeout, @NonNull TimeUnit timeUnit) { + return readCurrentInternal(goalsReadRequest, timeout, timeUnit); + } + + private Observable readCurrentInternal(GoalsReadRequest goalsReadRequest, Long timeout, TimeUnit timeUnit) { + return Single.create(new GoalsReadCurrentSingle(rxFit, goalsReadRequest, timeout, timeUnit)) + .flatMapObservable(new Func1, Observable>() { + @Override + public Observable call(List goals) { + return Observable.from(goals); + } + }); + } + +} diff --git a/library/src/main/java/com/patloew/rxfit/GoalsReadCurrentSingle.java b/library/src/main/java/com/patloew/rxfit/GoalsReadCurrentSingle.java new file mode 100644 index 0000000..87d69ef --- /dev/null +++ b/library/src/main/java/com/patloew/rxfit/GoalsReadCurrentSingle.java @@ -0,0 +1,52 @@ +package com.patloew.rxfit; + +import android.support.annotation.NonNull; + +import com.google.android.gms.common.api.GoogleApiClient; +import com.google.android.gms.common.api.ResultCallback; +import com.google.android.gms.fitness.Fitness; +import com.google.android.gms.fitness.data.Goal; +import com.google.android.gms.fitness.request.GoalsReadRequest; +import com.google.android.gms.fitness.result.GoalsResult; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +import rx.SingleSubscriber; + +/* Copyright 2016 Patrick Löwenstein + * + * 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. */ +class GoalsReadCurrentSingle extends BaseSingle> { + + final GoalsReadRequest goalsReadRequest; + + GoalsReadCurrentSingle(RxFit rxFit, GoalsReadRequest goalsReadRequest, Long timeout, TimeUnit timeUnit) { + super(rxFit, timeout, timeUnit); + this.goalsReadRequest = goalsReadRequest; + } + + @Override + protected void onGoogleApiClientReady(GoogleApiClient apiClient, final SingleSubscriber> subscriber) { + setupFitnessPendingResult(Fitness.GoalsApi.readCurrentGoals(apiClient, goalsReadRequest), new ResultCallback() { + @Override + public void onResult(@NonNull GoalsResult goalsResult) { + if (!goalsResult.getStatus().isSuccess()) { + subscriber.onError(new StatusException(goalsResult.getStatus())); + } else { + subscriber.onSuccess(goalsResult.getGoals()); + } + } + }); + } +} diff --git a/library/src/main/java/com/patloew/rxfit/RxFit.java b/library/src/main/java/com/patloew/rxfit/RxFit.java index 26f0199..9ab8d39 100644 --- a/library/src/main/java/com/patloew/rxfit/RxFit.java +++ b/library/src/main/java/com/patloew/rxfit/RxFit.java @@ -42,6 +42,7 @@ public class RxFit { private final Ble ble = new Ble(this); private final Config config = new Config(this); + private final Goals goals = new Goals(this); private final History history = new History(this); private final Recording recording = new Recording(this); private final Sensors sensors = new Sensors(this); @@ -99,6 +100,10 @@ public Config config() { return config; } + public Goals goals() { + return goals; + } + public History history() { return history; } diff --git a/library/src/test/java/com/patloew/rxfit/BaseOnSubscribeTest.java b/library/src/test/java/com/patloew/rxfit/BaseOnSubscribeTest.java index f70043c..c8ffd9b 100644 --- a/library/src/test/java/com/patloew/rxfit/BaseOnSubscribeTest.java +++ b/library/src/test/java/com/patloew/rxfit/BaseOnSubscribeTest.java @@ -12,6 +12,7 @@ import com.google.android.gms.fitness.BleApi; import com.google.android.gms.fitness.ConfigApi; import com.google.android.gms.fitness.Fitness; +import com.google.android.gms.fitness.GoalsApi; import com.google.android.gms.fitness.HistoryApi; import com.google.android.gms.fitness.RecordingApi; import com.google.android.gms.fitness.SensorsApi; @@ -44,6 +45,7 @@ public abstract class BaseOnSubscribeTest extends BaseTest { @Mock BleApi bleApi; @Mock ConfigApi configApi; + @Mock GoalsApi goalsApi; @Mock HistoryApi historyApi; @Mock RecordingApi recordingApi; @Mock SensorsApi sensorsApi; @@ -54,6 +56,7 @@ public void setup() throws Exception { PowerMockito.mockStatic(Fitness.class); Whitebox.setInternalState(Fitness.class, bleApi); Whitebox.setInternalState(Fitness.class, configApi); + Whitebox.setInternalState(Fitness.class, goalsApi); Whitebox.setInternalState(Fitness.class, historyApi); Whitebox.setInternalState(Fitness.class, recordingApi); Whitebox.setInternalState(Fitness.class, sensorsApi); diff --git a/library/src/test/java/com/patloew/rxfit/GoalsOnSubscribeTest.java b/library/src/test/java/com/patloew/rxfit/GoalsOnSubscribeTest.java new file mode 100644 index 0000000..a0eb9ec --- /dev/null +++ b/library/src/test/java/com/patloew/rxfit/GoalsOnSubscribeTest.java @@ -0,0 +1,104 @@ +package com.patloew.rxfit; + +import android.app.PendingIntent; +import android.support.v4.content.ContextCompat; + +import com.google.android.gms.common.ConnectionResult; +import com.google.android.gms.common.api.GoogleApiClient; +import com.google.android.gms.common.api.Status; +import com.google.android.gms.fitness.Fitness; +import com.google.android.gms.fitness.data.DataPoint; +import com.google.android.gms.fitness.data.DataSource; +import com.google.android.gms.fitness.data.DataType; +import com.google.android.gms.fitness.data.Goal; +import com.google.android.gms.fitness.request.DataSourcesRequest; +import com.google.android.gms.fitness.request.GoalsReadRequest; +import com.google.android.gms.fitness.request.OnDataPointListener; +import com.google.android.gms.fitness.request.SensorRequest; +import com.google.android.gms.fitness.result.DataSourcesResult; +import com.google.android.gms.fitness.result.GoalsResult; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Matchers; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareOnlyThisForTest; +import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor; +import org.powermock.modules.junit4.PowerMockRunner; + +import java.util.ArrayList; +import java.util.List; + +import rx.Observable; +import rx.Single; +import rx.observers.TestSubscriber; + +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@RunWith(PowerMockRunner.class) +@SuppressStaticInitializationFor("com.google.android.gms.fitness.Fitness") +@PrepareOnlyThisForTest({ ContextCompat.class, Fitness.class, Status.class, ConnectionResult.class, BaseRx.class }) +public class GoalsOnSubscribeTest extends BaseOnSubscribeTest { + + @Mock GoalsReadRequest goalsReadRequest; + @Mock Goal goal; + + @Override + @Before + public void setup() throws Exception { + MockitoAnnotations.initMocks(this); + super.setup(); + } + + // GoalsReadCurrentSingle + + @Test + public void GoalsReadCurrentSingle_Success() { + TestSubscriber> sub = new TestSubscriber<>(); + GoalsResult goalsResult = Mockito.mock(GoalsResult.class); + + GoalsReadCurrentSingle single = PowerMockito.spy(new GoalsReadCurrentSingle(rxFit, goalsReadRequest, null, null)); + + List goalList = new ArrayList<>(); + goalList.add(goal); + when(goalsResult.getGoals()).thenReturn(goalList); + + setPendingResultValue(goalsResult); + when(goalsResult.getStatus()).thenReturn(status); + when(status.isSuccess()).thenReturn(true); + when(goalsApi.readCurrentGoals(apiClient, goalsReadRequest)).thenReturn(pendingResult); + + setupBaseSingleSuccess(single); + Single.create(single).subscribe(sub); + + assertSingleValue(sub, goalList); + } + + @Test + public void GoalsReadCurrentSingle_StatusException() { + TestSubscriber> sub = new TestSubscriber<>(); + GoalsResult goalsResult = Mockito.mock(GoalsResult.class); + + GoalsReadCurrentSingle single = PowerMockito.spy(new GoalsReadCurrentSingle(rxFit, goalsReadRequest, null, null)); + + List goalList = new ArrayList<>(); + goalList.add(goal); + when(goalsResult.getGoals()).thenReturn(goalList); + + setPendingResultValue(goalsResult); + when(goalsResult.getStatus()).thenReturn(status); + when(status.isSuccess()).thenReturn(false); + when(goalsApi.readCurrentGoals(apiClient, goalsReadRequest)).thenReturn(pendingResult); + + setupBaseSingleSuccess(single); + Single.create(single).subscribe(sub); + + assertError(sub, StatusException.class); + } +} diff --git a/library/src/test/java/com/patloew/rxfit/GoalsTest.java b/library/src/test/java/com/patloew/rxfit/GoalsTest.java new file mode 100644 index 0000000..e1e947a --- /dev/null +++ b/library/src/test/java/com/patloew/rxfit/GoalsTest.java @@ -0,0 +1,69 @@ +package com.patloew.rxfit; + +import android.app.PendingIntent; +import android.support.v4.content.ContextCompat; + +import com.google.android.gms.common.ConnectionResult; +import com.google.android.gms.common.api.Status; +import com.google.android.gms.fitness.Fitness; +import com.google.android.gms.fitness.data.DataType; +import com.google.android.gms.fitness.request.DataSourcesRequest; +import com.google.android.gms.fitness.request.GoalsReadRequest; +import com.google.android.gms.fitness.request.SensorRequest; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareOnlyThisForTest; +import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor; +import org.powermock.modules.junit4.PowerMockRunner; + +import rx.Observable; +import rx.Single; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNull; +import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.times; + +@RunWith(PowerMockRunner.class) +@SuppressStaticInitializationFor("com.google.android.gms.fitness.Fitness") +@PrepareOnlyThisForTest({ Observable.class, Single.class, ContextCompat.class, Fitness.class, Status.class, ConnectionResult.class }) +public class GoalsTest extends BaseTest { + + @Override + @Before + public void setup() throws Exception { + MockitoAnnotations.initMocks(this); + PowerMockito.spy(Single.class); + PowerMockito.mockStatic(Observable.class); + super.setup(); + } + + // Read Current + + @Test + public void Goals_ReadCurrent() throws Exception { + ArgumentCaptor captor = ArgumentCaptor.forClass(GoalsReadCurrentSingle.class); + + final GoalsReadRequest request = Mockito.mock(GoalsReadRequest.class); + rxFit.goals().readCurrent(request); + rxFit.goals().readCurrent(request, TIMEOUT_TIME, TIMEOUT_TIMEUNIT); + + PowerMockito.verifyStatic(atLeast(2)); + Single.create(captor.capture()); + + GoalsReadCurrentSingle single = captor.getAllValues().get(0); + assertEquals(request, single.goalsReadRequest); + assertNoTimeoutSet(single); + + single = captor.getAllValues().get(2); + assertEquals(request, single.goalsReadRequest); + assertTimeoutSet(single); + } + +} diff --git a/sample/build.gradle b/sample/build.gradle index 90601c2..ecfca6f 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -2,13 +2,13 @@ apply plugin: 'com.android.application' apply plugin: 'me.tatarka.retrolambda' android { - compileSdkVersion 24 - buildToolsVersion "24.0.2" + compileSdkVersion 25 + buildToolsVersion "25.0.0" defaultConfig { applicationId "com.patloew.rxfitsample" minSdkVersion 9 - targetSdkVersion 24 + targetSdkVersion 25 versionCode 1 versionName "1.0.0" } @@ -34,18 +34,18 @@ retrolambda { dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' - compile 'com.android.support:appcompat-v7:24.2.1' - compile "com.android.support:design:24.2.1" - compile "com.android.support:recyclerview-v7:24.2.1" - compile "com.android.support:gridlayout-v7:24.2.1" + compile 'com.android.support:appcompat-v7:25.0.0' + compile "com.android.support:design:25.0.0" + compile "com.android.support:recyclerview-v7:25.0.0" + compile "com.android.support:gridlayout-v7:25.0.0" compile project(':library') - //compile 'com.patloew.rxfit:rxfit:1.4.0' + //compile 'com.patloew.rxfit:rxfit:1.5.0' - compile 'io.reactivex:rxjava:1.2.0' + compile 'io.reactivex:rxjava:1.2.1' compile 'io.reactivex:rxandroid:1.2.1' - compile 'com.google.android.gms:play-services-fitness:9.6.1' + compile 'com.google.android.gms:play-services-fitness:9.8.0' testCompile 'junit:junit:4.12' testCompile 'org.mockito:mockito-core:1.10.19'