Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/androido #153

Merged
merged 13 commits into from
Sep 26, 2017
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@ android:
components:
- tools
- platform-tools
- build-tools-25.0.2
- android-24
- tools
- doc-24
- extra-android-m2repository
- sys-img-armeabi-v7a-android-24
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why downgrade? More users probably on 24 than 22.

- sys-img-armeabi-v7a-android-22
jdk:
- oraclejdk8
before_cache:
Expand All @@ -19,7 +18,8 @@ cache:
before_script:
- echo $TRAVIS_BRANCH
- echo $TRAVIS_TAG
- echo no | android create avd --force -n test -t android-24 --abi default/armeabi-v7a
- android list targets
- echo no | android create avd --force -n test -t android-22 --abi armeabi-v7a
- emulator -avd test -no-audio -no-window &
- android-wait-for-emulator
- adb shell input keyevent 82 &
Expand Down
6 changes: 3 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ allprojects {
}

ext {
compile_sdk_version = 24
build_tools_version = "25.0.2"
compile_sdk_version = 26
build_tools_version = "26.0.1"
min_sdk_version = 10
target_sdk_version = 24
target_sdk_version = 26

java_core_ver = "1.8.0"
android_logger_ver = "1.3.6"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public class DatafileLoaderTest {
private Client client;
private Logger logger;
private DatafileLoadedListener datafileLoadedListener;
Context context = InstrumentationRegistry.getTargetContext();

@Before
public void setup() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,19 @@

package com.optimizely.ab.android.datafile_handler;

import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.app.job.JobWorkItem;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.support.annotation.NonNull;

import com.optimizely.ab.android.shared.Cache;
import com.optimizely.ab.android.shared.JobWorkService;
import com.optimizely.ab.android.shared.ServiceScheduler;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -91,7 +98,7 @@ void dispatch(Intent intent) {
List<String> projectIds = backgroundWatchersCache.getWatchingProjectIds();
for (String projectId : projectIds) {
intent.putExtra(DatafileService.EXTRA_PROJECT_ID, projectId);
context.startService(intent);
ServiceScheduler.startService(context, DatafileService.JOB_ID, intent);

logger.info("Rescheduled data file watching for project {}", projectId);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,19 @@
package com.optimizely.ab.android.datafile_handler;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;

import com.optimizely.ab.android.shared.Cache;
import com.optimizely.ab.android.shared.Client;
import com.optimizely.ab.android.shared.OptlyStorage;
import com.optimizely.ab.android.shared.JobWorkScheduledService;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -38,13 +41,14 @@
* These services will only be used if you are using our {@link DefaultDatafileHandler}.
* You can chose to implement your own handler and use all or part of this package.
*/
public class DatafileService extends Service {
public class DatafileService extends Service implements JobWorkScheduledService {
/**
* Extra containing the project id this instance of Optimizely was built with
*/
public static final String EXTRA_PROJECT_ID = "com.optimizely.ab.android.EXTRA_PROJECT_ID";
public static final String FORMAT_VERSIONED_CDN_URL = "https://cdn.optimizely.com/public/%s/datafile_v%s.json";
static final String DATAFILE_VERSION = "3";
public static final Integer JOB_ID = 2113;

@NonNull private final IBinder binder = new LocalBinder();
Logger logger = LoggerFactory.getLogger(DatafileService.class);
Expand All @@ -57,26 +61,7 @@ public class DatafileService extends Service {
@RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null) {
if (intent.hasExtra(EXTRA_PROJECT_ID)) {
String projectId = intent.getStringExtra(EXTRA_PROJECT_ID);
DatafileClient datafileClient = new DatafileClient(
new Client(new OptlyStorage(getApplicationContext()), LoggerFactory.getLogger(OptlyStorage.class)),
LoggerFactory.getLogger(DatafileClient.class));
DatafileCache datafileCache = new DatafileCache(
projectId,
new Cache(getApplicationContext(), LoggerFactory.getLogger(Cache.class)),
LoggerFactory.getLogger(DatafileCache.class));

String datafileUrl = getDatafileUrl(projectId);
DatafileLoader datafileLoader = new DatafileLoader(this, datafileClient, datafileCache, Executors.newSingleThreadExecutor(), LoggerFactory.getLogger(DatafileLoader.class));
datafileLoader.getDatafile(datafileUrl, null);
} else {
logger.warn("Data file service received an intent with no project id extra");
}
} else {
logger.warn("Data file service received a null intent");
}
onWork(intent);
return super.onStartCommand(intent, flags, startId);
}

Expand Down Expand Up @@ -119,6 +104,37 @@ public void getDatafile(String projectId, DatafileLoader datafileLoader, Datafil
datafileLoader.getDatafile(datafileUrl, loadedListener);
}

@Override
public void initialize() {

}

@RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)
@Override
public void onWork(@Nullable Intent intent) {
if (intent != null) {
if (intent.hasExtra(EXTRA_PROJECT_ID)) {
String projectId = intent.getStringExtra(EXTRA_PROJECT_ID);
DatafileClient datafileClient = new DatafileClient(
new Client(new OptlyStorage(this.getApplicationContext()), LoggerFactory.getLogger(OptlyStorage.class)),
LoggerFactory.getLogger(DatafileClient.class));
DatafileCache datafileCache = new DatafileCache(
projectId,
new Cache(this.getApplicationContext(), LoggerFactory.getLogger(Cache.class)),
LoggerFactory.getLogger(DatafileCache.class));

String datafileUrl = getDatafileUrl(projectId);
DatafileLoader datafileLoader = new DatafileLoader(this, datafileClient, datafileCache, Executors.newSingleThreadExecutor(), LoggerFactory.getLogger(DatafileLoader.class));
datafileLoader.getDatafile(datafileUrl, null);
} else {
logger.warn("Data file service received an intent with no project id extra");
}
} else {
logger.warn("Data file service received a null intent");
}

}

public class LocalBinder extends Binder {
public DatafileService getService() {
// Return this instance of LocalService so clients can call public methods
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,13 @@ public void onServiceConnected(ComponentName className,
final DatafileService datafileService = binder.getService();
if (datafileService != null) {
DatafileClient datafileClient = new DatafileClient(
new Client(new OptlyStorage(datafileService.getApplicationContext()),
new Client(new OptlyStorage(context.getApplicationContext()),
LoggerFactory.getLogger(OptlyStorage.class)),
LoggerFactory.getLogger(DatafileClient.class));

DatafileCache datafileCache = new DatafileCache(
projectId,
new Cache(datafileService.getApplicationContext(), LoggerFactory.getLogger(Cache.class)),
new Cache(context.getApplicationContext(), LoggerFactory.getLogger(Cache.class)),
LoggerFactory.getLogger(DatafileCache.class));

DatafileLoader datafileLoader = new DatafileLoader(datafileService,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,9 @@ public void onStop(Context context) {
public void startBackgroundUpdates(Context context, String projectId, Long updateInterval) {
enableBackgroundCache(context, projectId);

AlarmManager alarmManager = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
ServiceScheduler.PendingIntentFactory pendingIntentFactory = new ServiceScheduler
.PendingIntentFactory(context.getApplicationContext());
ServiceScheduler serviceScheduler = new ServiceScheduler(alarmManager, pendingIntentFactory,
ServiceScheduler serviceScheduler = new ServiceScheduler(context, pendingIntentFactory,
LoggerFactory.getLogger(ServiceScheduler.class));

Intent intent = new Intent(context.getApplicationContext(), DatafileService.class);
Expand All @@ -127,11 +125,9 @@ public void startBackgroundUpdates(Context context, String projectId, Long updat
* @param projectId project id of the datafile uploading
*/
public void stopBackgroundUpdates(Context context, String projectId) {
AlarmManager alarmManager = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
ServiceScheduler.PendingIntentFactory pendingIntentFactory = new ServiceScheduler
.PendingIntentFactory(context.getApplicationContext());
ServiceScheduler serviceScheduler = new ServiceScheduler(alarmManager, pendingIntentFactory,
ServiceScheduler serviceScheduler = new ServiceScheduler(context, pendingIntentFactory,
LoggerFactory.getLogger(ServiceScheduler.class));
Intent intent = new Intent(context.getApplicationContext(), DatafileService.class);
serviceScheduler.unschedule(intent);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,33 @@

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.app.job.JobWorkItem;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;

import com.optimizely.ab.android.shared.JobWorkService;
import com.optimizely.ab.android.shared.OptlyStorage;
import com.optimizely.ab.android.shared.ServiceScheduler;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.slf4j.Logger;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

Expand All @@ -48,18 +57,27 @@ public class ServiceSchedulerTest {
private OptlyStorage optlyStorage;
private ServiceScheduler.PendingIntentFactory pendingIntentFactory;
private AlarmManager alarmManager;
private JobScheduler jobScheduler;
private Logger logger;
private ServiceScheduler serviceScheduler;
private Context context;

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Before
public void setup() {
context = InstrumentationRegistry.getTargetContext();
context = mock(Context.class);
optlyStorage = mock(OptlyStorage.class);
alarmManager = mock(AlarmManager.class);
jobScheduler = mock(JobScheduler.class);

when(context.getApplicationContext()).thenReturn(context);

when(context.getSystemService(Context.ALARM_SERVICE)).thenReturn(alarmManager);
when(context.getSystemService(Context.JOB_SCHEDULER_SERVICE)).thenReturn(jobScheduler);

pendingIntentFactory = mock(ServiceScheduler.PendingIntentFactory.class);
logger = mock(Logger.class);
serviceScheduler = new ServiceScheduler(alarmManager, pendingIntentFactory, logger);
serviceScheduler = new ServiceScheduler(context, pendingIntentFactory, logger);
}

@Test
Expand All @@ -72,7 +90,18 @@ public void testScheduleWithNoDurationExtra() {

serviceScheduler.schedule(intent, AlarmManager.INTERVAL_HOUR);

verify(alarmManager).setInexactRepeating(AlarmManager.ELAPSED_REALTIME, AlarmManager.INTERVAL_HOUR, AlarmManager.INTERVAL_HOUR, pendingIntent);
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
ArgumentCaptor<JobInfo> jobInfoArgumentCaptor = ArgumentCaptor.forClass(JobInfo.class);
ArgumentCaptor<JobWorkItem> workItemArgumentCaptor = ArgumentCaptor.forClass(JobWorkItem.class);

verify(jobScheduler).enqueue(jobInfoArgumentCaptor.capture(), workItemArgumentCaptor.capture());

assertEquals(jobInfoArgumentCaptor.getValue().getIntervalMillis(), AlarmManager.INTERVAL_HOUR );

}
else {
verify(alarmManager).setInexactRepeating(AlarmManager.ELAPSED_REALTIME, AlarmManager.INTERVAL_HOUR, AlarmManager.INTERVAL_HOUR, pendingIntent);
}
verify(logger).info("Scheduled {}", intent.getComponent().toShortString());
pendingIntent.cancel();
}
Expand All @@ -95,7 +124,18 @@ public void testScheduleWithDurationExtra() {
intent.putExtra(EventIntentService.EXTRA_INTERVAL, duration);
serviceScheduler.schedule(intent, duration);

verify(alarmManager).setInexactRepeating(AlarmManager.ELAPSED_REALTIME, duration, duration, pendingIntent);
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
ArgumentCaptor<JobInfo> jobInfoArgumentCaptor = ArgumentCaptor.forClass(JobInfo.class);
ArgumentCaptor<JobWorkItem> workItemArgumentCaptor = ArgumentCaptor.forClass(JobWorkItem.class);

verify(jobScheduler).enqueue(jobInfoArgumentCaptor.capture(), workItemArgumentCaptor.capture());

assertEquals(jobInfoArgumentCaptor.getValue().getIntervalMillis(), duration );
}
else {
verify(alarmManager).setInexactRepeating(AlarmManager.ELAPSED_REALTIME, duration, duration, pendingIntent);
}

verify(logger).info("Scheduled {}", intent.getComponent().toShortString());
pendingIntent.cancel();
}
Expand All @@ -104,7 +144,7 @@ public void testScheduleWithDurationExtra() {
public void testAlreadyScheduledAlarm() {
final Intent intent = new Intent(context, EventIntentService.class);
when(pendingIntentFactory.hasPendingIntent(intent)).thenReturn(true);
when(pendingIntentFactory.getPendingIntent(intent)).thenReturn(PendingIntent.getService(InstrumentationRegistry.getTargetContext(), 1, intent, 0));
when(pendingIntentFactory.getPendingIntent(intent)).thenReturn(getPendingIntent());

serviceScheduler.schedule(intent, AlarmManager.INTERVAL_HOUR);

Expand Down Expand Up @@ -153,7 +193,12 @@ public void testCancel() {
final Intent intent = new Intent(context, EventIntentService.class);
when(pendingIntentFactory.getPendingIntent(intent)).thenReturn(pendingIntent);
serviceScheduler.unschedule(intent);
verify(alarmManager).cancel(pendingIntent);
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
verify(jobScheduler).cancel(EventIntentService.JOB_ID);
}
else {
verify(alarmManager).cancel(pendingIntent);
}
verify(logger).info("Unscheduled {}", intent.getComponent().toShortString());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import android.content.Intent;
import android.support.annotation.NonNull;

import com.optimizely.ab.android.shared.ServiceScheduler;
import com.optimizely.ab.event.EventHandler;
import com.optimizely.ab.event.LogEvent;

Expand Down Expand Up @@ -96,7 +97,8 @@ public void dispatchEvent(@NonNull LogEvent logEvent) {
intent.putExtra(EventIntentService.EXTRA_REQUEST_BODY, logEvent.getBody());
intent.putExtra(EventIntentService.EXTRA_INTERVAL, dispatchInterval);

context.startService(intent);
ServiceScheduler.startService(context, EventIntentService.JOB_ID, intent);

logger.info("Sent url {} to the event handler service", logEvent.getEndpointUrl());
}
}
Loading