mirror of
https://github.com/etesync/android
synced 2025-08-01 19:38:22 +00:00
Proof of concept: create remote address books, delete remote collections
This commit is contained in:
parent
c30195d9ba
commit
212cd8ddb0
@ -34,6 +34,7 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
lintOptions {
|
lintOptions {
|
||||||
|
disable 'ExtraTranslation'
|
||||||
disable 'IconColors'
|
disable 'IconColors'
|
||||||
disable 'IconLauncherShape'
|
disable 'IconLauncherShape'
|
||||||
disable 'IconMissingDensityFolder'
|
disable 'IconMissingDensityFolder'
|
||||||
|
@ -121,7 +121,6 @@
|
|||||||
android:theme="@style/AppTheme.NoActionBar">
|
android:theme="@style/AppTheme.NoActionBar">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER"/>
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
@ -129,8 +128,9 @@
|
|||||||
android:name=".ui.AccountActivity"
|
android:name=".ui.AccountActivity"
|
||||||
android:parentActivityName=".ui.AccountsActivity">
|
android:parentActivityName=".ui.AccountsActivity">
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name=".ui.AccountSettingsActivity">
|
<activity android:name=".ui.AccountSettingsActivity"/>
|
||||||
</activity>
|
<activity android:name=".ui.CreateAddressBookActivity"
|
||||||
|
android:label="@string/create_address_book_title"/>
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.DebugInfoActivity"
|
android:name=".ui.DebugInfoActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
|
@ -22,6 +22,7 @@ import java.util.Locale;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import at.bitfire.dav4android.BasicDigestAuthenticator;
|
import at.bitfire.dav4android.BasicDigestAuthenticator;
|
||||||
|
import at.bitfire.davdroid.syncadapter.AccountSettings;
|
||||||
import de.duenndns.ssl.MemorizingTrustManager;
|
import de.duenndns.ssl.MemorizingTrustManager;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@ -84,6 +85,10 @@ public class HttpClient {
|
|||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static OkHttpClient addAuthentication(@NonNull OkHttpClient httpClient, @NonNull AccountSettings accountSettings) {
|
||||||
|
return addAuthentication(httpClient, accountSettings.username(), accountSettings.password(), accountSettings.preemptiveAuth());
|
||||||
|
}
|
||||||
|
|
||||||
public static OkHttpClient addAuthentication(@NonNull OkHttpClient httpClient, @NonNull String host, @NonNull String username, @NonNull String password) {
|
public static OkHttpClient addAuthentication(@NonNull OkHttpClient httpClient, @NonNull String host, @NonNull String username, @NonNull String password) {
|
||||||
return httpClient.newBuilder()
|
return httpClient.newBuilder()
|
||||||
.authenticator(new BasicDigestAuthenticator(host, username, password))
|
.authenticator(new BasicDigestAuthenticator(host, username, password))
|
||||||
|
@ -10,6 +10,8 @@ package at.bitfire.davdroid.model;
|
|||||||
|
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
import at.bitfire.dav4android.DavResource;
|
import at.bitfire.dav4android.DavResource;
|
||||||
import at.bitfire.dav4android.Property;
|
import at.bitfire.dav4android.Property;
|
||||||
import at.bitfire.dav4android.property.AddressbookDescription;
|
import at.bitfire.dav4android.property.AddressbookDescription;
|
||||||
@ -25,7 +27,7 @@ import lombok.ToString;
|
|||||||
import at.bitfire.davdroid.model.ServiceDB.*;
|
import at.bitfire.davdroid.model.ServiceDB.*;
|
||||||
|
|
||||||
@ToString
|
@ToString
|
||||||
public class CollectionInfo {
|
public class CollectionInfo implements Serializable {
|
||||||
public long id;
|
public long id;
|
||||||
public Long serviceID;
|
public Long serviceID;
|
||||||
|
|
||||||
|
30
app/src/main/java/at/bitfire/davdroid/model/DavService.java
Normal file
30
app/src/main/java/at/bitfire/davdroid/model/DavService.java
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2013 – 2016 Ricki Hirner (bitfire web engineering).
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the GNU Public License v3.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.gnu.org/licenses/gpl.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
package at.bitfire.davdroid.model;
|
||||||
|
|
||||||
|
import android.content.ContentValues;
|
||||||
|
|
||||||
|
public class DavService {
|
||||||
|
|
||||||
|
public long id;
|
||||||
|
public String accountName, service, principal;
|
||||||
|
public long lastRefresh;
|
||||||
|
|
||||||
|
|
||||||
|
public static DavService fromDB(ContentValues values) {
|
||||||
|
DavService service = new DavService();
|
||||||
|
service.id = values.getAsLong(ServiceDB.Services.ID);
|
||||||
|
service.accountName = values.getAsString(ServiceDB.Services.ACCOUNT_NAME);
|
||||||
|
service.service = values.getAsString(ServiceDB.Services.SERVICE);
|
||||||
|
service.principal = values.getAsString(ServiceDB.Services.PRINCIPAL);
|
||||||
|
//service.lastRefresh = values.getAsLong(ServiceDB.Services.LAST_REFRESH);
|
||||||
|
return service;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
29
app/src/main/java/at/bitfire/davdroid/model/HomeSet.java
Normal file
29
app/src/main/java/at/bitfire/davdroid/model/HomeSet.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2013 – 2016 Ricki Hirner (bitfire web engineering).
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the GNU Public License v3.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.gnu.org/licenses/gpl.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
package at.bitfire.davdroid.model;
|
||||||
|
|
||||||
|
import android.content.ContentValues;
|
||||||
|
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@ToString
|
||||||
|
public class HomeSet {
|
||||||
|
|
||||||
|
public long id, serviceID;
|
||||||
|
public String URL;
|
||||||
|
|
||||||
|
public static HomeSet fromDB(ContentValues values) {
|
||||||
|
HomeSet homeSet = new HomeSet();
|
||||||
|
homeSet.id = values.getAsLong(ServiceDB.HomeSets.ID);
|
||||||
|
homeSet.serviceID = values.getAsLong(ServiceDB.HomeSets.SERVICE_ID);
|
||||||
|
homeSet.URL = values.getAsString(ServiceDB.HomeSets.URL);
|
||||||
|
return homeSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -34,11 +34,13 @@ import android.os.IBinder;
|
|||||||
import android.provider.CalendarContract;
|
import android.provider.CalendarContract;
|
||||||
import android.provider.ContactsContract;
|
import android.provider.ContactsContract;
|
||||||
import android.support.design.widget.Snackbar;
|
import android.support.design.widget.Snackbar;
|
||||||
|
import android.support.v4.app.DialogFragment;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
import android.support.v7.widget.AppCompatRadioButton;
|
import android.support.v7.widget.AppCompatRadioButton;
|
||||||
import android.support.v7.widget.CardView;
|
import android.support.v7.widget.CardView;
|
||||||
import android.support.v7.widget.Toolbar;
|
import android.support.v7.widget.Toolbar;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.view.Gravity;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
@ -49,8 +51,10 @@ import android.widget.AdapterView;
|
|||||||
import android.widget.ArrayAdapter;
|
import android.widget.ArrayAdapter;
|
||||||
import android.widget.CheckBox;
|
import android.widget.CheckBox;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
|
import android.widget.PopupMenu;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
@ -66,13 +70,14 @@ import at.bitfire.davdroid.model.ServiceDB.Services;
|
|||||||
import at.bitfire.ical4android.TaskProvider;
|
import at.bitfire.ical4android.TaskProvider;
|
||||||
import lombok.Cleanup;
|
import lombok.Cleanup;
|
||||||
|
|
||||||
public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenuItemClickListener, LoaderManager.LoaderCallbacks<AccountActivity.AccountInfo> {
|
public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenuItemClickListener, PopupMenu.OnMenuItemClickListener, LoaderManager.LoaderCallbacks<AccountActivity.AccountInfo> {
|
||||||
|
|
||||||
public static final String EXTRA_ACCOUNT_NAME = "account_name";
|
public static final String EXTRA_ACCOUNT_NAME = "account_name";
|
||||||
|
|
||||||
private Account account;
|
private Account account;
|
||||||
private AccountInfo accountInfo;
|
private AccountInfo accountInfo;
|
||||||
|
|
||||||
|
ListView listCalDAV, listCardDAV;
|
||||||
Toolbar tbCardDAV, tbCalDAV;
|
Toolbar tbCardDAV, tbCalDAV;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -150,7 +155,9 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu
|
|||||||
startService(intent);
|
startService(intent);
|
||||||
break;
|
break;
|
||||||
case R.id.create_address_book:
|
case R.id.create_address_book:
|
||||||
// TODO
|
intent = new Intent(this, CreateAddressBookActivity.class);
|
||||||
|
intent.putExtra(CreateAddressBookActivity.EXTRA_ACCOUNT, account);
|
||||||
|
startActivity(intent);
|
||||||
break;
|
break;
|
||||||
case R.id.refresh_calendars:
|
case R.id.refresh_calendars:
|
||||||
intent = new Intent(this, DavService.class);
|
intent = new Intent(this, DavService.class);
|
||||||
@ -165,7 +172,7 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu
|
|||||||
|
|
||||||
/* LOADERS AND LOADED DATA */
|
/* LOADERS AND LOADED DATA */
|
||||||
|
|
||||||
public static class AccountInfo {
|
protected static class AccountInfo {
|
||||||
ServiceInfo carddav, caldav;
|
ServiceInfo carddav, caldav;
|
||||||
|
|
||||||
public static class ServiceInfo {
|
public static class ServiceInfo {
|
||||||
@ -217,11 +224,42 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private AdapterView.OnItemLongClickListener onItemLongClickListener = new AdapterView.OnItemLongClickListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
|
||||||
|
final ListView list = (ListView)parent;
|
||||||
|
final ArrayAdapter<CollectionInfo> adapter = (ArrayAdapter)list.getAdapter();
|
||||||
|
final CollectionInfo info = adapter.getItem(position);
|
||||||
|
|
||||||
|
PopupMenu popup = new PopupMenu(AccountActivity.this, view, Gravity.CENTER);
|
||||||
|
popup.inflate(R.menu.account_collection_operations);
|
||||||
|
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onMenuItemClick(MenuItem item) {
|
||||||
|
switch (item.getItemId()) {
|
||||||
|
case R.id.delete_collection:
|
||||||
|
DeleteCollectionFragment.newInstance(account, info).show(getSupportFragmentManager(), null);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
popup.show();
|
||||||
|
|
||||||
|
// long click was handled
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Loader<AccountInfo> onCreateLoader(int id, Bundle args) {
|
public Loader<AccountInfo> onCreateLoader(int id, Bundle args) {
|
||||||
return new AccountLoader(this, args.getString(EXTRA_ACCOUNT_NAME));
|
return new AccountLoader(this, args.getString(EXTRA_ACCOUNT_NAME));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void reload() {
|
||||||
|
getLoaderManager().restartLoader(0, getIntent().getExtras(), this);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoadFinished(Loader<AccountInfo> loader, final AccountInfo info) {
|
public void onLoadFinished(Loader<AccountInfo> loader, final AccountInfo info) {
|
||||||
accountInfo = info;
|
accountInfo = info;
|
||||||
@ -231,14 +269,15 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu
|
|||||||
ProgressBar progress = (ProgressBar)findViewById(R.id.carddav_refreshing);
|
ProgressBar progress = (ProgressBar)findViewById(R.id.carddav_refreshing);
|
||||||
progress.setVisibility(info.carddav.refreshing ? View.VISIBLE : View.GONE);
|
progress.setVisibility(info.carddav.refreshing ? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
ListView list = (ListView)findViewById(R.id.address_books);
|
listCardDAV = (ListView)findViewById(R.id.address_books);
|
||||||
list.setEnabled(!info.carddav.refreshing);
|
listCardDAV.setEnabled(!info.carddav.refreshing);
|
||||||
list.setAlpha(info.carddav.refreshing ? 0.5f : 1);
|
listCardDAV.setAlpha(info.carddav.refreshing ? 0.5f : 1);
|
||||||
|
|
||||||
AddressBookAdapter adapter = new AddressBookAdapter(this);
|
AddressBookAdapter adapter = new AddressBookAdapter(this);
|
||||||
adapter.addAll(info.carddav.collections);
|
adapter.addAll(info.carddav.collections);
|
||||||
list.setAdapter(adapter);
|
listCardDAV.setAdapter(adapter);
|
||||||
list.setOnItemClickListener(onItemClickListener);
|
listCardDAV.setOnItemClickListener(onItemClickListener);
|
||||||
|
listCardDAV.setOnItemLongClickListener(onItemLongClickListener);
|
||||||
} else
|
} else
|
||||||
card.setVisibility(View.GONE);
|
card.setVisibility(View.GONE);
|
||||||
|
|
||||||
@ -247,14 +286,15 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu
|
|||||||
ProgressBar progress = (ProgressBar)findViewById(R.id.caldav_refreshing);
|
ProgressBar progress = (ProgressBar)findViewById(R.id.caldav_refreshing);
|
||||||
progress.setVisibility(info.caldav.refreshing ? View.VISIBLE : View.GONE);
|
progress.setVisibility(info.caldav.refreshing ? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
final ListView list = (ListView)findViewById(R.id.calendars);
|
listCalDAV = (ListView)findViewById(R.id.calendars);
|
||||||
list.setEnabled(!info.caldav.refreshing);
|
listCalDAV.setEnabled(!info.caldav.refreshing);
|
||||||
list.setAlpha(info.caldav.refreshing ? 0.5f : 1);
|
listCalDAV.setAlpha(info.caldav.refreshing ? 0.5f : 1);
|
||||||
|
|
||||||
final CalendarAdapter adapter = new CalendarAdapter(this);
|
final CalendarAdapter adapter = new CalendarAdapter(this);
|
||||||
adapter.addAll(info.caldav.collections);
|
adapter.addAll(info.caldav.collections);
|
||||||
list.setAdapter(adapter);
|
listCalDAV.setAdapter(adapter);
|
||||||
list.setOnItemClickListener(onItemClickListener);
|
listCalDAV.setOnItemClickListener(onItemClickListener);
|
||||||
|
listCalDAV.setOnItemLongClickListener(onItemLongClickListener);
|
||||||
} else
|
} else
|
||||||
card.setVisibility(View.GONE);
|
card.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
@ -263,6 +303,7 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu
|
|||||||
public void onLoaderReset(Loader<AccountInfo> loader) {
|
public void onLoaderReset(Loader<AccountInfo> loader) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static class AccountLoader extends AsyncTaskLoader<AccountInfo> implements DavService.RefreshingStatusListener, ServiceConnection {
|
private static class AccountLoader extends AsyncTaskLoader<AccountInfo> implements DavService.RefreshingStatusListener, ServiceConnection {
|
||||||
private final String accountName;
|
private final String accountName;
|
||||||
private final OpenHelper dbHelper;
|
private final OpenHelper dbHelper;
|
||||||
@ -289,6 +330,8 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu
|
|||||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||||
davService = (DavService.InfoBinder)service;
|
davService = (DavService.InfoBinder)service;
|
||||||
davService.addRefreshingStatusListener(this, false);
|
davService.addRefreshingStatusListener(this, false);
|
||||||
|
|
||||||
|
SQLiteDatabase db;
|
||||||
forceLoad();
|
forceLoad();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ public class AccountListFragment extends ListFragment implements LoaderManager.L
|
|||||||
|
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public static class AccountInfo {
|
protected static class AccountInfo {
|
||||||
final Account account;
|
final Account account;
|
||||||
Long cardDavService, calDavService;
|
Long cardDavService, calDavService;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,240 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2013 – 2016 Ricki Hirner (bitfire web engineering).
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the GNU Public License v3.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.gnu.org/licenses/gpl.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
package at.bitfire.davdroid.ui;
|
||||||
|
|
||||||
|
import android.accounts.Account;
|
||||||
|
import android.content.ContentValues;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.database.DatabaseUtils;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.v4.app.LoaderManager;
|
||||||
|
import android.support.v4.content.AsyncTaskLoader;
|
||||||
|
import android.support.v4.content.Loader;
|
||||||
|
import android.support.v7.app.AppCompatActivity;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.widget.SimpleAdapter;
|
||||||
|
import android.widget.Spinner;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import org.xmlpull.v1.XmlSerializer;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import at.bitfire.dav4android.DavResource;
|
||||||
|
import at.bitfire.dav4android.XmlUtils;
|
||||||
|
import at.bitfire.dav4android.exception.HttpException;
|
||||||
|
import at.bitfire.davdroid.Constants;
|
||||||
|
import at.bitfire.davdroid.HttpClient;
|
||||||
|
import at.bitfire.davdroid.R;
|
||||||
|
import at.bitfire.davdroid.model.CollectionInfo;
|
||||||
|
import at.bitfire.davdroid.model.DavService;
|
||||||
|
import at.bitfire.davdroid.model.HomeSet;
|
||||||
|
import at.bitfire.davdroid.model.ServiceDB;
|
||||||
|
import at.bitfire.davdroid.syncadapter.AccountSettings;
|
||||||
|
import lombok.Cleanup;
|
||||||
|
import okhttp3.HttpUrl;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
|
||||||
|
public class CreateAddressBookActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<CreateAddressBookActivity.AccountInfo> {
|
||||||
|
public final static String EXTRA_ACCOUNT = "account";
|
||||||
|
|
||||||
|
private Account account;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_create_address_book);
|
||||||
|
|
||||||
|
account = getIntent().getParcelableExtra(EXTRA_ACCOUNT);
|
||||||
|
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||||
|
|
||||||
|
getSupportLoaderManager().initLoader(0, getIntent().getExtras(), this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
|
getMenuInflater().inflate(R.menu.activity_create_address_book, menu);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
switch (item.getItemId()) {
|
||||||
|
case android.R.id.home:
|
||||||
|
Intent intent = new Intent(this, AccountActivity.class);
|
||||||
|
intent.putExtra(AccountActivity.EXTRA_ACCOUNT_NAME, account.name);
|
||||||
|
startActivity(intent);
|
||||||
|
break;
|
||||||
|
case R.id.create_address_book:
|
||||||
|
createAddressBook();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void createAddressBook() {
|
||||||
|
Spinner spnrHomeSets = (Spinner)findViewById(R.id.homeset);
|
||||||
|
HashMap<String, String> homeSet = (HashMap<String, String>)spnrHomeSets.getSelectedItem();
|
||||||
|
|
||||||
|
HttpUrl urlHomeSet = HttpUrl.parse(homeSet.get(ServiceDB.HomeSets.URL));
|
||||||
|
|
||||||
|
CollectionInfo info = new CollectionInfo();
|
||||||
|
info.url = urlHomeSet.resolve("myAddrBook.vcf").toString();
|
||||||
|
info.displayName = "myAddrBook";
|
||||||
|
|
||||||
|
new AddressBookCreator().execute( info);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// AsyncTask for creating the address book
|
||||||
|
|
||||||
|
class AddressBookCreator extends AsyncTask<CollectionInfo, Void, Exception> {
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Exception e) {
|
||||||
|
String msg = (e == null) ? "Created!" : e.getLocalizedMessage();
|
||||||
|
Toast.makeText(CreateAddressBookActivity.this, msg, Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Exception doInBackground(CollectionInfo[] infoArray) {
|
||||||
|
AccountSettings accountSettings = new AccountSettings(CreateAddressBookActivity.this, account);
|
||||||
|
|
||||||
|
CollectionInfo info = infoArray[0];
|
||||||
|
OkHttpClient client = HttpClient.create(CreateAddressBookActivity.this);
|
||||||
|
client = HttpClient.addAuthentication(client, accountSettings.username(), accountSettings.password(), accountSettings.preemptiveAuth());
|
||||||
|
|
||||||
|
DavResource addressBook = new DavResource(null, client, HttpUrl.parse(info.url));
|
||||||
|
|
||||||
|
StringWriter writer = new StringWriter();
|
||||||
|
try {
|
||||||
|
XmlSerializer serializer = XmlUtils.newSerializer();
|
||||||
|
serializer.setOutput(writer);
|
||||||
|
serializer.startDocument("UTF-8", null);
|
||||||
|
serializer.setPrefix("", XmlUtils.NS_WEBDAV);
|
||||||
|
serializer.setPrefix("CARD", XmlUtils.NS_CARDDAV);
|
||||||
|
|
||||||
|
serializer.startTag(XmlUtils.NS_WEBDAV, "mkcol");
|
||||||
|
serializer.startTag(XmlUtils.NS_WEBDAV, "set");
|
||||||
|
serializer.startTag(XmlUtils.NS_WEBDAV, "prop");
|
||||||
|
serializer.startTag(XmlUtils.NS_WEBDAV, "resourcetype");
|
||||||
|
serializer.startTag(XmlUtils.NS_WEBDAV, "collection");
|
||||||
|
serializer.endTag(XmlUtils.NS_WEBDAV, "collection");
|
||||||
|
serializer.startTag(XmlUtils.NS_CARDDAV, "addressbook");
|
||||||
|
serializer.endTag(XmlUtils.NS_CARDDAV, "addressbook");
|
||||||
|
serializer.endTag(XmlUtils.NS_WEBDAV, "resourcetype");
|
||||||
|
serializer.startTag(XmlUtils.NS_WEBDAV, "displayname");
|
||||||
|
serializer.text(info.displayName);
|
||||||
|
serializer.endTag(XmlUtils.NS_WEBDAV, "displayname");
|
||||||
|
serializer.endTag(XmlUtils.NS_WEBDAV, "prop");
|
||||||
|
serializer.endTag(XmlUtils.NS_WEBDAV, "set");
|
||||||
|
serializer.endTag(XmlUtils.NS_WEBDAV, "mkcol");
|
||||||
|
serializer.endDocument();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Constants.log.error("Couldn't assemble MKCOL request", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
String error = null;
|
||||||
|
try {
|
||||||
|
addressBook.mkCol(writer.toString());
|
||||||
|
} catch (IOException|HttpException e) {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// loader
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Loader<AccountInfo> onCreateLoader(int id, Bundle args) {
|
||||||
|
return new AccountLoader(this, account);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoadFinished(Loader<AccountInfo> loader, AccountInfo data) {
|
||||||
|
Spinner spnrHomeSets = (Spinner)findViewById(R.id.homeset);
|
||||||
|
|
||||||
|
List<HashMap<String, String>> adapterData = new LinkedList<>();
|
||||||
|
for (HomeSet homeSet : data.homeSets) {
|
||||||
|
HashMap<String, String> map = new HashMap();
|
||||||
|
map.put(ServiceDB.HomeSets.ID, String.valueOf(homeSet.id));
|
||||||
|
map.put(ServiceDB.HomeSets.URL, homeSet.URL);
|
||||||
|
adapterData.add(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
spnrHomeSets.setAdapter(new SimpleAdapter(this, adapterData, android.R.layout.simple_spinner_item, new String[] { ServiceDB.HomeSets.URL }, new int[] { android.R.id.text1 } ));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoaderReset(Loader<AccountInfo> loader) {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static class AccountInfo {
|
||||||
|
DavService service;
|
||||||
|
List<HomeSet> homeSets = new LinkedList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class AccountLoader extends AsyncTaskLoader<AccountInfo> {
|
||||||
|
private final Account account;
|
||||||
|
ServiceDB.OpenHelper dbHelper;
|
||||||
|
|
||||||
|
public AccountLoader(Context context, Account account) {
|
||||||
|
super(context);
|
||||||
|
this.account = account;
|
||||||
|
|
||||||
|
dbHelper = new ServiceDB.OpenHelper(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onStartLoading() {
|
||||||
|
forceLoad();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AccountInfo loadInBackground() {
|
||||||
|
SQLiteDatabase db = dbHelper.getReadableDatabase();
|
||||||
|
try {
|
||||||
|
@Cleanup Cursor cursorService = db.query(ServiceDB.Services._TABLE, null, ServiceDB.Services.ACCOUNT_NAME + "=? AND " + ServiceDB.Services.SERVICE + "=?",
|
||||||
|
new String[] { account.name, ServiceDB.Services.SERVICE_CARDDAV }, null, null, null);
|
||||||
|
if (!cursorService.moveToNext())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
AccountInfo info = new AccountInfo();
|
||||||
|
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
DatabaseUtils.cursorRowToContentValues(cursorService, values);
|
||||||
|
info.service = DavService.fromDB(values);
|
||||||
|
|
||||||
|
@Cleanup Cursor cursorHomeSets = db.query(ServiceDB.HomeSets._TABLE, null, ServiceDB.HomeSets.SERVICE_ID + "=?",
|
||||||
|
new String[] { String.valueOf(info.service.id) }, null, null, null);
|
||||||
|
while (cursorHomeSets.moveToNext()) {
|
||||||
|
values.clear();
|
||||||
|
DatabaseUtils.cursorRowToContentValues(cursorHomeSets, values);
|
||||||
|
info.homeSets.add(HomeSet.fromDB(values));
|
||||||
|
}
|
||||||
|
|
||||||
|
return info;
|
||||||
|
} finally {
|
||||||
|
dbHelper.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2013 – 2016 Ricki Hirner (bitfire web engineering).
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the GNU Public License v3.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.gnu.org/licenses/gpl.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
package at.bitfire.davdroid.ui;
|
||||||
|
|
||||||
|
import android.accounts.Account;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.app.ProgressDialog;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.v4.app.DialogFragment;
|
||||||
|
import android.support.v4.app.LoaderManager;
|
||||||
|
import android.support.v4.content.AsyncTaskLoader;
|
||||||
|
import android.support.v4.content.Loader;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import at.bitfire.dav4android.DavResource;
|
||||||
|
import at.bitfire.dav4android.exception.HttpException;
|
||||||
|
import at.bitfire.davdroid.Constants;
|
||||||
|
import at.bitfire.davdroid.HttpClient;
|
||||||
|
import at.bitfire.davdroid.model.CollectionInfo;
|
||||||
|
import at.bitfire.davdroid.model.ServiceDB;
|
||||||
|
import at.bitfire.davdroid.syncadapter.AccountSettings;
|
||||||
|
import okhttp3.HttpUrl;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
|
||||||
|
public class DeleteCollectionFragment extends DialogFragment implements LoaderManager.LoaderCallbacks<Exception> {
|
||||||
|
protected static final String
|
||||||
|
ARG_ACCOUNT = "account",
|
||||||
|
ARG_COLLECTION_INFO = "collectionInfo";
|
||||||
|
|
||||||
|
public static DeleteCollectionFragment newInstance(Account account, CollectionInfo collectionInfo) {
|
||||||
|
DeleteCollectionFragment frag = new DeleteCollectionFragment();
|
||||||
|
Bundle args = new Bundle(2);
|
||||||
|
args.putParcelable(ARG_ACCOUNT, account);
|
||||||
|
args.putSerializable(ARG_COLLECTION_INFO, collectionInfo);
|
||||||
|
frag.setArguments(args);
|
||||||
|
return frag;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
getLoaderManager().initLoader(0, getArguments(), this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
|
Dialog dialog = new ProgressDialog.Builder(getContext())
|
||||||
|
.setTitle("Deleting collection")
|
||||||
|
.setMessage("Deleting collection from server, please wait.")
|
||||||
|
.setCancelable(false)
|
||||||
|
.create();
|
||||||
|
dialog.setCanceledOnTouchOutside(false);
|
||||||
|
return dialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Loader<Exception> onCreateLoader(int id, Bundle args) {
|
||||||
|
CollectionInfo collectionInfo = (CollectionInfo)args.getSerializable(ARG_COLLECTION_INFO);
|
||||||
|
return new DeleteCollectionLoader(
|
||||||
|
getContext(),
|
||||||
|
(Account)args.getParcelable(ARG_ACCOUNT),
|
||||||
|
collectionInfo.id,
|
||||||
|
HttpUrl.parse(collectionInfo.url)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoadFinished(Loader<Exception> loader, Exception exception) {
|
||||||
|
String msg = (exception == null) ? "Collection deleted" : exception.getLocalizedMessage();
|
||||||
|
Toast.makeText(getContext(), msg, Toast.LENGTH_LONG).show();
|
||||||
|
dismissAllowingStateLoss();
|
||||||
|
|
||||||
|
AccountActivity activity = (AccountActivity)getActivity();
|
||||||
|
activity.reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoaderReset(Loader<Exception> loader) {
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class DeleteCollectionLoader extends AsyncTaskLoader<Exception> {
|
||||||
|
final Account account;
|
||||||
|
final long collectionId;
|
||||||
|
final HttpUrl url;
|
||||||
|
final ServiceDB.OpenHelper dbHelper;
|
||||||
|
|
||||||
|
public DeleteCollectionLoader(Context context, Account account, long collectionId, HttpUrl url) {
|
||||||
|
super(context);
|
||||||
|
this.account = account;
|
||||||
|
this.collectionId = collectionId;
|
||||||
|
this.url = url;
|
||||||
|
|
||||||
|
dbHelper = new ServiceDB.OpenHelper(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onStartLoading() {
|
||||||
|
forceLoad();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Exception loadInBackground() {
|
||||||
|
SQLiteDatabase db = dbHelper.getReadableDatabase();
|
||||||
|
|
||||||
|
OkHttpClient httpClient = HttpClient.create(getContext());
|
||||||
|
httpClient = HttpClient.addAuthentication(httpClient, new AccountSettings(getContext(), account));
|
||||||
|
|
||||||
|
DavResource collection = new DavResource(null, httpClient, url);
|
||||||
|
try {
|
||||||
|
collection.delete(null);
|
||||||
|
|
||||||
|
db.delete(ServiceDB.Collections._TABLE, ServiceDB.Collections.ID + "=?", new String[] { String.valueOf(collectionId) });
|
||||||
|
|
||||||
|
return null;
|
||||||
|
} catch (IOException|HttpException e) {
|
||||||
|
return e;
|
||||||
|
} finally {
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -14,9 +14,9 @@ import android.view.View;
|
|||||||
import android.widget.ListAdapter;
|
import android.widget.ListAdapter;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
|
|
||||||
public class NonScrollingListView extends ListView {
|
public class MaximizedListView extends ListView {
|
||||||
|
|
||||||
public NonScrollingListView(Context context, AttributeSet attrs) {
|
public MaximizedListView(Context context, AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
}
|
}
|
||||||
|
|
@ -32,6 +32,7 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:indeterminate="true"
|
android:indeterminate="true"
|
||||||
|
android:visibility="invisible"
|
||||||
style="@android:style/Widget.ProgressBar.Small"/>
|
style="@android:style/Widget.ProgressBar.Small"/>
|
||||||
|
|
||||||
<Space
|
<Space
|
||||||
|
@ -50,7 +50,7 @@
|
|||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
android:indeterminate="true"/>
|
android:indeterminate="true"/>
|
||||||
|
|
||||||
<at.bitfire.davdroid.ui.widget.NonScrollingListView
|
<at.bitfire.davdroid.ui.widget.MaximizedListView
|
||||||
android:id="@+id/address_books"
|
android:id="@+id/address_books"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@ -89,7 +89,7 @@
|
|||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
android:indeterminate="true"/>
|
android:indeterminate="true"/>
|
||||||
|
|
||||||
<at.bitfire.davdroid.ui.widget.NonScrollingListView
|
<at.bitfire.davdroid.ui.widget.MaximizedListView
|
||||||
android:id="@+id/calendars"
|
android:id="@+id/calendars"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
25
app/src/main/res/layout/activity_create_address_book.xml
Normal file
25
app/src/main/res/layout/activity_create_address_book.xml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright © 2013 – 2016 Ricki Hirner (bitfire web engineering).
|
||||||
|
~ All rights reserved. This program and the accompanying materials
|
||||||
|
~ are made available under the terms of the GNU Public License v3.0
|
||||||
|
~ which accompanies this distribution, and is available at
|
||||||
|
~ http://www.gnu.org/licenses/gpl.html
|
||||||
|
-->
|
||||||
|
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/homeset_label"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Home set:"/>
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/homeset"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
15
app/src/main/res/menu/account_collection_operations.xml
Normal file
15
app/src/main/res/menu/account_collection_operations.xml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright © 2013 – 2016 Ricki Hirner (bitfire web engineering).
|
||||||
|
~ All rights reserved. This program and the accompanying materials
|
||||||
|
~ are made available under the terms of the GNU Public License v3.0
|
||||||
|
~ which accompanies this distribution, and is available at
|
||||||
|
~ http://www.gnu.org/licenses/gpl.html
|
||||||
|
-->
|
||||||
|
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<item android:id="@+id/delete_collection"
|
||||||
|
android:title="Delete collection"/>
|
||||||
|
|
||||||
|
</menu>
|
17
app/src/main/res/menu/activity_create_address_book.xml
Normal file
17
app/src/main/res/menu/activity_create_address_book.xml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright © 2013 – 2016 Ricki Hirner (bitfire web engineering).
|
||||||
|
~ All rights reserved. This program and the accompanying materials
|
||||||
|
~ are made available under the terms of the GNU Public License v3.0
|
||||||
|
~ which accompanies this distribution, and is available at
|
||||||
|
~ http://www.gnu.org/licenses/gpl.html
|
||||||
|
-->
|
||||||
|
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<item android:id="@+id/create_address_book"
|
||||||
|
app:showAsAction="always"
|
||||||
|
android:title="Create address book"/>
|
||||||
|
|
||||||
|
</menu>
|
@ -170,6 +170,9 @@
|
|||||||
<item>Once a day</item>
|
<item>Once a day</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<!-- CreateAddressBookActivity -->
|
||||||
|
<string name="create_address_book_title">Create address book</string>
|
||||||
|
|
||||||
<string name="settings_android_update_title">Android version update</string>
|
<string name="settings_android_update_title">Android version update</string>
|
||||||
<string name="settings_android_update_description">Android version updates may have an impact on how DAVdroid works. If there are problems, please delete your DAVdroid accounts and add them again.</string>
|
<string name="settings_android_update_description">Android version updates may have an impact on how DAVdroid works. If there are problems, please delete your DAVdroid accounts and add them again.</string>
|
||||||
<string name="settings_version_update_title">Settings have been updated</string>
|
<string name="settings_version_update_title">Settings have been updated</string>
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 519decc0aa66a5f7d828fd5741b5250649f9a85a
|
Subproject commit 0e9522bb3a2d4e33bac214883f8316b91be0960e
|
Loading…
Reference in New Issue
Block a user