/* * Copyright (C) 2011 Whisper Systems * Copyright (C) 2013-2017 Open Whisper Systems * * 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 . */ package org.thoughtcrime.securesms; import android.annotation.TargetApi; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Build.VERSION; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; import android.support.v4.content.ContextCompat; import android.support.v4.graphics.drawable.DrawableCompat; import android.support.v7.app.AlertDialog; import android.support.v7.preference.Preference; import android.util.Log; import android.widget.Toast; import org.thoughtcrime.securesms.crypto.IdentityKeyUtil; import org.thoughtcrime.securesms.loki.LinkedDevicesActivity; import org.thoughtcrime.securesms.loki.QRCodeDialog; import org.thoughtcrime.securesms.preferences.AppProtectionPreferenceFragment; import org.thoughtcrime.securesms.preferences.ChatsPreferenceFragment; import org.thoughtcrime.securesms.preferences.CorrectedPreferenceFragment; import org.thoughtcrime.securesms.preferences.NotificationsPreferenceFragment; import org.thoughtcrime.securesms.preferences.widgets.ProfilePreference; import org.thoughtcrime.securesms.service.KeyCachingService; import org.thoughtcrime.securesms.util.DynamicLanguage; import org.thoughtcrime.securesms.util.DynamicTheme; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.whispersystems.signalservice.loki.crypto.MnemonicCodec; import org.whispersystems.signalservice.loki.utilities.Analytics; import org.whispersystems.signalservice.loki.utilities.SerializationKt; import java.io.File; import network.loki.messenger.R; /** * The Activity for application preference display and management. * * @author Moxie Marlinspike * */ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarActivity implements SharedPreferences.OnSharedPreferenceChangeListener { @SuppressWarnings("unused") private static final String TAG = ApplicationPreferencesActivity.class.getSimpleName(); private static final String PREFERENCE_CATEGORY_PROFILE = "preference_category_profile"; // private static final String PREFERENCE_CATEGORY_SMS_MMS = "preference_category_sms_mms"; private static final String PREFERENCE_CATEGORY_NOTIFICATIONS = "preference_category_notifications"; private static final String PREFERENCE_CATEGORY_APP_PROTECTION = "preference_category_app_protection"; // private static final String PREFERENCE_CATEGORY_APPEARANCE = "preference_category_appearance"; private static final String PREFERENCE_CATEGORY_CHATS = "preference_category_chats"; // private static final String PREFERENCE_CATEGORY_DEVICES = "preference_category_devices"; // private static final String PREFERENCE_CATEGORY_ADVANCED = "preference_category_advanced"; private static final String PREFERENCE_CATEGORY_PUBLIC_KEY = "preference_category_public_key"; private static final String PREFERENCE_CATEGORY_QR_CODE = "preference_category_qr_code"; private static final String PREFERENCE_CATEGORY_LINKED_DEVICES = "preference_category_linked_devices"; private static final String PREFERENCE_CATEGORY_SEED = "preference_category_seed"; private final DynamicTheme dynamicTheme = new DynamicTheme(); private final DynamicLanguage dynamicLanguage = new DynamicLanguage(); @Override protected void onPreCreate() { dynamicTheme.onCreate(this); dynamicLanguage.onCreate(this); } @Override protected void onCreate(Bundle icicle, boolean ready) { //noinspection ConstantConditions this.getSupportActionBar().setDisplayHomeAsUpEnabled(true); if (getIntent() != null && getIntent().getCategories() != null && getIntent().getCategories().contains("android.intent.category.NOTIFICATION_PREFERENCES")) { initFragment(android.R.id.content, new NotificationsPreferenceFragment()); } else if (icicle == null) { Analytics.Companion.getShared().track("Settings Opened"); initFragment(android.R.id.content, new ApplicationPreferenceFragment()); } } @Override public void onResume() { super.onResume(); dynamicTheme.onResume(this); dynamicLanguage.onResume(this); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); Fragment fragment = getSupportFragmentManager().findFragmentById(android.R.id.content); fragment.onActivityResult(requestCode, resultCode, data); } @Override public boolean onSupportNavigateUp() { FragmentManager fragmentManager = getSupportFragmentManager(); if (fragmentManager.getBackStackEntryCount() > 0) { fragmentManager.popBackStack(); } else { Intent intent = new Intent(this, ConversationListActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(intent); finish(); } return true; } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { if (key.equals(TextSecurePreferences.THEME_PREF)) { recreate(); } else if (key.equals(TextSecurePreferences.LANGUAGE_PREF)) { recreate(); Intent intent = new Intent(this, KeyCachingService.class); intent.setAction(KeyCachingService.LOCALE_CHANGE_EVENT); startService(intent); } } public static class ApplicationPreferenceFragment extends CorrectedPreferenceFragment { @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); String masterHexEncodedPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(getContext()); boolean isMasterDevice = (masterHexEncodedPublicKey == null); Preference profilePreference = this.findPreference(PREFERENCE_CATEGORY_PROFILE); if (isMasterDevice) { profilePreference.setOnPreferenceClickListener(new ProfileClickListener()); } /* this.findPreference(PREFERENCE_CATEGORY_SMS_MMS) .setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_SMS_MMS)); */ this.findPreference(PREFERENCE_CATEGORY_NOTIFICATIONS) .setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_NOTIFICATIONS)); this.findPreference(PREFERENCE_CATEGORY_APP_PROTECTION) .setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_APP_PROTECTION)); /* this.findPreference(PREFERENCE_CATEGORY_APPEARANCE) .setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_APPEARANCE)); */ this.findPreference(PREFERENCE_CATEGORY_CHATS) .setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_CHATS)); /* this.findPreference(PREFERENCE_CATEGORY_DEVICES) .setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_DEVICES)); this.findPreference(PREFERENCE_CATEGORY_ADVANCED) .setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_ADVANCED)); */ this.findPreference(PREFERENCE_CATEGORY_PUBLIC_KEY) .setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_PUBLIC_KEY)); this.findPreference(PREFERENCE_CATEGORY_QR_CODE) .setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_QR_CODE)); Preference linkDevicesPreference = this.findPreference(PREFERENCE_CATEGORY_LINKED_DEVICES); linkDevicesPreference.setVisible(isMasterDevice); linkDevicesPreference.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_LINKED_DEVICES)); Preference seedPreference = this.findPreference(PREFERENCE_CATEGORY_SEED); // Hide if this is a slave device seedPreference.setVisible(isMasterDevice); seedPreference.setOnPreferenceClickListener(new CategoryClickListener((PREFERENCE_CATEGORY_SEED))); if (VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { tintIcons(getActivity()); } } @Override public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) { addPreferencesFromResource(R.xml.preferences); } @Override public void onResume() { super.onResume(); //noinspection ConstantConditions ((ApplicationPreferencesActivity) getActivity()).getSupportActionBar().setTitle(R.string.text_secure_normal__menu_settings); setCategorySummaries(); setCategoryVisibility(); } private void setCategorySummaries() { ((ProfilePreference)this.findPreference(PREFERENCE_CATEGORY_PROFILE)).refresh(); /* this.findPreference(PREFERENCE_CATEGORY_SMS_MMS) .setSummary(SmsMmsPreferenceFragment.getSummary(getActivity())); */ this.findPreference(PREFERENCE_CATEGORY_NOTIFICATIONS) .setSummary(NotificationsPreferenceFragment.getSummary(getActivity())); this.findPreference(PREFERENCE_CATEGORY_APP_PROTECTION) .setSummary(AppProtectionPreferenceFragment.getSummary(getActivity())); /* this.findPreference(PREFERENCE_CATEGORY_APPEARANCE) .setSummary(AppearancePreferenceFragment.getSummary(getActivity())); */ this.findPreference(PREFERENCE_CATEGORY_CHATS) .setSummary(ChatsPreferenceFragment.getSummary(getActivity())); } private void setCategoryVisibility() { /* Preference devicePreference = this.findPreference(PREFERENCE_CATEGORY_DEVICES); if (devicePreference != null && !TextSecurePreferences.isPushRegistered(getActivity())) { getPreferenceScreen().removePreference(devicePreference); } */ } @TargetApi(11) private void tintIcons(Context context) { Drawable sms = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.ic_textsms_white_24dp)); Drawable notifications = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.ic_notifications_white_24dp)); Drawable privacy = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.ic_security_white_24dp)); Drawable appearance = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.ic_brightness_6_white_24dp)); Drawable chats = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.ic_forum_white_24dp)); Drawable devices = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.ic_laptop_white_24dp)); Drawable advanced = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.ic_advanced_white_24dp)); Drawable publicKey = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.ic_textsms_24dp)); Drawable qrCode = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.icon_qr_code)); Drawable linkDevice = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.icon_link)); Drawable seed = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.icon_seedling)); int[] tintAttr = new int[]{R.attr.pref_icon_tint}; TypedArray typedArray = context.obtainStyledAttributes(tintAttr); int color = typedArray.getColor(0, 0x0); typedArray.recycle(); DrawableCompat.setTint(sms, color); DrawableCompat.setTint(notifications, color); DrawableCompat.setTint(privacy, color); DrawableCompat.setTint(appearance, color); DrawableCompat.setTint(chats, color); DrawableCompat.setTint(devices, color); DrawableCompat.setTint(advanced, color); DrawableCompat.setTint(publicKey, color); DrawableCompat.setTint(qrCode, color); DrawableCompat.setTint(linkDevice, color); DrawableCompat.setTint(seed, color); // this.findPreference(PREFERENCE_CATEGORY_SMS_MMS).setIcon(sms); this.findPreference(PREFERENCE_CATEGORY_NOTIFICATIONS).setIcon(notifications); this.findPreference(PREFERENCE_CATEGORY_APP_PROTECTION).setIcon(privacy); // this.findPreference(PREFERENCE_CATEGORY_APPEARANCE).setIcon(appearance); this.findPreference(PREFERENCE_CATEGORY_CHATS).setIcon(chats); // this.findPreference(PREFERENCE_CATEGORY_DEVICES).setIcon(devices); // this.findPreference(PREFERENCE_CATEGORY_ADVANCED).setIcon(advanced); this.findPreference(PREFERENCE_CATEGORY_PUBLIC_KEY).setIcon(publicKey); this.findPreference(PREFERENCE_CATEGORY_QR_CODE).setIcon(qrCode); this.findPreference(PREFERENCE_CATEGORY_LINKED_DEVICES).setIcon(linkDevice); this.findPreference(PREFERENCE_CATEGORY_SEED).setIcon(seed); } private class CategoryClickListener implements Preference.OnPreferenceClickListener { private String category; CategoryClickListener(String category) { this.category = category; } @Override public boolean onPreferenceClick(Preference preference) { Fragment fragment = null; switch (category) { /* case PREFERENCE_CATEGORY_SMS_MMS: fragment = new SmsMmsPreferenceFragment(); break; */ case PREFERENCE_CATEGORY_NOTIFICATIONS: fragment = new NotificationsPreferenceFragment(); break; case PREFERENCE_CATEGORY_APP_PROTECTION: fragment = new AppProtectionPreferenceFragment(); break; /* case PREFERENCE_CATEGORY_APPEARANCE: fragment = new AppearancePreferenceFragment(); break; */ case PREFERENCE_CATEGORY_CHATS: fragment = new ChatsPreferenceFragment(); break; /* case PREFERENCE_CATEGORY_DEVICES: Intent intent = new Intent(getActivity(), DeviceActivity.class); startActivity(intent); break; case PREFERENCE_CATEGORY_ADVANCED: fragment = new AdvancedPreferenceFragment(); break; */ case PREFERENCE_CATEGORY_PUBLIC_KEY: Analytics.Companion.getShared().track("Public Key Shared"); String hexEncodedPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(getContext()); if (hexEncodedPublicKey == null) { hexEncodedPublicKey = TextSecurePreferences.getLocalNumber(getContext()); } Intent shareIntent = new Intent(); shareIntent.setAction(Intent.ACTION_SEND); shareIntent.putExtra(Intent.EXTRA_TEXT, hexEncodedPublicKey); shareIntent.setType("text/plain"); startActivity(shareIntent); break; case PREFERENCE_CATEGORY_QR_CODE: QRCodeDialog.INSTANCE.show(getContext()); break; case PREFERENCE_CATEGORY_LINKED_DEVICES: Intent intent = new Intent(getActivity(), LinkedDevicesActivity.class); startActivity(intent); break; case PREFERENCE_CATEGORY_SEED: Analytics.Companion.getShared().track("Seed Modal Shown"); File languageFileDirectory = new File(getContext().getApplicationInfo().dataDir); try { String hexEncodedSeed = IdentityKeyUtil.retrieve(getContext(), IdentityKeyUtil.lokiSeedKey); if (hexEncodedSeed == null) { hexEncodedSeed = SerializationKt.getHexEncodedPrivateKey(IdentityKeyUtil.getIdentityKeyPair(getContext())); // Legacy account } String seed = new MnemonicCodec(languageFileDirectory).encode(hexEncodedSeed, MnemonicCodec.Language.Configuration.Companion.getEnglish()); new AlertDialog.Builder(getContext()) .setTitle(R.string.activity_settings_seed_dialog_title) .setMessage(seed) .setPositiveButton(R.string.activity_settings_seed_dialog_copy_button_title, (DialogInterface.OnClickListener) (dialog, which) -> { ClipboardManager clipboard = (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE); ClipData clip = ClipData.newPlainText("seed", seed); clipboard.setPrimaryClip(clip); Toast.makeText(getContext(), R.string.activity_settings_seed_copied_message, Toast.LENGTH_SHORT).show(); }) .setNeutralButton(R.string.activity_settings_seed_dialog_ok_button_title, null) .show(); } catch (Exception e) { Log.d("Loki", e.getMessage()); } break; default: throw new AssertionError(); } if (fragment != null) { Bundle args = new Bundle(); fragment.setArguments(args); FragmentManager fragmentManager = getActivity().getSupportFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); fragmentTransaction.replace(android.R.id.content, fragment); fragmentTransaction.addToBackStack(null); fragmentTransaction.commit(); } return true; } } private class ProfileClickListener implements Preference.OnPreferenceClickListener { @Override public boolean onPreferenceClick(Preference preference) { Intent intent = new Intent(preference.getContext(), CreateProfileActivity.class); intent.putExtra(CreateProfileActivity.EXCLUDE_SYSTEM, true); getActivity().startActivity(intent); // ((BaseActionBarActivity)getActivity()).startActivitySceneTransition(intent, getActivity().findViewById(R.id.avatar), "avatar"); return true; } } } }