public class

DataUsageListener

extends Object
/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.phone;

import com.android.phone.R;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceScreen;
import android.net.Uri;
import android.net.ThrottleManager;
import android.util.Log;

import java.util.Calendar;
import java.util.GregorianCalendar;
import java.text.DateFormat;

/**
 * Listener for broadcasts from ThrottleManager
 */
public class DataUsageListener {

    private ThrottleManager mThrottleManager;
    private Preference mCurrentUsagePref = null;
    private Preference mTimeFramePref = null;
    private Preference mThrottleRatePref = null;
    private Preference mSummaryPref = null;
    private PreferenceScreen mPrefScreen = null;
    private boolean mSummaryPrefEnabled = false;

    private final Context mContext;
    private IntentFilter mFilter;
    private BroadcastReceiver mReceiver;

    private int mPolicyThrottleValue;  //in kbps
    private long mPolicyThreshold;
    private int mCurrentThrottleRate;
    private long mDataUsed;
    private Calendar mStart;
    private Calendar mEnd;

    public DataUsageListener(Context context, Preference summary, PreferenceScreen prefScreen) {
        mContext = context;
        mSummaryPref = summary;
        mPrefScreen = prefScreen;
        mSummaryPrefEnabled = true;
        initialize();
    }

    public DataUsageListener(Context context, Preference currentUsage,
            Preference timeFrame, Preference throttleRate) {
        mContext = context;
        mCurrentUsagePref = currentUsage;
        mTimeFramePref = timeFrame;
        mThrottleRatePref = throttleRate;
        initialize();
    }

    private void initialize() {

        mThrottleManager = (ThrottleManager) mContext.getSystemService(Context.THROTTLE_SERVICE);

        mStart = GregorianCalendar.getInstance();
        mEnd = GregorianCalendar.getInstance();

        mFilter = new IntentFilter();
        mFilter.addAction(ThrottleManager.THROTTLE_POLL_ACTION);
        mFilter.addAction(ThrottleManager.THROTTLE_ACTION);
        mFilter.addAction(ThrottleManager.POLICY_CHANGED_ACTION);

        mReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
                if (ThrottleManager.THROTTLE_POLL_ACTION.equals(action)) {
                    updateUsageStats(intent.getLongExtra(ThrottleManager.EXTRA_CYCLE_READ, 0),
                        intent.getLongExtra(ThrottleManager.EXTRA_CYCLE_WRITE, 0),
                        intent.getLongExtra(ThrottleManager.EXTRA_CYCLE_START, 0),
                        intent.getLongExtra(ThrottleManager.EXTRA_CYCLE_END, 0));
                } else if (ThrottleManager.POLICY_CHANGED_ACTION.equals(action)) {
                    updatePolicy();
                } else if (ThrottleManager.THROTTLE_ACTION.equals(action)) {
                    updateThrottleRate(intent.getIntExtra(ThrottleManager.EXTRA_THROTTLE_LEVEL, -1));
                }
            }
        };
    }

    void resume() {
        mContext.registerReceiver(mReceiver, mFilter);
        updatePolicy();
    }

    void pause() {
        mContext.unregisterReceiver(mReceiver);
    }

    private void updatePolicy() {
        /* Fetch values for default interface */
        mPolicyThrottleValue = mThrottleManager.getCliffLevel(null, 1);
        mPolicyThreshold = mThrottleManager.getCliffThreshold(null, 1);

        if (mSummaryPref != null) { /* Settings preference */
            /**
             * Remove data usage preference in settings
             * if policy change disables throttling
             */
            if (mPolicyThreshold == 0) {
                if (mSummaryPrefEnabled) {
                    mPrefScreen.removePreference(mSummaryPref);
                    mSummaryPrefEnabled = false;
                }
            } else {
                if (!mSummaryPrefEnabled) {
                    mSummaryPrefEnabled = true;
                    mPrefScreen.addPreference(mSummaryPref);
                }
            }
        }
        updateUI();
    }

    private void updateThrottleRate(int throttleRate) {
        mCurrentThrottleRate = throttleRate;
        updateUI();
    }

    private void updateUsageStats(long readByteCount, long writeByteCount,
            long startTime, long endTime) {
        mDataUsed = readByteCount + writeByteCount;
        mStart.setTimeInMillis(startTime);
        mEnd.setTimeInMillis(endTime);
        updateUI();
    }

    private void updateUI() {
        if (mPolicyThreshold == 0)
            return;
        int dataUsedPercent = (int) ((mDataUsed * 100) / mPolicyThreshold);

        long cycleTime = mEnd.getTimeInMillis() - mStart.getTimeInMillis();
        long currentTime = GregorianCalendar.getInstance().getTimeInMillis()
                            - mStart.getTimeInMillis();

        int cycleThroughPercent = (cycleTime == 0) ? 0 : (int) ((currentTime * 100) / cycleTime);

        Calendar cal = Calendar.getInstance();
        cal.setTimeInMillis(cycleTime - currentTime);
        int daysLeft = cal.get(Calendar.DAY_OF_YEAR);
        //cal.get() returns 365 for less than a day
        if (daysLeft >= 365) daysLeft = 0;

        if (mCurrentUsagePref != null) {
            /* Update the UI based on whether we are in a throttled state */
            if (mCurrentThrottleRate > 0) {
                mCurrentUsagePref.setSummary(mContext.getString(
                        R.string.throttle_data_rate_reduced_subtext,
                        toReadable(mPolicyThreshold),
                        mCurrentThrottleRate));
            } else {
                mCurrentUsagePref.setSummary(mContext.getString(
                        R.string.throttle_data_usage_subtext,
                        toReadable(mDataUsed), dataUsedPercent, toReadable(mPolicyThreshold)));
            }
        }
        if (mTimeFramePref != null) {
            mTimeFramePref.setSummary(mContext.getString(R.string.throttle_time_frame_subtext,
                        cycleThroughPercent, daysLeft,
                        DateFormat.getDateInstance(DateFormat.SHORT).format(mEnd.getTime())));
        }
        if (mThrottleRatePref != null) {
            mThrottleRatePref.setSummary(mContext.getString(R.string.throttle_rate_subtext,
                    mPolicyThrottleValue));
        }
        if (mSummaryPref != null && mSummaryPrefEnabled) {

            /* Update the UI based on whether we are in a throttled state */
            if (mCurrentThrottleRate > 0) {
                mSummaryPref.setSummary(mContext.getString(
                        R.string.throttle_data_rate_reduced_subtext,
                        toReadable(mPolicyThreshold),
                        mCurrentThrottleRate));
            } else {
                mSummaryPref.setSummary(mContext.getString(R.string.throttle_status_subtext,
                            toReadable(mDataUsed),
                            dataUsedPercent,
                            toReadable(mPolicyThreshold),
                            daysLeft,
                            DateFormat.getDateInstance(DateFormat.SHORT).format(mEnd.getTime())));
            }
        }
    }

    private String toReadable (long data) {
        long KB = 1024;
        long MB = 1024 * KB;
        long GB = 1024 * MB;
        long TB = 1024 * GB;
        String ret;

        if (data < KB) {
            ret = data + " bytes";
        } else if (data < MB) {
            ret = (data / KB) + " KB";
        } else if (data < GB) {
            ret = (data / MB) + " MB";
        } else if (data < TB) {
            ret = (data / GB) + " GB";
        } else {
            ret = (data / TB) + " TB";
        }
        return ret;
    }
}