Remove LOCK button from foreground notification

When the user removes the screen lock, the app does not get really
locked. There is no way about getting notified about this. Before users
lock the app without it getting actually locked, we rather remove the
button that was collapsed and not easy to find anyway.
This commit is contained in:
Torsten Grote
2018-08-07 15:48:16 -03:00
parent 02ff37b187
commit 5d2c96f916
9 changed files with 58 additions and 122 deletions

View File

@@ -35,7 +35,6 @@ import org.briarproject.briar.R;
import org.briarproject.briar.android.contact.ConversationActivity; import org.briarproject.briar.android.contact.ConversationActivity;
import org.briarproject.briar.android.forum.ForumActivity; import org.briarproject.briar.android.forum.ForumActivity;
import org.briarproject.briar.android.login.SignInReminderReceiver; import org.briarproject.briar.android.login.SignInReminderReceiver;
import org.briarproject.briar.android.login.UnlockActivity;
import org.briarproject.briar.android.navdrawer.NavDrawerActivity; import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
import org.briarproject.briar.android.privategroup.conversation.GroupActivity; import org.briarproject.briar.android.privategroup.conversation.GroupActivity;
import org.briarproject.briar.android.splash.SplashScreenActivity; import org.briarproject.briar.android.splash.SplashScreenActivity;
@@ -277,12 +276,11 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
@UiThread @UiThread
@Override @Override
public Notification getForegroundNotification() { public Notification getForegroundNotification() {
return getForegroundNotification(false, false); return getForegroundNotification(false);
} }
@UiThread @UiThread
private Notification getForegroundNotification(boolean lockable, private Notification getForegroundNotification(boolean locked) {
boolean locked) {
int title = locked ? R.string.lock_is_locked : int title = locked ? R.string.lock_is_locked :
R.string.ongoing_notification_title; R.string.ongoing_notification_title;
int text = locked ? R.string.lock_tap_to_unlock : int text = locked ? R.string.lock_tap_to_unlock :
@@ -304,24 +302,13 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
b.setVisibility(VISIBILITY_SECRET); b.setVisibility(VISIBILITY_SECRET);
} }
b.setPriority(PRIORITY_MIN); b.setPriority(PRIORITY_MIN);
// Add a 'Lock' action
if (lockable && !locked) {
String actionTitle = appContext.getString(R.string.lock_lock);
Intent i1 = new Intent(appContext, UnlockActivity.class);
i1.setAction(ACTION_LOCK);
PendingIntent actionIntent =
PendingIntent.getActivity(appContext, 0, i1, 0);
b.addAction(R.drawable.startup_lock, actionTitle, actionIntent);
}
return b.build(); return b.build();
} }
@UiThread @UiThread
@Override @Override
public void updateForegroundNotification(boolean lockable, public void updateForegroundNotification(boolean locked) {
boolean locked) { Notification n = getForegroundNotification(locked);
Notification n = getForegroundNotification(lockable, locked);
notificationManager.notify(ONGOING_NOTIFICATION_ID, n); notificationManager.notify(ONGOING_NOTIFICATION_ID, n);
} }

View File

@@ -204,10 +204,7 @@ public class AppModule {
@Provides @Provides
@Singleton @Singleton
LockManager provideLockManager(LifecycleManager lifecycleManager, LockManager provideLockManager(LockManagerImpl lockManager) {
EventBus eventBus, LockManagerImpl lockManager) {
lifecycleManager.registerService(lockManager);
eventBus.addListener(lockManager);
return lockManager; return lockManager;
} }

View File

@@ -8,14 +8,10 @@ import android.support.annotation.UiThread;
import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventListener;
import org.briarproject.bramble.api.lifecycle.Service;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.settings.Settings; import org.briarproject.bramble.api.settings.Settings;
import org.briarproject.bramble.api.settings.SettingsManager; import org.briarproject.bramble.api.settings.SettingsManager;
import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent;
import org.briarproject.briar.api.android.AndroidNotificationManager; import org.briarproject.briar.api.android.AndroidNotificationManager;
import org.briarproject.briar.api.android.LockManager; import org.briarproject.briar.api.android.LockManager;
@@ -34,7 +30,7 @@ import static org.briarproject.briar.android.util.UiUtils.hasScreenLock;
@ThreadSafe @ThreadSafe
@MethodsNotNullByDefault @MethodsNotNullByDefault
@ParametersNotNullByDefault @ParametersNotNullByDefault
public class LockManagerImpl implements LockManager, Service, EventListener { public class LockManagerImpl implements LockManager {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(LockManagerImpl.class.getName()); Logger.getLogger(LockManagerImpl.class.getName());
@@ -45,7 +41,7 @@ public class LockManagerImpl implements LockManager, Service, EventListener {
@DatabaseExecutor @DatabaseExecutor
private final Executor dbExecutor; private final Executor dbExecutor;
private final MutableLiveData<Boolean> locked = new MutableLiveData<>(); private volatile boolean locked = false;
private final MutableLiveData<Boolean> lockable = new MutableLiveData<>(); private final MutableLiveData<Boolean> lockable = new MutableLiveData<>();
@Inject @Inject
@@ -57,58 +53,10 @@ public class LockManagerImpl implements LockManager, Service, EventListener {
this.notificationManager = notificationManager; this.notificationManager = notificationManager;
this.dbExecutor = dbExecutor; this.dbExecutor = dbExecutor;
// setting these in the constructor makes #getValue() @NonNull // setting this in the constructor makes #getValue() @NonNull
this.locked.setValue(false);
this.lockable.setValue(false); this.lockable.setValue(false);
} }
@Override
public void startService() {
lockable.observeForever(this::onLockableChanged);
if (hasScreenLock(appContext)) {
loadLockableSetting();
} else {
lockable.postValue(false);
}
}
@Override
public void stopService() {
lockable.removeObserver(this::onLockableChanged);
}
@Override
public void eventOccurred(Event event) {
if (event instanceof SettingsUpdatedEvent) {
SettingsUpdatedEvent e = (SettingsUpdatedEvent) event;
String namespace = e.getNamespace();
if (namespace.equals(SETTINGS_NAMESPACE)) {
loadLockableSetting();
}
}
}
private void loadLockableSetting() {
dbExecutor.execute(() -> {
try {
Settings settings =
settingsManager.getSettings(SETTINGS_NAMESPACE);
boolean lockable =
settings.getBoolean(PREF_SCREEN_LOCK, false);
boolean newValue = hasScreenLock(appContext) && lockable;
this.lockable.postValue(newValue);
} catch (DbException e) {
logException(LOG, WARNING, e);
this.lockable.postValue(false);
}
});
}
private void onLockableChanged(boolean lockable) {
notificationManager
.updateForegroundNotification(lockable, locked.getValue());
}
@Override @Override
public LiveData<Boolean> isLockable() { public LiveData<Boolean> isLockable() {
return lockable; return lockable;
@@ -116,23 +64,33 @@ public class LockManagerImpl implements LockManager, Service, EventListener {
@UiThread @UiThread
@Override @Override
public void recheckLockable() { public void checkIfLockable() {
boolean oldValue = this.lockable.getValue(); boolean oldValue = lockable.getValue();
boolean newValue = hasScreenLock(appContext) && lockable.getValue(); dbExecutor.execute(() -> {
if (oldValue != newValue) { try {
this.lockable.setValue(newValue); Settings settings =
} settingsManager.getSettings(SETTINGS_NAMESPACE);
boolean lockable =
settings.getBoolean(PREF_SCREEN_LOCK, false);
boolean newValue = hasScreenLock(appContext) && lockable;
if (oldValue != newValue) {
this.lockable.postValue(newValue);
}
} catch (DbException e) {
logException(LOG, WARNING, e);
this.lockable.postValue(false);
}
});
} }
@Override @Override
public LiveData<Boolean> isLocked() { public boolean isLocked() {
return locked; return locked;
} }
@Override @Override
public void setLocked(boolean locked) { public void setLocked(boolean locked) {
this.locked.setValue(locked); this.locked = locked;
notificationManager notificationManager.updateForegroundNotification(locked);
.updateForegroundNotification(lockable.getValue(), locked);
} }
} }

View File

@@ -70,35 +70,22 @@ public abstract class BriarActivity extends BaseActivity {
if (!briarController.accountSignedIn() && !isFinishing()) { if (!briarController.accountSignedIn() && !isFinishing()) {
Intent i = new Intent(this, PasswordActivity.class); Intent i = new Intent(this, PasswordActivity.class);
startActivityForResult(i, REQUEST_PASSWORD); startActivityForResult(i, REQUEST_PASSWORD);
} else if (lockManager.isLocked().getValue()) { } else if (lockManager.isLocked()) {
Intent i = new Intent(this, UnlockActivity.class); Intent i = new Intent(this, UnlockActivity.class);
startActivityForResult(i, REQUEST_UNLOCK); startActivityForResult(i, REQUEST_UNLOCK);
} else { } else if (SDK_INT >= 23) {
lockManager.isLocked().observe(this, locked -> { briarController.hasDozed(new UiResultHandler<Boolean>(this) {
if (locked != null && locked) moveTaskToBack(true); @Override
}); public void onResultUi(Boolean result) {
lockManager.recheckLockable(); if (result) {
if (SDK_INT >= 23) { showDozeDialog(getString(R.string.warning_dozed,
briarController.hasDozed(new UiResultHandler<Boolean>(this) { getString(R.string.app_name)));
@Override
public void onResultUi(Boolean result) {
if (result) {
showDozeDialog(getString(R.string.warning_dozed,
getString(R.string.app_name)));
}
} }
}); }
} });
} }
} }
@Override
protected void onStop() {
super.onStop();
// only react to lock changes while in foreground
lockManager.isLocked().removeObservers(this);
}
public void setSceneTransitionAnimation() { public void setSceneTransitionAnimation() {
if (SDK_INT < 21) return; if (SDK_INT < 21) return;
// workaround for #1007 // workaround for #1007

View File

@@ -22,7 +22,6 @@ import java.util.logging.Logger;
import javax.inject.Inject; import javax.inject.Inject;
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_UNLOCK; import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_UNLOCK;
import static org.briarproject.briar.api.android.AndroidNotificationManager.ACTION_LOCK;
@RequiresApi(21) @RequiresApi(21)
@MethodsNotNullByDefault @MethodsNotNullByDefault
@@ -49,13 +48,7 @@ public class UnlockActivity extends BaseActivity {
Button button = findViewById(R.id.unlock); Button button = findViewById(R.id.unlock);
button.setOnClickListener(view -> requestKeyguardUnlock()); button.setOnClickListener(view -> requestKeyguardUnlock());
Intent intent = getIntent(); requestKeyguardUnlock();
if (intent != null && ACTION_LOCK.equals(intent.getAction())) {
lockManager.setLocked(true);
finish();
} else {
requestKeyguardUnlock();
}
} }
@Override @Override

View File

@@ -155,6 +155,7 @@ public class NavDrawerActivity extends BriarActivity implements
public void onStart() { public void onStart() {
super.onStart(); super.onStart();
updateTransports(); updateTransports();
lockManager.checkIfLockable();
controller.showExpiryWarning(new UiResultHandler<ExpiryWarning>(this) { controller.showExpiryWarning(new UiResultHandler<ExpiryWarning>(this) {
@Override @Override
public void onResultUi(ExpiryWarning expiry) { public void onResultUi(ExpiryWarning expiry) {

View File

@@ -49,7 +49,7 @@ public class SplashScreenActivity extends BaseActivity {
if (accountManager.hasDatabaseKey()) { if (accountManager.hasDatabaseKey()) {
Intent i; Intent i;
if (lockManager.isLocked().getValue()) { if (lockManager.isLocked()) {
// The database needs to be opened for the app to be locked. // The database needs to be opened for the app to be locked.
// Start main activity right away. It will open UnlockActivity. // Start main activity right away. It will open UnlockActivity.
// Otherwise, we would end up with two screen unlock inputs. // Otherwise, we would end up with two screen unlock inputs.

View File

@@ -53,11 +53,10 @@ public interface AndroidNotificationManager {
// Actions for pending intents // Actions for pending intents
String ACTION_DISMISS_REMINDER = "dismissReminder"; String ACTION_DISMISS_REMINDER = "dismissReminder";
String ACTION_LOCK = "lock";
Notification getForegroundNotification(); Notification getForegroundNotification();
void updateForegroundNotification(boolean lockable, boolean locked); void updateForegroundNotification(boolean locked);
void clearContactNotification(ContactId c); void clearContactNotification(ContactId c);

View File

@@ -5,13 +5,27 @@ import android.support.annotation.UiThread;
public interface LockManager { public interface LockManager {
/**
* Returns an observable LiveData to indicate whether the app can be locked.
*/
LiveData<Boolean> isLockable(); LiveData<Boolean> isLockable();
/**
* Updates the LiveData returned by {@link #isLockable()}.
* It checks whether a device screen lock is available and
* whether the app setting is checked.
*/
@UiThread @UiThread
void recheckLockable(); void checkIfLockable();
LiveData<Boolean> isLocked(); /**
* Returns true if app is currently locked, false otherwise.
*/
boolean isLocked();
/**
* Locks the app if true is passed, otherwise unlocks the app.
*/
void setLocked(boolean locked); void setLocked(boolean locked);
} }