Snap for 9191040 from 772c437de4 to udc-release
Change-Id: I68d8b8d7ab3b37934d5a370ba48663a7552be825
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 -->
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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 -> {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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() {}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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 */)));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user