diff --git a/res/layout/app_high_usage_item.xml b/res/layout/app_high_usage_item.xml
new file mode 100755
index 00000000000..473315f2ade
--- /dev/null
+++ b/res/layout/app_high_usage_item.xml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
diff --git a/res/layout/recycler_view.xml b/res/layout/recycler_view.xml
new file mode 100644
index 00000000000..a7dabe5d720
--- /dev/null
+++ b/res/layout/recycler_view.xml
@@ -0,0 +1,23 @@
+
+
+
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 52bcdbfbee7..8c7b6f4789f 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -4773,6 +4773,21 @@
Low battery capacity
Battery can\'t provide good battery life
+
+ Phone used heavily
+
+ Tablet used heavily
+
+ Device used heavily
+
+ About %1$s used since last full charge
+
+ 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 %1$s since last full charge.\n\n Total usage:
+
+ 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 %1$s since last full charge.\n\n Total usage:
+
+ 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 %1$s since last full charge.\n\n Total usage:
+
Smart battery manager
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index cd64799f804..ad951216781 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -94,6 +94,7 @@ import android.text.TextUtils;
import android.text.format.DateUtils;
import android.text.style.TtsSpan;
import android.util.ArraySet;
+import android.util.IconDrawableFactory;
import android.util.Log;
import android.util.TypedValue;
import android.view.LayoutInflater;
@@ -1382,4 +1383,18 @@ public final class Utils extends com.android.settingslib.Utils {
}
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();
+ }
+ }
}
diff --git a/src/com/android/settings/fuelgauge/BatteryUtils.java b/src/com/android/settings/fuelgauge/BatteryUtils.java
index 68677fab2de..0952f1f095d 100644
--- a/src/com/android/settings/fuelgauge/BatteryUtils.java
+++ b/src/com/android/settings/fuelgauge/BatteryUtils.java
@@ -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) {
Log.d(tag, message + ": " + (System.currentTimeMillis() - startTime) + "ms");
}
@@ -432,6 +443,20 @@ public class BatteryUtils {
return batteryInfo;
}
+ /**
+ * Find the {@link BatterySipper} with the corresponding {@link BatterySipper.DrainType}
+ */
+ public BatterySipper findBatterySipperByType(List 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() {
return mPackageManager == null || mAppOpsManager == null;
}
diff --git a/src/com/android/settings/fuelgauge/PowerUsageAnomalyDetails.java b/src/com/android/settings/fuelgauge/PowerUsageAnomalyDetails.java
index 0d73511e84d..143733db2b8 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageAnomalyDetails.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageAnomalyDetails.java
@@ -31,6 +31,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
+import com.android.settings.Utils;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.fuelgauge.anomaly.Anomaly;
import com.android.settings.fuelgauge.anomaly.AnomalyDialogFragment;
@@ -151,12 +152,6 @@ public class PowerUsageAnomalyDetails extends DashboardFragment implements
@VisibleForTesting
Drawable getBadgedIcon(String packageName, int userId) {
- try {
- final ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName,
- PackageManager.GET_META_DATA);
- return mIconDrawableFactory.getBadgedIcon(appInfo, userId);
- } catch (PackageManager.NameNotFoundException e) {
- return mPackageManager.getDefaultActivityIcon();
- }
+ return Utils.getBadgedIcon(mIconDrawableFactory, mPackageManager, packageName, userId);
}
}
diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
index 0315f032e66..205ac0b15a8 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
@@ -266,7 +266,7 @@ public class PowerUsageSummary extends PowerUsageBase implements OnLongClickList
KEY_APP_LIST, lifecycle, activity, this);
controllers.add(mBatteryAppListPreferenceController);
mBatteryTipPreferenceController = new BatteryTipPreferenceController(context,
- KEY_BATTERY_TIP, this);
+ KEY_BATTERY_TIP, this, this);
controllers.add(mBatteryTipPreferenceController);
controllers.add(new BatterySaverController(context, getLifecycle()));
controllers.add(new BatteryPercentagePreferenceController(context));
@@ -369,8 +369,9 @@ public class PowerUsageSummary extends PowerUsageBase implements OnLongClickList
restartBatteryInfoLoader();
final long lastFullChargeTime = mBatteryUtils.calculateLastFullChargeTime(mStatsHelper,
System.currentTimeMillis());
- updateScreenPreference();
updateLastFullChargePreference(lastFullChargeTime);
+ mScreenUsagePref.setSubtitle(Utils.formatElapsedTime(getContext(),
+ mBatteryUtils.calculateScreenUsageTime(mStatsHelper), false));
final CharSequence timeSequence = Utils.formatRelativeTime(context, lastFullChargeTime,
false);
@@ -393,26 +394,6 @@ public class PowerUsageSummary extends PowerUsageBase implements OnLongClickList
return new AnomalyDetectionPolicy(getContext());
}
- @VisibleForTesting
- BatterySipper findBatterySipperByType(List 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
void updateLastFullChargePreference(long timeMs) {
final CharSequence timeSequence = Utils.formatRelativeTime(getContext(), timeMs, false);
diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipDialogFragment.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipDialogFragment.java
new file mode 100644
index 00000000000..3e091b3b44c
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipDialogFragment.java
@@ -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);
+ }
+
+}
diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
index 9c3f48c0a6b..a1db57a409a 100644
--- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
+++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
@@ -23,6 +23,7 @@ import com.android.internal.os.BatteryStatsHelper;
import com.android.settings.fuelgauge.BatteryInfo;
import com.android.settings.fuelgauge.BatteryUtils;
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.SummaryDetector;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
@@ -65,6 +66,8 @@ public class BatteryTipLoader extends AsyncLoader> {
mVisibleTips = 0;
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
addBatteryTipFromDetector(tips, new SummaryDetector(policy, mVisibleTips));
diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceController.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceController.java
index f6114052cf6..9aa70c55264 100644
--- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceController.java
@@ -18,6 +18,7 @@ package com.android.settings.fuelgauge.batterytip;
import android.content.Context;
import android.support.annotation.VisibleForTesting;
+import android.support.v14.preference.PreferenceFragment;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceGroup;
import android.support.v7.preference.PreferenceScreen;
@@ -34,6 +35,9 @@ import java.util.Map;
* Controller in charge of the battery tip group
*/
public class BatteryTipPreferenceController extends BasePreferenceController {
+ private static final String TAG = "BatteryTipPreferenceController";
+ private static final int REQUEST_ANOMALY_ACTION = 0;
+
private BatteryTipListener mBatteryTipListener;
private List mBatteryTips;
private Map mBatteryTipMap;
@@ -41,16 +45,18 @@ public class BatteryTipPreferenceController extends BasePreferenceController {
PreferenceGroup mPreferenceGroup;
@VisibleForTesting
Context mPrefContext;
+ PreferenceFragment mFragment;
public BatteryTipPreferenceController(Context context, String preferenceKey) {
- this(context, preferenceKey, null);
+ this(context, preferenceKey, null, null);
}
public BatteryTipPreferenceController(Context context, String preferenceKey,
- BatteryTipListener batteryTipListener) {
+ PreferenceFragment fragment, BatteryTipListener batteryTipListener) {
super(context, preferenceKey);
mBatteryTipListener = batteryTipListener;
mBatteryTipMap = new HashMap<>();
+ mFragment = fragment;
}
@Override
@@ -96,7 +102,10 @@ public class BatteryTipPreferenceController extends BasePreferenceController {
final BatteryTip batteryTip = mBatteryTipMap.get(preference.getKey());
if (batteryTip != null) {
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 {
batteryTip.action();
if (mBatteryTipListener != null) {
diff --git a/src/com/android/settings/fuelgauge/batterytip/HighUsageAdapter.java b/src/com/android/settings/fuelgauge/batterytip/HighUsageAdapter.java
new file mode 100644
index 00000000000..8b743946648
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batterytip/HighUsageAdapter.java
@@ -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 {
+ private final Context mContext;
+ private final IconDrawableFactory mIconDrawableFactory;
+ private final PackageManager mPackageManager;
+ private final List 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 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();
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/fuelgauge/batterytip/HighUsageApp.java b/src/com/android/settings/fuelgauge/batterytip/HighUsageApp.java
new file mode 100644
index 00000000000..f75ecf0e322
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batterytip/HighUsageApp.java
@@ -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, 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];
+ }
+ };
+}
\ No newline at end of file
diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetector.java
new file mode 100644
index 00000000000..237f430c575
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetector.java
@@ -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 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 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);
+ }
+}
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java
index 17e395ef185..eadd0e1a811 100644
--- a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java
@@ -16,8 +16,9 @@
package com.android.settings.fuelgauge.batterytip.tips;
-import android.app.Dialog;
import android.content.Context;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.support.annotation.IdRes;
import android.support.annotation.IntDef;
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
* pre-defined action(e.g. turn on battery saver)
*/
-public abstract class BatteryTip implements Comparable {
+public abstract class BatteryTip implements Comparable, Parcelable {
@Retention(RetentionPolicy.SOURCE)
@IntDef({StateType.NEW,
StateType.HANDLED,
@@ -62,12 +63,34 @@ public abstract class BatteryTip implements Comparable {
private static final String KEY_PREFIX = "key_battery_tip";
- @TipType
protected int mType;
- @StateType
protected int mState;
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 getSummary(Context context);
@@ -77,6 +100,7 @@ public abstract class BatteryTip implements Comparable {
/**
* Update the current {@link #mState} using the new {@code tip}.
+ *
* @param tip used to update
*/
public abstract void updateState(BatteryTip tip);
@@ -86,12 +110,6 @@ public abstract class BatteryTip implements Comparable {
*/
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) {
Preference preference = new Preference(context);
@@ -110,6 +128,10 @@ public abstract class BatteryTip implements Comparable {
return KEY_PREFIX + mType;
}
+ public int getType() {
+ return mType;
+ }
+
@StateType
public int getState() {
return mState;
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/HighUsageTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/HighUsageTip.java
new file mode 100644
index 00000000000..001a48eedc3
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/HighUsageTip.java
@@ -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 mHighUsageAppList;
+
+ public HighUsageTip(long screenTimeMs, List 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 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];
+ }
+ };
+
+}
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/LowBatteryTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/LowBatteryTip.java
index 8605fbb6319..4a207e0b126 100644
--- a/src/com/android/settings/fuelgauge/batterytip/tips/LowBatteryTip.java
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/LowBatteryTip.java
@@ -16,8 +16,9 @@
package com.android.settings.fuelgauge.batterytip.tips;
-import android.app.Dialog;
import android.content.Context;
+import android.os.Parcel;
+import android.os.Parcelable;
import com.android.settings.R;
@@ -27,9 +28,11 @@ import com.android.settings.R;
public class LowBatteryTip extends BatteryTip {
public LowBatteryTip(@StateType int state) {
- mShowDialog = false;
- mState = state;
- mType = TipType.LOW_BATTERY;
+ super(TipType.LOW_BATTERY, state, false /* showDialog */);
+ }
+
+ private LowBatteryTip(Parcel in) {
+ super(in);
}
@Override
@@ -57,9 +60,14 @@ public class LowBatteryTip extends BatteryTip {
// do nothing
}
- @Override
- public Dialog buildDialog() {
- //TODO(b/70570352): create the dialog for low battery tip and add test
- return null;
- }
+ public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
+ public BatteryTip createFromParcel(Parcel in) {
+ return new LowBatteryTip(in);
+ }
+
+ public BatteryTip[] newArray(int size) {
+ return new LowBatteryTip[size];
+ }
+ };
+
}
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/SummaryTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/SummaryTip.java
index 2a2deabfa8f..51019a8d35d 100644
--- a/src/com/android/settings/fuelgauge/batterytip/tips/SummaryTip.java
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/SummaryTip.java
@@ -16,8 +16,9 @@
package com.android.settings.fuelgauge.batterytip.tips;
-import android.app.Dialog;
import android.content.Context;
+import android.os.Parcel;
+import android.os.Parcelable;
import com.android.settings.R;
@@ -27,9 +28,11 @@ import com.android.settings.R;
public class SummaryTip extends BatteryTip {
public SummaryTip(@StateType int state) {
- mShowDialog = false;
- mState = state;
- mType = TipType.SUMMARY;
+ super(TipType.SUMMARY, state, false /* showDialog */);
+ }
+
+ private SummaryTip(Parcel in) {
+ super(in);
}
@Override
@@ -57,9 +60,13 @@ public class SummaryTip extends BatteryTip {
// do nothing
}
- @Override
- public Dialog buildDialog() {
- //TODO(b/70570352): create the dialog for summary tip and add test
- return null;
- }
+ public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
+ public BatteryTip createFromParcel(Parcel in) {
+ return new SummaryTip(in);
+ }
+
+ public BatteryTip[] newArray(int size) {
+ return new SummaryTip[size];
+ }
+ };
}
diff --git a/tests/robotests/src/com/android/settings/UtilsTest.java b/tests/robotests/src/com/android/settings/UtilsTest.java
index f8134578117..fb571bb5cf3 100644
--- a/tests/robotests/src/com/android/settings/UtilsTest.java
+++ b/tests/robotests/src/com/android/settings/UtilsTest.java
@@ -4,13 +4,16 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.anyString;
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.spy;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.net.ConnectivityManager;
import android.net.LinkAddress;
@@ -25,6 +28,7 @@ import android.os.storage.VolumeInfo;
import android.text.SpannableStringBuilder;
import android.text.format.DateUtils;
import android.text.style.TtsSpan;
+import android.util.IconDrawableFactory;
import android.widget.EditText;
import android.widget.TextView;
@@ -46,8 +50,8 @@ import java.util.List;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class UtilsTest {
-
private static final String PACKAGE_NAME = "com.android.app";
+ private static final int USER_ID = 1;
@Mock
private WifiManager wifiManager;
@@ -59,6 +63,12 @@ public class UtilsTest {
private DevicePolicyManagerWrapper mDevicePolicyManager;
@Mock
private UserManager mUserManager;
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ private IconDrawableFactory mIconDrawableFactory;
+ @Mock
+ private ApplicationInfo mApplicationInfo;
private Context mContext;
@Before
@@ -332,4 +342,17 @@ public class UtilsTest {
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);
+ }
+
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java
index 1393d5718b0..844aca4c4a5 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java
@@ -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_TOP;
import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP_SLEEPING;
+
import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyLong;
@@ -141,6 +143,7 @@ public class BatteryUtilsTest {
private BatteryUtils mBatteryUtils;
private FakeFeatureFactory mFeatureFactory;
private PowerUsageFeatureProvider mProvider;
+ private List mUsageList;
@Before
public void setUp() {
@@ -194,6 +197,12 @@ public class BatteryUtilsTest {
mBatteryUtils.mPowerUsageFeatureProvider = mProvider;
doReturn(0L).when(mBatteryUtils).getForegroundServiceTotalTimeUs(
any(BatteryStats.Uid.class), anyLong());
+
+ mUsageList = new ArrayList<>();
+ mUsageList.add(mNormalBatterySipper);
+ mUsageList.add(mScreenBatterySipper);
+ mUsageList.add(mCellBatterySipper);
+ doReturn(mUsageList).when(mBatteryStatsHelper).getUsageList();
}
@Test
@@ -468,4 +477,28 @@ public class BatteryUtilsTest {
verify(mBatteryStatsHelper).refreshStats(BatteryStats.STATS_SINCE_CHARGED,
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);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageAnomalyDetailsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageAnomalyDetailsTest.java
index c992d0aef63..8aa0659671d 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageAnomalyDetailsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageAnomalyDetailsTest.java
@@ -67,7 +67,6 @@ public class PowerUsageAnomalyDetailsTest {
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_3 = "com.android.app3";
- private static final int USER_ID = 1;
@Mock
private SettingsActivity mSettingsActivity;
@@ -198,16 +197,4 @@ public class PowerUsageAnomalyDetailsTest {
assertThat(mBundle.getParcelableArrayList(
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);
- }
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java
index 272890939aa..6fecf3ce928 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java
@@ -247,34 +247,6 @@ public class PowerUsageSummaryTest {
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
public void testUpdateLastFullChargePreference_showCorrectSummary() {
doReturn(mRealContext).when(mFragment).getContext();
@@ -284,16 +256,6 @@ public class PowerUsageSummaryTest {
assertThat(mLastFullChargePref.getSubtitle()).isEqualTo("2 hr. ago");
}
- @Test
- public void testUpdatePreference_usageListEmpty_shouldNotCrash() {
- when(mBatteryHelper.getUsageList()).thenReturn(new ArrayList());
- doReturn(STUB_STRING).when(mFragment).getString(anyInt(), any());
- doReturn(mRealContext).when(mFragment).getContext();
-
- // Should not crash when update
- mFragment.updateScreenPreference();
- }
-
@Test
public void testNonIndexableKeys_MatchPreferenceKeys() {
final Context context = RuntimeEnvironment.application;
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceControllerTest.java
index 944587fb21e..9f0c61fc9c8 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceControllerTest.java
@@ -85,7 +85,7 @@ public class BatteryTipPreferenceControllerTest {
mNewBatteryTips.add(new SummaryTip(BatteryTip.StateType.INVISIBLE));
mBatteryTipPreferenceController = new BatteryTipPreferenceController(mContext, KEY_PREF,
- mBatteryTipListener);
+ null, mBatteryTipListener);
mBatteryTipPreferenceController.mPreferenceGroup = mPreferenceGroup;
mBatteryTipPreferenceController.mPrefContext = mContext;
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetectorTest.java
new file mode 100644
index 00000000000..2a719916fb0
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetectorTest.java
@@ -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 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();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTipTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTipTest.java
index eec8e760914..1c6c8683c04 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTipTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTipTest.java
@@ -19,6 +19,8 @@ import static com.google.common.truth.Truth.assertThat;
import android.app.Dialog;
import android.content.Context;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.support.annotation.IdRes;
import android.support.v7.preference.Preference;
@@ -58,10 +60,32 @@ public class BatteryTipTest {
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}
*/
- public class TestBatteryTip extends BatteryTip {
+ public static class TestBatteryTip extends BatteryTip {
+ TestBatteryTip() {
+ super(TipType.SUMMARY, StateType.NEW, true);
+ }
+
+ TestBatteryTip(Parcel in) {
+ super(in);
+ }
@Override
public String getTitle(Context context) {
@@ -88,10 +112,15 @@ public class BatteryTipTest {
// do nothing
}
- @Override
- public Dialog buildDialog() {
- return null;
- }
+ public final Parcelable.Creator CREATOR = new Parcelable.Creator() {
+ public BatteryTip createFromParcel(Parcel in) {
+ return new TestBatteryTip(in);
+ }
+
+ public BatteryTip[] newArray(int size) {
+ return new TestBatteryTip[size];
+ }
+ };
}
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/HighUsageTipTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/HighUsageTipTest.java
new file mode 100644
index 00000000000..e2f8a26cc7e
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/HighUsageTipTest.java
@@ -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 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);
+ }
+}