com.kaliturin.blacklist.fragments.SettingsFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.kaliturin.blacklist.fragments.SettingsFragment.java

Source

/*
 * Copyright (C) 2017 Anton Kaliturin <kaliturin@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.kaliturin.blacklist.fragments;

import android.app.Activity;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.support.annotation.IdRes;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.v4.app.Fragment;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.telephony.SubscriptionInfo;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.kaliturin.blacklist.R;
import com.kaliturin.blacklist.activities.MainActivity;
import com.kaliturin.blacklist.adapters.SettingsArrayAdapter;
import com.kaliturin.blacklist.utils.DatabaseAccessHelper;
import com.kaliturin.blacklist.utils.DefaultSMSAppHelper;
import com.kaliturin.blacklist.utils.DialogBuilder;
import com.kaliturin.blacklist.utils.Permissions;
import com.kaliturin.blacklist.utils.Settings;
import com.kaliturin.blacklist.utils.SubscriptionHelper;
import com.kaliturin.blacklist.utils.Utils;

import java.io.File;
import java.util.List;

/**
 * Settings fragment
 */
public class SettingsFragment extends Fragment implements FragmentArguments {
    private static final int DEFAULT_SMS_APP = 1;
    private static final int BLOCKED_SMS = 2;
    private static final int RECEIVED_SMS = 3;
    private static final int BLOCKED_CALL = 4;
    private SettingsArrayAdapter adapter = null;
    private ListView listView = null;
    private int listPosition = 0;

    public SettingsFragment() {
        // Required empty public constructor
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        // set activity title
        Bundle arguments = getArguments();
        ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
        if (arguments != null && actionBar != null) {
            actionBar.setTitle(arguments.getString(TITLE));
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        if (savedInstanceState != null) {
            listPosition = savedInstanceState.getInt(LIST_POSITION, 0);
        } else {
            Bundle arguments = getArguments();
            if (arguments != null) {
                listPosition = arguments.getInt(LIST_POSITION, listPosition);
            }
        }

        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_settings, container, false);
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        Permissions.notifyIfNotGranted(getContext(), Permissions.WRITE_EXTERNAL_STORAGE);

        listView = (ListView) view.findViewById(R.id.settings_list);
        loadListViewItems(listPosition);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt(LIST_POSITION, listView.getFirstVisiblePosition());
    }

    @Override
    public void onPause() {
        super.onPause();
        listPosition = listView.getFirstVisiblePosition();
    }

    // Is used for getting result of ringtone picker dialog & default sms app dialog
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        switch (requestCode) {
        // default sms app dialog result
        case DEFAULT_SMS_APP:
            if (resultCode == Activity.RESULT_OK) {
                Permissions.invalidateCache();
            }
            // reload list
            reloadListViewItems();
            break;
        // ringtone picker dialog results
        default:
            // get ringtone url
            Uri uri = null;
            if (resultCode == Activity.RESULT_OK && data != null) {
                uri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
            }
            // save url as settings property value
            setRingtoneUri(requestCode, uri);
            break;
        }
    }

    // Reloads the Settings list
    private void reloadListViewItems() {
        listPosition = listView.getFirstVisiblePosition();
        loadListViewItems(listPosition);
    }

    // Loads the Settings list
    private void loadListViewItems(final int listPosition) {
        // Create list adapter and fill it with data
        adapter = new SettingsArrayAdapter(getContext());

        // default sms feature is available
        boolean isDefaultSmsAppAvailable = DefaultSMSAppHelper.isAvailable();
        // current app is default sms app
        boolean isDefaultSmsApp = DefaultSMSAppHelper.isDefault(getContext());

        if (isDefaultSmsAppAvailable) {
            // show sms default app switch
            adapter.addTitle(R.string.SMS_default_app);
            adapter.addCheckbox(R.string.Default_SMS_app, R.string.Set_as_default_SMS_app, isDefaultSmsApp,
                    new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            DefaultSMSAppHelper.askForDefaultAppChange(SettingsFragment.this, DEFAULT_SMS_APP);
                        }
                    });
        }

        if (SubscriptionHelper.isAvailable()) {
            // SIM-card
            adapter.addTitle(R.string.SIM_card);
            adapter.addButton(getString(R.string.Chosen_SIM), getCurrentSimName(), new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    // check permissions
                    if (Permissions.notifyIfNotGranted(getContext(), Permissions.READ_PHONE_STATE)) {
                        return;
                    }
                    // open the dialog of SIM choosing
                    showSimChoosingDialog();
                }
            });
        }

        if (isDefaultSmsApp) {
            // sms blocking settings
            adapter.addTitle(R.string.SMS_blocking);
            adapter.addCheckbox(R.string.All_SMS, R.string.Block_all_SMS, Settings.BLOCK_ALL_SMS);
            adapter.addCheckbox(R.string.Black_list, R.string.Block_SMS_from_black_list,
                    Settings.BLOCK_SMS_FROM_BLACK_LIST);
            adapter.addCheckbox(R.string.Contacts_list, R.string.Block_SMS_not_from_contacts,
                    Settings.BLOCK_SMS_NOT_FROM_CONTACTS);
            adapter.addCheckbox(R.string.SMS_list, R.string.Block_SMS_not_from_SMS_list,
                    Settings.BLOCK_SMS_NOT_FROM_SMS_CONTENT);
            adapter.addCheckbox(R.string.Private_numbers, R.string.Block_SMS_from_private,
                    Settings.BLOCK_PRIVATE_SMS);
            adapter.addCheckbox(R.string.Journal, R.string.Write_SMS_to_journal, Settings.WRITE_SMS_JOURNAL);

            // sms notifications settings
            adapter.addTitle(R.string.SMS_blocking_notification);
            adapter.addCheckbox(R.string.Status_bar, R.string.Notify_in_status_bar_blocked_SMS,
                    Settings.BLOCKED_SMS_STATUS_NOTIFICATION, new DependentRowOnClickListener());
            adapter.addCheckbox(R.string.Sound, R.string.Notify_with_sound_blocked_SMS,
                    Settings.BLOCKED_SMS_SOUND_NOTIFICATION, new RingtonePickerOnClickListener(BLOCKED_SMS));
            adapter.addCheckbox(R.string.Vibration, R.string.Notify_with_vibration_blocked_SMS,
                    Settings.BLOCKED_SMS_VIBRATION_NOTIFICATION, new DependentRowOnClickListener());
        }

        // sms receiving/sending
        adapter.addTitle(R.string.SMS_receiving_notification);
        adapter.addCheckbox(R.string.Sound, R.string.Notify_with_sound_received_SMS,
                Settings.RECEIVED_SMS_SOUND_NOTIFICATION, new RingtonePickerOnClickListener(RECEIVED_SMS));
        adapter.addCheckbox(R.string.Vibration, R.string.Notify_with_vibration_received_SMS,
                Settings.RECEIVED_SMS_VIBRATION_NOTIFICATION);
        adapter.addCheckbox(R.string.SMS_delivery, R.string.Notify_on_SMS_delivery,
                Settings.DELIVERY_SMS_NOTIFICATION);

        // calls blocking settings
        adapter.addTitle(R.string.Calls_blocking);
        adapter.addCheckbox(R.string.All_calls, R.string.Block_all_calls, Settings.BLOCK_ALL_CALLS);

        adapter.addCheckbox(R.string.Black_list, R.string.Block_calls_from_black_list,
                Settings.BLOCK_CALLS_FROM_BLACK_LIST);
        adapter.addCheckbox(R.string.Contacts_list, R.string.Block_calls_not_from_contacts,
                Settings.BLOCK_CALLS_NOT_FROM_CONTACTS);
        adapter.addCheckbox(R.string.SMS_list, R.string.Block_calls_not_from_SMS_list,
                Settings.BLOCK_CALLS_NOT_FROM_SMS_CONTENT);
        adapter.addCheckbox(R.string.Private_numbers, R.string.Block_calls_from_private,
                Settings.BLOCK_PRIVATE_CALLS);
        adapter.addCheckbox(R.string.Journal, R.string.Write_calls_to_journal, Settings.WRITE_CALLS_JOURNAL);
        adapter.addCheckbox(R.string.Call_log, R.string.Remove_from_call_log, Settings.REMOVE_FROM_CALL_LOG);

        // calls notifications settings
        adapter.addTitle(R.string.Calls_blocking_notification);
        adapter.addCheckbox(R.string.Status_bar, R.string.Notify_in_status_bar_blocked_call,
                Settings.BLOCKED_CALL_STATUS_NOTIFICATION, new DependentRowOnClickListener());
        adapter.addCheckbox(R.string.Sound, R.string.Notify_with_sound_blocked_call,
                Settings.BLOCKED_CALL_SOUND_NOTIFICATION, new RingtonePickerOnClickListener(BLOCKED_CALL));
        adapter.addCheckbox(R.string.Vibration, R.string.Notify_with_vibration_blocked_call,
                Settings.BLOCKED_CALL_VIBRATION_NOTIFICATION, new DependentRowOnClickListener());

        // app interface
        adapter.addTitle(R.string.App_interface);
        adapter.addCheckbox(R.string.Text_folding, R.string.Journal_SMS_text_folding,
                Settings.FOLD_SMS_TEXT_IN_JOURNAL);
        adapter.addCheckbox(R.string.Journal, R.string.Go_to_Journal_at_start, Settings.GO_TO_JOURNAL_AT_START);
        adapter.addCheckbox(R.string.Back_button, R.string.Exit_on_back_pressed,
                Settings.DONT_EXIT_ON_BACK_PRESSED);
        adapter.addCheckbox(R.string.UI_theme_dark, 0, Settings.UI_THEME_DARK, new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                restartApp();
            }
        });

        // app data export/import
        adapter.addTitle(R.string.App_data);
        // export DB file
        adapter.addButton(R.string.Export_data, R.string.Write_data_into_external, new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // check permissions
                if (Permissions.notifyIfNotGranted(getContext(), Permissions.WRITE_EXTERNAL_STORAGE)) {
                    return;
                }
                // open the dialog for getting the exporting DB file path
                showFilePathDialog(R.string.Export_data, new TextView.OnEditorActionListener() {
                    @Override
                    public boolean onEditorAction(TextView textView, int actionId, KeyEvent event) {
                        // export data file
                        exportDataFile(textView.getText().toString());
                        return true;
                    }
                });
            }
        });
        // import DB file
        adapter.addButton(R.string.Import_data, R.string.Load_data_from_external, new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // check permissions
                if (Permissions.notifyIfNotGranted(getContext(), Permissions.WRITE_EXTERNAL_STORAGE)) {
                    return;
                }
                // open the dialog for getting the importing DB file path
                showFilePathDialog(R.string.Import_data, new TextView.OnEditorActionListener() {
                    @Override
                    public boolean onEditorAction(TextView textView, int actionId, KeyEvent event) {
                        // import data file
                        if (importDataFile(textView.getText().toString())) {
                            // import complete - restart
                            Settings.invalidateCache();
                            restartApp();
                        }
                        return true;
                    }
                });
            }
        });

        // add adapter to the ListView and scroll list to position
        listView.setAdapter(adapter);
        listView.post(new Runnable() {
            @Override
            public void run() {
                listView.setSelection(listPosition);
            }
        });
    }

    // Saves ringtone url as settings property value
    private void setRingtoneUri(int requestCode, @Nullable Uri uri) {
        String ringtoneProperty, soundProperty, statusProperty = null;
        switch (requestCode) {
        case BLOCKED_CALL:
            ringtoneProperty = Settings.BLOCKED_CALL_RINGTONE;
            soundProperty = Settings.BLOCKED_CALL_SOUND_NOTIFICATION;
            statusProperty = Settings.BLOCKED_CALL_STATUS_NOTIFICATION;
            break;
        case BLOCKED_SMS:
            ringtoneProperty = Settings.BLOCKED_SMS_RINGTONE;
            soundProperty = Settings.BLOCKED_SMS_SOUND_NOTIFICATION;
            statusProperty = Settings.BLOCKED_SMS_STATUS_NOTIFICATION;
            break;
        case RECEIVED_SMS:
            ringtoneProperty = Settings.RECEIVED_SMS_RINGTONE;
            soundProperty = Settings.RECEIVED_SMS_SOUND_NOTIFICATION;
            break;
        default:
            return;
        }

        if (uri != null) {
            Settings.setStringValue(getContext(), ringtoneProperty, uri.toString());
            adapter.setRowChecked(soundProperty, true);
            if (statusProperty != null) {
                // if we enable ringtone we must enable status bar notification
                adapter.setRowChecked(statusProperty, true);
            }
        } else {
            adapter.setRowChecked(soundProperty, false);
        }
    }

    // Returns ringtone url from settings property
    @Nullable
    private Uri getRingtoneUri(int requestCode) {
        String uriString = null;
        switch (requestCode) {
        case BLOCKED_CALL:
            uriString = Settings.getStringValue(getContext(), Settings.BLOCKED_CALL_RINGTONE);
            break;
        case BLOCKED_SMS:
            uriString = Settings.getStringValue(getContext(), Settings.BLOCKED_SMS_RINGTONE);
            break;
        case RECEIVED_SMS:
            uriString = Settings.getStringValue(getContext(), Settings.RECEIVED_SMS_RINGTONE);
            break;
        }

        return (uriString != null ? Uri.parse(uriString) : null);
    }

    // On row click listener for opening ringtone picker
    private class RingtonePickerOnClickListener implements View.OnClickListener {
        int requestCode;

        RingtonePickerOnClickListener(int requestCode) {
            this.requestCode = requestCode;
        }

        @Override
        public void onClick(View view) {
            if (isAdded()) {
                if (adapter.isRowChecked(view)) {
                    // open ringtone picker dialog
                    Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
                    intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_NOTIFICATION);
                    intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TITLE, getString(R.string.Ringtone_picker));
                    intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, getRingtoneUri(requestCode));
                    startActivityForResult(intent, requestCode);
                }
            } else {
                adapter.setRowChecked(view, false);
            }
        }
    }

    // On row click listener for updating dependent rows
    private class DependentRowOnClickListener implements View.OnClickListener {
        @Override
        public void onClick(View view) {
            String property = adapter.getRowProperty(view);
            if (property == null) {
                return;
            }

            boolean checked = adapter.isRowChecked(view);
            if (!checked) {
                // if row was unchecked - reset dependent rows
                switch (property) {
                case Settings.BLOCKED_SMS_STATUS_NOTIFICATION:
                    adapter.setRowChecked(Settings.BLOCKED_SMS_SOUND_NOTIFICATION, false);
                    adapter.setRowChecked(Settings.BLOCKED_SMS_VIBRATION_NOTIFICATION, false);
                    break;
                case Settings.BLOCKED_CALL_STATUS_NOTIFICATION:
                    adapter.setRowChecked(Settings.BLOCKED_CALL_SOUND_NOTIFICATION, false);
                    adapter.setRowChecked(Settings.BLOCKED_CALL_VIBRATION_NOTIFICATION, false);
                    break;
                }
            } else {
                switch (property) {
                case Settings.BLOCKED_SMS_SOUND_NOTIFICATION:
                case Settings.BLOCKED_SMS_VIBRATION_NOTIFICATION:
                    adapter.setRowChecked(Settings.BLOCKED_SMS_STATUS_NOTIFICATION, true);
                    break;
                case Settings.BLOCKED_CALL_SOUND_NOTIFICATION:
                case Settings.BLOCKED_CALL_VIBRATION_NOTIFICATION:
                    adapter.setRowChecked(Settings.BLOCKED_CALL_STATUS_NOTIFICATION, true);
                    break;
                }
            }
        }
    }

    // Shows the dialog of database file path definition
    private void showFilePathDialog(@StringRes int titleId, final TextView.OnEditorActionListener listener) {
        if (!isAdded())
            return;
        String filePath = Environment.getExternalStorageDirectory().getPath() + "/Download/"
                + DatabaseAccessHelper.DATABASE_NAME;

        @IdRes
        final int editId = 1;
        // create dialog
        DialogBuilder dialog = new DialogBuilder(getContext());
        dialog.setTitle(titleId);
        dialog.addEdit(editId, filePath, getString(R.string.File_path));
        dialog.addButtonLeft(getString(R.string.CANCEL), null);
        dialog.addButtonRight(getString(R.string.OK), new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                Window window = ((Dialog) dialog).getWindow();
                if (window != null) {
                    TextView textView = (TextView) window.findViewById(editId);
                    if (textView != null) {
                        listener.onEditorAction(textView, 0, null);
                    }
                }
            }
        });
        dialog.show();
    }

    // Exports data file to the passed path
    private boolean exportDataFile(String dstFilePath) {
        if (!Permissions.isGranted(getContext(), Permissions.WRITE_EXTERNAL_STORAGE)) {
            return false;
        }

        // get source file
        DatabaseAccessHelper db = DatabaseAccessHelper.getInstance(getContext());
        if (db == null) {
            return false;
        }
        File srcFile = new File(db.getReadableDatabase().getPath());

        // check destination file
        File dstFile = new File(dstFilePath);
        if (dstFile.getParent() == null) {
            toast(R.string.Error_invalid_file_path);
            return false;
        }
        // create destination file path
        if (!Utils.makeFilePath(dstFile)) {
            toast(R.string.Error_on_file_path_creating);
            return false;
        }
        // copy source file to destination
        if (!Utils.copyFile(srcFile, dstFile)) {
            toast(R.string.Error_on_file_writing);
            return false;
        }

        toast(R.string.Export_complete);

        return true;
    }

    // Imports data file from the passed path
    private boolean importDataFile(String srcFilePath) {
        if (!Permissions.isGranted(getContext(), Permissions.WRITE_EXTERNAL_STORAGE)) {
            return false;
        }

        // check source file
        if (!DatabaseAccessHelper.isSQLiteFile(srcFilePath)) {
            toast(R.string.Error_file_is_not_valid);
            return false;
        }
        // get source file
        File srcFile = new File(srcFilePath);

        // get destination file
        DatabaseAccessHelper db = DatabaseAccessHelper.getInstance(getContext());
        if (db == null) {
            return false;
        }
        File dstFile = new File(db.getReadableDatabase().getPath());
        // clear cache
        DatabaseAccessHelper.invalidateCache();
        // remove the old file
        if (dstFile.exists() && !dstFile.delete()) {
            toast(R.string.Error_on_old_data_deletion);
            return false;
        }
        // copy source file to destination
        if (!Utils.copyFile(srcFile, dstFile)) {
            toast(R.string.Error_on_file_writing);
            return false;
        }

        toast(R.string.Import_complete);

        return true;
    }

    // Shows toast
    private void toast(@StringRes int messageId) {
        Toast.makeText(getContext(), messageId, Toast.LENGTH_SHORT).show();
    }

    // Restarts the current app and opens settings fragment
    private void restartApp() {
        Intent intent = new Intent(getActivity(), MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setAction(MainActivity.ACTION_SETTINGS);
        intent.putExtra(LIST_POSITION, listView.getFirstVisiblePosition());
        startActivity(intent);
        getActivity().finish();
    }

    // Returns the name of the current chosen SIM-card
    private String getCurrentSimName() {
        String name = SubscriptionHelper.getCurrentSubscriptionName(getContext());
        return name == null ? getString(R.string.By_default) : name;
    }

    // Shows dialog of SIM choosing
    private void showSimChoosingDialog() {
        // create and show menu dialog for actions with the contact
        DialogBuilder dialog = new DialogBuilder(getContext());
        dialog.setTitle(R.string.Choose_SIM);

        List<SubscriptionInfo> list = SubscriptionHelper.getSubscriptions(getContext());
        if (list != null) {
            for (SubscriptionInfo info : list) {
                String name = SubscriptionHelper.getName(info);
                if (name != null) {
                    dialog.addItem(0, name, info, new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            SubscriptionInfo info2 = (SubscriptionInfo) v.getTag();
                            Integer id = SubscriptionHelper.getId(info2);
                            if (id != null) {
                                Settings.setIntegerValue(getContext(), Settings.SIM_SUBSCRIPTION_ID, id);
                                reloadListViewItems();
                            }
                        }
                    });
                }
            }
        }
        dialog.addItem(R.string.By_default, new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Settings.setIntegerValue(getContext(), Settings.SIM_SUBSCRIPTION_ID, -1);
                reloadListViewItems();
            }
        }).show();
    }
}