com.harshad.linconnectclient.SettingsActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.harshad.linconnectclient.SettingsActivity.java

Source

/*    
LinConnect: Mirror Android notifications on Linux Desktop
    
Copyright (C) 2013  Will Hauck
    
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 <http://www.gnu.org/licenses/>.
*/

package com.harshad.linconnectclient;

//import android.annotation.SuppressLint;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiManager.MulticastLock;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceActivity;
import android.preference.PreferenceCategory;
import android.preference.PreferenceManager;
import android.util.Base64;
import android.widget.EditText;
import android.widget.Toast;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.InputStreamBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.jmdns.JmDNS;
import javax.jmdns.ServiceEvent;
import javax.jmdns.ServiceListener;

@SuppressWarnings("deprecation")
public class SettingsActivity extends PreferenceActivity {
    private String jmDnsServiceType = "_linconnect._tcp.local.";

    private JmDNS mJmDNS;
    private ServiceListener ServerListener;
    private WifiManager mWifiManager;
    public MulticastLock mMulticastLock;
    private Handler serverFoundHandler;
    private static SharedPreferences sharedPreferences;

    // Preferences
    Preference refreshPreference;
    Preference loadingPreference;

    // Preference Categories
    static PreferenceCategory serverCategory;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Show changelog if needed
        ChangeLog cl = new ChangeLog(this);
        if (cl.isFirstRun()) {
            cl.getLogDialog().show();
        }
        mWifiManager = (android.net.wifi.WifiManager) getSystemService(android.content.Context.WIFI_SERVICE);
    }

    @Override
    protected void onDestroy() {
        // Remove Wifi Multicast lock
        if (mMulticastLock != null)
            mMulticastLock.release();
        try {
            mJmDNS.removeServiceListener(jmDnsServiceType, ServerListener);
            mJmDNS.close();
        } catch (Exception e) {
        }
        super.onDestroy();
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        setupSimplePreferencesScreen();
    }

    @SuppressLint("SimpleDateFormat")
    private void setupSimplePreferencesScreen() {
        // Load preferences
        sharedPreferences = PreferenceManager.getDefaultSharedPreferences(SettingsActivity.this);

        // Add preferences from XML
        addPreferencesFromResource(R.xml.pref_general);
        bindPreferenceSummaryToValue(findPreference("pref_ip"));

        // Preference Categories
        serverCategory = ((PreferenceCategory) findPreference("cat_servers"));

        // Preferences
        refreshPreference = ((Preference) findPreference("pref_refresh"));
        serverCategory.removePreference(refreshPreference);

        loadingPreference = ((Preference) findPreference("pref_loading"));
        serverCategory.removePreference(loadingPreference);

        Preference prefEnable = findPreference("pref_enable");
        prefEnable.setOnPreferenceClickListener(new OnPreferenceClickListener() {
            @Override
            public boolean onPreferenceClick(Preference arg0) {
                // If Android 4.3+, open Notification Listener settings,
                // otherwise open accessibility settings
                if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                    startActivityForResult(new Intent(android.provider.Settings.ACTION_ACCESSIBILITY_SETTINGS), 0);
                } else {
                    Intent intent = new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS");
                    startActivity(intent);
                }
                return true;
            }
        });

        ((Preference) findPreference("pref_ip")).setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
            @Override
            public boolean onPreferenceChange(Preference arg0, Object arg1) {
                // Update Custom IP address summary
                arg0.setSummary((String) arg1);

                refreshServerList();

                // Create and send test notification
                SimpleDateFormat sf = new SimpleDateFormat("HH:mm:ss");
                Object[] notif = new Object[3];
                notif[0] = "Hello from Android!";
                notif[1] = "Test succesful @ " + sf.format(new Date());
                notif[2] = SettingsActivity.this.getResources().getDrawable(R.drawable.ic_launcher);
                new TestTask().execute(notif);

                return true;
            }
        });

        Preference prefDownload = findPreference("pref_download");
        prefDownload.setOnPreferenceClickListener(new OnPreferenceClickListener() {
            @Override
            public boolean onPreferenceClick(Preference arg0) {
                // Create share dialog with server download URL
                Intent sendIntent = new Intent();
                sendIntent.setAction(Intent.ACTION_SEND);
                sendIntent.putExtra(Intent.EXTRA_TEXT,
                        "Download LinConnect server @ https://github.com/hauckwill/linconnect-server");
                sendIntent.setType("text/plain");
                startActivity(sendIntent);
                return true;
            }
        });

        Preference prefApplication = findPreference("pref_application");
        prefApplication.setOnPreferenceClickListener(new OnPreferenceClickListener() {
            @Override
            public boolean onPreferenceClick(Preference arg0) {
                // Open application settings screen
                Intent intent = new Intent(getApplicationContext(), ApplicationSettingsActivity.class);

                startActivity(intent);
                return true;
            }
        });

        //   Preference prefDonateBitcoin = findPreference("pref_donate_btc");
        //   prefDonateBitcoin
        //         .setOnPreferenceClickListener(new OnPreferenceClickListener() {
        //            @Override
        //            public boolean onPreferenceClick(Preference arg0) {
        //               try {
        // Open installed Bitcoin wallet if possible
        //                  Intent intent = new Intent(Intent.ACTION_VIEW);
        //                  intent.setData(Uri
        //                        .parse("bitcoin:1125MguyS1feaop99bCDPQG6ukUcMuvVBo?label=Will%20Hauck&message=Donation%20for%20LinConnect"));
        //                  startActivity(intent);
        //               } catch (Exception e) {
        // Otherwise, show dialog with Bitcoin address
        //                  EditText input = new EditText(SettingsActivity.this);
        //                  input.setText("1125MguyS1feaop99bCDPQG6ukUcMuvVBo");
        //                  input.setEnabled(false);

        //                  new AlertDialog.Builder(SettingsActivity.this)
        //                        .setTitle("Bitcoin Address")
        //                        .setMessage(
        //                              "Please donate to the following Bitcoin address. Thank you for the support.")
        //                        .setView(input)
        //                        .setPositiveButton(
        //                              "Copy Address",
        //                              new DialogInterface.OnClickListener() {
        //                                 public void onClick(
        //                                       DialogInterface dialog,
        //                                       int whichButton) {
        //                                    android.text.ClipboardManager clipboard = (android.text.ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
        //                                    clipboard
        //                                          .setText("1125MguyS1feaop99bCDPQG6ukUcMuvVBo");
        //                                 }
        //                              })
        //                        .setNegativeButton(
        //                              "Okay",
        //                              new DialogInterface.OnClickListener() {
        //                                 public void onClick(
        //                                       DialogInterface dialog,
        //                                       int whichButton) {
        //                                 }
        //                              }).show();
        //               }
        //               return true;
        //            }
        //         });

        //   Preference prefGooglePlus = findPreference("pref_google_plus");
        //   prefGooglePlus
        //         .setOnPreferenceClickListener(new OnPreferenceClickListener() {
        //            @Override
        //            public boolean onPreferenceClick(Preference arg0) {
        //               // Open Google Plus page
        //               Intent intent = new Intent(Intent.ACTION_VIEW);
        //               intent.setData(Uri
        //                     .parse("https://plus.google.com/114633032648182423928/posts"));
        //               startActivity(intent);
        //               return true;
        //            }
        //         });

        //   Preference prefDonatePlay = findPreference("pref_donate_play");
        //   prefDonatePlay
        //         .setOnPreferenceClickListener(new OnPreferenceClickListener() {
        //            @Override
        //            public boolean onPreferenceClick(Preference arg0) {
        // Open Donation Key app on Play Store
        //               Intent intent = new Intent(Intent.ACTION_VIEW);
        //               intent.setData(Uri
        //                     .parse("market://details?id=com.willhauck.donation"));
        //               startActivity(intent);
        //               return true;
        //            }
        //         });

        // Create handler to process a detected server
        serverFoundHandler = new Handler(new Handler.Callback() {
            @Override
            public boolean handleMessage(Message msg) {
                if (msg.obj != null) {

                    javax.jmdns.ServiceInfo serviceInfo = mJmDNS.getServiceInfo(jmDnsServiceType, (String) msg.obj);

                    // Get info about server
                    String name = serviceInfo.getName();
                    String port = String.valueOf(serviceInfo.getPort());
                    String ip = serviceInfo.getHostAddresses()[0];

                    // Create a preference representing the server
                    Preference p = new Preference(SettingsActivity.this);
                    p.setTitle(name);
                    p.setSummary(ip + ":" + port);

                    p.setOnPreferenceClickListener(new OnPreferenceClickListener() {
                        @Override
                        public boolean onPreferenceClick(Preference arg0) {
                            refreshServerList();

                            // Save IP address in preferences
                            Editor e = sharedPreferences.edit();
                            e.putString("pref_ip", arg0.getSummary().toString());
                            e.apply();

                            // Create and send test notification
                            SimpleDateFormat sf = new SimpleDateFormat("HH:mm:ss");

                            Object[] notif = new Object[3];
                            notif[0] = "Hello from Android!";
                            notif[1] = "Test succesful @ " + sf.format(new Date());
                            notif[2] = SettingsActivity.this.getResources().getDrawable(R.drawable.ic_launcher);

                            new TestTask().execute(notif);

                            return true;
                        }

                    });

                    // Add preference to server list if it doesn't already exist
                    boolean found = false;
                    for (int i = 0; i < serverCategory.getPreferenceCount(); i++) {
                        if (serverCategory.getPreference(i) != null
                                && serverCategory.getPreference(i).getTitle() != null
                                && serverCategory.getPreference(i).getTitle().equals(p.getTitle())) {
                            found = true;
                        }
                    }
                    if (!found) {
                        serverCategory.addPreference(p);
                    }

                    refreshServerList();

                    // Remove loading indicator, add refresh indicator if it
                    // isn't already there
                    if (findPreference("pref_loading") != null)
                        serverCategory.removePreference(findPreference("pref_loading"));
                    if (findPreference("pref_refresh") == null)
                        serverCategory.addPreference(refreshPreference);

                }
                return true;
            }
        });

        // Create task to scan for servers
        class ServerScanTask extends AsyncTask<String, ServiceEvent, Boolean> {

            @Override
            protected void onPreExecute() {
                // Remove refresh preference, add loading preference
                if (findPreference("pref_refresh") != null)
                    serverCategory.removePreference(refreshPreference);
                serverCategory.addPreference(loadingPreference);

                try {
                    mJmDNS.removeServiceListener(jmDnsServiceType, ServerListener);
                } catch (Exception e) {
                }

                refreshServerList();

            }

            @Override
            protected Boolean doInBackground(String... notif) {
                WifiInfo wifiinfo = mWifiManager.getConnectionInfo();
                int intaddr = wifiinfo.getIpAddress();

                // Ensure there is an active Wifi connection
                if (intaddr != 0) {
                    byte[] byteaddr = new byte[] { (byte) (intaddr & 0xff), (byte) (intaddr >> 8 & 0xff),
                            (byte) (intaddr >> 16 & 0xff), (byte) (intaddr >> 24 & 0xff) };
                    InetAddress addr = null;
                    try {
                        addr = InetAddress.getByAddress(byteaddr);
                    } catch (UnknownHostException e1) {
                    }

                    // Create Multicast lock (required for JmDNS)
                    mMulticastLock = mWifiManager.createMulticastLock("LinConnect");
                    mMulticastLock.setReferenceCounted(true);
                    mMulticastLock.acquire();

                    try {
                        mJmDNS = JmDNS.create(addr, "LinConnect");
                    } catch (IOException e) {
                    }

                    // Create listener for detected servers
                    ServerListener = new ServiceListener() {

                        @Override
                        public void serviceAdded(ServiceEvent arg0) {
                            final String name = arg0.getName();
                            // Send the server data to the handler, delayed by
                            // 500ms to ensure all information is read
                            serverFoundHandler.sendMessageDelayed(Message.obtain(serverFoundHandler, -1, name),
                                    500);
                        }

                        @Override
                        public void serviceRemoved(ServiceEvent arg0) {
                        }

                        @Override
                        public void serviceResolved(ServiceEvent arg0) {
                            mJmDNS.requestServiceInfo(arg0.getType(), arg0.getName(), 1);
                        }
                    };
                    mJmDNS.addServiceListener(jmDnsServiceType, ServerListener);

                    return true;
                }
                return false;
            }

            @Override
            protected void onPostExecute(Boolean result) {
                if (!result) {
                    // Notify user if there is no connection
                    if (findPreference("pref_loading") != null) {
                        serverCategory.removePreference(findPreference("pref_loading"));
                        serverCategory.addPreference(refreshPreference);

                    }
                    Toast.makeText(getApplicationContext(), "Error: no connection.", Toast.LENGTH_LONG).show();
                }
            }
        }

        refreshPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {

            @Override
            public boolean onPreferenceClick(Preference arg0) {
                new ServerScanTask().execute();
                return true;
            }

        });

        // Start scanning for servers
        new ServerScanTask().execute();
    }

    private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() {
        @Override
        public boolean onPreferenceChange(Preference preference, Object value) {
            String stringValue = value.toString();

            if (preference instanceof ListPreference) {
                ListPreference listPreference = (ListPreference) preference;
                int index = listPreference.findIndexOfValue(stringValue);

                preference.setSummary(index >= 0 ? listPreference.getEntries()[index] : null);
            } else {
                preference.setSummary(stringValue);
            }
            return true;
        }
    };

    private static void bindPreferenceSummaryToValue(Preference preference) {
        preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);

        sBindPreferenceSummaryToValueListener.onPreferenceChange(preference, PreferenceManager
                .getDefaultSharedPreferences(preference.getContext()).getString(preference.getKey(), ""));
    }

    class TestTask extends AsyncTask<Object, Void, Boolean> {
        @SuppressLint("SimpleDateFormat")
        @Override
        protected Boolean doInBackground(Object... notif) {

            // Get server IP
            SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
            String ip = prefs.getString("pref_ip", "0.0.0.0:9090");

            // Create HTTP request
            MultipartEntity entity = new MultipartEntity();
            entity.addPart("notificon", new InputStreamBody(
                    ImageUtilities.bitmapToInputStream(ImageUtilities.drawableToBitmap((Drawable) notif[2])),
                    "drawable.png"));

            HttpPost post = new HttpPost("http://" + ip + "/notif");
            post.setEntity(entity);

            try {
                post.addHeader("notifheader", Base64.encodeToString(((String) notif[0]).getBytes("UTF-8"),
                        Base64.URL_SAFE | Base64.NO_WRAP));
                post.addHeader("notifdescription", Base64.encodeToString(((String) notif[1]).getBytes("UTF-8"),
                        Base64.URL_SAFE | Base64.NO_WRAP));
            } catch (UnsupportedEncodingException e) {
                post.addHeader("notifheader",
                        Base64.encodeToString(((String) notif[0]).getBytes(), Base64.URL_SAFE | Base64.NO_WRAP));
                post.addHeader("notifdescription",
                        Base64.encodeToString(((String) notif[1]).getBytes(), Base64.URL_SAFE | Base64.NO_WRAP));
            }

            HttpClient client = new DefaultHttpClient();
            HttpResponse response;
            try {
                response = client.execute(post);
                String html = EntityUtils.toString(response.getEntity());
                if (html.contains("true")) {
                    return true;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return false;
        }

        @Override
        protected void onPostExecute(Boolean result) {
            if (result == true) {
                Toast.makeText(getApplicationContext(), "Test notification recieved.", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(getApplicationContext(),
                        "Test notification not recieved. Ensure the server is updated to the latest version.",
                        Toast.LENGTH_LONG).show();
            }

        }
    }

    public static void refreshServerList() {

        // Determine server list icons based on IP address
        String ip = sharedPreferences.getString("pref_ip", "0.0.0.0:9090");
        for (int i = 0; i < serverCategory.getPreferenceCount() - 1; i++) {
            Preference p = serverCategory.getPreference(i);
            if (ip.equals(p.getSummary().toString())) {
                p.setIcon(R.drawable.ic_checkmark);
            } else {
                p.setIcon(R.drawable.ic_computer);
            }
        }
    }
}