/* * This source is part of the * _____ ___ ____ * __ / / _ \/ _ | / __/___ _______ _ * / // / , _/ __ |/ _/_/ _ \/ __/ _ `/ * \___/_/|_/_/ |_/_/ (_)___/_/ \_, / * /___/ * repository. * * Copyright (C) 2013 Benoit 'BoD' Lubek (BoD@JRAF.org) * Copyright (C) 2013-2017 Carmen Alvarez (c@rmen.ca) * * 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 ca.rmen.android.networkmonitor.app.prefs; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.location.LocationManager; import android.media.RingtoneManager; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.provider.Settings; import android.support.v4.app.TaskStackBuilder; import android.support.v7.app.AppCompatActivity; import android.support.v7.preference.EditTextPreference; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceManager; import android.text.TextUtils; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; import ca.rmen.android.networkmonitor.Constants; import ca.rmen.android.networkmonitor.R; import ca.rmen.android.networkmonitor.app.Theme; import ca.rmen.android.networkmonitor.app.bus.NetMonBus; import ca.rmen.android.networkmonitor.app.dbops.backend.DBOpIntentService; import ca.rmen.android.networkmonitor.app.dialog.ConfirmDialogFragment; import ca.rmen.android.networkmonitor.app.dialog.DialogFragmentFactory; import ca.rmen.android.networkmonitor.app.email.EmailPreferences; import ca.rmen.android.networkmonitor.app.prefs.NetMonPreferences.LocationFetchingStrategy; import ca.rmen.android.networkmonitor.app.service.NetMonNotification; import ca.rmen.android.networkmonitor.util.Log; public class AdvancedPreferencesActivity extends AppCompatActivity implements ConfirmDialogFragment.DialogButtonListener { private static final String TAG = Constants.TAG + AdvancedPreferencesActivity.class.getSimpleName(); private static final int ACTIVITY_REQUEST_CODE_IMPORT_DB = 1; private static final int ACTIVITY_REQUEST_CODE_RINGTONE = 2; private static final int ACTIVITY_REQUEST_CODE_IMPORT_SETTINGS = 3; private static final String EXTRA_IMPORT_URI = AdvancedPreferencesActivity.class.getPackage().getName() + "_db_url"; private static final int ID_ACTION_IMPORT_DB = 3; private static final int ID_ACTION_LOCATION_SETTINGS = 4; private static final int ID_ACTION_COMPRESS = 5; private static final int ID_ACTION_IMPORT_SETTINGS = 6; private static final String PREF_COMPRESS = "PREF_COMPRESS"; private static final String PREF_IMPORT_DB = "PREF_IMPORT_DB"; private static final String PREF_EXPORT_SETTINGS = "PREF_EXPORT_SETTINGS"; private static final String PREF_IMPORT_SETTINGS = "PREF_IMPORT_SETTINGS"; private NetMonPreferenceFragmentCompat mPreferenceFragment; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getSupportActionBar() != null) getSupportActionBar().setDisplayHomeAsUpEnabled(true); SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); // The first time the user sees the notification preferences, we'll set the ringtone preference // to the default notification ringtone. if (!sharedPrefs.contains(NetMonPreferences.PREF_NOTIFICATION_RINGTONE)) NetMonPreferences.getInstance(this).setDefaultNotificationSoundUri(); PreferenceManager.setDefaultValues(this, R.xml.adv_preferences, false); loadPreferences(); } private void loadPreferences() { mPreferenceFragment = NetMonPreferenceFragmentCompat.newInstance(R.xml.adv_preferences); getSupportFragmentManager(). beginTransaction(). replace(android.R.id.content, mPreferenceFragment). commit(); getSupportFragmentManager().executePendingTransactions(); updatePreferenceSummary(NetMonPreferences.PREF_TEST_SERVER, R.string.pref_summary_test_server); updatePreferenceSummary(NetMonPreferences.PREF_NOTIFICATION_RINGTONE, R.string.pref_summary_notification_ringtone); Preference enableConnectionTest = mPreferenceFragment.findPreference(NetMonPreferences.PREF_ENABLE_CONNECTION_TEST); NetMonPreferences prefs = NetMonPreferences.getInstance(this); if (prefs.isFastPollingEnabled()) enableConnectionTest.setEnabled(false); setOnPreferenceChangeListeners(NetMonPreferences.PREF_TEST_SERVER); setOnPreferenceClickListeners(PREF_IMPORT_DB, PREF_COMPRESS, NetMonPreferences.PREF_NOTIFICATION_RINGTONE, PREF_IMPORT_SETTINGS, PREF_EXPORT_SETTINGS); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) { Preference emailPreference = mPreferenceFragment.findPreference(EmailPreferences.PREF_EMAIL_REPORTS); emailPreference.setVisible(false); Preference themePreference = mPreferenceFragment.findPreference(NetMonPreferences.PREF_THEME); themePreference.setVisible(false); } if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { Preference notificationPriorityPreference = mPreferenceFragment.findPreference(NetMonPreferences.PREF_NOTIFICATION_PRIORITY); notificationPriorityPreference.setVisible(false); } } private void setOnPreferenceClickListeners(String... keys) { for (String key : keys) { Preference preference = mPreferenceFragment.findPreference(key); preference.setOnPreferenceClickListener(mOnPreferenceClickListener); } } private void setOnPreferenceChangeListeners(String... keys) { for (String key : keys) { Preference preference = mPreferenceFragment.findPreference(key); preference.setOnPreferenceChangeListener(mOnPreferenceChangeListener); } } @Override protected void onStart() { super.onStart(); PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(mOnSharedPreferenceChangeListener); NetMonBus.getBus().register(this); } @Override protected void onStop() { PreferenceManager.getDefaultSharedPreferences(this).unregisterOnSharedPreferenceChangeListener(mOnSharedPreferenceChangeListener); NetMonBus.getBus().unregister(this); super.onStop(); } private final OnSharedPreferenceChangeListener mOnSharedPreferenceChangeListener = (sharedPreferences, key) -> { final NetMonPreferences prefs = NetMonPreferences.getInstance(AdvancedPreferencesActivity.this); Log.v(TAG, "onSharedPreferenceChanged: key = " + key); if (NetMonPreferences.PREF_TEST_SERVER.equals(key)) { updatePreferenceSummary(key, R.string.pref_summary_test_server); } else if (NetMonPreferences.PREF_NOTIFICATION_RINGTONE.equals(key)) { updatePreferenceSummary(key, R.string.pref_summary_notification_ringtone); } else if (NetMonPreferences.PREF_LOCATION_FETCHING_STRATEGY.equals(key)) { if (prefs.getLocationFetchingStrategy() == LocationFetchingStrategy.HIGH_ACCURACY || prefs.getLocationFetchingStrategy() == LocationFetchingStrategy.HIGH_ACCURACY_GMS) { checkLocationSettings(); } } else if (NetMonPreferences.PREF_NOTIFICATION_ENABLED.equals(key)) { if (!prefs.getShowNotificationOnTestFailure()) NetMonNotification.dismissFailedTestNotification(AdvancedPreferencesActivity.this); } else if (NetMonPreferences.PREF_DB_RECORD_COUNT.equals(key)) { int rowsToKeep = NetMonPreferences.getInstance(AdvancedPreferencesActivity.this).getDBRecordCount(); if (rowsToKeep > 0) DBOpIntentService.startActionPurge(AdvancedPreferencesActivity.this, rowsToKeep); } else if (NetMonPreferences.PREF_THEME.equals(key)) { // When the theme changes, restart the activity Theme.setThemeFromSettings(getApplicationContext()); Intent intent = new Intent(AdvancedPreferencesActivity.this, AdvancedPreferencesActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); TaskStackBuilder stackBuilder = TaskStackBuilder.create(AdvancedPreferencesActivity.this); stackBuilder.addNextIntentWithParentStack(intent); stackBuilder.startActivities(); } }; private void updatePreferenceSummary(final String key, final int summaryResId) { final Preference pref = mPreferenceFragment.findPreference(key); // I don't see how this is possible, but a crash was reported for a null pref... if (pref == null) { Log.v(TAG, "updatePreferenceSummary: No preference found for " + key); return; } if (pref instanceof EditTextPreference) { pref.setSummary(getString(summaryResId, ((EditTextPreference) pref).getText())); } else if (pref.getKey().equals(NetMonPreferences.PREF_NOTIFICATION_RINGTONE)) { new RingtonePreferenceSummaryUpdater().execute(pref); } } private static String getFileOpenIntentAction() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) return Intent.ACTION_OPEN_DOCUMENT; return Intent.ACTION_GET_CONTENT; } private final Preference.OnPreferenceClickListener mOnPreferenceClickListener = preference -> { Log.v(TAG, "onPreferenceClick: " + preference); if (PREF_IMPORT_DB.equals(preference.getKey())) { Intent importIntent = new Intent(getFileOpenIntentAction()); importIntent.setType("*/*"); importIntent.addCategory(Intent.CATEGORY_OPENABLE); startActivityForResult(Intent.createChooser(importIntent, getResources().getText(R.string.pref_summary_import)), ACTIVITY_REQUEST_CODE_IMPORT_DB); } else if (PREF_COMPRESS.equals(preference.getKey())) { DialogFragmentFactory.showConfirmDialog(AdvancedPreferencesActivity.this, getString(R.string.compress_confirm_title), getString(R.string.compress_confirm_message), ID_ACTION_COMPRESS, null); } else if (NetMonPreferences.PREF_NOTIFICATION_RINGTONE.equals(preference.getKey())) { Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER); intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, NetMonPreferences.getInstance(getApplicationContext()).getNotificationSoundUri()); intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true); intent.putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI, RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)); intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, true); intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_NOTIFICATION); intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TITLE, getString(R.string.pref_title_notification_ringtone)); startActivityForResult(intent, ACTIVITY_REQUEST_CODE_RINGTONE); } else if (PREF_IMPORT_SETTINGS.equals(preference.getKey())) { Intent importIntent = new Intent(getFileOpenIntentAction()); importIntent.setType("*/*"); importIntent.addCategory(Intent.CATEGORY_OPENABLE); startActivityForResult(Intent.createChooser(importIntent, getResources().getText(R.string.pref_title_import_settings)), ACTIVITY_REQUEST_CODE_IMPORT_SETTINGS); } else if (PREF_EXPORT_SETTINGS.equals(preference.getKey())) { SettingsExportImport.exportSettings(AdvancedPreferencesActivity.this); } return false; }; private final Preference.OnPreferenceChangeListener mOnPreferenceChangeListener = (preference, newValue) -> { // Ignore the value if it is empty. if (NetMonPreferences.PREF_TEST_SERVER.equals(preference.getKey())) { String newValueStr = (String) newValue; return !TextUtils.isEmpty(newValueStr); } return true; }; @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); Log.v(TAG, "onActivityResult: requestCode = " + requestCode + ", resultCode = " + resultCode + ", data=" + data); /** * Allow the user to choose a DB to import */ if (requestCode == ACTIVITY_REQUEST_CODE_IMPORT_DB) { if (resultCode == Activity.RESULT_OK) { // Get the file the user selected, and show a dialog asking for confirmation to import the file. Uri importFile = data.getData(); Bundle extras = new Bundle(1); extras.putParcelable(EXTRA_IMPORT_URI, importFile); DialogFragmentFactory.showConfirmDialog(this, getString(R.string.import_confirm_title), getString(R.string.import_confirm_message, importFile.getPath()), ID_ACTION_IMPORT_DB, extras); } } else if (requestCode == ACTIVITY_REQUEST_CODE_RINGTONE) { if (resultCode == Activity.RESULT_OK) { Uri uri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI); NetMonPreferences.getInstance(this).setNotificationSoundUri(uri); updatePreferenceSummary(NetMonPreferences.PREF_NOTIFICATION_RINGTONE, R.string.pref_summary_notification_ringtone); } } else if (requestCode == ACTIVITY_REQUEST_CODE_IMPORT_SETTINGS) { if (resultCode == Activity.RESULT_OK) { Uri importFile = data.getData(); Bundle extras = new Bundle(1); extras.putParcelable(EXTRA_IMPORT_URI, importFile); DialogFragmentFactory.showConfirmDialog(this, getString(R.string.import_confirm_title), getString(R.string.import_settings_confirm_message, importFile.getPath()), ID_ACTION_IMPORT_SETTINGS, extras); } } } @Override public void onOkClicked(int actionId, Bundle extras) { // Import the database in a background thread. if (actionId == ID_ACTION_IMPORT_DB) { final Uri uri = extras.getParcelable(EXTRA_IMPORT_URI); DBOpIntentService.startActionImport(this, uri); } // Compress the database in a background thread else if (actionId == ID_ACTION_COMPRESS) { DBOpIntentService.startActionCompress(this); } else if (actionId == ID_ACTION_LOCATION_SETTINGS) { Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); startActivity(intent); } else if (actionId == ID_ACTION_IMPORT_SETTINGS) { final Uri uri = extras.getParcelable(EXTRA_IMPORT_URI); SettingsExportImport.importSettings(this, uri, this::loadPreferences); } } @Override public void onCancelClicked(int actionId, Bundle extras) { Log.v(TAG, "onCancelClicked, actionId=" + actionId + ", extras = " + extras); } @SuppressWarnings("unused") @Subscribe(sticky = true, threadMode = ThreadMode.MAIN) public void onDBOperationStarted(NetMonBus.DBOperationStarted event) { Log.d(TAG, "onDBOperationStarted() called with " + "event = [" + event + "]"); mPreferenceFragment.findPreference(PREF_IMPORT_DB).setEnabled(false); mPreferenceFragment.findPreference(PREF_COMPRESS).setEnabled(false); mPreferenceFragment.findPreference(NetMonPreferences.PREF_DB_RECORD_COUNT).setEnabled(false); } @SuppressWarnings("unused") @Subscribe public void onDBOperationEnded(NetMonBus.DBOperationEnded event) { Log.d(TAG, "onDBOperationEnded() called with " + "event = [" + event + "]"); mPreferenceFragment.findPreference(PREF_IMPORT_DB).setEnabled(true); mPreferenceFragment.findPreference(PREF_COMPRESS).setEnabled(true); mPreferenceFragment.findPreference(NetMonPreferences.PREF_DB_RECORD_COUNT).setEnabled(true); } /** * Checks if we have either the GPS or Network location provider enabled. If not, shows a popup dialog telling the user they should go to the system * settings to enable location tracking. */ private void checkLocationSettings() { // If the user chose high accuracy, make sure we have at least one location provider. LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); if (!(locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER))) { DialogFragmentFactory.showConfirmDialog(this, getString(R.string.no_location_confirm_dialog_title), getString(R.string.no_location_confirm_dialog_message), ID_ACTION_LOCATION_SETTINGS, null); } } }