diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 19861c3..7489cd6 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,104 +1,131 @@ + xmlns:tools="http://schemas.android.com/tools" + package="ch.dissem.apps.abit"> - - - - - + + + + + + + + + android:allowBackup="true" + android:icon="@mipmap/ic_launcher" + android:label="@string/app_name" + android:theme="@style/AppTheme"> + android:name=".MessageListActivity" + android:label="@string/app_name"> - + - + + android:name=".MessageDetailActivity" + android:label="@string/title_message_detail" + android:parentActivityName=".MessageListActivity" + tools:ignore="UnusedAttribute"> + android:name="android.support.PARENT_ACTIVITY" + android:value=".MessageListActivity" /> + android:name=".SubscriptionDetailActivity" + android:label="@string/title_subscription_detail" + android:parentActivityName=".MessageListActivity" + tools:ignore="UnusedAttribute"> + android:name="android.support.PARENT_ACTIVITY" + android:value=".MessageListActivity" /> + android:name=".ComposeMessageActivity" + android:label="Compose" + android:parentActivityName=".MessageListActivity"> + android:name="android.support.PARENT_ACTIVITY" + android:value=".MessageListActivity" /> - + - - - + + + - + - + - + - + - + - + - + + android:name=".SettingsActivity" + android:label="@string/settings" + android:parentActivityName=".MessageListActivity"> - + - + + android:name=".OpenBitmessageLinkActivity" + android:label="@string/title_activity_open_bitmessage_link" + android:theme="@style/Theme.AppCompat.Light.Dialog"> - + - - - + + + - - + + + + + + + + + + + + + + + + diff --git a/app/src/main/java/ch/dissem/apps/abit/AbstractItemListFragment.java b/app/src/main/java/ch/dissem/apps/abit/AbstractItemListFragment.java index 7ddfce9..3500931 100644 --- a/app/src/main/java/ch/dissem/apps/abit/AbstractItemListFragment.java +++ b/app/src/main/java/ch/dissem/apps/abit/AbstractItemListFragment.java @@ -21,6 +21,7 @@ import android.os.Bundle; import android.support.v4.app.ListFragment; import android.view.View; import android.widget.ListView; + import ch.dissem.apps.abit.listeners.ListSelectionListener; import ch.dissem.apps.abit.service.Singleton; import ch.dissem.bitmessage.BitmessageContext; @@ -54,6 +55,7 @@ public abstract class AbstractItemListFragment extends ListFragment { * The current activated item position. Only used on tablets. */ private int activatedPosition = ListView.INVALID_POSITION; + private boolean activateOnItemClick; abstract void updateList(Label label); @@ -75,6 +77,17 @@ public abstract class AbstractItemListFragment extends ListFragment { } } + @Override + public void onResume() { + super.onResume(); + + // When setting CHOICE_MODE_SINGLE, ListView will automatically + // give items the 'activated' state when touched. + getListView().setChoiceMode(activateOnItemClick + ? ListView.CHOICE_MODE_SINGLE + : ListView.CHOICE_MODE_NONE); + } + @Override public void onAttach(Activity activity) { super.onAttach(activity); @@ -118,11 +131,15 @@ public abstract class AbstractItemListFragment extends ListFragment { * given the 'activated' state when touched. */ public void setActivateOnItemClick(boolean activateOnItemClick) { - // When setting CHOICE_MODE_SINGLE, ListView will automatically - // give items the 'activated' state when touched. - getListView().setChoiceMode(activateOnItemClick - ? ListView.CHOICE_MODE_SINGLE - : ListView.CHOICE_MODE_NONE); + this.activateOnItemClick = activateOnItemClick; + + if (isVisible()) { + // When setting CHOICE_MODE_SINGLE, ListView will automatically + // give items the 'activated' state when touched. + getListView().setChoiceMode(activateOnItemClick + ? ListView.CHOICE_MODE_SINGLE + : ListView.CHOICE_MODE_NONE); + } } private void setActivatedPosition(int position) { diff --git a/app/src/main/java/ch/dissem/apps/abit/MessageListActivity.java b/app/src/main/java/ch/dissem/apps/abit/MessageListActivity.java index 0ec6bfa..dbe16ea 100644 --- a/app/src/main/java/ch/dissem/apps/abit/MessageListActivity.java +++ b/app/src/main/java/ch/dissem/apps/abit/MessageListActivity.java @@ -1,5 +1,8 @@ package ch.dissem.apps.abit; +import android.accounts.Account; +import android.accounts.AccountManager; +import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.support.v4.app.Fragment; @@ -13,6 +16,8 @@ import android.widget.AdapterView; import ch.dissem.apps.abit.listeners.ActionBarListener; import ch.dissem.apps.abit.listeners.ListSelectionListener; import ch.dissem.apps.abit.service.Singleton; +import ch.dissem.apps.abit.synchronization.Authenticator; +import ch.dissem.apps.abit.synchronization.SyncAdapter; import ch.dissem.bitmessage.BitmessageContext; import ch.dissem.bitmessage.entity.BitmessageAddress; import ch.dissem.bitmessage.entity.Plaintext; @@ -66,6 +71,8 @@ public class MessageListActivity extends AppCompatActivity private static final Logger LOG = LoggerFactory.getLogger(MessageListActivity.class); private static final int ADD_IDENTITY = 1; + private Account account; + /** * Whether or not the activity is in two-pane mode, i.e. running on a tablet * device. @@ -97,6 +104,10 @@ public class MessageListActivity extends AppCompatActivity // res/values-sw600dp). If this view is present, then the // activity should be in two-pane mode. twoPane = true; + + // In two-pane mode, list items should be given the + // 'activated' state when touched. + listFragment.setActivateOnItemClick(true); } createDrawer(toolbar); @@ -107,17 +118,40 @@ public class MessageListActivity extends AppCompatActivity if (getIntent().hasExtra(EXTRA_SHOW_MESSAGE)) { onItemSelected(getIntent().getSerializableExtra(EXTRA_SHOW_MESSAGE)); } + + account = createSyncAccount(this); + getContentResolver().setSyncAutomatically(account, SyncAdapter.AUTHORITY, true); + } + + private Account createSyncAccount(Context context) { + // Create the account type and default account + Account newAccount = new Account(Authenticator.ACCOUNT_NAME, Authenticator.ACCOUNT_TYPE); + // Get an instance of the Android account manager + AccountManager accountManager = (AccountManager) context.getSystemService(ACCOUNT_SERVICE); + /* + * Add the account and account type, no password or user data + * If successful, return the Account object, otherwise report an error. + */ + if (accountManager.addAccountExplicitly(newAccount, null, null)) { + /* + * If you don't set android:syncable="true" in + * in your element in the manifest, + * then call context.setIsSyncable(account, AUTHORITY, 1) + * here. + */ + } else { + /* + * The account exists or some other error occurred. Log this, report it, + * or handle it internally. + */ + LOG.error("Couldn't add account"); + } + return newAccount; } @Override protected void onResume() { super.onResume(); - if (twoPane) { - // In two-pane mode, list items should be given the - // 'activated' state when touched. - ((MessageListFragment) getSupportFragmentManager().findFragmentById(R.id.item_list)) - .setActivateOnItemClick(true); - } } private void changeList(AbstractItemListFragment listFragment) { @@ -232,7 +266,7 @@ public class MessageListActivity extends AppCompatActivity if (item.getTag() instanceof Label) { selectedLabel = (Label) item.getTag(); if (!(getSupportFragmentManager().findFragmentById(R.id.item_list) instanceof MessageListFragment)) { - MessageListFragment listFragment = new MessageListFragment(); + MessageListFragment listFragment = new MessageListFragment(getApplicationContext()); changeList(listFragment); listFragment.updateList(selectedLabel); } else { diff --git a/app/src/main/java/ch/dissem/apps/abit/MessageListFragment.java b/app/src/main/java/ch/dissem/apps/abit/MessageListFragment.java index cb02e54..a5515c5 100644 --- a/app/src/main/java/ch/dissem/apps/abit/MessageListFragment.java +++ b/app/src/main/java/ch/dissem/apps/abit/MessageListFragment.java @@ -1,6 +1,7 @@ package ch.dissem.apps.abit; import android.app.Activity; +import android.content.Context; import android.content.Intent; import android.graphics.Typeface; import android.os.Bundle; @@ -11,6 +12,7 @@ import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; + import ch.dissem.apps.abit.listeners.ActionBarListener; import ch.dissem.apps.abit.listeners.ListSelectionListener; import ch.dissem.apps.abit.service.Singleton; @@ -41,6 +43,10 @@ public class MessageListFragment extends AbstractItemListFragment { public MessageListFragment() { } + public MessageListFragment(Context ctx) { + bmc = Singleton.getBitmessageContext(ctx); + } + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -58,6 +64,9 @@ public class MessageListFragment extends AbstractItemListFragment<Plaintext> { @Override public void updateList(Label label) { currentLabel = label; + + if (!isVisible()) return; + setListAdapter(new ArrayAdapter<Plaintext>( getActivity(), android.R.layout.simple_list_item_activated_1, diff --git a/app/src/main/java/ch/dissem/apps/abit/synchronization/Authenticator.java b/app/src/main/java/ch/dissem/apps/abit/synchronization/Authenticator.java new file mode 100644 index 0000000..5a6d3c3 --- /dev/null +++ b/app/src/main/java/ch/dissem/apps/abit/synchronization/Authenticator.java @@ -0,0 +1,82 @@ +package ch.dissem.apps.abit.synchronization; + +import android.accounts.AbstractAccountAuthenticator; +import android.accounts.Account; +import android.accounts.AccountAuthenticatorResponse; +import android.accounts.NetworkErrorException; +import android.content.Context; +import android.os.Bundle; + +/* + * Implement AbstractAccountAuthenticator and stub out all + * of its methods + */ +public class Authenticator extends AbstractAccountAuthenticator { + public static final String ACCOUNT_NAME = "Bitmessage"; + public static final String ACCOUNT_TYPE = "bitmessage.dissem.ch"; + + // Simple constructor + public Authenticator(Context context) { + super(context); + } + + // Editing properties is not supported + @Override + public Bundle editProperties( + AccountAuthenticatorResponse r, String s) { + throw new UnsupportedOperationException(); + } + + // Don't add additional accounts + @Override + public Bundle addAccount( + AccountAuthenticatorResponse r, + String s, + String s2, + String[] strings, + Bundle bundle) throws NetworkErrorException { + return null; + } + + // Ignore attempts to confirm credentials + @Override + public Bundle confirmCredentials( + AccountAuthenticatorResponse r, + Account account, + Bundle bundle) throws NetworkErrorException { + return null; + } + + // Getting an authentication token is not supported + @Override + public Bundle getAuthToken( + AccountAuthenticatorResponse r, + Account account, + String s, + Bundle bundle) throws NetworkErrorException { + throw new UnsupportedOperationException(); + } + + // Getting a label for the auth token is not supported + @Override + public String getAuthTokenLabel(String s) { + throw new UnsupportedOperationException(); + } + + // Updating user credentials is not supported + @Override + public Bundle updateCredentials( + AccountAuthenticatorResponse r, + Account account, + String s, Bundle bundle) throws NetworkErrorException { + throw new UnsupportedOperationException(); + } + + // Checking features for the account is not supported + @Override + public Bundle hasFeatures( + AccountAuthenticatorResponse r, + Account account, String[] strings) throws NetworkErrorException { + throw new UnsupportedOperationException(); + } +} \ No newline at end of file diff --git a/app/src/main/java/ch/dissem/apps/abit/synchronization/AuthenticatorService.java b/app/src/main/java/ch/dissem/apps/abit/synchronization/AuthenticatorService.java new file mode 100644 index 0000000..8fe717d --- /dev/null +++ b/app/src/main/java/ch/dissem/apps/abit/synchronization/AuthenticatorService.java @@ -0,0 +1,31 @@ +package ch.dissem.apps.abit.synchronization; + +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; + +/** + * A bound Service that instantiates the authenticator + * when started. + */ +public class AuthenticatorService extends Service { + /** + * Instance field that stores the authenticator object + */ + private Authenticator authenticator; + + @Override + public void onCreate() { + // Create a new authenticator object + authenticator = new Authenticator(this); + } + + /* + * When the system binds to this Service to make the RPC call + * return the authenticator's IBinder. + */ + @Override + public IBinder onBind(Intent intent) { + return authenticator.getIBinder(); + } +} \ No newline at end of file diff --git a/app/src/main/java/ch/dissem/apps/abit/synchronization/StubProvider.java b/app/src/main/java/ch/dissem/apps/abit/synchronization/StubProvider.java new file mode 100644 index 0000000..c79f074 --- /dev/null +++ b/app/src/main/java/ch/dissem/apps/abit/synchronization/StubProvider.java @@ -0,0 +1,65 @@ +package ch.dissem.apps.abit.synchronization; + +import android.content.ContentProvider; +import android.content.ContentValues; +import android.database.Cursor; +import android.net.Uri; + +/* + * Define an implementation of ContentProvider that stubs out + * all methods + */ +public class StubProvider extends ContentProvider { + /* + * Always return true, indicating that the + * provider loaded correctly. + */ + @Override + public boolean onCreate() { + return true; + } + /* + * Return no type for MIME type + */ + @Override + public String getType(Uri uri) { + return null; + } + /* + * query() always returns no results + * + */ + @Override + public Cursor query( + Uri uri, + String[] projection, + String selection, + String[] selectionArgs, + String sortOrder) { + return null; + } + /* + * insert() always returns null (no URI) + */ + @Override + public Uri insert(Uri uri, ContentValues values) { + return null; + } + /* + * delete() always returns "no rows affected" (0) + */ + @Override + public int delete(Uri uri, String selection, String[] selectionArgs) { + return 0; + } + /* + * update() always returns "no rows affected" (0) + */ + public int update( + Uri uri, + ContentValues values, + String selection, + String[] selectionArgs) { + return 0; + } +} diff --git a/app/src/main/java/ch/dissem/apps/abit/synchronization/SyncAdapter.java b/app/src/main/java/ch/dissem/apps/abit/synchronization/SyncAdapter.java new file mode 100644 index 0000000..890b097 --- /dev/null +++ b/app/src/main/java/ch/dissem/apps/abit/synchronization/SyncAdapter.java @@ -0,0 +1,74 @@ +package ch.dissem.apps.abit.synchronization; + +import android.accounts.Account; +import android.content.AbstractThreadedSyncAdapter; +import android.content.ContentProviderClient; +import android.content.Context; +import android.content.SharedPreferences; +import android.content.SyncResult; +import android.os.Bundle; +import android.preference.PreferenceManager; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +import ch.dissem.apps.abit.service.Singleton; +import ch.dissem.bitmessage.BitmessageContext; + +/** + * Sync Adapter to synchronize with the Bitmessage network - fetches + * new objects and then disconnects. + */ +public class SyncAdapter extends AbstractThreadedSyncAdapter { + private final static Logger LOG = LoggerFactory.getLogger(SyncAdapter.class); + + public static final String AUTHORITY = "ch.dissem.bitmessage.provider"; + + private final BitmessageContext bmc; + + public SyncAdapter(Context context) { + super(context, true, false); + bmc = Singleton.getBitmessageContext(context); + } + + @Override + public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) { + // If the Bitmessage context acts as a full node, synchronization isn't necessary + if (bmc.isRunning()) return; + + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getContext()); + + String trustedNode = preferences.getString("trusted_node", null); + if (trustedNode == null) return; + trustedNode = trustedNode.trim(); + if (trustedNode.isEmpty()) return; + + int port; + if (trustedNode.matches("^(?![0-9a-fA-F]*:[0-9a-fA-F]*:).*(:[0-9]+)$")) { + int index = trustedNode.lastIndexOf(':'); + String portString = trustedNode.substring(index + 1); + trustedNode = trustedNode.substring(0, index); + try { + port = Integer.parseInt(portString);// FIXME + } catch (NumberFormatException e) { + LOG.error("Invalid port " + portString); + // TODO: show error as notification + return; + } + } else { + port = 8444; + } + long timeoutInSeconds = preferences.getInt("sync_timeout", 120); + try { + LOG.info("Synchronization started"); + bmc.synchronize(InetAddress.getByName(trustedNode), port, timeoutInSeconds, true); + LOG.info("Synchronization finished"); + } catch (UnknownHostException e) { + LOG.error("Couldn't synchronize", e); + // TODO: show error as notification + } + } +} diff --git a/app/src/main/java/ch/dissem/apps/abit/synchronization/SyncService.java b/app/src/main/java/ch/dissem/apps/abit/synchronization/SyncService.java new file mode 100644 index 0000000..fb6fd9f --- /dev/null +++ b/app/src/main/java/ch/dissem/apps/abit/synchronization/SyncService.java @@ -0,0 +1,49 @@ +package ch.dissem.apps.abit.synchronization; + +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; + +/** + * Define a Service that returns an IBinder for the + * sync adapter class, allowing the sync adapter framework to call + * onPerformSync(). + */ +public class SyncService extends Service { + // Storage for an instance of the sync adapter + private static SyncAdapter syncAdapter = null; + // Object to use as a thread-safe lock + private static final Object syncAdapterLock = new Object(); + + /* + * Instantiate the sync adapter object. + */ + @Override + public void onCreate() { + /* + * Create the sync adapter as a singleton. + * Set the sync adapter as syncable + * Disallow parallel syncs + */ + synchronized (syncAdapterLock) { + if (syncAdapter == null) { + syncAdapter = new SyncAdapter(getApplicationContext()); + } + } + } + + /** + * Return an object that allows the system to invoke + * the sync adapter. + */ + @Override + public IBinder onBind(Intent intent) { + /* + * Get the object that allows external processes + * to call onPerformSync(). The object is created + * in the base class code when the SyncAdapter + * constructors call super() + */ + return syncAdapter.getSyncAdapterBinder(); + } +} \ No newline at end of file diff --git a/app/src/main/res/layout-sw600dp/activity_message_list.xml b/app/src/main/res/layout-w720dp/activity_message_list.xml similarity index 100% rename from app/src/main/res/layout-sw600dp/activity_message_list.xml rename to app/src/main/res/layout-w720dp/activity_message_list.xml diff --git a/app/src/main/res/layout/activity_open_bitmessage_link.xml b/app/src/main/res/layout/activity_open_bitmessage_link.xml index 95f792d..fedbd9d 100644 --- a/app/src/main/res/layout/activity_open_bitmessage_link.xml +++ b/app/src/main/res/layout/activity_open_bitmessage_link.xml @@ -1,83 +1,81 @@ <?xml version="1.0" encoding="utf-8"?> -<RelativeLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:padding="16dp"> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:padding="16dp"> <TextView - android:id="@+id/address" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="BM-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" - android:textAppearance="?android:attr/textAppearanceSmall"/> + android:id="@+id/address" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="BM-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + android:textAppearance="?android:attr/textAppearanceSmall" /> <android.support.design.widget.TextInputLayout - android:id="@+id/label_wrapper" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_below="@+id/address"> + android:id="@+id/label_wrapper" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@+id/address"> <EditText - android:id="@+id/label" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:inputType="textPersonName" - android:hint="@string/label"/> + android:id="@+id/label" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:hint="@string/label" + android:inputType="textPersonName" /> </android.support.design.widget.TextInputLayout> <Switch - android:id="@+id/import_contact" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/import_contact" - android:layout_below="@+id/label_wrapper" - android:layout_centerHorizontal="true" - android:layout_marginTop="8dp"/> + android:id="@+id/import_contact" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@+id/label_wrapper" + android:layout_centerHorizontal="true" + android:layout_marginTop="8dp" + android:text="@string/import_contact" /> <Switch - android:id="@+id/subscribe" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/subscribe" - android:layout_below="@+id/import_contact" - android:layout_centerHorizontal="true" - android:layout_marginTop="8dp" - android:layout_marginBottom="8dp"/> + android:id="@+id/subscribe" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@+id/import_contact" + android:layout_centerHorizontal="true" + android:layout_marginBottom="8dp" + android:layout_marginTop="8dp" + android:text="@string/subscribe" /> <Button - android:id="@+id/compose_message" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="Message" - style="?android:attr/borderlessButtonStyle" - android:layout_below="@+id/subscribe" - android:layout_alignParentRight="true" - android:layout_alignParentEnd="true" - android:layout_marginTop="12dp" - android:layout_marginBottom="12dp"/> + android:id="@+id/do_import" + style="?android:attr/borderlessButtonStyle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentEnd="true" + android:layout_alignParentRight="true" + android:layout_below="@+id/subscribe" + android:layout_marginBottom="12dp" + android:layout_marginTop="12dp" + android:text="@string/do_import" /> <Button - android:id="@+id/do_import" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/do_import" - style="?android:attr/borderlessButtonStyle" - android:layout_below="@+id/subscribe" - android:layout_alignParentRight="true" - android:layout_alignParentEnd="true" - android:layout_marginTop="12dp" - android:layout_marginBottom="12dp"/> + android:id="@+id/compose_message" + style="?android:attr/borderlessButtonStyle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignTop="@+id/do_import" + android:layout_below="@+id/subscribe" + android:layout_toLeftOf="@+id/do_import" + android:layout_toStartOf="@+id/do_import" + android:text="@string/write_message" /> <Button - android:id="@+id/cancel" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/cancel" - style="?android:attr/borderlessButtonStyle" - android:layout_alignTop="@+id/do_import" - android:layout_toLeftOf="@+id/do_import" - android:layout_toStartOf="@+id/do_import"/> + android:id="@+id/cancel" + style="?android:attr/borderlessButtonStyle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignTop="@+id/compose_message" + android:layout_toLeftOf="@+id/compose_message" + android:layout_toStartOf="@+id/compose_message" + android:text="@string/cancel" /> </RelativeLayout> diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 2222570..b86c0f8 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -33,4 +33,8 @@ <string name="stream_number">Stream #%d</string> <string name="enabled">Aktiv</string> <string name="title_subscription_detail">Abonnement</string> + <string name="sync_timeout">Zeitbeschränkung der Synchronisierung</string> + <string name="sync_timeout_summary">Timeout in Sekunden</string> + <string name="trusted_node">Vertrauenswürdiger Knoten</string> + <string name="trusted_node_summary">Diese Adresse wird für die Synchronisation verwendet</string> </resources> \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 43775b5..72fa388 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -33,4 +33,9 @@ <string name="empty_trash">Empty Trash</string> <string name="stream_number">Stream #%d</string> <string name="enabled">Enabled</string> + <string name="trusted_node">Trusted node</string> + <string name="trusted_node_summary">Use this node for synchronization</string> + <string name="sync_timeout">Synchronization Timeout</string> + <string name="sync_timeout_summary">Timeout in seconds</string> + <string name="write_message">Write message</string> </resources> diff --git a/app/src/main/res/xml/authenticator.xml b/app/src/main/res/xml/authenticator.xml new file mode 100644 index 0000000..aa46bf6 --- /dev/null +++ b/app/src/main/res/xml/authenticator.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android" + android:accountType="bitmessage.dissem.ch" + android:icon="@mipmap/ic_launcher" + android:label="@string/app_name" + android:smallIcon="@mipmap/ic_launcher" /> \ No newline at end of file diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index e1f7327..d026e3f 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -9,8 +9,19 @@ android:entryValues="@array/connection_mode_values"/> --> <SwitchPreference - android:key="wifi_only" - android:title="@string/wifi_only" - android:summary="@string/wifi_only_summary" - android:defaultValue="true"/> + android:defaultValue="true" + android:key="wifi_only" + android:summary="@string/wifi_only_summary" + android:title="@string/wifi_only" /> + <EditTextPreference + android:inputType="textUri" + android:key="trusted_node" + android:summary="@string/trusted_node_summary" + android:title="@string/trusted_node" /> + <EditTextPreference + android:defaultValue="120" + android:inputType="number" + android:key="sync_timeout" + android:summary="@string/sync_timeout_summary" + android:title="@string/sync_timeout" /> </PreferenceScreen> \ No newline at end of file diff --git a/app/src/main/res/xml/syncadapter.xml b/app/src/main/res/xml/syncadapter.xml new file mode 100644 index 0000000..20cacd2 --- /dev/null +++ b/app/src/main/res/xml/syncadapter.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<sync-adapter + xmlns:android="http://schemas.android.com/apk/res/android" + android:contentAuthority="ch.dissem.bitmessage.provider" + android:accountType="ch.dissem.bitmessage" + android:userVisible="true" + android:supportsUploading="true" + android:allowParallelSyncs="false" + android:isAlwaysSyncable="true"/> \ No newline at end of file