From 0a0ba915ca67260d9d5162c6d776ca696b1bb3a5 Mon Sep 17 00:00:00 2001 From: Kuan Wang Date: Thu, 13 Oct 2022 18:07:54 +0800 Subject: [PATCH] Copy BatterySettingsContentProvider from SettingsIntelligence to Settings and rename it to BatteryUsageContentProvider. Bug: 253395332 Test: make RunSettingsRoboTests + manually Change-Id: Ib6c2240cd065f6e29393e13b7231bba7afd2d850 --- AndroidManifest.xml | 12 + .../BatteryUsageContentProvider.java | 168 ++++++++++ .../fuelgauge/batteryusage/DatabaseUtils.java | 36 ++ .../BatteryUsageContentProviderTest.java | 311 ++++++++++++++++++ .../android/settings/testutils/FakeClock.java | 54 +++ 5 files changed, 581 insertions(+) create mode 100644 src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProvider.java create mode 100644 src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java create mode 100644 tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProviderTest.java create mode 100644 tests/robotests/src/com/android/settings/testutils/FakeClock.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index f5da15fe711..935c1a47f0d 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -6,6 +6,11 @@ + + + @@ -2961,6 +2966,13 @@ android:value="@string/menu_key_battery"/> + + + mProvider.query( + uri, /*strings=*/ null, /*s=*/ null, /*strings1=*/ null, + /*s1=*/ null)); + assertThrows( + IllegalArgumentException.class, + () -> mProvider.insert(uri, /*contentValues=*/ null)); + } + + @Test + public void queryAndInsert_incorrectAuthority_throwsIllegalArgumentException() { + final Uri.Builder builder = + new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(DatabaseUtils.AUTHORITY + ".debug") + .appendPath(DatabaseUtils.BATTERY_STATE_TABLE); + final Uri uri = builder.build(); + mProvider.onCreate(); + + assertThrows( + IllegalArgumentException.class, + () -> + mProvider.query( + uri, /*strings=*/ null, /*s=*/ null, /*strings1=*/ null, + /*s1=*/ null)); + assertThrows( + IllegalArgumentException.class, + () -> mProvider.insert(uri, /*contentValues=*/ null)); + } + + @Test + public void query_batteryState_returnsExpectedResult() throws Exception { + mProvider.onCreate(); + final Duration currentTime = Duration.ofHours(52); + final long expiredTimeCutoff = currentTime.toMillis() + - BatteryUsageContentProvider.QUERY_DURATION_HOURS.toMillis(); + testQueryBatteryState(currentTime, expiredTimeCutoff, /*hasQueryTimestamp=*/ false); + } + + @Test + public void query_batteryStateTimestamp_returnsExpectedResult() throws Exception { + mProvider.onCreate(); + final Duration currentTime = Duration.ofHours(52); + final long expiredTimeCutoff = currentTime.toMillis() - Duration.ofHours(10).toMillis(); + testQueryBatteryState(currentTime, expiredTimeCutoff, /*hasQueryTimestamp=*/ true); + } + + @Test + public void query_incorrectParameterFormat_returnsExpectedResult() throws Exception { + mProvider.onCreate(); + final Duration currentTime = Duration.ofHours(52); + final long expiredTimeCutoff = + currentTime.toMillis() + - BatteryUsageContentProvider.QUERY_DURATION_HOURS.toMillis(); + testQueryBatteryState( + currentTime, + expiredTimeCutoff, + /*hasQueryTimestamp=*/ false, + /*customParameter=*/ "invalid number format"); + } + + @Test + public void insert_batteryState_returnsExpectedResult() { + mProvider.onCreate(); + ContentValues values = new ContentValues(); + values.put("uid", Long.valueOf(101L)); + values.put("userId", Long.valueOf(1001L)); + values.put("appLabel", new String("Settings")); + values.put("packageName", new String("com.android.settings")); + values.put("timestamp", Long.valueOf(2100021L)); + values.put("isHidden", Boolean.valueOf(true)); + values.put("totalPower", Double.valueOf(99.0)); + values.put("consumePower", Double.valueOf(9.0)); + values.put("percentOfTotal", Double.valueOf(0.9)); + values.put("foregroundUsageTimeInMs", Long.valueOf(1000)); + values.put("backgroundUsageTimeInMs", Long.valueOf(2000)); + values.put("drainType", Integer.valueOf(1)); + values.put("consumerType", Integer.valueOf(2)); + values.put("batteryLevel", Integer.valueOf(51)); + values.put("batteryStatus", Integer.valueOf(2)); + values.put("batteryHealth", Integer.valueOf(3)); + + final Uri uri = mProvider.insert(VALID_BATTERY_STATE_CONTENT_URI, values); + + assertThat(uri).isEqualTo(VALID_BATTERY_STATE_CONTENT_URI); + // Verifies the BatteryState content. + final List states = + BatteryStateDatabase.getInstance(mContext).batteryStateDao().getAllAfter(0); + assertThat(states).hasSize(1); + assertThat(states.get(0).uid).isEqualTo(101L); + assertThat(states.get(0).userId).isEqualTo(1001L); + assertThat(states.get(0).appLabel).isEqualTo("Settings"); + assertThat(states.get(0).packageName).isEqualTo("com.android.settings"); + assertThat(states.get(0).isHidden).isTrue(); + assertThat(states.get(0).timestamp).isEqualTo(2100021L); + assertThat(states.get(0).totalPower).isEqualTo(99.0); + assertThat(states.get(0).consumePower).isEqualTo(9.0); + assertThat(states.get(0).percentOfTotal).isEqualTo(0.9); + assertThat(states.get(0).foregroundUsageTimeInMs).isEqualTo(1000); + assertThat(states.get(0).backgroundUsageTimeInMs).isEqualTo(2000); + assertThat(states.get(0).drainType).isEqualTo(1); + assertThat(states.get(0).consumerType).isEqualTo(2); + assertThat(states.get(0).batteryLevel).isEqualTo(51); + assertThat(states.get(0).batteryStatus).isEqualTo(2); + assertThat(states.get(0).batteryHealth).isEqualTo(3); + } + + @Test + public void insert_partialFieldsContentValues_returnsExpectedResult() { + mProvider.onCreate(); + final ContentValues values = new ContentValues(); + values.put("packageName", new String("fake_data")); + values.put("timestamp", Long.valueOf(2100022L)); + values.put("batteryLevel", Integer.valueOf(52)); + values.put("batteryStatus", Integer.valueOf(3)); + values.put("batteryHealth", Integer.valueOf(2)); + + final Uri uri = mProvider.insert(VALID_BATTERY_STATE_CONTENT_URI, values); + + assertThat(uri).isEqualTo(VALID_BATTERY_STATE_CONTENT_URI); + // Verifies the BatteryState content. + final List states = + BatteryStateDatabase.getInstance(mContext).batteryStateDao().getAllAfter(0); + assertThat(states).hasSize(1); + assertThat(states.get(0).packageName).isEqualTo("fake_data"); + assertThat(states.get(0).timestamp).isEqualTo(2100022L); + assertThat(states.get(0).batteryLevel).isEqualTo(52); + assertThat(states.get(0).batteryStatus).isEqualTo(3); + assertThat(states.get(0).batteryHealth).isEqualTo(2); + } + + @Test + public void delete_throwsUnsupportedOperationException() { + assertThrows( + UnsupportedOperationException.class, + () -> mProvider.delete(/*uri=*/ null, /*s=*/ null, /*strings=*/ null)); + } + + @Test + public void update_throwsUnsupportedOperationException() { + assertThrows( + UnsupportedOperationException.class, + () -> + mProvider.update( + /*uri=*/ null, /*contentValues=*/ null, /*s=*/ null, + /*strings=*/ null)); + } + + private void testQueryBatteryState( + Duration currentTime, long expiredTimeCutoff, boolean hasQueryTimestamp) + throws Exception { + testQueryBatteryState(currentTime, expiredTimeCutoff, hasQueryTimestamp, null); + } + + private void testQueryBatteryState( + Duration currentTime, + long expiredTimeCutoff, + boolean hasQueryTimestamp, + String customParameter) + throws Exception { + mProvider.onCreate(); + final FakeClock fakeClock = new FakeClock(); + fakeClock.setCurrentTime(currentTime); + mProvider.setClock(fakeClock); + // Inserts some expired testing data. + BatteryTestUtils.insertDataToBatteryStateDatabase( + mContext, expiredTimeCutoff - 1, "com.android.sysui1"); + BatteryTestUtils.insertDataToBatteryStateDatabase( + mContext, expiredTimeCutoff - 2, "com.android.sysui2"); + BatteryTestUtils.insertDataToBatteryStateDatabase( + mContext, expiredTimeCutoff - 3, "com.android.sysui3"); + // Inserts some valid testing data. + final String packageName1 = "com.android.settings1"; + final String packageName2 = "com.android.settings2"; + final String packageName3 = "com.android.settings3"; + BatteryTestUtils.insertDataToBatteryStateDatabase( + mContext, currentTime.toMillis(), packageName1); + BatteryTestUtils.insertDataToBatteryStateDatabase( + mContext, expiredTimeCutoff + 2, packageName2); + BatteryTestUtils.insertDataToBatteryStateDatabase( + mContext, expiredTimeCutoff, packageName3); + + final Uri.Builder builder = + new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(DatabaseUtils.AUTHORITY) + .appendPath(DatabaseUtils.BATTERY_STATE_TABLE); + if (customParameter != null) { + builder.appendQueryParameter( + BatteryUsageContentProvider.QUERY_KEY_TIMESTAMP, customParameter); + } else if (hasQueryTimestamp) { + builder.appendQueryParameter( + BatteryUsageContentProvider.QUERY_KEY_TIMESTAMP, + Long.toString(expiredTimeCutoff)); + } + final Uri batteryStateQueryContentUri = builder.build(); + + final Cursor cursor = + mProvider.query( + batteryStateQueryContentUri, + /*strings=*/ null, + /*s=*/ null, + /*strings1=*/ null, + /*s1=*/ null); + + // Verifies the result not include expired data. + assertThat(cursor.getCount()).isEqualTo(3); + final int packageNameIndex = cursor.getColumnIndex("packageName"); + // Verifies the first data package name. + cursor.moveToFirst(); + final String actualPackageName1 = cursor.getString(packageNameIndex); + assertThat(actualPackageName1).isEqualTo(packageName1); + // Verifies the second data package name. + cursor.moveToNext(); + final String actualPackageName2 = cursor.getString(packageNameIndex); + assertThat(actualPackageName2).isEqualTo(packageName2); + // Verifies the third data package name. + cursor.moveToNext(); + final String actualPackageName3 = cursor.getString(packageNameIndex); + assertThat(actualPackageName3).isEqualTo(packageName3); + cursor.close(); + // TODO: add verification for recheck broadcast. + } +} diff --git a/tests/robotests/src/com/android/settings/testutils/FakeClock.java b/tests/robotests/src/com/android/settings/testutils/FakeClock.java new file mode 100644 index 00000000000..946d0515340 --- /dev/null +++ b/tests/robotests/src/com/android/settings/testutils/FakeClock.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2022 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.testutils; + +import java.time.Clock; +import java.time.Duration; +import java.time.Instant; +import java.time.ZoneId; + +/** A fake {@link Clock} class for testing. */ +public final class FakeClock extends Clock { + private long mCurrentTimeMillis; + + public FakeClock() {} + + /** Sets the time in millis for {@link Clock#millis()} method. */ + public void setCurrentTime(Duration duration) { + mCurrentTimeMillis = duration.toMillis(); + } + + @Override + public ZoneId getZone() { + throw new UnsupportedOperationException("unsupported!"); + } + + @Override + public Clock withZone(ZoneId zone) { + throw new UnsupportedOperationException("unsupported!"); + } + + @Override + public Instant instant() { + throw new UnsupportedOperationException("unsupported!"); + } + + @Override + public long millis() { + return mCurrentTimeMillis; + } +}