Skip to content

Commit

Permalink
[New Designs] Implement add link flow (#642)
Browse files Browse the repository at this point in the history
Fixes ooni/probe#2595

## Proposed Changes

- Add `intent-filter` to `MainActivity` so v2 events are handled by it.
- Load `descriptor` from the backend and send to `AddDescriptorActivity`
to be displayed.
- Ensure `AddDescriptorActivity` doesn't lose state on configuration
change.
  • Loading branch information
aanorbel authored Feb 16, 2024
1 parent 0060c85 commit c459e1c
Show file tree
Hide file tree
Showing 127 changed files with 3,033 additions and 320 deletions.
4 changes: 4 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ android {
buildFeatures {
viewBinding = true
}
dataBinding {
enabled = true
enabledForTests = true
}
namespace 'org.openobservatory.ooniprobe'
}

Expand Down
409 changes: 222 additions & 187 deletions app/src/main/AndroidManifest.xml

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -60,22 +60,21 @@ 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);
}

public static Intent newIntent(Context context, int resItem, String message) {
return new Intent(context, MainActivity.class)
.putExtra(RES_ITEM, resItem)
.putExtra(RES_SNACKBAR_MESSAGE, message)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
}
public static Intent newIntent(Context context, int resItem, String message) {
return new Intent(context, MainActivity.class)
.putExtra(RES_ITEM, resItem)
.putExtra(RES_SNACKBAR_MESSAGE, message)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
}

@Override
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getActivityComponent().inject(this);
if (preferenceManager.isShowOnboarding()) {
startActivity(new Intent(MainActivity.this, OnboardingActivity.class));
finish();
}
else {
} else {
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
binding.bottomNavigation.setOnItemSelectedListener(item -> {
Expand All @@ -96,15 +95,15 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
/* TODO(aanorbel): Fix change in state(theme change from notification) changes the selected item.
The proper fix would be to track the selected item as well as other properties in a `ViewModel`. */
binding.bottomNavigation.setSelectedItemId(getIntent().getIntExtra(RES_ITEM, R.id.dashboard));
/* Check if we are restoring the activity from a saved state first.
* If we have a message to show, show it as a snackbar.
* This is used to show the message from test completion.
*/
if (savedInstanceState == null && getIntent().hasExtra(RES_SNACKBAR_MESSAGE)) {
Snackbar.make(binding.getRoot(), getIntent().getStringExtra(RES_SNACKBAR_MESSAGE), Snackbar.LENGTH_SHORT)
.setAnchorView(binding.bottomNavigation)
.show();
}
/* Check if we are restoring the activity from a saved state first.
* If we have a message to show, show it as a snackbar.
* This is used to show the message from test completion.
*/
if (savedInstanceState == null && getIntent().hasExtra(RES_SNACKBAR_MESSAGE)) {
Snackbar.make(binding.getRoot(), getIntent().getStringExtra(RES_SNACKBAR_MESSAGE), Snackbar.LENGTH_SHORT)
.setAnchorView(binding.bottomNavigation)
.show();
}
if (notificationManager.shouldShowAutoTest()) {
new ConfirmDialogFragment.Builder()
.withTitle(getString(R.string.Modal_Autorun_Modal_Title))
Expand All @@ -128,9 +127,9 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
ThirdPartyServices.checkUpdates(this);
}

if (android.os.Build.VERSION.SDK_INT >= 29){
if (android.os.Build.VERSION.SDK_INT >= 29) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
} else{
} else {
if (preferenceManager.isDarkTheme()) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
} else {
Expand All @@ -150,20 +149,20 @@ private void requestNotificationPermission() {
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);
).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 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());
// for Android 8 and above
intent.putExtra("android.provider.extra.APP_PACKAGE", getPackageName());

startActivity(intent);
}).show();
startActivity(intent);
}).show();
}
}
);
Expand All @@ -181,10 +180,16 @@ private void requestNotificationPermission() {
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
if (intent.getExtras() != null){
if (intent.getExtras().containsKey(RES_ITEM))
/**
* Check if we are starting the activity with an intent extra.
* This is invoked when we are starting the activity from a notification or
* when the activity is launched from the onboarding fragment
* @see {@link org.openobservatory.ooniprobe.fragment.onboarding.Onboarding3Fragment#masterClick}.
*/
if (intent.getExtras() != null) {
if (intent.getExtras().containsKey(RES_ITEM)) {
binding.bottomNavigation.setSelectedItemId(intent.getIntExtra(RES_ITEM, R.id.dashboard));
else if (intent.getExtras().containsKey(NOTIFICATION_DIALOG)){
} else if (intent.getExtras().containsKey(NOTIFICATION_DIALOG)) {
new ConfirmDialogFragment.Builder()
.withTitle(intent.getExtras().getString("title"))
.withMessage(intent.getExtras().getString("message"))
Expand All @@ -202,34 +207,31 @@ public void onConfirmation(Serializable extra, int i) {
notificationManager.getUpdates(i == DialogInterface.BUTTON_POSITIVE);

//If positive answer reload consents and init notification
if (i == DialogInterface.BUTTON_POSITIVE){
if (i == DialogInterface.BUTTON_POSITIVE) {
ThirdPartyServices.reloadConsents((Application) getApplication());
}
else if (i == DialogInterface.BUTTON_NEUTRAL){
} else if (i == DialogInterface.BUTTON_NEUTRAL) {
notificationManager.disableAskNotificationDialog();
}
}
if (extra.equals(AUTOTEST_DIALOG)) {
preferenceManager.setNotificationsFromDialog(i == DialogInterface.BUTTON_POSITIVE);
if (i == DialogInterface.BUTTON_POSITIVE){
if (i == DialogInterface.BUTTON_POSITIVE) {
//For API < 23 we ignore battery optimization
boolean isIgnoringBatteryOptimizations = true;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
isIgnoringBatteryOptimizations = pm.isIgnoringBatteryOptimizations(getPackageName());
}
if(!isIgnoringBatteryOptimizations){
if (!isIgnoringBatteryOptimizations) {
Intent intent = new Intent();
intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, PreferenceManager.IGNORE_OPTIMIZATION_REQUEST);
}
else {
} else {
preferenceManager.enableAutomatedTesting();
ServiceUtil.scheduleJob(this);
}
}
else if (i == DialogInterface.BUTTON_NEUTRAL){
} else if (i == DialogInterface.BUTTON_NEUTRAL) {
preferenceManager.disableAskAutomaticTestDialog();
}
}
Expand Down Expand Up @@ -257,17 +259,15 @@ public void onActivityResult(int requestCode, int resultCode, @Nullable Intent d
if (isIgnoringBatteryOptimizations) {
preferenceManager.enableAutomatedTesting();
ServiceUtil.scheduleJob(this);
}
else {
} else {
new ConfirmDialogFragment.Builder()
.withMessage(getString(R.string.Modal_Autorun_BatteryOptimization))
.withPositiveButton(getString(R.string.Modal_OK))
.withNegativeButton(getString(R.string.Modal_Cancel))
.withExtra(BATTERY_DIALOG)
.build().show(getSupportFragmentManager(), null);
}
}
else if (requestCode == PreferenceManager.ASK_UPDATE_APP) {
} else if (requestCode == PreferenceManager.ASK_UPDATE_APP) {
if (resultCode != RESULT_OK) {
//We don't need to check the result for now
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import android.view.Window;

import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.core.text.TextUtilsCompat;
import androidx.core.view.ViewCompat;

Expand All @@ -25,13 +24,16 @@
import org.openobservatory.ooniprobe.activity.customwebsites.CustomWebsiteActivity;
import org.openobservatory.ooniprobe.activity.overview.OverviewTestsExpandableListViewAdapter;
import org.openobservatory.ooniprobe.activity.overview.OverviewViewModel;
import org.openobservatory.ooniprobe.common.OONIDescriptor;
import org.openobservatory.ooniprobe.common.AbstractDescriptor;
import org.openobservatory.ooniprobe.common.OONITests;
import org.openobservatory.ooniprobe.common.PreferenceManager;
import org.openobservatory.ooniprobe.common.ReadMorePlugin;
import org.openobservatory.ooniprobe.databinding.ActivityOverviewBinding;
import org.openobservatory.ooniprobe.model.database.InstalledDescriptor;
import org.openobservatory.ooniprobe.model.database.Result;
import org.openobservatory.ooniprobe.model.database.TestDescriptor;

import java.text.SimpleDateFormat;
import java.util.Locale;
import java.util.Objects;

Expand All @@ -52,24 +54,24 @@ public class OverviewActivity extends AbstractActivity {

OverviewTestsExpandableListViewAdapter adapter;

private OONIDescriptor<BaseNettest> descriptor;
private AbstractDescriptor<BaseNettest> descriptor;

public static Intent newIntent(Context context, OONIDescriptor<BaseNettest> descriptor) {
public static Intent newIntent(Context context, AbstractDescriptor<BaseNettest> descriptor) {
return new Intent(context, OverviewActivity.class).putExtra(TEST, descriptor);
}

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getActivityComponent().inject(this);
descriptor = (OONIDescriptor) getIntent().getSerializableExtra(TEST);
descriptor = (AbstractDescriptor) getIntent().getSerializableExtra(TEST);
binding = ActivityOverviewBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
viewModel.updateDescriptor(descriptor);
setSupportActionBar(binding.toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
setTitle(descriptor.getTitle());
setThemeColor(ContextCompat.getColor(this, descriptor.getColor()));
setThemeColor(descriptor.getColor());
binding.icon.setImageResource(descriptor.getDisplayIcon(this));
binding.customUrl.setVisibility(descriptor.getName().equals(OONITests.WEBSITES.getLabel()) ? View.VISIBLE : View.GONE);
Markwon markwon = Markwon.builder(this)
Expand All @@ -81,7 +83,20 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
binding.desc.setTextDirection(View.TEXT_DIRECTION_RTL);
}
} else {
markwon.setMarkdown(binding.desc, descriptor.getDescription());
if (descriptor instanceof InstalledDescriptor) {
TestDescriptor testDescriptor = ((InstalledDescriptor) descriptor).getTestDescriptor();
markwon.setMarkdown(
binding.desc,
String.format(
"Created by %s on %s\n\n%s",
testDescriptor.getAuthor(),
new SimpleDateFormat("MMM dd, yyyy", Locale.ENGLISH).format(testDescriptor.getDescriptorCreationTime()),
descriptor.getDescription()
)
);
} else {
markwon.setMarkdown(binding.desc, descriptor.getDescription());
}
}
Result lastResult = Result.getLastResult(descriptor.getName());
if (lastResult == null) {
Expand Down Expand Up @@ -127,6 +142,18 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
binding.expandableListView.expandGroup(i);
}

if (descriptor instanceof InstalledDescriptor) {
binding.uninstallLink.setVisibility(View.VISIBLE);
binding.automaticUpdatesContainer.setVisibility(View.VISIBLE);
binding.automaticUpdatesSwitch.setChecked(((InstalledDescriptor) descriptor).getTestDescriptor().isAutoUpdate());
} else {
binding.uninstallLink.setVisibility(View.GONE);
/**
* We need to set the height to 0 because the layout is broken when the view is gone
*/
binding.automaticUpdatesContainer.getLayoutParams().height = 0;
}

setUpOnCLickListeners();
}

Expand Down Expand Up @@ -157,6 +184,8 @@ public void setThemeColor(int color) {

private void setUpOnCLickListeners() {
binding.customUrl.setOnClickListener(view -> customUrlClick());
binding.uninstallLink.setOnClickListener(view -> viewModel.uninstallLinkClicked(this, (InstalledDescriptor) descriptor));
binding.automaticUpdatesSwitch.setOnCheckedChangeListener((compoundButton, isChecked) -> viewModel.automaticUpdatesSwitchClicked(isChecked));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.drawable.ColorDrawable;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
Expand Down Expand Up @@ -173,11 +174,17 @@ private void applyUIChanges(RunTestService service) {
binding.name.setText(service.task.currentTest.getName());
else
binding.name.setText(getString(service.task.currentTest.getLabelResId()));
getWindow().setBackgroundDrawableResource(service.task.currentSuite.getColor());
if (Build.VERSION.SDK_INT >= 21) {
getWindow().setStatusBarColor(service.task.currentSuite.getColor());

getWindow().setBackgroundDrawable(new ColorDrawable(service.task.currentSuite.getColor()));
getWindow().setStatusBarColor(service.task.currentSuite.getColor());
if (service.task.currentSuite.getAnim() == null){
binding.animation.setImageResource(service.task.currentSuite.getIconGradient());
binding.animation.setColorFilter(getResources().getColor(R.color.color_gray2));
binding.animation.setPadding(0,100,0,100);
} else {
binding.animation.setAnimation(service.task.currentSuite.getAnim());
}
binding.animation.setAnimation(service.task.currentSuite.getAnim());

binding.progress.setMax(service.task.getMax(preferenceManager));
}

Expand Down
Loading

0 comments on commit c459e1c

Please sign in to comment.