From fde637ff603ef3d28cacb221a749f3d4653760b8 Mon Sep 17 00:00:00 2001 From: jackqdyulei Date: Tue, 2 Jan 2018 14:51:01 -0800 Subject: [PATCH] Add BatteryTipDialogFragment. This DialogFragment handles all the tip related dialogs. This cl makes: 1. All the tips parcelable. 2. Add dialog for HighUsageTip. It also need adapter to populate app list in dialog. 3. Add and update tests Bug: 70570352 Test: RunSettingsRoboTests Change-Id: Ie4c986172cfc73d8746abc7457d966c8600c6145 --- res/layout/app_high_usage_item.xml | 48 ++++++++++ res/layout/recycler_view.xml | 23 +++++ src/com/android/settings/Utils.java | 15 +++ .../fuelgauge/PowerUsageAnomalyDetails.java | 9 +- .../settings/fuelgauge/PowerUsageSummary.java | 2 +- .../batterytip/BatteryTipDialogFragment.java | 104 +++++++++++++++++++++ .../batterytip/BatteryTipPreferenceController.java | 15 ++- .../fuelgauge/batterytip/HighUsageAdapter.java | 87 +++++++++++++++++ .../fuelgauge/batterytip/HighUsageApp.java | 64 +++++++++++++ .../batterytip/detectors/HighUsageDetector.java | 8 +- .../fuelgauge/batterytip/tips/BatteryTip.java | 42 +++++++-- .../fuelgauge/batterytip/tips/HighUsageTip.java | 66 +++++++------ .../fuelgauge/batterytip/tips/LowBatteryTip.java | 26 ++++-- .../fuelgauge/batterytip/tips/SummaryTip.java | 25 +++-- .../src/com/android/settings/UtilsTest.java | 25 ++++- .../fuelgauge/PowerUsageAnomalyDetailsTest.java | 13 --- .../BatteryTipPreferenceControllerTest.java | 2 +- .../fuelgauge/batterytip/tips/BatteryTipTest.java | 39 +++++++- .../batterytip/tips/HighUsageTipTest.java | 74 +++++++++++++++ 19 files changed, 598 insertions(+), 89 deletions(-) create mode 100755 res/layout/app_high_usage_item.xml create mode 100644 res/layout/recycler_view.xml create mode 100644 src/com/android/settings/fuelgauge/batterytip/BatteryTipDialogFragment.java create mode 100644 src/com/android/settings/fuelgauge/batterytip/HighUsageAdapter.java create mode 100644 src/com/android/settings/fuelgauge/batterytip/HighUsageApp.java create mode 100644 tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/HighUsageTipTest.java diff --git a/res/layout/app_high_usage_item.xml b/res/layout/app_high_usage_item.xml new file mode 100755 index 0000000000..473315f2ad --- /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 0000000000..a7dabe5d72 --- /dev/null +++ b/res/layout/recycler_view.xml @@ -0,0 +1,23 @@ + + + diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java index cd64799f80..ad95121678 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/PowerUsageAnomalyDetails.java b/src/com/android/settings/fuelgauge/PowerUsageAnomalyDetails.java index 0d73511e84..143733db2b 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 507043f155..205ac0b15a 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)); 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 0000000000..3e091b3b44 --- /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/BatteryTipPreferenceController.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceController.java index f6114052cf..9aa70c5526 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 0000000000..8b74394664 --- /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 0000000000..f75ecf0e32 --- /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 index 5c2ecad1e0..237f430c57 100644 --- a/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetector.java +++ b/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetector.java @@ -26,6 +26,7 @@ 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; @@ -41,7 +42,7 @@ import java.util.List; public class HighUsageDetector implements BatteryTipDetector { private BatteryTipPolicy mPolicy; private BatteryStatsHelper mBatteryStatsHelper; - private List mHighUsageAppList; + private List mHighUsageAppList; private Context mContext; @VisibleForTesting BatteryUtils mBatteryUtils; @@ -67,7 +68,7 @@ public class HighUsageDetector implements BatteryTipDetector { final long foregroundTimeMs = mBatteryUtils.getProcessTimeMs( BatteryUtils.StatusType.FOREGROUND, batterySipper.uidObj, BatteryStats.STATS_SINCE_CHARGED); - mHighUsageAppList.add(new HighUsageTip.HighUsageApp( + mHighUsageAppList.add(new HighUsageApp( mBatteryUtils.getPackageName(batterySipper.getUid()), foregroundTimeMs)); } @@ -78,7 +79,6 @@ public class HighUsageDetector implements BatteryTipDetector { Collections.sort(mHighUsageAppList, Collections.reverseOrder()); } - return new HighUsageTip(Utils.formatElapsedTime(mContext, screenUsageTimeMs, false), - mHighUsageAppList); + 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 17e395ef18..eadd0e1a81 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 index 38f2a26c94..001a48eedc 100644 --- a/src/com/android/settings/fuelgauge/batterytip/tips/HighUsageTip.java +++ b/src/com/android/settings/fuelgauge/batterytip/tips/HighUsageTip.java @@ -16,10 +16,14 @@ 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.VisibleForTesting; import com.android.settings.R; +import com.android.settings.Utils; +import com.android.settings.fuelgauge.batterytip.HighUsageApp; import java.util.List; @@ -28,15 +32,29 @@ import java.util.List; */ public class HighUsageTip extends BatteryTip { - private final CharSequence mScreenTimeText; - private final List mHighUsageAppList; + private final long mScreenTimeMs; + @VisibleForTesting + final List mHighUsageAppList; - public HighUsageTip(CharSequence screenTimeText, List appList) { - mShowDialog = true; - mScreenTimeText = screenTimeText; - mType = TipType.HIGH_DEVICE_USAGE; + public HighUsageTip(long screenTimeMs, List appList) { + super(TipType.HIGH_DEVICE_USAGE, appList.isEmpty() ? StateType.INVISIBLE : StateType.NEW, + true /* showDialog */); + mScreenTimeMs = screenTimeMs; mHighUsageAppList = appList; - mState = appList.isEmpty() ? StateType.INVISIBLE : StateType.NEW; + } + + @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 @@ -46,7 +64,8 @@ public class HighUsageTip extends BatteryTip { @Override public CharSequence getSummary(Context context) { - return context.getString(R.string.battery_tip_high_usage_summary, mScreenTimeText); + return context.getString(R.string.battery_tip_high_usage_summary, + Utils.formatElapsedTime(context, mScreenTimeMs, false)); } @Override @@ -64,27 +83,22 @@ public class HighUsageTip extends BatteryTip { // do nothing } - @Override - public Dialog buildDialog() { - //TODO(b/70570352): build the real dialog - return null; + public long getScreenTimeMs() { + return mScreenTimeMs; } - /** - * Class representing app with high screen usage - */ - public static class HighUsageApp implements Comparable { - public final String packageName; - public final long screenOnTimeMs; + public List getHighUsageAppList() { + return mHighUsageAppList; + } - public HighUsageApp(String packageName, long screenOnTimeMs) { - this.packageName = packageName; - this.screenOnTimeMs = screenOnTimeMs; + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public BatteryTip createFromParcel(Parcel in) { + return new HighUsageTip(in); } - @Override - public int compareTo(HighUsageApp o) { - return Long.compare(screenOnTimeMs, o.screenOnTimeMs); + 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 8605fbb631..4a207e0b12 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 2a2deabfa8..51019a8d35 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 f813457811..fb571bb5cf 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/PowerUsageAnomalyDetailsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageAnomalyDetailsTest.java index c992d0aef6..8aa0659671 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/batterytip/BatteryTipPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceControllerTest.java index 944587fb21..9f0c61fc9c 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/tips/BatteryTipTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTipTest.java index eec8e76091..1c6c8683c0 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 0000000000..e2f8a26cc7 --- /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); + } +} -- 2.11.0