davdrod学习记录
1.Preference的使用
<?xml version="1.0" encoding="utf-8"?><!-- ~ Copyright (c) 2013 – 2015 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 --><PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <PreferenceCategory android:title="@string/settings_authentication"> <EditTextPreference android:key="username" android:title="@string/settings_username" android:persistent="false" android:dialogTitle="@string/settings_enter_username" /> <EditTextPreference android:key="password" android:title="@string/settings_password" android:persistent="false" android:inputType="textPassword" android:summary="@string/settings_password_summary" android:dialogTitle="@string/settings_enter_password" /> </PreferenceCategory> <PreferenceCategory android:title="@string/settings_sync"> <ListPreference android:key="sync_interval_contacts" android:persistent="false" android:title="@string/settings_sync_interval_contacts" android:entries="@array/settings_sync_interval_names" android:entryValues="@array/settings_sync_interval_seconds" /> <ListPreference android:key="sync_interval_calendars" android:persistent="false" android:title="@string/settings_sync_interval_calendars" android:entries="@array/settings_sync_interval_names" android:entryValues="@array/settings_sync_interval_seconds" /> <ListPreference android:key="sync_interval_tasks" android:persistent="false" android:title="@string/settings_sync_interval_tasks" android:entries="@array/settings_sync_interval_names" android:entryValues="@array/settings_sync_interval_seconds" /> <SwitchPreferenceCompat android:key="sync_wifi_only" android:persistent="false" android:title="@string/settings_sync_wifi_only" android:summaryOn="@string/settings_sync_wifi_only_on" android:summaryOff="@string/settings_sync_wifi_only_off" /> <EditTextPreference android:key="sync_wifi_only_ssid" android:dependency="sync_wifi_only" android:persistent="false" android:title="@string/settings_sync_wifi_only_ssid" android:dialogMessage="@string/settings_sync_wifi_only_ssid_message"/> </PreferenceCategory> <PreferenceCategory android:title="@string/settings_carddav"> <ListPreference android:key="contact_group_method" android:persistent="false" android:title="@string/settings_contact_group_method" android:entries="@array/settings_contact_group_method_entries" android:entryValues="@array/settings_contact_group_method_values"/> <SwitchPreferenceCompat android:key="vcard_rfc6868" android:persistent="false" android:title="@string/settings_rfc6868_for_vcards" android:summaryOn="@string/settings_rfc6868_for_vcards_on" android:summaryOff="@string/settings_rfc6868_for_vcards_off"/> </PreferenceCategory> <PreferenceCategory android:title="@string/settings_caldav"> <EditTextPreference android:key="time_range_past_days" android:persistent="false" android:title="@string/settings_sync_time_range_past" android:dialogMessage="@string/settings_sync_time_range_past_message" android:inputType="number"/> <SwitchPreferenceCompat android:key="manage_calendar_colors" android:persistent="false" android:title="@string/settings_manage_calendar_colors" android:summaryOn="@string/settings_manage_calendar_colors_on" android:summaryOff="@string/settings_manage_calendar_colors_off"/> </PreferenceCategory></PreferenceScreen>
public class AccountSettingsActivity extends AppCompatActivity { public final static String EXTRA_ACCOUNT = "account"; private Account account; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); account = getIntent().getParcelableExtra(EXTRA_ACCOUNT); setTitle(getString(R.string.settings_title, account.name)); getSupportActionBar().setDisplayHomeAsUpEnabled(true); if (savedInstanceState == null) getSupportFragmentManager().beginTransaction() .replace(android.R.id.content, AccountSettingsFragment.instantiate(this, AccountSettingsFragment.class.getName(), getIntent().getExtras())) .commit(); } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == android.R.id.home) { Intent intent = new Intent(this, AccountActivity.class); intent.putExtra(AccountActivity.EXTRA_ACCOUNT, account); NavUtils.navigateUpTo(this, intent); return true; } else return false; } public static class AccountSettingsFragment extends PreferenceFragmentCompat { Account account; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); account = getArguments().getParcelable(EXTRA_ACCOUNT); refresh(); } @Override public void onCreatePreferences(Bundle bundle, String s) { addPreferencesFromResource(R.xml.settings_account); } public void refresh() { final AccountSettings settings; try { settings = new AccountSettings(getActivity(), account); } catch(InvalidAccountException e) { App.log.log(Level.INFO, "Account is invalid or doesn't exist (anymore)", e); getActivity().finish(); return; } // category: authentication final EditTextPreference prefUserName = (EditTextPreference)findPreference("username"); prefUserName.setSummary(settings.username()); prefUserName.setText(settings.username()); prefUserName.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(Preference preference, Object newValue) { settings.username((String)newValue); refresh(); return false; } }); final EditTextPreference prefPassword = (EditTextPreference)findPreference("password"); prefPassword.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(Preference preference, Object newValue) { settings.password((String)newValue); refresh(); return false; } }); // category: synchronization final ListPreference prefSyncContacts = (ListPreference)findPreference("sync_interval_contacts"); final Long syncIntervalContacts = settings.getSyncInterval(ContactsContract.AUTHORITY); if (syncIntervalContacts != null) { prefSyncContacts.setValue(syncIntervalContacts.toString()); if (syncIntervalContacts == AccountSettings.SYNC_INTERVAL_MANUALLY) prefSyncContacts.setSummary(R.string.settings_sync_summary_manually); else prefSyncContacts.setSummary(getString(R.string.settings_sync_summary_periodically, syncIntervalContacts / 60)); prefSyncContacts.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(Preference preference, Object newValue) { settings.setSyncInterval(ContactsContract.AUTHORITY, Long.parseLong((String)newValue)); refresh(); return false; } }); } else { prefSyncContacts.setEnabled(false); prefSyncContacts.setSummary(R.string.settings_sync_summary_not_available); } final ListPreference prefSyncCalendars = (ListPreference)findPreference("sync_interval_calendars"); final Long syncIntervalCalendars = settings.getSyncInterval(CalendarContract.AUTHORITY); if (syncIntervalCalendars != null) { prefSyncCalendars.setValue(syncIntervalCalendars.toString()); if (syncIntervalCalendars == AccountSettings.SYNC_INTERVAL_MANUALLY) prefSyncCalendars.setSummary(R.string.settings_sync_summary_manually); else prefSyncCalendars.setSummary(getString(R.string.settings_sync_summary_periodically, syncIntervalCalendars / 60)); prefSyncCalendars.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(Preference preference, Object newValue) { settings.setSyncInterval(CalendarContract.AUTHORITY, Long.parseLong((String)newValue)); refresh(); return false; } }); } else { prefSyncCalendars.setEnabled(false); prefSyncCalendars.setSummary(R.string.settings_sync_summary_not_available); } final ListPreference prefSyncTasks = (ListPreference)findPreference("sync_interval_tasks"); final Long syncIntervalTasks = settings.getSyncInterval(TaskProvider.ProviderName.OpenTasks.authority); if (syncIntervalTasks != null) { prefSyncTasks.setValue(syncIntervalTasks.toString()); if (syncIntervalTasks == AccountSettings.SYNC_INTERVAL_MANUALLY) prefSyncTasks.setSummary(R.string.settings_sync_summary_manually); else prefSyncTasks.setSummary(getString(R.string.settings_sync_summary_periodically, syncIntervalTasks / 60)); prefSyncTasks.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(Preference preference, Object newValue) { settings.setSyncInterval(TaskProvider.ProviderName.OpenTasks.authority, Long.parseLong((String)newValue)); refresh(); return false; } }); } else { prefSyncTasks.setEnabled(false); prefSyncTasks.setSummary(R.string.settings_sync_summary_not_available); } final SwitchPreferenceCompat prefWifiOnly = (SwitchPreferenceCompat)findPreference("sync_wifi_only"); prefWifiOnly.setChecked(settings.getSyncWifiOnly()); prefWifiOnly.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(Preference preference, Object wifiOnly) { settings.setSyncWiFiOnly((Boolean)wifiOnly); refresh(); return false; } }); final EditTextPreference prefWifiOnlySSID = (EditTextPreference)findPreference("sync_wifi_only_ssid"); final String onlySSID = settings.getSyncWifiOnlySSID(); prefWifiOnlySSID.setText(onlySSID); if (onlySSID != null) prefWifiOnlySSID.setSummary(getString(R.string.settings_sync_wifi_only_ssid_on, onlySSID)); else prefWifiOnlySSID.setSummary(R.string.settings_sync_wifi_only_ssid_off); prefWifiOnlySSID.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(Preference preference, Object newValue) { String ssid = (String)newValue; settings.setSyncWifiOnlySSID(!TextUtils.isEmpty(ssid) ? ssid : null); refresh(); return false; } }); // category: CardDAV final SwitchPreferenceCompat prefRFC6868 = (SwitchPreferenceCompat)findPreference("vcard_rfc6868"); if (syncIntervalContacts != null) { prefRFC6868.setChecked(settings.getVCardRFC6868()); prefRFC6868.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(Preference preference, Object o) { settings.setVCardRFC6868((Boolean)o); refresh(); return false; } }); } else prefRFC6868.setEnabled(false); final ListPreference prefGroupMethod = (ListPreference)findPreference("contact_group_method"); if (syncIntervalContacts != null) { prefGroupMethod.setValue(settings.getGroupMethod().name()); prefGroupMethod.setSummary(prefGroupMethod.getEntry()); prefGroupMethod.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(Preference preference, Object o) { String name = (String)o; settings.setGroupMethod(GroupMethod.valueOf(name)); refresh(); return false; } }); } else prefGroupMethod.setEnabled(false); // category: CalDAV final EditTextPreference prefTimeRangePastDays = (EditTextPreference)findPreference("time_range_past_days"); if (syncIntervalCalendars != null) { Integer pastDays = settings.getTimeRangePastDays(); if (pastDays != null) { prefTimeRangePastDays.setText(pastDays.toString()); prefTimeRangePastDays.setSummary(getResources().getQuantityString(R.plurals.settings_sync_time_range_past_days, pastDays, pastDays)); } else { prefTimeRangePastDays.setText(null); prefTimeRangePastDays.setSummary(R.string.settings_sync_time_range_past_none); } prefTimeRangePastDays.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(Preference preference, Object newValue) { int days; try { days = Integer.parseInt((String)newValue); } catch(NumberFormatException ignored) { days = -1; } settings.setTimeRangePastDays(days < 0 ? null : days); refresh(); return false; } }); } else prefTimeRangePastDays.setEnabled(false); final SwitchPreferenceCompat prefManageColors = (SwitchPreferenceCompat)findPreference("manage_calendar_colors"); if (syncIntervalCalendars != null || syncIntervalTasks != null) { prefManageColors.setChecked(settings.getManageCalendarColors()); prefManageColors.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(Preference preference, Object newValue) { settings.setManageCalendarColors((Boolean)newValue); refresh(); return false; } }); } else prefManageColors.setEnabled(false); } }}
2.DilogFragment
public class StartupDialogFragment extends DialogFragment { public static final String HINT_BATTERY_OPTIMIZATIONS = "hint_BatteryOptimizations", HINT_GOOGLE_PLAY_ACCOUNTS_REMOVED = "hint_GooglePlayAccountsRemoved", HINT_OPENTASKS_NOT_INSTALLED = "hint_OpenTasksNotInstalled"; private static final String ARGS_MODE = "mode"; enum Mode { BATTERY_OPTIMIZATIONS, DEVELOPMENT_VERSION, FDROID_DONATE, GOOGLE_PLAY_ACCOUNTS_REMOVED, OPENTASKS_NOT_INSTALLED } public static StartupDialogFragment[] getStartupDialogs(Context context) { List<StartupDialogFragment> dialogs = new LinkedList<>(); @Cleanup ServiceDB.OpenHelper dbHelper = new ServiceDB.OpenHelper(context); Settings settings = new Settings(dbHelper.getReadableDatabase()); if (BuildConfig.VERSION_NAME.contains("-alpha") || BuildConfig.VERSION_NAME.contains("-beta") || BuildConfig.VERSION_NAME.contains("-rc")) dialogs.add(StartupDialogFragment.instantiate(Mode.DEVELOPMENT_VERSION)); else dialogs.add(StartupDialogFragment.instantiate(Mode.FDROID_DONATE)); // battery optimization whitelisting if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && settings.getBoolean(HINT_BATTERY_OPTIMIZATIONS, true)) { PowerManager powerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); if (!powerManager.isIgnoringBatteryOptimizations(BuildConfig.APPLICATION_ID)) dialogs.add(StartupDialogFragment.instantiate(Mode.BATTERY_OPTIMIZATIONS)); } // OpenTasks information if (!LocalTaskList.tasksProviderAvailable(context) && settings.getBoolean(HINT_OPENTASKS_NOT_INSTALLED, true)) dialogs.add(StartupDialogFragment.instantiate(Mode.OPENTASKS_NOT_INSTALLED)); Collections.reverse(dialogs); return dialogs.toArray(new StartupDialogFragment[dialogs.size()]); } public static StartupDialogFragment instantiate(Mode mode) { StartupDialogFragment frag = new StartupDialogFragment(); Bundle args = new Bundle(1); args.putString(ARGS_MODE, mode.name()); frag.setArguments(args); return frag; } @NonNull @Override @TargetApi(Build.VERSION_CODES.M) @SuppressLint("BatteryLife") public Dialog onCreateDialog(Bundle savedInstanceState) { setCancelable(false); final ServiceDB.OpenHelper dbHelper = new ServiceDB.OpenHelper(getContext()); Mode mode = Mode.valueOf(getArguments().getString(ARGS_MODE)); switch (mode) { case BATTERY_OPTIMIZATIONS: return new AlertDialog.Builder(getActivity()) .setTitle(R.string.startup_battery_optimization) .setMessage(R.string.startup_battery_optimization_message) .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }) .setNeutralButton(R.string.startup_battery_optimization_disable, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Intent intent = new Intent(android.provider.Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, Uri.parse("package:" + BuildConfig.APPLICATION_ID)); getContext().startActivity(intent); } }) .setNegativeButton(R.string.startup_dont_show_again, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Settings settings = new Settings(dbHelper.getWritableDatabase()); settings.putBoolean(HINT_BATTERY_OPTIMIZATIONS, false); } }) .create(); case DEVELOPMENT_VERSION: return new AlertDialog.Builder(getActivity()) .setIcon(R.mipmap.ic_launcher) .setTitle(R.string.startup_development_version) .setMessage(R.string.startup_development_version_message) .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }) .setNeutralButton(R.string.startup_development_version_give_feedback, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { startActivity(new Intent(Intent.ACTION_VIEW, Constants.webUri.buildUpon().appendEncodedPath("forums/").build())); } }) .create(); case FDROID_DONATE: return new AlertDialog.Builder(getActivity()) .setIcon(R.mipmap.ic_launcher) .setTitle(R.string.startup_donate) .setMessage(R.string.startup_donate_message) .setPositiveButton(R.string.startup_donate_now, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { startActivity(new Intent(Intent.ACTION_VIEW, Constants.webUri.buildUpon().appendEncodedPath("donate/").build())); } }) .setNegativeButton(R.string.startup_donate_later, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }) .create(); case OPENTASKS_NOT_INSTALLED: StringBuilder builder = new StringBuilder(getString(R.string.startup_opentasks_not_installed_message)); if (Build.VERSION.SDK_INT < 23) builder.append("\n\n").append(getString(R.string.startup_opentasks_reinstall_davdroid)); return new AlertDialog.Builder(getActivity()) .setIcon(R.drawable.ic_alarm_on_dark) .setTitle(R.string.startup_opentasks_not_installed) .setMessage(builder.toString()) .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }) .setNeutralButton(R.string.startup_opentasks_not_installed_install, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=org.dmfs.tasks")); if (intent.resolveActivity(getContext().getPackageManager()) != null) getContext().startActivity(intent); else App.log.warning("No market app available, can't install OpenTasks"); } }) .setNegativeButton(R.string.startup_dont_show_again, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Settings settings = new Settings(dbHelper.getWritableDatabase()); settings.putBoolean(HINT_OPENTASKS_NOT_INSTALLED, false); } }) .create(); } throw new IllegalArgumentException(/* illegal mode argument */); } private static String installedFrom(Context context) { try { return context.getPackageManager().getInstallerPackageName(context.getPackageName()); } catch(IllegalArgumentException e) { return null; } }}
4.静态ListFragment
/* * 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.accounts.AccountManager;import android.accounts.OnAccountsUpdateListener;import android.annotation.SuppressLint;import android.content.Context;import android.content.Intent;import android.os.Bundle;import android.support.v4.app.ListFragment;import android.support.v4.app.LoaderManager;import android.support.v4.content.AsyncTaskLoader;import android.support.v4.content.Loader;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.AbsListView;import android.widget.AdapterView;import android.widget.ArrayAdapter;import android.widget.ListView;import android.widget.TextView;import at.bitfire.davdroid.AccountsChangedReceiver;import at.bitfire.davdroid.Constants;import at.bitfire.davdroid.R;public class AccountListFragment extends ListFragment implements LoaderManager.LoaderCallbacks<Account[]>, AdapterView.OnItemClickListener { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { setListAdapter(new AccountListAdapter(getContext())); return inflater.inflate(R.layout.account_list, container, false); } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); getLoaderManager().initLoader(0, getArguments(), this); ListView list = getListView(); list.setOnItemClickListener(this); list.setChoiceMode(AbsListView.CHOICE_MODE_SINGLE); } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Account account = (Account)getListAdapter().getItem(position); Intent intent = new Intent(getContext(), AccountActivity.class); intent.putExtra(AccountActivity.EXTRA_ACCOUNT, account); startActivity(intent); } // loader @Override public Loader<Account[]> onCreateLoader(int id, Bundle args) { return new AccountLoader(getContext()); } @Override public void onLoadFinished(Loader<Account[]> loader, Account[] accounts) { AccountListAdapter adapter = (AccountListAdapter)getListAdapter(); adapter.clear(); adapter.addAll(accounts); } @Override public void onLoaderReset(Loader<Account[]> loader) { ((AccountListAdapter)getListAdapter()).clear(); } private static class AccountLoader extends AsyncTaskLoader<Account[]> implements OnAccountsUpdateListener { private final AccountManager accountManager; public AccountLoader(Context context) { super(context); accountManager = AccountManager.get(context); } @Override protected void onStartLoading() { AccountsChangedReceiver.registerListener(this, true); } @Override protected void onStopLoading() { AccountsChangedReceiver.unregisterListener(this); } @Override public void onAccountsUpdated(Account[] accounts) { forceLoad(); } @Override @SuppressLint("MissingPermission") public Account[] loadInBackground() { return accountManager.getAccountsByType(Constants.ACCOUNT_TYPE); } } // list adapter static class AccountListAdapter extends ArrayAdapter<Account> { public AccountListAdapter(Context context) { super(context, R.layout.account_list_item); } @Override public View getView(int position, View v, ViewGroup parent) { if (v == null) v = LayoutInflater.from(getContext()).inflate(R.layout.account_list_item, parent, false); Account account = getItem(position); TextView tv = (TextView)v.findViewById(R.id.account_name); tv.setText(account.name); return v; } }}
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="at.bitfire.davdroid.ui.AccountsActivity"> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <android.support.v7.widget.Toolbar app:theme="@style/ThemeOverlay.AppCompat.ActionBar" android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary"/> </android.support.design.widget.AppBarLayout> <fragment class="at.bitfire.davdroid.ui.AccountListFragment" android:id="@+id/account_list" android:layout_width="match_parent" android:layout_height="match_parent" tools:layout="@layout/account_list" app:layout_scrollFlags="scroll" app:layout_behavior="@string/appbar_scrolling_view_behavior"/> <android.support.design.widget.FloatingActionButton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|end" android:layout_margin="@dimen/fab_margin" android:src="@drawable/ic_add_light"/></android.support.design.widget.CoordinatorLayout>
5 android:empty android:list
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <ListView android:id="@id/android:list" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="8dp" android:divider="@android:color/transparent" android:background="@android:color/transparent" android:cacheColorHint="@android:color/transparent"/> <TextView android:id="@id/android:empty" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="16dp" android:gravity="center" android:textAppearance="@style/TextAppearance.AppCompat.Large" android:text="@string/account_list_empty" /></LinearLayout>
6.Scrollview切换
/*
* 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.setup;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import org.apache.commons.lang3.StringUtils;
import java.net.IDN;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.logging.Level;
import at.bitfire.dav4android.Constants;
import at.bitfire.davdroid.R;
import at.bitfire.davdroid.ui.widget.EditPassword;
public class LoginCredentialsFragment extends Fragment implements CompoundButton.OnCheckedChangeListener {
RadioButton radioUseEmail;
LinearLayout emailDetails;
EditText editEmailAddress;
EditPassword editEmailPassword;
RadioButton radioUseURL;
LinearLayout urlDetails;
EditText editBaseURL, editUserName;
EditPassword editUrlPassword;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.login_credentials_fragment, container, false);
radioUseEmail = (RadioButton)v.findViewById(R.id.login_type_email);
emailDetails = (LinearLayout)v.findViewById(R.id.login_type_email_details);
editEmailAddress = (EditText)v.findViewById(R.id.email_address);
editEmailPassword = (EditPassword)v.findViewById(R.id.email_password);
radioUseURL = (RadioButton)v.findViewById(R.id.login_type_url);
urlDetails = (LinearLayout)v.findViewById(R.id.login_type_url_details);
editBaseURL = (EditText)v.findViewById(R.id.base_url);
editUserName = (EditText)v.findViewById(R.id.user_name);
editUrlPassword = (EditPassword)v.findViewById(R.id.url_password);
radioUseEmail.setOnCheckedChangeListener(this);
radioUseURL.setOnCheckedChangeListener(this);
if (savedInstanceState == null) {
// first call
Activity activity = getActivity();
Intent intent = (activity != null) ? activity.getIntent() : null;
if (intent != null) {
// we've got initial login data
String url = intent.getStringExtra(LoginActivity.EXTRA_URL),
username = intent.getStringExtra(LoginActivity.EXTRA_USERNAME),
password = intent.getStringExtra(LoginActivity.EXTRA_PASSWORD);
if (url != null) {
radioUseURL.setChecked(true);
editBaseURL.setText(url);
editUserName.setText(username);
editUrlPassword.setText(password);
} else {
radioUseEmail.setChecked(true);
editEmailAddress.setText(username);
editEmailPassword.setText(password);
}
} else
radioUseEmail.setChecked(true);
}
final Button login = (Button)v.findViewById(R.id.login);
login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
LoginCredentials credentials = validateLoginData();
if (credentials != null)
DetectConfigurationFragment.newInstance(credentials).show(getFragmentManager(), null);
}
});
return v;
}
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
boolean loginByEmail = buttonView == radioUseEmail;
emailDetails.setVisibility(loginByEmail ? View.VISIBLE : View.GONE);
urlDetails.setVisibility(loginByEmail ? View.GONE : View.VISIBLE);
(loginByEmail ? editEmailAddress : editBaseURL).requestFocus();
}
}
protected LoginCredentials validateLoginData() {
if (radioUseEmail.isChecked()) {
URI uri = null;
boolean valid = true;
String email = editEmailAddress.getText().toString();
if (!email.matches(".+@.+")) {
editEmailAddress.setError(getString(R.string.login_email_address_error));
valid = false;
} else
try {
uri = new URI("mailto", email, null);
} catch (URISyntaxException e) {
editEmailAddress.setError(e.getLocalizedMessage());
valid = false;
}
String password = editEmailPassword.getText().toString();
if (password.isEmpty()) {
editEmailPassword.setError(getString(R.string.login_password_required));
valid = false;
}
return valid ? new LoginCredentials(uri, email, password) : null;
} else if (radioUseURL.isChecked()) {
URI uri = null;
boolean valid = true;
Uri baseUrl = Uri.parse(editBaseURL.getText().toString());
String scheme = baseUrl.getScheme();
if ("https".equalsIgnoreCase(scheme) || "http".equalsIgnoreCase(scheme)) {
String host = baseUrl.getHost();
if (StringUtils.isEmpty(host)) {
editBaseURL.setError(getString(R.string.login_url_host_name_required));
valid = false;
} else
try {
host = IDN.toASCII(host);
} catch(IllegalArgumentException e) {
Constants.log.log(Level.WARNING, "Host name not conforming to RFC 3490", e);
}
String path = baseUrl.getEncodedPath();
int port = baseUrl.getPort();
try {
uri = new URI(baseUrl.getScheme(), null, host, port, path, null, null);
} catch (URISyntaxException e) {
editBaseURL.setError(e.getLocalizedMessage());
valid = false;
}
} else {
editBaseURL.setError(getString(R.string.login_url_must_be_http_or_https));
valid = false;
}
String userName = editUserName.getText().toString();
if (userName.isEmpty()) {
editUserName.setError(getString(R.string.login_user_name_required));
valid = false;
}
String password = editUrlPassword.getText().toString();
if (password.isEmpty()) {
editUrlPassword.setError(getString(R.string.login_password_required));
valid = false;
}
return valid ? new LoginCredentials(uri, userName, password) : null;
}
return null;
}
}
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- We don't want the keyboard up when the user arrives in this initial screen -->
<View android:layout_height="0dp"
android:layout_width="0dp"
android:focusable="true"
android:focusableInTouchMode="true"
android:contentDescription="@null"
android:importantForAccessibility="no" tools:ignore="UnusedAttribute">
<requestFocus/>
</View>
<ScrollView android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_margin="@dimen/activity_margin">
<RadioGroup
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:animateLayoutChanges="true">
<RadioButton
android:id="@+id/login_type_email"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/login_type_email"
android:paddingLeft="14dp" tools:ignore="RtlSymmetry"
style="@style/login_type_headline"/>
<LinearLayout
android:id="@+id/login_type_email_details"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<EditText
android:id="@+id/email_address"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/login_email_address"
android:inputType="textEmailAddress"/>
<at.bitfire.davdroid.ui.widget.EditPassword
android:id="@+id/email_password"
android:hint="@string/login_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
<RadioButton
android:id="@+id/login_type_url"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/login_type_url"
android:layout_marginTop="16dp"
android:paddingLeft="14dp" tools:ignore="RtlSymmetry"
style="@style/login_type_headline"/>
<LinearLayout
android:id="@+id/login_type_url_details"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<EditText
android:id="@+id/base_url"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/login_base_url"
android:inputType="textUri"/>
<EditText
android:id="@+id/user_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/login_user_name"
android:inputType="textEmailAddress"/>
<at.bitfire.davdroid.ui.widget.EditPassword
android:id="@+id/url_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/login_password"/>
</LinearLayout>
</RadioGroup>
</ScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/stepper_nav_bar">
<Space
android:layout_width="0dp"
android:layout_weight="1"
style="@style/stepper_nav_button"/>
<Button
android:id="@+id/login"
android:layout_width="0dp"
android:layout_weight="1"
android:text="@string/login_login"
style="@style/stepper_nav_button"/>
</LinearLayout>
</LinearLayout>
5 ListView
public class MaximizedListView extends ListView { public MaximizedListView(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int widthMode = MeasureSpec.getMode(widthMeasureSpec), widthSize = MeasureSpec.getSize(widthMeasureSpec), heightMode = MeasureSpec.getMode(heightMeasureSpec), heightSize = MeasureSpec.getSize(heightMeasureSpec); int width = 0, height = 0; if (widthMode == MeasureSpec.EXACTLY || widthMode == MeasureSpec.AT_MOST) width = widthSize; if (heightMode == MeasureSpec.EXACTLY) height = heightSize; else { ListAdapter listAdapter = getAdapter(); if (listAdapter != null) { int widthSpec = View.MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY); for (int i = 0; i < listAdapter.getCount(); i++) { View listItem = listAdapter.getView(i, null, this); listItem.measure(widthSpec, View.MeasureSpec.UNSPECIFIED); height += listItem.getMeasuredHeight(); } height += getDividerHeight() * (listAdapter.getCount() - 1); } } setMeasuredDimension(width, height); }}
网友评论