Skip to content

Commit

Permalink
Merge branch 'master' of github.com:ooni/probe-android into issues/1430
Browse files Browse the repository at this point in the history
  • Loading branch information
aanorbel committed Sep 1, 2023
2 parents c68eb72 + 9f033e7 commit f4a1da3
Show file tree
Hide file tree
Showing 24 changed files with 216 additions and 57 deletions.
24 changes: 12 additions & 12 deletions .github/workflows/archive.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ jobs:
build:
runs-on: macos-latest
steps:
- uses: actions/setup-java@v2
with:
java-version: '11'
distribution: 'temurin'
- name: checkout
uses: actions/checkout@v2
- run: ./gradlew clean && ./gradlew assembleDevFullRelease
- name: uploads dev apk
uses: actions/upload-artifact@v3
with:
name: dev-apk
path: app/build/outputs/apk/devFull/release
- uses: actions/setup-java@v2
with:
java-version: '11'
distribution: 'temurin'
- name: checkout
uses: actions/checkout@v2
- run: ./gradlew clean assembleDevFullRelease
- name: uploads dev apk
uses: actions/upload-artifact@v3
with:
name: dev-apk
path: app/build/outputs/apk/devFull/release
12 changes: 6 additions & 6 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ apply plugin: 'com.android.application'
apply from: 'jacoco.gradle'

android {
compileSdk 33
compileSdk 34
ndkVersion '22.0.7026061'

defaultConfig {
applicationId 'org.openobservatory.ooniprobe'
minSdk 21
targetSdk 33
versionName '3.8.1'
versionCode 99
targetSdk 34
versionName '3.8.3'
versionCode 102
testInstrumentationRunner "org.openobservatory.ooniprobe.TestAndroidJUnitRunner"
buildConfigField 'String', 'OONI_API_BASE_URL', '"https://api.ooni.io/"'
buildConfigField 'String', 'NOTIFICATION_SERVER', '"https://countly.ooni.io"'
Expand Down Expand Up @@ -105,7 +105,7 @@ dependencies {
implementation project(path: ':engine')

// AndroidX
implementation 'androidx.appcompat:appcompat:1.4.2'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.lifecycle:lifecycle-process:2.5.1'
implementation 'androidx.preference:preference:1.2.0'
Expand Down Expand Up @@ -160,7 +160,7 @@ dependencies {
testImplementation 'org.mockito:mockito-inline:4.6.1'
testImplementation 'org.robolectric:robolectric:4.5.1'
testImplementation 'com.github.blocoio:faker:1.2.8'
testImplementation 'org.ooni:oonimkall:2023.03.16-173249'
testImplementation 'org.ooni:oonimkall:2023.07.18-162729'
testAnnotationProcessor 'com.google.dagger:dagger-compiler:2.36'

// Instrumentation Testing
Expand Down
Binary file modified app/src/debug/assets/v2.db
Binary file not shown.
3 changes: 3 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />

<permission
android:name="${applicationId}.permission.C2D_MESSAGE"
Expand Down Expand Up @@ -173,6 +175,7 @@
<service
android:name=".common.service.RunTestService"
android:icon="@drawable/notification_icon"
android:foregroundServiceType="specialUse"
android:label="@string/Dashboard_Card_Run"/>
<service
android:name=".common.service.RunTestJobService"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,34 @@
package org.openobservatory.ooniprobe.activity;

import static org.openobservatory.ooniprobe.common.service.RunTestService.CHANNEL_ID;

import android.Manifest;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.PowerManager;
import android.provider.Settings;

import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.content.ContextCompat;

import com.google.android.material.bottomnavigation.BottomNavigationView;
import com.google.android.material.snackbar.Snackbar;

import org.openobservatory.ooniprobe.R;
import org.openobservatory.ooniprobe.common.Application;
import org.openobservatory.ooniprobe.common.NotificationUtility;
import org.openobservatory.ooniprobe.common.PreferenceManager;
import org.openobservatory.ooniprobe.common.ThirdPartyServices;
import org.openobservatory.ooniprobe.common.service.ServiceUtil;
import org.openobservatory.ooniprobe.databinding.ActivityMainBinding;
import org.openobservatory.ooniprobe.domain.UpdatesNotificationManager;
import org.openobservatory.ooniprobe.fragment.DashboardFragment;
import org.openobservatory.ooniprobe.fragment.PreferenceGlobalFragment;
Expand All @@ -37,15 +48,16 @@ public class MainActivity extends AbstractActivity implements ConfirmDialogFragm
public static final String AUTOTEST_DIALOG = "automatic_testing";
public static final String BATTERY_DIALOG = "battery_optimization";

@BindView(R.id.bottomNavigation)
BottomNavigationView bottomNavigation;
private ActivityMainBinding binding;

@Inject
UpdatesNotificationManager notificationManager;

@Inject
PreferenceManager preferenceManager;

private ActivityResultLauncher<String> requestPermissionLauncher;

public static Intent newIntent(Context context, int resItem) {
return new Intent(context, MainActivity.class).putExtra(RES_ITEM, resItem).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
}
Expand All @@ -59,9 +71,10 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
finish();
}
else {
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
bottomNavigation.setOnNavigationItemSelectedListener(item -> {
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
binding.bottomNavigation.setOnItemSelectedListener(item -> {
switch (item.getItemId()) {
case R.id.dashboard:
getSupportFragmentManager().beginTransaction().replace(R.id.content, new DashboardFragment()).commit();
Expand All @@ -76,7 +89,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
return false;
}
});
bottomNavigation.setSelectedItemId(getIntent().getIntExtra(RES_ITEM, R.id.dashboard));
binding.bottomNavigation.setSelectedItemId(getIntent().getIntExtra(RES_ITEM, R.id.dashboard));
if (notificationManager.shouldShowAutoTest()) {
new ConfirmDialogFragment.Builder()
.withTitle(getString(R.string.Modal_Autorun_Modal_Title))
Expand Down Expand Up @@ -109,15 +122,53 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
}
}
requestNotificationPermission();
}

private void requestNotificationPermission() {

requestPermissionLauncher = registerForActivityResult(
new ActivityResultContracts.RequestPermission(),
(result) -> {
if (!result) {
Snackbar.make(
binding.getRoot(),
"Please grant Notification permission from App Settings",
Snackbar.LENGTH_LONG
).setAction(R.string.Settings_Title, view -> {
Intent intent = new Intent();
intent.setAction("android.settings.APP_NOTIFICATION_SETTINGS");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

//for Android 5-7
intent.putExtra("app_package", getPackageName());
intent.putExtra("app_uid", getApplicationInfo().uid);

// for Android 8 and above
intent.putExtra("android.provider.extra.APP_PACKAGE", getPackageName());

startActivity(intent);
}).show();
}
}
);
NotificationUtility.setChannel(getApplicationContext(), CHANNEL_ID, getString(R.string.Settings_AutomatedTesting_Label), false, false, false);
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED
) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS);
}
}
}

@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
if (intent.getExtras() != null){
if (intent.getExtras().containsKey(RES_ITEM))
bottomNavigation.setSelectedItemId(intent.getIntExtra(RES_ITEM, R.id.dashboard));
binding.bottomNavigation.setSelectedItemId(intent.getIntExtra(RES_ITEM, R.id.dashboard));
else if (intent.getExtras().containsKey(NOTIFICATION_DIALOG)){
new ConfirmDialogFragment.Builder()
.withTitle(intent.getExtras().getString("title"))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.openobservatory.ooniprobe.activity;

import static java.util.Locale.ENGLISH;

import android.app.AlertDialog;
import android.app.NotificationManager;
import android.content.Context;
Expand All @@ -17,6 +19,7 @@
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
Expand Down Expand Up @@ -143,8 +146,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
});
testProgressRepository.getEta().observe(this,etaValue -> {
if (etaValue!=null) {
eta.setText(getString(R.string.Dashboard_Running_Seconds,
String.valueOf(Math.round(etaValue))));
eta.setText(readableTimeRemaining(etaValue));
}
});

Expand Down Expand Up @@ -186,8 +188,7 @@ private void applyUIChanges(RunTestService service) {

Double etaValue = testProgressRepository.getEta().getValue();
if (etaValue!=null){
eta.setText(getString(R.string.Dashboard_Running_Seconds,
String.valueOf(Math.round(etaValue))));
eta.setText(readableTimeRemaining(etaValue));
}else {
eta.setText(R.string.Dashboard_Running_CalculatingETA);
}
Expand Down Expand Up @@ -270,8 +271,8 @@ public void onRun(String value) {
public void onProgress(int state, double timeLeft) {
progress.setIndeterminate(false);
progress.setProgress(state);
eta.setText(getString(R.string.Dashboard_Running_Seconds,
String.valueOf(Math.round(timeLeft))));

eta.setText(readableTimeRemaining(timeLeft));
}

@Override
Expand Down Expand Up @@ -300,4 +301,10 @@ public void onEnd(Context context) {
testEnded(context);
}
}

@NonNull
private static String readableTimeRemaining(double timeLeft) {
long letaValue = Math.round(timeLeft);
return String.format(ENGLISH,"%dm %02ds", letaValue/60, letaValue%60);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ public void onBindViewHolder(ViewHolder viewHolder, final int position) {
case API:
viewHolder.binding.textView.setTextColor(context.getResources().getColor(R.color.color_blue9));
break;
default:
viewHolder.binding.textView.setTextColor(context.getResources().getColor(R.color.color_black));
break;
}
}catch (Exception e){
System.out.println(items.get(position).trim());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ public void i(String tag, String message) {
logger.i(String.format("%s: %s", tag, message));
}

public void d(String tag, String message) {
logger.d(String.format("%s: %s", tag, message));
}

public void deleteOldLog() {
logger.deleteOldLog();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public class PreferenceManager {
public static final String AUTORUN_COUNT = "autorun_count";
public static final String AUTORUN_DATE = "autorun_last_date";
public static final int IGNORE_OPTIMIZATION_REQUEST = 15;
public static final int COUNT_WEBSITE_CATEGORIES = 31;
public static final int ASK_UPDATE_APP = 16;

private final SharedPreferences sp;
Expand Down Expand Up @@ -264,6 +265,14 @@ public Integer countEnabledCategory() {
return count;
}

public void updateAllWebsiteCategories(boolean value) {
SharedPreferences.Editor ed = sp.edit();
for (String key : r.getStringArray(R.array.CategoryCodes)){
ed.putBoolean(key,value);
}
ed.apply();
}

public boolean canCallDeleteJson(){
long lastCalled = sp.getLong(DELETE_JSON_KEY, 0);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.openobservatory.ooniprobe.common.service;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.KeyguardManager;
Expand All @@ -9,17 +10,17 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;

import androidx.core.app.ActivityCompat;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import androidx.core.content.ContextCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;

import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;

import org.openobservatory.ooniprobe.R;
import org.openobservatory.ooniprobe.activity.MainActivity;
import org.openobservatory.ooniprobe.activity.RunningActivity;
Expand Down Expand Up @@ -47,7 +48,7 @@ public void onCreate() {
super.onCreate();
IntentFilter filter = new IntentFilter(ACTION_INTERRUPT);
receiver = new ActionReceiver();
this.registerReceiver(receiver, filter);
ContextCompat.registerReceiver(this, receiver, filter, ContextCompat.RECEIVER_NOT_EXPORTED);

LocalBroadcastManager.getInstance(this).registerReceiver(
new ProgressBroadcastReceiver(),
Expand Down Expand Up @@ -110,6 +111,12 @@ public void onDestroy() {
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.setProgress(100, 100, false);
if (ActivityCompat.checkSelfPermission(
RunTestService.this,
Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED
) {
return;
}
notificationManager.notify(1, builder.build());
} else if (notificationManager != null)
notificationManager.cancel(NOTIFICATION_ID);
Expand Down Expand Up @@ -195,6 +202,12 @@ private class ProgressBroadcastReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
String key = intent.getStringExtra("key");
String value = intent.getStringExtra("value");
if (ActivityCompat.checkSelfPermission(
RunTestService.this,
Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED
) {
return;
}
switch (key) {
case TestAsyncTask.RUN:
Log.d(TAG, "TestAsyncTask.RUN");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public static void callCheckInAPI(Application app) {

public static void startRunTestService(Context context, ArrayList<AbstractSuite> iTestSuites, boolean storeDB) {
ArrayList<AbstractSuite> testSuites = Lists.newArrayList(
Iterables.filter(iTestSuites, testSuite -> !testSuite.isTestEmpty(d.preferenceManager))
Iterables.filter(Iterables.filter(iTestSuites, item -> item != null), testSuite -> !testSuite.isTestEmpty(d.preferenceManager))
);

Intent serviceIntent = new Intent(context, RunTestService.class);
Expand Down
Loading

0 comments on commit f4a1da3

Please sign in to comment.