/* Copyright (C) 2013-2015, Silent Circle, LLC. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Any redistribution, use, or modification is done solely for personal benefit and not for any commercial purpose or for monetary gain * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name Silent Circle nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SILENT CIRCLE, LLC BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.silentcircle.silenttext.fragment; import java.lang.ref.SoftReference; import android.annotation.TargetApi; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnCancelListener; import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.preference.CheckBoxPreference; import android.preference.Preference; import android.preference.Preference.OnPreferenceChangeListener; import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceCategory; import android.preference.PreferenceGroup; import android.preference.PreferenceScreen; import android.preference.TwoStatePreference; import android.text.InputType; import android.view.LayoutInflater; import android.view.View; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.LinearLayout; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.TextView; import android.widget.Toast; import com.silentcircle.silentstorage.repository.Repository; import com.silentcircle.silenttext.R; import com.silentcircle.silenttext.ServiceConfiguration; import com.silentcircle.silenttext.activity.LicenseActivity; import com.silentcircle.silenttext.activity.LockActivity; import com.silentcircle.silenttext.application.SilentTextApplication; import com.silentcircle.silenttext.dialog.EditTextDialog; import com.silentcircle.silenttext.dialog.EditTextDialog.Callback; import com.silentcircle.silenttext.listener.ConfirmOnClick; import com.silentcircle.silenttext.listener.DeactivateApplicationOnConfirm; import com.silentcircle.silenttext.listener.DismissDialogOnClick; import com.silentcircle.silenttext.log.Log; import com.silentcircle.silenttext.model.UserPreferences; import com.silentcircle.silenttext.preference.SilentRingtonePreference; import com.silentcircle.silenttext.receiver.LockApplicationOnReceive; import com.silentcircle.silenttext.receiver.NotificationBroadcaster; import com.silentcircle.silenttext.task.ResetPassphraseTask; import com.silentcircle.silenttext.transport.TransportQueue; import com.silentcircle.silenttext.util.AsyncUtils; import com.silentcircle.silenttext.util.DeviceUtils; import com.silentcircle.silenttext.util.InactivityTimeout; import com.silentcircle.silenttext.view.OptionsDrawer; public abstract class SettingsFragmentHelper implements OnSharedPreferenceChangeListener, OnPreferenceClickListener, OnCheckedChangeListener, OnCancelListener, DialogInterface.OnClickListener, Callback, OnPreferenceChangeListener { public static class DeactivateApplicationAndRemoveAccountPreferenceOnConfirm extends DeactivateApplicationOnConfirm { public static interface Callback { public PreferenceScreen getPreferenceScreen(); public String getUsername(); public boolean shouldRemoveUserData(); public void shouldRemoveUserData( boolean shouldRemoveUserData ); } private final Callback callback; public DeactivateApplicationAndRemoveAccountPreferenceOnConfirm( Callback callback ) { this.callback = callback; } @Override public void onConfirm( Context context ) { setRemoveUserData( callback.shouldRemoveUserData() ); super.onConfirm( context ); callback.shouldRemoveUserData( false ); toast( context, R.string.notify_account_removed ); PreferenceScreen screen = callback.getPreferenceScreen(); if( screen != null ) { PreferenceCategory accounts = (PreferenceCategory) screen.findPreference( "accounts" ); if( accounts != null ) { remove( accounts, callback.getUsername() ); if( accounts.getPreferenceCount() < 1 ) { screen.removePreference( accounts ); PreferenceGroup notificationPreferences = (PreferenceGroup) screen.findPreference( "notifications" ); remove( notificationPreferences, "should_send_read_receipts" ); } } } } } public static class DeactivateApplicationAndRemoveAccountPreferenceOnConfirmCallback implements DeactivateApplicationAndRemoveAccountPreferenceOnConfirm.Callback { private final SoftReference<SettingsFragmentHelper> settingsReference; private final String username; public DeactivateApplicationAndRemoveAccountPreferenceOnConfirmCallback( SettingsFragmentHelper settings, String username ) { settingsReference = new SoftReference<SettingsFragmentHelper>( settings ); this.username = username; } @Override public PreferenceScreen getPreferenceScreen() { SettingsFragmentHelper settings = settingsReference.get(); return settings != null ? settings.getPreferenceScreen() : null; } @Override public String getUsername() { return username; } @Override public boolean shouldRemoveUserData() { SettingsFragmentHelper settings = settingsReference.get(); return settings != null && settings.shouldRemoveUserData(); } @Override public void shouldRemoveUserData( boolean shouldRemoveUserData ) { SettingsFragmentHelper settings = settingsReference.get(); if( settings != null ) { settings.shouldRemoveUserData( shouldRemoveUserData ); } } } public static class OnPassphraseResetCallback implements ResetPassphraseAndToastTask.Callback { private final SoftReference<SettingsFragmentHelper> settingsReference; public OnPassphraseResetCallback( SettingsFragmentHelper settings ) { settingsReference = new SoftReference<SettingsFragmentHelper>( settings ); } @Override public void onAfterPassphraseReset() { SettingsFragmentHelper settings = settingsReference.get(); if( settings != null ) { settings.update(); } } @Override public void onPostExecute() { SettingsFragmentHelper settings = settingsReference.get(); if( settings != null ) { settings.setPendingPassphraseReset( false ); } } } public static class ResetPassphraseAndToastTask extends ResetPassphraseTask { public static interface Callback { public void onAfterPassphraseReset(); public void onPostExecute(); } private final Callback callback; public ResetPassphraseAndToastTask( Context context, Callback callback ) { super( context ); this.callback = callback; } @Override protected void onPassphraseReset() { Context context = getContext(); // Passcode is removed. SilentTextApplication app = SilentTextApplication.from( context ); SharedPreferences prefs = app.getSharedPreferences( LockActivity.PASS_CODE_SET, Context.MODE_PRIVATE ); SharedPreferences.Editor editor = prefs.edit(); editor.putBoolean( LockActivity.PASS_CODE_SET, false ).apply(); OptionsDrawer.setEmptyPasscode( context, true ); LockApplicationOnReceive.cancel( context ); toast( context, R.string.notify_passcode_removed ); callback.onAfterPassphraseReset(); } @Override protected void onPassphraseResetFailed() { toast( getContext(), R.string.error_incorrect_passcode ); callback.onAfterPassphraseReset(); } @Override protected void onPostExecute( Boolean success ) { callback.onPostExecute(); super.onPostExecute( success ); } } public static class SetInactivityTimeoutOnSeekBarChange implements OnSeekBarChangeListener { private final SoftReference<View> viewReference; public SetInactivityTimeoutOnSeekBarChange( View view ) { viewReference = new SoftReference<View>( view ); } @Override public void onProgressChanged( SeekBar seekBar, int progress, boolean fromUser ) { View view = viewReference.get(); if( view != null ) { ( (TextView) view.findViewById( R.id.inactivity_timeout_label ) ).setText( InactivityTimeout.Defaults.getLabel( seekBar.getContext(), progress ) ); } } @Override public void onStartTrackingTouch( SeekBar seekBar ) { // Ignore this. } @Override public void onStopTrackingTouch( SeekBar seekBar ) { OptionsDrawer.setInactivityTimeout( seekBar.getContext(), InactivityTimeout.Defaults.getDelay( seekBar.getProgress() ) ); } } private static Preference addPreferenceIfNecessary( PreferenceGroup parent, String key, int titleResourceID, int summaryResourceID, OnPreferenceClickListener onPreferenceClickListener ) { Preference preference = addPreferenceIfNecessary( parent, key, titleResourceID, onPreferenceClickListener ); if( preference != null ) { preference.setSummary( summaryResourceID ); } return preference; } private static Preference addPreferenceIfNecessary( PreferenceGroup parent, String key, int titleResourceID, OnPreferenceClickListener onPreferenceClickListener ) { Preference preference = parent.findPreference( key ); if( preference == null ) { preference = createPreference( parent.getContext(), key, titleResourceID, onPreferenceClickListener ); parent.addPreference( preference ); } return preference; } private static Preference createPreference( Context context, String key, int titleResourceID, OnPreferenceClickListener onPreferenceClickListener ) { Preference preference = new Preference( context ); preference.setKey( key ); preference.setTitle( titleResourceID ); preference.setOnPreferenceClickListener( onPreferenceClickListener ); return preference; } protected static void remove( PreferenceGroup parent, String preferenceKey ) { if( parent != null && preferenceKey != null ) { Preference preference = parent.findPreference( preferenceKey ); if( preference != null ) { parent.removePreference( preference ); } } } private static boolean runJNITest( SilentTextApplication application, Context context, String key ) { if( key == null || !key.startsWith( "test_" ) ) { return false; } AlertDialog.Builder alert = new AlertDialog.Builder( context ); alert.setTitle( "SCimp JNI Tests" ); String messageS = ""; if( "test_pki_keygen".equals( key ) ) { final String username = application.getUsername(); byte [] result = application.getKeyGenerator().generateKey( username != null ? username : "alice@silentcircle.com", application.getLocalStorageKey() ); if( result != null ) { alert.setTitle( "Generated Key Pair" ); messageS = new String( result ); } } else { int err = 0; if( "test_scimp_DHCommunication".equals( key ) ) { err = application.getSCimpBridge().testSCimpDHCommunication(); } else if( "test_scimp_DHSimultaneousCommunication".equals( key ) ) { err = application.getSCimpBridge().testSCimpDHSimultaneousCommunication(); } else if( "test_scimp_KeySerializer".equals( key ) ) { err = application.getSCimpBridge().testSCimpKeySerializer(); } else if( "test_scimp_OfflinePKCommunication".equals( key ) ) { err = application.getSCimpBridge().testSCimpOfflinePKCommunication(); } else if( "test_scimp_PKCommunication".equals( key ) ) { err = application.getSCimpBridge().testSCimpPKCommunication(); } else if( "test_scimp_PKContention".equals( key ) ) { err = application.getSCimpBridge().testSCimpPKContention(); } else if( "test_scimp_PKExpiration".equals( key ) ) { err = application.getSCimpBridge().testSCimpPKExpiration(); } else if( "test_scimp_PKSaveRestore".equals( key ) ) { err = application.getSCimpBridge().testSCimpPKSaveRestore(); } else if( "test_scimp_SimultaneousPKCommunication".equals( key ) ) { err = application.getSCimpBridge().testSCimpSimultaneousPKCommunication(); } messageS = err == 0 ? "Tests successful." : "Tests failed with error: " + err; } if( !messageS.isEmpty() ) { alert.setMessage( messageS ); alert.show(); } return true; } @TargetApi( Build.VERSION_CODES.ICE_CREAM_SANDWICH ) private static void setChecked( PreferenceGroup parent, String preferenceKey, boolean checked ) { Preference p = parent.findPreference( preferenceKey ); if( p instanceof CheckBoxPreference ) { ( (CheckBoxPreference) p ).setChecked( checked ); } else if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH ) { if( p instanceof TwoStatePreference ) { ( (TwoStatePreference) p ).setChecked( checked ); } } if( p != null ) { p.setDefaultValue( Boolean.valueOf( checked ) ); } } @TargetApi( Build.VERSION_CODES.HONEYCOMB ) private static void setIconCompat( Preference preference, int iconResourceID ) { if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ) { preference.setIcon( iconResourceID ); } } private static void setInactivityTimeout( Preference preference, int delay ) { Context context = preference.getContext(); preference.setDefaultValue( Integer.toString( delay ) ); preference.setSummary( InactivityTimeout.Defaults.getLabel( context, InactivityTimeout.Defaults.getLevel( delay ) ) ); } protected static void toast( Context context, int messageResourceID ) { Toast.makeText( context, messageResourceID, Toast.LENGTH_SHORT ).show(); } protected static void toast( Context context, String message ) { Toast.makeText( context, message, Toast.LENGTH_SHORT ).show(); } private boolean removeUserData; private boolean pendingPassphraseReset; protected abstract void addPreferencesFromResource( int xmlResourceID ); protected Context getContext() { PreferenceScreen screen = getPreferenceScreen(); return screen != null ? screen.getContext() : null; } protected abstract PreferenceScreen getPreferenceScreen(); public void onActivityResult( int requestCode, int resultCode, Intent data ) { if( data != null ) { Log.i( "SettingsFragmentHelper", "onActivityResult: " + requestCode + " : " + resultCode + " : " + data.toString() ); } } @Override public void onCancel( DialogInterface dialog ) { update( getPreferenceScreen() ); } @Override public void onCheckedChanged( CompoundButton buttonView, boolean isChecked ) { shouldRemoveUserData( !isChecked ); } @Override public void onClick( DialogInterface dialog, int which ) { update( getPreferenceScreen() ); } /** * @param savedInstanceState */ public void onCreate( Bundle savedInstanceState ) { restoreState( savedInstanceState ); addPreferencesFromResource( R.xml.preferences ); PreferenceScreen screen = getPreferenceScreen(); registerClick( screen, "clear_user_cache" ); registerClick( screen, "clear_object_cache" ); registerClick( screen, "clear_network_cache" ); registerClick( screen, "clear_packet_queue" ); registerClick( screen, "clear_key_pairs" ); registerClick( screen, "license_information" ); registerClick( screen, "privacy_statement" ); registerClick( screen, "terms_and_conditions" ); registerClick( screen, "send_feedback" ); registerClick( screen, "set_passcode" ); registerClick( screen, "change_passcode" ); registerClick( screen, "remove_passcode" ); registerClick( screen, "autolock" ); registerChange( screen, "notification_vibrate" ); registerChange( screen, "should_send_read_receipts" ); // tests registerClick( screen, "test_pki_keygen" ); registerClick( screen, "test_scimp_DHCommunication" ); registerClick( screen, "test_scimp_DHSimultaneousCommunication" ); registerClick( screen, "test_scimp_KeySerializer" ); registerClick( screen, "test_scimp_OfflinePKCommunication" ); registerClick( screen, "test_scimp_PKCommunication" ); registerClick( screen, "test_scimp_PKContention" ); registerClick( screen, "test_scimp_PKExpiration" ); registerClick( screen, "test_scimp_PKSaveRestore" ); registerClick( screen, "test_scimp_SimultaneousPKCommunication" ); } public void onDestroy() { // By default, do nothing. } public void onPause() { PreferenceScreen screen = getPreferenceScreen(); screen.getSharedPreferences().unregisterOnSharedPreferenceChangeListener( this ); SilentTextApplication.from( screen.getContext() ).sendToBackground(); } @Override public boolean onPreferenceChange( Preference preference, Object newValue ) { String key = preference.getKey(); Context context = preference.getContext(); SilentTextApplication application = SilentTextApplication.from( context ); if( "notification_vibrate".equals( key ) ) { UserPreferences preferences = application.getGlobalPreferences(); preferences.notificationVibrate = newValue != null && ( (Boolean) newValue ).booleanValue(); application.saveApplicationPreferences( preferences ); return true; } if( "should_send_read_receipts".equals( key ) ) { OptionsDrawer.setSendReceipts( context, newValue != null && ( (Boolean) newValue ).booleanValue() ); return true; } return true; } @Override public boolean onPreferenceClick( Preference preference ) { String key = preference.getKey(); Context context = preference.getContext(); SilentTextApplication application = SilentTextApplication.from( context ); if( "clear_user_cache".equals( key ) ) { application.getUsers().clear(); toast( context, "User cache cleared." ); return true; } if( "clear_packet_queue".equals( key ) ) { TransportQueue queue = application.getOutgoingMessageQueue(); if( queue instanceof Repository ) { ( (Repository<?>) queue ).clear(); toast( context, "Packet queue cleared." ); return true; } } if( "clear_object_cache".equals( key ) ) { application.getAttachments().clear(); toast( context, "Object cache cleared." ); return true; } if( "clear_network_cache".equals( key ) ) { application.getServiceEndpointRepository().clear(); toast( context, "Network cache cleared." ); return true; } if( "clear_key_pairs".equals( key ) ) { application.revokeAllKeyPairs(); toast( context, "Revoking all published public keys and clearing their corresponding private keys from local storage." ); return true; } if( "license_information".equals( key ) ) { context.startActivity( new Intent( context, LicenseActivity.class ) ); return true; } if( "privacy_statement".equals( key ) ) { context.startActivity( new Intent( Intent.ACTION_VIEW, Uri.parse( context.getResources().getString( R.string.sc_privacy_link ) ) ) ); return true; } if( "terms_and_conditions".equals( key ) ) { context.startActivity( new Intent( Intent.ACTION_VIEW, Uri.parse( context.getResources().getString( R.string.sc_tos_link ) ) ) ); return true; } if( "autolock".equals( key ) ) { AlertDialog.Builder alert = new AlertDialog.Builder( context ); final View view = LayoutInflater.from( context ).inflate( R.layout.inactivity_timeout, null ); SeekBar seeker = (SeekBar) view.findViewById( R.id.inactivity_timeout_seeker ); seeker.setProgress( InactivityTimeout.Defaults.getLevel( OptionsDrawer.getInactivityTimeout( context ) ) ); ( (TextView) view.findViewById( R.id.inactivity_timeout_label ) ).setText( InactivityTimeout.Defaults.getLabel( context, seeker.getProgress() ) ); seeker.setOnSeekBarChangeListener( new SetInactivityTimeoutOnSeekBarChange( view ) ); alert.setTitle( preference.getTitle() ); alert.setView( view ); alert.setOnCancelListener( this ); alert.setPositiveButton( android.R.string.ok, this ); alert.show(); return true; } if( "set_passcode".equals( key ) ) { context.startActivity( new Intent( context, LockActivity.class ) ); return true; } if( "change_passcode".equals( key ) ) { context.startActivity( new Intent( context, LockActivity.class ) ); return true; } if( "remove_passcode".equals( key ) ) { EditTextDialog.show( context, R.id.remove_passcode, R.string.current_passcode, "", "", InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD, this ); return true; } final String username = application.getUsername(); if( username != null && username.equals( key ) ) { AlertDialog.Builder alert = new AlertDialog.Builder( context ); LinearLayout layout = (LinearLayout) LayoutInflater.from( context ).inflate( R.layout.dialog_with_checkbox, null ); ( (TextView) layout.findViewById( R.id.message ) ).setText( context.getString( R.string.confirm_account_removal, username ) ); ( (CheckBox) layout.findViewById( R.id.checkbox ) ).setOnCheckedChangeListener( this ); ( (CheckBox) layout.findViewById( R.id.checkbox ) ).setChecked( !shouldRemoveUserData() ); alert.setTitle( R.string.are_you_sure ); alert.setView( layout ); alert.setNegativeButton( R.string.cancel, new DismissDialogOnClick() ); alert.setPositiveButton( R.string.remove, new ConfirmOnClick( new DeactivateApplicationAndRemoveAccountPreferenceOnConfirm( new DeactivateApplicationAndRemoveAccountPreferenceOnConfirmCallback( this, username ) ) ) ); alert.show(); return true; } if( "send_feedback".equals( key ) ) { DeviceUtils.shareDebugInformation( context ); return true; } if( key != null && key.startsWith( "test_" ) ) { runJNITest( application, context, key ); return true; } return false; } public void onResume() { PreferenceScreen screen = getPreferenceScreen(); update( screen ); screen.getSharedPreferences().registerOnSharedPreferenceChangeListener( this ); SilentTextApplication.from( screen.getContext() ).sendToForeground(); } @Override public void onSharedPreferenceChanged( SharedPreferences preferences, String key ) { update( getPreferenceScreen() ); } @Override public void onValue( int dialogID, CharSequence value ) { if( R.id.remove_passcode == dialogID ) { pendingPassphraseReset = true; update(); AsyncUtils.execute( new ResetPassphraseAndToastTask( getContext(), new OnPassphraseResetCallback( this ) ), value, "" ); return; } } private void registerChange( PreferenceScreen screen, String preferenceKey ) { Preference preference = screen.findPreference( preferenceKey ); if( preference != null ) { preference.setOnPreferenceChangeListener( this ); } } private void registerClick( PreferenceScreen screen, String preferenceKey ) { screen.findPreference( preferenceKey ).setOnPreferenceClickListener( this ); } public void restoreState( Bundle savedInstanceState ) { if( savedInstanceState != null ) { removeUserData = savedInstanceState.getBoolean( "removeUserData" ); pendingPassphraseReset = savedInstanceState.getBoolean( "pendingPassphraseReset" ); } } public void saveState( Bundle outState ) { outState.putBoolean( "removeUserData", removeUserData ); outState.putBoolean( "pendingPassphraseReset", pendingPassphraseReset ); } public void setPendingPassphraseReset( boolean pendingPassphraseReset ) { this.pendingPassphraseReset = pendingPassphraseReset; } protected boolean shouldRemoveUserData() { return removeUserData; } protected void shouldRemoveUserData( boolean removeUserData ) { this.removeUserData = removeUserData; } protected void update() { update( getPreferenceScreen() ); } private void update( PreferenceScreen screen ) { ServiceConfiguration.getInstance().update( screen ); Context context = screen.getContext(); SilentTextApplication application = SilentTextApplication.from( context ); if( application.isUserKeyUnlocked() ) { PreferenceCategory accounts = (PreferenceCategory) screen.findPreference( "accounts" ); if( accounts != null ) { accounts.removeAll(); Preference account = new Preference( context ); String username = application.getUsername(); account.setKey( username ); account.setDefaultValue( username ); account.setTitle( username ); account.setSummary( R.string.tap_to_remove ); setIconCompat( account, R.drawable.ic_action_delete ); account.setPersistent( false ); account.setOnPreferenceClickListener( this ); accounts.addPreference( account ); } } else { remove( screen, "accounts" ); } PreferenceGroup passcodePreferences = (PreferenceGroup) screen.findPreference( "passcode" ); if( !OptionsDrawer.isEmptyPasscode( screen.getContext() ) ) { remove( passcodePreferences, "set_passcode" ); addPreferenceIfNecessary( passcodePreferences, "autolock", R.string.autolock, this ).setEnabled( !pendingPassphraseReset ); addPreferenceIfNecessary( passcodePreferences, "change_passcode", R.string.change_passcode, this ).setEnabled( !pendingPassphraseReset ); addPreferenceIfNecessary( passcodePreferences, "remove_passcode", R.string.remove_passcode, R.string.remove_passcode_description, this ).setEnabled( !pendingPassphraseReset ); setInactivityTimeout( passcodePreferences.findPreference( "autolock" ), OptionsDrawer.getInactivityTimeout( context ) ); } else { addPreferenceIfNecessary( passcodePreferences, "set_passcode", R.string.set_passcode, R.string.set_passcode_description, this ); remove( passcodePreferences, "autolock" ); remove( passcodePreferences, "change_passcode" ); remove( passcodePreferences, "remove_passcode" ); } if( !ServiceConfiguration.getInstance().debug ) { remove( screen, "developer_options" ); } PreferenceGroup notificationPreferences = (PreferenceGroup) screen.findPreference( "notifications" ); if( application.getUserPreferences() == null ) { remove( notificationPreferences, "should_send_read_receipts" ); } setChecked( screen, "should_send_read_receipts", OptionsDrawer.isSendReceiptsEnabled( context ) ); setChecked( screen, "notification_vibrate", NotificationBroadcaster.isVibrateEnabled( context ) ); ( (SilentRingtonePreference) screen.findPreference( "notification_ringtone" ) ).updateSummary(); PreferenceGroup debugInformation = (PreferenceGroup) screen.findPreference( "debug_information" ); DeviceUtils.putDebugInformation( debugInformation ); } }