Snap for 9191040 from 772c437de4 to udc-release

Change-Id: I68d8b8d7ab3b37934d5a370ba48663a7552be825
This commit is contained in:
Android Build Coastguard Worker
2022-10-19 01:26:36 +00:00
29 changed files with 1890 additions and 102 deletions

View File

@@ -90,8 +90,11 @@ android_library {
"WifiTrackerLib",
"SettingsLibActivityEmbedding",
"Settings-change-ids",
"androidx.room_room-runtime",
],
plugins: ["androidx.room_room-compiler-plugin"],
libs: [
"telephony-common",
"ims-common",

View File

@@ -6,6 +6,11 @@
<original-package android:name="com.android.settings"/>
<!-- Permissions for reading or writing battery-related data. -->
<permission
android:name="com.android.settings.BATTERY_DATA"
android:protectionLevel="signature|privileged"/>
<uses-permission android:name="android.permission.REQUEST_NETWORK_SCORES" />
<uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
@@ -2961,6 +2966,13 @@
android:value="@string/menu_key_battery"/>
</activity>
<provider
android:name=".fuelgauge.batteryusage.BatteryUsageContentProvider"
android:enabled="true"
android:exported="true"
android:authorities="${applicationId}.battery.usage.provider"
android:permission="com.android.settings.BATTERY_DATA"/>
<activity
android:name="Settings$BatterySaverSettingsActivity"
android:label="@string/battery_saver"

View File

@@ -183,17 +183,17 @@
<item msgid="346101114322879720">"ማሳወቂያዎችን ድረስ"</item>
<item msgid="4760681822601767255">"ካሜራ"</item>
<item msgid="2172823594140104317">"ኦዲዮ ቅረጽ"</item>
<item msgid="5612873260709742213">"ድምጽ አጫውት"</item>
<item msgid="5612873260709742213">"ድምፅ አጫውት"</item>
<item msgid="2027206403725749996">"ቅንጥብ መለያ አንብብ"</item>
<item msgid="5643742956725663156">"ቅንጥብ መለያ ቀይር"</item>
<item msgid="7362845549479684378">"የሚዲያ አዝራሮች"</item>
<item msgid="3843484466100107397">"የድምጽ ትኩረት"</item>
<item msgid="617344340943430125">"ዋናው ድምጽ መቆጣጠሪያ"</item>
<item msgid="617344340943430125">"ዋናው ድምፅ መቆጣጠሪያ"</item>
<item msgid="1249691739381713634">"የድምጽ መጠን"</item>
<item msgid="6485000384018554920">"የጥሪ ድምጽ መጠን"</item>
<item msgid="6485000384018554920">"የጥሪ ድምፅ መጠን"</item>
<item msgid="3378000878531336372">"የማህደረ መረጃ መጠን"</item>
<item msgid="5272927168355895681">"የማንቂያ ድምፅ መጠን"</item>
<item msgid="4422070755065530548">"የማሳወቂያ ድምጽ መጠን"</item>
<item msgid="4422070755065530548">"የማሳወቂያ ድምፅ መጠን"</item>
<item msgid="3250654589277825306">"የብሉቱዝ ድምፅ መጠን"</item>
<item msgid="4212187233638382465">"እንደነቃ አቆይ"</item>
<item msgid="5099026183238335900">"አካባቢን ይቆጣጠሩ"</item>
@@ -250,7 +250,7 @@
<item msgid="8267704990417682222">"ማሳወቂያዎችን ይድረሱ"</item>
<item msgid="3180676986290096851">"ካሜራ"</item>
<item msgid="9174072114281872917">"ኦዲዮ ቅረጽ"</item>
<item msgid="1444183972646890539">"ድምጽ አጫውት"</item>
<item msgid="1444183972646890539">"ድምፅ አጫውት"</item>
<item msgid="4337542044275236638">"ቅንጥብ ሰሌዳ አንብብ"</item>
<item msgid="2681224211796661809">"ቅንጥብ መለያ ቀይር"</item>
<item msgid="4479361062226474111">"የሚዲያ አዝራሮች"</item>
@@ -260,7 +260,7 @@
<item msgid="6749550886745567276">"የጥሪ መጠን"</item>
<item msgid="2218685029915863168">"የማህደረ መረጃ ክፍልፍል"</item>
<item msgid="4266577290496513640">"የማንቂያ ድምፅ መጠን"</item>
<item msgid="8608084169623998854">"የማሳወቂያ ድምጽ መጠን"</item>
<item msgid="8608084169623998854">"የማሳወቂያ ድምፅ መጠን"</item>
<item msgid="7948784184567841794">"የብሉቱዝ ድምፅ መጠን"</item>
<item msgid="1148968792599973150">"እንደነቃ አቆይ"</item>
<item msgid="8482874682804856549">"አካባቢ"</item>

View File

@@ -2599,6 +2599,8 @@
<string name="screensaver_settings_title">Screen saver</string>
<!-- List of synonyms used in the settings search bar to find the “Screen saver”. [CHAR LIMIT=NONE] -->
<string name="keywords_screensaver">screensaver</string>
<!-- Summary for screensaver unavailable when Bedtime mode is on [CHAR LIMIT=50] -->
<string name="screensaver_settings_when_to_dream_bedtime">Unavailable because bedtime mode is on</string>
<!-- The title for the toggle which disables/enables screen savers [CHAR_LIMIT=30] -->
<string name="screensaver_settings_toggle_title">Use screen saver</string>
<!-- Display settings screen, summary fragment for screen saver options, activated when docked or asleep and charging [CHAR LIMIT=35] -->
@@ -8022,6 +8024,8 @@
<string name="notif_listener_excluded_app_summary">Change settings for each app that sends notifications</string>
<string name="notif_listener_excluded_app_screen_title">Apps shown on device</string>
<string name="notif_listener_not_migrated">This app doesn\u2019t support enhanced settings</string>
<string name="notif_listener_more_settings">More settings</string>
<string name="notif_listener_more_settings_desc">More settings are available inside this app</string>
<!-- Title for managing VR (virtual reality) helper services. [CHAR LIMIT=50] -->
<string name="vr_listeners_title">VR helper services</string>

View File

@@ -64,6 +64,12 @@
settings:searchable="false"
settings:controller="com.android.settings.applications.specialaccess.notificationaccess.BridgedAppsLinkPreferenceController" />
<Preference
android:key="more_settings"
android:title="@string/notif_listener_more_settings"
android:summary="@string/notif_listener_more_settings_desc"
settings:controller="com.android.settings.applications.specialaccess.notificationaccess.MoreSettingsPreferenceController" />
<com.android.settingslib.widget.FooterPreference
android:key="notif_listener_not_migrated"
android:title="@string/notif_listener_not_migrated"

View File

@@ -86,8 +86,7 @@
<com.android.settings.RestrictedListPreference
android:key="privacy_lock_screen_notifications"
android:title="@string/lock_screen_notifs_title"
android:summary="@string/summary_placeholder"
settings:searchable="false"/>
android:summary="@string/summary_placeholder"/>
<!-- Show media on lock screen -->
<SwitchPreference
@@ -117,8 +116,7 @@
android:key="privacy_lock_screen_work_profile_notifications"
android:title="@string/locked_work_profile_notification_title"
android:summary="@string/summary_placeholder"
android:order="999"
settings:searchable="false"/>
android:order="999"/>
</PreferenceCategory>
<!-- Content Capture -->

View File

@@ -0,0 +1,79 @@
/*
* 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.applications.specialaccess.notificationaccess;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.service.notification.NotificationListenerService;
import androidx.preference.Preference;
import com.android.settings.core.BasePreferenceController;
import java.util.List;
/**
* Controls link to reach more preference settings inside the app.
*/
public class MoreSettingsPreferenceController extends BasePreferenceController {
private static final String TAG = "MoreSettingsPrefContr";
private static final String KEY_MORE_SETTINGS = "more_settings";
PackageManager mPm;
String mPackage;
int mUserId;
Intent mIntent = new Intent(Intent.ACTION_MAIN)
.addCategory(NotificationListenerService.INTENT_CATEGORY_SETTINGS_HOME);
public MoreSettingsPreferenceController(Context context) {
super(context, KEY_MORE_SETTINGS);
}
@Override
public int getAvailabilityStatus() {
final List<ResolveInfo> resolveInfos = mPm.queryIntentActivities(
mIntent,
PackageManager.ResolveInfoFlags.of(0));
if (resolveInfos == null || resolveInfos.isEmpty()) {
return CONDITIONALLY_UNAVAILABLE;
}
return AVAILABLE;
}
@Override
public String getPreferenceKey() {
return KEY_MORE_SETTINGS;
}
public MoreSettingsPreferenceController setPackageManager(PackageManager pm) {
mPm = pm;
return this;
}
public MoreSettingsPreferenceController setPackage(String pkg) {
mPackage = pkg;
mIntent.setPackage(mPackage);
return this;
}
public void updateState(Preference preference) {
preference.setIntent(mIntent);
}
}

View File

@@ -124,6 +124,9 @@ public class NotificationAccessDetails extends DashboardFragment {
.setCn(mComponentName)
.setUserId(mUserId)
.setTargetSdk(listenerTargetSdk);
use(MoreSettingsPreferenceController.class)
.setPackage(mComponentName.getPackageName())
.setPackageManager(mPm);
final int finalListenerTargetSdk = listenerTargetSdk;
getPreferenceControllers().forEach(controllers -> {
controllers.forEach(controller -> {

View File

@@ -18,6 +18,7 @@ import android.os.UserManager;
import androidx.preference.Preference;
import com.android.settings.R;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.dream.DreamSettings;
import com.android.settingslib.core.AbstractPreferenceController;
@@ -26,9 +27,12 @@ public class ScreenSaverPreferenceController extends AbstractPreferenceControlle
PreferenceControllerMixin {
private static final String KEY_SCREEN_SAVER = "screensaver";
private final boolean mDreamsDisabledByAmbientModeSuppression;
public ScreenSaverPreferenceController(Context context) {
super(context);
mDreamsDisabledByAmbientModeSuppression = context.getResources().getBoolean(
com.android.internal.R.bool.config_dreamsDisabledByAmbientModeSuppressionConfig);
}
@Override
@@ -47,7 +51,12 @@ public class ScreenSaverPreferenceController extends AbstractPreferenceControlle
@Override
public void updateState(Preference preference) {
preference.setSummary(DreamSettings.getSummaryTextWithDreamName(mContext));
if (mDreamsDisabledByAmbientModeSuppression
&& AmbientDisplayAlwaysOnPreferenceController.isAodSuppressedByBedtime(mContext)) {
preference.setSummary(R.string.screensaver_settings_when_to_dream_bedtime);
} else {
preference.setSummary(DreamSettings.getSummaryTextWithDreamName(mContext));
}
}
private boolean isSystemUser() {

View File

@@ -20,7 +20,10 @@ import android.content.Context;
import androidx.preference.Preference;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.display.AmbientDisplayAlwaysOnPreferenceController;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.dream.DreamBackend;
@@ -29,19 +32,34 @@ public class WhenToDreamPreferenceController extends AbstractPreferenceControlle
private static final String WHEN_TO_START = "when_to_start";
private final DreamBackend mBackend;
private final boolean mDreamsDisabledByAmbientModeSuppression;
WhenToDreamPreferenceController(Context context) {
this(context, context.getResources().getBoolean(
com.android.internal.R.bool.config_dreamsDisabledByAmbientModeSuppressionConfig));
}
@VisibleForTesting
WhenToDreamPreferenceController(Context context,
boolean dreamsDisabledByAmbientModeSuppression) {
super(context);
mBackend = DreamBackend.getInstance(context);
mDreamsDisabledByAmbientModeSuppression = dreamsDisabledByAmbientModeSuppression;
}
@Override
public void updateState(Preference preference) {
super.updateState(preference);
int resId = DreamSettings.getDreamSettingDescriptionResId(mBackend.getWhenToDreamSetting());
preference.setSummary(preference.getContext().getString(resId));
if (mDreamsDisabledByAmbientModeSuppression
&& AmbientDisplayAlwaysOnPreferenceController.isAodSuppressedByBedtime(mContext)) {
preference.setSummary(R.string.screensaver_settings_when_to_dream_bedtime);
} else {
final int resId = DreamSettings.getDreamSettingDescriptionResId(
mBackend.getWhenToDreamSetting());
preference.setSummary(resId);
}
}
@Override

View File

@@ -0,0 +1,168 @@
/*
* 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.fuelgauge.batteryusage;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.android.settings.fuelgauge.batteryusage.db.BatteryState;
import com.android.settings.fuelgauge.batteryusage.db.BatteryStateDao;
import com.android.settings.fuelgauge.batteryusage.db.BatteryStateDatabase;
import java.time.Clock;
import java.time.Duration;
/** {@link ContentProvider} class to fetch battery usage data. */
public class BatteryUsageContentProvider extends ContentProvider {
private static final String TAG = "BatteryUsageContentProvider";
// TODO: Updates the duration to a more reasonable value for since-last-full-charge.
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
public static final Duration QUERY_DURATION_HOURS = Duration.ofHours(28);
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
public static final String QUERY_KEY_TIMESTAMP = "timestamp";
/** Codes */
private static final int BATTERY_STATE_CODE = 1;
private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
sUriMatcher.addURI(
DatabaseUtils.AUTHORITY,
/*path=*/ DatabaseUtils.BATTERY_STATE_TABLE,
/*code=*/ BATTERY_STATE_CODE);
}
private Clock mClock;
private BatteryStateDao mBatteryStateDao;
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
public void setClock(Clock clock) {
this.mClock = clock;
}
@Override
public boolean onCreate() {
if (DatabaseUtils.isWorkProfile(getContext())) {
Log.w(TAG, "do not create provider for work profile");
return false;
}
mClock = Clock.systemUTC();
mBatteryStateDao = BatteryStateDatabase.getInstance(getContext()).batteryStateDao();
Log.w(TAG, "create content provider from " + getCallingPackage());
return true;
}
@Nullable
@Override
public Cursor query(
@NonNull Uri uri,
@Nullable String[] strings,
@Nullable String s,
@Nullable String[] strings1,
@Nullable String s1) {
switch (sUriMatcher.match(uri)) {
case BATTERY_STATE_CODE:
return getBatteryStates(uri);
default:
throw new IllegalArgumentException("unknown URI: " + uri);
}
}
@Nullable
@Override
public String getType(@NonNull Uri uri) {
return null;
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) {
switch (sUriMatcher.match(uri)) {
case BATTERY_STATE_CODE:
try {
mBatteryStateDao.insert(BatteryState.create(contentValues));
return uri;
} catch (RuntimeException e) {
Log.e(TAG, "insert() from:" + uri + " error:" + e);
return null;
}
default:
throw new IllegalArgumentException("unknown URI: " + uri);
}
}
@Override
public int delete(@NonNull Uri uri, @Nullable String s, @Nullable String[] strings) {
throw new UnsupportedOperationException("unsupported!");
}
@Override
public int update(
@NonNull Uri uri,
@Nullable ContentValues contentValues,
@Nullable String s,
@Nullable String[] strings) {
throw new UnsupportedOperationException("unsupported!");
}
private Cursor getBatteryStates(Uri uri) {
final long defaultTimestamp = mClock.millis() - QUERY_DURATION_HOURS.toMillis();
final long queryTimestamp = getQueryTimestamp(uri, defaultTimestamp);
return getBatteryStates(uri, queryTimestamp);
}
private Cursor getBatteryStates(Uri uri, long firstTimestamp) {
final long timestamp = mClock.millis();
Cursor cursor = null;
try {
cursor = mBatteryStateDao.getCursorAfter(firstTimestamp);
} catch (RuntimeException e) {
Log.e(TAG, "query() from:" + uri + " error:" + e);
}
// TODO: Invokes hourly job recheck.
Log.w(TAG, "query battery states in " + (mClock.millis() - timestamp) + "/ms");
return cursor;
}
// If URI contains query parameter QUERY_KEY_TIMESTAMP, use the value directly.
// Otherwise, load the data for QUERY_DURATION_HOURS by default.
private long getQueryTimestamp(Uri uri, long defaultTimestamp) {
final String firstTimestampString = uri.getQueryParameter(QUERY_KEY_TIMESTAMP);
if (TextUtils.isEmpty(firstTimestampString)) {
Log.w(TAG, "empty query timestamp");
return defaultTimestamp;
}
try {
return Long.parseLong(firstTimestampString);
} catch (NumberFormatException e) {
Log.e(TAG, "invalid query timestamp: " + firstTimestampString, e);
return defaultTimestamp;
}
}
}

View File

@@ -0,0 +1,36 @@
/*
* 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.fuelgauge.batteryusage;
import android.content.Context;
import android.os.UserManager;
/** A utility class to operate battery usage database. */
public final class DatabaseUtils {
private static final String TAG = "DatabaseUtils";
/** An authority name of the battery content provider. */
public static final String AUTHORITY = "com.android.settings.battery.usage.provider";
/** A table name for battery usage history. */
public static final String BATTERY_STATE_TABLE = "BatteryState";
/** Returns true if current user is a work profile user. */
public static boolean isWorkProfile(Context context) {
final UserManager userManager = context.getSystemService(UserManager.class);
return userManager.isManagedProfile() && !userManager.isSystemUser();
}
}

View File

@@ -0,0 +1,397 @@
/*
* 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.fuelgauge.batteryusage.db;
import android.content.ContentValues;
import android.content.Intent;
import android.os.BatteryManager;
import androidx.room.Entity;
import androidx.room.PrimaryKey;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
/** A {@link Entity} class to save battery states snapshot into database. */
@Entity
public class BatteryState {
private static String sCacheZoneId;
private static SimpleDateFormat sCacheSimpleDateFormat;
@PrimaryKey(autoGenerate = true)
private long mId;
// Records the app relative information.
public final long uid;
public final long userId;
public final String appLabel;
public final String packageName;
// Whether the data is represented as system component or not?
public final boolean isHidden;
// Records the timestamp relative information.
public final long bootTimestamp;
public final long timestamp;
public final String zoneId;
// Records the battery usage relative information.
public final double totalPower;
public final double consumePower;
public final double percentOfTotal;
public final long foregroundUsageTimeInMs;
public final long backgroundUsageTimeInMs;
public final int drainType;
public final int consumerType;
// Records the battery intent relative information.
public final int batteryLevel;
public final int batteryStatus;
public final int batteryHealth;
public BatteryState(
long uid,
long userId,
String appLabel,
String packageName,
boolean isHidden,
long bootTimestamp,
long timestamp,
String zoneId,
double totalPower,
double consumePower,
double percentOfTotal,
long foregroundUsageTimeInMs,
long backgroundUsageTimeInMs,
int drainType,
int consumerType,
int batteryLevel,
int batteryStatus,
int batteryHealth) {
// Records the app relative information.
this.uid = uid;
this.userId = userId;
this.appLabel = appLabel;
this.packageName = packageName;
this.isHidden = isHidden;
// Records the timestamp relative information.
this.bootTimestamp = bootTimestamp;
this.timestamp = timestamp;
this.zoneId = zoneId;
// Records the battery usage relative information.
this.totalPower = totalPower;
this.consumePower = consumePower;
this.percentOfTotal = percentOfTotal;
this.foregroundUsageTimeInMs = foregroundUsageTimeInMs;
this.backgroundUsageTimeInMs = backgroundUsageTimeInMs;
this.drainType = drainType;
this.consumerType = consumerType;
// Records the battery intent relative information.
this.batteryLevel = batteryLevel;
this.batteryStatus = batteryStatus;
this.batteryHealth = batteryHealth;
}
/** Sets the auto-generated content ID. */
public void setId(long id) {
this.mId = id;
}
/** Gets the auto-generated content ID. */
public long getId() {
return mId;
}
@Override
@SuppressWarnings("JavaUtilDate")
public String toString() {
final String currentZoneId = TimeZone.getDefault().getID();
if (!currentZoneId.equals(sCacheZoneId) || sCacheSimpleDateFormat == null) {
sCacheZoneId = currentZoneId;
sCacheSimpleDateFormat = new SimpleDateFormat("MMM dd,yyyy HH:mm:ss", Locale.US);
}
final String recordAtDateTime = sCacheSimpleDateFormat.format(new Date(timestamp));
final StringBuilder builder = new StringBuilder()
.append("\nBatteryState{")
.append(String.format(Locale.US,
"\n\tpackage=%s|label=%s|uid=%d|userId=%d|isHidden=%b",
packageName, appLabel, uid, userId, isHidden))
.append(String.format(Locale.US, "\n\ttimestamp=%s|zoneId=%s|bootTimestamp=%d",
recordAtDateTime, zoneId, Duration.ofMillis(bootTimestamp).getSeconds()))
.append(String.format(Locale.US,
"\n\tusage=%f|total=%f|consume=%f|elapsedTime=%d|%d",
percentOfTotal, totalPower, consumePower,
Duration.ofMillis(foregroundUsageTimeInMs).getSeconds(),
Duration.ofMillis(backgroundUsageTimeInMs).getSeconds()))
.append(String.format(Locale.US,
"\n\tdrain=%d|consumer=%d", drainType, consumerType))
.append(String.format(Locale.US, "\n\tbattery=%d|status=%d|health=%d\n}",
batteryLevel, batteryStatus, batteryHealth));
return builder.toString();
}
/** Creates new {@link BatteryState} from {@link ContentValues}. */
public static BatteryState create(ContentValues contentValues) {
Builder builder = BatteryState.newBuilder();
if (contentValues.containsKey("uid")) {
builder.setUid(contentValues.getAsLong("uid"));
}
if (contentValues.containsKey("userId")) {
builder.setUserId(contentValues.getAsLong("userId"));
}
if (contentValues.containsKey("appLabel")) {
builder.setAppLabel(contentValues.getAsString("appLabel"));
}
if (contentValues.containsKey("packageName")) {
builder.setPackageName(contentValues.getAsString("packageName"));
}
if (contentValues.containsKey("isHidden")) {
builder.setIsHidden(contentValues.getAsBoolean("isHidden"));
}
if (contentValues.containsKey("bootTimestamp")) {
builder.setBootTimestamp(contentValues.getAsLong("bootTimestamp"));
}
if (contentValues.containsKey("timestamp")) {
builder.setTimestamp(contentValues.getAsLong("timestamp"));
}
if (contentValues.containsKey("consumePower")) {
builder.setConsumePower(contentValues.getAsDouble("consumePower"));
}
if (contentValues.containsKey("totalPower")) {
builder.setTotalPower(contentValues.getAsDouble("totalPower"));
}
if (contentValues.containsKey("percentOfTotal")) {
builder.setPercentOfTotal(contentValues.getAsDouble("percentOfTotal"));
}
if (contentValues.containsKey("foregroundUsageTimeInMs")) {
builder.setForegroundUsageTimeInMs(
contentValues.getAsLong("foregroundUsageTimeInMs"));
}
if (contentValues.containsKey("backgroundUsageTimeInMs")) {
builder.setBackgroundUsageTimeInMs(
contentValues.getAsLong("backgroundUsageTimeInMs"));
}
if (contentValues.containsKey("drainType")) {
builder.setDrainType(contentValues.getAsInteger("drainType"));
}
if (contentValues.containsKey("consumerType")) {
builder.setConsumerType(contentValues.getAsInteger("consumerType"));
}
if (contentValues.containsKey("batteryLevel")) {
builder.setBatteryLevel(contentValues.getAsInteger("batteryLevel"));
}
if (contentValues.containsKey("batteryStatus")) {
builder.setBatteryStatus(contentValues.getAsInteger("batteryStatus"));
}
if (contentValues.containsKey("batteryHealth")) {
builder.setBatteryHealth(contentValues.getAsInteger("batteryHealth"));
}
return builder.build();
}
/** Creates a new {@link Builder} instance. */
public static Builder newBuilder() {
return new Builder();
}
/** A convenience builder class to improve readability. */
public static class Builder {
private long mUid;
private long mUserId;
private String mAppLabel;
private String mPackageName;
private boolean mIsHidden;
private long mBootTimestamp;
private long mTimestamp;
private double mTotalPower;
private double mConsumePower;
private double mPercentOfTotal;
private long mForegroundUsageTimeInMs;
private long mBackgroundUsageTimeInMs;
private int mDrainType;
private int mConsumerType;
private int mBatteryLevel;
private int mBatteryStatus;
private int mBatteryHealth;
/** Sets the uid. */
@CanIgnoreReturnValue
public Builder setUid(long uid) {
this.mUid = uid;
return this;
}
/** Sets the user ID. */
@CanIgnoreReturnValue
public Builder setUserId(long userId) {
this.mUserId = userId;
return this;
}
/** Sets the app label. */
@CanIgnoreReturnValue
public Builder setAppLabel(String appLabel) {
this.mAppLabel = appLabel;
return this;
}
/** Sets the package name. */
@CanIgnoreReturnValue
public Builder setPackageName(String packageName) {
this.mPackageName = packageName;
return this;
}
/** Sets the is hidden value. */
@CanIgnoreReturnValue
public Builder setIsHidden(boolean isHidden) {
this.mIsHidden = isHidden;
return this;
}
/** Sets the boot timestamp. */
@CanIgnoreReturnValue
public Builder setBootTimestamp(long bootTimestamp) {
this.mBootTimestamp = bootTimestamp;
return this;
}
/** Sets the timestamp. */
@CanIgnoreReturnValue
public Builder setTimestamp(long timestamp) {
this.mTimestamp = timestamp;
return this;
}
/** Sets the total power. */
@CanIgnoreReturnValue
public Builder setTotalPower(double totalPower) {
this.mTotalPower = totalPower;
return this;
}
/** Sets the consumed power. */
@CanIgnoreReturnValue
public Builder setConsumePower(double consumePower) {
this.mConsumePower = consumePower;
return this;
}
/** Sets the percentage of total. */
@CanIgnoreReturnValue
public Builder setPercentOfTotal(double percentOfTotal) {
this.mPercentOfTotal = percentOfTotal;
return this;
}
/** Sets the foreground usage time. */
@CanIgnoreReturnValue
public Builder setForegroundUsageTimeInMs(long foregroundUsageTimeInMs) {
this.mForegroundUsageTimeInMs = foregroundUsageTimeInMs;
return this;
}
/** Sets the background usage time. */
@CanIgnoreReturnValue
public Builder setBackgroundUsageTimeInMs(long backgroundUsageTimeInMs) {
this.mBackgroundUsageTimeInMs = backgroundUsageTimeInMs;
return this;
}
/** Sets the drain type. */
@CanIgnoreReturnValue
public Builder setDrainType(int drainType) {
this.mDrainType = drainType;
return this;
}
/** Sets the consumer type. */
@CanIgnoreReturnValue
public Builder setConsumerType(int consumerType) {
this.mConsumerType = consumerType;
return this;
}
/** Sets the battery level. */
@CanIgnoreReturnValue
public Builder setBatteryLevel(int batteryLevel) {
this.mBatteryLevel = batteryLevel;
return this;
}
/** Sets the battery status. */
@CanIgnoreReturnValue
public Builder setBatteryStatus(int batteryStatus) {
this.mBatteryStatus = batteryStatus;
return this;
}
/** Sets the battery health. */
@CanIgnoreReturnValue
public Builder setBatteryHealth(int batteryHealth) {
this.mBatteryHealth = batteryHealth;
return this;
}
/** Sets the battery intent. */
@CanIgnoreReturnValue
public Builder setBatteryIntent(Intent batteryIntent) {
final int level = batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
final int scale = batteryIntent.getIntExtra(BatteryManager.EXTRA_SCALE, 0);
this.mBatteryLevel =
scale == 0
? -1 /*invalid battery level*/
: Math.round((level / (float) scale) * 100f);
this.mBatteryStatus =
batteryIntent.getIntExtra(
BatteryManager.EXTRA_STATUS,
BatteryManager.BATTERY_STATUS_UNKNOWN);
this.mBatteryHealth =
batteryIntent.getIntExtra(
BatteryManager.EXTRA_HEALTH,
BatteryManager.BATTERY_HEALTH_UNKNOWN);
return this;
}
/** Builds the BatteryState. */
public BatteryState build() {
return new BatteryState(
mUid,
mUserId,
mAppLabel,
mPackageName,
mIsHidden,
mBootTimestamp,
mTimestamp,
/*zoneId=*/ TimeZone.getDefault().getID(),
mTotalPower,
mConsumePower,
mPercentOfTotal,
mForegroundUsageTimeInMs,
mBackgroundUsageTimeInMs,
mDrainType,
mConsumerType,
mBatteryLevel,
mBatteryStatus,
mBatteryHealth);
}
private Builder() {}
}
}

View File

@@ -0,0 +1,63 @@
/*
* 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.fuelgauge.batteryusage.db;
import android.database.Cursor;
import androidx.room.Dao;
import androidx.room.Insert;
import androidx.room.OnConflictStrategy;
import androidx.room.Query;
import java.util.List;
/** Data access object for accessing {@link BatteryState} in the database. */
@Dao
public interface BatteryStateDao {
/** Inserts a {@link BatteryState} data into the database. */
@Insert(onConflict = OnConflictStrategy.REPLACE)
void insert(BatteryState state);
/** Inserts {@link BatteryState} data into the database. */
@Insert(onConflict = OnConflictStrategy.REPLACE)
void insertAll(List<BatteryState> states);
/** Lists all recorded data after a specific timestamp. */
@Query("SELECT * FROM BatteryState WHERE timestamp > :timestamp ORDER BY timestamp DESC")
List<BatteryState> getAllAfter(long timestamp);
/** Gets the {@link Cursor} of all recorded data from a specific timestamp. */
@Query("SELECT * FROM BatteryState WHERE timestamp >= :timestamp ORDER BY timestamp DESC")
Cursor getCursorAfter(long timestamp);
/** Get the count of distinct timestamp after a specific timestamp. */
@Query("SELECT COUNT(DISTINCT timestamp) FROM BatteryState WHERE timestamp > :timestamp")
int getDistinctTimestampCount(long timestamp);
/** Lists all distinct timestamps after a specific timestamp. */
@Query("SELECT DISTINCT timestamp FROM BatteryState WHERE timestamp > :timestamp")
List<Long> getDistinctTimestamps(long timestamp);
/** Deletes all recorded data before a specific timestamp. */
@Query("DELETE FROM BatteryState WHERE timestamp <= :timestamp")
void clearAllBefore(long timestamp);
/** Clears all recorded data in the database. */
@Query("DELETE FROM BatteryState")
void clearAll();
}

View File

@@ -0,0 +1,57 @@
/*
* 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.fuelgauge.batteryusage.db;
import android.content.Context;
import android.util.Log;
import androidx.room.Database;
import androidx.room.Room;
import androidx.room.RoomDatabase;
/** A {@link RoomDatabase} for battery usage states history. */
@Database(
entities = {BatteryState.class},
version = 1)
public abstract class BatteryStateDatabase extends RoomDatabase {
private static final String TAG = "BatteryStateDatabase";
private static BatteryStateDatabase sBatteryStateDatabase;
/** Provides DAO for battery state table. */
public abstract BatteryStateDao batteryStateDao();
/** Gets or creates an instance of {@link RoomDatabase}. */
public static BatteryStateDatabase getInstance(Context context) {
if (sBatteryStateDatabase == null) {
sBatteryStateDatabase =
Room.databaseBuilder(
context, BatteryStateDatabase.class, "battery-usage-db-v1")
// Allows accessing data in the main thread for dumping bugreport.
.allowMainThreadQueries()
.fallbackToDestructiveMigration()
.build();
Log.d(TAG, "initialize battery states database");
}
return sBatteryStateDatabase;
}
/** Sets the instance of {@link RoomDatabase}. */
public static void setBatteryStateDatabase(BatteryStateDatabase database) {
BatteryStateDatabase.sBatteryStateDatabase = database;
}
}

View File

@@ -28,7 +28,6 @@ import android.telephony.UiccSlotMapping;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.uicc.UiccController;
import com.android.settingslib.utils.ThreadUtils;
import com.google.common.collect.ImmutableList;
@@ -273,6 +272,7 @@ public class UiccSlotUtil {
if (slotId == INVALID_PHYSICAL_SLOT_ID) {
for (int i = 0; i < slots.length; i++) {
if (slots[i].isRemovable()
&& !slots[i].getIsEuicc()
&& !slots[i].getPorts().stream().findFirst().get().isActive()
&& slots[i].getCardStateInfo() != UiccSlotInfo.CARD_STATE_INFO_ERROR
&& slots[i].getCardStateInfo() != UiccSlotInfo.CARD_STATE_INFO_RESTRICTED) {
@@ -413,4 +413,29 @@ public class UiccSlotUtil {
.findFirst()
.orElse(INVALID_LOGICAL_SLOT_ID);
}
/**
* Return whether the removable psim is enabled.
*
* @param telMgr is a TelephonyManager.
* @return whether the removable psim is enabled.
*/
public static boolean isRemovableSimEnabled(TelephonyManager telMgr) {
if (telMgr == null) {
return false;
}
ImmutableList<UiccSlotInfo> slotInfos = UiccSlotUtil.getSlotInfos(telMgr);
boolean isRemovableSimEnabled =
slotInfos.stream()
.anyMatch(
slot -> slot != null
&& slot.isRemovable()
&& !slot.getIsEuicc()
&& slot.getPorts().stream().anyMatch(
port -> port.isActive())
&& slot.getCardStateInfo()
== UiccSlotInfo.CARD_STATE_INFO_PRESENT);
Log.i(TAG, "isRemovableSimEnabled: " + isRemovableSimEnabled);
return isRemovableSimEnabled;
}
}

View File

@@ -24,7 +24,6 @@ import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.UiccCardInfo;
import android.telephony.UiccSlotInfo;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
@@ -39,8 +38,6 @@ import com.android.settings.network.SwitchToRemovableSlotSidecar;
import com.android.settings.network.UiccSlotUtil;
import com.android.settings.sim.SimActivationNotifier;
import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@@ -586,18 +583,7 @@ public class ToggleSubscriptionDialogActivity extends SubscriptionActionDialogAc
}
private boolean isRemovableSimEnabled() {
ImmutableList<UiccSlotInfo> slotInfos = UiccSlotUtil.getSlotInfos(mTelMgr);
boolean isRemovableSimEnabled =
slotInfos.stream()
.anyMatch(
slot -> slot != null
&& slot.isRemovable()
&& slot.getPorts().stream().anyMatch(
port -> port.isActive())
&& slot.getCardStateInfo()
== UiccSlotInfo.CARD_STATE_INFO_PRESENT);
Log.i(TAG, "isRemovableSimEnabled: " + isRemovableSimEnabled);
return isRemovableSimEnabled;
return UiccSlotUtil.isRemovableSimEnabled(mTelMgr);
}
private boolean isMultipleEnabledProfilesSupported() {

View File

@@ -25,9 +25,12 @@ import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROF
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.SearchIndexableResource;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.notification.LockScreenNotificationPreferenceController;
import com.android.settings.safetycenter.SafetyCenterManagerWrapper;
@@ -131,5 +134,21 @@ public class PrivacyDashboardFragment extends DashboardFragment {
Context context) {
return buildPreferenceControllers(context, null);
}
@Override
public List<String> getNonIndexableKeys(Context context) {
final List<String> keys = super.getNonIndexableKeys(context);
final int profileUserId =
Utils.getManagedProfileId(
UserManager.get(context), UserHandle.myUserId());
// If work profile is supported, we should keep the search result.
if (profileUserId != UserHandle.USER_NULL) {
return keys;
}
// Otherwise, we should hide the search result.
keys.add(KEY_NOTIFICATION_WORK_PROFILE_NOTIFICATIONS);
return keys;
}
};
}

View File

@@ -626,7 +626,14 @@ class ConfigDialog extends AlertDialog implements TextWatcher,
String proxyPort = mProxyPort.getText().toString().trim();
// 0 is a last resort default, but the interface validates that the proxy port is
// present and non-zero.
int port = proxyPort.isEmpty() ? 0 : Integer.parseInt(proxyPort);
int port = 0;
if (!proxyPort.isEmpty()) {
try {
port = Integer.parseInt(proxyPort);
} catch (NumberFormatException e) {
Log.e(TAG, "Could not parse proxy port integer ", e);
}
}
profile.proxy = ProxyInfo.buildDirectProxy(proxyHost, port);
} else {
profile.proxy = null;

View File

@@ -27,12 +27,14 @@ import android.net.wifi.WifiManager.NetworkRequestUserSelectionCallback;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.Looper;
import android.os.Message;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import com.android.settings.R;
import com.android.settings.wifi.NetworkRequestErrorDialogFragment.ERROR_DIALOG_TYPE;
@@ -143,7 +145,7 @@ public class NetworkRequestDialogActivity extends FragmentActivity implements
super.onPause();
}
private final Handler mHandler = new Handler() {
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
@@ -162,13 +164,17 @@ public class NetworkRequestDialogActivity extends FragmentActivity implements
dismissDialogs();
// Throws error dialog.
final FragmentManager fragmentManager = getSupportFragmentManager();
if (fragmentManager.isDestroyed() || fragmentManager.isStateSaved()) {
return;
}
final NetworkRequestErrorDialogFragment dialogFragment =
NetworkRequestErrorDialogFragment.newInstance();
dialogFragment.setRejectCallback(mUserSelectionCallback);
final Bundle bundle = new Bundle();
bundle.putSerializable(NetworkRequestErrorDialogFragment.DIALOG_TYPE, type);
dialogFragment.setArguments(bundle);
dialogFragment.show(getSupportFragmentManager(), TAG);
dialogFragment.show(fragmentManager, TAG);
mShowingErrorDialog = true;
}

View File

@@ -16,15 +16,24 @@
package com.android.settings.dream;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyString;
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.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.PowerManager;
import androidx.preference.Preference;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import com.android.settings.display.AmbientDisplayAlwaysOnPreferenceController;
import com.android.settingslib.dream.DreamBackend;
import com.android.settingslib.dream.DreamBackend.WhenToDream;
@@ -38,32 +47,64 @@ import org.robolectric.util.ReflectionHelpers;
@RunWith(RobolectricTestRunner.class)
public class WhenToDreamPreferenceControllerTest {
private static final String TEST_PACKAGE = "com.android.test";
private WhenToDreamPreferenceController mController;
private Context mContext;
@Mock
private DreamBackend mBackend;
@Mock
private PowerManager mPowerManager;
@Mock
private PackageManager mPackageManager;
@Mock
private ApplicationInfo mApplicationInfo;
@Before
public void setup() {
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
mContext = ApplicationProvider.getApplicationContext();
mController = new WhenToDreamPreferenceController(mContext);
mContext = spy(ApplicationProvider.getApplicationContext());
mController = new WhenToDreamPreferenceController(mContext, true);
ReflectionHelpers.setField(mController, "mBackend", mBackend);
when(mContext.getSystemService(PowerManager.class)).thenReturn(mPowerManager);
when(mPowerManager.isAmbientDisplaySuppressedForTokenByApp(anyString(), anyInt()))
.thenReturn(false);
mApplicationInfo.uid = 1;
when(mContext.getString(
com.android.internal.R.string.config_defaultWellbeingPackage)).thenReturn(
TEST_PACKAGE);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mPackageManager.getApplicationInfo(TEST_PACKAGE, /* flag= */ 0)).thenReturn(
mApplicationInfo);
}
@Test
public void updateSummary() {
public void testUpdateSummary() {
// Don't have to test the other settings because DreamSettings tests that all
// @WhenToDream values map to the correct ResId
final @WhenToDream int testSetting = DreamBackend.WHILE_CHARGING;
final Preference mockPref = mock(Preference.class);
when(mockPref.getContext()).thenReturn(mContext);
when(mBackend.getWhenToDreamSetting()).thenReturn(testSetting);
final String expectedString =
mContext.getString(DreamSettings.getDreamSettingDescriptionResId(testSetting));
final int expectedResId = DreamSettings.getDreamSettingDescriptionResId(testSetting);
mController.updateState(mockPref);
verify(mockPref).setSummary(expectedString);
verify(mockPref).setSummary(expectedResId);
}
@Test
public void testBedtimeModeSuppression() {
final Preference mockPref = mock(Preference.class);
when(mockPref.getContext()).thenReturn(mContext);
when(mBackend.getWhenToDreamSetting()).thenReturn(DreamBackend.WHILE_CHARGING);
when(mPowerManager.isAmbientDisplaySuppressedForTokenByApp(anyString(), anyInt()))
.thenReturn(true);
assertTrue(AmbientDisplayAlwaysOnPreferenceController.isAodSuppressedByBedtime(mContext));
mController.updateState(mockPref);
verify(mockPref).setSummary(R.string.screensaver_settings_when_to_dream_bedtime);
}
}

View File

@@ -0,0 +1,311 @@
/*
* 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.fuelgauge.batteryusage;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.fuelgauge.batteryusage.db.BatteryState;
import com.android.settings.fuelgauge.batteryusage.db.BatteryStateDatabase;
import com.android.settings.testutils.BatteryTestUtils;
import com.android.settings.testutils.FakeClock;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import java.time.Duration;
import java.util.List;
/** Tests for {@link BatteryUsageContentProvider}. */
@RunWith(RobolectricTestRunner.class)
public final class BatteryUsageContentProviderTest {
private static final Uri VALID_BATTERY_STATE_CONTENT_URI =
new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(DatabaseUtils.AUTHORITY)
.appendPath(DatabaseUtils.BATTERY_STATE_TABLE)
.build();
private Context mContext;
private BatteryUsageContentProvider mProvider;
@Before
public void setUp() {
mContext = ApplicationProvider.getApplicationContext();
mProvider = new BatteryUsageContentProvider();
mProvider.attachInfo(mContext, /*info=*/ null);
BatteryTestUtils.setUpBatteryStateDatabase(mContext);
}
@Test
public void onCreate_withoutWorkProfileMode_returnsTrue() {
assertThat(mProvider.onCreate()).isTrue();
}
@Test
public void onCreate_withWorkProfileMode_returnsFalse() {
BatteryTestUtils.setWorkProfile(mContext);
assertThat(mProvider.onCreate()).isFalse();
}
@Test
public void queryAndInsert_incorrectContentUri_throwsIllegalArgumentException() {
final Uri.Builder builder =
new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(DatabaseUtils.AUTHORITY)
.appendPath(DatabaseUtils.BATTERY_STATE_TABLE + "/0");
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 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<BatteryState> 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<BatteryState> 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.
}
}

View File

@@ -0,0 +1,135 @@
/*
* 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.fuelgauge.batteryusage.db;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.database.Cursor;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.testutils.BatteryTestUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import java.util.List;
/** Tests for {@link BatteryStateDao}. */
@RunWith(RobolectricTestRunner.class)
public final class BatteryStateDaoTest {
private static final int CURSOR_COLUMN_SIZE = 19;
private static final long TIMESTAMP1 = System.currentTimeMillis();
private static final long TIMESTAMP2 = System.currentTimeMillis() + 2;
private static final long TIMESTAMP3 = System.currentTimeMillis() + 4;
private static final String PACKAGE_NAME1 = "com.android.apps.settings";
private static final String PACKAGE_NAME2 = "com.android.apps.calendar";
private static final String PACKAGE_NAME3 = "com.android.apps.gmail";
private Context mContext;
private BatteryStateDatabase mDatabase;
private BatteryStateDao mBatteryStateDao;
@Before
public void setUp() {
mContext = ApplicationProvider.getApplicationContext();
mDatabase = BatteryTestUtils.setUpBatteryStateDatabase(mContext);
mBatteryStateDao = mDatabase.batteryStateDao();
BatteryTestUtils.insertDataToBatteryStateDatabase(mContext, TIMESTAMP3, PACKAGE_NAME3);
BatteryTestUtils.insertDataToBatteryStateDatabase(mContext, TIMESTAMP2, PACKAGE_NAME2);
BatteryTestUtils.insertDataToBatteryStateDatabase(
mContext, TIMESTAMP1, PACKAGE_NAME1, /*multiple=*/ true);
}
@After
public void closeDb() {
mDatabase.close();
BatteryStateDatabase.setBatteryStateDatabase(/*database=*/ null);
}
@Test
public void batteryStateDao_insertAll() throws Exception {
final List<BatteryState> states = mBatteryStateDao.getAllAfter(TIMESTAMP1);
assertThat(states).hasSize(2);
// Verifies the queried battery states.
assertBatteryState(states.get(0), TIMESTAMP3, PACKAGE_NAME3);
assertBatteryState(states.get(1), TIMESTAMP2, PACKAGE_NAME2);
}
@Test
public void batteryStateDao_getCursorAfter() throws Exception {
final Cursor cursor = mBatteryStateDao.getCursorAfter(TIMESTAMP2);
assertThat(cursor.getCount()).isEqualTo(2);
assertThat(cursor.getColumnCount()).isEqualTo(CURSOR_COLUMN_SIZE);
// Verifies the queried first battery state.
cursor.moveToFirst();
assertThat(cursor.getString(4 /*packageName*/)).isEqualTo(PACKAGE_NAME3);
// Verifies the queried second battery state.
cursor.moveToNext();
assertThat(cursor.getString(4 /*packageName*/)).isEqualTo(PACKAGE_NAME2);
}
@Test
public void batteryStateDao_clearAllBefore() throws Exception {
mBatteryStateDao.clearAllBefore(TIMESTAMP2);
final List<BatteryState> states = mBatteryStateDao.getAllAfter(0);
assertThat(states).hasSize(1);
// Verifies the queried battery state.
assertBatteryState(states.get(0), TIMESTAMP3, PACKAGE_NAME3);
}
@Test
public void batteryStateDao_clearAll() throws Exception {
assertThat(mBatteryStateDao.getAllAfter(0)).hasSize(3);
mBatteryStateDao.clearAll();
assertThat(mBatteryStateDao.getAllAfter(0)).isEmpty();
}
@Test
public void getInstance_createNewInstance() throws Exception {
BatteryStateDatabase.setBatteryStateDatabase(/*database=*/ null);
assertThat(BatteryStateDatabase.getInstance(mContext)).isNotNull();
}
@Test
public void getDistinctTimestampCount_returnsExpectedResult() {
assertThat(mBatteryStateDao.getDistinctTimestampCount(/*timestamp=*/ 0))
.isEqualTo(3);
assertThat(mBatteryStateDao.getDistinctTimestampCount(TIMESTAMP1))
.isEqualTo(2);
}
@Test
public void getDistinctTimestamps_returnsExpectedResult() {
final List<Long> timestamps =
mBatteryStateDao.getDistinctTimestamps(/*timestamp=*/ 0);
assertThat(timestamps).hasSize(3);
assertThat(timestamps).containsExactly(TIMESTAMP1, TIMESTAMP2, TIMESTAMP3);
}
private static void assertBatteryState(
BatteryState state, long timestamp, String packageName) {
assertThat(state.timestamp).isEqualTo(timestamp);
assertThat(state.packageName).isEqualTo(packageName);
}
}

View File

@@ -0,0 +1,98 @@
/*
* 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.fuelgauge.batteryusage.db;
import static com.google.common.truth.Truth.assertThat;
import android.content.Intent;
import android.os.BatteryManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
/** Tests for {@link BatteryState}. */
@RunWith(RobolectricTestRunner.class)
public final class BatteryStateTest {
private static final int BATTERY_LEVEL = 45;
private static final int BATTERY_STATUS = BatteryManager.BATTERY_STATUS_FULL;
private static final int BATTERY_HEALTH = BatteryManager.BATTERY_HEALTH_COLD;
private Intent mBatteryIntent;
@Before
public void setUp() {
mBatteryIntent = new Intent(Intent.ACTION_BATTERY_CHANGED);
// Inserts the battery states into intent.
mBatteryIntent.putExtra(BatteryManager.EXTRA_LEVEL, BATTERY_LEVEL);
mBatteryIntent.putExtra(BatteryManager.EXTRA_STATUS, BATTERY_STATUS);
mBatteryIntent.putExtra(BatteryManager.EXTRA_HEALTH, BATTERY_HEALTH);
}
@Test
public void testBuilder_returnsExpectedResult() {
mBatteryIntent.putExtra(BatteryManager.EXTRA_SCALE, 100);
BatteryState state = create(mBatteryIntent);
// Verifies the app relative information.
assertThat(state.uid).isEqualTo(1001L);
assertThat(state.userId).isEqualTo(100L);
assertThat(state.appLabel).isEqualTo("Settings");
assertThat(state.packageName).isEqualTo("com.android.settings");
assertThat(state.isHidden).isTrue();
assertThat(state.bootTimestamp).isEqualTo(101L);
assertThat(state.timestamp).isEqualTo(100001L);
// Verifies the battery relative information.
assertThat(state.totalPower).isEqualTo(100);
assertThat(state.consumePower).isEqualTo(3);
assertThat(state.percentOfTotal).isEqualTo(10);
assertThat(state.foregroundUsageTimeInMs).isEqualTo(60000);
assertThat(state.backgroundUsageTimeInMs).isEqualTo(10000);
assertThat(state.drainType).isEqualTo(1);
assertThat(state.consumerType).isEqualTo(2);
assertThat(state.batteryLevel).isEqualTo(BATTERY_LEVEL);
assertThat(state.batteryStatus).isEqualTo(BATTERY_STATUS);
assertThat(state.batteryHealth).isEqualTo(BATTERY_HEALTH);
}
@Test
public void create_withoutBatteryScale_returnsStateWithInvalidLevel() {
BatteryState state = create(mBatteryIntent);
assertThat(state.batteryLevel).isEqualTo(-1);
}
private static BatteryState create(Intent intent) {
return BatteryState.newBuilder()
.setUid(1001L)
.setUserId(100L)
.setAppLabel("Settings")
.setPackageName("com.android.settings")
.setIsHidden(true)
.setBootTimestamp(101L)
.setTimestamp(100001L)
.setTotalPower(100f)
.setConsumePower(3f)
.setPercentOfTotal(10f)
.setForegroundUsageTimeInMs(60000)
.setBackgroundUsageTimeInMs(10000)
.setDrainType(1)
.setConsumerType(2)
.setBatteryIntent(intent)
.build();
}
}

View File

@@ -61,12 +61,9 @@ import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
import com.android.settings.testutils.shadow.ShadowThreadUtils;
import com.android.settings.testutils.shadow.ShadowUserManager;
import com.android.settings.testutils.shadow.ShadowUtils;
import com.android.settings.wifi.slice.WifiScanWorker;
import com.android.settingslib.wifi.WifiTracker;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -100,7 +97,6 @@ import java.util.Set;
@Config(shadows = {ShadowUserManager.class, ShadowUtils.class,
SlicesDatabaseAccessorTest.ShadowApplicationPackageManager.class,
ShadowBluetoothAdapter.class, ShadowLockPatternUtils.class,
SettingsSliceProviderTest.ShadowWifiScanWorker.class,
SettingsSliceProviderTest.ShadowTheme.class})
public class SettingsSliceProviderTest {
@@ -123,6 +119,7 @@ public class SettingsSliceProviderTest {
private Context mContext;
private SettingsSliceProvider mProvider;
private ShadowPackageManager mPackageManager;
@Mock
private SliceManager mManager;
@@ -572,14 +569,6 @@ public class SettingsSliceProviderTest {
assertThat(pendingIntent).isEqualTo(settingsPendingIntent);
}
@Test
@Ignore
public void bindSlice_wifiSlice_returnsWifiSlice() {
final Slice wifiSlice = mProvider.onBindSlice(CustomSliceRegistry.WIFI_SLICE_URI);
assertThat(wifiSlice.getUri()).isEqualTo(CustomSliceRegistry.WIFI_SLICE_URI);
}
@Test
public void bindSlice_flashlightSlice_returnsFlashlightSlice() {
Settings.Secure.putInt(
@@ -603,32 +592,6 @@ public class SettingsSliceProviderTest {
mProvider.onSlicePinned(uri);
}
@Test
@Ignore
public void onSlicePinned_backgroundWorker_started() {
mProvider.onSlicePinned(CustomSliceRegistry.WIFI_SLICE_URI);
verify(ShadowWifiScanWorker.getWifiTracker()).onStart();
}
@Test
@Ignore
public void onSlicePinned_backgroundWorker_stopped() {
mProvider.onSlicePinned(CustomSliceRegistry.WIFI_SLICE_URI);
mProvider.onSliceUnpinned(CustomSliceRegistry.WIFI_SLICE_URI);
verify(ShadowWifiScanWorker.getWifiTracker()).onStop();
}
@Test
@Ignore
public void shutdown_backgroundWorker_closed() {
mProvider.onSlicePinned(CustomSliceRegistry.WIFI_SLICE_URI);
mProvider.shutdown();
verify(ShadowWifiScanWorker.getWifiTracker()).onDestroy();
}
@Test
@Config(qualifiers = "mcc998")
public void grantAllowlistedPackagePermissions_noAllowlist_shouldNotGrant() {
@@ -716,31 +679,6 @@ public class SettingsSliceProviderTest {
.build();
}
@Implements(WifiScanWorker.class)
public static class ShadowWifiScanWorker {
private static WifiTracker mWifiTracker;
@Implementation
protected void onSlicePinned() {
mWifiTracker = mock(WifiTracker.class);
mWifiTracker.onStart();
}
@Implementation
protected void onSliceUnpinned() {
mWifiTracker.onStop();
}
@Implementation
protected void close() {
mWifiTracker.onDestroy();
}
static WifiTracker getWifiTracker() {
return mWifiTracker;
}
}
@Implements(value = StrictMode.class)
public static class ShadowStrictMode {

View File

@@ -16,8 +16,21 @@
package com.android.settings.testutils;
import android.content.Context;
import android.content.Intent;
import android.os.BatteryManager;
import android.os.UserManager;
import androidx.room.Room;
import com.android.settings.fuelgauge.batteryusage.db.BatteryState;
import com.android.settings.fuelgauge.batteryusage.db.BatteryStateDao;
import com.android.settings.fuelgauge.batteryusage.db.BatteryStateDatabase;
import com.google.common.collect.ImmutableList;
import org.robolectric.Shadows;
import org.robolectric.shadows.ShadowUserManager;
public class BatteryTestUtils {
@@ -37,6 +50,65 @@ public class BatteryTestUtils {
BatteryManager.BATTERY_STATUS_DISCHARGING);
}
/** Sets the work profile mode. */
public static void setWorkProfile(Context context) {
final UserManager userManager = context.getSystemService(UserManager.class);
Shadows.shadowOf(userManager).setManagedProfile(true);
// Changes out of the default system user so isSystemUser() returns false.
final int userId = 1001;
Shadows.shadowOf(userManager)
.addUser(userId, "name", /*flags=*/ ShadowUserManager.FLAG_PRIMARY);
Shadows.shadowOf(userManager).switchUser(userId);
}
/** Creates and sets up the in-memory {@link BatteryStateDatabase}. */
public static BatteryStateDatabase setUpBatteryStateDatabase(Context context) {
final BatteryStateDatabase inMemoryDatabase =
Room.inMemoryDatabaseBuilder(context, BatteryStateDatabase.class)
.allowMainThreadQueries()
.build();
BatteryStateDatabase.setBatteryStateDatabase(inMemoryDatabase);
return inMemoryDatabase;
}
/** Inserts a fake data into the database for testing. */
public static void insertDataToBatteryStateDatabase(
Context context, long timestamp, String packageName) {
insertDataToBatteryStateDatabase(context, timestamp, packageName, /*multiple=*/ false);
}
/** Inserts a fake data into the database for testing. */
public static void insertDataToBatteryStateDatabase(
Context context, long timestamp, String packageName, boolean multiple) {
final BatteryState state =
new BatteryState(
/*uid=*/ 1001L,
/*userId=*/ 100L,
/*appLabel=*/ "Settings",
packageName,
/*isHidden=*/ true,
/*bootTimestamp=*/ timestamp - 1,
timestamp,
/*zoneId=*/ "Europe/Paris",
/*totalPower=*/ 100f,
/*consumePower=*/ 0.3f,
/*percentOfTotal=*/ 10f,
/*foregroundUsageTimeInMs=*/ 60000,
/*backgroundUsageTimeInMs=*/ 10000,
/*drainType=*/ 1,
/*consumerType=*/ 2,
/*batteryLevel=*/ 31,
/*batteryStatus=*/ 0,
/*batteryHealth=*/ 0);
BatteryStateDao dao =
BatteryStateDatabase.getInstance(context).batteryStateDao();
if (multiple) {
dao.insertAll(ImmutableList.of(state));
} else {
dao.insert(state);
}
}
private static Intent getCustomBatteryIntent(int plugged, int level, int scale, int status) {
Intent intent = new Intent();
intent.putExtra(BatteryManager.EXTRA_PLUGGED, plugged);

View File

@@ -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;
}
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright (C) 2020 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.applications.specialaccess.notificationaccess;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.service.notification.NotificationListenerService;
import androidx.preference.Preference;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.common.collect.ImmutableList;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
public class MoreSettingsPreferenceControllerTest {
Context mContext;
private MoreSettingsPreferenceController mController;
@Mock
PackageManager mPm;
final String mPkg = "pkg";
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = ApplicationProvider.getApplicationContext();
mController = new MoreSettingsPreferenceController(mContext);
mController.setPackage(mPkg);
mController.setPackageManager(mPm);
}
@Test
public void getAvailabilityStatus_available() {
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
when(mPm.queryIntentActivities(captor.capture(), any())).thenReturn(
ImmutableList.of(mock(ResolveInfo.class)));
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
assertThat(captor.getValue().getPackage()).isEqualTo(mPkg);
assertThat(captor.getValue().getAction()).isEqualTo(Intent.ACTION_MAIN);
assertThat(captor.getValue().getCategories()).contains(
NotificationListenerService.INTENT_CATEGORY_SETTINGS_HOME);
}
@Test
public void getAvailabilityStatus_notAvailable() {
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
when(mPm.queryIntentActivities(captor.capture(), any())).thenReturn(ImmutableList.of());
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
}
@Test
public void updateState() {
Preference preference = new Preference(mContext);
mController.updateState(preference);
assertThat(preference.getIntent().getPackage()).isEqualTo(mPkg);
assertThat(preference.getIntent().getAction()).isEqualTo(Intent.ACTION_MAIN);
assertThat(preference.getIntent().getCategories()).contains(
NotificationListenerService.INTENT_CATEGORY_SETTINGS_HOME);
}
}

View File

@@ -638,6 +638,106 @@ public class UiccSlotUtilTest {
assertThat(testExcludedLogicalSlotIndex).isEqualTo(verifyExcludedLogicalSlotIndex);
}
@Test
public void isRemovableSimEnabled_noPsim_returnsFalse() {
when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(
oneSimSlotDeviceActiveEsim());
boolean testSlot = UiccSlotUtil.isRemovableSimEnabled(mTelephonyManager);
assertThat(testSlot).isFalse();
}
@Test
public void isRemovableSimEnabled_activeRemovableEsimAndInactivePsim_returnsFalse() {
when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(
twoSimSlotsDeviceActiveRemovableEsimInactivePsim());
boolean testSlot = UiccSlotUtil.isRemovableSimEnabled(mTelephonyManager);
assertThat(testSlot).isFalse();
}
@Test
public void isRemovableSimEnabled_activeRemovableEsimAndActivePsim_returnsTrue() {
when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(
twoSimSlotsDeviceActivePsimActiveRemovableEsim());
boolean testSlot = UiccSlotUtil.isRemovableSimEnabled(mTelephonyManager);
assertThat(testSlot).isTrue();
}
@Test
public void isRemovableSimEnabled_inactiveRemovableEsimAndActivePsim_returnsTrue() {
when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(
twoSimSlotsDeviceInactiveRemovableEsimActivePsim());
boolean testSlot = UiccSlotUtil.isRemovableSimEnabled(mTelephonyManager);
assertThat(testSlot).isTrue();
}
@Test
public void isRemovableSimEnabled_twoActiveRemovableEsimsAndInactivePsim_returnsFalse() {
when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(
twoSimSlotsDeviceTwoActiveRemovableEsimsInactivePsim());
boolean testSlot = UiccSlotUtil.isRemovableSimEnabled(mTelephonyManager);
assertThat(testSlot).isFalse();
}
@Test
public void isRemovableSimEnabled_oneActiveOneInactiveRemovableEsimActivePsim_returnsTrue() {
when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(
twoSimSlotsDeviceOneActiveOneInactiveRemovableEsimsActivePsim());
boolean testSlot = UiccSlotUtil.isRemovableSimEnabled(mTelephonyManager);
assertThat(testSlot).isTrue();
}
@Test
public void isRemovableSimEnabled_activePsim_returnsTrue() {
when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(
oneSimSlotDeviceActivePsim());
boolean testSlot = UiccSlotUtil.isRemovableSimEnabled(mTelephonyManager);
assertThat(testSlot).isTrue();
}
@Test
public void isRemovableSimEnabled_inactivePsim_returnsFalse() {
when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(
oneSimSlotDeviceinactivePsim());
boolean testSlot = UiccSlotUtil.isRemovableSimEnabled(mTelephonyManager);
assertThat(testSlot).isFalse();
}
@Test
public void isRemovableSimEnabled_activeEsimAndActivePsim_returnsTrue() {
when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(
twoSimSlotsDeviceActivePsimActiveEsim());
boolean testSlot = UiccSlotUtil.isRemovableSimEnabled(mTelephonyManager);
assertThat(testSlot).isTrue();
}
@Test
public void isRemovableSimEnabled_activeEsimAndInactivePsim_returnsFalse() {
when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(
twoSimSlotsDeviceInactivePsimActiveEsim());
boolean testSlot = UiccSlotUtil.isRemovableSimEnabled(mTelephonyManager);
assertThat(testSlot).isFalse();
}
private void compareTwoUiccSlotMappings(Collection<UiccSlotMapping> testUiccSlotMappings,
Collection<UiccSlotMapping> verifyUiccSlotMappings) {
assertThat(testUiccSlotMappings.size()).isEqualTo(verifyUiccSlotMappings.size());
@@ -792,6 +892,10 @@ public class UiccSlotUtilTest {
return new UiccSlotInfo[]{createUiccSlotInfo(true, false, 1, true)};
}
private UiccSlotInfo[] oneSimSlotDeviceinactivePsim() {
return new UiccSlotInfo[]{createUiccSlotInfo(false, true, -1, false)};
}
private UiccSlotInfo[] twoSimSlotsDeviceActivePsimActiveEsim() {
return new UiccSlotInfo[]{
createUiccSlotInfo(false, true, 0, true),
@@ -810,6 +914,30 @@ public class UiccSlotUtilTest {
createUiccSlotInfo(true, true, 1, true)};
}
private UiccSlotInfo[] twoSimSlotsDeviceActiveRemovableEsimInactivePsim() {
return new UiccSlotInfo[]{
createUiccSlotInfo(true, true, 0, true),
createUiccSlotInfo(false, true, -1, false)};
}
private UiccSlotInfo[] twoSimSlotsDeviceInactiveRemovableEsimActivePsim() {
return new UiccSlotInfo[]{
createUiccSlotInfo(true, true, -1, false),
createUiccSlotInfo(false, true, 0, true)};
}
private UiccSlotInfo[] twoSimSlotsDeviceTwoActiveRemovableEsimsInactivePsim() {
return new UiccSlotInfo[]{
createUiccSlotInfoForRemovableEsimMep(0, true, 1, true),
createUiccSlotInfo(false, true, -1, false)};
}
private UiccSlotInfo[] twoSimSlotsDeviceOneActiveOneInactiveRemovableEsimsActivePsim() {
return new UiccSlotInfo[]{
createUiccSlotInfoForRemovableEsimMep(1, true, -1, false),
createUiccSlotInfo(false, true, 0, true)};
}
private UiccSlotInfo[] twoSimSlotsDeviceActiveEsimActivePsim() {
return new UiccSlotInfo[]{
createUiccSlotInfo(true, false, 0, true),
@@ -872,4 +1000,20 @@ public class UiccSlotUtilTest {
logicalSlotIdx2 /* logicalSlotIdx */,
isActiveEsim2 /* isActive */)));
}
private UiccSlotInfo createUiccSlotInfoForRemovableEsimMep(int logicalSlotIdx1,
boolean isActiveEsim1, int logicalSlotIdx2, boolean isActiveEsim2) {
return new UiccSlotInfo(
true, /* isEuicc */
"123", /* cardId */
CARD_STATE_INFO_PRESENT, /* cardStateInfo */
true, /* isExtendApduSupported */
true, /* isRemovable */
Arrays.asList(
new UiccPortInfo("" /* iccId */, 0 /* portIdx */,
logicalSlotIdx1 /* logicalSlotIdx */, isActiveEsim1 /* isActive */),
new UiccPortInfo("" /* iccId */, 1 /* portIdx */,
logicalSlotIdx2 /* logicalSlotIdx */,
isActiveEsim2 /* isActive */)));
}
}