initial work toward api 26+

* introduce notification channels
* always use foreground service on 26+
This commit is contained in:
Daniel Gultsch 2018-09-05 21:37:05 +02:00
parent d5b50d1076
commit 676d31f606
17 changed files with 1074 additions and 914 deletions

View file

@ -60,13 +60,13 @@ ext {
} }
android { android {
compileSdkVersion 27 compileSdkVersion 28
defaultConfig { defaultConfig {
minSdkVersion 19 minSdkVersion 19
targetSdkVersion 25 targetSdkVersion 28
versionCode 283 versionCode 283
versionName "2.2.9" versionName "2.3.0-alpha"
archivesBaseName += "-$versionName" archivesBaseName += "-$versionName"
applicationId "eu.siacs.conversations" applicationId "eu.siacs.conversations"
resValue "string", "applicationId", applicationId resValue "string", "applicationId", applicationId

View file

@ -13,4 +13,3 @@
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true # org.gradle.parallel=true
org.gradle.jvmargs=-Xmx2048M org.gradle.jvmargs=-Xmx2048M
org.gradle.configureondemand=false

View file

@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-4.10-all.zip

View file

@ -16,6 +16,7 @@
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-feature <uses-feature
android:name="android.hardware.location" android:name="android.hardware.location"

View file

@ -14,6 +14,7 @@ import android.os.CancellationSignal;
import android.os.IBinder; import android.os.IBinder;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.util.Log; import android.util.Log;
import com.google.zxing.BarcodeFormat; import com.google.zxing.BarcodeFormat;
@ -162,7 +163,6 @@ public class BarcodeProvider extends ContentProvider implements ServiceConnectio
synchronized (this) { synchronized (this) {
if (mXmppConnectionService == null && !mBindingInProcess) { if (mXmppConnectionService == null && !mBindingInProcess) {
Log.d(Config.LOGTAG, "calling to bind service"); Log.d(Config.LOGTAG, "calling to bind service");
context.startService(intent);
context.bindService(intent, this, Context.BIND_AUTO_CREATE); context.bindService(intent, this, Context.BIND_AUTO_CREATE);
this.mBindingInProcess = true; this.mBindingInProcess = true;
} }

View file

@ -12,6 +12,7 @@ import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
import android.service.chooser.ChooserTarget; import android.service.chooser.ChooserTarget;
import android.service.chooser.ChooserTargetService; import android.service.chooser.ChooserTargetService;
import android.support.v4.content.ContextCompat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -32,7 +33,6 @@ public class ContactChooserTargetService extends ChooserTargetService implements
public List<ChooserTarget> onGetChooserTargets(ComponentName targetActivityName, IntentFilter matchedFilter) { public List<ChooserTarget> onGetChooserTargets(ComponentName targetActivityName, IntentFilter matchedFilter) {
Intent intent = new Intent(this, XmppConnectionService.class); Intent intent = new Intent(this, XmppConnectionService.class);
intent.setAction("contact_chooser"); intent.setAction("contact_chooser");
startService(intent);
bindService(intent, this, Context.BIND_AUTO_CREATE); bindService(intent, this, Context.BIND_AUTO_CREATE);
ArrayList<ChooserTarget> chooserTargets = new ArrayList<>(); ArrayList<ChooserTarget> chooserTargets = new ArrayList<>();
try { try {

View file

@ -3,38 +3,37 @@ package eu.siacs.conversations.services;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.support.v4.content.ContextCompat;
import android.util.Log; import android.util.Log;
import eu.siacs.conversations.Config; import eu.siacs.conversations.Config;
import eu.siacs.conversations.persistance.DatabaseBackend;
public class EventReceiver extends BroadcastReceiver { public class EventReceiver extends BroadcastReceiver {
public static final String SETTING_ENABLED_ACCOUNTS = "enabled_accounts"; public static final String SETTING_ENABLED_ACCOUNTS = "enabled_accounts";
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(final Context context, final Intent originalIntent) {
Intent mIntentForService = new Intent(context, XmppConnectionService.class); final Intent intentForService = new Intent(context, XmppConnectionService.class);
if (intent.getAction() != null) { if (originalIntent.getAction() != null) {
mIntentForService.setAction(intent.getAction()); intentForService.setAction(originalIntent.getAction());
} else { } else {
mIntentForService.setAction("other"); intentForService.setAction("other");
} }
final String action = intent.getAction(); final String action = originalIntent.getAction();
if (action.equals("ui") || hasEnabledAccounts(context)) { if (action.equals("ui") || hasEnabledAccounts(context)) {
try { try {
context.startService(mIntentForService); ContextCompat.startForegroundService(context, intentForService);
} catch (RuntimeException e) { } catch (RuntimeException e) {
Log.d(Config.LOGTAG,"EventReceiver was unable to start service"); Log.d(Config.LOGTAG,"EventReceiver was unable to start service");
} }
} else { } else {
Log.d(Config.LOGTAG,"EventReceiver ignored action "+mIntentForService.getAction()); Log.d(Config.LOGTAG,"EventReceiver ignored action "+intentForService.getAction());
} }
} }
public static boolean hasEnabledAccounts(Context context) { public static boolean hasEnabledAccounts(final Context context) {
return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(SETTING_ENABLED_ACCOUNTS,true); return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(SETTING_ENABLED_ACCOUNTS,true);
} }

View file

@ -42,15 +42,12 @@ public class ExportLogsService extends Service {
@Override @Override
public int onStartCommand(Intent intent, int flags, int startId) { public int onStartCommand(Intent intent, int flags, int startId) {
if (running.compareAndSet(false, true)) { if (running.compareAndSet(false, true)) {
new Thread(new Runnable() { new Thread(() -> {
@Override export();
public void run() { stopForeground(true);
export(); running.set(false);
stopForeground(true); stopSelf();
running.set(false); }).start();
stopSelf();
}
}).start();
} }
return START_NOT_STICKY; return START_NOT_STICKY;
} }

View file

@ -1,5 +1,6 @@
package eu.siacs.conversations.services; package eu.siacs.conversations.services;
import android.Manifest;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.app.AlarmManager; import android.app.AlarmManager;
@ -104,6 +105,7 @@ import eu.siacs.conversations.ui.SettingsActivity;
import eu.siacs.conversations.ui.UiCallback; import eu.siacs.conversations.ui.UiCallback;
import eu.siacs.conversations.ui.interfaces.OnAvatarPublication; import eu.siacs.conversations.ui.interfaces.OnAvatarPublication;
import eu.siacs.conversations.ui.interfaces.OnSearchResultsAvailable; import eu.siacs.conversations.ui.interfaces.OnSearchResultsAvailable;
import eu.siacs.conversations.utils.Compatibility;
import eu.siacs.conversations.utils.ConversationsFileObserver; import eu.siacs.conversations.utils.ConversationsFileObserver;
import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.utils.ExceptionHelper; import eu.siacs.conversations.utils.ExceptionHelper;
@ -157,7 +159,6 @@ public class XmppConnectionService extends Service {
public static final String ACTION_IDLE_PING = "idle_ping"; public static final String ACTION_IDLE_PING = "idle_ping";
public static final String ACTION_FCM_TOKEN_REFRESH = "fcm_token_refresh"; public static final String ACTION_FCM_TOKEN_REFRESH = "fcm_token_refresh";
public static final String ACTION_FCM_MESSAGE_RECEIVED = "fcm_message_received"; public static final String ACTION_FCM_MESSAGE_RECEIVED = "fcm_message_received";
private static final String ACTION_MERGE_PHONE_CONTACTS = "merge_phone_contacts";
private static final String SETTING_LAST_ACTIVITY_TS = "last_activity_timestamp"; private static final String SETTING_LAST_ACTIVITY_TS = "last_activity_timestamp";
@ -193,10 +194,9 @@ public class XmppConnectionService extends Service {
@Override @Override
public void onChange(boolean selfChange) { public void onChange(boolean selfChange) {
super.onChange(selfChange); super.onChange(selfChange);
Intent intent = new Intent(getApplicationContext(), if (restoredFromDatabaseLatch.getCount() == 0) {
XmppConnectionService.class); loadPhoneContacts();
intent.setAction(ACTION_MERGE_PHONE_CONTACTS); }
startService(intent);
} }
}; };
private FileBackend fileBackend = new FileBackend(this); private FileBackend fileBackend = new FileBackend(this);
@ -240,6 +240,7 @@ public class XmppConnectionService extends Service {
) { ) {
@Override @Override
public void onEvent(int event, String path) { public void onEvent(int event, String path) {
Log.d(Config.LOGTAG,"event "+event+" path="+path);
markFileDeleted(path); markFileDeleted(path);
} }
}; };
@ -569,11 +570,6 @@ public class XmppConnectionService extends Service {
resetAllAttemptCounts(true, false); resetAllAttemptCounts(true, false);
} }
break; break;
case ACTION_MERGE_PHONE_CONTACTS:
if (restoredFromDatabaseLatch.getCount() == 0) {
loadPhoneContacts();
}
return START_STICKY;
case Intent.ACTION_SHUTDOWN: case Intent.ACTION_SHUTDOWN:
logoutAndSave(true); logoutAndSave(true);
return START_NOT_STICKY; return START_NOT_STICKY;
@ -958,6 +954,9 @@ public class XmppConnectionService extends Service {
Resolver.init(this); Resolver.init(this);
this.mRandom = new SecureRandom(); this.mRandom = new SecureRandom();
updateMemorizingTrustmanager(); updateMemorizingTrustmanager();
if (Compatibility.twentySix()) {
mNotificationService.initializeChannels();
}
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
final int cacheSize = maxMemory / 8; final int cacheSize = maxMemory / 8;
this.mBitmapCache = new LruCache<String, Bitmap>(cacheSize) { this.mBitmapCache = new LruCache<String, Bitmap>(cacheSize) {
@ -984,7 +983,10 @@ public class XmppConnectionService extends Service {
restoreFromDatabase(); restoreFromDatabase();
getContentResolver().registerContentObserver(ContactsContract.Contacts.CONTENT_URI, true, contactObserver); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
//TODO get this restarted if users gives permission
getContentResolver().registerContentObserver(ContactsContract.Contacts.CONTENT_URI, true, contactObserver);
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
Log.d(Config.LOGTAG, "starting file observer"); Log.d(Config.LOGTAG, "starting file observer");
new Thread(fileObserver::startWatching).start(); new Thread(fileObserver::startWatching).start();
@ -1062,7 +1064,7 @@ public class XmppConnectionService extends Service {
} }
public void toggleForegroundService() { public void toggleForegroundService() {
if (mForceForegroundService.get() || (keepForegroundService() && hasEnabledAccounts())) { if (mForceForegroundService.get() || (Compatibility.keepForegroundService(this) && hasEnabledAccounts())) {
startForeground(NotificationService.FOREGROUND_NOTIFICATION_ID, this.mNotificationService.createForegroundNotification()); startForeground(NotificationService.FOREGROUND_NOTIFICATION_ID, this.mNotificationService.createForegroundNotification());
Log.d(Config.LOGTAG, "started foreground service"); Log.d(Config.LOGTAG, "started foreground service");
} else { } else {
@ -1071,14 +1073,11 @@ public class XmppConnectionService extends Service {
} }
} }
public boolean keepForegroundService() {
return getBooleanPreference(SettingsActivity.KEEP_FOREGROUND_SERVICE, R.bool.enable_foreground_service);
}
@Override @Override
public void onTaskRemoved(final Intent rootIntent) { public void onTaskRemoved(final Intent rootIntent) {
super.onTaskRemoved(rootIntent); super.onTaskRemoved(rootIntent);
if (keepForegroundService() || mForceForegroundService.get()) { //TODO check for accounts enabled
if ((Compatibility.keepForegroundService(this) && hasEnabledAccounts()) || mForceForegroundService.get()) {
Log.d(Config.LOGTAG, "ignoring onTaskRemoved because foreground service is activated"); Log.d(Config.LOGTAG, "ignoring onTaskRemoved because foreground service is activated");
} else { } else {
this.logoutAndSave(false); this.logoutAndSave(false);
@ -1951,6 +1950,7 @@ public class XmppConnectionService extends Service {
updateAccountUi(); updateAccountUi();
getNotificationService().updateErrorNotification(); getNotificationService().updateErrorNotification();
syncEnabledAccountSetting(); syncEnabledAccountSetting();
toggleForegroundService();
} }
} }

View file

@ -2,6 +2,7 @@ package eu.siacs.conversations.ui;
import android.preference.CheckBoxPreference; import android.preference.CheckBoxPreference;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.app.FragmentManager; import android.app.FragmentManager;
import android.content.DialogInterface; import android.content.DialogInterface;
@ -406,7 +407,7 @@ public class SettingsActivity extends XmppActivity implements
} }
private void startExport() { private void startExport() {
startService(new Intent(getApplicationContext(), ExportLogsService.class)); ContextCompat.startForegroundService(this, new Intent(this, ExportLogsService.class));
} }
private void displayToast(final String msg) { private void displayToast(final String msg) {

View file

@ -11,6 +11,7 @@ import android.widget.ListView;
import eu.siacs.conversations.Config; import eu.siacs.conversations.Config;
import eu.siacs.conversations.R; import eu.siacs.conversations.R;
import eu.siacs.conversations.utils.Compatibility;
public class SettingsFragment extends PreferenceFragment { public class SettingsFragment extends PreferenceFragment {
@ -32,6 +33,7 @@ public class SettingsFragment extends PreferenceFragment {
mCategory.removePreference(cleanPrivateStorage); mCategory.removePreference(cleanPrivateStorage);
} }
} }
Compatibility.removeUnusedPreferences(this);
if (!TextUtils.isEmpty(page)) { if (!TextUtils.isEmpty(page)) {
openPreferenceScreen(page); openPreferenceScreen(page);

View file

@ -532,11 +532,15 @@ public abstract class XmppActivity extends ActionBarActivity {
} }
protected void delegateUriPermissionsToService(Uri uri) { protected void delegateUriPermissionsToService(Uri uri) {
Intent intent = new Intent(this,XmppConnectionService.class); Intent intent = new Intent(this, XmppConnectionService.class);
intent.setAction(Intent.ACTION_SEND); intent.setAction(Intent.ACTION_SEND);
intent.setData(uri); intent.setData(uri);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startService(intent); try {
startService(intent);
} catch (Exception e) {
Log.e(Config.LOGTAG,"unable to delegate uri permission",e);
}
} }
protected void inviteToConversation(Conversation conversation) { protected void inviteToConversation(Conversation conversation) {

View file

@ -0,0 +1,62 @@
package eu.siacs.conversations.utils;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Build;
import android.preference.Preference;
import android.preference.PreferenceCategory;
import android.preference.PreferenceGroup;
import android.preference.PreferenceManager;
import android.support.annotation.BoolRes;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import eu.siacs.conversations.R;
import eu.siacs.conversations.ui.SettingsActivity;
import eu.siacs.conversations.ui.SettingsFragment;
public class Compatibility {
private static final List<String> UNUSED_SETTINGS_POST_TWENTYSIX = Arrays.asList(
SettingsActivity.KEEP_FOREGROUND_SERVICE,
"led",
"notification_ringtone",
"notification_headsup",
"vibrate_on_notification");
private static final List<String> UNUESD_SETTINGS_PRE_TWENTYSIX = Collections.singletonList("more_notification_settings");
public static boolean twentySix() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
}
private static boolean getBooleanPreference(Context context, String name, @BoolRes int res) {
return getPreferences(context).getBoolean(name, context.getResources().getBoolean(res));
}
private static SharedPreferences getPreferences(final Context context) {
return PreferenceManager.getDefaultSharedPreferences(context);
}
public static boolean keepForegroundService(Context context) {
return twentySix() || getBooleanPreference(context, SettingsActivity.KEEP_FOREGROUND_SERVICE, R.bool.enable_foreground_service);
}
public static void removeUnusedPreferences(SettingsFragment settingsFragment) {
List<PreferenceCategory> categories = Arrays.asList(
(PreferenceCategory) settingsFragment.findPreference("notification_category"),
(PreferenceCategory) settingsFragment.findPreference("other_expert_category"));
for (String key : (twentySix() ? UNUSED_SETTINGS_POST_TWENTYSIX : UNUESD_SETTINGS_PRE_TWENTYSIX)) {
Preference preference = settingsFragment.findPreference(key);
if (preference != null) {
for (PreferenceCategory category : categories) {
if (category != null) {
category.removePreference(preference);
}
}
}
}
}
}

View file

@ -2,12 +2,15 @@ package eu.siacs.conversations.utils;
import android.os.FileObserver; import android.os.FileObserver;
import android.util.Log;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Stack; import java.util.Stack;
import eu.siacs.conversations.Config;
/** /**
* Copyright (C) 2012 Bartek Przybylski * Copyright (C) 2012 Bartek Przybylski
* Copyright (C) 2015 ownCloud Inc. * Copyright (C) 2015 ownCloud Inc.
@ -19,7 +22,7 @@ public abstract class ConversationsFileObserver {
private final String path; private final String path;
private final List<SingleFileObserver> mObservers = new ArrayList<>(); private final List<SingleFileObserver> mObservers = new ArrayList<>();
public ConversationsFileObserver(String path) { protected ConversationsFileObserver(String path) {
this.path = path; this.path = path;
} }
@ -83,13 +86,17 @@ public abstract class ConversationsFileObserver {
private class SingleFileObserver extends FileObserver { private class SingleFileObserver extends FileObserver {
private final String path; private final String path;
public SingleFileObserver(String path, int mask) { SingleFileObserver(String path, int mask) {
super(path, mask); super(path, mask);
this.path = path; this.path = path;
} }
@Override @Override
public void onEvent(int event, String filename) { public void onEvent(int event, String filename) {
if (filename == null) {
Log.d(Config.LOGTAG,"ignored file event with NULL filename (event="+event+")");
return;
}
ConversationsFileObserver.this.onEvent(event, path+'/'+filename); ConversationsFileObserver.this.onEvent(event, path+'/'+filename);
} }

View file

@ -727,4 +727,15 @@
<string name="conference_destroyed">This group chat has been destroyed</string> <string name="conference_destroyed">This group chat has been destroyed</string>
<string name="phone_book">Address book</string> <string name="phone_book">Address book</string>
<string name="unable_to_save_recording">Unable to save recording</string> <string name="unable_to_save_recording">Unable to save recording</string>
<string name="foreground_service_channel_name">Foreground service</string>
<string name="foreground_service_channel_description">This notification category is used to display a permanent notification indicating that Conversations is running.</string>
<string name="notification_group_status_information">Status Information</string>
<string name="error_channel_name">Connectivity Problems</string>
<string name="error_channel_description">This notification category is used to display a notification in case there is a problem connecting to an account.</string>
<string name="notification_group_messages">Messages</string>
<string name="messages_channel_name">Messages</string>
<string name="silent_messages_channel_name">Silent messages</string>
<string name="silent_messages_channel_description">This notification group is used to display notifications that should not trigger any sound. For example when being active on another device (Grace Period).</string>
<string name="pref_more_notification_settings">Notification Settings</string>
<string name="pref_more_notification_settings_summary">Importance, Sound, Vibrate</string>
</resources> </resources>

View file

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android"
android:background="?attr/color_background_secondary" android:background="?attr/color_background_secondary"
android:key="main_screen"> android:key="main_screen">
@ -10,11 +9,10 @@
<PreferenceScreen <PreferenceScreen
android:key="huawei" android:key="huawei"
android:summary="@string/huawei_protected_apps_summary" android:summary="@string/huawei_protected_apps_summary"
android:title="@string/huawei_protected_apps" android:title="@string/huawei_protected_apps">
>
<intent <intent
android:targetClass="com.huawei.systemmanager.optimize.process.ProtectActivity" android:targetClass="com.huawei.systemmanager.optimize.process.ProtectActivity"
android:targetPackage="com.huawei.systemmanager"/> android:targetPackage="com.huawei.systemmanager" />
</PreferenceScreen> </PreferenceScreen>
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory android:title="@string/pref_privacy"> <PreferenceCategory android:title="@string/pref_privacy">
@ -24,62 +22,77 @@
android:entryValues="@array/omemo_setting_entry_values" android:entryValues="@array/omemo_setting_entry_values"
android:key="omemo" android:key="omemo"
android:summary="@string/pref_omemo_setting_summary_default_on" android:summary="@string/pref_omemo_setting_summary_default_on"
android:title="@string/pref_omemo_setting" android:title="@string/pref_omemo_setting" />
/>
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="@bool/confirm_messages" android:defaultValue="@bool/confirm_messages"
android:key="confirm_messages" android:key="confirm_messages"
android:summary="@string/pref_confirm_messages_summary" android:summary="@string/pref_confirm_messages_summary"
android:title="@string/pref_confirm_messages"/> android:title="@string/pref_confirm_messages" />
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="@bool/chat_states" android:defaultValue="@bool/chat_states"
android:key="chat_states" android:key="chat_states"
android:summary="@string/pref_chat_states_summary" android:summary="@string/pref_chat_states_summary"
android:title="@string/pref_chat_states"/> android:title="@string/pref_chat_states" />
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="@bool/last_activity" android:defaultValue="@bool/last_activity"
android:key="last_activity" android:key="last_activity"
android:summary="@string/pref_broadcast_last_activity_summary" android:summary="@string/pref_broadcast_last_activity_summary"
android:title="@string/pref_broadcast_last_activity"/> android:title="@string/pref_broadcast_last_activity" />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory android:title="@string/pref_notification_settings"> <PreferenceCategory
android:title="@string/pref_notification_settings"
android:key="notification_category">
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="@bool/show_notification" android:defaultValue="@bool/show_notification"
android:key="show_notification" android:key="show_notification"
android:summary="@string/pref_notifications_summary" android:summary="@string/pref_notifications_summary"
android:title="@string/pref_notifications"/> android:title="@string/pref_notifications" />
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="@bool/notifications_from_strangers" android:defaultValue="@bool/notifications_from_strangers"
android:dependency="show_notification" android:dependency="show_notification"
android:key="notifications_from_strangers" android:key="notifications_from_strangers"
android:summary="@string/pref_notifications_from_strangers_summary" android:summary="@string/pref_notifications_from_strangers_summary"
android:title="@string/pref_notifications_from_strangers"/> android:title="@string/pref_notifications_from_strangers" />
<PreferenceScreen
android:key="more_notification_settings"
android:dependency="show_notification"
android:summary="@string/pref_more_notification_settings_summary"
android:title="@string/pref_more_notification_settings">
<intent android:action="android.settings.CHANNEL_NOTIFICATION_SETTINGS">
<extra
android:name="android.provider.extra.APP_PACKAGE"
android:value="@string/applicationId" />
<extra
android:name="android.provider.extra.CHANNEL_ID"
android:value="messages" />
</intent>
</PreferenceScreen>
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="@bool/headsup_notifications" android:defaultValue="@bool/headsup_notifications"
android:dependency="show_notification" android:dependency="show_notification"
android:key="notification_headsup" android:key="notification_headsup"
android:summary="@string/pref_headsup_notifications_summary" android:summary="@string/pref_headsup_notifications_summary"
android:title="@string/pref_headsup_notifications"/> android:title="@string/pref_headsup_notifications" />
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="@bool/vibrate_on_notification" android:defaultValue="@bool/vibrate_on_notification"
android:dependency="show_notification" android:dependency="show_notification"
android:key="vibrate_on_notification" android:key="vibrate_on_notification"
android:summary="@string/pref_vibrate_summary" android:summary="@string/pref_vibrate_summary"
android:title="@string/pref_vibrate"/> android:title="@string/pref_vibrate" />
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="@bool/led" android:defaultValue="@bool/led"
android:dependency="show_notification" android:dependency="show_notification"
android:key="led" android:key="led"
android:summary="@string/pref_led_summary" android:summary="@string/pref_led_summary"
android:title="@string/pref_led"/> android:title="@string/pref_led" />
<RingtonePreference <RingtonePreference
android:defaultValue="@string/notification_ringtone" android:defaultValue="@string/notification_ringtone"
android:dependency="show_notification" android:dependency="show_notification"
android:key="notification_ringtone" android:key="notification_ringtone"
android:ringtoneType="notification" android:ringtoneType="notification"
android:summary="@string/pref_sound_summary" android:summary="@string/pref_sound_summary"
android:title="@string/pref_sound"/> android:title="@string/pref_sound" />
<PreferenceScreen <PreferenceScreen
android:dependency="show_notification" android:dependency="show_notification"
android:key="quiet_hours" android:key="quiet_hours"
@ -91,25 +104,25 @@
android:targetPackage="@string/applicationId"> android:targetPackage="@string/applicationId">
<extra <extra
android:name="page" android:name="page"
android:value="quiet_hours"/> android:value="quiet_hours" />
</intent> </intent>
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="@bool/enable_quiet_hours" android:defaultValue="@bool/enable_quiet_hours"
android:key="enable_quiet_hours" android:key="enable_quiet_hours"
android:summary="@string/pref_quiet_hours_summary" android:summary="@string/pref_quiet_hours_summary"
android:title="@string/title_pref_enable_quiet_hours"/> android:title="@string/title_pref_enable_quiet_hours" />
<eu.siacs.conversations.ui.TimePreference <eu.siacs.conversations.ui.TimePreference
android:dependency="enable_quiet_hours" android:dependency="enable_quiet_hours"
android:key="quiet_hours_start" android:key="quiet_hours_start"
android:negativeButtonText="@string/cancel" android:negativeButtonText="@string/cancel"
android:positiveButtonText="@string/set" android:positiveButtonText="@string/set"
android:title="@string/title_pref_quiet_hours_start_time"/> android:title="@string/title_pref_quiet_hours_start_time" />
<eu.siacs.conversations.ui.TimePreference <eu.siacs.conversations.ui.TimePreference
android:dependency="enable_quiet_hours" android:dependency="enable_quiet_hours"
android:key="quiet_hours_end" android:key="quiet_hours_end"
android:negativeButtonText="@string/cancel" android:negativeButtonText="@string/cancel"
android:positiveButtonText="@string/set" android:positiveButtonText="@string/set"
android:title="@string/title_pref_quiet_hours_end_time"/> android:title="@string/title_pref_quiet_hours_end_time" />
</PreferenceScreen> </PreferenceScreen>
<ListPreference <ListPreference
android:defaultValue="@integer/grace_period" android:defaultValue="@integer/grace_period"
@ -118,8 +131,7 @@
android:entryValues="@array/grace_periods_values" android:entryValues="@array/grace_periods_values"
android:key="grace_period_length" android:key="grace_period_length"
android:summary="@string/pref_notification_grace_period_summary" android:summary="@string/pref_notification_grace_period_summary"
android:title="@string/pref_notification_grace_period" android:title="@string/pref_notification_grace_period" />
/>
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory
android:key="attachments" android:key="attachments"
@ -130,24 +142,24 @@
android:entryValues="@array/filesizes_values" android:entryValues="@array/filesizes_values"
android:key="auto_accept_file_size" android:key="auto_accept_file_size"
android:summary="@string/pref_accept_files_summary" android:summary="@string/pref_accept_files_summary"
android:title="@string/pref_accept_files"/> android:title="@string/pref_accept_files" />
<ListPreference <ListPreference
android:defaultValue="@string/picture_compression" android:defaultValue="@string/picture_compression"
android:entries="@array/picture_compression_entries" android:entries="@array/picture_compression_entries"
android:entryValues="@array/picture_compression_values" android:entryValues="@array/picture_compression_values"
android:key="picture_compression" android:key="picture_compression"
android:summary="@string/pref_picture_compression_summary" android:summary="@string/pref_picture_compression_summary"
android:title="@string/pref_picture_compression"/> android:title="@string/pref_picture_compression" />
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="@bool/return_to_previous" android:defaultValue="@bool/return_to_previous"
android:key="return_to_previous" android:key="return_to_previous"
android:summary="@string/pref_return_to_previous_summary" android:summary="@string/pref_return_to_previous_summary"
android:title="@string/pref_return_to_previous"/> android:title="@string/pref_return_to_previous" />
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="@bool/use_share_location_plugin" android:defaultValue="@bool/use_share_location_plugin"
android:key="use_share_location_plugin" android:key="use_share_location_plugin"
android:summary="@string/pref_use_share_location_plugin_summary" android:summary="@string/pref_use_share_location_plugin_summary"
android:title="@string/pref_use_share_location_plugin"/> android:title="@string/pref_use_share_location_plugin" />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory android:title="@string/pref_ui_options"> <PreferenceCategory android:title="@string/pref_ui_options">
<ListPreference <ListPreference
@ -156,24 +168,24 @@
android:entryValues="@array/themes_values" android:entryValues="@array/themes_values"
android:key="theme" android:key="theme"
android:summary="@string/pref_theme_options_summary" android:summary="@string/pref_theme_options_summary"
android:title="@string/pref_theme_options"/> android:title="@string/pref_theme_options" />
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="@bool/use_green_background" android:defaultValue="@bool/use_green_background"
android:key="use_green_background" android:key="use_green_background"
android:summary="@string/pref_use_green_background_summary" android:summary="@string/pref_use_green_background_summary"
android:title="@string/pref_use_green_background"/> android:title="@string/pref_use_green_background" />
<ListPreference <ListPreference
android:defaultValue="@string/default_font_size" android:defaultValue="@string/default_font_size"
android:entries="@array/font_size_entries" android:entries="@array/font_size_entries"
android:entryValues="@array/font_size_entry_values" android:entryValues="@array/font_size_entry_values"
android:key="font_size" android:key="font_size"
android:summary="@string/pref_font_size_summary" android:summary="@string/pref_font_size_summary"
android:title="@string/pref_font_size"/> android:title="@string/pref_font_size" />
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="@bool/send_button_status" android:defaultValue="@bool/send_button_status"
android:key="send_button_status" android:key="send_button_status"
android:summary="@string/pref_use_send_button_to_indicate_status_summary" android:summary="@string/pref_use_send_button_to_indicate_status_summary"
android:title="@string/pref_use_send_button_to_indicate_status"/> android:title="@string/pref_use_send_button_to_indicate_status" />
<ListPreference <ListPreference
android:defaultValue="@string/quick_action" android:defaultValue="@string/quick_action"
android:dialogTitle="@string/choose_quick_action" android:dialogTitle="@string/choose_quick_action"
@ -181,12 +193,12 @@
android:entryValues="@array/quick_action_values" android:entryValues="@array/quick_action_values"
android:key="quick_action" android:key="quick_action"
android:summary="@string/pref_quick_action_summary" android:summary="@string/pref_quick_action_summary"
android:title="@string/pref_quick_action"/> android:title="@string/pref_quick_action" />
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="@bool/show_dynamic_tags" android:defaultValue="@bool/show_dynamic_tags"
android:key="show_dynamic_tags" android:key="show_dynamic_tags"
android:summary="@string/pref_show_dynamic_tags_summary" android:summary="@string/pref_show_dynamic_tags_summary"
android:title="@string/pref_show_dynamic_tags"/> android:title="@string/pref_show_dynamic_tags" />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory
android:key="advanced" android:key="advanced"
@ -201,7 +213,7 @@
android:targetPackage="@string/applicationId"> android:targetPackage="@string/applicationId">
<extra <extra
android:name="page" android:name="page"
android:value="expert"/> android:value="expert" />
</intent> </intent>
<PreferenceCategory <PreferenceCategory
android:key="security_options" android:key="security_options"
@ -210,43 +222,43 @@
android:defaultValue="@bool/btbv" android:defaultValue="@bool/btbv"
android:key="btbv" android:key="btbv"
android:summary="@string/pref_blind_trust_before_verification_summary" android:summary="@string/pref_blind_trust_before_verification_summary"
android:title="@string/pref_blind_trust_before_verification"/> android:title="@string/pref_blind_trust_before_verification" />
<ListPreference <ListPreference
android:defaultValue="@integer/automatic_message_deletion" android:defaultValue="@integer/automatic_message_deletion"
android:key="automatic_message_deletion" android:key="automatic_message_deletion"
android:summary="@string/pref_automatically_delete_messages_description" android:summary="@string/pref_automatically_delete_messages_description"
android:title="@string/pref_automatically_delete_messages"/> android:title="@string/pref_automatically_delete_messages" />
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="@bool/dont_trust_system_cas" android:defaultValue="@bool/dont_trust_system_cas"
android:key="dont_trust_system_cas" android:key="dont_trust_system_cas"
android:summary="@string/pref_dont_trust_system_cas_summary" android:summary="@string/pref_dont_trust_system_cas_summary"
android:title="@string/pref_dont_trust_system_cas_title"/> android:title="@string/pref_dont_trust_system_cas_title" />
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="@bool/validate_hostname" android:defaultValue="@bool/validate_hostname"
android:key="validate_hostname" android:key="validate_hostname"
android:summary="@string/pref_validate_hostname_summary" android:summary="@string/pref_validate_hostname_summary"
android:title="@string/pref_validate_hostname"/> android:title="@string/pref_validate_hostname" />
<Preference <Preference
android:key="remove_trusted_certificates" android:key="remove_trusted_certificates"
android:summary="@string/pref_remove_trusted_certificates_summary" android:summary="@string/pref_remove_trusted_certificates_summary"
android:title="@string/pref_remove_trusted_certificates_title"/> android:title="@string/pref_remove_trusted_certificates_title" />
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="@bool/allow_message_correction" android:defaultValue="@bool/allow_message_correction"
android:key="allow_message_correction" android:key="allow_message_correction"
android:summary="@string/pref_allow_message_correction_summary" android:summary="@string/pref_allow_message_correction_summary"
android:title="@string/pref_allow_message_correction"/> android:title="@string/pref_allow_message_correction" />
<Preference <Preference
android:key="clean_cache" android:key="clean_cache"
android:summary="@string/pref_clean_cache_summary" android:summary="@string/pref_clean_cache_summary"
android:title="@string/pref_clean_cache"/> android:title="@string/pref_clean_cache" />
<Preference <Preference
android:key="clean_private_storage" android:key="clean_private_storage"
android:summary="@string/pref_clean_private_storage_summary" android:summary="@string/pref_clean_private_storage_summary"
android:title="@string/pref_clean_private_storage"/> android:title="@string/pref_clean_private_storage" />
<Preference <Preference
android:key="delete_omemo_identities" android:key="delete_omemo_identities"
android:summary="@string/pref_delete_omemo_identities_summary" android:summary="@string/pref_delete_omemo_identities_summary"
android:title="@string/pref_delete_omemo_identities"/> android:title="@string/pref_delete_omemo_identities" />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory
android:key="connection_options" android:key="connection_options"
@ -255,34 +267,34 @@
android:defaultValue="@bool/use_tor" android:defaultValue="@bool/use_tor"
android:key="use_tor" android:key="use_tor"
android:summary="@string/pref_use_tor_summary" android:summary="@string/pref_use_tor_summary"
android:title="@string/pref_use_tor"/> android:title="@string/pref_use_tor" />
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="@bool/show_connection_options" android:defaultValue="@bool/show_connection_options"
android:key="show_connection_options" android:key="show_connection_options"
android:summary="@string/pref_show_connection_options_summary" android:summary="@string/pref_show_connection_options_summary"
android:title="@string/pref_show_connection_options"/> android:title="@string/pref_show_connection_options" />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory android:title="@string/pref_input_options"> <PreferenceCategory android:title="@string/pref_input_options">
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="@bool/start_searching" android:defaultValue="@bool/start_searching"
android:key="start_searching" android:key="start_searching"
android:summary="@string/pref_start_search_summary" android:summary="@string/pref_start_search_summary"
android:title="@string/pref_start_search"/> android:title="@string/pref_start_search" />
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="@bool/enter_is_send" android:defaultValue="@bool/enter_is_send"
android:key="enter_is_send" android:key="enter_is_send"
android:summary="@string/pref_enter_is_send_summary" android:summary="@string/pref_enter_is_send_summary"
android:title="@string/pref_enter_is_send"/> android:title="@string/pref_enter_is_send" />
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="@bool/display_enter_key" android:defaultValue="@bool/display_enter_key"
android:key="display_enter_key" android:key="display_enter_key"
android:summary="@string/pref_display_enter_key_summary" android:summary="@string/pref_display_enter_key_summary"
android:title="@string/pref_display_enter_key"/> android:title="@string/pref_display_enter_key" />
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="@bool/scroll_to_bottom" android:defaultValue="@bool/scroll_to_bottom"
android:key="scroll_to_bottom" android:key="scroll_to_bottom"
android:summary="@string/pref_scroll_to_bottom_summary" android:summary="@string/pref_scroll_to_bottom_summary"
android:title="@string/pref_scroll_to_bottom"/> android:title="@string/pref_scroll_to_bottom" />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory android:title="@string/pref_presence_settings"> <PreferenceCategory android:title="@string/pref_presence_settings">
<CheckBoxPreference <CheckBoxPreference
@ -290,47 +302,48 @@
android:disableDependentsState="true" android:disableDependentsState="true"
android:key="manually_change_presence" android:key="manually_change_presence"
android:summary="@string/pref_manually_change_presence_summary" android:summary="@string/pref_manually_change_presence_summary"
android:title="@string/pref_manually_change_presence"/> android:title="@string/pref_manually_change_presence" />
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="@bool/away_when_screen_off" android:defaultValue="@bool/away_when_screen_off"
android:dependency="manually_change_presence" android:dependency="manually_change_presence"
android:key="away_when_screen_off" android:key="away_when_screen_off"
android:summary="@string/pref_away_when_screen_off_summary" android:summary="@string/pref_away_when_screen_off_summary"
android:title="@string/pref_away_when_screen_off"/> android:title="@string/pref_away_when_screen_off" />
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="@bool/dnd_on_silent_mode" android:defaultValue="@bool/dnd_on_silent_mode"
android:dependency="manually_change_presence" android:dependency="manually_change_presence"
android:key="dnd_on_silent_mode" android:key="dnd_on_silent_mode"
android:summary="@string/pref_dnd_on_silent_mode_summary" android:summary="@string/pref_dnd_on_silent_mode_summary"
android:title="@string/pref_dnd_on_silent_mode"/> android:title="@string/pref_dnd_on_silent_mode" />
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="@bool/treat_vibrate_as_silent" android:defaultValue="@bool/treat_vibrate_as_silent"
android:dependency="dnd_on_silent_mode" android:dependency="dnd_on_silent_mode"
android:key="treat_vibrate_as_silent" android:key="treat_vibrate_as_silent"
android:summary="@string/pref_treat_vibrate_as_dnd_summary" android:summary="@string/pref_treat_vibrate_as_dnd_summary"
android:title="@string/pref_treat_vibrate_as_silent"/> android:title="@string/pref_treat_vibrate_as_silent" />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory android:title="@string/pref_expert_options_other"> <PreferenceCategory
android:key="other_expert_category"
android:title="@string/pref_expert_options_other">
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="@bool/autojoin" android:defaultValue="@bool/autojoin"
android:key="autojoin" android:key="autojoin"
android:summary="@string/pref_autojoin_summary" android:summary="@string/pref_autojoin_summary"
android:title="@string/pref_autojoin" android:title="@string/pref_autojoin" />
/>
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="@bool/indicate_received" android:defaultValue="@bool/indicate_received"
android:key="indicate_received" android:key="indicate_received"
android:summary="@string/pref_use_indicate_received_summary" android:summary="@string/pref_use_indicate_received_summary"
android:title="@string/pref_use_indicate_received"/> android:title="@string/pref_use_indicate_received" />
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="@bool/enable_foreground_service" android:defaultValue="@bool/enable_foreground_service"
android:key="enable_foreground_service" android:key="enable_foreground_service"
android:summary="@string/pref_keep_foreground_service_summary" android:summary="@string/pref_keep_foreground_service_summary"
android:title="@string/pref_keep_foreground_service"/> android:title="@string/pref_keep_foreground_service" />
<Preference <Preference
android:key="export_logs" android:key="export_logs"
android:summary="@string/pref_export_logs_summary" android:summary="@string/pref_export_logs_summary"
android:title="@string/pref_export_logs"/> android:title="@string/pref_export_logs" />
</PreferenceCategory> </PreferenceCategory>
</PreferenceScreen> </PreferenceScreen>
@ -338,9 +351,9 @@
android:defaultValue="@bool/never_send" android:defaultValue="@bool/never_send"
android:key="never_send" android:key="never_send"
android:summary="@string/pref_never_send_crash_summary" android:summary="@string/pref_never_send_crash_summary"
android:title="@string/pref_never_send_crash"/> android:title="@string/pref_never_send_crash" />
</PreferenceCategory> </PreferenceCategory>
<eu.siacs.conversations.ui.AboutPreference <eu.siacs.conversations.ui.AboutPreference
android:summary="@string/pref_about_conversations_summary" android:summary="@string/pref_about_conversations_summary"
android:title="@string/title_activity_about"/> android:title="@string/title_activity_about" />
</PreferenceScreen> </PreferenceScreen>