Merge changes Ie4c98617,I6a7248d9
* changes: Add BatteryTipDialogFragment. Add high usage battery tip
This commit is contained in:
committed by
Android (Google) Code Review
commit
92aa8583c6
48
res/layout/app_high_usage_item.xml
Executable file
48
res/layout/app_high_usage_item.xml
Executable file
@@ -0,0 +1,48 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="4dp"
|
||||||
|
android:paddingStart="?android:dialogPreferredPadding"
|
||||||
|
android:paddingEnd="?android:dialogPreferredPadding"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/app_icon"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_gravity="center_vertical"/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/app_name"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_marginStart="24dp"
|
||||||
|
android:textColor="?android:textColorPrimary"
|
||||||
|
android:paddingEnd="7dp"/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/app_screen_time"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:paddingEnd="16dp"
|
||||||
|
android:textAlignment="viewEnd"
|
||||||
|
android:textColor="?android:textColorPrimary"/>
|
||||||
|
</LinearLayout>
|
23
res/layout/recycler_view.xml
Normal file
23
res/layout/recycler_view.xml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
<android.support.v7.widget.RecyclerView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/recycler_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:paddingTop="8dp"
|
||||||
|
android:scrollbars="vertical"/>
|
@@ -4773,6 +4773,21 @@
|
|||||||
<string name="battery_tip_low_battery_title">Low battery capacity</string>
|
<string name="battery_tip_low_battery_title">Low battery capacity</string>
|
||||||
<!-- Summary for the low battery tip [CHAR LIMIT=NONE] -->
|
<!-- Summary for the low battery tip [CHAR LIMIT=NONE] -->
|
||||||
<string name="battery_tip_low_battery_summary">Battery can\'t provide good battery life</string>
|
<string name="battery_tip_low_battery_summary">Battery can\'t provide good battery life</string>
|
||||||
|
<!-- Title for the battery high usage tip [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="battery_tip_high_usage_title" product="default">Phone used heavily</string>
|
||||||
|
<!-- Title for the battery high usage tip [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="battery_tip_high_usage_title" product="tablet">Tablet used heavily</string>
|
||||||
|
<!-- Title for the battery high usage tip [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="battery_tip_high_usage_title" product="device">Device used heavily</string>
|
||||||
|
<!-- Summary for the battery high usage tip, which presents how many hours the device been used since last full charge [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="battery_tip_high_usage_summary">About <xliff:g id="hour">%1$s</xliff:g> used since last full charge</string>
|
||||||
|
<!-- Message for battery tip dialog to show the status about the battery [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="battery_tip_dialog_message" product="default">Your phone was used heavily and this consumed a lot of battery. Your battery is behaving normally.\n\n Your phone was used for about <xliff:g id="hour">%1$s</xliff:g> since last full charge.\n\n Total usage:</string>
|
||||||
|
<!-- Message for battery tip dialog to show the status about the battery [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="battery_tip_dialog_message" product="tablet">Your tablet was used heavily and this consumed a lot of battery. Your battery is behaving normally.\n\n Your tablet was used for about <xliff:g id="hour">%1$s</xliff:g> since last full charge.\n\n Total usage:</string>
|
||||||
|
<!-- Message for battery tip dialog to show the status about the battery [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="battery_tip_dialog_message" product="device">Your device was used heavily and this consumed a lot of battery. Your battery is behaving normally.\n\n Your device was used for about <xliff:g id="hour">%1$s</xliff:g> since last full charge.\n\n Total usage:</string>
|
||||||
|
|
||||||
<!-- Title for the smart battery manager preference [CHAR LIMIT=NONE] -->
|
<!-- Title for the smart battery manager preference [CHAR LIMIT=NONE] -->
|
||||||
<string name="smart_battery_manager_title">Smart battery manager</string>
|
<string name="smart_battery_manager_title">Smart battery manager</string>
|
||||||
<!-- Title for the smart battery toggle [CHAR LIMIT=NONE] -->
|
<!-- Title for the smart battery toggle [CHAR LIMIT=NONE] -->
|
||||||
|
@@ -94,6 +94,7 @@ import android.text.TextUtils;
|
|||||||
import android.text.format.DateUtils;
|
import android.text.format.DateUtils;
|
||||||
import android.text.style.TtsSpan;
|
import android.text.style.TtsSpan;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
|
import android.util.IconDrawableFactory;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.TypedValue;
|
import android.util.TypedValue;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
@@ -1382,4 +1383,18 @@ public final class Utils extends com.android.settingslib.Utils {
|
|||||||
}
|
}
|
||||||
return new BitmapDrawable(null, bitmap);
|
return new BitmapDrawable(null, bitmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the {@link Drawable} that represents the app icon
|
||||||
|
*/
|
||||||
|
public static Drawable getBadgedIcon(IconDrawableFactory iconDrawableFactory,
|
||||||
|
PackageManager packageManager, String packageName, int userId) {
|
||||||
|
try {
|
||||||
|
final ApplicationInfo appInfo = packageManager.getApplicationInfo(packageName,
|
||||||
|
PackageManager.GET_META_DATA);
|
||||||
|
return iconDrawableFactory.getBadgedIcon(appInfo, userId);
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
return packageManager.getDefaultActivityIcon();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -345,6 +345,17 @@ public class BatteryUtils {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the screen usage time since last full charge.
|
||||||
|
* @param batteryStatsHelper utility class that contains the screen usage data
|
||||||
|
* @return time in millis
|
||||||
|
*/
|
||||||
|
public long calculateScreenUsageTime(BatteryStatsHelper batteryStatsHelper) {
|
||||||
|
final BatterySipper sipper = findBatterySipperByType(
|
||||||
|
batteryStatsHelper.getUsageList(), BatterySipper.DrainType.SCREEN);
|
||||||
|
return sipper != null ? sipper.usageTimeMs : 0;
|
||||||
|
}
|
||||||
|
|
||||||
public static void logRuntime(String tag, String message, long startTime) {
|
public static void logRuntime(String tag, String message, long startTime) {
|
||||||
Log.d(tag, message + ": " + (System.currentTimeMillis() - startTime) + "ms");
|
Log.d(tag, message + ": " + (System.currentTimeMillis() - startTime) + "ms");
|
||||||
}
|
}
|
||||||
@@ -432,6 +443,20 @@ public class BatteryUtils {
|
|||||||
return batteryInfo;
|
return batteryInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the {@link BatterySipper} with the corresponding {@link BatterySipper.DrainType}
|
||||||
|
*/
|
||||||
|
public BatterySipper findBatterySipperByType(List<BatterySipper> usageList,
|
||||||
|
BatterySipper.DrainType type) {
|
||||||
|
for (int i = 0, size = usageList.size(); i < size; i++) {
|
||||||
|
final BatterySipper sipper = usageList.get(i);
|
||||||
|
if (sipper.drainType == type) {
|
||||||
|
return sipper;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isDataCorrupted() {
|
private boolean isDataCorrupted() {
|
||||||
return mPackageManager == null || mAppOpsManager == null;
|
return mPackageManager == null || mAppOpsManager == null;
|
||||||
}
|
}
|
||||||
|
@@ -31,6 +31,7 @@ import com.android.internal.annotations.VisibleForTesting;
|
|||||||
import com.android.internal.logging.nano.MetricsProto;
|
import com.android.internal.logging.nano.MetricsProto;
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.SettingsActivity;
|
import com.android.settings.SettingsActivity;
|
||||||
|
import com.android.settings.Utils;
|
||||||
import com.android.settings.dashboard.DashboardFragment;
|
import com.android.settings.dashboard.DashboardFragment;
|
||||||
import com.android.settings.fuelgauge.anomaly.Anomaly;
|
import com.android.settings.fuelgauge.anomaly.Anomaly;
|
||||||
import com.android.settings.fuelgauge.anomaly.AnomalyDialogFragment;
|
import com.android.settings.fuelgauge.anomaly.AnomalyDialogFragment;
|
||||||
@@ -151,12 +152,6 @@ public class PowerUsageAnomalyDetails extends DashboardFragment implements
|
|||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
Drawable getBadgedIcon(String packageName, int userId) {
|
Drawable getBadgedIcon(String packageName, int userId) {
|
||||||
try {
|
return Utils.getBadgedIcon(mIconDrawableFactory, mPackageManager, packageName, userId);
|
||||||
final ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName,
|
|
||||||
PackageManager.GET_META_DATA);
|
|
||||||
return mIconDrawableFactory.getBadgedIcon(appInfo, userId);
|
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
|
||||||
return mPackageManager.getDefaultActivityIcon();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -266,7 +266,7 @@ public class PowerUsageSummary extends PowerUsageBase implements OnLongClickList
|
|||||||
KEY_APP_LIST, lifecycle, activity, this);
|
KEY_APP_LIST, lifecycle, activity, this);
|
||||||
controllers.add(mBatteryAppListPreferenceController);
|
controllers.add(mBatteryAppListPreferenceController);
|
||||||
mBatteryTipPreferenceController = new BatteryTipPreferenceController(context,
|
mBatteryTipPreferenceController = new BatteryTipPreferenceController(context,
|
||||||
KEY_BATTERY_TIP, this);
|
KEY_BATTERY_TIP, this, this);
|
||||||
controllers.add(mBatteryTipPreferenceController);
|
controllers.add(mBatteryTipPreferenceController);
|
||||||
controllers.add(new BatterySaverController(context, getLifecycle()));
|
controllers.add(new BatterySaverController(context, getLifecycle()));
|
||||||
controllers.add(new BatteryPercentagePreferenceController(context));
|
controllers.add(new BatteryPercentagePreferenceController(context));
|
||||||
@@ -369,8 +369,9 @@ public class PowerUsageSummary extends PowerUsageBase implements OnLongClickList
|
|||||||
restartBatteryInfoLoader();
|
restartBatteryInfoLoader();
|
||||||
final long lastFullChargeTime = mBatteryUtils.calculateLastFullChargeTime(mStatsHelper,
|
final long lastFullChargeTime = mBatteryUtils.calculateLastFullChargeTime(mStatsHelper,
|
||||||
System.currentTimeMillis());
|
System.currentTimeMillis());
|
||||||
updateScreenPreference();
|
|
||||||
updateLastFullChargePreference(lastFullChargeTime);
|
updateLastFullChargePreference(lastFullChargeTime);
|
||||||
|
mScreenUsagePref.setSubtitle(Utils.formatElapsedTime(getContext(),
|
||||||
|
mBatteryUtils.calculateScreenUsageTime(mStatsHelper), false));
|
||||||
|
|
||||||
final CharSequence timeSequence = Utils.formatRelativeTime(context, lastFullChargeTime,
|
final CharSequence timeSequence = Utils.formatRelativeTime(context, lastFullChargeTime,
|
||||||
false);
|
false);
|
||||||
@@ -393,26 +394,6 @@ public class PowerUsageSummary extends PowerUsageBase implements OnLongClickList
|
|||||||
return new AnomalyDetectionPolicy(getContext());
|
return new AnomalyDetectionPolicy(getContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
BatterySipper findBatterySipperByType(List<BatterySipper> usageList, DrainType type) {
|
|
||||||
for (int i = 0, size = usageList.size(); i < size; i++) {
|
|
||||||
final BatterySipper sipper = usageList.get(i);
|
|
||||||
if (sipper.drainType == type) {
|
|
||||||
return sipper;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
void updateScreenPreference() {
|
|
||||||
final BatterySipper sipper = findBatterySipperByType(
|
|
||||||
mStatsHelper.getUsageList(), DrainType.SCREEN);
|
|
||||||
final long usageTimeMs = sipper != null ? sipper.usageTimeMs : 0;
|
|
||||||
|
|
||||||
mScreenUsagePref.setSubtitle(Utils.formatElapsedTime(getContext(), usageTimeMs, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
void updateLastFullChargePreference(long timeMs) {
|
void updateLastFullChargePreference(long timeMs) {
|
||||||
final CharSequence timeSequence = Utils.formatRelativeTime(getContext(), timeMs, false);
|
final CharSequence timeSequence = Utils.formatRelativeTime(getContext(), timeMs, false);
|
||||||
|
@@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* 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.fuelgauge.batterytip;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.VisibleForTesting;
|
||||||
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
||||||
|
import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController.BatteryTipListener;
|
||||||
|
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
|
||||||
|
import com.android.settings.fuelgauge.batterytip.tips.HighUsageTip;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dialog Fragment to show action dialog for each anomaly
|
||||||
|
*/
|
||||||
|
public class BatteryTipDialogFragment extends InstrumentedDialogFragment implements
|
||||||
|
DialogInterface.OnClickListener {
|
||||||
|
|
||||||
|
private static final String ARG_BATTERY_TIP = "battery_tip";
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
BatteryTip mBatteryTip;
|
||||||
|
|
||||||
|
public static BatteryTipDialogFragment newInstance(BatteryTip batteryTip) {
|
||||||
|
BatteryTipDialogFragment dialogFragment = new BatteryTipDialogFragment();
|
||||||
|
|
||||||
|
Bundle args = new Bundle(1);
|
||||||
|
args.putParcelable(ARG_BATTERY_TIP, batteryTip);
|
||||||
|
dialogFragment.setArguments(args);
|
||||||
|
|
||||||
|
return dialogFragment;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
|
final Bundle bundle = getArguments();
|
||||||
|
final Context context = getContext();
|
||||||
|
|
||||||
|
mBatteryTip = bundle.getParcelable(ARG_BATTERY_TIP);
|
||||||
|
|
||||||
|
switch (mBatteryTip.getType()) {
|
||||||
|
case BatteryTip.TipType.SUMMARY:
|
||||||
|
case BatteryTip.TipType.LOW_BATTERY:
|
||||||
|
//TODO(b/70570352): add dialog
|
||||||
|
return null;
|
||||||
|
case BatteryTip.TipType.HIGH_DEVICE_USAGE:
|
||||||
|
final HighUsageTip highUsageTip = (HighUsageTip) mBatteryTip;
|
||||||
|
final RecyclerView view = (RecyclerView) LayoutInflater.from(context).inflate(
|
||||||
|
R.layout.recycler_view,
|
||||||
|
null);
|
||||||
|
view.setLayoutManager(new LinearLayoutManager(context));
|
||||||
|
view.setAdapter(new HighUsageAdapter(context,
|
||||||
|
highUsageTip.getHighUsageAppList()));
|
||||||
|
|
||||||
|
return new AlertDialog.Builder(context)
|
||||||
|
.setMessage(getString(R.string.battery_tip_dialog_message,
|
||||||
|
highUsageTip.getScreenTimeMs()))
|
||||||
|
.setView(view)
|
||||||
|
.setPositiveButton(android.R.string.ok, null)
|
||||||
|
.create();
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("unknown type " + mBatteryTip.getType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMetricsCategory() {
|
||||||
|
//TODO(b/70570352): add correct metric id
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
final BatteryTipListener lsn = (BatteryTipListener) getTargetFragment();
|
||||||
|
if (lsn == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mBatteryTip.action();
|
||||||
|
lsn.onBatteryTipHandled(mBatteryTip);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -23,6 +23,7 @@ import com.android.internal.os.BatteryStatsHelper;
|
|||||||
import com.android.settings.fuelgauge.BatteryInfo;
|
import com.android.settings.fuelgauge.BatteryInfo;
|
||||||
import com.android.settings.fuelgauge.BatteryUtils;
|
import com.android.settings.fuelgauge.BatteryUtils;
|
||||||
import com.android.settings.fuelgauge.batterytip.detectors.BatteryTipDetector;
|
import com.android.settings.fuelgauge.batterytip.detectors.BatteryTipDetector;
|
||||||
|
import com.android.settings.fuelgauge.batterytip.detectors.HighUsageDetector;
|
||||||
import com.android.settings.fuelgauge.batterytip.detectors.LowBatteryDetector;
|
import com.android.settings.fuelgauge.batterytip.detectors.LowBatteryDetector;
|
||||||
import com.android.settings.fuelgauge.batterytip.detectors.SummaryDetector;
|
import com.android.settings.fuelgauge.batterytip.detectors.SummaryDetector;
|
||||||
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
|
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
|
||||||
@@ -65,6 +66,8 @@ public class BatteryTipLoader extends AsyncLoader<List<BatteryTip>> {
|
|||||||
mVisibleTips = 0;
|
mVisibleTips = 0;
|
||||||
|
|
||||||
addBatteryTipFromDetector(tips, new LowBatteryDetector(policy, batteryInfo));
|
addBatteryTipFromDetector(tips, new LowBatteryDetector(policy, batteryInfo));
|
||||||
|
addBatteryTipFromDetector(tips,
|
||||||
|
new HighUsageDetector(getContext(), policy, mBatteryStatsHelper));
|
||||||
// Add summary detector at last since it need other detectors to update the mVisibleTips
|
// Add summary detector at last since it need other detectors to update the mVisibleTips
|
||||||
addBatteryTipFromDetector(tips, new SummaryDetector(policy, mVisibleTips));
|
addBatteryTipFromDetector(tips, new SummaryDetector(policy, mVisibleTips));
|
||||||
|
|
||||||
|
@@ -18,6 +18,7 @@ package com.android.settings.fuelgauge.batterytip;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.support.annotation.VisibleForTesting;
|
import android.support.annotation.VisibleForTesting;
|
||||||
|
import android.support.v14.preference.PreferenceFragment;
|
||||||
import android.support.v7.preference.Preference;
|
import android.support.v7.preference.Preference;
|
||||||
import android.support.v7.preference.PreferenceGroup;
|
import android.support.v7.preference.PreferenceGroup;
|
||||||
import android.support.v7.preference.PreferenceScreen;
|
import android.support.v7.preference.PreferenceScreen;
|
||||||
@@ -34,6 +35,9 @@ import java.util.Map;
|
|||||||
* Controller in charge of the battery tip group
|
* Controller in charge of the battery tip group
|
||||||
*/
|
*/
|
||||||
public class BatteryTipPreferenceController extends BasePreferenceController {
|
public class BatteryTipPreferenceController extends BasePreferenceController {
|
||||||
|
private static final String TAG = "BatteryTipPreferenceController";
|
||||||
|
private static final int REQUEST_ANOMALY_ACTION = 0;
|
||||||
|
|
||||||
private BatteryTipListener mBatteryTipListener;
|
private BatteryTipListener mBatteryTipListener;
|
||||||
private List<BatteryTip> mBatteryTips;
|
private List<BatteryTip> mBatteryTips;
|
||||||
private Map<String, BatteryTip> mBatteryTipMap;
|
private Map<String, BatteryTip> mBatteryTipMap;
|
||||||
@@ -41,16 +45,18 @@ public class BatteryTipPreferenceController extends BasePreferenceController {
|
|||||||
PreferenceGroup mPreferenceGroup;
|
PreferenceGroup mPreferenceGroup;
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
Context mPrefContext;
|
Context mPrefContext;
|
||||||
|
PreferenceFragment mFragment;
|
||||||
|
|
||||||
public BatteryTipPreferenceController(Context context, String preferenceKey) {
|
public BatteryTipPreferenceController(Context context, String preferenceKey) {
|
||||||
this(context, preferenceKey, null);
|
this(context, preferenceKey, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BatteryTipPreferenceController(Context context, String preferenceKey,
|
public BatteryTipPreferenceController(Context context, String preferenceKey,
|
||||||
BatteryTipListener batteryTipListener) {
|
PreferenceFragment fragment, BatteryTipListener batteryTipListener) {
|
||||||
super(context, preferenceKey);
|
super(context, preferenceKey);
|
||||||
mBatteryTipListener = batteryTipListener;
|
mBatteryTipListener = batteryTipListener;
|
||||||
mBatteryTipMap = new HashMap<>();
|
mBatteryTipMap = new HashMap<>();
|
||||||
|
mFragment = fragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -96,7 +102,10 @@ public class BatteryTipPreferenceController extends BasePreferenceController {
|
|||||||
final BatteryTip batteryTip = mBatteryTipMap.get(preference.getKey());
|
final BatteryTip batteryTip = mBatteryTipMap.get(preference.getKey());
|
||||||
if (batteryTip != null) {
|
if (batteryTip != null) {
|
||||||
if (batteryTip.shouldShowDialog()) {
|
if (batteryTip.shouldShowDialog()) {
|
||||||
// build and show the dialog
|
BatteryTipDialogFragment dialogFragment = BatteryTipDialogFragment.newInstance(
|
||||||
|
batteryTip);
|
||||||
|
dialogFragment.setTargetFragment(mFragment, REQUEST_ANOMALY_ACTION);
|
||||||
|
dialogFragment.show(mFragment.getFragmentManager(), TAG);
|
||||||
} else {
|
} else {
|
||||||
batteryTip.action();
|
batteryTip.action();
|
||||||
if (mBatteryTipListener != null) {
|
if (mBatteryTipListener != null) {
|
||||||
|
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* 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.fuelgauge.batterytip;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.os.UserHandle;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.util.IconDrawableFactory;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.Utils;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapter for the high usage app list
|
||||||
|
*/
|
||||||
|
public class HighUsageAdapter extends RecyclerView.Adapter<HighUsageAdapter.ViewHolder> {
|
||||||
|
private final Context mContext;
|
||||||
|
private final IconDrawableFactory mIconDrawableFactory;
|
||||||
|
private final PackageManager mPackageManager;
|
||||||
|
private final List<HighUsageApp> mHighUsageAppList;
|
||||||
|
|
||||||
|
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
public View view;
|
||||||
|
public ImageView appIcon;
|
||||||
|
public TextView appName;
|
||||||
|
public TextView appTime;
|
||||||
|
|
||||||
|
public ViewHolder(View v) {
|
||||||
|
super(v);
|
||||||
|
view = v;
|
||||||
|
appIcon = v.findViewById(R.id.app_icon);
|
||||||
|
appName = v.findViewById(R.id.app_name);
|
||||||
|
appTime = v.findViewById(R.id.app_screen_time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public HighUsageAdapter(Context context, List<HighUsageApp> highUsageAppList) {
|
||||||
|
mContext = context;
|
||||||
|
mHighUsageAppList = highUsageAppList;
|
||||||
|
mIconDrawableFactory = IconDrawableFactory.newInstance(context);
|
||||||
|
mPackageManager = context.getPackageManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||||
|
final View view = LayoutInflater.from(mContext).inflate(R.layout.app_high_usage_item,
|
||||||
|
parent, false);
|
||||||
|
return new ViewHolder(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||||
|
final HighUsageApp app = mHighUsageAppList.get(position);
|
||||||
|
holder.appIcon.setImageDrawable(
|
||||||
|
Utils.getBadgedIcon(mIconDrawableFactory, mPackageManager, app.packageName,
|
||||||
|
UserHandle.myUserId()));
|
||||||
|
holder.appName.setText(Utils.getApplicationLabel(mContext, app.packageName));
|
||||||
|
holder.appTime.setText(Utils.formatElapsedTime(mContext, app.screenOnTimeMs, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return mHighUsageAppList.size();
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* 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.fuelgauge.batterytip;
|
||||||
|
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class representing app with high screen usage
|
||||||
|
*/
|
||||||
|
public class HighUsageApp implements Comparable<HighUsageApp>, Parcelable {
|
||||||
|
public final String packageName;
|
||||||
|
public final long screenOnTimeMs;
|
||||||
|
|
||||||
|
public HighUsageApp(String packageName, long screenOnTimeMs) {
|
||||||
|
this.packageName = packageName;
|
||||||
|
this.screenOnTimeMs = screenOnTimeMs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private HighUsageApp(Parcel in) {
|
||||||
|
packageName = in.readString();
|
||||||
|
screenOnTimeMs = in.readLong();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(HighUsageApp o) {
|
||||||
|
return Long.compare(screenOnTimeMs, o.screenOnTimeMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
dest.writeString(packageName);
|
||||||
|
dest.writeLong(screenOnTimeMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
|
||||||
|
public HighUsageApp createFromParcel(Parcel in) {
|
||||||
|
return new HighUsageApp(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HighUsageApp[] newArray(int size) {
|
||||||
|
return new HighUsageApp[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* 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.fuelgauge.batterytip.detectors;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.BatteryStats;
|
||||||
|
import android.support.annotation.VisibleForTesting;
|
||||||
|
import android.text.format.DateUtils;
|
||||||
|
|
||||||
|
import com.android.internal.os.BatterySipper;
|
||||||
|
import com.android.internal.os.BatteryStatsHelper;
|
||||||
|
import com.android.settings.Utils;
|
||||||
|
import com.android.settings.fuelgauge.BatteryUtils;
|
||||||
|
import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy;
|
||||||
|
import com.android.settings.fuelgauge.batterytip.HighUsageApp;
|
||||||
|
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
|
||||||
|
import com.android.settings.fuelgauge.batterytip.tips.HighUsageTip;
|
||||||
|
import com.android.settings.fuelgauge.batterytip.tips.SummaryTip;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detector whether to show summary tip. This detector should be executed as the last
|
||||||
|
* {@link BatteryTipDetector} since it need the most up-to-date {@code visibleTips}
|
||||||
|
*/
|
||||||
|
public class HighUsageDetector implements BatteryTipDetector {
|
||||||
|
private BatteryTipPolicy mPolicy;
|
||||||
|
private BatteryStatsHelper mBatteryStatsHelper;
|
||||||
|
private List<HighUsageApp> mHighUsageAppList;
|
||||||
|
private Context mContext;
|
||||||
|
@VisibleForTesting
|
||||||
|
BatteryUtils mBatteryUtils;
|
||||||
|
|
||||||
|
public HighUsageDetector(Context context, BatteryTipPolicy policy,
|
||||||
|
BatteryStatsHelper batteryStatsHelper) {
|
||||||
|
mContext = context;
|
||||||
|
mPolicy = policy;
|
||||||
|
mBatteryStatsHelper = batteryStatsHelper;
|
||||||
|
mHighUsageAppList = new ArrayList<>();
|
||||||
|
mBatteryUtils = BatteryUtils.getInstance(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BatteryTip detect() {
|
||||||
|
final long screenUsageTimeMs = mBatteryUtils.calculateScreenUsageTime(mBatteryStatsHelper);
|
||||||
|
//TODO(b/70570352): Change it to detect whether battery drops 25% in last 2 hours
|
||||||
|
if (mPolicy.highUsageEnabled && screenUsageTimeMs > DateUtils.HOUR_IN_MILLIS) {
|
||||||
|
final List<BatterySipper> batterySippers = mBatteryStatsHelper.getUsageList();
|
||||||
|
for (int i = 0, size = batterySippers.size(); i < size; i++) {
|
||||||
|
final BatterySipper batterySipper = batterySippers.get(i);
|
||||||
|
if (!mBatteryUtils.shouldHideSipper(batterySipper)) {
|
||||||
|
final long foregroundTimeMs = mBatteryUtils.getProcessTimeMs(
|
||||||
|
BatteryUtils.StatusType.FOREGROUND, batterySipper.uidObj,
|
||||||
|
BatteryStats.STATS_SINCE_CHARGED);
|
||||||
|
mHighUsageAppList.add(new HighUsageApp(
|
||||||
|
mBatteryUtils.getPackageName(batterySipper.getUid()),
|
||||||
|
foregroundTimeMs));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mHighUsageAppList = mHighUsageAppList.subList(0,
|
||||||
|
Math.min(mPolicy.highUsageAppCount, mHighUsageAppList.size()));
|
||||||
|
Collections.sort(mHighUsageAppList, Collections.reverseOrder());
|
||||||
|
}
|
||||||
|
|
||||||
|
return new HighUsageTip(screenUsageTimeMs, mHighUsageAppList);
|
||||||
|
}
|
||||||
|
}
|
@@ -16,8 +16,9 @@
|
|||||||
|
|
||||||
package com.android.settings.fuelgauge.batterytip.tips;
|
package com.android.settings.fuelgauge.batterytip.tips;
|
||||||
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
import android.support.annotation.IdRes;
|
import android.support.annotation.IdRes;
|
||||||
import android.support.annotation.IntDef;
|
import android.support.annotation.IntDef;
|
||||||
import android.support.v7.preference.Preference;
|
import android.support.v7.preference.Preference;
|
||||||
@@ -31,7 +32,7 @@ import java.lang.annotation.RetentionPolicy;
|
|||||||
* Each {@link BatteryTip} contains basic data(e.g. title, summary, icon) as well as the
|
* Each {@link BatteryTip} contains basic data(e.g. title, summary, icon) as well as the
|
||||||
* pre-defined action(e.g. turn on battery saver)
|
* pre-defined action(e.g. turn on battery saver)
|
||||||
*/
|
*/
|
||||||
public abstract class BatteryTip implements Comparable<BatteryTip> {
|
public abstract class BatteryTip implements Comparable<BatteryTip>, Parcelable {
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
@IntDef({StateType.NEW,
|
@IntDef({StateType.NEW,
|
||||||
StateType.HANDLED,
|
StateType.HANDLED,
|
||||||
@@ -62,12 +63,34 @@ public abstract class BatteryTip implements Comparable<BatteryTip> {
|
|||||||
|
|
||||||
private static final String KEY_PREFIX = "key_battery_tip";
|
private static final String KEY_PREFIX = "key_battery_tip";
|
||||||
|
|
||||||
@TipType
|
|
||||||
protected int mType;
|
protected int mType;
|
||||||
@StateType
|
|
||||||
protected int mState;
|
protected int mState;
|
||||||
protected boolean mShowDialog;
|
protected boolean mShowDialog;
|
||||||
|
|
||||||
|
BatteryTip(Parcel in) {
|
||||||
|
mType = in.readInt();
|
||||||
|
mState = in.readInt();
|
||||||
|
mShowDialog = in.readBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
BatteryTip(int type, int state, boolean showDialog) {
|
||||||
|
mType = type;
|
||||||
|
mState = state;
|
||||||
|
mShowDialog = showDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
dest.writeInt(mType);
|
||||||
|
dest.writeInt(mState);
|
||||||
|
dest.writeBoolean(mShowDialog);
|
||||||
|
}
|
||||||
|
|
||||||
public abstract CharSequence getTitle(Context context);
|
public abstract CharSequence getTitle(Context context);
|
||||||
|
|
||||||
public abstract CharSequence getSummary(Context context);
|
public abstract CharSequence getSummary(Context context);
|
||||||
@@ -77,6 +100,7 @@ public abstract class BatteryTip implements Comparable<BatteryTip> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the current {@link #mState} using the new {@code tip}.
|
* Update the current {@link #mState} using the new {@code tip}.
|
||||||
|
*
|
||||||
* @param tip used to update
|
* @param tip used to update
|
||||||
*/
|
*/
|
||||||
public abstract void updateState(BatteryTip tip);
|
public abstract void updateState(BatteryTip tip);
|
||||||
@@ -86,12 +110,6 @@ public abstract class BatteryTip implements Comparable<BatteryTip> {
|
|||||||
*/
|
*/
|
||||||
public abstract void action();
|
public abstract void action();
|
||||||
|
|
||||||
/**
|
|
||||||
* Build the dialog to display either the info about {@link BatteryTip} or confirmation
|
|
||||||
* about the action.
|
|
||||||
*/
|
|
||||||
public abstract Dialog buildDialog();
|
|
||||||
|
|
||||||
public Preference buildPreference(Context context) {
|
public Preference buildPreference(Context context) {
|
||||||
Preference preference = new Preference(context);
|
Preference preference = new Preference(context);
|
||||||
|
|
||||||
@@ -110,6 +128,10 @@ public abstract class BatteryTip implements Comparable<BatteryTip> {
|
|||||||
return KEY_PREFIX + mType;
|
return KEY_PREFIX + mType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getType() {
|
||||||
|
return mType;
|
||||||
|
}
|
||||||
|
|
||||||
@StateType
|
@StateType
|
||||||
public int getState() {
|
public int getState() {
|
||||||
return mState;
|
return mState;
|
||||||
|
@@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* 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.fuelgauge.batterytip.tips;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
import android.support.annotation.VisibleForTesting;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.Utils;
|
||||||
|
import com.android.settings.fuelgauge.batterytip.HighUsageApp;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tip to show general summary about battery life
|
||||||
|
*/
|
||||||
|
public class HighUsageTip extends BatteryTip {
|
||||||
|
|
||||||
|
private final long mScreenTimeMs;
|
||||||
|
@VisibleForTesting
|
||||||
|
final List<HighUsageApp> mHighUsageAppList;
|
||||||
|
|
||||||
|
public HighUsageTip(long screenTimeMs, List<HighUsageApp> appList) {
|
||||||
|
super(TipType.HIGH_DEVICE_USAGE, appList.isEmpty() ? StateType.INVISIBLE : StateType.NEW,
|
||||||
|
true /* showDialog */);
|
||||||
|
mScreenTimeMs = screenTimeMs;
|
||||||
|
mHighUsageAppList = appList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
HighUsageTip(Parcel in) {
|
||||||
|
super(in);
|
||||||
|
mScreenTimeMs = in.readLong();
|
||||||
|
mHighUsageAppList = in.createTypedArrayList(HighUsageApp.CREATOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
super.writeToParcel(dest, flags);
|
||||||
|
dest.writeLong(mScreenTimeMs);
|
||||||
|
dest.writeTypedList(mHighUsageAppList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CharSequence getTitle(Context context) {
|
||||||
|
return context.getString(R.string.battery_tip_high_usage_title);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CharSequence getSummary(Context context) {
|
||||||
|
return context.getString(R.string.battery_tip_high_usage_summary,
|
||||||
|
Utils.formatElapsedTime(context, mScreenTimeMs, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getIconId() {
|
||||||
|
return R.drawable.ic_perm_device_information_red_24dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateState(BatteryTip tip) {
|
||||||
|
mState = tip.mState;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void action() {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getScreenTimeMs() {
|
||||||
|
return mScreenTimeMs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<HighUsageApp> getHighUsageAppList() {
|
||||||
|
return mHighUsageAppList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
|
||||||
|
public BatteryTip createFromParcel(Parcel in) {
|
||||||
|
return new HighUsageTip(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BatteryTip[] newArray(int size) {
|
||||||
|
return new HighUsageTip[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@@ -16,8 +16,9 @@
|
|||||||
|
|
||||||
package com.android.settings.fuelgauge.batterytip.tips;
|
package com.android.settings.fuelgauge.batterytip.tips;
|
||||||
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
|
|
||||||
@@ -27,9 +28,11 @@ import com.android.settings.R;
|
|||||||
public class LowBatteryTip extends BatteryTip {
|
public class LowBatteryTip extends BatteryTip {
|
||||||
|
|
||||||
public LowBatteryTip(@StateType int state) {
|
public LowBatteryTip(@StateType int state) {
|
||||||
mShowDialog = false;
|
super(TipType.LOW_BATTERY, state, false /* showDialog */);
|
||||||
mState = state;
|
}
|
||||||
mType = TipType.LOW_BATTERY;
|
|
||||||
|
private LowBatteryTip(Parcel in) {
|
||||||
|
super(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -57,9 +60,14 @@ public class LowBatteryTip extends BatteryTip {
|
|||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
|
||||||
public Dialog buildDialog() {
|
public BatteryTip createFromParcel(Parcel in) {
|
||||||
//TODO(b/70570352): create the dialog for low battery tip and add test
|
return new LowBatteryTip(in);
|
||||||
return null;
|
}
|
||||||
}
|
|
||||||
|
public BatteryTip[] newArray(int size) {
|
||||||
|
return new LowBatteryTip[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -16,8 +16,9 @@
|
|||||||
|
|
||||||
package com.android.settings.fuelgauge.batterytip.tips;
|
package com.android.settings.fuelgauge.batterytip.tips;
|
||||||
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
|
|
||||||
@@ -27,9 +28,11 @@ import com.android.settings.R;
|
|||||||
public class SummaryTip extends BatteryTip {
|
public class SummaryTip extends BatteryTip {
|
||||||
|
|
||||||
public SummaryTip(@StateType int state) {
|
public SummaryTip(@StateType int state) {
|
||||||
mShowDialog = false;
|
super(TipType.SUMMARY, state, false /* showDialog */);
|
||||||
mState = state;
|
}
|
||||||
mType = TipType.SUMMARY;
|
|
||||||
|
private SummaryTip(Parcel in) {
|
||||||
|
super(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -57,9 +60,13 @@ public class SummaryTip extends BatteryTip {
|
|||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
|
||||||
public Dialog buildDialog() {
|
public BatteryTip createFromParcel(Parcel in) {
|
||||||
//TODO(b/70570352): create the dialog for summary tip and add test
|
return new SummaryTip(in);
|
||||||
return null;
|
}
|
||||||
}
|
|
||||||
|
public BatteryTip[] newArray(int size) {
|
||||||
|
return new SummaryTip[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@@ -4,13 +4,16 @@ import static com.google.common.truth.Truth.assertThat;
|
|||||||
|
|
||||||
import static org.mockito.Matchers.anyString;
|
import static org.mockito.Matchers.anyString;
|
||||||
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
|
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
|
||||||
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.UserInfo;
|
import android.content.pm.UserInfo;
|
||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
import android.net.LinkAddress;
|
import android.net.LinkAddress;
|
||||||
@@ -25,6 +28,7 @@ import android.os.storage.VolumeInfo;
|
|||||||
import android.text.SpannableStringBuilder;
|
import android.text.SpannableStringBuilder;
|
||||||
import android.text.format.DateUtils;
|
import android.text.format.DateUtils;
|
||||||
import android.text.style.TtsSpan;
|
import android.text.style.TtsSpan;
|
||||||
|
import android.util.IconDrawableFactory;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
@@ -46,8 +50,8 @@ import java.util.List;
|
|||||||
@RunWith(SettingsRobolectricTestRunner.class)
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||||
public class UtilsTest {
|
public class UtilsTest {
|
||||||
|
|
||||||
private static final String PACKAGE_NAME = "com.android.app";
|
private static final String PACKAGE_NAME = "com.android.app";
|
||||||
|
private static final int USER_ID = 1;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private WifiManager wifiManager;
|
private WifiManager wifiManager;
|
||||||
@@ -59,6 +63,12 @@ public class UtilsTest {
|
|||||||
private DevicePolicyManagerWrapper mDevicePolicyManager;
|
private DevicePolicyManagerWrapper mDevicePolicyManager;
|
||||||
@Mock
|
@Mock
|
||||||
private UserManager mUserManager;
|
private UserManager mUserManager;
|
||||||
|
@Mock
|
||||||
|
private PackageManager mPackageManager;
|
||||||
|
@Mock
|
||||||
|
private IconDrawableFactory mIconDrawableFactory;
|
||||||
|
@Mock
|
||||||
|
private ApplicationInfo mApplicationInfo;
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@@ -332,4 +342,17 @@ public class UtilsTest {
|
|||||||
|
|
||||||
assertThat(editText.getSelectionEnd()).isEqualTo(length);
|
assertThat(editText.getSelectionEnd()).isEqualTo(length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetBadgedIcon_usePackageNameAndUserId() throws
|
||||||
|
PackageManager.NameNotFoundException {
|
||||||
|
doReturn(mApplicationInfo).when(mPackageManager).getApplicationInfo(PACKAGE_NAME,
|
||||||
|
PackageManager.GET_META_DATA);
|
||||||
|
|
||||||
|
Utils.getBadgedIcon(mIconDrawableFactory, mPackageManager, PACKAGE_NAME, USER_ID);
|
||||||
|
|
||||||
|
// Verify that it uses the correct user id
|
||||||
|
verify(mIconDrawableFactory).getBadgedIcon(mApplicationInfo, USER_ID);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -20,7 +20,9 @@ import static android.os.BatteryStats.Uid.PROCESS_STATE_FOREGROUND;
|
|||||||
import static android.os.BatteryStats.Uid.PROCESS_STATE_FOREGROUND_SERVICE;
|
import static android.os.BatteryStats.Uid.PROCESS_STATE_FOREGROUND_SERVICE;
|
||||||
import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP;
|
import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP;
|
||||||
import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP_SLEEPING;
|
import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP_SLEEPING;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import static org.mockito.Matchers.any;
|
import static org.mockito.Matchers.any;
|
||||||
import static org.mockito.Matchers.anyInt;
|
import static org.mockito.Matchers.anyInt;
|
||||||
import static org.mockito.Matchers.anyLong;
|
import static org.mockito.Matchers.anyLong;
|
||||||
@@ -141,6 +143,7 @@ public class BatteryUtilsTest {
|
|||||||
private BatteryUtils mBatteryUtils;
|
private BatteryUtils mBatteryUtils;
|
||||||
private FakeFeatureFactory mFeatureFactory;
|
private FakeFeatureFactory mFeatureFactory;
|
||||||
private PowerUsageFeatureProvider mProvider;
|
private PowerUsageFeatureProvider mProvider;
|
||||||
|
private List<BatterySipper> mUsageList;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
@@ -194,6 +197,12 @@ public class BatteryUtilsTest {
|
|||||||
mBatteryUtils.mPowerUsageFeatureProvider = mProvider;
|
mBatteryUtils.mPowerUsageFeatureProvider = mProvider;
|
||||||
doReturn(0L).when(mBatteryUtils).getForegroundServiceTotalTimeUs(
|
doReturn(0L).when(mBatteryUtils).getForegroundServiceTotalTimeUs(
|
||||||
any(BatteryStats.Uid.class), anyLong());
|
any(BatteryStats.Uid.class), anyLong());
|
||||||
|
|
||||||
|
mUsageList = new ArrayList<>();
|
||||||
|
mUsageList.add(mNormalBatterySipper);
|
||||||
|
mUsageList.add(mScreenBatterySipper);
|
||||||
|
mUsageList.add(mCellBatterySipper);
|
||||||
|
doReturn(mUsageList).when(mBatteryStatsHelper).getUsageList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -468,4 +477,28 @@ public class BatteryUtilsTest {
|
|||||||
verify(mBatteryStatsHelper).refreshStats(BatteryStats.STATS_SINCE_CHARGED,
|
verify(mBatteryStatsHelper).refreshStats(BatteryStats.STATS_SINCE_CHARGED,
|
||||||
mUserManager.getUserProfiles());
|
mUserManager.getUserProfiles());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFindBatterySipperByType_findTypeScreen() {
|
||||||
|
BatterySipper sipper = mBatteryUtils.findBatterySipperByType(mUsageList,
|
||||||
|
BatterySipper.DrainType.SCREEN);
|
||||||
|
|
||||||
|
assertThat(sipper).isSameAs(mScreenBatterySipper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFindBatterySipperByType_findTypeApp() {
|
||||||
|
BatterySipper sipper = mBatteryUtils.findBatterySipperByType(mUsageList,
|
||||||
|
BatterySipper.DrainType.APP);
|
||||||
|
|
||||||
|
assertThat(sipper).isSameAs(mNormalBatterySipper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCalculateScreenUsageTime_returnCorrectTime() {
|
||||||
|
mScreenBatterySipper.usageTimeMs = TIME_EXPECTED_FOREGROUND;
|
||||||
|
|
||||||
|
assertThat(mBatteryUtils.calculateScreenUsageTime(mBatteryStatsHelper)).isEqualTo(
|
||||||
|
TIME_EXPECTED_FOREGROUND);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -67,7 +67,6 @@ public class PowerUsageAnomalyDetailsTest {
|
|||||||
private static final String PACKAGE_NAME_1 = "com.android.app1";
|
private static final String PACKAGE_NAME_1 = "com.android.app1";
|
||||||
private static final String PACKAGE_NAME_2 = "com.android.app2";
|
private static final String PACKAGE_NAME_2 = "com.android.app2";
|
||||||
private static final String PACKAGE_NAME_3 = "com.android.app3";
|
private static final String PACKAGE_NAME_3 = "com.android.app3";
|
||||||
private static final int USER_ID = 1;
|
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private SettingsActivity mSettingsActivity;
|
private SettingsActivity mSettingsActivity;
|
||||||
@@ -198,16 +197,4 @@ public class PowerUsageAnomalyDetailsTest {
|
|||||||
assertThat(mBundle.getParcelableArrayList(
|
assertThat(mBundle.getParcelableArrayList(
|
||||||
PowerUsageAnomalyDetails.EXTRA_ANOMALY_LIST)).isEqualTo(mAnomalyList);
|
PowerUsageAnomalyDetails.EXTRA_ANOMALY_LIST)).isEqualTo(mAnomalyList);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetBadgedIcon_usePackageNameAndUserId() throws
|
|
||||||
PackageManager.NameNotFoundException {
|
|
||||||
doReturn(mApplicationInfo).when(mPackageManager).getApplicationInfo(PACKAGE_NAME_1,
|
|
||||||
PackageManager.GET_META_DATA);
|
|
||||||
|
|
||||||
mFragment.getBadgedIcon(PACKAGE_NAME_1, USER_ID);
|
|
||||||
|
|
||||||
// Verify that it uses the correct user id
|
|
||||||
verify(mIconDrawableFactory).getBadgedIcon(mApplicationInfo, USER_ID);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -247,34 +247,6 @@ public class PowerUsageSummaryTest {
|
|||||||
assertThat(mFragment.mShowAllApps).isEqualTo(!isShowApps);
|
assertThat(mFragment.mShowAllApps).isEqualTo(!isShowApps);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFindBatterySipperByType_findTypeScreen() {
|
|
||||||
BatterySipper sipper = mFragment.findBatterySipperByType(mUsageList,
|
|
||||||
BatterySipper.DrainType.SCREEN);
|
|
||||||
|
|
||||||
assertThat(sipper).isSameAs(mScreenBatterySipper);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFindBatterySipperByType_findTypeApp() {
|
|
||||||
BatterySipper sipper = mFragment.findBatterySipperByType(mUsageList,
|
|
||||||
BatterySipper.DrainType.APP);
|
|
||||||
|
|
||||||
assertThat(sipper).isSameAs(mNormalBatterySipper);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testUpdateScreenPreference_showCorrectSummary() {
|
|
||||||
doReturn(mScreenBatterySipper).when(mFragment).findBatterySipperByType(any(), any());
|
|
||||||
doReturn(mRealContext).when(mFragment).getContext();
|
|
||||||
final CharSequence expectedSummary = Utils.formatElapsedTime(mRealContext, USAGE_TIME_MS,
|
|
||||||
false);
|
|
||||||
|
|
||||||
mFragment.updateScreenPreference();
|
|
||||||
|
|
||||||
assertThat(mScreenUsagePref.getSubtitle()).isEqualTo(expectedSummary);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUpdateLastFullChargePreference_showCorrectSummary() {
|
public void testUpdateLastFullChargePreference_showCorrectSummary() {
|
||||||
doReturn(mRealContext).when(mFragment).getContext();
|
doReturn(mRealContext).when(mFragment).getContext();
|
||||||
@@ -284,16 +256,6 @@ public class PowerUsageSummaryTest {
|
|||||||
assertThat(mLastFullChargePref.getSubtitle()).isEqualTo("2 hr. ago");
|
assertThat(mLastFullChargePref.getSubtitle()).isEqualTo("2 hr. ago");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testUpdatePreference_usageListEmpty_shouldNotCrash() {
|
|
||||||
when(mBatteryHelper.getUsageList()).thenReturn(new ArrayList<BatterySipper>());
|
|
||||||
doReturn(STUB_STRING).when(mFragment).getString(anyInt(), any());
|
|
||||||
doReturn(mRealContext).when(mFragment).getContext();
|
|
||||||
|
|
||||||
// Should not crash when update
|
|
||||||
mFragment.updateScreenPreference();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNonIndexableKeys_MatchPreferenceKeys() {
|
public void testNonIndexableKeys_MatchPreferenceKeys() {
|
||||||
final Context context = RuntimeEnvironment.application;
|
final Context context = RuntimeEnvironment.application;
|
||||||
|
@@ -85,7 +85,7 @@ public class BatteryTipPreferenceControllerTest {
|
|||||||
mNewBatteryTips.add(new SummaryTip(BatteryTip.StateType.INVISIBLE));
|
mNewBatteryTips.add(new SummaryTip(BatteryTip.StateType.INVISIBLE));
|
||||||
|
|
||||||
mBatteryTipPreferenceController = new BatteryTipPreferenceController(mContext, KEY_PREF,
|
mBatteryTipPreferenceController = new BatteryTipPreferenceController(mContext, KEY_PREF,
|
||||||
mBatteryTipListener);
|
null, mBatteryTipListener);
|
||||||
mBatteryTipPreferenceController.mPreferenceGroup = mPreferenceGroup;
|
mBatteryTipPreferenceController.mPreferenceGroup = mPreferenceGroup;
|
||||||
mBatteryTipPreferenceController.mPrefContext = mContext;
|
mBatteryTipPreferenceController.mPrefContext = mContext;
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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.fuelgauge.batterytip.detectors;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.doReturn;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.BatteryStats;
|
||||||
|
import android.text.format.DateUtils;
|
||||||
|
|
||||||
|
import com.android.internal.os.BatterySipper;
|
||||||
|
import com.android.internal.os.BatteryStatsHelper;
|
||||||
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.fuelgauge.BatteryInfo;
|
||||||
|
import com.android.settings.fuelgauge.BatteryUtils;
|
||||||
|
import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy;
|
||||||
|
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
import org.robolectric.util.ReflectionHelpers;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||||
|
public class HighUsageDetectorTest {
|
||||||
|
private Context mContext;
|
||||||
|
@Mock
|
||||||
|
private BatteryStatsHelper mBatteryStatsHelper;
|
||||||
|
@Mock
|
||||||
|
private BatteryUtils mBatteryUtils;
|
||||||
|
@Mock
|
||||||
|
private BatterySipper mBatterySipper;
|
||||||
|
|
||||||
|
private BatteryTipPolicy mPolicy;
|
||||||
|
private HighUsageDetector mHighUsageDetector;
|
||||||
|
private List<BatterySipper> mUsageList;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
|
mContext = RuntimeEnvironment.application;
|
||||||
|
mPolicy = spy(new BatteryTipPolicy(mContext));
|
||||||
|
mHighUsageDetector = new HighUsageDetector(mContext, mPolicy, mBatteryStatsHelper);
|
||||||
|
mHighUsageDetector.mBatteryUtils = mBatteryUtils;
|
||||||
|
|
||||||
|
mUsageList = new ArrayList<>();
|
||||||
|
mUsageList.add(mBatterySipper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDetect_disabledByPolicy_tipInvisible() {
|
||||||
|
ReflectionHelpers.setField(mPolicy, "highUsageEnabled", false);
|
||||||
|
|
||||||
|
assertThat(mHighUsageDetector.detect().isVisible()).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDetect_containsHighUsageApp_tipVisible() {
|
||||||
|
doReturn(2 * DateUtils.HOUR_IN_MILLIS).when(mBatteryUtils).calculateScreenUsageTime(
|
||||||
|
mBatteryStatsHelper);
|
||||||
|
doReturn(mUsageList).when(mBatteryStatsHelper).getUsageList();
|
||||||
|
doReturn(DateUtils.HOUR_IN_MILLIS).when(mBatteryUtils).getProcessTimeMs(
|
||||||
|
BatteryUtils.StatusType.FOREGROUND, mBatterySipper.uidObj,
|
||||||
|
BatteryStats.STATS_SINCE_CHARGED);
|
||||||
|
|
||||||
|
assertThat(mHighUsageDetector.detect().isVisible()).isTrue();
|
||||||
|
}
|
||||||
|
}
|
@@ -19,6 +19,8 @@ import static com.google.common.truth.Truth.assertThat;
|
|||||||
|
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
import android.support.annotation.IdRes;
|
import android.support.annotation.IdRes;
|
||||||
import android.support.v7.preference.Preference;
|
import android.support.v7.preference.Preference;
|
||||||
|
|
||||||
@@ -58,10 +60,32 @@ public class BatteryTipTest {
|
|||||||
assertThat(preference.getIcon()).isEqualTo(mContext.getDrawable(ICON_ID));
|
assertThat(preference.getIcon()).isEqualTo(mContext.getDrawable(ICON_ID));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParcelable() {
|
||||||
|
final BatteryTip batteryTip = new TestBatteryTip();
|
||||||
|
|
||||||
|
Parcel parcel = Parcel.obtain();
|
||||||
|
batteryTip.writeToParcel(parcel, batteryTip.describeContents());
|
||||||
|
parcel.setDataPosition(0);
|
||||||
|
|
||||||
|
final BatteryTip parcelTip = new TestBatteryTip(parcel);
|
||||||
|
|
||||||
|
assertThat(parcelTip.getTitle(mContext)).isEqualTo(TITLE);
|
||||||
|
assertThat(parcelTip.getSummary(mContext)).isEqualTo(SUMMARY);
|
||||||
|
assertThat(parcelTip.getIconId()).isEqualTo(ICON_ID);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to test the non abstract methods in {@link TestBatteryTip}
|
* Used to test the non abstract methods in {@link TestBatteryTip}
|
||||||
*/
|
*/
|
||||||
public class TestBatteryTip extends BatteryTip {
|
public static class TestBatteryTip extends BatteryTip {
|
||||||
|
TestBatteryTip() {
|
||||||
|
super(TipType.SUMMARY, StateType.NEW, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
TestBatteryTip(Parcel in) {
|
||||||
|
super(in);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getTitle(Context context) {
|
public String getTitle(Context context) {
|
||||||
@@ -88,10 +112,15 @@ public class BatteryTipTest {
|
|||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public final Parcelable.Creator CREATOR = new Parcelable.Creator() {
|
||||||
public Dialog buildDialog() {
|
public BatteryTip createFromParcel(Parcel in) {
|
||||||
return null;
|
return new TestBatteryTip(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BatteryTip[] newArray(int size) {
|
||||||
|
return new TestBatteryTip[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* 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.fuelgauge.batterytip.tips;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.text.format.DateUtils;
|
||||||
|
|
||||||
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.fuelgauge.batterytip.HighUsageApp;
|
||||||
|
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||||
|
public class HighUsageTipTest {
|
||||||
|
private static final String PACKAGE_NAME = "com.android.app";
|
||||||
|
private static final long SCREEN_TIME = 30 * DateUtils.MINUTE_IN_MILLIS;
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
private HighUsageTip mBatteryTip;
|
||||||
|
private List<HighUsageApp> mUsageAppList;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
mContext = RuntimeEnvironment.application;
|
||||||
|
|
||||||
|
mUsageAppList = new ArrayList<>();
|
||||||
|
mUsageAppList.add(new HighUsageApp(PACKAGE_NAME, SCREEN_TIME));
|
||||||
|
mBatteryTip = new HighUsageTip(SCREEN_TIME, mUsageAppList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParcelable() {
|
||||||
|
|
||||||
|
Parcel parcel = Parcel.obtain();
|
||||||
|
mBatteryTip.writeToParcel(parcel, mBatteryTip.describeContents());
|
||||||
|
parcel.setDataPosition(0);
|
||||||
|
|
||||||
|
final HighUsageTip parcelTip = new HighUsageTip(parcel);
|
||||||
|
|
||||||
|
assertThat(parcelTip.getTitle(mContext)).isEqualTo("Phone used heavily");
|
||||||
|
assertThat(parcelTip.getType()).isEqualTo(BatteryTip.TipType.HIGH_DEVICE_USAGE);
|
||||||
|
assertThat(parcelTip.getState()).isEqualTo(BatteryTip.StateType.NEW);
|
||||||
|
assertThat(parcelTip.getScreenTimeMs()).isEqualTo(SCREEN_TIME);
|
||||||
|
assertThat(parcelTip.mHighUsageAppList.size()).isEqualTo(1);
|
||||||
|
final HighUsageApp app = parcelTip.mHighUsageAppList.get(0);
|
||||||
|
assertThat(app.packageName).isEqualTo(PACKAGE_NAME);
|
||||||
|
assertThat(app.screenOnTimeMs).isEqualTo(SCREEN_TIME);
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user