Android Open Source - volumescheduler Volume Scheduler Service






From Project

Back to project page volumescheduler.

License

The source code is released under:

GNU General Public License

If you think the Android project volumescheduler listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Copyright (c) 2014 RuneCasters IT Solutions.
 *//ww  w .j  av a2s.  c  o m
 * This file is part of VolumeScheduler.
 *
 * VolumeScheduler 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.
 *
 * VolumeScheduler 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 VolumeScheduler.  If not, see <http://www.gnu.org/licenses/>.
 */

package au.com.runecasters.volumescheduler.service;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.media.AudioManager;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.provider.CalendarContract.Events;
import android.util.Log;
import au.com.runecasters.volumescheduler.model.DatabaseHelper;
import au.com.runecasters.volumescheduler.model.SchedulerRule;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;

public class VolumeSchedulerService extends Service {
    public static final String TAG = "Service";
    private static final List<String> EVENT_PROJECTION = new ArrayList<String>() {{
        add(Events._ID);
        add(Events.CALENDAR_ID);
        add(Events.TITLE);
        add(Events.EVENT_LOCATION);
        add(Events.DESCRIPTION);
        add(Events.AVAILABILITY);
        add(Events.DTSTART);
        add(Events.DTEND);
    }};
    private AudioManager mAudioManager;
    private AlarmManager mAlarmManager;
    private PendingIntent mPendingIntent;
    private List<SchedulerRule> mRuleList;
    private HandlerThread mHandlerThread;
    private Handler mHandler;
    private Runnable mRunTriggersRunnable = new Runnable() {
        @Override
        public void run() {
            runTriggers();
        }
    };
    private SharedPreferences mSharedPrefs;
    private long mCurrentRule;
    private int mCurrentRulePriority;
    private boolean mIgnorePriority;
    private int mNormVolRingtone;
    private int mNormVolNotification;
    private int mNormVolMedia;
    private int mNormVolAlarm;
    private int mNormRingerMode;

    public VolumeSchedulerService() {
    }

    @Override
    public void onCreate() {
        super.onCreate();
        createBackgroundThread();
        updateTriggers(this);
        mIgnorePriority = false;
        mSharedPrefs = getSharedPreferences("VolumeScheduler", MODE_PRIVATE);
        mCurrentRule = mSharedPrefs.getLong("currentRule", -1);
        mCurrentRulePriority = mSharedPrefs.getInt("currentRulePriority", -1);
        mNormVolRingtone = mSharedPrefs.getInt("normVolRingtone", -1);
        mNormVolNotification = mSharedPrefs.getInt("normVolNotification", -1);
        mNormVolMedia = mSharedPrefs.getInt("normVolMedia", -1);
        mNormVolAlarm = mSharedPrefs.getInt("normVolAlarm", -1);
        mNormRingerMode = mSharedPrefs.getInt("normRingerMode", -1);
        mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mHandlerThread.quit();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (intent != null) {
            String intentAction = intent.getAction();
            if(intentAction.equalsIgnoreCase(Intent.ACTION_BOOT_COMPLETED) ||
                    intentAction.equals(VolumeSchedulerReceiver.START_TRIGGERS)) {
                if (mAlarmManager == null && mPendingIntent == null) {
                    setTriggers(this);
                }
            } else if (intentAction.equals(VolumeSchedulerReceiver.STOP_TRIGGERS)) {
                removeTriggers();
            } else if (intentAction.equals(VolumeSchedulerReceiver.RUN_TRIGGERS)) {
                mHandler.post(mRunTriggersRunnable);
            } else if (intentAction.equals(VolumeSchedulerReceiver.UPDATE_TRIGGERS)) {
                updateTriggers(this);
            }
        }
        return START_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    private void createBackgroundThread() {
        mHandlerThread = new HandlerThread("VolumeSchedulerBGThread");
        mHandlerThread.start();
        mHandler = new Handler(mHandlerThread.getLooper());
    }

    public void setTriggers(Context context) {
        Intent alarmIntent = new Intent(context, VolumeSchedulerReceiver.class);
        alarmIntent.setAction(VolumeSchedulerReceiver.RUN_TRIGGERS);
        mPendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        mAlarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
        mAlarmManager.set(AlarmManager.RTC, Calendar.getInstance().getTimeInMillis(), mPendingIntent);
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(System.currentTimeMillis());
        calendar.set(Calendar.MILLISECOND, 0);
        calendar.set(Calendar.SECOND, 0);
        mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 60000, mPendingIntent);
        Log.i(TAG, "Service started");
    }

    public void removeTriggers() {
        if (mAlarmManager != null && mPendingIntent != null) {
            mAlarmManager.cancel(mPendingIntent);
            mAlarmManager = null;
            mPendingIntent = null;
        }
        Log.i(TAG, "Service stopped");
        deactivateRule();
        stopSelf();
    }

    public void updateTriggers(Context context) {
        DatabaseHelper dbHelper = DatabaseHelper.getInstance(context);
        mRuleList = dbHelper.getRules();
        mIgnorePriority = true;
        Log.i(TAG, "Trigger rules updated from database");
    }

    public void runTriggers() {
//        Log.v(TAG, "Running triggers");
        int listLength = mRuleList.size();
        boolean activeRuleStillExists = false;
        long oldCurrentRule = mCurrentRule;
        for (int priority = 1; priority <= listLength; priority++) {
            if (priority <= mCurrentRulePriority || mCurrentRulePriority < 0 || mIgnorePriority) {
                SchedulerRule rule = mRuleList.get(priority-1);
                if (rule.getRuleID() == mCurrentRule) activeRuleStillExists = true;
                int ruleType = rule.getRuleType();
                if (ruleType == SchedulerRule.CALENDAR_RULE) {
                    runCalendarEventTrigger(rule, priority);
                } else if (ruleType == SchedulerRule.TIME_RULE) {
                    runTimeDayRuleTrigger(rule, priority);
                }
            }
        }
        if (!activeRuleStillExists && mCurrentRule == oldCurrentRule && mCurrentRule >= 0) deactivateRule();
        mIgnorePriority = false;
    }

    private void runCalendarEventTrigger(SchedulerRule rule, int priority) {
//        Log.v(TAG, "Running CalendarEventTrigger on rule " + rule);
        Cursor eventCursor = getContentResolver().query(Events.CONTENT_URI,
                EVENT_PROJECTION.toArray(new String[EVENT_PROJECTION.size()]),
                Events.CALENDAR_ID + " = " + rule.getCalendarID(),
                null, null);
        boolean triggered = false;
        long currentTime = System.currentTimeMillis();
        while (eventCursor.moveToNext()) {
            long startTime = eventCursor.getLong(EVENT_PROJECTION.indexOf(Events.DTSTART));
            long endTime = eventCursor.getLong(EVENT_PROJECTION.indexOf(Events.DTEND));
            String eventTitle = eventCursor.getString(EVENT_PROJECTION.indexOf(Events.TITLE));
            String eventLoc = eventCursor.getString(EVENT_PROJECTION.indexOf(Events.EVENT_LOCATION));
            String eventDesc = eventCursor.getString(EVENT_PROJECTION.indexOf(Events.DESCRIPTION));
            // Because Google apparently stores empty strings as null instead of "" in their events table
            eventTitle = eventTitle == null ? "" : eventTitle.toUpperCase(Locale.US);
            eventLoc = eventLoc == null ? "" : eventLoc.toUpperCase(Locale.US);
            eventDesc = eventDesc == null ? "" : eventDesc.toUpperCase(Locale.US);
            int eventAvail = eventCursor.getInt(EVENT_PROJECTION.indexOf(Events.AVAILABILITY));
            if (currentTime >= startTime && currentTime < endTime &&
                    (eventTitle.contains(rule.getSearchTitle().toUpperCase(Locale.US)) &&
                    eventLoc.contains(rule.getSearchLocation().toUpperCase(Locale.US)) &&
                    eventDesc.contains(rule.getSearchDesc().toUpperCase(Locale.US)) &&
                    (rule.getAvailability() < 0 || eventAvail == rule.getAvailability()))) {
                triggered = true;
                if (rule.getRuleID() != mCurrentRule || mIgnorePriority) {
//                    Log.v(TAG, "Calendar Rule \"" + rule + "\" Activated");
                    activateRule(rule, priority);
                }
                mIgnorePriority = false;
            }
        }
        if (!triggered && rule.getRuleID() == mCurrentRule) {
//            Log.v(TAG, "Calendar Rule \"" + rule + "\" Deactivated");
            deactivateRule();
        }
        eventCursor.close();
    }

    private void runTimeDayRuleTrigger(SchedulerRule rule, int priority) {
//        Log.v(TAG, "Running TimeDayRuleTrigger on rule " + rule);
        Calendar currentTime = Calendar.getInstance();
        if (rule.getDaysOfWeek()[currentTime.get(Calendar.DAY_OF_WEEK) - 1]) {
            int[] startTime = rule.getStartTime();
            int[] endTime = rule.getEndTime();
            int currentMinuteOfDay = currentTime.get(Calendar.HOUR_OF_DAY) * 60 + currentTime.get(Calendar.MINUTE);
            int startMinuteOfDay = startTime[0] * 60 + startTime[1];
            int endMinuteOfDay = endTime[0] * 60 + endTime[1];
            // Check for overnight rule - times straddling midnight
            boolean overnightRule = endMinuteOfDay < startMinuteOfDay;
            if ((startMinuteOfDay <= currentMinuteOfDay && endMinuteOfDay > currentMinuteOfDay) ||
                    (overnightRule && !(startMinuteOfDay > currentMinuteOfDay && endMinuteOfDay <= currentMinuteOfDay)) ||
                    startMinuteOfDay == endMinuteOfDay) {
                if (rule.getRuleID() != mCurrentRule || mIgnorePriority) {
//                    Log.v(TAG, "Time/Day Rule \"" + rule + "\" Activated");
                    activateRule(rule, priority);
                }
                mIgnorePriority = false;
            } else {
                if (rule.getRuleID() == mCurrentRule) {
//                    Log.v(TAG, "Time/Day Rule \"" + rule + "\" Deactivated");
                    deactivateRule();
                }
            }
        }
    }

    private void activateRule(SchedulerRule rule, int priority) {
        deactivateRule(); // Deactivate any current rule
        SharedPreferences.Editor sharedPrefsEditor = mSharedPrefs.edit();
        if (rule.changingRingtone() && mNormVolNotification < 0) {
            mNormVolRingtone = mAudioManager.getStreamVolume(AudioManager.STREAM_RING);
            sharedPrefsEditor.putInt("normVolRingtone", mNormVolRingtone);
        }
        if (rule.changingNotification() && mNormVolNotification < 0) {
            mNormVolNotification = mAudioManager.getStreamVolume(AudioManager.STREAM_NOTIFICATION);
            sharedPrefsEditor.putInt("normVolNotification", mNormVolNotification);
        }
        if (rule.changingMedia() && mNormVolMedia < 0) {
            mNormVolMedia = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
            sharedPrefsEditor.putInt("normVolMedia", mNormVolMedia);
        }
        if (rule.changingAlarm() && mNormVolAlarm < 0) {
            mNormVolAlarm = mAudioManager.getStreamVolume(AudioManager.STREAM_ALARM);
            sharedPrefsEditor.putInt("normVolAlarm", mNormVolAlarm);
        }
        if (rule.isVibrate() && mNormRingerMode < 0) {
            mNormRingerMode = mAudioManager.getRingerMode();
            sharedPrefsEditor.putInt("normRingerMode", mNormRingerMode);
        }
        mCurrentRule = rule.getRuleID();
        mCurrentRulePriority = priority;
        sharedPrefsEditor.putLong("currentRule", mCurrentRule);
        sharedPrefsEditor.putInt("currentRulePriority", mCurrentRulePriority);
        sharedPrefsEditor.commit();
        if (rule.getVolRingtone() == 0 && rule.getVolNotification() == 0) {
            int vibrateSetting = rule.isVibrate() ?
                    AudioManager.RINGER_MODE_VIBRATE : AudioManager.RINGER_MODE_SILENT;
            mAudioManager.setRingerMode(vibrateSetting);
        } else {
            if (rule.changingRingtone()) {
                mAudioManager.setStreamVolume(AudioManager.STREAM_RING, rule.getVolRingtone(), 0);
            }
            if (rule.changingNotification()) {
                mAudioManager.setStreamVolume(AudioManager.STREAM_NOTIFICATION, rule.getVolNotification(), 0);
            }
        }
        if (rule.changingMedia()) {
            mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, rule.getVolMedia(), 0);
        }
        if (rule.changingAlarm()) {
            mAudioManager.setStreamVolume(AudioManager.STREAM_ALARM, rule.getVolAlarm(), 0);
        }
    }

    private void deactivateRule() {
        SharedPreferences.Editor sharedPrefsEditor = mSharedPrefs.edit();
        mCurrentRule = -1;
        mCurrentRulePriority = -1;
        sharedPrefsEditor.remove("currentRule");
        sharedPrefsEditor.remove("currentRulePriority");
        if (mNormRingerMode >= 0) {
            mAudioManager.setRingerMode(mNormRingerMode);
            mNormRingerMode = -1;
            sharedPrefsEditor.remove("normVolRingtone");
        }
        if (mNormVolRingtone >= 0) {
            mAudioManager.setStreamVolume(AudioManager.STREAM_RING, mNormVolRingtone, 0);
            mNormVolRingtone = -1;
            sharedPrefsEditor.remove("normRingerMode");
        }
        if (mNormVolNotification >= 0) {
            mAudioManager.setStreamVolume(AudioManager.STREAM_NOTIFICATION, mNormVolNotification, 0);
            mNormVolNotification = -1;
            sharedPrefsEditor.remove("normVolNotification");
        }
        if (mNormVolMedia >= 0) {
            mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, mNormVolMedia, 0);
            mNormVolMedia = -1;
            sharedPrefsEditor.remove("normVolMedia");
        }
        if (mNormVolAlarm >= 0) {
            mAudioManager.setStreamVolume(AudioManager.STREAM_ALARM, mNormVolAlarm, 0);
            mNormVolAlarm = -1;
            sharedPrefsEditor.remove("normVolAlarm");
        }
        sharedPrefsEditor.commit();
//        Log.v(TAG, "All rules deactivated");
    }

    private void changeVolume(int stream, int newVol) {
        // Because Android doesn't seem to always respect setStreamVolume
        while (mAudioManager.getStreamVolume(stream) != newVol) {
            mAudioManager.setStreamVolume(stream, newVol, 0);
        }
    }

    public static class VolumeSchedulerReceiver extends BroadcastReceiver {
        public static final String START_TRIGGERS = "au.com.runecasters.volumescheduler.service.START_TRIGGERS";
        public static final String STOP_TRIGGERS = "au.com.runecasters.volumescheduler.service.STOP_TRIGGERS";
        public static final String RUN_TRIGGERS = "au.com.runecasters.volumescheduler.service.RUN_TRIGGERS";
        public static final String UPDATE_TRIGGERS = "au.com.runecasters.volumescheduler.service.UPDATE_TRIGGERS";

        @Override
        public void onReceive(Context context, Intent intent) {
            intent.setClass(context, VolumeSchedulerService.class);
            context.startService(intent);
        }
    }
}




Java Source Code List

au.com.runecasters.volumescheduler.app.AboutActivity.java
au.com.runecasters.volumescheduler.app.AdFragment.java
au.com.runecasters.volumescheduler.app.ApplicationTest.java
au.com.runecasters.volumescheduler.app.CalendarRuleFragment.java
au.com.runecasters.volumescheduler.app.MainActivity.java
au.com.runecasters.volumescheduler.app.RuleActivity.java
au.com.runecasters.volumescheduler.app.TimeRuleFragment.java
au.com.runecasters.volumescheduler.app.VolumeRuleFragment.java
au.com.runecasters.volumescheduler.model.DatabaseHelper.java
au.com.runecasters.volumescheduler.model.SchedulerRule.java
au.com.runecasters.volumescheduler.service.VolumeSchedulerService.java
au.com.runecasters.volumescheduler.view.DialogFragments.java
au.com.runecasters.volumescheduler.view.RuleListAdapter.java