Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: No prompt to enable notifications #603

Merged
merged 7 commits into from
Jul 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading