Skip to content

Commit

Permalink
Fix: No prompt to enable notifications (#603)
Browse files Browse the repository at this point in the history
Fixes  ooni/probe#2507

## Proposed Changes

- Create views to match designs (
https://www.figma.com/file/G0MMzbEyAUEYpAgV9ZEzTC/OONI-Probe-Mobile-Android?type=design&node-id=48-900&mode=design&t=NPmXdEojkX3gqQRg-0
)
- Add action to request for system notification when `Sounds great` is
clicked.
- Update preference fragment to request for system notification if
option is toggled.

| .| . | . | . | . |
|-|-| -| -|-|
|
![Screenshot_20230822_202406](https://github.com/ooni/probe-android/assets/17911892/cbbfa6cf-e288-40c2-92aa-f41937e20a9c)
|
![Screenshot_20230822_202514](https://github.com/ooni/probe-android/assets/17911892/1f1d2d54-8923-4de8-97dd-8cb7267b865f)
|
![Screenshot_20230823_140954](https://github.com/ooni/probe-android/assets/17911892/e1a1e55c-14d1-4a68-8fb4-d2b22178b60d)
|
![Screenshot_20230822_202527](https://github.com/ooni/probe-android/assets/17911892/c242648f-0723-4b39-90fa-04e6d3254228)
|
![Screenshot_20230823_140044](https://github.com/ooni/probe-android/assets/17911892/da76f553-d37d-4225-bb55-a9fd6fde640a)
|
  • Loading branch information
aanorbel authored Jul 5, 2024
1 parent 3643df2 commit e1fe836
Show file tree
Hide file tree
Showing 13 changed files with 516 additions and 68 deletions.
5 changes: 5 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,11 @@
</intent-filter>
</activity>

<activity
android:name=".activity.PromptActivity"
android:theme="@style/Theme.MaterialComponents.NoActionBar.Onboarding"
android:exported="false" />

<service
android:name=".common.service.RunTestService"
android:icon="@drawable/notification_icon"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
package org.openobservatory.ooniprobe.activity;

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

import android.Manifest;
import android.app.Activity;
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;
Expand All @@ -22,8 +17,6 @@
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;
Expand Down Expand Up @@ -53,8 +46,6 @@ public class MainActivity extends AbstractActivity implements ConfirmDialogFragm
@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 Down Expand Up @@ -97,14 +88,9 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
.withExtra(AUTOTEST_DIALOG)
.build().show(getSupportFragmentManager(), null);
} else if (notificationManager.shouldShow()) {
new ConfirmDialogFragment.Builder()
.withTitle(getString(R.string.Modal_EnableNotifications_Title))
.withMessage(getString(R.string.Modal_EnableNotifications_Paragraph))
.withPositiveButton(getString(R.string.Modal_SoundsGreat))
.withNegativeButton(getString(R.string.Modal_NotNow))
.withNeutralButton(getString(R.string.Modal_DontAskAgain))
.withExtra(NOTIFICATION_DIALOG)
.build().show(getSupportFragmentManager(), null);
registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
if (result.getResultCode() == Activity.RESULT_OK) {}
}).launch(PromptActivity.newIntent(this, PromptActivity.Prompt.CENSORSHIP_CONSENT));
}
ThirdPartyServices.checkUpdates(this);
}
Expand All @@ -118,46 +104,8 @@ 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) {
Expand All @@ -179,17 +127,6 @@ else if (intent.getExtras().containsKey(NOTIFICATION_DIALOG)){
@Override
public void onConfirmation(Serializable extra, int i) {
if (extra == null) return;
if (extra.equals(NOTIFICATION_DIALOG)) {
notificationManager.getUpdates(i == DialogInterface.BUTTON_POSITIVE);

//If positive answer reload consents and init notification
if (i == DialogInterface.BUTTON_POSITIVE){
ThirdPartyServices.reloadConsents((Application) getApplication());
}
else if (i == DialogInterface.BUTTON_NEUTRAL){
notificationManager.disableAskNotificationDialog();
}
}
if (extra.equals(AUTOTEST_DIALOG)) {
preferenceManager.setNotificationsFromDialog(i == DialogInterface.BUTTON_POSITIVE);
if (i == DialogInterface.BUTTON_POSITIVE){
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
package org.openobservatory.ooniprobe.activity;


import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.view.View;

import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.StringRes;
import androidx.core.content.ContextCompat;

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

import org.openobservatory.ooniprobe.R;
import org.openobservatory.ooniprobe.databinding.ActivityPromptBinding;
import org.openobservatory.ooniprobe.domain.UpdatesNotificationManager;

import javax.inject.Inject;

public class PromptActivity extends AbstractActivity {
private static final String PROMPT_ITEM = "promptItem";
@Inject
UpdatesNotificationManager notificationManager;
private ActivityPromptBinding binding;
private Prompt prompt;

private ActivityResultLauncher<String> requestPermissionLauncher;

public static Intent newIntent(Context context, Prompt prompt) {
return new Intent(context, PromptActivity.class).putExtra(PROMPT_ITEM, prompt);
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getActivityComponent().inject(this);
binding = ActivityPromptBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());

prompt = (Prompt) getIntent().getExtras().get(PROMPT_ITEM);
binding.title.setText(prompt.title);
binding.description.setText(prompt.paragraph);

registerPermissionRequest();
setUpClickListeners();
}

private void registerPermissionRequest() {
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();
}
setResult(result ? Activity.RESULT_OK : Activity.RESULT_CANCELED);
finish();
});
}

private void setUpClickListeners() {
OnPromptAction actions;
switch (prompt) {
case CENSORSHIP_CONSENT:
actions = new InternetCensorshipConsentActions();
break;
case TEST_PROGRESS_CONSENT:
actions = new TestProgressNotificationConsentActions();
break;
default:
actions = new OnPromptAction() {
@Override
public void onClickPositive(View view) { /*No Implementation*/ }

@Override
public void onClickNeutral(View view) { /*No Implementation*/ }

@Override
public void onClickNegative(View view) { /*No Implementation*/ }
};
}

binding.soundsGreat.setOnClickListener(actions::onClickPositive);
binding.notNow.setOnClickListener(actions::onClickNeutral);
binding.dontAskAgain.setOnClickListener(actions::onClickNegative);
}

public void requestNotificationPermission() {
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);
}
}
}

public enum Prompt {
CENSORSHIP_CONSENT(R.string.Modal_EnableNotifications_Title, R.string.Modal_EnableNotifications_Paragraph),
TEST_PROGRESS_CONSENT(R.string.Prompt_EnableTestProgressNotifications_Title, R.string.Prompt_EnableTestProgressNotifications_Paragraph);

private final int title;
private final int paragraph;

Prompt(@StringRes int title, @StringRes int paragraph) {
this.title = title;
this.paragraph = paragraph;
}
}

interface OnPromptAction {
/**
* Callback for View#onClick of `soundsGreat` button.
*
* @param view The view that was clicked.
*/
void onClickPositive(View view);

/**
* Callback for View#onClick of `notNow` button.
*
* @param view The view that was clicked.
*/
void onClickNeutral(View view);

/**
* Callback for View#onClick of `dontAskAgain` button.
*
* @param view The view that was clicked.
*/
void onClickNegative(View view);
}

private class InternetCensorshipConsentActions implements OnPromptAction {

@Override
public void onClickPositive(View view) {
notificationManager.getUpdates(true);
if (ContextCompat.checkSelfPermission(
PromptActivity.this,
Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED){
PromptActivity.this.requestNotificationPermission();
} else {
setResult(Activity.RESULT_OK);
finish();
}
}

@Override
public void onClickNeutral(View view) {
PromptActivity.this.setResult(Activity.RESULT_CANCELED);
PromptActivity.this.finish();
}

@Override
public void onClickNegative(View view) {
notificationManager.disableAskNotificationDialog();
onClickNeutral(view);
}
}

private class TestProgressNotificationConsentActions implements OnPromptAction {

@Override
public void onClickPositive(View view) {
notificationManager.setTestProgressNotificationConsent(true);
if (ContextCompat.checkSelfPermission(
PromptActivity.this,
Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED){
PromptActivity.this.requestNotificationPermission();
} else {
setResult(Activity.RESULT_OK);
finish();
}
}

@Override
public void onClickNeutral(View view) {
PromptActivity.this.setResult(Activity.RESULT_CANCELED);
PromptActivity.this.finish();
}

@Override
public void onClickNegative(View view) {
notificationManager.disableAskTestProgressNotificationConsent();
onClickNeutral(view);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ public static void runAsForegroundService(AbstractActivity context,
ArrayList<AbstractSuite> testSuites,
OnTestServiceStartedListener onTestServiceStartedListener,
PreferenceManager iPreferenceManager) {

if (iPreferenceManager.shouldShowTestProgressConsent()){
context.startActivity(PromptActivity.newIntent(context, PromptActivity.Prompt.TEST_PROGRESS_CONSENT));
}

if (ReachabilityManager.getNetworkType(context).equals(ReachabilityManager.NO_INTERNET)) {
new MessageDialogFragment.Builder()
.withTitle(context.getString(R.string.Modal_Error))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public class PreferenceManager {
public static final int NOTIFICATION_DIALOG_COUNT = 7;
public static final int AUTOTEST_DIALOG_COUNT = 5;
static final String NOTIFICATION_DIALOG_DISABLE = "isNotificationDialogDisabled";
static final String TEST_PROGRESS_NOTIFICATION_DISABLE = "isTestProgressNotificationDisabled";
private static final String AUTOTEST_DIALOG_DISABLE = "isAutomaticTestDialogDisabled";
private static final String TOKEN = "token";
static final String SHOW_ONBOARDING = "first_run";
Expand Down Expand Up @@ -115,6 +116,31 @@ public boolean isNotifications() {
return sp.getBoolean(r.getString(R.string.notifications_enabled), false);
}

public boolean isTestProgressNotifications() {
return sp.getBoolean(r.getString(R.string.test_progress_notifications_enabled), false);
}

public boolean isAskTestProgressNotificationConsent() {
return sp.getBoolean(TEST_PROGRESS_NOTIFICATION_DISABLE, false);
}

public void disableAskTestProgressNotificationConsent() {
sp.edit().putBoolean(TEST_PROGRESS_NOTIFICATION_DISABLE, true)
.apply();
}

public void setTestProgressNotificationConsent(boolean enabled) {
//set notification value and increment app open
sp.edit()
.putBoolean(r.getString(R.string.test_progress_notifications_enabled), enabled)
.apply();
}

public boolean shouldShowTestProgressConsent() {
return !isTestProgressNotifications()
&& !isAskTestProgressNotificationConsent();
}

public boolean isDarkTheme() {
return sp.getBoolean(r.getString(R.string.theme_enabled), false);
}
Expand Down
Loading

0 comments on commit e1fe836

Please sign in to comment.