com.adamkruger.myipaddressinfo.IPAddressInfoFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.adamkruger.myipaddressinfo.IPAddressInfoFragment.java

Source

/*
 * Copyright (c) 2014 Adam Kruger
 * All rights reserved.
 *
 * 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.adamkruger.myipaddressinfo;

import java.lang.ref.WeakReference;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Locale;

import org.json.JSONException;
import org.json.JSONObject;

import android.annotation.TargetApi;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.AsyncTask.Status;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.TextView;

public class IPAddressInfoFragment extends Fragment implements OnClickListener {

    private String mIPAddress;
    private String mISP;
    private String mCountry;
    private String mCity;
    private String mRegion;
    private String mLatLong;
    private boolean mLastUpdateTimedOut;
    private boolean mLastUpdateSucceeded;
    private long mLastUpdateElapsedTimeMs;
    private String mLastUpdateTime;
    private int mDefaultLastUpdateTimeColor;
    private WeakReference<AsyncHTTPRequest> mRequestTaskWeakRef;
    private ArrayList<GeoIpServiceRequestCaller> mGeoIpProviders;
    private TelizeDotComRequestCaller mTelizeDotComRequestCaller;
    private FreegeoipDotNetRequestCaller mFreegeoipDotNetRequestCaller;
    private int mMaxFailovers;
    private int mFailovers;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);

        mGeoIpProviders = new ArrayList<GeoIpServiceRequestCaller>();
        mTelizeDotComRequestCaller = new TelizeDotComRequestCaller();
        mFreegeoipDotNetRequestCaller = new FreegeoipDotNetRequestCaller();
        mGeoIpProviders.add(mTelizeDotComRequestCaller);
        mGeoIpProviders.add(mFreegeoipDotNetRequestCaller);
        mMaxFailovers = mGeoIpProviders.size() - 1;
        mFailovers = 0;

        makeIPAddressInfoRequest();
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_ip_address_info, container, false);
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
            ((TextView) rootView.findViewById(R.id.ipValue)).setTextIsSelectable(true);
            ((TextView) rootView.findViewById(R.id.ispValue)).setTextIsSelectable(true);
            ((TextView) rootView.findViewById(R.id.countryValue)).setTextIsSelectable(true);
            ((TextView) rootView.findViewById(R.id.cityValue)).setTextIsSelectable(true);
            ((TextView) rootView.findViewById(R.id.regionValue)).setTextIsSelectable(true);
            ((TextView) rootView.findViewById(R.id.coordinatesValue)).setTextIsSelectable(true);
        }
        rootView.findViewById(R.id.coordinatesValue).setOnClickListener(this);
        mDefaultLastUpdateTimeColor = ((TextView) rootView.findViewById(R.id.lastUpdateTime)).getTextColors()
                .getDefaultColor();
        return rootView;
    }

    public int getOptimalHeight() {
        int height = 0;
        View view = getView();
        if (view != null) {
            height += view.findViewById(R.id.ipAddressFragmentTableLayout).getHeight();
            height += view.findViewById(R.id.lastUpdateStatus).getHeight();
            height += view.findViewById(R.id.lastUpdateTime).getHeight();
        }
        return height;
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.coordinatesValue:
            onMapValueClick();
            break;
        }
    }

    private void onMapValueClick() {
        if (mLatLong.length() > 0) {
            String uri = mapLink(mLatLong, mIPAddress);
            startActivity(new Intent(android.content.Intent.ACTION_VIEW, Uri.parse(uri)));
        }
    }

    private String mapLink(String latLong, String label) {
        return String.format("http://maps.google.com/?q=%s(%s)", latLong, label);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        updateViewState();
    }

    @Override
    public void onResume() {
        super.onResume();
        updateViewState();
    }

    private void updateViewState() {
        View view = getView();
        if (view != null) {
            ((TextView) view.findViewById(R.id.ipValue)).setText(mIPAddress);
            ((TextView) view.findViewById(R.id.ispValue)).setText(mISP);
            ((TextView) view.findViewById(R.id.countryValue)).setText(mCountry);
            ((TextView) view.findViewById(R.id.cityValue)).setText(mCity);
            ((TextView) view.findViewById(R.id.regionValue)).setText(mRegion);
            ((TextView) view.findViewById(R.id.coordinatesValue)).setText(mLatLong.length() == 0 ? ""
                    : Html.fromHtml(
                            String.format("<a href=\"%s\">%s</a>", mapLink(mLatLong, mIPAddress), mLatLong)));

            if (mLastUpdateTime != null) {
                TextView lastUpdateStatus = (TextView) view.findViewById(R.id.lastUpdateStatus);
                if (mLastUpdateTimedOut) {
                    lastUpdateStatus
                            .setText(String.format(getResources().getString(R.string.last_update_status_timeout),
                                    mLastUpdateElapsedTimeMs / 1000));
                    lastUpdateStatus.setTextColor(getResources().getColor(R.color.error_color));
                } else if (mLastUpdateSucceeded) {
                    lastUpdateStatus
                            .setText(String.format(getResources().getString(R.string.last_update_status_success),
                                    mLastUpdateElapsedTimeMs));
                    if (mLastUpdateElapsedTimeMs < 2000) {
                        lastUpdateStatus.setTextColor(getResources().getColor(R.color.success_color));
                    } else {
                        lastUpdateStatus.setTextColor(getResources().getColor(R.color.warning_color));
                    }
                } else {
                    lastUpdateStatus.setText(String.format(
                            getResources().getString(R.string.last_update_status_fail), mLastUpdateElapsedTimeMs));
                    lastUpdateStatus.setTextColor(getResources().getColor(R.color.error_color));
                }

                TextView lastUpdateTime = (TextView) view.findViewById(R.id.lastUpdateTime);
                lastUpdateTime.setText(
                        String.format(getResources().getString(R.string.last_update_time), mLastUpdateTime));
                String currentTime = DateFormat.getTimeInstance(DateFormat.SHORT, Locale.getDefault())
                        .format(new Date());
                if (currentTime.equals(mLastUpdateTime)) {
                    lastUpdateTime.setTextColor(mDefaultLastUpdateTimeColor);
                } else {
                    lastUpdateTime.setTextColor(getResources().getColor(R.color.warning_color));
                }
            }
        }
    }

    private void setLoadingViewState() {
        mIPAddress = getResources().getString(R.string.loading_message);
        mISP = getResources().getString(R.string.loading_message);
        mCountry = getResources().getString(R.string.loading_message);
        mCity = getResources().getString(R.string.loading_message);
        mRegion = getResources().getString(R.string.loading_message);
        mLatLong = "";
        updateViewState();
    }

    /*
     * Simple GeoIpProvider automatic failover: Always make requests using the
     * first item in the List. On failure, move the first item to the end. If
     * mFailovers < mMaxFailovers, increment mFailovers, and make the request
     * again. Set mFailovers to 0 whenever not failing over.
     */

    public void makeIPAddressInfoRequest() {
        String providerPreference = GeoIPProviderSettingsFragment.getProviderPreference(getActivity());
        if (providerPreference.equals(getResources().getString(R.string.PREFERENCE_GEOIP_PROVIDER_AUTO))) {
            mGeoIpProviders.get(0).makeRequest();
        } else if (providerPreference
                .equals(getResources().getString(R.string.PREFERENCE_GEOIP_PROVIDER_FREEGEOIPDOTNET))) {
            mFreegeoipDotNetRequestCaller.makeRequest();
        } else if (providerPreference
                .equals(getResources().getString(R.string.PREFERENCE_GEOIP_PROVIDER_TELIZEDOTCOM))) {
            mTelizeDotComRequestCaller.makeRequest();
        }
    }

    private void onRequestCompleted() {
        if (mLastUpdateSucceeded) {
            requestsDone();
        } else if (GeoIPProviderSettingsFragment.getProviderPreference(getActivity())
                .equals((getResources().getString(R.string.PREFERENCE_GEOIP_PROVIDER_AUTO)))) {
            mGeoIpProviders.add(mGeoIpProviders.remove(0));
            if (mFailovers < mMaxFailovers) {
                mFailovers++;
                makeIPAddressInfoRequest();
            } else {
                requestsDone();
            }
        } else {
            requestsDone();
        }
    }

    private void requestsDone() {
        mFailovers = 0;
        updateViewState();
    }

    public abstract class GeoIpServiceRequestCaller implements AsyncHTTPRequest.RequestTaskCaller {
        public synchronized void makeRequest() {
            if (IPAddressRequestTaskIsPendingOrRunning()) {
                return;
            }

            AsyncHTTPRequest ipAddressRequestTask = new AsyncHTTPRequest(this, getProxySettings());
            mRequestTaskWeakRef = new WeakReference<AsyncHTTPRequest>(ipAddressRequestTask);
            ipAddressRequestTask.execute(requestURL());
        }

        private boolean IPAddressRequestTaskIsPendingOrRunning() {
            return mRequestTaskWeakRef != null && mRequestTaskWeakRef.get() != null
                    && !mRequestTaskWeakRef.get().getStatus().equals(Status.FINISHED);
        }

        private Proxy getProxySettings() {
            Proxy proxySettings = Proxy.NO_PROXY;

            SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
            boolean useProxy = preferences.getBoolean(getResources().getString(R.string.PREFERENCE_USE_PROXY),
                    false);

            if (useProxy) {
                int proxyPort = preferences.getInt(getResources().getString(R.string.PREFERENCE_PROXY_PORT), 0);
                InetSocketAddress socketAddress = InetSocketAddress.createUnresolved("127.0.0.1", proxyPort);
                proxySettings = new Proxy(Proxy.Type.HTTP, socketAddress);
            }

            return proxySettings;
        }

        @Override
        public void onPreExecute() {
            setLoadingViewState();
        }

        @Override
        public void onPostExecute(String result, long elapsedTime, boolean timedOut) {
            mIPAddress = "";
            mISP = "";
            mCountry = "";
            mCity = "";
            mRegion = "";
            mLatLong = "";

            mLastUpdateTimedOut = timedOut;
            mLastUpdateSucceeded = processIPAddressInfoResponse(result);
            mLastUpdateElapsedTimeMs = elapsedTime;
            mLastUpdateTime = DateFormat.getTimeInstance(DateFormat.SHORT, Locale.getDefault()).format(new Date());

            // Attempt to post onRequestCompleted so that this asyncTask can
            // finish in case we need to fail over and start a new asyncTask
            Handler handler = new Handler();
            boolean postSuccess = handler.post(new Runnable() {
                public void run() {
                    onRequestCompleted();
                }
            });
            if (!postSuccess) {
                onRequestCompleted();
            }
        }

        protected abstract String requestURL();

        protected abstract boolean processIPAddressInfoResponse(String response);
    }

    public class FreegeoipDotNetRequestCaller extends GeoIpServiceRequestCaller {
        @Override
        public String requestURL() {
            return "http://freegeoip.net/json/";
        }

        @Override
        protected boolean processIPAddressInfoResponse(String response) {
            try {
                JSONObject json = new JSONObject(response);
                mIPAddress = json.getString("ip");
                mISP = "";
                mCountry = json.getString("country_name");
                mCity = json.getString("city");
                mRegion = json.getString("region_name");
                mLatLong = json.getString("latitude") + "," + json.getString("longitude");
                return true;
            } catch (JSONException e) {

            }
            return false;
        }
    }

    public class TelizeDotComRequestCaller extends GeoIpServiceRequestCaller {
        @Override
        public String requestURL() {
            return "http://www.telize.com/geoip/";
        }

        @Override
        protected boolean processIPAddressInfoResponse(String response) {
            try {
                JSONObject json = new JSONObject(response);
                // If there is no IP Address, we should fail
                mIPAddress = json.getString("ip");
                mISP = safeGetJSONString(json, "isp");
                mCountry = safeGetJSONString(json, "country");
                mCity = safeGetJSONString(json, "city");
                mRegion = safeGetJSONString(json, "region");
                mLatLong = "";
                String latitude = safeGetJSONString(json, "latitude");
                String longitude = safeGetJSONString(json, "longitude");
                if (latitude.length() > 0 && longitude.length() > 0) {
                    mLatLong = latitude + "," + longitude;
                }
                return true;
            } catch (JSONException e) {

            }
            return false;
        }
    }

    private static String safeGetJSONString(JSONObject json, String key) throws JSONException {
        String jsonString = "";
        if (json.has(key)) {
            jsonString = json.getString(key);
        }
        return jsonString;
    }
}