Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 58871ff9 authored by Chaohui Wang's avatar Chaohui Wang Committed by Android (Google) Code Review
Browse files

Merge "Improve the latency of DataUsageList" into main

parents e9d57e01 22057624
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -22,7 +22,9 @@
        android:title="@string/summary_placeholder">

        <com.android.settings.datausage.ChartDataUsagePreference
            android:key="chart_data" />
            android:key="chart_data"
            settings:controller="com.android.settings.datausage.ChartDataUsagePreferenceController"
            />

        <Preference
            android:key="non_carrier_data_usage_warning"
+4 −1
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import android.telephony.SubscriptionManager;
import android.util.ArraySet;
import android.util.IconDrawableFactory;
import android.util.Log;
import android.util.Range;
import android.view.View;
import android.widget.AdapterView;

@@ -472,7 +473,9 @@ public class AppDataUsage extends DataUsageBaseFragment implements OnPreferenceC
                        List<NetworkCycleDataForUid> data) {
                    mUsageData = data;
                    mCycle.setOnItemSelectedListener(mCycleListener);
                    mCycleAdapter.updateCycleList(data);
                    mCycleAdapter.updateCycleList(data.stream()
                            .map(cycle -> new Range<>(cycle.getStartTime(), cycle.getEndTime()))
                            .toList());
                    if (mSelectedCycle > 0L) {
                        final int numCycles = data.size();
                        int position = 0;
+38 −32
Original line number Diff line number Diff line
@@ -26,15 +26,17 @@ import android.util.AttributeSet;
import android.util.DataUnit;
import android.util.SparseIntArray;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;

import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.datausage.lib.NetworkCycleChartData;
import com.android.settings.datausage.lib.NetworkUsageData;
import com.android.settings.widget.UsageView;
import com.android.settingslib.net.NetworkCycleChartData;
import com.android.settingslib.net.NetworkCycleData;

import java.util.ArrayList;
import java.util.Comparator;
@@ -51,8 +53,8 @@ public class ChartDataUsagePreference extends Preference {
    private final int mWarningColor;
    private final int mLimitColor;

    private Resources mResources;
    private NetworkPolicy mPolicy;
    private final Resources mResources;
    @Nullable private NetworkPolicy mPolicy;
    private long mStart;
    private long mEnd;
    private NetworkCycleChartData mNetworkCycleChartData;
@@ -67,18 +69,16 @@ public class ChartDataUsagePreference extends Preference {
    }

    @Override
    public void onBindViewHolder(PreferenceViewHolder holder) {
    public void onBindViewHolder(@NonNull PreferenceViewHolder holder) {
        super.onBindViewHolder(holder);
        final UsageView chart = (UsageView) holder.findViewById(R.id.data_usage);
        if (mNetworkCycleChartData == null) {
            return;
        }

        final UsageView chart = holder.itemView.requireViewById(R.id.data_usage);
        final int top = getTop();
        chart.clearPaths();
        chart.configureGraph(toInt(mEnd - mStart), top);
        calcPoints(chart, mNetworkCycleChartData.getUsageBuckets());
        setupContentDescription(chart, mNetworkCycleChartData.getUsageBuckets());
        if (mNetworkCycleChartData != null) {
            calcPoints(chart, mNetworkCycleChartData.getDailyUsage());
            setupContentDescription(chart, mNetworkCycleChartData.getDailyUsage());
        }
        chart.setBottomLabels(new CharSequence[] {
                Utils.formatDateRange(getContext(), mStart, mStart),
                Utils.formatDateRange(getContext(), mEnd, mEnd),
@@ -88,23 +88,21 @@ public class ChartDataUsagePreference extends Preference {
    }

    public int getTop() {
        final long totalData = mNetworkCycleChartData.getTotalUsage();
        final long totalData =
                mNetworkCycleChartData != null ? mNetworkCycleChartData.getTotal().getUsage() : 0;
        final long policyMax =
            mPolicy != null ? Math.max(mPolicy.limitBytes, mPolicy.warningBytes) : 0;
        return (int) (Math.max(totalData, policyMax) / RESOLUTION);
    }

    @VisibleForTesting
    void calcPoints(UsageView chart, List<NetworkCycleData> usageSummary) {
        if (usageSummary == null) {
            return;
        }
    void calcPoints(UsageView chart, @NonNull List<NetworkUsageData> usageSummary) {
        final SparseIntArray points = new SparseIntArray();
        points.put(0, 0);

        final long now = System.currentTimeMillis();
        long totalData = 0;
        for (NetworkCycleData data : usageSummary) {
        for (NetworkUsageData data : usageSummary) {
            final long startTime = data.getStartTime();
            if (startTime > now) {
                break;
@@ -112,7 +110,7 @@ public class ChartDataUsagePreference extends Preference {
            final long endTime = data.getEndTime();

            // increment by current bucket total
            totalData += data.getTotalUsage();
            totalData += data.getUsage();

            if (points.size() == 1) {
                points.put(toInt(startTime - mStart) - 1, -1);
@@ -125,7 +123,8 @@ public class ChartDataUsagePreference extends Preference {
        }
    }

    private void setupContentDescription(UsageView chart, List<NetworkCycleData> usageSummary) {
    private void setupContentDescription(
            UsageView chart, @NonNull List<NetworkUsageData> usageSummary) {
        final Context context = getContext();
        final StringBuilder contentDescription = new StringBuilder();
        final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_MONTH;
@@ -137,7 +136,7 @@ public class ChartDataUsagePreference extends Preference {
                .getString(R.string.data_usage_chart_brief_content_description, startDate, endDate);
        contentDescription.append(briefContentDescription);

        if (usageSummary == null || usageSummary.isEmpty()) {
        if (usageSummary.isEmpty()) {
            final String noDataContentDescription = mResources
                    .getString(R.string.data_usage_chart_no_data_content_description);
            contentDescription.append(noDataContentDescription);
@@ -170,17 +169,17 @@ public class ChartDataUsagePreference extends Preference {
     * Collect the date of the same percentage, e.g., Aug 2 to Aug 22: 0%; Aug 23: 2%.
     */
    @VisibleForTesting
    List<DataUsageSummaryNode> getDensedStatsData(List<NetworkCycleData> usageSummary) {
    List<DataUsageSummaryNode> getDensedStatsData(@NonNull List<NetworkUsageData> usageSummary) {
        final List<DataUsageSummaryNode> dataUsageSummaryNodes = new ArrayList<>();
        final long overallDataUsage = Math.max(1L, usageSummary.stream()
                .mapToLong(NetworkCycleData::getTotalUsage).sum());
                .mapToLong(NetworkUsageData::getUsage).sum());
        long cumulatedDataUsage = 0L;
        int cumulatedDataUsagePercentage = 0;

        // Collect List of DataUsageSummaryNode for data usage percentage information.
        for (NetworkCycleData data : usageSummary) {
            cumulatedDataUsage += data.getTotalUsage();
            cumulatedDataUsagePercentage = (int) ((cumulatedDataUsage * 100) / overallDataUsage);
        for (NetworkUsageData data : usageSummary) {
            cumulatedDataUsage += data.getUsage();
            int cumulatedDataUsagePercentage =
                    (int) ((cumulatedDataUsage * 100) / overallDataUsage);

            final DataUsageSummaryNode node = new DataUsageSummaryNode(data.getStartTime(),
                    data.getEndTime(), cumulatedDataUsagePercentage);
@@ -268,8 +267,9 @@ public class ChartDataUsagePreference extends Preference {
        }

        if (policy.warningBytes != NetworkPolicy.WARNING_DISABLED) {
            chart.setDividerLoc((int) (policy.warningBytes / RESOLUTION));
            float weight = policy.warningBytes / RESOLUTION / (float) top;
            int dividerLoc = (int) (policy.warningBytes / RESOLUTION);
            chart.setDividerLoc(dividerLoc);
            float weight = dividerLoc / (float) top;
            float above = 1 - weight;
            chart.setSideLabelWeights(above, weight);
            middleVisibility = mWarningColor;
@@ -289,15 +289,21 @@ public class ChartDataUsagePreference extends Preference {
        return new SpannableStringBuilder().append(label, new ForegroundColorSpan(mLimitColor), 0);
    }

    public void setNetworkPolicy(NetworkPolicy policy) {
    /** Sets network policy. */
    public void setNetworkPolicy(@Nullable NetworkPolicy policy) {
        mPolicy = policy;
        notifyChanged();
    }

    /** Sets time. */
    public void setTime(long start, long end) {
        mStart = start;
        mEnd = end;
        notifyChanged();
    }

    public void setNetworkCycleData(NetworkCycleChartData data) {
        mNetworkCycleChartData = data;
        mStart = data.getStartTime();
        mEnd = data.getEndTime();
        notifyChanged();
    }
}
+82 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.settings.datausage

import android.content.Context
import android.net.NetworkTemplate
import androidx.annotation.OpenForTesting
import androidx.annotation.VisibleForTesting
import androidx.lifecycle.LifecycleCoroutineScope
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.preference.PreferenceScreen
import com.android.settings.core.BasePreferenceController
import com.android.settings.datausage.lib.INetworkCycleDataRepository
import com.android.settings.datausage.lib.NetworkCycleDataRepository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

@OpenForTesting
open class ChartDataUsagePreferenceController(context: Context, preferenceKey: String) :
    BasePreferenceController(context, preferenceKey) {

    private lateinit var repository: INetworkCycleDataRepository
    private lateinit var preference: ChartDataUsagePreference
    private lateinit var lifecycleScope: LifecycleCoroutineScope

    open fun init(template: NetworkTemplate) {
        this.repository = NetworkCycleDataRepository(mContext, template)
    }

    @VisibleForTesting
    fun init(repository: INetworkCycleDataRepository) {
        this.repository = repository
    }

    override fun getAvailabilityStatus() = AVAILABLE

    override fun displayPreference(screen: PreferenceScreen) {
        super.displayPreference(screen)
        preference = screen.findPreference(preferenceKey)!!
    }

    override fun onViewCreated(viewLifecycleOwner: LifecycleOwner) {
        lifecycleScope = viewLifecycleOwner.lifecycleScope
    }

    /**
     * Sets whether billing cycle modifiable.
     *
     * Don't bind warning / limit sweeps if not modifiable.
     */
    open fun setBillingCycleModifiable(isModifiable: Boolean) {
        preference.setNetworkPolicy(
            if (isModifiable) repository.getPolicy() else null
        )
    }

    fun update(startTime: Long, endTime: Long) {
        preference.setTime(startTime, endTime)
        lifecycleScope.launch {
            val chartData = withContext(Dispatchers.Default) {
                repository.querySummary(startTime, endTime)
            }
            preference.setNetworkCycleData(chartData)
        }
    }
}
+4 −4
Original line number Diff line number Diff line
@@ -14,9 +14,9 @@
package com.android.settings.datausage;

import android.content.Context;
import android.util.Range;

import com.android.settings.Utils;
import com.android.settingslib.net.NetworkCycleData;
import com.android.settingslib.widget.SettingsSpinnerAdapter;

import java.util.List;
@@ -62,15 +62,15 @@ public class CycleAdapter extends SettingsSpinnerAdapter<CycleAdapter.CycleItem>
     * Rebuild list based on network data. Always selects the newest item,
     * updating the inspection range on chartData.
     */
    public void updateCycleList(List<? extends NetworkCycleData> cycleData) {
    public void updateCycleList(List<Range<Long>> cycleData) {
        // stash away currently selected cycle to try restoring below
        final CycleAdapter.CycleItem previousItem = (CycleAdapter.CycleItem)
                mSpinner.getSelectedItem();
        clear();

        final Context context = getContext();
        for (NetworkCycleData data : cycleData) {
            add(new CycleAdapter.CycleItem(context, data.getStartTime(), data.getEndTime()));
        for (Range<Long> cycle : cycleData) {
            add(new CycleAdapter.CycleItem(context, cycle.getLower(), cycle.getUpper()));
        }

        // force pick the current cycle (first item)
Loading