diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7489cd6..f43e1e6 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -103,9 +103,10 @@ + 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 dbe16ea..bc40eec 100644 --- a/app/src/main/java/ch/dissem/apps/abit/MessageListActivity.java +++ b/app/src/main/java/ch/dissem/apps/abit/MessageListActivity.java @@ -2,27 +2,15 @@ package ch.dissem.apps.abit; import android.accounts.Account; import android.accounts.AccountManager; -import android.content.Context; +import android.content.ContentResolver; import android.content.Intent; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; -import android.view.Menu; -import android.view.MenuItem; import android.view.View; 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; -import ch.dissem.bitmessage.entity.Streamable; -import ch.dissem.bitmessage.entity.valueobject.Label; +import android.widget.CompoundButton; import com.mikepenz.community_material_typeface_library.CommunityMaterial; import com.mikepenz.google_material_typeface_library.GoogleMaterial; @@ -34,10 +22,11 @@ import com.mikepenz.materialdrawer.accountswitcher.AccountHeaderBuilder; import com.mikepenz.materialdrawer.model.PrimaryDrawerItem; import com.mikepenz.materialdrawer.model.ProfileDrawerItem; import com.mikepenz.materialdrawer.model.ProfileSettingDrawerItem; -import com.mikepenz.materialdrawer.model.SecondaryDrawerItem; +import com.mikepenz.materialdrawer.model.SwitchDrawerItem; import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem; import com.mikepenz.materialdrawer.model.interfaces.IProfile; import com.mikepenz.materialdrawer.model.interfaces.Nameable; +import com.mikepenz.materialdrawer.model.interfaces.OnCheckedChangeListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -45,6 +34,17 @@ import org.slf4j.LoggerFactory; import java.io.Serializable; import java.util.ArrayList; +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.bitmessage.BitmessageContext; +import ch.dissem.bitmessage.entity.BitmessageAddress; +import ch.dissem.bitmessage.entity.Plaintext; +import ch.dissem.bitmessage.entity.valueobject.Label; + +import static ch.dissem.apps.abit.synchronization.StubProvider.AUTHORITY; + /** * An activity representing a list of Messages. This activity @@ -69,10 +69,9 @@ public class MessageListActivity extends AppCompatActivity public static final String ACTION_SHOW_INBOX = "ch.dissem.abit.ShowInbox"; private static final Logger LOG = LoggerFactory.getLogger(MessageListActivity.class); + private static final long SYNC_FREQUENCY = 15 * 60; // seconds 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. @@ -82,7 +81,6 @@ public class MessageListActivity extends AppCompatActivity private AccountHeader accountHeader; private BitmessageContext bmc; private Label selectedLabel; - private Menu menu; @Override protected void onCreate(Bundle savedInstanceState) { @@ -119,39 +117,22 @@ public class MessageListActivity extends AppCompatActivity onItemSelected(getIntent().getSerializableExtra(EXTRA_SHOW_MESSAGE)); } - account = createSyncAccount(this); - getContentResolver().setSyncAutomatically(account, SyncAdapter.AUTHORITY, true); + createSyncAccount(); } - 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"); + private void createSyncAccount() { + // Create account, if it's missing. (Either first run, or user has deleted account.) + Account account = new Account(Authenticator.ACCOUNT_NAME, Authenticator.ACCOUNT_TYPE); + + if (AccountManager.get(this).addAccountExplicitly(account, null, null)) { + // Inform the system that this account supports sync + ContentResolver.setIsSyncable(account, AUTHORITY, 1); + // Inform the system that this account is eligible for auto sync when the network is up + ContentResolver.setSyncAutomatically(account, AUTHORITY, true); + // Recommend a schedule for automatic synchronization. The system may modify this based + // on other scheduled syncs and network utilization. + ContentResolver.addPeriodicSync(account, AUTHORITY, new Bundle(), SYNC_FREQUENCY); } - return newAccount; - } - - @Override - protected void onResume() { - super.onResume(); } private void changeList(AbstractItemListFragment listFragment) { @@ -253,12 +234,24 @@ public class MessageListActivity extends AppCompatActivity .withAccountHeader(accountHeader) .withDrawerItems(drawerItems) .addStickyDrawerItems( - new SecondaryDrawerItem() + new PrimaryDrawerItem() .withName(R.string.subscriptions) .withIcon(CommunityMaterial.Icon.cmd_rss_box), - new SecondaryDrawerItem() + new PrimaryDrawerItem() .withName(R.string.settings) - .withIcon(GoogleMaterial.Icon.gmd_settings) + .withIcon(GoogleMaterial.Icon.gmd_settings), + new SwitchDrawerItem() + .withName(R.string.full_node) + .withIcon(CommunityMaterial.Icon.cmd_cloud_outline) + .withOnCheckedChangeListener(new OnCheckedChangeListener() { + @Override + public void onCheckedChanged(IDrawerItem drawerItem, CompoundButton buttonView, boolean isChecked) { + // TODO: warn user, option to restrict to WiFi + if (isChecked && !bmc.isRunning()) bmc.startup(); + else if (bmc.isRunning()) bmc.shutdown(); + } + }) + .withChecked(bmc.isRunning()) ) .withOnDrawerItemClickListener(new Drawer.OnDrawerItemClickListener() { @Override @@ -288,6 +281,8 @@ public class MessageListActivity extends AppCompatActivity case R.string.settings: startActivity(new Intent(MessageListActivity.this, SettingsActivity.class)); break; + case R.string.full_node: + return true; } } return false; @@ -297,36 +292,6 @@ public class MessageListActivity extends AppCompatActivity .build(); } - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.main, menu); - this.menu = menu; - updateMenu(); - return true; - } - - private void updateMenu() { - boolean running = bmc.isRunning(); - menu.findItem(R.id.sync_enabled).setVisible(running); - menu.findItem(R.id.sync_disabled).setVisible(!running); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.sync_disabled: - bmc.startup(); - updateMenu(); - return true; - case R.id.sync_enabled: - bmc.shutdown(); - updateMenu(); - return true; - default: - return super.onOptionsItemSelected(item); - } - } - /** * Callback method from {@link ListSelectionListener} * indicating that the item with the given ID was selected. diff --git a/app/src/main/java/ch/dissem/apps/abit/service/Singleton.java b/app/src/main/java/ch/dissem/apps/abit/service/Singleton.java index 76c3301..e16b235 100644 --- a/app/src/main/java/ch/dissem/apps/abit/service/Singleton.java +++ b/app/src/main/java/ch/dissem/apps/abit/service/Singleton.java @@ -1,6 +1,5 @@ package ch.dissem.apps.abit.service; -import android.app.NotificationManager; import android.content.Context; import ch.dissem.apps.abit.listeners.MessageListener; 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 index c79f074..f5b3d2d 100644 --- a/app/src/main/java/ch/dissem/apps/abit/synchronization/StubProvider.java +++ b/app/src/main/java/ch/dissem/apps/abit/synchronization/StubProvider.java @@ -10,6 +10,8 @@ import android.net.Uri; * all methods */ public class StubProvider extends ContentProvider { + public static final String AUTHORITY = "ch.dissem.apps.abit.provider"; + /* * Always return true, indicating that the * provider loaded correctly. @@ -18,6 +20,7 @@ public class StubProvider extends ContentProvider { public boolean onCreate() { return true; } + /* * Return no type for MIME type */ @@ -25,6 +28,7 @@ public class StubProvider extends ContentProvider { public String getType(Uri uri) { return null; } + /* * query() always returns no results * @@ -38,6 +42,7 @@ public class StubProvider extends ContentProvider { String sortOrder) { return null; } + /* * insert() always returns null (no URI) */ @@ -45,6 +50,7 @@ public class StubProvider extends ContentProvider { public Uri insert(Uri uri, ContentValues values) { return null; } + /* * delete() always returns "no rows affected" (0) */ @@ -52,6 +58,7 @@ public class StubProvider extends ContentProvider { public int delete(Uri uri, String selection, String[] selectionArgs) { return 0; } + /* * update() always returns "no rows affected" (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 index 890b097..c12d30c 100644 --- a/app/src/main/java/ch/dissem/apps/abit/synchronization/SyncAdapter.java +++ b/app/src/main/java/ch/dissem/apps/abit/synchronization/SyncAdapter.java @@ -25,17 +25,32 @@ import ch.dissem.bitmessage.BitmessageContext; 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); + /** + * Set up the sync adapter + */ + public SyncAdapter(Context context, boolean autoInitialize) { + super(context, autoInitialize); + bmc = Singleton.getBitmessageContext(context); + } + + /** + * Set up the sync adapter. This form of the + * constructor maintains compatibility with Android 3.0 + * and later platform versions + */ + public SyncAdapter( + Context context, + boolean autoInitialize, + boolean allowParallelSyncs) { + super(context, autoInitialize, allowParallelSyncs); bmc = Singleton.getBitmessageContext(context); } @Override public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) { + LOG.info("Synchronizing Bitmessage"); // If the Bitmessage context acts as a full node, synchronization isn't necessary if (bmc.isRunning()) return; @@ -52,7 +67,7 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter { String portString = trustedNode.substring(index + 1); trustedNode = trustedNode.substring(0, index); try { - port = Integer.parseInt(portString);// FIXME + port = Integer.parseInt(portString); } catch (NumberFormatException e) { LOG.error("Invalid port " + portString); // 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 index fb6fd9f..4beaa04 100644 --- a/app/src/main/java/ch/dissem/apps/abit/synchronization/SyncService.java +++ b/app/src/main/java/ch/dissem/apps/abit/synchronization/SyncService.java @@ -27,7 +27,7 @@ public class SyncService extends Service { */ synchronized (syncAdapterLock) { if (syncAdapter == null) { - syncAdapter = new SyncAdapter(getApplicationContext()); + syncAdapter = new SyncAdapter(getApplicationContext(), true); } } } diff --git a/app/src/main/res/menu/compose.xml b/app/src/main/res/menu/compose.xml index ee25c89..dae8007 100644 --- a/app/src/main/res/menu/compose.xml +++ b/app/src/main/res/menu/compose.xml @@ -5,5 +5,5 @@ android:id="@+id/send" app:showAsAction="always" android:icon="@drawable/ic_action_send" - android:title="@string/disable_sync"/>` + android:title="@string/send"/>` \ No newline at end of file diff --git a/app/src/main/res/menu/main.xml b/app/src/main/res/menu/main.xml index 9f35ce1..9eb7100 100644 --- a/app/src/main/res/menu/main.xml +++ b/app/src/main/res/menu/main.xml @@ -1,14 +1,4 @@ - - \ No newline at end of file diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index b86c0f8..43a43cc 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -5,8 +5,6 @@ Nur WLAN Nicht mit Mobilfunknetz verbinden Bitmessage ist aktiv - Synchronisieren ausschalten - Synchronisieren einschalten Betreff An Nachricht @@ -37,4 +35,7 @@ Timeout in Sekunden Vertrauenswürdiger Knoten Diese Adresse wird für die Synchronisation verwendet + Aktiver Knoten + Senden + Schreiben \ 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 72fa388..adf6794 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2,8 +2,6 @@ Abit Message Detail Subscription Detail - Disable Sync - Enable Sync Bitmessage active Wi-Fi Connection Mode Settings @@ -38,4 +36,6 @@ Synchronization Timeout Timeout in seconds Write message + Full node + Send