Skip to content

Commit

Permalink
Test as service (#382)
Browse files Browse the repository at this point in the history
* Started the implementation of automatic testing

* Update strings.xml

* Added preference

* Adding time preference

* First raw implementation of alarm service

* Commented code

* Start RunningActivity from background

* How to backgroun an activity

* Clean code

* Send activity to background

* Always send the local notification

* versionCode

* Change software_name

* Update build.gradle

* Update build.gradle

* Update preferences_global.xml

* Adapting code

* Update PreferenceFragment.java

* Solve intent crash

* Default values (revert this commit in the future)

* Update PreferenceManager.java

* Update PreferenceFragment.java

* Update strings.xml

* Update RunningActivity.java

* Adding preferences

* New alarm service

* Trying refactor TestAsync

* Update TestAsyncTask.java

* fix

* Update AbstractTest.java

* Change TestAsync class

* Update AlarmReceiver.java

* add TODO

* Add no internet check

* Start implementation of a ServiceJob

* First working(ish) implementation of the test as a service

* Start code cleanup

* Stop test

* Check test running

* Managing test start stop and post Execution

* Fix unexpected end of stream on Connection in android

* Update TestAsyncTask.java

* Notification final fixes

* Adjusting services classes

* open RunningActivity and handling testSuite

* Unused code

* Test new scheduling

* Last testing

* Null checking

* last todo

* Removing background service classes

* Separate runTest and downloadURLs

* Fix crash

* Removed comments

* Update preferences_global.xml

* Update AndroidManifest.xml

* Update MainActivity.java

* Update preferences_global.xml

* Fixing interrupt problem

* Remove vibration and sounds

* removing icon

* Localize string

* Adding comments

* Update build.gradle

* Update build.gradle

* Cancel notification on app open
  • Loading branch information
lorenzoPrimi authored Nov 30, 2020
1 parent c0b8245 commit f3a1395
Show file tree
Hide file tree
Showing 14 changed files with 463 additions and 189 deletions.
6 changes: 3 additions & 3 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ android {

defaultConfig {
applicationId 'org.openobservatory.ooniprobe'
minSdkVersion 19
minSdkVersion 21
targetSdkVersion 29
versionName '2.7.1'
versionCode 66
versionName '2.8.0-beta.1'
versionCode 67
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
buildConfigField 'String', 'OONI_ORCHESTRATE_BASE_URL', '"https://orchestrate.ooni.io/"'
buildConfigField 'String', 'OONI_API_BASE_URL', '"https://api.ooni.io/"'
Expand Down
7 changes: 7 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<permission android:name="org.openobservatory.ooniprobe.permission.C2D_MESSAGE" android:protectionLevel="signature" />
<uses-permission android:name="org.openobservatory.ooniprobe.permission.C2D_MESSAGE" />

Expand Down Expand Up @@ -122,5 +123,11 @@
android:scheme="ooni" />
</intent-filter>
</activity>

<service
android:name=".common.service.RunTestService"
android:icon="@drawable/notification_icon"
android:label="@string/Dashboard_Card_Run">
</service>
</application>
</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,6 @@ boolean isTestRunning() {
return ((Application) getApplication()).isTestRunning();
}

void setTestRunning(boolean testRunning) {
((Application) getApplication()).setTestRunning(testRunning);
}

public OONIOrchestraClient getOrchestraClient() {
return ((Application) getApplication()).getOrchestraClient();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ else if (getPreferenceManager().getAppOpenCount() == PreferenceManager.NOTIFICAT

@Override protected void onResume() {
super.onResume();
//TODO-SERVICE show RunningActivity
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
package org.openobservatory.ooniprobe.activity;

import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.view.animation.Animation;
import android.widget.ImageButton;
Expand All @@ -12,17 +19,17 @@
import android.widget.Toast;

import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;

import com.airbnb.lottie.LottieAnimationView;

import org.openobservatory.ooniprobe.R;
import org.openobservatory.ooniprobe.common.CountlyManager;
import org.openobservatory.ooniprobe.common.ReachabilityManager;
import org.openobservatory.ooniprobe.common.NotificationService;
import org.openobservatory.ooniprobe.model.database.Result;
import org.openobservatory.ooniprobe.common.service.RunTestService;
import org.openobservatory.ooniprobe.test.TestAsyncTask;
import org.openobservatory.ooniprobe.test.suite.AbstractSuite;
import org.openobservatory.ooniprobe.test.suite.WebsitesSuite;

import java.util.ArrayList;

Expand All @@ -33,8 +40,7 @@
import localhost.toolkit.app.fragment.ConfirmDialogFragment;
import localhost.toolkit.app.fragment.MessageDialogFragment;

public class RunningActivity extends AbstractActivity implements ConfirmDialogFragment.OnConfirmedListener {
private static final String TEST = "test";
public class RunningActivity extends AbstractActivity implements ConfirmDialogFragment.OnConfirmedListener, ServiceConnection {
@BindView(R.id.running)
TextView running;
@BindView(R.id.name)
Expand All @@ -49,11 +55,10 @@ public class RunningActivity extends AbstractActivity implements ConfirmDialogFr
ImageButton close;
@BindView(R.id.animation)
LottieAnimationView animation;
private ArrayList<AbstractSuite> testSuites;
private AbstractSuite testSuite;
private boolean background;
private Integer runtime;
private TestAsyncTask task;
private RunTestService service;
private TestRunBroadRequestReceiver receiver;
boolean isBound = false;

public static Intent newIntent(AbstractActivity context, ArrayList<AbstractSuite> testSuites) {
if (ReachabilityManager.getNetworkType(context).equals(ReachabilityManager.NO_INTERNET)) {
Expand All @@ -63,9 +68,10 @@ public static Intent newIntent(AbstractActivity context, ArrayList<AbstractSuite
.build().show(context.getSupportFragmentManager(), null);
return null;
} else {
Bundle extra = new Bundle();
extra.putSerializable(TEST, testSuites);
return new Intent(context, RunningActivity.class).putExtra(TEST, extra);
Intent serviceIntent = new Intent(context, RunTestService.class);
serviceIntent.putExtra("testSuites", testSuites);
ContextCompat.startForegroundService(context, serviceIntent);
return new Intent(context, RunningActivity.class);
}
}

Expand All @@ -75,40 +81,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
setTheme(R.style.Theme_MaterialComponents_NoActionBar_App);
setContentView(R.layout.activity_running);
ButterKnife.bind(this);
Bundle extra = getIntent().getBundleExtra(TEST);
testSuites = (ArrayList<AbstractSuite>) extra.getSerializable(TEST);
if (testSuites == null) {
finish();
return;
}
CountlyManager.recordView("TestRunning");
runTest();
}

private void runTest() {
if (testSuites.size() > 0) {
testSuite = testSuites.get(0);
testStart();
setTestRunning(true);
task = (TestAsyncTaskImpl) new TestAsyncTaskImpl(this, testSuite.getResult()).execute(testSuite.getTestList(getPreferenceManager()));
}
}

private void testStart(){
runtime = testSuite.getRuntime(getPreferenceManager());
getWindow().setBackgroundDrawableResource(testSuite.getColor());
if (Build.VERSION.SDK_INT >= 21) {
getWindow().setStatusBarColor(testSuite.getColor());
}
animation.setImageAssetsFolder("anim/");
animation.setAnimation(testSuite.getAnim());
animation.setRepeatCount(Animation.INFINITE);
animation.playAnimation();
progress.setIndeterminate(true);
eta.setText(R.string.Dashboard_Running_CalculatingETA);
progress.setMax(testSuite.getTestList(getPreferenceManager()).length * 100);
//TODO remove this line when web_connectiviity will be in go
close.setVisibility(testSuite.getName().equals(WebsitesSuite.NAME) ? View.GONE : View.VISIBLE);
close.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Expand All @@ -122,92 +95,132 @@ public void onClick(View view) {
});
}

private void applyUIChanges(){
if (service == null || service.task == null ||
service.task.currentSuite == null || service.task.currentTest == null) {
return;
}
animation.setImageAssetsFolder("anim/");
animation.setRepeatCount(Animation.INFINITE);
animation.playAnimation();
progress.setIndeterminate(true);
eta.setText(R.string.Dashboard_Running_CalculatingETA);

name.setText(getString(service.task.currentTest.getLabelResId()));
runtime = service.task.currentSuite.getRuntime(getPreferenceManager());
getWindow().setBackgroundDrawableResource(service.task.currentSuite.getColor());
if (Build.VERSION.SDK_INT >= 21) {
getWindow().setStatusBarColor(service.task.currentSuite.getColor());
}
animation.setAnimation(service.task.currentSuite.getAnim());
progress.setMax(service.task.currentSuite.getTestList(getPreferenceManager()).length * 100);
}

@Override
protected void onResume() {
super.onResume();
background = false;
if (!isTestRunning()) {
NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
assert notificationManager != null;
notificationManager.cancel(RunTestService.NOTIFICATION_ID);
testEnded(this);
return;
}
IntentFilter filter = new IntentFilter("org.openobservatory.ooniprobe.activity.RunningActivity");
receiver = new TestRunBroadRequestReceiver();
LocalBroadcastManager.getInstance(this).registerReceiver(receiver, filter);
//Bind the RunTestService
Intent intent = new Intent(this, RunTestService.class);
bindService(intent, this, Context.BIND_AUTO_CREATE);
}

@Override
protected void onPause() {
background = true;
super.onPause();
if (isBound) {
unbindService(this);
isBound = false;
}
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
}

@Override
protected void onDestroy() {
setTestRunning(false);
super.onDestroy();
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
}

@Override
public void onBackPressed() {
Toast.makeText(this, getString(R.string.Modal_Error_CantCloseScreen), Toast.LENGTH_SHORT).show();
}

private static class TestAsyncTaskImpl extends TestAsyncTask<RunningActivity> {
TestAsyncTaskImpl(RunningActivity activity, Result result) {
super(activity, result);
}
@Override
public void onServiceConnected(ComponentName cname, IBinder binder) {
//Bind the service to this activity
RunTestService.TestBinder b = (RunTestService.TestBinder) binder;
service = b.getService();
isBound = true;
applyUIChanges();
}

@Override
protected void onProgressUpdate(String... values) {
RunningActivity act = ref.get();
if (act != null && !act.isFinishing())
switch (values[0]) {
case RUN:
act.name.setText(values[1]);
break;
case PRG:
act.progress.setIndeterminate(false);
int prgs = Integer.parseInt(values[1]);
act.progress.setProgress(prgs);
act.eta.setText(act.getString(R.string.Dashboard_Running_Seconds, String.valueOf(Math.round(act.runtime - ((double) prgs) / act.progress.getMax() * act.runtime))));
break;
case LOG:
if (!act.task.isInterrupted())
act.log.setText(values[1]);
break;
case ERR:
Toast.makeText(act, values[1], Toast.LENGTH_SHORT).show();
act.finish();
break;
case URL:
act.progress.setIndeterminate(false);
act.runtime = act.testSuite.getRuntime(act.getPreferenceManager());
break;
}
}

@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
RunningActivity act = ref.get();
act.testSuites.remove(act.testSuite);
if (act.testSuites.size() == 0)
endTest(act);
else
act.runTest();
}
@Override
public void onServiceDisconnected(ComponentName name) {
service = null;
}

private void endTest(RunningActivity act){
if (act != null && !act.isFinishing()) {
if (act.background) {
NotificationService.notifyTestEnded(act, act.testSuite);
} else
act.startActivity(MainActivity.newIntent(act, R.id.testResults));
act.finish();
public class TestRunBroadRequestReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String key = intent.getStringExtra("key");
String value = intent.getStringExtra("value");
switch (key) {
case TestAsyncTask.START:
applyUIChanges();
break;
case TestAsyncTask.RUN:
name.setText(value);
break;
case TestAsyncTask.PRG:
int prgs = Integer.parseInt(value);
progress.setIndeterminate(false);
progress.setProgress(prgs);
if (runtime != null)
eta.setText(getString(R.string.Dashboard_Running_Seconds,
String.valueOf(Math.round(runtime - ((double) prgs) / progress.getMax() * runtime))));
break;
case TestAsyncTask.LOG:
log.setText(value);
break;
case TestAsyncTask.ERR:
Toast.makeText(context, value, Toast.LENGTH_SHORT).show();
break;
case TestAsyncTask.URL:
progress.setIndeterminate(false);
runtime = service.task.currentSuite.getRuntime(getPreferenceManager());
break;
case TestAsyncTask.INT:
running.setText(getString(R.string.Dashboard_Running_Stopping_Title));
log.setText(getString(R.string.Dashboard_Running_Stopping_Notice));
break;
case TestAsyncTask.END:
testEnded(context);
break;
}

}
}

private void testEnded(Context context) {
startActivity(MainActivity.newIntent(context, R.id.testResults));
finish();
}

@Override
public void onConfirmation(Serializable serializable, int i) {
if (i == DialogInterface.BUTTON_POSITIVE) {
running.setText(getString(R.string.Dashboard_Running_Stopping_Title));
log.setText(getString(R.string.Dashboard_Running_Stopping_Notice));
task.interrupt();
if (service != null)
service.task.interrupt();
}
}
}
Loading

0 comments on commit f3a1395

Please sign in to comment.