diff --git a/app/build.gradle b/app/build.gradle index 38a247cc..939c6f0c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -17,8 +17,8 @@ android { minSdkVersion 14 targetSdkVersion 22 - versionCode 83 - versionName "0.9.1-beta1" + versionCode 84 + versionName "0.9.1" buildConfigField "java.util.Date", "buildTime", "new java.util.Date()" } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6eeeb717..37d7820e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -104,7 +104,7 @@ + android:excludeFromRecents="true"> 0; + + String email = editEmail.getText().toString(); + try { + URI uri = new URI("mailto:" + email); + if (uri.isOpaque()) { + int pos = email.lastIndexOf("@"); + if (pos != -1) + emailOk = !email.substring(pos + 1).isEmpty(); } - break; - default: - return false; - } - return true; - } + } catch (URISyntaxException e) { + // invalid mailto: URI + } - - // input validation - - @Override - public void onPrepareOptionsMenu(Menu menu) { - boolean emailOk = false, - passwordOk = editPassword.getText().length() > 0; + MenuItem item = menu.findItem(R.id.next); + item.setEnabled(emailOk && passwordOk); + } - String email = editEmail.getText().toString(); - try { - URI uri = new URI("mailto:" + email); - if (uri.isOpaque()) { - int pos = email.lastIndexOf("@"); - if (pos != -1) - emailOk = !email.substring(pos+1).isEmpty(); - } - } catch (URISyntaxException e) { - // invalid mailto: URI - } - - MenuItem item = menu.findItem(R.id.next); - item.setEnabled(emailOk && passwordOk); - } - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - } + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - getActivity().invalidateOptionsMenu(); - } + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + getActivity().invalidateOptionsMenu(); + } - @Override - public void afterTextChanged(Editable s) { - } + @Override + public void afterTextChanged(Editable s) { + } } diff --git a/app/src/main/java/at/bitfire/davdroid/ui/setup/LoginURLFragment.java b/app/src/main/java/at/bitfire/davdroid/ui/setup/LoginURLFragment.java index b3dda862..29fa18af 100644 --- a/app/src/main/java/at/bitfire/davdroid/ui/setup/LoginURLFragment.java +++ b/app/src/main/java/at/bitfire/davdroid/ui/setup/LoginURLFragment.java @@ -9,6 +9,7 @@ package at.bitfire.davdroid.ui.setup; import android.app.DialogFragment; import android.app.Fragment; +import android.content.Context; import android.os.Bundle; import android.text.Editable; import android.text.TextUtils; @@ -19,6 +20,7 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; +import android.view.inputmethod.InputMethodManager; import android.widget.AdapterView; import android.widget.AdapterView.OnItemSelectedListener; import android.widget.CheckBox; @@ -34,120 +36,130 @@ import at.bitfire.davdroid.R; import at.bitfire.davdroid.resource.ServerInfo; public class LoginURLFragment extends Fragment implements TextWatcher { - - protected Spinner spnrScheme; - protected TextView textHttpWarning; - protected EditText editBaseURI, editUserName, editPassword; - protected CheckBox checkboxPreemptive; + + protected Spinner spnrScheme; + protected TextView textHttpWarning; + protected EditText editBaseURI, editUserName, editPassword; + protected CheckBox checkboxPreemptive; - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View v = inflater.inflate(R.layout.setup_login_url, container, false); - - // protocol selection spinner - textHttpWarning = (TextView)v.findViewById(R.id.http_warning); - - spnrScheme = (Spinner)v.findViewById(R.id.login_scheme); - spnrScheme.setOnItemSelectedListener(new OnItemSelectedListener() { - @Override - public void onItemSelected(AdapterView parent, View view, int position, long id) { - String scheme = parent.getAdapter().getItem(position).toString(); - textHttpWarning.setVisibility(scheme.equals("https://") ? View.GONE : View.VISIBLE); - } + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View v = inflater.inflate(R.layout.setup_login_url, container, false); - @Override - public void onNothingSelected(AdapterView parent) { - } - }); - spnrScheme.setSelection(1); // HTTPS + // protocol selection spinner + textHttpWarning = (TextView)v.findViewById(R.id.http_warning); - // other input fields - editBaseURI = (EditText)v.findViewById(R.id.login_host_path); - editBaseURI.addTextChangedListener(this); - - editUserName = (EditText)v.findViewById(R.id.userName); - editUserName.addTextChangedListener(this); - - editPassword = (EditText)v.findViewById(R.id.password); - editPassword.addTextChangedListener(this); - - checkboxPreemptive = (CheckBox) v.findViewById(R.id.auth_preemptive); - - // hook into action bar - setHasOptionsMenu(true); - - return v; - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - inflater.inflate(R.menu.only_next, menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.next: - try { - ServerInfo serverInfo = new ServerInfo( - getBaseURI(), - editUserName.getText().toString(), - editPassword.getText().toString(), - checkboxPreemptive.isChecked() - ); - Bundle args = new Bundle(); - args.putSerializable(QueryServerDialogFragment.KEY_SERVER_INFO, serverInfo); - DialogFragment dialog = new QueryServerDialogFragment(); - dialog.setArguments(args); - dialog.show(getFragmentManager(), null); - } catch(URISyntaxException e) { - Constants.log.debug("Invalid URI", e); + spnrScheme = (Spinner)v.findViewById(R.id.login_scheme); + spnrScheme.setOnItemSelectedListener(new OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + String scheme = parent.getAdapter().getItem(position).toString(); + textHttpWarning.setVisibility(scheme.equals("https://") ? View.GONE : View.VISIBLE); } - break; - default: - return false; - } - return true; - } - - - private URI getBaseURI() throws URISyntaxException { - String scheme = spnrScheme.getSelectedItem().toString(), - host_path = editBaseURI.getText().toString(); - return new URI(scheme + host_path); - } - - // input validation - - @Override - public void onPrepareOptionsMenu(Menu menu) { - boolean usernameOk = editUserName.getText().length() > 0, - passwordOk = editPassword.getText().length() > 0, - urlOk = false; - - // check host name - try { - if (!TextUtils.isEmpty(getBaseURI().getHost())) - urlOk = true; - } catch (Exception e) { - } - - MenuItem item = menu.findItem(R.id.next); - item.setEnabled(usernameOk && passwordOk && urlOk); - } + @Override + public void onNothingSelected(AdapterView parent) { + } + }); + spnrScheme.setSelection(1); // HTTPS - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - } + // other input fields + editBaseURI = (EditText)v.findViewById(R.id.login_host_path); + editBaseURI.addTextChangedListener(this); - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - getActivity().invalidateOptionsMenu(); - } + editUserName = (EditText)v.findViewById(R.id.userName); + editUserName.addTextChangedListener(this); - @Override - public void afterTextChanged(Editable s) { - } + editPassword = (EditText)v.findViewById(R.id.password); + editPassword.addTextChangedListener(this); + + checkboxPreemptive = (CheckBox)v.findViewById(R.id.auth_preemptive); + + // hook into action bar + setHasOptionsMenu(true); + + return v; + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + inflater.inflate(R.menu.only_next, menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.next: + try { + ServerInfo serverInfo = new ServerInfo( + getBaseURI(), + editUserName.getText().toString(), + editPassword.getText().toString(), + checkboxPreemptive.isChecked() + ); + Bundle args = new Bundle(); + args.putSerializable(QueryServerDialogFragment.KEY_SERVER_INFO, serverInfo); + DialogFragment dialog = new QueryServerDialogFragment(); + dialog.setArguments(args); + dialog.show(getFragmentManager(), null); + } catch (URISyntaxException e) { + Constants.log.debug("Invalid URI", e); + } + break; + default: + return false; + } + return true; + } + + @Override + public void onResume() { + super.onResume(); + // set focus and show soft keyboard + if (editBaseURI.requestFocus()) { + InputMethodManager imm = (InputMethodManager)getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); + imm.showSoftInput(editBaseURI, InputMethodManager.SHOW_IMPLICIT); + } + } + + + private URI getBaseURI() throws URISyntaxException { + String scheme = spnrScheme.getSelectedItem().toString(), + host_path = editBaseURI.getText().toString(); + return new URI(scheme + host_path); + } + + + // input validation + + @Override + public void onPrepareOptionsMenu(Menu menu) { + boolean usernameOk = editUserName.getText().length() > 0, + passwordOk = editPassword.getText().length() > 0, + urlOk = false; + + // check host name + try { + if (!TextUtils.isEmpty(getBaseURI().getHost())) + urlOk = true; + } catch (Exception e) { + } + + MenuItem item = menu.findItem(R.id.next); + item.setEnabled(usernameOk && passwordOk && urlOk); + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + getActivity().invalidateOptionsMenu(); + } + + @Override + public void afterTextChanged(Editable s) { + } } diff --git a/app/src/main/java/at/bitfire/davdroid/ui/setup/QueryServerDialogFragment.java b/app/src/main/java/at/bitfire/davdroid/ui/setup/QueryServerDialogFragment.java index 3d4e13d1..2c17207e 100644 --- a/app/src/main/java/at/bitfire/davdroid/ui/setup/QueryServerDialogFragment.java +++ b/app/src/main/java/at/bitfire/davdroid/ui/setup/QueryServerDialogFragment.java @@ -20,6 +20,8 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.Loader; import android.os.Bundle; +import android.view.WindowManager; +import android.view.inputmethod.InputMethodManager; import java.io.BufferedReader; import java.io.IOException; @@ -48,29 +50,30 @@ public class QueryServerDialogFragment extends DialogFragment implements LoaderC @Override public Dialog onCreateDialog(Bundle savedInstanceState) { ProgressDialog dialog = new ProgressDialog(getActivity()); - dialog.setCancelable(false); + dialog.setCanceledOnTouchOutside(false); + setCancelable(false); + dialog.setTitle(R.string.setup_resource_detection); dialog.setIndeterminate(true); dialog.setMessage(getString(R.string.setup_querying_server)); return dialog; } + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); -@Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + Loader loader = getLoaderManager().initLoader(0, getArguments(), this); + } - Loader loader = getLoaderManager().initLoader(0, getArguments(), this); - } + @Override + public Loader onCreateLoader(int id, Bundle args) { + return new ServerInfoLoader(getActivity(), args); + } - @Override - public Loader onCreateLoader(int id, Bundle args) { - return new ServerInfoLoader(getActivity(), args); - } - - @Override + @Override @SuppressLint("CommitTransaction") - public void onLoadFinished(Loader loader, ServerInfo serverInfo) { + public void onLoadFinished(Loader loader, ServerInfo serverInfo) { if (serverInfo.isEmpty()) { // resource detection didn't find anything getFragmentManager().beginTransaction() @@ -78,7 +81,7 @@ public class QueryServerDialogFragment extends DialogFragment implements LoaderC .commitAllowingStateLoss(); } else { - ((AddAccountActivity) getActivity()).serverInfo = serverInfo; + ((AddAccountActivity)getActivity()).serverInfo = serverInfo; // resource detection brought some results Fragment nextFragment; @@ -93,12 +96,12 @@ public class QueryServerDialogFragment extends DialogFragment implements LoaderC .commitAllowingStateLoss(); } - getDialog().dismiss(); - } + getDialog().dismiss(); + } - @Override - public void onLoaderReset(Loader arg0) { - } + @Override + public void onLoaderReset(Loader arg0) { + } public static class NothingDetectedFragment extends DialogFragment { @@ -135,17 +138,17 @@ public class QueryServerDialogFragment extends DialogFragment implements LoaderC .create(); } } - - static class ServerInfoLoader extends AsyncTaskLoader { - private static final String TAG = "davdroid.ServerInfoLoader"; - final Bundle args; - final Context context; - - public ServerInfoLoader(Context context, Bundle args) { - super(context); - this.context = context; - this.args = args; - } + + static class ServerInfoLoader extends AsyncTaskLoader { + private static final String TAG = "davdroid.ServerInfoLoader"; + final Bundle args; + final Context context; + + public ServerInfoLoader(Context context, Bundle args) { + super(context); + this.context = context; + this.args = args; + } @Override protected void onStartLoading() { @@ -153,8 +156,8 @@ public class QueryServerDialogFragment extends DialogFragment implements LoaderC } @Override - public ServerInfo loadInBackground() { - ServerInfo serverInfo = (ServerInfo)args.getSerializable(KEY_SERVER_INFO); + public ServerInfo loadInBackground() { + ServerInfo serverInfo = (ServerInfo)args.getSerializable(KEY_SERVER_INFO); StringLogger logger = new StringLogger("DavResourceFinder", true); DavResourceFinder finder = new DavResourceFinder(logger, context, serverInfo); @@ -174,8 +177,8 @@ public class QueryServerDialogFragment extends DialogFragment implements LoaderC serverInfo.setLogs(logger.toString()); - return serverInfo; - } - } + return serverInfo; + } + } } diff --git a/app/src/main/java/at/bitfire/davdroid/ui/setup/SelectCollectionsFragment.java b/app/src/main/java/at/bitfire/davdroid/ui/setup/SelectCollectionsFragment.java index 2d68f85f..85a439cb 100644 --- a/app/src/main/java/at/bitfire/davdroid/ui/setup/SelectCollectionsFragment.java +++ b/app/src/main/java/at/bitfire/davdroid/ui/setup/SelectCollectionsFragment.java @@ -25,101 +25,101 @@ import at.bitfire.davdroid.resource.ServerInfo; public class SelectCollectionsFragment extends ListFragment { - protected ServerInfo serverInfo; + protected ServerInfo serverInfo; - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - serverInfo = ((AddAccountActivity)getActivity()).serverInfo; + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + serverInfo = ((AddAccountActivity)getActivity()).serverInfo; - View v = super.onCreateView(inflater, container, savedInstanceState); - setHasOptionsMenu(true); + View v = super.onCreateView(inflater, container, savedInstanceState); + setHasOptionsMenu(true); - return v; - } + return v; + } - @Override - public void onDestroyView() { - super.onDestroyView(); - setListAdapter(null); - } + @Override + public void onDestroyView() { + super.onDestroyView(); + setListAdapter(null); + } - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - - final ListView listView = getListView(); - listView.setPadding(20, 30, 20, 30); - - View header = getActivity().getLayoutInflater().inflate(R.layout.setup_select_collections_header, getListView(), false); - listView.addHeaderView(header, getListView(), false); + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); - final SelectCollectionsAdapter adapter = new SelectCollectionsAdapter(view.getContext(), serverInfo); - setListAdapter(adapter); - - listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); - listView.setOnItemClickListener(new OnItemClickListener() { - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - int itemPosition = position - 1; // one list header view at pos. 0 - if (adapter.getItemViewType(itemPosition) == SelectCollectionsAdapter.TYPE_ADDRESS_BOOKS_ROW) { - // unselect all other address books - for (int pos = 1; pos <= adapter.getNAddressBooks(); pos++) - if (pos != itemPosition) - listView.setItemChecked(pos + 1, false); - } - - getActivity().invalidateOptionsMenu(); - } - }); - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - inflater.inflate(R.menu.only_next, menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.next: - // synchronize only selected collections - for (ServerInfo.ResourceInfo addressBook : serverInfo.getAddressBooks()) - addressBook.setEnabled(false); - for (ServerInfo.ResourceInfo calendar : serverInfo.getCalendars()) - calendar.setEnabled(false); - for (ServerInfo.ResourceInfo todoList : serverInfo.getTaskLists()) - todoList.setEnabled(false); - - ListAdapter adapter = getListView().getAdapter(); - for (long id : getListView().getCheckedItemIds()) { - int position = (int)id + 1; // +1 because header view is inserted at pos. 0 - ServerInfo.ResourceInfo info = (ServerInfo.ResourceInfo)adapter.getItem(position); - info.setEnabled(true); - } - - getFragmentManager().beginTransaction() - .replace(R.id.right_pane, new AccountDetailsFragment()) - .addToBackStack(null) - .commitAllowingStateLoss(); - break; - default: - return false; - } - return true; - } - - - // input validation - - @Override - public void onPrepareOptionsMenu(Menu menu) { - boolean ok = false; - try { - ok = getListView().getCheckedItemCount() > 0; - } catch(IllegalStateException e) { - } - MenuItem item = menu.findItem(R.id.next); - item.setEnabled(ok); - } + final ListView listView = getListView(); + listView.setPadding(20, 30, 20, 30); + + View header = getActivity().getLayoutInflater().inflate(R.layout.setup_select_collections_header, getListView(), false); + listView.addHeaderView(header, getListView(), false); + + final SelectCollectionsAdapter adapter = new SelectCollectionsAdapter(view.getContext(), serverInfo); + setListAdapter(adapter); + + listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); + listView.setOnItemClickListener(new OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + int itemPosition = position - 1; // one list header view at pos. 0 + if (adapter.getItemViewType(itemPosition) == SelectCollectionsAdapter.TYPE_ADDRESS_BOOKS_ROW) { + // unselect all other address books + for (int pos = 1; pos <= adapter.getNAddressBooks(); pos++) + if (pos != itemPosition) + listView.setItemChecked(pos + 1, false); + } + + getActivity().invalidateOptionsMenu(); + } + }); + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + inflater.inflate(R.menu.only_next, menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.next: + // synchronize only selected collections + for (ServerInfo.ResourceInfo addressBook : serverInfo.getAddressBooks()) + addressBook.setEnabled(false); + for (ServerInfo.ResourceInfo calendar : serverInfo.getCalendars()) + calendar.setEnabled(false); + for (ServerInfo.ResourceInfo todoList : serverInfo.getTaskLists()) + todoList.setEnabled(false); + + ListAdapter adapter = getListView().getAdapter(); + for (long id : getListView().getCheckedItemIds()) { + int position = (int)id + 1; // +1 because header view is inserted at pos. 0 + ServerInfo.ResourceInfo info = (ServerInfo.ResourceInfo)adapter.getItem(position); + info.setEnabled(true); + } + + getFragmentManager().beginTransaction() + .replace(R.id.right_pane, new AccountDetailsFragment()) + .addToBackStack(null) + .commitAllowingStateLoss(); + break; + default: + return false; + } + return true; + } + + + // input validation + + @Override + public void onPrepareOptionsMenu(Menu menu) { + boolean ok = false; + try { + ok = getListView().getCheckedItemCount() > 0; + } catch (IllegalStateException e) { + } + MenuItem item = menu.findItem(R.id.next); + item.setEnabled(ok); + } } diff --git a/app/src/main/res/layout/setup_login_email.xml b/app/src/main/res/layout/setup_login_email.xml index e6adddd8..21a5cb9d 100644 --- a/app/src/main/res/layout/setup_login_email.xml +++ b/app/src/main/res/layout/setup_login_email.xml @@ -50,7 +50,6 @@ android:id="@+id/password" android:layout_gravity="fill_horizontal" android:inputType="textPassword" - android:imeOptions="actionGo" android:layout_width="0dp" android:scrollHorizontally="true" android:scrollbars="horizontal" diff --git a/app/src/main/res/layout/setup_login_url.xml b/app/src/main/res/layout/setup_login_url.xml index 1001620c..0282df37 100644 --- a/app/src/main/res/layout/setup_login_url.xml +++ b/app/src/main/res/layout/setup_login_url.xml @@ -64,7 +64,6 @@ android:id="@+id/userName" android:layout_gravity="fill_horizontal" android:inputType="textNoSuggestions|textEmailAddress" - android:imeOptions="actionNext" android:layout_width="0dp" android:scrollHorizontally="true" android:scrollbars="horizontal" @@ -78,7 +77,6 @@ android:id="@+id/password" android:layout_gravity="fill_horizontal" android:inputType="textPassword" - android:imeOptions="actionGo" android:layout_width="0dp" android:scrollHorizontally="true" android:scrollbars="horizontal"