Skip to content

Commit

Permalink
Feature/androido (#153)
Browse files Browse the repository at this point in the history
* Android O solution.... to start.  Need to replace the scheduler with job service instead of alarm service.

* use job scheduler instead of alarm service for android o

* update for android o.  set the context via ContextWrapper and cleanup tests to run on android o as well as other platforms.

* make sure to use logger and update proguard rules
  • Loading branch information
thomaszurkan-optimizely committed Oct 5, 2017
1 parent 91d986d commit f19bb4e
Show file tree
Hide file tree
Showing 20 changed files with 513 additions and 93 deletions.
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
- 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
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,8 @@ public void injectOptimizely() {
verify(startListener).onStart(any(OptimizelyClient.class));
}

@RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)
@Test
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public void injectOptimizelyNullListener() {
Context context = mock(Context.class);
PackageManager packageManager = mock(PackageManager.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,14 @@ void setOptimizelyStartListener(@Nullable OptimizelyStartListener optimizelyStar
this.optimizelyStartListener = optimizelyStartListener;
}

private void notifyStartListener() {
if (optimizelyStartListener != null) {
optimizelyStartListener.onStart(getOptimizely());
optimizelyStartListener = null;
}

}

/**
* Initialize Optimizely Synchronously
* <p>
Expand Down Expand Up @@ -232,16 +240,13 @@ public void onDatafileLoaded(@Nullable String datafile) {
// We should always call the callback even with the dummy
// instances. Devs might gate the rest of their app
// based on the loading of Optimizely
OptimizelyStartListener optimizelyStartListener = getOptimizelyStartListener();
if (optimizelyStartListener != null) {
optimizelyStartListener.onStart(getOptimizely());
}
notifyStartListener();
}
}

@Override
public void onStop(Context context) {
stop(context);

}
};
}
Expand Down Expand Up @@ -345,7 +350,7 @@ void injectOptimizely(@NonNull final Context context, final @NonNull UserProfile
public void onStartComplete(UserProfileService userProfileService) {
if (optimizelyStartListener != null) {
logger.info("Sending Optimizely instance to listener");
optimizelyStartListener.onStart(optimizelyClient);
notifyStartListener();
} else {
logger.info("No listener to send Optimizely to");
}
Expand All @@ -355,7 +360,7 @@ public void onStartComplete(UserProfileService userProfileService) {
else {
if (optimizelyStartListener != null) {
logger.info("Sending Optimizely instance to listener");
optimizelyStartListener.onStart(optimizelyClient);
notifyStartListener();
} else {
logger.info("No listener to send Optimizely to");
}
Expand All @@ -364,7 +369,7 @@ public void onStartComplete(UserProfileService userProfileService) {
logger.error("Unable to build OptimizelyClient instance", e);
if (optimizelyStartListener != null) {
logger.info("Sending Optimizely instance to listener may be null on failure");
optimizelyStartListener.onStart(optimizelyClient);
notifyStartListener();
}
} catch (Error e) {
logger.error("Unable to build OptimizelyClient instance", e);
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
Loading

0 comments on commit f19bb4e

Please sign in to comment.