summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-07-07 05:28:40 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-07-07 05:28:40 +0000
commit582fa8f7d317c2ece43d04c42ec7d15db23cbce5 (patch)
tree801e5153963a9a347f13082c836e331d5a8e3760
parent8b2cc74c9ad4d049aceada86225e5d0c22d2d846 (diff)
parent4eb7b888ab394100643c6500e06e3b31f1780760 (diff)
downloadTvSettings-aml_tz5_341510010.tar.gz
Snap for 10453563 from 4eb7b888ab394100643c6500e06e3b31f1780760 to mainline-tzdata5-releaseaml_tz5_341510050aml_tz5_341510010aml_tz5_341510010
Change-Id: I4895ad412593f7eab35363332240542322685ffc
-rw-r--r--Settings/AndroidManifest.xml13
-rw-r--r--Settings/res/values/energy-modes.xml3
-rw-r--r--Settings/res/values/integers.xml3
-rw-r--r--Settings/res/values/strings.xml8
-rw-r--r--Settings/src/com/android/tv/settings/TvSettingsApplication.java4
-rw-r--r--Settings/src/com/android/tv/settings/device/apps/specialaccess/NotificationAccess.java8
-rw-r--r--Settings/src/com/android/tv/settings/device/displaysound/ResolutionSelectionFragment.java3
-rw-r--r--Settings/src/com/android/tv/settings/device/displaysound/ResolutionSelectionInfo.java22
-rw-r--r--Settings/src/com/android/tv/settings/device/eco/EnergyModesContentProvider.java215
-rw-r--r--Settings/src/com/android/tv/settings/device/eco/EnergyModesHelper.java8
-rw-r--r--Settings/src/com/android/tv/settings/device/eco/EnergyModesService.java130
-rw-r--r--Settings/src/com/android/tv/settings/device/eco/EnergyModesStatsLogJobService.java125
-rw-r--r--Settings/src/com/android/tv/settings/device/eco/IEnergyModesService.aidl62
-rw-r--r--Settings/src/com/android/tv/settings/util/ResolutionSelectionUtils.java31
-rw-r--r--TwoPanelSettingsLib/Android.bp2
15 files changed, 419 insertions, 218 deletions
diff --git a/Settings/AndroidManifest.xml b/Settings/AndroidManifest.xml
index d077ad99d..db2d4cec2 100644
--- a/Settings/AndroidManifest.xml
+++ b/Settings/AndroidManifest.xml
@@ -1304,8 +1304,17 @@
</intent-filter>
</activity>
- <service android:name=".device.eco.EnergyModesService"
- android:exported="true" />
+ <service android:name=".device.eco.EnergyModesStatsLogJobService"
+ android:permission="android.permission.BIND_JOB_SERVICE" />
+
+ <provider
+ android:name=".device.eco.EnergyModesContentProvider"
+ android:authorities="com.android.tv.settings.device.eco.energymodes"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="com.android.tv.settings.ENERGY_MODES_PROVIDER"/>
+ </intent-filter>
+ </provider>
<activity
android:name=".device.eco.EnergyModesActivity"
diff --git a/Settings/res/values/energy-modes.xml b/Settings/res/values/energy-modes.xml
index 50a1374e0..182796205 100644
--- a/Settings/res/values/energy-modes.xml
+++ b/Settings/res/values/energy-modes.xml
@@ -21,6 +21,9 @@
If false, falls back to a toggle to enable/disable Low Power Standby if LPS is supported. -->
<bool name="enable_energy_modes">true</bool>
+ <!-- The default energy mode, used if none has been set yet. -->
+ <string name="default_energy_mode" translatable="false">@null</string>
+
<!-- Energy mode: Low -->
<eat-comment />
diff --git a/Settings/res/values/integers.xml b/Settings/res/values/integers.xml
index a65838fab..68960fc92 100644
--- a/Settings/res/values/integers.xml
+++ b/Settings/res/values/integers.xml
@@ -14,6 +14,9 @@
limitations under the License.
-->
<resources>
+ <!-- Reserve all the job ids in TvSettings -->
+ <integer name="job_energy_modes_stats_log">100</integer>
+
<!-- Pin dialog -->
<integer name="pin_dialog_anim_duration">250</integer>
<integer name="pin_dialog_enter_offset_y">32</integer>
diff --git a/Settings/res/values/strings.xml b/Settings/res/values/strings.xml
index 29245e7bf..22209724f 100644
--- a/Settings/res/values/strings.xml
+++ b/Settings/res/values/strings.xml
@@ -579,7 +579,7 @@
<!-- Description of resolution mode that is shown on the side panel when user is scrolling
through resolution modes. It lists all HDR types that this mode supports.
[CHAR LIMIT=300]-->
- <string name="resolution_hdr_description_info">This mode supports %1$s. On some TVs, you may
+ <string name="resolution_hdr_description_info">This mode supports: %1$s\nOn some TVs, you may
need to turn on Enhanced HDMI to enable more HDR formats. Check your TV settings to see if
this is supported.</string>
<!-- Cancel button title for dialog that is shown when user changes the resolution.
@@ -899,10 +899,8 @@
<string name="do_disclosure_with_name">This device is managed by <xliff:g id="organization_name" example="Foo, Inc.">%s</xliff:g>.</string>
<!-- Message indicating that the device is enterprise-managed: Space that separates the main text and the "learn more" link that follows it. [CHAR LIMIT=NONE] -->
<string name="do_disclosure_learn_more_separator">" "</string>
- <!-- A word separator (e.g. a comma), indicating a pause between parts of a sentence or separating items in a list. [CHAR LIMIT=NONE] -->
- <string name="word_separator">,</string>
- <!-- A space, used for separating words -->
- <string name="space_separator">" "</string>
+ <!-- An HDR capability[CHAR LIMIT=NONE] -->
+ <string name="hdr_capability">- %1$s</string>
<!-- Button label to allow the user to view additional information [CHAR LIMIT=NONE BACKUP_MESSAGE_ID=2416766240581561009] -->
<string name="learn_more">Learn more</string>
diff --git a/Settings/src/com/android/tv/settings/TvSettingsApplication.java b/Settings/src/com/android/tv/settings/TvSettingsApplication.java
index 5a62e5bc9..2e88e2930 100644
--- a/Settings/src/com/android/tv/settings/TvSettingsApplication.java
+++ b/Settings/src/com/android/tv/settings/TvSettingsApplication.java
@@ -20,6 +20,8 @@ import android.app.Application;
import androidx.annotation.Nullable;
+import com.android.tv.settings.device.eco.EnergyModesStatsLogJobService;
+
/**
* Application class that instantiates system sound player singleton so sound effects are only
* loaded once and shared between components.
@@ -33,6 +35,8 @@ public class TvSettingsApplication extends Application {
if (getResources().getBoolean(R.bool.config_enableSystemSounds)) {
mSystemSoundsPlayer = new SystemSoundsPlayer(this);
}
+
+ EnergyModesStatsLogJobService.scheduleEnergyModesStatsLog(this);
}
@Nullable
diff --git a/Settings/src/com/android/tv/settings/device/apps/specialaccess/NotificationAccess.java b/Settings/src/com/android/tv/settings/device/apps/specialaccess/NotificationAccess.java
index 2caef3d1d..df13211d6 100644
--- a/Settings/src/com/android/tv/settings/device/apps/specialaccess/NotificationAccess.java
+++ b/Settings/src/com/android/tv/settings/device/apps/specialaccess/NotificationAccess.java
@@ -49,6 +49,8 @@ import java.util.List;
public class NotificationAccess extends SettingsPreferenceFragment {
private static final String TAG = "NotificationAccess";
+ private static final int MAX_CN_LENGTH = 500;
+
private static final String HEADER_KEY = "header";
private static final String DEFAULT_PACKAGES_SEPARATOR = ":";
@@ -76,6 +78,12 @@ public class NotificationAccess extends SettingsPreferenceFragment {
.setIntentAction(NotificationListenerService.SERVICE_INTERFACE)
.setPermission(android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE)
.setNoun("notification listener")
+ .setValidator(info -> {
+ if (info.getComponentName().flattenToString().length() > MAX_CN_LENGTH) {
+ return false;
+ }
+ return true;
+ })
.build();
mServiceListing.addCallback(this::updateList);
}
diff --git a/Settings/src/com/android/tv/settings/device/displaysound/ResolutionSelectionFragment.java b/Settings/src/com/android/tv/settings/device/displaysound/ResolutionSelectionFragment.java
index b7426e7d0..db515ba65 100644
--- a/Settings/src/com/android/tv/settings/device/displaysound/ResolutionSelectionFragment.java
+++ b/Settings/src/com/android/tv/settings/device/displaysound/ResolutionSelectionFragment.java
@@ -169,7 +169,8 @@ public class ResolutionSelectionFragment extends PreferenceControllerFragment {
mode.getPhysicalWidth(), mode.getPhysicalHeight()),
ResolutionSelectionUtils.getRefreshRateString(mode.getRefreshRate()));
- String summary = mode.getPhysicalWidth() + " x " + mode.getPhysicalHeight();
+ String summary = ResolutionSelectionUtils.getResolutionSummary(mode.getPhysicalWidth(),
+ mode.getPhysicalHeight());
RadioPreference pref = new RadioPreference(getContext());
pref.setTitle(title);
pref.setSummary(summary);
diff --git a/Settings/src/com/android/tv/settings/device/displaysound/ResolutionSelectionInfo.java b/Settings/src/com/android/tv/settings/device/displaysound/ResolutionSelectionInfo.java
index 73463b2f4..3f3c9ff11 100644
--- a/Settings/src/com/android/tv/settings/device/displaysound/ResolutionSelectionInfo.java
+++ b/Settings/src/com/android/tv/settings/device/displaysound/ResolutionSelectionInfo.java
@@ -44,28 +44,32 @@ public class ResolutionSelectionInfo {
public static class HDRInfoFragment extends ResolutionSelectionInfo.BaseInfoFragment {
private String hdrTypesAsString(int[] hdrTypes) {
- StringBuilder supportedTypes = new StringBuilder(
- getResources().getString(R.string.hdr_format_sdr));
+ StringBuilder supportedTypes = new StringBuilder(System.lineSeparator()).append(
+ getResources().getString(R.string.hdr_capability,
+ getResources().getString(R.string.hdr_format_sdr)));
for (int supportedType : hdrTypes) {
- supportedTypes.append(getResources().getString(R.string.word_separator))
- .append(getResources().getString(
- R.string.space_separator));
+ supportedTypes.append(System.lineSeparator());
switch (supportedType) {
case HDR_TYPE_DOLBY_VISION:
supportedTypes
- .append(getResources().getString(R.string.hdr_format_dolby_vision));
+ .append(getResources().getString(R.string.hdr_capability,
+ getResources().getString(
+ R.string.hdr_format_dolby_vision)));
break;
case HDR_TYPE_HDR10:
supportedTypes
- .append(getResources().getString(R.string.hdr_format_hdr10));
+ .append(getResources().getString(R.string.hdr_capability,
+ getResources().getString(R.string.hdr_format_hdr10)));
break;
case HDR_TYPE_HLG:
supportedTypes
- .append(getResources().getString(R.string.hdr_format_hlg));
+ .append(getResources().getString(R.string.hdr_capability,
+ getResources().getString(R.string.hdr_format_hlg)));
break;
case HDR_TYPE_HDR10_PLUS:
supportedTypes
- .append(getResources().getString(R.string.hdr_format_hdr10plus));
+ .append(getResources().getString(R.string.hdr_capability,
+ getResources().getString(R.string.hdr_format_hdr10plus)));
break;
}
}
diff --git a/Settings/src/com/android/tv/settings/device/eco/EnergyModesContentProvider.java b/Settings/src/com/android/tv/settings/device/eco/EnergyModesContentProvider.java
new file mode 100644
index 000000000..18265cde6
--- /dev/null
+++ b/Settings/src/com/android/tv/settings/device/eco/EnergyModesContentProvider.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2023 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.tv.settings.device.eco;
+
+import static android.Manifest.permission.MANAGE_LOW_POWER_STANDBY;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Bundle;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.tv.settings.device.eco.EnergyModesHelper.EnergyMode;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * ContentProvider that provides methods to query and set Energy Modes.
+ */
+public class EnergyModesContentProvider extends ContentProvider {
+ /** Method to get available energy modes, default mode, and selected mode */
+ private static final String METHOD_GET_ENERGY_MODES = "getEnergyModes";
+
+ /**
+ * Method to set the selected energy mode.
+ * Requires permission MANAGE_LOW_POWER_STANDBY.
+ */
+ private static final String METHOD_SET_ENERGY_MODE = "setEnergyMode";
+
+ /** Key for a String representing the identifier of the default mode (may be null). */
+ private static final String KEY_DEFAULT_MODE = "default_mode";
+
+ /** Key for a String representing the currently selected mode. */
+ private static final String KEY_SELECTED_MODE = "selected_mode";
+
+ /** Key for a List of Bundle representing the available energy modes. */
+ private static final String KEY_ENERGY_MODES = "energy_modes";
+
+ /** Key for a String representing the identifier for an energy mode. */
+ private static final String KEY_IDENTIFIER = "identifier";
+
+ /** Key for an Icon representing the icon of an energy mode. */
+ private static final String KEY_ICON = "icon";
+
+ /** Key for an int representing the color of an energy mode (in ARGB). */
+ private static final String KEY_COLOR = "color";
+
+ /** Key for a String representing the title of an energy mode. */
+ private static final String KEY_TITLE = "title";
+
+ /** Key for a String representing the subtitle of an energy mode. */
+ private static final String KEY_SUBTITLE = "subtitle";
+
+ /** Key for a String representing the description of an energy mode. */
+ private static final String KEY_DESCRIPTION = "description";
+
+ /** Key for a String representing a short description of an energy mode. */
+ private static final String KEY_SHORT_DESCRIPTION = "short_description";
+
+ /** Key for a String array representing the (human-friendly) features of an energy mode. */
+ private static final String KEY_FEATURES_LIST = "features_list";
+
+ /** Key for a String array representing the features of an energy mode. */
+ private static final String KEY_FEATURES = "features";
+
+ @Override
+ public boolean onCreate() {
+ return true;
+ }
+
+ @Nullable
+ @Override
+ public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,
+ @Nullable String[] selectionArgs, @Nullable String sortOrder) {
+ throw new UnsupportedOperationException("query operation not supported currently.");
+ }
+
+ @Nullable
+ @Override
+ public String getType(@NonNull Uri uri) {
+ throw new UnsupportedOperationException("getType operation not supported currently.");
+ }
+
+ @Nullable
+ @Override
+ public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
+ throw new UnsupportedOperationException("insert operation not supported currently.");
+ }
+
+ @Override
+ public int delete(@NonNull Uri uri, @Nullable String selection,
+ @Nullable String[] selectionArgs) {
+ throw new UnsupportedOperationException("delete operation not supported currently.");
+ }
+
+ @Override
+ public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection,
+ @Nullable String[] selectionArgs) {
+ throw new UnsupportedOperationException("update operation not supported currently.");
+ }
+
+ @Override
+ public Bundle call(String method, String arg, Bundle extras) {
+ if (METHOD_GET_ENERGY_MODES.equals(method)) {
+ return getEnergyModesFromBinder();
+ } else if (METHOD_SET_ENERGY_MODE.equals(method)) {
+ return setEnergyModeFromBinder(arg);
+ }
+
+ throw new IllegalArgumentException("Unknown method name");
+ }
+
+ private Bundle getEnergyModesFromBinder() {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return getEnergyModes();
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ private Bundle getEnergyModes() {
+ EnergyModesHelper energyModesHelper = new EnergyModesHelper(getContext());
+
+ final EnergyMode defaultMode = energyModesHelper.getDefaultEnergyMode();
+ final EnergyMode currentMode = energyModesHelper.updateEnergyMode();
+
+ Bundle bundle = new Bundle();
+ bundle.putString(KEY_DEFAULT_MODE, getModeIdentifier(defaultMode));
+ bundle.putString(KEY_SELECTED_MODE, getModeIdentifier(currentMode));
+ bundle.putParcelableList(KEY_ENERGY_MODES, getModes(energyModesHelper));
+ return bundle;
+ }
+
+ private Bundle setEnergyModeFromBinder(String identifier) {
+ getContext().enforceCallingOrSelfPermission(MANAGE_LOW_POWER_STANDBY, null);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ EnergyModesHelper energyModesHelper = new EnergyModesHelper(getContext());
+ EnergyMode energyMode = energyModesHelper.getEnergyMode(/* identifier= */ identifier);
+ if (energyMode == null) {
+ throw new IllegalArgumentException("Unknown energy mode: " + identifier);
+ }
+
+ energyModesHelper.setEnergyMode(energyMode);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+
+ return null;
+ }
+
+ @Nullable
+ private String getModeIdentifier(@Nullable EnergyMode mode) {
+ if (mode == null) {
+ return null;
+ }
+
+ return getContext().getString(mode.identifierRes);
+ }
+
+ @NonNull
+ private List<Bundle> getModes(@NonNull EnergyModesHelper helper) {
+ final List<Bundle> result = new ArrayList<>();
+ final List<EnergyMode> energyModes = helper.getEnergyModes();
+
+ for (EnergyMode mode : energyModes) {
+ result.add(convertEnergyModeToBundle(helper, mode));
+ }
+
+ return result;
+ }
+
+ @NonNull
+ private Bundle convertEnergyModeToBundle(
+ @NonNull EnergyModesHelper helper, @NonNull EnergyMode mode) {
+ Context context = getContext();
+ Bundle bundle = new Bundle();
+
+ bundle.putString(KEY_IDENTIFIER, getModeIdentifier(mode));
+ bundle.putParcelable(KEY_ICON, Icon.createWithResource(context, mode.iconRes));
+ bundle.putInt(KEY_COLOR, context.getColor(mode.colorRes));
+ bundle.putString(KEY_TITLE, context.getString(mode.titleRes));
+ bundle.putString(KEY_SUBTITLE, context.getString(mode.subtitleRes));
+ bundle.putString(KEY_DESCRIPTION, context.getString(mode.infoTextRes));
+ bundle.putString(KEY_SHORT_DESCRIPTION, context.getString(mode.infoTextRes));
+ bundle.putStringArray(KEY_FEATURES_LIST,
+ context.getResources().getStringArray(mode.featuresRes));
+ bundle.putStringArray(KEY_FEATURES,
+ helper.getAllowedFeatures(mode).toArray(new String[0]));
+
+ return bundle;
+ }
+}
diff --git a/Settings/src/com/android/tv/settings/device/eco/EnergyModesHelper.java b/Settings/src/com/android/tv/settings/device/eco/EnergyModesHelper.java
index ffa32c7fd..e8ce5efd2 100644
--- a/Settings/src/com/android/tv/settings/device/eco/EnergyModesHelper.java
+++ b/Settings/src/com/android/tv/settings/device/eco/EnergyModesHelper.java
@@ -330,7 +330,7 @@ public final class EnergyModesHelper {
return string.split(",");
}
- private LowPowerStandbyPolicy getPolicy(EnergyMode mode) {
+ LowPowerStandbyPolicy getPolicy(EnergyMode mode) {
if (!mode.enableLowPowerStandby) {
return new LowPowerStandbyPolicy(
mContext.getString(mode.identifierRes),
@@ -410,7 +410,7 @@ public final class EnergyModesHelper {
if (!areEnergyModesAvailable()) {
return null;
}
- return getEnergyModes().get(0);
+ return getEnergyMode(mContext.getString(R.string.default_energy_mode));
}
/**
@@ -466,6 +466,10 @@ public final class EnergyModesHelper {
targetEnergyMode = MODE_HIGH_ENERGY;
} else {
targetEnergyMode = getDefaultEnergyMode();
+ if (targetEnergyMode == null) {
+ // Fall back to lowest energy mode if default is not set or invalid
+ targetEnergyMode = getEnergyModes().get(0);
+ }
}
}
diff --git a/Settings/src/com/android/tv/settings/device/eco/EnergyModesService.java b/Settings/src/com/android/tv/settings/device/eco/EnergyModesService.java
deleted file mode 100644
index 7f089a51a..000000000
--- a/Settings/src/com/android/tv/settings/device/eco/EnergyModesService.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2023 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.tv.settings.device.eco;
-
-import static android.Manifest.permission.MANAGE_LOW_POWER_STANDBY;
-
-import android.annotation.EnforcePermission;
-import android.app.Service;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.drawable.Icon;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.IBinder;
-
-import com.android.tv.settings.device.eco.EnergyModesHelper.EnergyMode;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Service that provides methods to query and set Energy Modes.
- */
-public class EnergyModesService extends Service {
-
- private BinderService mService;
-
- @Override
- public void onCreate() {
- super.onCreate();
- mService = new BinderService(getApplication());
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- return mService;
- }
-
- private class BinderService extends IEnergyModesService.Stub {
- private final Context mContext;
- private final EnergyModesHelper mHelper;
-
- BinderService(Context context) {
- mContext = context;
- mHelper = new EnergyModesHelper(context);
- }
-
- @Override
- public List<Bundle> getModes() {
- final long ident = Binder.clearCallingIdentity();
- try {
- final List<Bundle> result = new ArrayList<>();
- final List<EnergyMode> energyModes = mHelper.getEnergyModes();
- final EnergyMode currentMode = mHelper.updateEnergyMode();
-
- for (EnergyMode mode : energyModes) {
- result.add(convertToBundle(mode, mode == currentMode));
- }
-
- return result;
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- private Bundle convertToBundle(EnergyMode mode, boolean selected) {
- Bundle bundle = new Bundle();
-
- bundle.putBoolean(KEY_SELECTED, selected);
- bundle.putString(KEY_IDENTIFIER, getString(mode.identifierRes));
- bundle.putParcelable(KEY_ICON, Icon.createWithResource(mContext, mode.iconRes));
- bundle.putInt(KEY_COLOR, getColor(mode.colorRes));
- bundle.putString(KEY_TITLE, getString(mode.titleRes));
- bundle.putString(KEY_SUBTITLE, getString(mode.subtitleRes));
- bundle.putString(KEY_DESCRIPTION, getString(mode.infoTextRes));
- bundle.putString(KEY_SHORT_DESCRIPTION, getString(mode.infoTextRes));
- bundle.putStringArray(KEY_FEATURES_LIST,
- getResources().getStringArray(mode.featuresRes));
- bundle.putStringArray(KEY_FEATURES,
- mHelper.getAllowedFeatures(mode).toArray(new String[0]));
-
- return bundle;
- }
-
- @EnforcePermission(MANAGE_LOW_POWER_STANDBY)
- @Override
- public void setMode(String identifier) {
- super.setMode_enforcePermission();
-
- final long ident = Binder.clearCallingIdentity();
- try {
- final EnergyMode mode = mHelper.getEnergyMode(identifier);
- if (mode == null) {
- throw new IllegalArgumentException("Unknown energy mode: " + identifier);
- }
- mHelper.setEnergyMode(mode);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- @Override
- public String getDefaultMode() {
- final long ident = Binder.clearCallingIdentity();
- try {
- final EnergyMode mode = mHelper.getDefaultEnergyMode();
- if (mode == null) {
- return null;
- }
- return getString(mode.identifierRes);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
- }
-}
diff --git a/Settings/src/com/android/tv/settings/device/eco/EnergyModesStatsLogJobService.java b/Settings/src/com/android/tv/settings/device/eco/EnergyModesStatsLogJobService.java
new file mode 100644
index 000000000..f3c416381
--- /dev/null
+++ b/Settings/src/com/android/tv/settings/device/eco/EnergyModesStatsLogJobService.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2023 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.tv.settings.device.eco;
+
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.PowerManager.LowPowerStandbyPolicy;
+import android.util.ArraySet;
+import android.util.Log;
+
+import com.android.settingslib.utils.ThreadUtils;
+import com.android.tv.settings.R;
+import com.android.tv.settings.device.eco.EnergyModesHelper.EnergyMode;
+import com.android.tv.twopanelsettings.slices.TvSettingsStatsLog;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * JobService to log available energy mode policies.
+ */
+public class EnergyModesStatsLogJobService extends JobService {
+ private static final String TAG = "EnergyModesStatsLogJobService";
+ private static final long WRITE_STATS_FREQUENCY_MS = TimeUnit.DAYS.toMillis(6);
+
+ /** Schedule a periodic job to log available energy mode policies. */
+ public static void scheduleEnergyModesStatsLog(Context context) {
+ final EnergyModesHelper energyModesHelper = new EnergyModesHelper(context);
+ if (!energyModesHelper.areEnergyModesAvailable()) {
+ return;
+ }
+
+ final JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
+ final ComponentName component =
+ new ComponentName(context, EnergyModesStatsLogJobService.class);
+ final JobInfo job =
+ new JobInfo.Builder(R.integer.job_energy_modes_stats_log, component)
+ .setPeriodic(WRITE_STATS_FREQUENCY_MS)
+ .setRequiresDeviceIdle(true)
+ .setPersisted(true)
+ .build();
+ final JobInfo pending = jobScheduler.getPendingJob(R.integer.job_energy_modes_stats_log);
+
+ // Don't schedule it if it already exists, to make sure it runs periodically even after
+ // reboot
+ if (pending == null && jobScheduler.schedule(job) != JobScheduler.RESULT_SUCCESS) {
+ Log.i(TAG, "Energy Modes stats log job service schedule failed.");
+ }
+ }
+
+ @Override
+ public boolean onStartJob(JobParameters params) {
+ ThreadUtils.postOnBackgroundThread(() -> {
+ writePoliciesStatsLog(getApplicationContext());
+ jobFinished(params, false /* wantsReschedule */);
+ });
+
+ return true;
+ }
+
+ @Override
+ public boolean onStopJob(JobParameters jobParameters) {
+ return false;
+ }
+
+ /** Writes available energy mode policies to stats log */
+ public static void writePoliciesStatsLog(Context context) {
+ final EnergyModesHelper energyModesHelper = new EnergyModesHelper(context);
+ final EnergyMode current = energyModesHelper.updateEnergyMode();
+ final List<EnergyMode> energyModes = energyModesHelper.getEnergyModes();
+
+ for (EnergyMode energyMode : energyModes) {
+ final LowPowerStandbyPolicy policy = energyModesHelper.getPolicy(energyMode);
+ TvSettingsStatsLog.write(
+ TvSettingsStatsLog.TV_LOW_POWER_STANDBY_POLICY,
+ policy.getIdentifier(),
+ getExemptPackageUids(context, policy),
+ policy.getAllowedReasons(),
+ policy.getAllowedFeatures().toArray(new String[0]),
+ energyMode == current
+ );
+ }
+ }
+
+ private static int[] getExemptPackageUids(Context context, LowPowerStandbyPolicy policy) {
+ final PackageManager packageManager = context.getPackageManager();
+ final ArraySet<Integer> exemptUids = new ArraySet<>();
+ for (String exemptPackage : policy.getExemptPackages()) {
+ try {
+ int uid = packageManager.getPackageUid(exemptPackage, PackageManager.MATCH_ALL);
+ exemptUids.add(uid);
+ } catch (PackageManager.NameNotFoundException e) {
+ }
+ }
+
+ final int[] exemptUidsArray = new int[exemptUids.size()];
+ int i = 0;
+ for (Integer uid : exemptUids) {
+ exemptUidsArray[i++] = uid;
+ }
+
+ Arrays.sort(exemptUidsArray);
+ return exemptUidsArray;
+ }
+}
diff --git a/Settings/src/com/android/tv/settings/device/eco/IEnergyModesService.aidl b/Settings/src/com/android/tv/settings/device/eco/IEnergyModesService.aidl
deleted file mode 100644
index 6f5c9269b..000000000
--- a/Settings/src/com/android/tv/settings/device/eco/IEnergyModesService.aidl
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2023 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.tv.settings.device.eco;
-
-import android.os.Bundle;
-
-/** {@hide} */
-interface IEnergyModesService {
- /** Key for a boolean representing whether the energy mode is currently selected. */
- const String KEY_SELECTED = "selected";
-
- /** Key for a String representing the identifier for an energy mode. */
- const String KEY_IDENTIFIER = "identifier";
-
- /** Key for an Icon representing the icon of an energy mode. */
- const String KEY_ICON = "icon";
-
- /** Key for an int representing the color of an energy mode (in ARGB). */
- const String KEY_COLOR = "color";
-
- /** Key for a String representing the title of an energy mode. */
- const String KEY_TITLE = "title";
-
- /** Key for a String representing the subtitle of an energy mode. */
- const String KEY_SUBTITLE = "subtitle";
-
- /** Key for a String representing the description of an energy mode. */
- const String KEY_DESCRIPTION = "description";
-
- /** Key for a String representing a short description of an energy mode. */
- const String KEY_SHORT_DESCRIPTION = "short_description";
-
- /** Key for a String array representing the (human-friendly) features of an energy mode. */
- const String KEY_FEATURES_LIST = "features_list";
-
- /** Key for a String array representing the features of an energy mode. */
- const String KEY_FEATURES = "features";
-
- /** Returns the list of available energy modes */
- List<Bundle> getModes();
-
- /** Sets the selected energy mode by the given identifier */
- @EnforcePermission("MANAGE_LOW_POWER_STANDBY")
- void setMode(String identifier);
-
- /** Returns the identifier of the default energy mode */
- String getDefaultMode();
-}
diff --git a/Settings/src/com/android/tv/settings/util/ResolutionSelectionUtils.java b/Settings/src/com/android/tv/settings/util/ResolutionSelectionUtils.java
index 3c2069aa9..72150403e 100644
--- a/Settings/src/com/android/tv/settings/util/ResolutionSelectionUtils.java
+++ b/Settings/src/com/android/tv/settings/util/ResolutionSelectionUtils.java
@@ -16,25 +16,35 @@
package com.android.tv.settings.util;
+import static java.math.RoundingMode.HALF_UP;
+
import android.content.Context;
+import android.icu.number.LocalizedNumberFormatter;
+import android.icu.number.NumberFormatter;
import android.view.Display;
import com.android.tv.settings.R;
+import java.util.Locale;
+
/** This utility class for Resolution Setting **/
public class ResolutionSelectionUtils {
/**
- * Returns the refresh rate converted to a string. If the refresh rate has only 0s after the
- * floating point, they are removed. The unit "Hz" is added to end of refresh rate.
+ * Returns the refresh rate converted to a string in the local language. If the refresh rate has
+ * only 0s after the floating point, they are removed.
+ * The unit "Hz" is added to end of refresh rate.
*/
public static String getRefreshRateString(float refreshRate) {
- float roundedRefreshRate = Math.round(refreshRate * 100.0f) / 100.0f;
+ LocalizedNumberFormatter localizedNumberFormatter = NumberFormatter.with().roundingMode(
+ HALF_UP).locale(Locale.getDefault());
+ double roundedRefreshRate = Math.round(refreshRate * 100.0f) / 100.0f;
if (roundedRefreshRate % 1 == 0) {
- return Integer.toString((int) roundedRefreshRate);
+ return localizedNumberFormatter.format(roundedRefreshRate).toString();
} else {
- return Float.toString(roundedRefreshRate);
+ return String.format(Locale.getDefault(), "%.2f",
+ localizedNumberFormatter.format(roundedRefreshRate).toBigDecimal());
}
}
@@ -64,4 +74,15 @@ public class ResolutionSelectionUtils {
ResolutionSelectionUtils.getRefreshRateString(mode.getRefreshRate()));
return modeString;
}
+
+ /**
+ * Returns the resolution mode converted to a string in the local language.
+ * Format: width + " x " + height
+ */
+ public static String getResolutionSummary(int physicalWidth, int physicalHeight) {
+ LocalizedNumberFormatter localizedNumberFormatter = NumberFormatter.with().locale(
+ Locale.getDefault());
+ return localizedNumberFormatter.format(physicalWidth).toString() + " x "
+ + localizedNumberFormatter.format(physicalHeight).toString();
+ }
}
diff --git a/TwoPanelSettingsLib/Android.bp b/TwoPanelSettingsLib/Android.bp
index fa0056bc6..a944c5d30 100644
--- a/TwoPanelSettingsLib/Android.bp
+++ b/TwoPanelSettingsLib/Android.bp
@@ -47,8 +47,6 @@ android_library {
"androidx.cardview_cardview",
"statslog-tvsettings",
],
-
- min_sdk_version: "30",
}
// For the test package.