com.noshufou.android.su.service.ResultService.java Source code

Java tutorial

Introduction

Here is the source code for com.noshufou.android.su.service.ResultService.java

Source

package com.noshufou.android.su.service;

import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.database.Cursor;
import android.net.Uri;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.widget.Toast;

import com.noshufou.android.su.HomeActivity;
import com.noshufou.android.su.R;
import com.noshufou.android.su.SuRequestReceiver;
import com.noshufou.android.su.preferences.Preferences;
import com.noshufou.android.su.provider.PermissionsProvider.Apps;
import com.noshufou.android.su.provider.PermissionsProvider.Logs;
import com.noshufou.android.su.util.Util;

public class ResultService extends IntentService {
    private static final String TAG = "Su.ResultService";

    public static final String EXTRA_ACTION = "action";
    public static final int ACTION_RESULT = 1;
    public static final int ACTION_RECYCLE = 2;

    final String LAST_NOTIFICATION_UID = "last_notification_uid";
    final String LAST_NOTIFICATION_TIME = "last_notification_time";

    public static final String[] PROJECTION = new String[] { Apps._ID, Apps.ALLOW, Apps.NOTIFICATIONS,
            Apps.LOGGING };

    private static final int COLUMN_ID = 0;
    private static final int COLUMN_ALLOW = 1;
    private static final int COLUMN_NOTIFICATIONS = 2;
    private static final int COLUMN_LOGGING = 3;

    // TODO: Add in a license check here
    //    private boolean mLicenseChecked = false;
    //    private boolean mLicensed = true;

    private SharedPreferences mPrefs = null;
    private boolean mNotify = true;
    private String mNotifyType = "toast";
    private boolean mLog = true;

    private Handler mHandler;

    public ResultService() {
        super(TAG);
    }

    @Override
    public void onCreate() {
        super.onCreate();

        mHandler = new Handler();
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        switch (intent.getIntExtra(EXTRA_ACTION, 0)) {
        case ACTION_RESULT:
            ensurePrefs();
            int callerUid = intent.getIntExtra(SuRequestReceiver.EXTRA_CALLERUID, 0);
            int allow = intent.getIntExtra(SuRequestReceiver.EXTRA_ALLOW, -1);
            String cmd = intent.getStringExtra(SuRequestReceiver.EXTRA_CMD);
            long currentTime = System.currentTimeMillis();

            long appId = -1;
            String appNotify = null;
            String appLog = null;

            // get what we need from the database
            Cursor c = getContentResolver().query(Uri.withAppendedPath(Apps.CONTENT_URI, "uid/" + callerUid),
                    PROJECTION, Apps.EXEC_CMD + "=?", new String[] { cmd }, null);
            if (c != null && c.moveToFirst()) {
                appId = c.getLong(COLUMN_ID);
                appNotify = c.getString(COLUMN_NOTIFICATIONS);
                appLog = c.getString(COLUMN_LOGGING);
            }
            c.close();

            sendNotification(appId, callerUid, allow, currentTime, appNotify);
            addLog(appId, callerUid, intent.getIntExtra(SuRequestReceiver.EXTRA_UID, 0), cmd, allow, currentTime,
                    appLog, intent.getIntExtra("all", 0));
            // No break statement here so that we can fall through and recycle the log
        case ACTION_RECYCLE:
            recycle();
            break;
        default:
            throw new IllegalArgumentException();
        }
    }

    private void sendNotification(long appId, int callerUid, int allow, long currentTime, String appNotify) {
        // Check to see if we should notify
        if ((appNotify == null && !mNotify) || (appNotify != null && appNotify.equals("0")) || allow == -1) {
            return;
        }
        final String notificationMessage = getString(
                allow == 1 ? R.string.notification_text_allow : R.string.notification_text_deny,
                Util.getAppName(this, callerUid, false));
        if (mNotifyType.equals("toast")) {
            ensurePrefs();
            int lastNotificationUid = mPrefs.getInt(LAST_NOTIFICATION_UID, 0);
            long lastNotificationTime = mPrefs.getLong(LAST_NOTIFICATION_TIME, 0);
            final int gravity = Integer.parseInt(mPrefs.getString(Preferences.TOAST_LOCATION, "0"));
            if (lastNotificationUid != callerUid || lastNotificationTime + (5 * 1000) < currentTime) {
                mHandler.post(new Runnable() {

                    @Override
                    public void run() {
                        Toast toast = Toast.makeText(getApplicationContext(), notificationMessage,
                                Toast.LENGTH_SHORT);
                        if (gravity > 0) {
                            toast.setGravity(gravity, 0, 0);
                        }
                        toast.show();
                    }

                });
                Editor editor = mPrefs.edit();
                editor.putInt(LAST_NOTIFICATION_UID, callerUid);
                editor.putLong(LAST_NOTIFICATION_TIME, currentTime);
                editor.commit();
            }
        } else if (mNotifyType.equals("status")) {
            NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            Intent notificationIntent = new Intent(this, HomeActivity.class);
            // TODO: Include extras to tell HomeActivity what to do
            PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
            Notification notification = new NotificationCompat.Builder(this).setSmallIcon(R.drawable.stat_su)
                    .setTicker(notificationMessage).setWhen(System.currentTimeMillis())
                    .setContentTitle(getText(R.string.app_name)).setContentText(notificationMessage)
                    .setContentIntent(contentIntent).setAutoCancel(true).setOnlyAlertOnce(true).getNotification();
            nm.notify(callerUid, notification);
        }
    }

    private void addLog(long appId, int callerUid, int execUid, String execCmd, int allow, long currentTime,
            String appLog, int all) {
        // Check to see if we should log
        if ((appLog == null && !mLog) || (appLog != null && appLog.equals("0")) || allow == -1) {
            return;
        }

        ContentValues values = new ContentValues();
        if (appId == -1) {
            // App was not found in the database, add a row for logging purposes
            values.put(Apps.UID, callerUid);
            values.put(Apps.PACKAGE, Util.getAppPackage(this, callerUid));
            values.put(Apps.NAME, Util.getAppName(this, callerUid, false));
            values.put(Apps.EXEC_UID, execUid);
            values.put(Apps.EXEC_CMD, execCmd);
            values.put(Apps.ALLOW, all == 0 ? Apps.AllowType.ASK : allow);
            appId = Long.parseLong(getContentResolver().insert(Apps.CONTENT_URI, values).getLastPathSegment());
        }

        values.clear();
        values.put(Logs.DATE, currentTime);
        values.put(Logs.TYPE, allow);
        getContentResolver().insert(Uri.withAppendedPath(Logs.CONTENT_URI, String.valueOf(appId)), values);
    }

    private void recycle() {
        ensurePrefs();
        if (!mPrefs.getBoolean(Preferences.DELETE_OLD_LOGS, true)) {
            // Log recycling is disabled, no need to go further
            return;
        }

        int limit = mPrefs.getInt(Preferences.LOG_ENTRY_LIMIT, 200);
        Cursor c = getContentResolver().query(Logs.CONTENT_URI, new String[] { "COUNT() as rows" }, null, null,
                null);
        c.moveToFirst();
        int count = c.getInt(0);
        c.close();
        if (count > limit) {
            c = getContentResolver().query(Logs.CONTENT_URI, new String[] { Logs._ID }, null, null,
                    Logs.DATE + " ASC");
            long id = 0;
            while (count > limit && c.moveToNext()) {
                id = c.getLong(0);
                count -= getContentResolver().delete(Logs.CONTENT_URI, Logs._ID + "=?",
                        new String[] { String.valueOf(id) });
            }
        }
    }

    private void ensurePrefs() {
        if (mPrefs == null) {
            mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
            // read some global settings that we need every time
            mNotify = mPrefs.getBoolean(Preferences.NOTIFICATIONS, true);
            mNotifyType = mPrefs.getString(Preferences.NOTIFICATION_TYPE, "toast");
            mLog = mPrefs.getBoolean(Preferences.LOGGING, true);
        }
    }
}