org.restcomm.app.qoslib.Utils.QosAPI.java Source code

Java tutorial

Introduction

Here is the source code for org.restcomm.app.qoslib.Utils.QosAPI.java

Source

package org.restcomm.app.qoslib.Utils;

import android.app.Activity;
import android.app.ActivityManager;
import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.SystemClock;
import android.preference.PreferenceManager;

import org.restcomm.app.qoslib.MainService;
import org.restcomm.app.qoslib.Services.Intents.IntentHandler;
import org.restcomm.app.qoslib.UtilsOld.ActiveEvent;
import org.restcomm.app.utillib.DataObjects.EventType;
import org.restcomm.app.utillib.DataObjects.PhoneState;
import org.restcomm.app.utillib.Reporters.ReportManager;
import org.restcomm.app.utillib.Utils.Global;
import org.restcomm.app.utillib.Utils.LoggerUtil;
import org.restcomm.app.utillib.Utils.PreferenceKeys;
import org.restcomm.app.utillib.Utils.UsageLimits;
//import com.securepreferences.SecurePreferences;

import org.json.JSONObject;

import java.util.List;

/*
 * TeleStax, Open Source Cloud Communications
 * Copyright 2011-2016, Telestax Inc and individual contributors
 * by the @authors tag.
 *
 * This program is free software: you can redistribute it and/or modify
 * under the terms of the GNU Affero 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 *
 * For questions related to commercial use licensing, please contact sales@telestax.com.
 *
 */

/**
* QosAPI is the main interface between the client application and the Quality of Service Library
* These methods allow the app to easily communicate and start and stop the background service
* using static methods.
* The main tasks to be performed using this class are:
* <ul>
* <li>start the service
* <li>set the login, and in some cases a password. This will register with the server.
* <li>Request QoS information such as all the mobile network measurements
* <li>Trigger events such as speed tests, which gather data and send to the server
* <li>Check for permissions
* </ul>
* <p>
*
* @author      Brad Scheurman
* @version     %I%, %G%
* @since       1.0
*/
public class QosAPI {

    public static final String TAG = QosAPI.class.getSimpleName();

    /**
     * Start the MMC/QOS Service. Keep this running to monitor for phone calls and other events
     * This should be called as soon as possible, before other calls to the library
     * If a login has been set with setLogin, it will register in the background if needed
     *
     * @param context pass your context
     */
    public static void start(Context context, boolean bFromUI) {
        Global.startService(context, bFromUI);
    }

    /**
     * Get the login name that was set with setLogin
     * The login name can be an email or any type of name, but it should be unique to avoid mixing data with another user
     *
     * @param context pass your context
     * @return the login name that has been set for the user
     */
    public static String getLogin(Context context) {
        SharedPreferences securePref = MainService.getSecurePreferences(context);
        String value = securePref.getString(PreferenceKeys.User.USER_EMAIL, null);
        return value;
    }

    /**
     * Get the password name that may have been set with setLogin
     * The password is optional but is used to login to the website to view data
     * If an email is used as a login name, there is no need to set a password because it can be set via email
     * There is also no need to set a password if the user does not need to directly access data on the web site
     *
     * @param context pass your context
     * @return the password that has been set for the user
     */
    public static String getPassword(Context context) {
        SharedPreferences securePref = MainService.getSecurePreferences(context);
        String value = securePref.getString(PreferenceKeys.User.USER_PASSWORD, null);
        return value;
    }

    /**
     * Set the login name to register the user with
     * The user/login is used to group data on the server collected by this device
     * It will register with the server if the service has been started
     *
     * @param context pass your context
     * @param login login name can be an email or any type of name, but it should be unique to avoid mixing data with another user
     */
    public static void setLogin(Context context, String login) {
        SharedPreferences securePref = MainService.getSecurePreferences(context);
        String oldlogin = securePref.getString(PreferenceKeys.User.USER_EMAIL, "");
        if (login == null || oldlogin.equals(login) || login.length() < 3)
            return;
        securePref.edit().putString(PreferenceKeys.User.USER_EMAIL, login).commit();
        registerLogin(context, login);
    }

    /**
     * Set the login name to register the user with
     * This version also sets a password for the user
     * The user/login is used to group data on the server collected by this device
     *
     * @param context pass your context
     * @param login login name can be an email or any type of name, but it should be unique to avoid mixing data with another user
     * @param password optional but is used to login to the website to view data
     */
    public static void setLogin(Context context, String login, String password) {
        SharedPreferences securePref = MainService.getSecurePreferences(context);
        String oldlogin = securePref.getString(PreferenceKeys.User.USER_EMAIL, "");
        if (login == null || oldlogin.equals(login) || login.length() < 3)
            return;
        securePref.edit().putString(PreferenceKeys.User.USER_EMAIL, login).commit();
        securePref.edit().putString(PreferenceKeys.User.USER_PASSWORD, password).commit();
        registerLogin(context, login, password);
    }

    /**
     * Set the login name anonymously to be the device IMEI
     * The user/login is used to group data on the server collected by this device
     *
     * @param context pass your context
     */
    public static void setLoginToIMEI(Context context) {
        SharedPreferences securePref = MainService.getSecurePreferences(context);
        ReportManager manager = ReportManager.getInstance(context);
        String imei = manager.getDevice().getIMEI();

        String oldlogin = securePref.getString(PreferenceKeys.User.USER_EMAIL, "");
        if (imei == null || oldlogin.equals(imei) || imei.length() < 3)
            return;
        securePref.edit().putString(PreferenceKeys.User.USER_EMAIL, imei).commit();
        registerLogin(context, imei);
    }

    // private function used by setLogin to register
    private static void registerLogin(final Context context, final String login, final String password) {
        final ReportManager reportmanager = ReportManager.getInstance(context);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    reportmanager.authorizeDevice(login, password, false);
                    //reportmanager.checkPlayServices(context, true);
                } catch (Exception e) {
                }
            }
        }).start();

    }

    // private function used by setLogin to register
    private static void registerLogin(final Context context, final String login) {
        registerLogin(context, login, null);
    }

    /**
     * Trigger an Active Event manually from the application, generally this is a type of active test or coverage gathering
     * Allowable events are from {@link ActiveEvent}
     *
     * @param context pass your context
     * @param {@link ActiveEvent} type of event to start
     * @return 0 if successful, 1 if event type can't be triggered, 2 if event is not enabled for your user, 3 if app doesnt have necessary permissions
     */
    public static int startEvent(Context context, ActiveEvent event) {
        if (!isEventEnabled(context, event.eventType))
            return 2; // Event has not been enabled by server
        if (!isEventPermitted(context, event.eventType, 1))
            return 3; // Event doesnt have enough manifest permissions to run

        JSONObject jobj = new JSONObject();
        try {
            // Trigger certain events using the Library
            if (event == ActiveEvent.SPEED_TEST)
                jobj.put("mmctype", "speed");
            else if (event == ActiveEvent.UPDATE_EVENT)
                jobj.put("mmctype", "ue");
            else if (event == ActiveEvent.AUDIO_TEST)
                jobj.put("mmctype", "audio");
            else if (event == ActiveEvent.CONNECT_TEST)
                jobj.put("mmctype", "latency");
            else if (event == ActiveEvent.SMS_TEST)
                jobj.put("mmctype", "sms");
            else if (event == ActiveEvent.VIDEO_TEST)
                jobj.put("mmctype", "video");
            else if (event == ActiveEvent.YOUTUBE_TEST)
                jobj.put("mmctype", "youtube");
            else if (event == ActiveEvent.WEB_TEST)
                jobj.put("mmctype", "web");
            else if (event == ActiveEvent.VOICE_QUALITY_TEST)
                jobj.put("mmctype", "vq");
            else if (event == ActiveEvent.COVERAGE_EVENT)
                jobj.put("mmctype", "fill");
            else
                return 1; // Event can't be triggered manually
        } catch (Exception e) {
            LoggerUtil.logToFile(LoggerUtil.Level.ERROR, TAG, "Library startEvent", "exception", e);
        }
        String command = "[" + jobj.toString() + "]";
        Intent mmcintent = new Intent(IntentHandler.COMMAND);
        mmcintent.putExtra(IntentHandler.COMMAND_EXTRA, command);
        context.sendBroadcast(mmcintent);
        return 0;
    }

    /**
     * Trigger an extended 'drive test' combining different types of tests on intervals
     *
     * @param context pass your context
     * @param minutes duration to repeat the tests in minutes
     * @param coverage true to gather coverage during the duration of the test
     * @param speed run speed tests during the test, the value is the number of minutes in betwee
     * @param connectivity run connectivity tests during the test, the value is the number of minutes in between
     * @param sms run sms tests during the test, the value is the number of minutes in between
     * @param video run video streaming tests during the test, the value is the number of minutes in between
     * @param audio run audio streaming tests during the test, the value is the number of minutes in between
     * @param web run web page load tests during the test, the value is the number of minutes in between
     * @param vq run voice quality tests during the test, the value is the number of minutes in between
     * @param youtube run youtube streaming tests during the test, the value is the number of minutes in between
     * @param youtube run ping tests during the test, the value is the number of minutes in betwee
     * @return 0 if successful
     */
    public static int startDriveTest(Context context, int minutes, boolean coverage, int speed, int connectivity,
            int sms, int video, int audio, int web, int vq, int youtube, int ping) {
        ReportManager.getInstance(context.getApplicationContext()).startDriveTest(context, minutes, coverage, speed,
                connectivity, sms, video, audio, web, vq, youtube, ping);
        return 0;
    }

    /**
     * Check whether an Active test EventType is able to run
     *
     * @param context pass your context
     * @param eventType {@link EventType} type of event to check
     * @return true if EventType is enabled to run
     */
    public static boolean isEventEnabled(Context context, EventType eventType) {
        String pref;
        if (eventType == EventType.AUDIO_TEST) {
            pref = PreferenceManager.getDefaultSharedPreferences(context)
                    .getString(PreferenceKeys.Miscellaneous.AUDIO_URL, null);
            if (pref == null || pref.length() == 0)
                return false;
        } else if (eventType == EventType.VIDEO_TEST) {
            pref = PreferenceManager.getDefaultSharedPreferences(context)
                    .getString(PreferenceKeys.Miscellaneous.VIDEO_URL, null);
            if (pref == null || pref.length() == 0)
                return false;
        } else if (eventType == EventType.YOUTUBE_TEST) {
            pref = PreferenceManager.getDefaultSharedPreferences(context)
                    .getString(PreferenceKeys.Miscellaneous.YOUTUBE_VIDEOID, null);
            if (pref == null || pref.length() == 0)
                return false;
        } else if (eventType == EventType.WEBPAGE_TEST) {
            pref = PreferenceManager.getDefaultSharedPreferences(context)
                    .getString(PreferenceKeys.Miscellaneous.WEB_URL, null);
            if (pref == null || pref.length() == 0)
                return false;
        } else if (eventType == EventType.EVT_VQ_CALL) {
            pref = PreferenceManager.getDefaultSharedPreferences(context)
                    .getString(PreferenceKeys.Miscellaneous.VOICETEST_SERVICE, null);
            if (pref == null || pref.length() == 0)
                return false;
        }
        return true;
    }

    /**
     * Check whether an Active test EventType has Android permissions needed to run
     *
     * @param context pass your context
     * @param eventType {@link EventType} type of event to check
     * @param trigger 0 to trigger the event manually, 1 to see if it can trigger the event automatically
     * @return true if EventType is enabled to run
     */
    public static boolean isEventPermitted(Context context, EventType eventType, int trigger) {
        if (eventType == EventType.SMS_TEST) {
            if (!PreferenceKeys.getSMSPermissionsAllowed(context, true))
                return false;
        }
        // Allow auto-connection tests?
        else if (eventType == EventType.LATENCY_TEST && trigger == 1) {
            if (context instanceof MainService) // this check only applies if called from the MainService
            {
                MainService svc = (MainService) context;
                String reason = null;
                int allow = PreferenceManager.getDefaultSharedPreferences(context)
                        .getInt(PreferenceKeys.Miscellaneous.AUTO_CONNECTION_TESTS, 1);
                if (PhoneState.isNetworkWifi(context))
                    reason = "on wifi";
                if (!svc.isOnline())
                    reason = "offline";
                if (allow != 1 && !LoggerUtil.isDebuggable())
                    reason = "not enabled";
                if (svc.getPhoneStateListener() != null && (svc.getPhoneState().isCallConnected() == true
                        || svc.getPhoneState().isCallDialing() == true))
                    reason = "phone call";
                if (svc.getUsageLimits().getUsageProfile() <= UsageLimits.MINIMAL)
                    reason = "minimal";
                if (svc.getUsageLimits().getDormantMode() >= 1)
                    reason = "dormant";
                if (reason != null) {
                    LoggerUtil.logToFile(LoggerUtil.Level.ERROR, TAG, "runLatencyTest cancelled ", reason);
                    return false;
                }
            }
        } else if (eventType == EventType.EVT_VQ_CALL) {
            PackageManager pkMan = context.getPackageManager();
            int voiceCallPermissionValue = pkMan.checkPermission("android.permission.CALL_PHONE",
                    context.getPackageName())
                    | pkMan.checkPermission("android.permission.RECORD_AUDIO", context.getPackageName());
            if (voiceCallPermissionValue != 0)
                return false;
        } else if (trigger > 0 && (eventType == EventType.VIDEO_TEST || eventType == EventType.WEBPAGE_TEST
                || eventType == EventType.AUDIO_TEST || eventType == EventType.YOUTUBE_TEST)) {
            PackageManager pkMan = context.getPackageManager();
            int permissionValue = pkMan.checkPermission("android.permission.SYSTEM_ALERT_WINDOW",
                    context.getPackageName());
            if (permissionValue != 0)
                return false;
        }
        return true;
    }

    /**
     * Cause the service to close and restart itself
     * You can do this when your App is finished, just as it closes
     * The reason to do this is to reclaim some memory held by the application's process.
     * When the service restarts it will have a new process, otherwise the process will continue to hold all the RAM the application was using
     * @param activity pass the activity that is being closed to close the App
     */
    //    public static void finishUI (Activity activity)
    //    {
    //        SecurePreferences securePrefs = MainService.getSecurePreferences(activity);
    //        boolean bStoppedService = securePrefs.getBoolean(PreferenceKeys.Miscellaneous.STOPPED_SERVICE, false);
    //        if (!bStoppedService)
    //        {
    //            Intent intent = new Intent(IntentHandler.RESTART_MMC_SERVICE);
    //            activity.sendBroadcast(intent);
    //        }
    //    }

    /**
     * Request a snapshot of all of the Network data the service has obtained
     * Network, Cell, Signal and Location data
     * The first call to this may not have up-to-date signal data, but it will begin listening so that subsequent calls will be up-to-date
     * The information will already be up to date during or just after a phone call, active test, or coverage sampling
     * For best results, call repeatedly on an interval
     * @param context pass your context
     * @return {@link QosInfo} where The most relevant information is contained in the connectedNetwork {@link QosInfo.NetworkInfo}
     * */
    public static QosInfo getQoSInfo(Context context) {
        QosInfo qos = new QosInfo(context);
        return qos;
    }

    public static void showHistory(final Activity activity, EventType[] eventTypes) {
        try {
            Intent intent = new Intent(activity, EventHistory.class);
            int[] ieventtypes = new int[eventTypes.length];
            for (int i = 0; i < eventTypes.length; i++)
                ieventtypes[i] = eventTypes[i].getIntValue();
            intent.putExtra("eventtypes", ieventtypes);
            activity.startActivity(intent);
        } catch (Exception e) {

        }
    }

    public static void showQoSPanel(final Activity activity) {
        try {
            AlertDialog.Builder builder1 = new AlertDialog.Builder(activity);
            CharSequence qosInfo = getQosInfo(activity);
            builder1.setMessage(qosInfo);
            builder1.setTitle("QOS Info");
            builder1.setCancelable(true);
            final AlertDialog alert11 = builder1.create();
            alert11.show();
            final Handler handler = new Handler();
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    CharSequence qosInfo = getQosInfo(activity);
                    if (alert11.isShowing()) {
                        try {
                            alert11.setMessage(qosInfo);
                            handler.postDelayed(this, 1000);
                        } catch (Exception e) {
                        }
                    }
                }
            }, 1000);

        } catch (Exception e) {
            LoggerUtil.logToFile(LoggerUtil.Level.ERROR, TAG, "CreateDevInfoAlertDialog", "exeption", e);
        }
    }

    public static CharSequence getQosInfo(Activity activity) {
        // Request all known Network information from QoS library
        QosInfo info = QosAPI.getQoSInfo(activity);
        if (info.connectedNetwork == null)
            return "";
        // The basic info as a string
        String strInfo = info.connectedNetwork.getType() + "\n";
        strInfo += info.connectedNetwork.getSignalDetails(true, true) + "\n";
        strInfo += info.connectedNetwork.getQualityDetails(true, true) + "\n";
        strInfo += info.connectedNetwork.getIdentifier() + "\n";

        return strInfo;

    }

    public static String watchActivity = null;
    public static long lastWatchActivity = 0;

    public static void watchHostApp(Context context, Class launchActivity, boolean bWatch) {
        if (bWatch && launchActivity != null) {
            LoggerUtil.logToFile(LoggerUtil.Level.ERROR, TAG, "watchHostApp", launchActivity.getCanonicalName());
            watchActivity = launchActivity.getCanonicalName();
        } else
            watchActivity = null;
        PreferenceKeys.getSecurePreferences(context).edit().putString("PREF_WATCH_ACTIVITY", watchActivity)
                .commit();
    }

    public static void checkHostApp(Context context) {
        watchActivity = PreferenceKeys.getSecurePreferences(context).getString("PREF_WATCH_ACTIVITY",
                watchActivity);
        if (watchActivity != null) {
            if (System.currentTimeMillis() - lastWatchActivity < 60000 || SystemClock.elapsedRealtime() > 300000)
                return;
            lastWatchActivity = System.currentTimeMillis();
            //int app = Global.getAppImportance (context.getPackageName(), context);
            boolean isRunning = isRunning(context, context.getPackageName());
            // 1 indicates foreground app and 2 indicates background (but not service-only)
            if (isRunning)
                return;
            try {
                // otherwise, launch the apps main activity
                Intent intent = new Intent();
                intent.setClassName(context, watchActivity);
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                context.startActivity(intent);
                LoggerUtil.logToFile(LoggerUtil.Level.ERROR, TAG, "checkHostApp mode=", "start " + watchActivity);
            } catch (Exception e) {
                LoggerUtil.logToFile(LoggerUtil.Level.ERROR, TAG, "checkHostApp", "exception", e);
            }
        }
    }

    static public boolean isMMCServiceRunning() {
        return Global.isMMCServiceRunning();
    }

    static public boolean isRunning(Context context, String PackageName) {
        // Get the Activity Manager
        ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);

        // Get a list of running tasks, we are only interested in the last one,
        // the top most so we give a 1 as parameter so we only get the topmost.
        List<ActivityManager.RunningTaskInfo> rtasks = manager.getRunningTasks(10000);
        // Get the info we need for comparison.
        for (ActivityManager.RunningTaskInfo task : rtasks) {
            ComponentName c = task.baseActivity;
            if (c != null && c.toString().indexOf(PackageName) >= 0)
                return true;
        }

        //        List<ActivityManager.AppTask> tasks = manager.getAppTasks();
        //
        //        // Get the info we need for comparison.
        //        for (ActivityManager.AppTask task:tasks) {
        //            ComponentName c = task.getTaskInfo().origActivity;
        //            if (c == null && c.equals(watchActivity))
        //                return true;
        //        }

        // If not then our app is not on the foreground.
        return false;
    }
}