From e756675e692daa1675a15d82e75dea09ce98d055 Mon Sep 17 00:00:00 2001 From: Zaiyue Xue Date: Sat, 17 Dec 2022 15:53:40 +0800 Subject: [PATCH] Combine system apps to one item in the battery usage app list. Bug: 262952385 Test: 262952385 Test: maunal Change-Id: I078677b13a22f5e2f8f194bb5d5259f8c54c6b1e --- res/values/config.xml | 3 - res/values/strings.xml | 2 + .../fuelgauge/PowerUsageFeatureProvider.java | 6 + .../PowerUsageFeatureProviderImpl.java | 6 + .../batteryusage/BatteryDiffEntry.java | 69 ++++++-- .../fuelgauge/batteryusage/BatteryEntry.java | 4 +- .../BatteryUsageBreakdownController.java | 2 +- .../fuelgauge/batteryusage/DataProcessor.java | 67 ++++++- .../BatteryChartPreferenceControllerTest.java | 1 + .../batteryusage/BatteryDiffEntryTest.java | 27 --- .../batteryusage/BatteryEntryTest.java | 12 +- .../batteryusage/DataProcessorTest.java | 167 ++++++++++++++---- 12 files changed, 276 insertions(+), 90 deletions(-) diff --git a/res/values/config.xml b/res/values/config.xml index bbacc5c23ca..40ca07fee27 100755 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -603,9 +603,6 @@ false - - false - 12 diff --git a/res/values/strings.xml b/res/values/strings.xml index c64ba93fee3..fe7353b6f67 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -5065,6 +5065,8 @@ No usage for past 24 hr + + System apps Estimated time left diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java index 676af2c3abe..3b4ab3716b3 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java +++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java @@ -22,6 +22,7 @@ import android.util.SparseIntArray; import com.android.settingslib.fuelgauge.Estimate; +import java.util.List; import java.util.Set; /** @@ -34,6 +35,11 @@ public interface PowerUsageFeatureProvider { */ boolean isBatteryUsageEnabled(Context context); + /** + * Returns an allowlist of app names combined into the system-apps item + */ + List getSystemAppsAllowlist(Context context); + /** * Check whether location setting is enabled */ diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java index 6e4ff95d4d0..522f6232b36 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java +++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java @@ -26,6 +26,7 @@ import android.util.SparseIntArray; import com.android.internal.util.ArrayUtils; import com.android.settingslib.fuelgauge.Estimate; +import java.util.List; import java.util.Set; /** Implementation of {@code PowerUsageFeatureProvider} */ @@ -70,6 +71,11 @@ public class PowerUsageFeatureProviderImpl implements PowerUsageFeatureProvider return true; } + @Override + public List getSystemAppsAllowlist(Context context) { + return null; + } + @Override public boolean isLocationSettingEnabled(String[] packages) { return false; diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java index 2c23bb377bd..bbd2b66a054 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java +++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java @@ -15,12 +15,12 @@ */ package com.android.settings.fuelgauge.batteryusage; +import android.content.ContentValues; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.graphics.drawable.Drawable; -import android.os.Process; import android.os.UserHandle; import android.os.UserManager; import android.util.Log; @@ -62,10 +62,10 @@ public class BatteryDiffEntry { // A BatteryHistEntry corresponding to this diff usage data. public final BatteryHistEntry mBatteryHistEntry; + protected Context mContext; + private double mTotalConsumePower; private double mPercentOfTotal; - - private Context mContext; private UserManager mUserManager; private String mDefaultPackageName = null; @@ -111,6 +111,11 @@ public class BatteryDiffEntry { ? 0 : (mConsumePower / mTotalConsumePower) * 100.0; } + /** Gets the total consumed power in a specific time slot. */ + public double getTotalConsumePower() { + return mTotalConsumePower; + } + /** Gets the percentage of total consumed power. */ public double getPercentOfTotal() { return mPercentOfTotal; @@ -176,23 +181,17 @@ public class BatteryDiffEntry { /** Whether the current BatteryDiffEntry is system component or not. */ public boolean isSystemEntry() { + if (mBatteryHistEntry.mIsHidden) { + return false; + } switch (mBatteryHistEntry.mConsumerType) { case ConvertUtils.CONSUMER_TYPE_USER_BATTERY: case ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY: return true; case ConvertUtils.CONSUMER_TYPE_UID_BATTERY: - final int uid = (int) mBatteryHistEntry.mUid; - if (mBatteryHistEntry.mIsHidden - || uid == BatteryUtils.UID_REMOVED_APPS - || uid == BatteryUtils.UID_TETHERING) { - return true; - } - final boolean combineSystemComponents = - mContext.getResources().getBoolean( - R.bool.config_battery_combine_system_components); - return combineSystemComponents && isSystemUid(uid); + default: + return false; } - return false; } void loadLabelAndIcon() { @@ -396,8 +395,44 @@ public class BatteryDiffEntry { mUserManager.getBadgedIconForUser(icon, new UserHandle(userId)); } - private static boolean isSystemUid(int uid) { - final int appUid = UserHandle.getAppId(uid); - return appUid >= Process.SYSTEM_UID && appUid < Process.FIRST_APPLICATION_UID; + /** Specific battery diff entry for system apps. */ + static class SystemAppsBatteryDiffEntry extends BatteryDiffEntry { + SystemAppsBatteryDiffEntry(Context context) { + super(context, + /*foregroundUsageTimeInMs=*/ 0, + /*backgroundUsageTimeInMs=*/ 0, + /*screenOnTimeInMs=*/ 0, + /*consumePower=*/ 0, + /*foregroundUsageConsumePower=*/ 0, + /*foregroundServiceUsageConsumePower=*/ 0, + /*backgroundUsageConsumePower=*/ 0, + /*cachedUsageConsumePower=*/ 0, + new BatteryHistEntry(new ContentValues())); + } + + @Override + public String getKey() { + return "A|SystemApps"; + } + + @Override + public String getAppLabel() { + return mContext.getString(R.string.battery_usage_system_apps); + } + + @Override + public Drawable getAppIcon() { + return mContext.getDrawable(R.drawable.ic_power_system); + } + + @Override + public boolean validForRestriction() { + return false; + } + + @Override + public boolean isSystemEntry() { + return false; + } } } diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryEntry.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryEntry.java index ba1ebaba860..acf62c264c5 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/BatteryEntry.java +++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryEntry.java @@ -200,11 +200,11 @@ public class BatteryEntry { /** Battery entry for a power component of AggregateBatteryConsumer */ public BatteryEntry(Context context, int powerComponentId, double devicePowerMah, - long usageDurationMs) { + long usageDurationMs, boolean isHidden) { mContext = context; mBatteryConsumer = null; mUid = Process.INVALID_UID; - mIsHidden = false; + mIsHidden = isHidden; mPowerComponentId = powerComponentId; mConsumedPower = devicePowerMah; mUsageDurationMs = usageDurationMs; diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java index 2f88e752daa..10cfd39fb9d 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java +++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java @@ -242,7 +242,7 @@ public class BatteryUsageBreakdownController extends BasePreferenceController Log.w(TAG, "cannot find app resource for:" + entry.getPackageName()); continue; } - final String prefKey = entry.mBatteryHistEntry.getKey(); + final String prefKey = entry.getKey(); PowerGaugePreference pref = mAppListPreferenceGroup.findPreference(prefKey); if (pref != null) { isAdded = true; diff --git a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java index 14b08dd0883..b0128bf0231 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java +++ b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java @@ -19,6 +19,7 @@ package com.android.settings.fuelgauge.batteryusage; import static com.android.settings.fuelgauge.batteryusage.ConvertUtils.getEffectivePackageName; import static com.android.settings.fuelgauge.batteryusage.ConvertUtils.utcToLocalTime; +import android.app.Application; import android.app.usage.IUsageStatsManager; import android.app.usage.UsageEvents; import android.app.usage.UsageEvents.Event; @@ -52,6 +53,7 @@ import com.android.internal.os.PowerProfile; import com.android.settings.Utils; import com.android.settings.fuelgauge.BatteryUtils; import com.android.settings.overlay.FeatureFactory; +import com.android.settingslib.applications.ApplicationsState; import com.android.settingslib.fuelgauge.BatteryStatus; import java.time.Duration; @@ -75,6 +77,8 @@ import java.util.stream.Stream; public final class DataProcessor { private static final boolean DEBUG = false; private static final String TAG = "DataProcessor"; + private static final int POWER_COMPONENT_SYSTEM_SERVICES = 7; + private static final int POWER_COMPONENT_WAKELOCK = 12; private static final int MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP = 10; private static final int MIN_DAILY_DATA_SIZE = 2; private static final int MIN_TIMESTAMP_DATA_SIZE = 2; @@ -1714,6 +1718,7 @@ public final class DataProcessor { hideBackgroundUsageTimeSet); batteryDiffData.setTotalConsumePower(); batteryDiffData.sortEntries(); + combineIntoSystemApps(context, batteryDiffData); }); }); } @@ -1739,6 +1744,64 @@ public final class DataProcessor { } } + private static void combineIntoSystemApps( + final Context context, final BatteryDiffData batteryDiffData) { + final List systemAppsAllowlist = + FeatureFactory.getFactory(context) + .getPowerUsageFeatureProvider(context) + .getSystemAppsAllowlist(context); + final Application application = (Application) context.getApplicationContext(); + final ApplicationsState applicationsState = + application == null ? null : ApplicationsState.getInstance(application); + + BatteryDiffEntry.SystemAppsBatteryDiffEntry systemAppsDiffEntry = null; + final Iterator appListIterator = + batteryDiffData.getAppDiffEntryList().iterator(); + while (appListIterator.hasNext()) { + final BatteryDiffEntry batteryDiffEntry = appListIterator.next(); + if (needsCombineInSystemApp(batteryDiffEntry, systemAppsAllowlist, applicationsState)) { + if (systemAppsDiffEntry == null) { + systemAppsDiffEntry = new BatteryDiffEntry.SystemAppsBatteryDiffEntry(context); + } + systemAppsDiffEntry.mConsumePower += batteryDiffEntry.mConsumePower; + systemAppsDiffEntry.setTotalConsumePower( + batteryDiffEntry.getTotalConsumePower()); + appListIterator.remove(); + } + } + if (systemAppsDiffEntry != null) { + batteryDiffData.getAppDiffEntryList().add(systemAppsDiffEntry); + } + } + + @VisibleForTesting + static boolean needsCombineInSystemApp(final BatteryDiffEntry batteryDiffEntry, + final List systemAppsAllowlist, final ApplicationsState applicationsState) { + if (batteryDiffEntry.mBatteryHistEntry.mIsHidden) { + return true; + } + + final String packageName = batteryDiffEntry.getPackageName(); + if (packageName == null || packageName.isEmpty()) { + return false; + } + + if (systemAppsAllowlist != null && systemAppsAllowlist.contains(packageName)) { + return true; + } + + if (applicationsState == null) { + return false; + } + final ApplicationsState.AppEntry appEntry = + applicationsState.getEntry(packageName, /* userId= */ 0); + if (appEntry == null || appEntry.info == null) { + return false; + } + return !ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER_AND_INSTANT.filterApp( + appEntry); + } + private static boolean shouldShowBatteryAttributionList(final Context context) { final PowerProfile powerProfile = new PowerProfile(context); // Cheap hack to try to figure out if the power_profile.xml was populated. @@ -1804,7 +1867,9 @@ public final class DataProcessor { componentId++) { results.add(new BatteryEntry(context, componentId, deviceConsumer.getConsumedPower(componentId), - deviceConsumer.getUsageDurationMillis(componentId))); + deviceConsumer.getUsageDurationMillis(componentId), + componentId == POWER_COMPONENT_SYSTEM_SERVICES + || componentId == POWER_COMPONENT_WAKELOCK)); } for (int componentId = BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID; diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java index a31fffa6717..054b44f01be 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java @@ -95,6 +95,7 @@ public final class BatteryChartPreferenceControllerTest { .when(mContext) .getSystemService(UserManager.class); doReturn(true).when(mUserManager).isUserUnlocked(anyInt()); + doReturn(new int[]{0}).when(mUserManager).getProfileIdsWithDisabled(anyInt()); final Resources resources = spy(mContext.getResources()); resources.getConfiguration().setLocales(new LocaleList(new Locale("en_US"))); doReturn(resources).when(mContext).getResources(); diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java index 900913b5526..4883563f026 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java @@ -370,15 +370,6 @@ public final class BatteryDiffEntryTest { assertThat(entry.isSystemEntry()).isFalse(); } - @Test - public void testIsSystemEntry_uidBatteryWithHiddenState_returnTrue() { - final BatteryDiffEntry entry = - createBatteryDiffEntry( - ConvertUtils.CONSUMER_TYPE_UID_BATTERY, - /*uid=*/ 123, /*isHidden=*/ true); - assertThat(entry.isSystemEntry()).isTrue(); - } - @Test public void testIsSystemEntry_uidBatteryWithSystemProcess_returnFalse() { final BatteryDiffEntry entry = @@ -388,24 +379,6 @@ public final class BatteryDiffEntryTest { assertThat(entry.isSystemEntry()).isFalse(); } - @Test - public void testIsSystemEntry_uidBatteryWithTetheringProcess_returnTrue() { - final BatteryDiffEntry entry = - createBatteryDiffEntry( - ConvertUtils.CONSUMER_TYPE_UID_BATTERY, - /*uid=*/ BatteryUtils.UID_TETHERING, /*isHidden=*/ false); - assertThat(entry.isSystemEntry()).isTrue(); - } - - @Test - public void testIsSystemEntry_uidBatteryWithRemovedAppsProcess_returnTrue() { - final BatteryDiffEntry entry = - createBatteryDiffEntry( - ConvertUtils.CONSUMER_TYPE_UID_BATTERY, - /*uid=*/ BatteryUtils.UID_REMOVED_APPS, /*isHidden=*/ false); - assertThat(entry.isSystemEntry()).isTrue(); - } - @Test public void testUpdateRestrictionFlagState_updateFlagAsExpected() throws Exception { final String expectedAppLabel = "fake app label"; diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryEntryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryEntryTest.java index 7e5aaea68e1..07a8dfefb9f 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryEntryTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryEntryTest.java @@ -108,7 +108,8 @@ public class BatteryEntryTest { mMockContext, powerComponentId, /* devicePowerMah= */ 200, - /* usageDurationMs= */ 1000); + /* usageDurationMs= */ 1000, + /* isHidden= */ false); } private BatteryEntry createCustomAggregateBatteryEntry(int powerComponentId) { @@ -169,7 +170,8 @@ public class BatteryEntryTest { final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY, /* devicePowerMah= */ 200, - /* usageDurationMs= */ 1000); + /* usageDurationMs= */ 1000, + /* isHidden= */ false); assertThat(entry.mIconId).isEqualTo(R.drawable.ic_settings_aod); assertThat(entry.mName).isEqualTo("Ambient display"); @@ -202,7 +204,8 @@ public class BatteryEntryTest { final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, BatteryConsumer.POWER_COMPONENT_BLUETOOTH, /* devicePowerMah= */ 10, - /* usageDurationMs= */ 100); + /* usageDurationMs= */ 100, + /* isHidden= */ false); assertThat(entry.getTimeInForegroundMs()).isEqualTo(100L); } @@ -223,7 +226,8 @@ public class BatteryEntryTest { final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, BatteryConsumer.POWER_COMPONENT_BLUETOOTH, /* devicePowerMah= */ 100, - /* usageDurationMs= */ 1000); + /* usageDurationMs= */ 1000, + /* isHidden= */ false); assertThat(entry.getTimeInBackgroundMs()).isEqualTo(0); } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java index fb91ea2060d..a1caa2c88a9 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java @@ -21,6 +21,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.spy; @@ -32,6 +33,7 @@ import android.app.usage.UsageEvents.Event; import android.content.ContentValues; import android.content.Context; import android.content.Intent; +import android.content.pm.ApplicationInfo; import android.content.pm.UserInfo; import android.os.BatteryConsumer; import android.os.BatteryManager; @@ -43,6 +45,7 @@ import android.text.format.DateUtils; import com.android.settings.fuelgauge.PowerUsageFeatureProvider; import com.android.settings.testutils.FakeFeatureFactory; +import com.android.settingslib.applications.ApplicationsState; import org.junit.Before; import org.junit.Test; @@ -75,13 +78,15 @@ public final class DataProcessorTest { @Mock private BatteryUsageStats mBatteryUsageStats; @Mock private UserManager mUserManager; @Mock private IUsageStatsManager mUsageStatsManager; + @Mock private ApplicationsState mApplicationsState; + @Mock private ApplicationsState.AppEntry mAppEntry; + @Mock private ApplicationInfo mApplicationInfo; @Mock private BatteryEntry mMockBatteryEntry1; @Mock private BatteryEntry mMockBatteryEntry2; @Mock private BatteryEntry mMockBatteryEntry3; @Mock private BatteryEntry mMockBatteryEntry4; @Mock private UsageEvents mUsageEvents1; - @Before public void setUp() { MockitoAnnotations.initMocks(this); @@ -95,7 +100,9 @@ public final class DataProcessorTest { doReturn(mIntent).when(mContext).registerReceiver(any(), any()); doReturn(100).when(mIntent).getIntExtra(eq(BatteryManager.EXTRA_SCALE), anyInt()); doReturn(66).when(mIntent).getIntExtra(eq(BatteryManager.EXTRA_LEVEL), anyInt()); + doReturn(mContext).when(mContext).getApplicationContext(); doReturn(mUserManager).when(mContext).getSystemService(UserManager.class); + doReturn(new int[]{0}).when(mUserManager).getProfileIdsWithDisabled(anyInt()); } @Test @@ -768,7 +775,8 @@ public final class DataProcessorTest { /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0, /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0, /*uid=*/ 0L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, - /*foregroundUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L); + /*foregroundUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L, + /*isHidden=*/ false); // Adds the index = 0 data. Map entryMap = new HashMap<>(); BatteryHistEntry entry = createBatteryHistEntry( @@ -777,7 +785,7 @@ public final class DataProcessorTest { /*backgroundUsageConsumePower=*/ 3, /*cachedUsageConsumePower=*/ 0, /*uid=*/ 1L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L, - /*backgroundUsageTimeInMs=*/ 20L); + /*backgroundUsageTimeInMs=*/ 20L, /*isHidden=*/ false); entryMap.put(entry.getKey(), entry); entryMap.put(fakeEntry.getKey(), fakeEntry); batteryHistoryMap.put(batteryHistoryKeys[0], entryMap); @@ -793,7 +801,7 @@ public final class DataProcessorTest { /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5, /*uid=*/ 2L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 15L, - /*backgroundUsageTimeInMs=*/ 25L); + /*backgroundUsageTimeInMs=*/ 25L, /*isHidden=*/ false); entryMap.put(entry.getKey(), entry); entryMap.put(fakeEntry.getKey(), fakeEntry); batteryHistoryMap.put(batteryHistoryKeys[2], entryMap); @@ -805,7 +813,7 @@ public final class DataProcessorTest { /*backgroundUsageConsumePower=*/ 8, /*cachedUsageConsumePower=*/ 8, /*uid=*/ 2L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 25L, - /*backgroundUsageTimeInMs=*/ 35L); + /*backgroundUsageTimeInMs=*/ 35L, /*isHidden=*/ false); entryMap.put(entry.getKey(), entry); entry = createBatteryHistEntry( "package3", "label3", /*consumePower=*/ 10.0, @@ -813,7 +821,7 @@ public final class DataProcessorTest { /*backgroundUsageConsumePower=*/ 2, /*cachedUsageConsumePower=*/ 2, /*uid=*/ 3L, currentUserId, ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY, /*foregroundUsageTimeInMs=*/ 40L, - /*backgroundUsageTimeInMs=*/ 50L); + /*backgroundUsageTimeInMs=*/ 50L, /*isHidden=*/ false); entryMap.put(entry.getKey(), entry); entry = createBatteryHistEntry( "package4", "label3", /*consumePower=*/ 15.0, @@ -821,7 +829,7 @@ public final class DataProcessorTest { /*backgroundUsageConsumePower=*/ 3, /*cachedUsageConsumePower=*/ 3, /*uid=*/ 4L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 5L, - /*backgroundUsageTimeInMs=*/ 5L); + /*backgroundUsageTimeInMs=*/ 5L, /*isHidden=*/ false); entryMap.put(entry.getKey(), entry); entryMap.put(fakeEntry.getKey(), fakeEntry); batteryHistoryMap.put(batteryHistoryKeys[3], entryMap); @@ -833,7 +841,7 @@ public final class DataProcessorTest { /*backgroundUsageConsumePower=*/ 9, /*cachedUsageConsumePower=*/ 8, /*uid=*/ 2L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 30L, - /*backgroundUsageTimeInMs=*/ 40L); + /*backgroundUsageTimeInMs=*/ 40L, /*isHidden=*/ false); entryMap.put(entry.getKey(), entry); entry = createBatteryHistEntry( "package3", "label3", /*consumePower=*/ 20.0, @@ -841,7 +849,7 @@ public final class DataProcessorTest { /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5, /*uid=*/ 3L, currentUserId, ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY, /*foregroundUsageTimeInMs=*/ 50L, - /*backgroundUsageTimeInMs=*/ 60L); + /*backgroundUsageTimeInMs=*/ 60L, /*isHidden=*/ false); entryMap.put(entry.getKey(), entry); entry = createBatteryHistEntry( "package4", "label4", /*consumePower=*/ 40.0, @@ -849,7 +857,7 @@ public final class DataProcessorTest { /*backgroundUsageConsumePower=*/ 8, /*cachedUsageConsumePower=*/ 8, /*uid=*/ 4L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 5L, - /*backgroundUsageTimeInMs=*/ 5L); + /*backgroundUsageTimeInMs=*/ 5L, /*isHidden=*/ false); entryMap.put(entry.getKey(), entry); entryMap.put(fakeEntry.getKey(), fakeEntry); batteryHistoryMap.put(batteryHistoryKeys[4], entryMap); @@ -966,7 +974,7 @@ public final class DataProcessorTest { /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0, /*uid=*/ 1L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L, - /*backgroundUsageTimeInMs=*/ 20L); + /*backgroundUsageTimeInMs=*/ 20L, /*isHidden=*/ false); entryMap.put(entry.getKey(), entry); entry = createBatteryHistEntry( "package1", "label1", /*consumePower=*/ 10.0, @@ -974,7 +982,7 @@ public final class DataProcessorTest { /*backgroundUsageConsumePower=*/ 1, /*cachedUsageConsumePower=*/ 1, /*uid=*/ 2L, currentUserId + 1, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L, - /*backgroundUsageTimeInMs=*/ 20L); + /*backgroundUsageTimeInMs=*/ 20L, /*isHidden=*/ false); entryMap.put(entry.getKey(), entry); entry = createBatteryHistEntry( "package2", "label2", /*consumePower=*/ 5.0, @@ -982,7 +990,7 @@ public final class DataProcessorTest { /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0, /*uid=*/ 3L, currentUserId + 2, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 20L, - /*backgroundUsageTimeInMs=*/ 30L); + /*backgroundUsageTimeInMs=*/ 30L, /*isHidden=*/ false); entryMap.put(entry.getKey(), entry); batteryHistoryMap.put(batteryHistoryKeys[0], entryMap); // Adds the index = 1 data. @@ -993,7 +1001,7 @@ public final class DataProcessorTest { /*backgroundUsageConsumePower=*/ 2, /*cachedUsageConsumePower=*/ 2, /*uid=*/ 1L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 20L, - /*backgroundUsageTimeInMs=*/ 30L); + /*backgroundUsageTimeInMs=*/ 30L, /*isHidden=*/ false); entryMap.put(entry.getKey(), entry); entry = createBatteryHistEntry( "package1", "label1", /*consumePower=*/ 30.0, @@ -1001,7 +1009,7 @@ public final class DataProcessorTest { /*backgroundUsageConsumePower=*/ 2, /*cachedUsageConsumePower=*/ 2, /*uid=*/ 2L, currentUserId + 1, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L, - /*backgroundUsageTimeInMs=*/ 20L); + /*backgroundUsageTimeInMs=*/ 20L, /*isHidden=*/ false); entryMap.put(entry.getKey(), entry); entry = createBatteryHistEntry( "package2", "label2", /*consumePower=*/ 15.0, @@ -1009,7 +1017,7 @@ public final class DataProcessorTest { /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0, /*uid=*/ 3L, currentUserId + 2, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 30L, - /*backgroundUsageTimeInMs=*/ 30L); + /*backgroundUsageTimeInMs=*/ 30L, /*isHidden=*/ false); entryMap.put(entry.getKey(), entry); batteryHistoryMap.put(batteryHistoryKeys[1], entryMap); // Adds the index = 2 data. @@ -1020,7 +1028,7 @@ public final class DataProcessorTest { /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5, /*uid=*/ 1L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 20L, - /*backgroundUsageTimeInMs=*/ 30L); + /*backgroundUsageTimeInMs=*/ 30L, /*isHidden=*/ false); entryMap.put(entry.getKey(), entry); entry = createBatteryHistEntry( "package1", "label1", /*consumePower=*/ 50.0, @@ -1028,7 +1036,7 @@ public final class DataProcessorTest { /*backgroundUsageConsumePower=*/ 10, /*cachedUsageConsumePower=*/ 10, /*uid=*/ 2L, currentUserId + 1, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 20L, - /*backgroundUsageTimeInMs=*/ 20L); + /*backgroundUsageTimeInMs=*/ 20L, /*isHidden=*/ false); entryMap.put(entry.getKey(), entry); entry = createBatteryHistEntry( "package2", "label2", /*consumePower=*/ 25.0, @@ -1036,7 +1044,7 @@ public final class DataProcessorTest { /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 0, /*uid=*/ 3L, currentUserId + 2, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 30L, - /*backgroundUsageTimeInMs=*/ 30L); + /*backgroundUsageTimeInMs=*/ 30L, /*isHidden=*/ false); entryMap.put(entry.getKey(), entry); batteryHistoryMap.put(batteryHistoryKeys[2], entryMap); final List hourlyBatteryLevelsPerDay = @@ -1084,7 +1092,7 @@ public final class DataProcessorTest { /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0, /*uid=*/ 1L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L, - /*backgroundUsageTimeInMs=*/ 0L); + /*backgroundUsageTimeInMs=*/ 0L, /*isHidden=*/ false); entryMap.put(entry.getKey(), entry); batteryHistoryMap.put(batteryHistoryKeys[0], entryMap); // Adds the index = 1 data. @@ -1095,7 +1103,7 @@ public final class DataProcessorTest { /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0, /*uid=*/ 1L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L, - /*backgroundUsageTimeInMs=*/ 0L); + /*backgroundUsageTimeInMs=*/ 0L, /*isHidden=*/ false); entryMap.put(entry.getKey(), entry); batteryHistoryMap.put(batteryHistoryKeys[1], entryMap); // Adds the index = 2 data. @@ -1106,7 +1114,7 @@ public final class DataProcessorTest { /*backgroundUsageConsumePower=*/ 100, /*cachedUsageConsumePower=*/ 100, /*uid=*/ 1L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 3600000L, - /*backgroundUsageTimeInMs=*/ 7200000L); + /*backgroundUsageTimeInMs=*/ 7200000L, /*isHidden=*/ false); entryMap.put(entry.getKey(), entry); batteryHistoryMap.put(batteryHistoryKeys[2], entryMap); final List hourlyBatteryLevelsPerDay = @@ -1174,7 +1182,7 @@ public final class DataProcessorTest { /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0, /*uid=*/ 1L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L, - /*backgroundUsageTimeInMs=*/ 0L); + /*backgroundUsageTimeInMs=*/ 0L, /*isHidden=*/ false); entryMap.put(entry.getKey(), entry); entry = createBatteryHistEntry( "package2", "label2", /*consumePower=*/ 0, @@ -1182,7 +1190,7 @@ public final class DataProcessorTest { /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0, /*uid=*/ 2L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L, - /*backgroundUsageTimeInMs=*/ 0L); + /*backgroundUsageTimeInMs=*/ 0L, /*isHidden=*/ false); entryMap.put(entry.getKey(), entry); batteryHistoryMap.put(batteryHistoryKeys[0], entryMap); // Adds the index = 1 data. @@ -1193,7 +1201,7 @@ public final class DataProcessorTest { /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0, /*uid=*/ 1L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L, - /*backgroundUsageTimeInMs=*/ 0L); + /*backgroundUsageTimeInMs=*/ 0L, /*isHidden=*/ false); entryMap.put(entry.getKey(), entry); entry = createBatteryHistEntry( "package2", "label2", /*consumePower=*/ 0, @@ -1201,7 +1209,7 @@ public final class DataProcessorTest { /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0, /*uid=*/ 2L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L, - /*backgroundUsageTimeInMs=*/ 0L); + /*backgroundUsageTimeInMs=*/ 0L, /*isHidden=*/ false); entryMap.put(entry.getKey(), entry); batteryHistoryMap.put(batteryHistoryKeys[1], entryMap); // Adds the index = 2 data. @@ -1212,7 +1220,7 @@ public final class DataProcessorTest { /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0, /*uid=*/ 1L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L, - /*backgroundUsageTimeInMs=*/ 20L); + /*backgroundUsageTimeInMs=*/ 20L, /*isHidden=*/ false); entryMap.put(entry.getKey(), entry); entry = createBatteryHistEntry( "package2", "label2", /*consumePower=*/ 10.0, @@ -1220,7 +1228,7 @@ public final class DataProcessorTest { /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5, /*uid=*/ 2L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L, - /*backgroundUsageTimeInMs=*/ 20L); + /*backgroundUsageTimeInMs=*/ 20L, /*isHidden=*/ false); entryMap.put(entry.getKey(), entry); batteryHistoryMap.put(batteryHistoryKeys[2], entryMap); final List hourlyBatteryLevelsPerDay = @@ -1267,7 +1275,7 @@ public final class DataProcessorTest { /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0, /*uid=*/ 1L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L, - /*backgroundUsageTimeInMs=*/ 0L); + /*backgroundUsageTimeInMs=*/ 0L, /*isHidden=*/ false); entryMap.put(entry.getKey(), entry); entry = createBatteryHistEntry( "package2", "label2", /*consumePower=*/ 0, @@ -1275,7 +1283,7 @@ public final class DataProcessorTest { /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0, /*uid=*/ 2L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L, - /*backgroundUsageTimeInMs=*/ 0L); + /*backgroundUsageTimeInMs=*/ 0L, /*isHidden=*/ false); entryMap.put(entry.getKey(), entry); batteryHistoryMap.put(batteryHistoryKeys[0], entryMap); // Adds the index = 1 data. @@ -1286,7 +1294,7 @@ public final class DataProcessorTest { /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0, /*uid=*/ 1L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L, - /*backgroundUsageTimeInMs=*/ 0L); + /*backgroundUsageTimeInMs=*/ 0L, /*isHidden=*/ false); entryMap.put(entry.getKey(), entry); entry = createBatteryHistEntry( "package2", "label2", /*consumePower=*/ 0, @@ -1294,7 +1302,7 @@ public final class DataProcessorTest { /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0, /*uid=*/ 2L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L, - /*backgroundUsageTimeInMs=*/ 0L); + /*backgroundUsageTimeInMs=*/ 0L, /*isHidden=*/ false); entryMap.put(entry.getKey(), entry); batteryHistoryMap.put(batteryHistoryKeys[1], entryMap); // Adds the index = 2 data. @@ -1305,7 +1313,7 @@ public final class DataProcessorTest { /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0, /*uid=*/ 1L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L, - /*backgroundUsageTimeInMs=*/ 20L); + /*backgroundUsageTimeInMs=*/ 20L, /*isHidden=*/ false); entryMap.put(entry.getKey(), entry); entry = createBatteryHistEntry( "package2", "label2", /*consumePower=*/ 10.0, @@ -1313,7 +1321,7 @@ public final class DataProcessorTest { /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5, /*uid=*/ 2L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L, - /*backgroundUsageTimeInMs=*/ 20L); + /*backgroundUsageTimeInMs=*/ 20L, /*isHidden=*/ false); entryMap.put(entry.getKey(), entry); batteryHistoryMap.put(batteryHistoryKeys[2], entryMap); final List hourlyBatteryLevelsPerDay = @@ -1603,6 +1611,93 @@ public final class DataProcessorTest { assertThat(DataProcessor.getScreenOnTime(appUsageMap, userId, packageName)).isEqualTo(0); } + @Test + public void needsCombineInSystemApp_isHidden_returnTrue() { + final int currentUserId = mContext.getUserId(); + final BatteryHistEntry hiddenHistEntry = createBatteryHistEntry( + ConvertUtils.FAKE_PACKAGE_NAME, "fake_label", /*consumePower=*/ 0, + /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0, + /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0, + /*uid=*/ 0L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, + /*foregroundUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L, true); + final BatteryDiffEntry hiddenDiffEntry = new BatteryDiffEntry( + mContext, + /*foregroundUsageTimeInMs=*/ 0, + /*backgroundUsageTimeInMs=*/ 0, + /*screenOnTimeInMs=*/ 0, + /*consumePower=*/ 0, + /*foregroundUsageConsumePower=*/ 0, + /*foregroundServiceUsageConsumePower=*/ 0, + /*backgroundUsageConsumePower=*/ 0, + /*cachedUsageConsumePower=*/ 0, + hiddenHistEntry); + + boolean needsCombineInSystemApp = DataProcessor.needsCombineInSystemApp( + hiddenDiffEntry, List.of(), mApplicationsState); + + assertThat(needsCombineInSystemApp).isTrue(); + } + + @Test + public void needsCombineInSystemApp_isSystemApp_returnTrue() { + final int currentUserId = mContext.getUserId(); + final BatteryHistEntry batteryHistEntry = createBatteryHistEntry( + ConvertUtils.FAKE_PACKAGE_NAME, "fake_label", /*consumePower=*/ 0, + /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0, + /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0, + /*uid=*/ 0L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, + /*foregroundUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L, false); + final BatteryDiffEntry batteryDiffEntry = new BatteryDiffEntry( + mContext, + /*foregroundUsageTimeInMs=*/ 0, + /*backgroundUsageTimeInMs=*/ 0, + /*screenOnTimeInMs=*/ 0, + /*consumePower=*/ 0, + /*foregroundUsageConsumePower=*/ 0, + /*foregroundServiceUsageConsumePower=*/ 0, + /*backgroundUsageConsumePower=*/ 0, + /*cachedUsageConsumePower=*/ 0, + batteryHistEntry); + doReturn(mAppEntry).when(mApplicationsState).getEntry(anyString(), anyInt()); + mAppEntry.info = mApplicationInfo; + mApplicationInfo.flags = ApplicationInfo.FLAG_SYSTEM; + + boolean needsCombineInSystemApp = DataProcessor.needsCombineInSystemApp( + batteryDiffEntry, List.of(), mApplicationsState); + + assertThat(needsCombineInSystemApp).isTrue(); + } + + @Test + public void needsCombineInSystemApp_notSystemApp_returnFalse() { + final int currentUserId = mContext.getUserId(); + final BatteryHistEntry batteryHistEntry = createBatteryHistEntry( + ConvertUtils.FAKE_PACKAGE_NAME, "fake_label", /*consumePower=*/ 0, + /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0, + /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0, + /*uid=*/ 0L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, + /*foregroundUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L, false); + final BatteryDiffEntry batteryDiffEntry = new BatteryDiffEntry( + mContext, + /*foregroundUsageTimeInMs=*/ 0, + /*backgroundUsageTimeInMs=*/ 0, + /*screenOnTimeInMs=*/ 0, + /*consumePower=*/ 0, + /*foregroundUsageConsumePower=*/ 0, + /*foregroundServiceUsageConsumePower=*/ 0, + /*backgroundUsageConsumePower=*/ 0, + /*cachedUsageConsumePower=*/ 0, + batteryHistEntry); + doReturn(mAppEntry).when(mApplicationsState).getEntry(anyString(), anyInt()); + mAppEntry.info = mApplicationInfo; + mApplicationInfo.flags = 0; + + boolean needsCombineInSystemApp = DataProcessor.needsCombineInSystemApp( + batteryDiffEntry, List.of(), mApplicationsState); + + assertThat(needsCombineInSystemApp).isFalse(); + } + private static Map> createHistoryMap( final long[] timestamps, final int[] levels) { final Map> batteryHistoryMap = new HashMap<>(); @@ -1639,7 +1734,8 @@ public final class DataProcessorTest { final double foregroundServiceUsageConsumePower, final double backgroundUsageConsumePower, final double cachedUsageConsumePower, final long uid, final long userId, final int consumerType, - final long foregroundUsageTimeInMs, final long backgroundUsageTimeInMs) { + final long foregroundUsageTimeInMs, final long backgroundUsageTimeInMs, + final boolean isHidden) { // Only insert required fields. final BatteryInformation batteryInformation = BatteryInformation @@ -1652,6 +1748,7 @@ public final class DataProcessorTest { .setCachedUsageConsumePower(cachedUsageConsumePower) .setForegroundUsageTimeInMs(foregroundUsageTimeInMs) .setBackgroundUsageTimeInMs(backgroundUsageTimeInMs) + .setIsHidden(isHidden) .build(); final ContentValues values = new ContentValues(); values.put(BatteryHistEntry.KEY_PACKAGE_NAME, packageName);