/* Copyright (c) 2009 Christoph Studer <chstuder@gmail.com> * Copyright (c) 2010 Jan Berkel <jan.berkel@gmail.com> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.zegoggles.smssync.activity; import android.annotation.TargetApi; import android.app.AlertDialog; import android.app.Dialog; import android.app.ProgressDialog; import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.StrictMode; import android.preference.CheckBoxPreference; import android.preference.ListPreference; import android.preference.Preference; import android.preference.Preference.OnPreferenceChangeListener; import android.preference.PreferenceActivity; import android.preference.PreferenceManager; import android.provider.Telephony; import android.text.TextUtils; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.TextView; import com.squareup.otto.Subscribe; import com.zegoggles.smssync.App; import com.zegoggles.smssync.BuildConfig; import com.zegoggles.smssync.Consts; import com.zegoggles.smssync.R; import com.zegoggles.smssync.activity.auth.AccountManagerAuthActivity; import com.zegoggles.smssync.activity.auth.OAuth2WebAuthActivity; import com.zegoggles.smssync.activity.donation.DonationActivity; import com.zegoggles.smssync.auth.OAuth2Client; import com.zegoggles.smssync.calendar.CalendarAccessor; import com.zegoggles.smssync.contacts.ContactAccessor; import com.zegoggles.smssync.mail.BackupImapStore; import com.zegoggles.smssync.mail.DataType; import com.zegoggles.smssync.preferences.AuthMode; import com.zegoggles.smssync.preferences.AuthPreferences; import com.zegoggles.smssync.preferences.BackupManagerWrapper; import com.zegoggles.smssync.preferences.Preferences; import com.zegoggles.smssync.receiver.SmsBroadcastReceiver; import com.zegoggles.smssync.service.Alarms; import com.zegoggles.smssync.service.BackupType; import com.zegoggles.smssync.service.SmsBackupService; import com.zegoggles.smssync.service.SmsRestoreService; import com.zegoggles.smssync.service.state.RestoreState; import com.zegoggles.smssync.tasks.OAuth2CallbackTask; import com.zegoggles.smssync.utils.AppLog; import com.zegoggles.smssync.utils.ListPreferenceHelper; import java.text.DateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Locale; import static com.zegoggles.smssync.App.TAG; import static com.zegoggles.smssync.mail.DataType.CALLLOG; import static com.zegoggles.smssync.mail.DataType.MMS; import static com.zegoggles.smssync.mail.DataType.SMS; import static com.zegoggles.smssync.preferences.Preferences.Keys.BACKUP_CONTACT_GROUP; import static com.zegoggles.smssync.preferences.Preferences.Keys.BACKUP_SETTINGS_SCREEN; import static com.zegoggles.smssync.preferences.Preferences.Keys.CALLLOG_SYNC_CALENDAR; import static com.zegoggles.smssync.preferences.Preferences.Keys.CALLLOG_SYNC_CALENDAR_ENABLED; import static com.zegoggles.smssync.preferences.Preferences.Keys.CONNECTED; import static com.zegoggles.smssync.preferences.Preferences.Keys.DONATE; import static com.zegoggles.smssync.preferences.Preferences.Keys.ENABLE_AUTO_BACKUP; import static com.zegoggles.smssync.preferences.Preferences.Keys.IMAP_SETTINGS; import static com.zegoggles.smssync.preferences.Preferences.Keys.INCOMING_TIMEOUT_SECONDS; import static com.zegoggles.smssync.preferences.Preferences.Keys.MAX_ITEMS_PER_RESTORE; import static com.zegoggles.smssync.preferences.Preferences.Keys.MAX_ITEMS_PER_SYNC; import static com.zegoggles.smssync.preferences.Preferences.Keys.REGULAR_TIMEOUT_SECONDS; import static com.zegoggles.smssync.preferences.Preferences.Keys.WIFI_ONLY; /** * This is the main activity showing the status of the SMS Sync service and * providing controls to configure it. */ public class MainActivity extends PreferenceActivity { public static final int MIN_VERSION_MMS = Build.VERSION_CODES.ECLAIR; public static final int MIN_VERSION_BACKUP = Build.VERSION_CODES.FROYO; private static final int REQUEST_CHANGE_DEFAULT_SMS_PACKAGE = 1; private static final int REQUEST_PICK_ACCOUNT = 2; private static final int REQUEST_WEB_AUTH = 3; enum Actions { Backup, Restore } private Actions mActions; private AuthPreferences authPreferences; private Preferences preferences; private StatusPreference statusPref; private OAuth2Client oauth2Client; @Override public void onCreate(Bundle bundle) { super.onCreate(bundle); authPreferences = new AuthPreferences(this); oauth2Client = new OAuth2Client(authPreferences.getOAuth2ClientId()); preferences = new Preferences(this); addPreferencesFromResource(R.xml.preferences); statusPref = new StatusPreference(this); statusPref.setOrder(-1); getPreferenceScreen().addPreference(statusPref); int version = Build.VERSION.SDK_INT; if (version < MIN_VERSION_MMS) { CheckBoxPreference backupMms = (CheckBoxPreference) findPreference(MMS.backupEnabledPreference); backupMms.setEnabled(false); backupMms.setChecked(false); backupMms.setSummary(R.string.ui_backup_mms_not_supported); } if (preferences.shouldShowUpgradeMessage()) show(Dialogs.UPGRADE_FROM_SMSBACKUP); setPreferenceListeners(version >= MIN_VERSION_BACKUP); checkAndDisplayDroidWarning(); preferences.migrateMarkAsRead(); if (preferences.shouldShowAboutDialog()) { show(Dialogs.ABOUT); } checkDefaultSmsApp(); setupStrictMode(); App.bus.register(this); } @Override protected void onResume() { Log.d(TAG, "onResume()"); super.onResume(); initCalendars(); initGroups(); updateLastBackupTimes(); updateAutoBackupSummary(); updateAutoBackupEnabledSummary(); updateBackupContactGroupLabelFromPref(); updateCallLogCalendarLabelFromPref(); updateImapFolderLabelFromPref(); updateImapCallogFolderLabelFromPref(); updateUsernameLabel(null); updateMaxItemsPerSync(null); updateMaxItemsPerRestore(null); updateImapSettings(!authPreferences.useXOAuth()); checkUserDonationStatus(); App.bus.register(statusPref); } @Override protected void onPause() { super.onPause(); App.bus.unregister(statusPref); } @Override protected void onDestroy() { super.onDestroy(); try { App.bus.unregister(this); } catch (Exception ignored) { } } @Override public boolean onCreateOptionsMenu(Menu menu) { android.view.MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.menu, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menu_about: show(Dialogs.ABOUT); return true; case R.id.menu_reset: show(Dialogs.RESET); return true; case R.id.menu_view_log: show(Dialogs.VIEW_LOG); default: return super.onOptionsItemSelected(item); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); Log.d(TAG, "onActivityResult(" + requestCode + "," + resultCode + "," + data + ")"); if (resultCode == RESULT_CANCELED) return; switch (requestCode) { case REQUEST_CHANGE_DEFAULT_SMS_PACKAGE: { preferences.setSeenSmsDefaultPackageChangeDialog(); if (preferences.getSmsDefaultPackage() != null) { startRestore(); } break; } case REQUEST_WEB_AUTH: { final String code = data.getStringExtra(OAuth2WebAuthActivity.EXTRA_CODE); if (!TextUtils.isEmpty(code)) { show(Dialogs.ACCESS_TOKEN); new OAuth2CallbackTask(oauth2Client).execute(code); } else { show(Dialogs.ACCESS_TOKEN_ERROR); } break; } case REQUEST_PICK_ACCOUNT: { if (AccountManagerAuthActivity.ACTION_ADD_ACCOUNT.equals(data.getAction())) { handleAccountManagerAuth(data); } else if (AccountManagerAuthActivity.ACTION_FALLBACKAUTH.equals(data.getAction())) { handleFallbackAuth(); } break; } } } @Subscribe public void restoreStateChanged(final RestoreState newState) { if (isSmsBackupDefaultSmsApp() && newState.isFinished()) { restoreDefaultSmsProvider(preferences.getSmsDefaultPackage()); } } @Subscribe public void onOAuth2Callback(OAuth2CallbackTask.OAuth2CallbackEvent event) { dismiss(Dialogs.ACCESS_TOKEN); if (event.valid()) { authPreferences.setOauth2Token(event.token.userName, event.token.accessToken, event.token.refreshToken); onAuthenticated(); } else { show(Dialogs.ACCESS_TOKEN_ERROR); } } private void onAuthenticated() { updateConnected(); // Invite use to perform a backup, but only once if (preferences.isFirstUse()) { show(Dialogs.FIRST_SYNC); } } String getLastSyncText(final long lastSync) { return getString(R.string.status_idle_details, lastSync < 0 ? getString(R.string.status_idle_details_never) : DateFormat.getDateTimeInstance().format(new Date(lastSync))); } private void updateLastBackupTimes() { for (DataType type : DataType.values()) { findPreference(type.backupEnabledPreference).setSummary( getLastSyncText(type.getMaxSyncedDate(this)) ); } } private ConnectivityManager getConnectivityManager() { return (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); } private void updateAutoBackupEnabledSummary() { findPreference(ENABLE_AUTO_BACKUP.key).setSummary(getEnabledBackupSummary()); for (DataType t : DataType.values()) { addSummaryListener(new Runnable() { public void run() { updateAutoBackupEnabledSummary(); } }, t.backupEnabledPreference); } } protected String getEnabledBackupSummary() { final List<String> enabled = new ArrayList<String>(); for (DataType dataType : DataType.enabled(this)) { enabled.add(getString(dataType.resId)); } StringBuilder summary = new StringBuilder(); if (!enabled.isEmpty()) { summary.append(getString(R.string.ui_enable_auto_sync_summary, TextUtils.join(", ", enabled))); if (!getConnectivityManager().getBackgroundDataSetting()) { summary.append(' ').append(getString(R.string.ui_enable_auto_sync_bg_data)); } if (preferences.isInstalledOnSDCard()) { summary.append(' ').append(getString(R.string.sd_card_disclaimer)); } } else { summary.append(getString(R.string.ui_enable_auto_sync_no_enabled_summary)); } return summary.toString(); } private void updateAutoBackupSummary() { final Preference autoBackup = findPreference(BACKUP_SETTINGS_SCREEN.key); final StringBuilder summary = new StringBuilder(); final ListPreference regSchedule = (ListPreference) findPreference(REGULAR_TIMEOUT_SECONDS.key); final ListPreference incomingSchedule = (ListPreference) findPreference(INCOMING_TIMEOUT_SECONDS.key); summary.append(regSchedule.getTitle()) .append(": ") .append(regSchedule.getEntry()) .append(", ") .append(incomingSchedule.getTitle()) .append(": ") .append(incomingSchedule.getEntry()); if (preferences.isWifiOnly()) { summary.append(" (") .append(findPreference(WIFI_ONLY.key).getTitle()) .append(")"); } autoBackup.setSummary(summary.toString()); addSummaryListener(new Runnable() { public void run() { updateAutoBackupSummary(); } }, INCOMING_TIMEOUT_SECONDS.key, REGULAR_TIMEOUT_SECONDS.key, WIFI_ONLY.key); } private void addSummaryListener(final Runnable r, String... prefs) { for (String p : prefs) { findPreference(p).setOnPreferenceChangeListener( new OnPreferenceChangeListener() { public boolean onPreferenceChange(Preference preference, final Object newValue) { new Handler().post(new Runnable() { @Override public void run() { r.run(); onContentChanged(); } }); return true; } }); } } private void updateUsernameLabel(String username) { if (username == null) { SharedPreferences prefs = getPreferenceManager().getSharedPreferences(); username = prefs.getString(AuthPreferences.LOGIN_USER, getString(R.string.ui_login_label)); } Preference pref = findPreference(AuthPreferences.LOGIN_USER); pref.setTitle(username); } private void updateBackupContactGroupLabelFromPref() { final ListPreference groupPref = (ListPreference) findPreference(BACKUP_CONTACT_GROUP.key); groupPref.setTitle(groupPref.getEntry() != null ? groupPref.getEntry() : getString(R.string.ui_backup_contact_group_label)); } private void updateCallLogCalendarLabelFromPref() { final ListPreference calendarPref = (ListPreference) findPreference(CALLLOG_SYNC_CALENDAR.key); calendarPref.setTitle(calendarPref.getEntry() != null ? calendarPref.getEntry() : getString(R.string.ui_backup_calllog_sync_calendar_label)); } private void updateImapFolderLabelFromPref() { String imapFolder = SMS.getFolder(this); Preference pref = findPreference(SMS.folderPreference); pref.setTitle(imapFolder); } private void updateImapCallogFolderLabelFromPref() { String imapFolder = CALLLOG.getFolder(this); Preference pref = findPreference(CALLLOG.folderPreference); pref.setTitle(imapFolder); } private void initGroups() { ContactAccessor contacts = ContactAccessor.Get.instance(); ListPreferenceHelper.initListPreference((ListPreference) findPreference(BACKUP_CONTACT_GROUP.key), contacts.getGroups(getContentResolver(), getResources()), false); } private void initCalendars() { final ListPreference calendarPref = (ListPreference) findPreference(CALLLOG_SYNC_CALENDAR.key); CalendarAccessor calendars = CalendarAccessor.Get.instance(getContentResolver()); boolean enabled = ListPreferenceHelper.initListPreference(calendarPref, calendars.getCalendars(), false); findPreference(CALLLOG_SYNC_CALENDAR_ENABLED.key).setEnabled(enabled); } private void initiateRestore() { if (checkLoginInformation()) { startRestore(); } } private void initiateBackup() { if (checkLoginInformation()) { if (preferences.isFirstBackup()) { show(Dialogs.FIRST_SYNC); } else { startBackup(false); } } } private boolean checkLoginInformation() { if (!authPreferences.isLoginInformationSet()) { show(Dialogs.MISSING_CREDENTIALS); return false; } else { return true; } } void performAction(Actions act) { performAction(act, preferences.confirmAction()); } private void performAction(Actions act, boolean needConfirm) { if (needConfirm) { this.mActions = act; show(Dialogs.CONFIRM_ACTION); } else { if (Actions.Backup.equals(act)) { initiateBackup(); } else if (Actions.Restore.equals(act)) { initiateRestore(); } } } private void startBackup(boolean skip) { final Intent intent = new Intent(this, SmsBackupService.class); if (preferences.isFirstBackup()) { intent.putExtra(Consts.KEY_SKIP_MESSAGES, skip); } intent.putExtra(BackupType.EXTRA, BackupType.MANUAL.name()); startService(intent); } @TargetApi(Build.VERSION_CODES.KITKAT) private void startRestore() { final Intent intent = new Intent(this, SmsRestoreService.class); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { if (isSmsBackupDefaultSmsApp()) { startService(intent); } else { String defaultSmsPackage = Telephony.Sms.getDefaultSmsPackage(this); Log.d(TAG, "default SMS package: " + defaultSmsPackage); preferences.setSmsDefaultPackage(defaultSmsPackage); if (preferences.hasSeenSmsDefaultPackageChangeDialog()) { requestDefaultSmsPackageChange(); } else { show(Dialogs.SMS_DEFAULT_PACKAGE_CHANGE); } } } else { startService(intent); } } @TargetApi(Build.VERSION_CODES.KITKAT) private boolean isSmsBackupDefaultSmsApp() { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && getPackageName().equals(Telephony.Sms.getDefaultSmsPackage(this)); } @Override protected void onPrepareDialog(int id, Dialog dialog) { super.onPrepareDialog(id, dialog); switch (Dialogs.values()[id]) { case VIEW_LOG: View view = dialog.findViewById(AppLog.ID); if (view instanceof TextView) { AppLog.readLog(App.LOG, (TextView) view); } } } @Override protected Dialog onCreateDialog(final int id) { String title, msg; switch (Dialogs.values()[id]) { case MISSING_CREDENTIALS: title = getString(R.string.ui_dialog_missing_credentials_title); msg = authPreferences.useXOAuth() ? getString(R.string.ui_dialog_missing_credentials_msg_xoauth) : getString(R.string.ui_dialog_missing_credentials_msg_plain); break; case INVALID_IMAP_FOLDER: title = getString(R.string.ui_dialog_invalid_imap_folder_title); msg = getString(R.string.ui_dialog_invalid_imap_folder_msg); break; case FIRST_SYNC: DialogInterface.OnClickListener firstSyncListener = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { startBackup(which == DialogInterface.BUTTON2); } }; final int maxItems = preferences.getMaxItemsPerSync(); final String syncMsg = maxItems < 0 ? getString(R.string.ui_dialog_first_sync_msg) : getString(R.string.ui_dialog_first_sync_msg_batched, maxItems); return new AlertDialog.Builder(this) .setTitle(R.string.ui_dialog_first_sync_title) .setMessage(syncMsg) .setPositiveButton(R.string.ui_sync, firstSyncListener) .setNegativeButton(R.string.ui_skip, firstSyncListener) .create(); case ABOUT: View contentView = getLayoutInflater().inflate(R.layout.about_dialog, null, false); WebView webView = (WebView) contentView.findViewById(R.id.about_content); webView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { startActivity(new Intent(Intent.ACTION_VIEW).setData(Uri.parse(url))); return true; } }); webView.loadUrl("file:///android_asset/about.html"); return new AlertDialog.Builder(this) .setCustomTitle(null) .setPositiveButton(android.R.string.ok, null) .setView(contentView) .create(); case VIEW_LOG: return AppLog.displayAsDialog(App.LOG, this); case RESET: return new AlertDialog.Builder(this) .setTitle(R.string.ui_dialog_reset_title) .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { reset(); dismissDialog(id); } }) .setMessage(R.string.ui_dialog_reset_message) .setNegativeButton(android.R.string.cancel, null) .create(); case REQUEST_TOKEN: ProgressDialog req = new ProgressDialog(this); req.setTitle(null); req.setMessage(getString(R.string.ui_dialog_request_token_msg)); req.setIndeterminate(true); req.setCancelable(false); return req; case ACCESS_TOKEN: ProgressDialog acc = new ProgressDialog(this); acc.setTitle(null); acc.setMessage(getString(R.string.ui_dialog_access_token_msg)); acc.setIndeterminate(true); acc.setCancelable(false); return acc; case ACCESS_TOKEN_ERROR: title = getString(R.string.ui_dialog_access_token_error_title); msg = getString(R.string.ui_dialog_access_token_error_msg); break; case CONNECT: return new AlertDialog.Builder(this) .setCustomTitle(null) .setMessage(getString(R.string.ui_dialog_connect_msg, getString(R.string.app_name))) .setNegativeButton(android.R.string.cancel, null) .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { startActivityForResult(new Intent(MainActivity.this, OAuth2WebAuthActivity.class) .setData(oauth2Client.requestUrl()), REQUEST_WEB_AUTH); dismissDialog(id); } }).create(); case CONNECT_TOKEN_ERROR: return new AlertDialog.Builder(this) .setCustomTitle(null) .setMessage(R.string.ui_dialog_connect_token_error) .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { } }).create(); case ACCOUNTMANAGER_TOKEN_ERROR: return new AlertDialog.Builder(this) .setCustomTitle(null) .setMessage(R.string.ui_dialog_account_manager_token_error) .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { handleFallbackAuth(); } }) .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }) .create(); case DISCONNECT: return new AlertDialog.Builder(this) .setCustomTitle(null) .setMessage(R.string.ui_dialog_disconnect_msg) .setNegativeButton(android.R.string.cancel, null) .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { authPreferences.clearOAuth1Data(); authPreferences.clearOauth2Data(); DataType.clearLastSyncData(MainActivity.this); updateConnected(); } }).create(); case UPGRADE_FROM_SMSBACKUP: title = getString(R.string.ui_dialog_upgrade_title); msg = getString(R.string.ui_dialog_upgrade_msg); break; case BROKEN_DROIDX: title = getString(R.string.ui_dialog_brokendroidx_title); msg = getString(R.string.ui_dialog_brokendroidx_msg); break; case CONFIRM_ACTION: return new AlertDialog.Builder(this) .setTitle(R.string.ui_dialog_confirm_action_title) .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { if (MainActivity.this.mActions != null) { performAction(MainActivity.this.mActions, false); } } }) .setMessage(R.string.ui_dialog_confirm_action_msg) .setNegativeButton(android.R.string.cancel, null) .create(); case SMS_DEFAULT_PACKAGE_CHANGE: return new AlertDialog.Builder(this) .setTitle(R.string.ui_dialog_sms_default_package_change_title) .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { requestDefaultSmsPackageChange(); } }) .setMessage(R.string.ui_dialog_sms_default_package_change_msg) .create(); default: return null; } return createMessageDialog(id, title, msg); } private void reset() { DataType.clearLastSyncData(MainActivity.this); preferences.reset(); } private Dialog createMessageDialog(final int id, String title, String msg) { return new AlertDialog.Builder(this) .setTitle(title) .setMessage(msg) .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.cancel(); } }) .create(); } private void updateMaxItemsPerSync(String newValue) { updateMaxItems(MAX_ITEMS_PER_SYNC.key, preferences.getMaxItemsPerSync(), newValue); } private void updateMaxItemsPerRestore(String newValue) { updateMaxItems(MAX_ITEMS_PER_RESTORE.key, preferences.getMaxItemsPerRestore(), newValue); } private void updateMaxItems(String prefKey, int currentValue, String newValue) { Preference pref = findPreference(prefKey); if (newValue == null) { newValue = String.valueOf(currentValue); } // XXX pref.setTitle("-1".equals(newValue) ? getString(R.string.all_messages) : newValue); } private CheckBoxPreference updateConnected() { CheckBoxPreference connected = (CheckBoxPreference) findPreference(CONNECTED.key); connected.setEnabled(authPreferences.useXOAuth()); connected.setChecked(authPreferences.hasOauthTokens() || authPreferences.hasOAuth2Tokens()); final String username = authPreferences.getUsername(); String summary = connected.isChecked() && !TextUtils.isEmpty(username) ? getString(R.string.gmail_already_connected, username) : getString(R.string.gmail_needs_connecting); connected.setSummary(summary); return connected; } private void show(Dialogs d) { showDialog(d.ordinal()); } private void dismiss(Dialogs d) { try { dismissDialog(d.ordinal()); } catch (IllegalArgumentException e) { // ignore } } private void updateImapSettings(boolean enabled) { findPreference(IMAP_SETTINGS.key).setEnabled(enabled); } private void setPreferenceListeners(boolean backup) { if (backup) { PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener( new SharedPreferences.OnSharedPreferenceChangeListener() { public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { BackupManagerWrapper.dataChanged(MainActivity.this); } } ); } findPreference(ENABLE_AUTO_BACKUP.key) .setOnPreferenceChangeListener(new OnPreferenceChangeListener() { public boolean onPreferenceChange(Preference preference, Object newValue) { boolean isEnabled = (Boolean) newValue; final ComponentName componentName = new ComponentName(MainActivity.this, SmsBroadcastReceiver.class); getPackageManager().setComponentEnabledSetting(componentName, isEnabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); if (!isEnabled) new Alarms(MainActivity.this).cancel(); return true; } }); findPreference(AuthPreferences.SERVER_AUTHENTICATION) .setOnPreferenceChangeListener(new OnPreferenceChangeListener() { public boolean onPreferenceChange(Preference preference, Object newValue) { final boolean plain = (AuthMode.PLAIN) == AuthMode.valueOf(newValue.toString().toUpperCase(Locale.ENGLISH)); updateConnected().setEnabled(!plain); updateImapSettings(plain); return true; } }); findPreference(MAX_ITEMS_PER_SYNC.key) .setOnPreferenceChangeListener(new OnPreferenceChangeListener() { public boolean onPreferenceChange(Preference preference, Object newValue) { updateMaxItemsPerSync(newValue.toString()); return true; } }); findPreference(MAX_ITEMS_PER_RESTORE.key) .setOnPreferenceChangeListener(new OnPreferenceChangeListener() { public boolean onPreferenceChange(Preference preference, Object newValue) { updateMaxItemsPerRestore(newValue.toString()); return true; } }); findPreference(AuthPreferences.LOGIN_USER) .setOnPreferenceChangeListener(new OnPreferenceChangeListener() { public boolean onPreferenceChange(Preference preference, Object newValue) { updateUsernameLabel(newValue.toString()); return true; } }); findPreference(AuthPreferences.LOGIN_PASSWORD) .setOnPreferenceChangeListener(new OnPreferenceChangeListener() { public boolean onPreferenceChange(Preference preference, Object newValue) { authPreferences.setImapPassword(newValue.toString()); return true; } }); updateConnected().setOnPreferenceChangeListener(new OnPreferenceChangeListener() { public boolean onPreferenceChange(Preference preference, Object change) { boolean newValue = (Boolean) change; if (newValue) { if (Build.VERSION.SDK_INT >= 5) { // use account manager on newer phones startActivityForResult(new Intent(MainActivity.this, AccountManagerAuthActivity.class), REQUEST_PICK_ACCOUNT); } else { // fall back to webview on older ones handleFallbackAuth(); } } else { show(Dialogs.DISCONNECT); } return false; } }); findPreference(SMS.folderPreference) .setOnPreferenceChangeListener(new OnPreferenceChangeListener() { public boolean onPreferenceChange(Preference preference, final Object newValue) { String imapFolder = newValue.toString(); if (BackupImapStore.isValidImapFolder(imapFolder)) { preference.setTitle(imapFolder); return true; } else { runOnUiThread(new Runnable() { @Override public void run() { show(Dialogs.INVALID_IMAP_FOLDER); } }); return false; } } }); findPreference(CALLLOG.folderPreference) .setOnPreferenceChangeListener(new OnPreferenceChangeListener() { public boolean onPreferenceChange(Preference preference, final Object newValue) { String imapFolder = newValue.toString(); if (BackupImapStore.isValidImapFolder(imapFolder)) { preference.setTitle(imapFolder); return true; } else { runOnUiThread(new Runnable() { @Override public void run() { show(Dialogs.INVALID_IMAP_FOLDER); } }); return false; } } }); } private void checkUserDonationStatus() { try { DonationActivity.checkUserHasDonated(this, new DonationActivity.DonationStatusListener() { @Override public void userDonationState(State s) { switch (s) { case NOT_AVAILABLE: case DONATED: Preference donate = getPreferenceScreen().findPreference(DONATE.key); if (donate != null) { getPreferenceScreen().removePreference(donate); } } } }); } catch (Exception e) { Log.w(TAG, e); } } @TargetApi(11) @SuppressWarnings({"ConstantConditions", "PointlessBooleanExpression"}) private void setupStrictMode() { if (BuildConfig.DEBUG && Build.VERSION.SDK_INT >= 11) { StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() // .detectDiskReads() .detectDiskWrites() .detectNetwork() .penaltyFlashScreen() .build()); } } private void checkAndDisplayDroidWarning() { if ("DROIDX".equals(Build.MODEL) || "DROID2".equals(Build.MODEL) && Build.VERSION.SDK_INT == Build.VERSION_CODES.FROYO && !getPreferences(MODE_PRIVATE).getBoolean("droidx_warning_displayed", false)) { getPreferences(MODE_PRIVATE).edit().putBoolean("droidx_warning_displayed", true).commit(); show(Dialogs.BROKEN_DROIDX); } } @TargetApi(Build.VERSION_CODES.KITKAT) private void requestDefaultSmsPackageChange() { final Intent changeIntent = new Intent(Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT) .putExtra(Telephony.Sms.Intents.EXTRA_PACKAGE_NAME, getPackageName()); startActivityForResult(changeIntent, REQUEST_CHANGE_DEFAULT_SMS_PACKAGE); } @TargetApi(Build.VERSION_CODES.KITKAT) private void restoreDefaultSmsProvider(String smsPackage) { Log.d(TAG, "restoring SMS provider "+smsPackage); if (!TextUtils.isEmpty(smsPackage)) { final Intent changeDefaultIntent = new Intent(Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT) .putExtra(Telephony.Sms.Intents.EXTRA_PACKAGE_NAME, smsPackage); startActivity(changeDefaultIntent); } } private void handleAccountManagerAuth(Intent data) { String token = data.getStringExtra(AccountManagerAuthActivity.EXTRA_TOKEN); String account = data.getStringExtra(AccountManagerAuthActivity.EXTRA_ACCOUNT); if (!TextUtils.isEmpty(token) && !TextUtils.isEmpty(account)) { authPreferences.setOauth2Token(account, token, null); onAuthenticated(); } else { String error = data.getStringExtra(AccountManagerAuthActivity.EXTRA_ERROR); if (!TextUtils.isEmpty(error)) { show(Dialogs.ACCOUNTMANAGER_TOKEN_ERROR); } } } private void handleFallbackAuth() { show(Dialogs.CONNECT); } private void checkDefaultSmsApp() { if (isSmsBackupDefaultSmsApp() && !SmsRestoreService.isServiceWorking()) { restoreDefaultSmsProvider(preferences.getSmsDefaultPackage()); } } }