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

Commit b92e9d42 authored by Raff Tsai's avatar Raff Tsai
Browse files

Add BatteryFix Slice

Change-Id: I504df1e9caadced71cc37f8be9207ab9fd26f9ab
Fixes: 114807643
Test: manual
parent 4fc11cee
Loading
Loading
Loading
Loading
+65 −29
Original line number Diff line number Diff line
<?xml version="1.0" encoding="UTF-8"?>
<issues format="4">

    <issue
        id="LintError"
        severity="Error"
        message="No `.class` files were found in project &quot;.&quot;, so none of the classfile based checks could be run. Does the project need to be built first?"
        category="Lint"
        priority="10"
        summary="Lint Failure"
        explanation="This issue type represents a problem running lint itself. Examples include failure to find bytecode for source files (which means certain detectors could not be run), parsing errors in lint configuration files, etc.&#xA;These errors are not errors in your own code, but they are shown to make it clear that some checks were not completed.">
        <location
            file="."/>
    </issue>

    <issue
        id="HardCodedColor"
        severity="Error"
@@ -2553,7 +2541,7 @@
        errorLine2="                                                                                                                                                                       ~~~~~~~~~~~~~~~~~~~">
        <location
            file="res/values-en-rXC/strings.xml"
            line="2530"
            line="2533"
            column="168"/>
    </issue>

@@ -2569,7 +2557,7 @@
        errorLine2="                                                               ~~~~~~~~~~~~~~~~~~~">
        <location
            file="res/values-en-rAU/strings.xml"
            line="2531"
            line="2534"
            column="64"/>
    </issue>

@@ -2585,7 +2573,7 @@
        errorLine2="                                                               ~~~~~~~~~~~~~~~~~~~">
        <location
            file="res/values-en-rCA/strings.xml"
            line="2531"
            line="2534"
            column="64"/>
    </issue>

@@ -2601,7 +2589,7 @@
        errorLine2="                                                               ~~~~~~~~~~~~~~~~~~~">
        <location
            file="res/values-en-rGB/strings.xml"
            line="2531"
            line="2534"
            column="64"/>
    </issue>

@@ -2617,7 +2605,7 @@
        errorLine2="                                                               ~~~~~~~~~~~~~~~~~~~">
        <location
            file="res/values-en-rIN/strings.xml"
            line="2531"
            line="2534"
            column="64"/>
    </issue>

@@ -2633,7 +2621,7 @@
        errorLine2="                                   ~~~~~~~~~~~~~~~~~~~">
        <location
            file="res/values/strings.xml"
            line="5886"
            line="5902"
            column="36"/>
    </issue>

@@ -2665,7 +2653,7 @@
        errorLine2="                                           ^">
        <location
            file="res/values/styles.xml"
            line="443"
            line="448"
            column="44"/>
    </issue>

@@ -2681,7 +2669,7 @@
        errorLine2="                                           ^">
        <location
            file="res/values/styles.xml"
            line="449"
            line="454"
            column="44"/>
    </issue>

@@ -2697,7 +2685,7 @@
        errorLine2="                                           ^">
        <location
            file="res/values/styles.xml"
            line="450"
            line="455"
            column="44"/>
    </issue>

@@ -2761,7 +2749,7 @@
        errorLine2="                                              ^">
        <location
            file="res/values/themes.xml"
            line="91"
            line="90"
            column="47"/>
    </issue>

@@ -2777,7 +2765,7 @@
        errorLine2="                                              ^">
        <location
            file="res/values/themes.xml"
            line="91"
            line="90"
            column="47"/>
    </issue>

@@ -2793,7 +2781,7 @@
        errorLine2="                                       ^">
        <location
            file="res/values/themes.xml"
            line="97"
            line="96"
            column="40"/>
    </issue>

@@ -2809,7 +2797,7 @@
        errorLine2="                                       ^">
        <location
            file="res/values/themes.xml"
            line="97"
            line="96"
            column="40"/>
    </issue>

@@ -2825,7 +2813,7 @@
        errorLine2="                                            ^">
        <location
            file="res/values/themes.xml"
            line="160"
            line="159"
            column="45"/>
    </issue>

@@ -2841,7 +2829,7 @@
        errorLine2="                                                ^">
        <location
            file="res/values/themes.xml"
            line="161"
            line="160"
            column="49"/>
    </issue>

@@ -2857,7 +2845,7 @@
        errorLine2="                                            ^">
        <location
            file="res/values/themes.xml"
            line="169"
            line="168"
            column="45"/>
    </issue>

@@ -2873,10 +2861,58 @@
        errorLine2="                                                ^">
        <location
            file="res/values/themes.xml"
            line="170"
            line="169"
            column="49"/>
    </issue>

    <issue
        id="HardCodedColor"
        severity="Error"
        message="Avoid using hardcoded color"
        category="Correctness"
        priority="4"
        summary="Using hardcoded color"
        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
        errorLine1="        &lt;item name=&quot;batteryGoodColor&quot;>@color/battery_good_color_light&lt;/item>"
        errorLine2="                                      ^">
        <location
            file="res/values/themes.xml"
            line="185"
            column="39"/>
    </issue>

    <issue
        id="HardCodedColor"
        severity="Error"
        message="Avoid using hardcoded color"
        category="Correctness"
        priority="4"
        summary="Using hardcoded color"
        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
        errorLine1="        &lt;item name=&quot;batteryMaybeColor&quot;>@color/battery_maybe_color_light&lt;/item>"
        errorLine2="                                       ^">
        <location
            file="res/values/themes.xml"
            line="186"
            column="40"/>
    </issue>

    <issue
        id="HardCodedColor"
        severity="Error"
        message="Avoid using hardcoded color"
        category="Correctness"
        priority="4"
        summary="Using hardcoded color"
        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
        errorLine1="        &lt;item name=&quot;batteryBadColor&quot;>@color/battery_bad_color_light&lt;/item>"
        errorLine2="                                     ^">
        <location
            file="res/values/themes.xml"
            line="187"
            column="38"/>
    </issue>

    <issue
        id="HardCodedColor"
        severity="Error"
+5 −0
Original line number Diff line number Diff line
@@ -180,6 +180,11 @@

        <!-- action bar, needed for search bar icon tinting -->
        <item name="android:actionBarTheme">@*android:style/ThemeOverlay.DeviceDefault.ActionBar.Accent</item>

        <!-- For battery status icons in -->
        <item name="batteryGoodColor">@color/battery_good_color_light</item>
        <item name="batteryMaybeColor">@color/battery_maybe_color_light</item>
        <item name="batteryBadColor">@color/battery_bad_color_light</item>
    </style>

    <style name="Theme.Settings.Home" parent="Theme.Settings.HomeBase">
+2 −1
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import androidx.annotation.IntDef;
import androidx.annotation.VisibleForTesting;

import com.android.settings.Utils;
import com.android.settings.homepage.contextualcards.slices.BatteryFixSlice;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -115,6 +116,6 @@ public class BatteryBroadcastReceiver extends BroadcastReceiver {
                mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_SAVER);
            }
        }
        BatteryFixSlice.updateBatteryTipAvailabilityCache(mContext);
    }

}
 No newline at end of file
+8 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static android.provider.SettingsSlicesContract.KEY_WIFI;
import android.annotation.Nullable;

import com.android.settings.homepage.contextualcards.deviceinfo.BatterySlice;
import com.android.settings.homepage.contextualcards.slices.BatteryFixSlice;
import com.android.settings.homepage.contextualcards.slices.ConnectedDeviceSlice;
import com.android.settings.homepage.contextualcards.slices.LowStorageSlice;
import com.android.settings.intelligence.ContextualCardProto.ContextualCard;
@@ -61,11 +62,18 @@ public class SettingsContextualCardProvider extends ContextualCardProvider {
                        .setCardName(LowStorageSlice.PATH_LOW_STORAGE)
                        .setCardCategory(ContextualCard.Category.IMPORTANT)
                        .build();
        final ContextualCard batteryFixCard =
                ContextualCard.newBuilder()
                        .setSliceUri(BatteryFixSlice.BATTERY_FIX_URI.toString())
                        .setCardName(BatteryFixSlice.PATH_BATTERY_FIX)
                        .setCardCategory(ContextualCard.Category.IMPORTANT)
                        .build();
        final ContextualCardList cards = ContextualCardList.newBuilder()
                .addCard(wifiCard)
                .addCard(batteryInfoCard)
                .addCard(connectedDeviceCard)
                .addCard(lowStorageCard)
                .addCard(batteryFixCard)
                .build();

        return cards;
+224 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.homepage.contextualcards.slices;

import static android.content.Context.MODE_PRIVATE;

import android.app.PendingIntent;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;

import androidx.annotation.VisibleForTesting;
import androidx.annotation.WorkerThread;
import androidx.core.graphics.drawable.IconCompat;
import androidx.slice.Slice;
import androidx.slice.builders.ListBuilder;
import androidx.slice.builders.ListBuilder.RowBuilder;
import androidx.slice.builders.SliceAction;

import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.os.BatteryStatsHelper;
import com.android.settings.R;
import com.android.settings.SubSettings;
import com.android.settings.Utils;
import com.android.settings.fuelgauge.BatteryStatsHelperLoader;
import com.android.settings.fuelgauge.PowerUsageSummary;
import com.android.settings.fuelgauge.batterytip.BatteryTipLoader;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
import com.android.settings.slices.CustomSliceable;
import com.android.settings.slices.SettingsSliceProvider;
import com.android.settings.slices.SliceBackgroundWorker;
import com.android.settings.slices.SliceBuilderUtils;
import com.android.settingslib.utils.ThreadUtils;

import java.util.List;

public class BatteryFixSlice implements CustomSliceable {

    /**
     * Unique name of Battery Fix Slice.
     */
    public static final String PATH_BATTERY_FIX = "battery_fix";

    /**
     * Uri for Battery Fix Slice.
     */
    public static final Uri BATTERY_FIX_URI = new Uri.Builder()
            .scheme(ContentResolver.SCHEME_CONTENT)
            .authority(SettingsSliceProvider.SLICE_AUTHORITY)
            .appendPath(PATH_BATTERY_FIX)
            .build();

    @VisibleForTesting
    static final String PREFS = "battery_fix_prefs";
    @VisibleForTesting
    static final String KEY_CURRENT_TIPS_TYPE = "current_tip_type";

    private static final String TAG = "BatteryFixSlice";

    private final Context mContext;

    public BatteryFixSlice(Context context) {
        mContext = context;
    }

    @Override
    public Uri getUri() {
        return BATTERY_FIX_URI;
    }

    /**
     * Return a Slice bound to {@link #BATTERY_FIX_URI}.
     */
    @Override
    public Slice getSlice() {
        IconCompat icon;
        SliceAction primaryAction;
        Slice slice = null;

        // TipType.SUMMARY is battery good
        if (readBatteryTipAvailabilityCache(mContext) == BatteryTip.TipType.SUMMARY) {
            return null;
        }

        final List<BatteryTip> batteryTips = SliceBackgroundWorker.getInstance(mContext,
                this).getResults();

        if (batteryTips != null) {
            for (BatteryTip batteryTip : batteryTips) {
                if (batteryTip.getState() != BatteryTip.StateType.INVISIBLE) {
                    icon = IconCompat.createWithResource(mContext, batteryTip.getIconId());
                    primaryAction = new SliceAction(getPrimaryAction(),
                            icon,
                            batteryTip.getTitle(mContext));
                    slice = new ListBuilder(mContext, BATTERY_FIX_URI, ListBuilder.INFINITY)
                            .setAccentColor(Utils.getColorAccentDefaultColor(mContext))
                            .addRow(new RowBuilder()
                                    .setTitle(batteryTip.getTitle(mContext))
                                    .setSubtitle(batteryTip.getSummary(mContext))
                                    .setPrimaryAction(primaryAction)
                                    .addEndItem(icon, ListBuilder.ICON_IMAGE))
                            .build();
                    break;
                }
            }
        } else {
            icon = IconCompat.createWithResource(mContext,
                    R.drawable.ic_battery_status_good_24dp);
            final String title = mContext.getString(R.string.power_usage_summary_title);
            primaryAction = new SliceAction(getPrimaryAction(), icon, title);
            slice = new ListBuilder(mContext, BATTERY_FIX_URI, ListBuilder.INFINITY)
                    .setAccentColor(Utils.getColorAccentDefaultColor(mContext))
                    .addRow(new RowBuilder()
                            .setTitle(title)
                            .setPrimaryAction(primaryAction)
                            .addEndItem(icon, ListBuilder.ICON_IMAGE))
                    .build();
        }
        return slice;
    }

    @Override
    public Intent getIntent() {
        final String screenTitle = mContext.getText(R.string.power_usage_summary_title)
                .toString();
        final Uri contentUri = new Uri.Builder().appendPath(PATH_BATTERY_FIX).build();

        return SliceBuilderUtils.buildSearchResultPageIntent(mContext,
                PowerUsageSummary.class.getName(), PATH_BATTERY_FIX,
                screenTitle,
                MetricsProto.MetricsEvent.SLICE)
                .setClassName(mContext.getPackageName(), SubSettings.class.getName())
                .setData(contentUri);
    }

    @Override
    public void onNotifyChange(Intent intent) {
    }

    @Override
    public Class getBackgroundWorkerClass() {
        return BatteryTipWorker.class;
    }

    private PendingIntent getPrimaryAction() {
        final Intent intent = getIntent();
        return PendingIntent.getActivity(mContext, 0  /* requestCode */, intent, 0  /* flags */);
    }

    // TODO(b/114807643): we should find a better way to get current battery tip type quickly
    // Now we save battery tip type to shared preference when battery level changes
    public static void updateBatteryTipAvailabilityCache(Context context) {
        ThreadUtils.postOnBackgroundThread(() -> {
            refreshBatteryTips(context);
        });
    }

    @VisibleForTesting
    static int readBatteryTipAvailabilityCache(Context context) {
        final SharedPreferences prefs = context.getSharedPreferences(PREFS, MODE_PRIVATE);
        return prefs.getInt(KEY_CURRENT_TIPS_TYPE, BatteryTip.TipType.SUMMARY);
    }

    @WorkerThread
    private static List<BatteryTip> refreshBatteryTips(Context context) {
        final BatteryStatsHelperLoader statsLoader = new BatteryStatsHelperLoader(context);
        final BatteryStatsHelper statsHelper = statsLoader.loadInBackground();
        final BatteryTipLoader loader = new BatteryTipLoader(context, statsHelper);
        final List<BatteryTip> batteryTips = loader.loadInBackground();
        for (BatteryTip batteryTip : batteryTips) {
            if (batteryTip.getState() != BatteryTip.StateType.INVISIBLE) {
                SharedPreferences.Editor editor = context.getSharedPreferences(PREFS,
                        MODE_PRIVATE).edit();
                editor.putInt(KEY_CURRENT_TIPS_TYPE, batteryTip.getType());
                editor.apply();
                break;
            }
        }
        return batteryTips;
    }

    public static class BatteryTipWorker extends SliceBackgroundWorker<BatteryTip> {

        private final Context mContext;

        public BatteryTipWorker(Context context, Uri uri) {
            super(context, uri);
            mContext = context;
        }

        @Override
        protected void onSlicePinned() {
            ThreadUtils.postOnBackgroundThread(() -> {
                final List<BatteryTip> batteryTips = refreshBatteryTips(mContext);
                updateResults(batteryTips);
            });
        }

        @Override
        protected void onSliceUnpinned() {
        }

        @Override
        public void close() {
        }
    }
}
Loading