/*
* Copyright (c) 2015 Jonas Kalderstam.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nononsenseapps.notepad.ui.settings;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerCallback;
import android.accounts.AccountManagerFuture;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceFragment;
import android.preference.PreferenceManager;
import android.support.v7.app.AlertDialog;
import android.widget.Toast;
import com.nononsenseapps.build.Config;
import com.nononsenseapps.notepad.ui.orgmodedropbox.DropboxFilePickerActivity;
import com.nononsenseapps.filepicker.FilePickerActivity;
import com.nononsenseapps.notepad.util.Log;
import com.nononsenseapps.notepad.BuildConfig;
import com.nononsenseapps.notepad.R;
import com.nononsenseapps.notepad.data.local.sql.MyContentProvider;
import com.nononsenseapps.notepad.data.remote.gtasks.GoogleTasksClient;
import com.nononsenseapps.notepad.data.remote.orgmodedropbox.DropboxSyncHelper;
import com.nononsenseapps.notepad.data.remote.orgmodedropbox.DropboxSynchronizer;
import com.nononsenseapps.notepad.data.service.OrgSyncService;
import com.nononsenseapps.notepad.data.local.orgmode.SDSynchronizer;
import java.io.File;
import java.io.IOException;
// import com.nononsenseapps.notepad.NotePad;
public class SyncPrefs extends PreferenceFragment implements
OnSharedPreferenceChangeListener {
public static final String KEY_SYNC_ENABLE = "syncEnablePref";
public static final String KEY_ACCOUNT = "accountPref";
// public static final String KEY_SYNC_FREQ = "syncFreq";
public static final String KEY_FULLSYNC = "syncFull";
public static final String KEY_SYNC_ON_START = "syncOnStart";
public static final String KEY_SYNC_ON_CHANGE = "syncOnChange";
public static final String KEY_BACKGROUND_SYNC = "syncInBackground";
// Used for sync on start and on change
public static final String KEY_LAST_SYNC = "lastSync";
// SD sync
public static final String KEY_SD_ENABLE = "pref_sync_sd_enabled";
public static final String KEY_SD_DIR = "pref_sync_sd_dir";
// Dropbox sync
public static final String KEY_DROPBOX_ENABLE = "pref_sync_dropbox_enabled";
public static final String KEY_DROPBOX_DIR = "pref_sync_dropbox_dir";
private static final int PICK_SD_DIR_CODE = 1;
private static final int PICK_DROPBOX_DIR_CODE = 2;
private Activity activity;
private Preference prefAccount;
private Preference prefSdDir;
private Preference prefDropboxDir;
private DropboxSyncHelper mDropboxHelper = null;
// private Preference prefSyncFreq;
/**
* Finds and returns the account of the name given
*
* @param accountName
* @return
*/
public static Account getAccount(AccountManager manager, String accountName) {
Account[] accounts = manager.getAccountsByType("com.google");
for (Account account : accounts) {
if (account.name.equals(accountName)) {
return account;
}
}
return null;
}
public static void setSyncInterval(Context activity,
SharedPreferences sharedPreferences) {
String accountName = sharedPreferences.getString(KEY_ACCOUNT, "");
boolean backgroundSync = sharedPreferences.getBoolean(
KEY_BACKGROUND_SYNC, false);
if (accountName != null && !accountName.isEmpty()) {
Account account = getAccount(AccountManager.get(activity), accountName);
if (account != null) {
if (!backgroundSync) {
// Disable periodic syncing
ContentResolver.removePeriodicSync(
account,
MyContentProvider.AUTHORITY, new Bundle());
} else {
// Convert from minutes to seconds
long pollFrequency = 3600;
// Set periodic syncing
ContentResolver.addPeriodicSync(
account,
MyContentProvider.AUTHORITY, new Bundle(),
pollFrequency);
}
}
}
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
this.activity = activity;
}
@Override
public void onResume() {
super.onResume();
if (mDropboxHelper != null) {
if (mDropboxHelper.handleLinkResult()) {
// Success
} else {
// Link failed or was cancelled by the user.
PreferenceManager.getDefaultSharedPreferences(getActivity()).edit().putBoolean
(KEY_DROPBOX_ENABLE, false).commit();
}
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.app_pref_sync);
prefAccount = findPreference(KEY_ACCOUNT);
// prefSyncFreq = findPreference(KEY_SYNC_FREQ);
final SharedPreferences sharedPrefs = PreferenceManager
.getDefaultSharedPreferences(activity);
// Set up a listener whenever a key changes
sharedPrefs.registerOnSharedPreferenceChangeListener(this);
// Set summaries
setAccountTitle(sharedPrefs);
prefAccount
.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) {
// Show dialog
showAccountDialog();
return true;
}
});
// Disable prefs if this is not correct build
findPreference(KEY_SYNC_ENABLE).setEnabled(
null != Config.getGtasksApiKey(getActivity()) &&
!Config.getGtasksApiKey(getActivity()).contains(" "));
// SD Card
prefSdDir = findPreference(KEY_SD_DIR);
setSdDirSummary(sharedPrefs);
prefSdDir.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(final Preference preference) {
// Start the filepicker
Intent i = new Intent(getActivity(), FilePickerActivity.class);
i.putExtra(FilePickerActivity.EXTRA_START_PATH,
sharedPrefs.getString(KEY_SD_DIR,
SDSynchronizer.DEFAULT_ORG_DIR)
)
.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false)
.putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, true)
.putExtra(FilePickerActivity.EXTRA_MODE,
FilePickerActivity.MODE_DIR);
startActivityForResult(i, PICK_SD_DIR_CODE);
return true;
}
});
if (BuildConfig.DROPBOX_ENABLED && BuildConfig.NONFREE) {
// Dropbox, disable if no key present
findPreference(KEY_DROPBOX_ENABLE)
.setEnabled(BuildConfig.DROPBOX_ENABLED &&
Config.getKeyDropboxAPI(getActivity()) !=
null &&
!Config.getKeyDropboxAPISecret(getActivity())
.contains(" "));
prefDropboxDir = findPreference(KEY_DROPBOX_DIR);
prefDropboxDir.setEnabled(BuildConfig.DROPBOX_ENABLED);
setDropboxDirSummary(sharedPrefs);
prefDropboxDir.setOnPreferenceClickListener(
new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(
final Preference preference) {
// See if initial sync is complete
if (mDropboxHelper == null) {
mDropboxHelper = new DropboxSyncHelper(getActivity());
}
if (mDropboxHelper.isLinked()) {
// Start the filepicker
Intent i = new Intent(getActivity(),
DropboxFilePickerActivity.class);
i.putExtra(FilePickerActivity.EXTRA_START_PATH,
sharedPrefs.getString(KEY_DROPBOX_DIR,
DropboxSynchronizer.DEFAULT_DIR));
i.putExtra(
FilePickerActivity.EXTRA_ALLOW_MULTIPLE,
false).putExtra(
FilePickerActivity.EXTRA_ALLOW_CREATE_DIR,
true)
.putExtra(FilePickerActivity.EXTRA_MODE,
FilePickerActivity.MODE_DIR);
i.addFlags(
Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivityForResult(i,
PICK_DROPBOX_DIR_CODE);
}
return true;
}
});
}
}
@Override
public void onDestroy() {
super.onDestroy();
PreferenceManager.getDefaultSharedPreferences(activity)
.unregisterOnSharedPreferenceChangeListener(this);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == PICK_DROPBOX_DIR_CODE) {
if (resultCode == Activity.RESULT_OK) {
PreferenceManager.getDefaultSharedPreferences(getActivity()).edit().putString
(KEY_DROPBOX_DIR, data.getData().getPath()).commit();
} // else was cancelled
} else if (requestCode == PICK_SD_DIR_CODE) {
if (resultCode == Activity.RESULT_OK) {
// Set it
File path = new File(data.getData().getPath());
if (path.exists() && path.isDirectory() && path.canWrite()) {
PreferenceManager.getDefaultSharedPreferences(getActivity()).edit().putString
(KEY_SD_DIR, path.toString()).commit();
} else {
Toast.makeText(getActivity(), R.string.cannot_write_to_directory, Toast
.LENGTH_SHORT).show();
}
} // else was cancelled
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
private void showAccountDialog() {
FragmentTransaction ft = getFragmentManager().beginTransaction();
Fragment prev = getFragmentManager().findFragmentByTag("accountdialog");
if (prev != null) {
ft.remove(prev);
}
ft.addToBackStack(null);
// Create and show the dialog.
// Bundle args = new Bundle();
// args.putString(KEY_ACCOUNT, newPassword);
DialogFragment newFragment = new AccountDialog();
// newFragment.setArguments(args);
newFragment.show(ft, "accountdialog");
}
public void onSharedPreferenceChanged(SharedPreferences prefs,
String key) {
try {
Log.d("syncPrefs", "onChanged");
if (activity.isFinishing()) {
// Setting the summary now would crash it with
// IllegalStateException since we are not attached to a view
} else {
if (KEY_SYNC_ENABLE.equals(key)) {
toggleSync(prefs);
} else if (KEY_BACKGROUND_SYNC.equals(key)) {
setSyncInterval(activity, prefs);
} else if (KEY_ACCOUNT.equals(key)) {
Log.d("syncPrefs", "account");
prefAccount.setTitle(prefs.getString(
KEY_ACCOUNT, ""));
} else if (KEY_SD_ENABLE.equals(key)) {
// Restart the sync service
OrgSyncService.stop(getActivity());
} else if (KEY_SD_DIR.equals(key)) {
setSdDirSummary(prefs);
} else if (KEY_DROPBOX_ENABLE.equals(key)) {
// TODO
if (mDropboxHelper == null) {
mDropboxHelper = new DropboxSyncHelper(getActivity());
}
if (prefs.getBoolean(key, false)) {
// authorize the user
mDropboxHelper.linkAccount();
// DropboxSynchronizer.linkAccount(this,
// DROPBOX_LINK_CODE);
} else {
mDropboxHelper.unlinkAccount();
// DropboxSynchronizer.unlink(getActivity());
}
// Restart sync service
OrgSyncService.stop(getActivity());
} else if (KEY_DROPBOX_DIR.equals(key)) {
setDropboxDirSummary(prefs);
}
}
} catch (IllegalStateException e) {
// This is just in case the "isFinishing" wouldn't be enough
// The isFinishing will try to prevent us from doing something
// stupid
// This catch prevents the app from crashing if we do something
// stupid
}
}
private void toggleSync(SharedPreferences sharedPreferences) {
boolean enabled = sharedPreferences.getBoolean(KEY_SYNC_ENABLE, false);
String accountName = sharedPreferences.getString(KEY_ACCOUNT, "");
if (accountName != null && !accountName.isEmpty()) {
Account account = getAccount(AccountManager.get(activity), accountName);
if (account != null) {
if (enabled) {
// set syncable
ContentResolver.setSyncAutomatically(
account,
MyContentProvider.AUTHORITY, true);
ContentResolver.setIsSyncable(
account,
MyContentProvider.AUTHORITY, 1);
// Also set sync frequency
setSyncInterval(activity, sharedPreferences);
} else {
// set unsyncable
// ContentResolver.setIsSyncable(
// getAccount(AccountManager.get(activity), accountName),
// MyContentProvider.AUTHORITY, 0);
}
}
} else if (enabled) {
showAccountDialog();
}
}
private void setAccountTitle(final SharedPreferences sharedPreferences) {
prefAccount.setTitle(sharedPreferences.getString(KEY_ACCOUNT, ""));
prefAccount.setSummary(R.string.settings_account_summary);
}
private void setSdDirSummary(final SharedPreferences sharedPreferences) {
prefSdDir.setSummary(sharedPreferences.getString(KEY_SD_DIR,
SDSynchronizer.DEFAULT_ORG_DIR));
}
private void setDropboxDirSummary(final SharedPreferences
sharedPreferences) {
prefDropboxDir.setSummary(sharedPreferences.getString(KEY_DROPBOX_DIR,
DropboxSynchronizer.DEFAULT_DIR));
}
public static class AccountDialog extends DialogFragment implements
AccountManagerCallback<Bundle> {
private Activity activity;
private Account account;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
this.activity = activity;
}
@Override
public Dialog onCreateDialog(Bundle args) {
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle(R.string.select_account);
final Account[] accounts = AccountManager.get(activity)
.getAccountsByType("com.google");
final int size = accounts.length;
String[] names = new String[size];
for (int i = 0; i < size; i++) {
names[i] = accounts[i].name;
}
// TODO
// Could add a clear alternative here
builder.setItems(names, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// Stuff to do when the account is selected by the user
accountSelected(accounts[which]);
}
});
return builder.create();
}
/**
* Called from the activity, since that one builds the dialog
*
* @param account
*/
public void accountSelected(final Account account) {
if (account != null) {
Log.d("prefsActivity", "step one");
this.account = account;
// Request user's permission
GoogleTasksClient.getAuthTokenAsync(activity, account, this);
// work continues in callback, method run()
}
}
/**
* User wants to select an account to sync with. If we get an approval,
* activate sync and set periodicity also.
*/
@SuppressLint("CommitPrefEdits")
@Override
public void run(AccountManagerFuture<Bundle> future) {
try {
Log.d("prefsActivity", "step two");
// If the user has authorized
// your application to use the
// tasks API
// a token is available.
String token = future.getResult().getString(
AccountManager.KEY_AUTHTOKEN);
// Now we are authorized by the user.
Log.d("prefsActivity", "step two-b: " + token);
if (token != null && !token.isEmpty() && account != null) {
Log.d("prefsActivity", "step three: " + account.name);
SharedPreferences customSharedPreference = PreferenceManager
.getDefaultSharedPreferences(activity);
customSharedPreference.edit()
.putString(SyncPrefs.KEY_ACCOUNT, account.name)
.putBoolean(KEY_SYNC_ENABLE, true).commit();
// Set it syncable
ContentResolver.setSyncAutomatically(account,
MyContentProvider.AUTHORITY, true);
ContentResolver.setIsSyncable(account,
MyContentProvider.AUTHORITY, 1);
// Set sync frequency
SyncPrefs.setSyncInterval(activity, customSharedPreference);
}
} catch (OperationCanceledException e) {
// if the request was canceled for any reason
} catch (AuthenticatorException e) {
// if there was an error communicating with the authenticator or
// if the authenticator returned an invalid response
} catch (IOException e) {
// if the authenticator returned an error response that
// indicates that it encountered an IOException while
// communicating with the authentication server
}
}
}
}