Merge "Import translations. DO NOT MERGE" into rvc-dev
diff --git a/api/test-current.txt b/api/test-current.txt
index d080d3d..6cdcc32 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -580,6 +580,7 @@
method public java.util.List<java.lang.String> getOwnerInstalledCaCerts(@NonNull android.os.UserHandle);
method public boolean isCurrentInputMethodSetByOwner();
method public boolean isDeviceManaged();
+ method public boolean isFactoryResetProtectionPolicySupported();
field public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_ALLOWED";
field public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_DISALLOWED";
field public static final String ACTION_DATA_SHARING_RESTRICTION_APPLIED = "android.app.action.DATA_SHARING_RESTRICTION_APPLIED";
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 41e2dc0..4b05045 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -10953,6 +10953,22 @@
}
/**
+ * Returns whether factory reset protection policy is supported on the device.
+ *
+ * @return {@code true} if the device support factory reset protection policy.
+ *
+ * @hide
+ */
+ @TestApi
+ public boolean isFactoryResetProtectionPolicySupported() {
+ try {
+ return mService.isFactoryResetProtectionPolicySupported();
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Called by the device owner or profile owner to clear application user data of a given
* package. The behaviour of this is equivalent to the target application calling
* {@link android.app.ActivityManager#clearApplicationUserData()}.
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index d10153c..9c6a274 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -108,6 +108,7 @@
void setFactoryResetProtectionPolicy(in ComponentName who, in FactoryResetProtectionPolicy policy);
FactoryResetProtectionPolicy getFactoryResetProtectionPolicy(in ComponentName who);
+ boolean isFactoryResetProtectionPolicySupported();
ComponentName setGlobalProxy(in ComponentName admin, String proxySpec, String exclusionList);
ComponentName getGlobalProxyAdmin(int userHandle);
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index 65a8e15..6bc962b 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -650,6 +650,68 @@
}
/**
+ * Controls whether volume control commands via HDMI CEC are enabled.
+ *
+ * <p>When disabled:
+ * <ul>
+ * <li>the device will not send any HDMI CEC audio messages
+ * <li>received HDMI CEC audio messages are responded to with {@code <Feature Abort>}
+ * </ul>
+ *
+ * <p>Effects on different device types:
+ * <table>
+ * <tr><th>HDMI CEC device type</th><th>enabled</th><th>disabled</th></tr>
+ * <tr>
+ * <td>TV (type: 0)</td>
+ * <td>Per CEC specification.</td>
+ * <td>TV changes system volume. TV no longer reacts to incoming volume changes via
+ * {@code <User Control Pressed>}. TV no longer handles {@code <Report Audio Status>}
+ * .</td>
+ * </tr>
+ * <tr>
+ * <td>Playback device (type: 4)</td>
+ * <td>Device sends volume commands to TV/Audio system via {@code <User Control
+ * Pressed>}</td><td>Device does not send volume commands via {@code <User Control
+ * Pressed>}.</td>
+ * </tr>
+ * <tr>
+ * <td>Audio device (type: 5)</td>
+ * <td>Full "System Audio Control" capabilities.</td>
+ * <td>Audio device no longer reacts to incoming {@code <User Control Pressed>}
+ * volume commands. Audio device no longer reports volume changes via {@code <Report
+ * Audio Status>}.</td>
+ * </tr>
+ * </table>
+ *
+ * <p> Due to the resulting behavior, usage on TV and Audio devices is discouraged.
+ *
+ * @param isHdmiCecVolumeControlEnabled target state of HDMI CEC volume control.
+ * @see Settings.Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.HDMI_CEC)
+ public void setHdmiCecVolumeControlEnabled(boolean isHdmiCecVolumeControlEnabled) {
+ try {
+ mService.setHdmiCecVolumeControlEnabled(isHdmiCecVolumeControlEnabled);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns whether volume changes via HDMI CEC are enabled.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.HDMI_CEC)
+ public boolean isHdmiCecVolumeControlEnabled() {
+ try {
+ return mService.isHdmiCecVolumeControlEnabled();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Gets whether the system is in system audio mode.
*
* @hide
diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
index a8fed2b..3582a92 100644
--- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
@@ -80,6 +80,8 @@
void sendMhlVendorCommand(int portId, int offset, int length, in byte[] data);
void addHdmiMhlVendorCommandListener(IHdmiMhlVendorCommandListener listener);
void setStandbyMode(boolean isStandbyModeOn);
+ void setHdmiCecVolumeControlEnabled(boolean isHdmiCecVolumeControlEnabled);
+ boolean isHdmiCecVolumeControlEnabled();
void reportAudioStatus(int deviceType, int volume, int maxVolume, boolean isMute);
void setSystemAudioModeOnForAudioOnlySource();
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ac1998a..fbd6cba 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9614,6 +9614,43 @@
*/
public static final String HDMI_CONTROL_ENABLED = "hdmi_control_enabled";
+ /**
+ * Controls whether volume control commands via HDMI CEC are enabled. (0 = false, 1 =
+ * true).
+ *
+ * <p>Effects on different device types:
+ * <table>
+ * <tr><th>HDMI CEC device type</th><th>0: disabled</th><th>1: enabled</th></tr>
+ * <tr>
+ * <td>TV (type: 0)</td>
+ * <td>Per CEC specification.</td>
+ * <td>TV changes system volume. TV no longer reacts to incoming volume changes
+ * via {@code <User Control Pressed>}. TV no longer handles {@code <Report Audio
+ * Status>}.</td>
+ * </tr>
+ * <tr>
+ * <td>Playback device (type: 4)</td>
+ * <td>Device sends volume commands to TV/Audio system via {@code <User Control
+ * Pressed>}</td>
+ * <td>Device does not send volume commands via {@code <User Control Pressed>}.</td>
+ * </tr>
+ * <tr>
+ * <td>Audio device (type: 5)</td>
+ * <td>Full "System Audio Control" capabilities.</td>
+ * <td>Audio device no longer reacts to incoming {@code <User Control Pressed>}
+ * volume commands. Audio device no longer reports volume changes via {@code
+ * <Report Audio Status>}.</td>
+ * </tr>
+ * </table>
+ *
+ * <p> Due to the resulting behavior, usage on TV and Audio devices is discouraged.
+ *
+ * @hide
+ * @see android.hardware.hdmi.HdmiControlManager#setHdmiCecVolumeControlEnabled(boolean)
+ */
+ public static final String HDMI_CONTROL_VOLUME_CONTROL_ENABLED =
+ "hdmi_control_volume_control_enabled";
+
/**
* Whether HDMI System Audio Control feature is enabled. If enabled, TV will try to turn on
* system audio mode if there's a connected CEC-enabled AV Receiver. Then audio stream will
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 2975d5e..28a18da 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -36,6 +36,7 @@
import android.os.IBinder;
import android.os.RemoteException;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.IResultReceiver;
import java.util.List;
@@ -69,7 +70,8 @@
public final class WindowManagerImpl implements WindowManager {
@UnsupportedAppUsage
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
- private final Context mContext;
+ @VisibleForTesting
+ public final Context mContext;
private final Window mParentWindow;
private IBinder mDefaultToken;
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 71dd665..3cf6109 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -645,11 +645,6 @@
@Override
public void setCurrentRootView(ViewRootImpl rootView) {
synchronized (mH) {
- if (mCurRootView != null) {
- // Reset the last served view and restart window focus state of the root view.
- mCurRootView.getImeFocusController().setServedView(null);
- mRestartOnNextWindowFocus = true;
- }
mCurRootView = rootView;
}
}
diff --git a/core/java/com/android/internal/policy/DecorContext.java b/core/java/com/android/internal/policy/DecorContext.java
index 99b4b5f..51b4119 100644
--- a/core/java/com/android/internal/policy/DecorContext.java
+++ b/core/java/com/android/internal/policy/DecorContext.java
@@ -22,8 +22,6 @@
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.view.ContextThemeWrapper;
-import android.view.WindowManager;
-import android.view.WindowManagerImpl;
import android.view.contentcapture.ContentCaptureManager;
import com.android.internal.annotations.VisibleForTesting;
@@ -31,8 +29,8 @@
import java.lang.ref.WeakReference;
/**
- * Context for decor views which can be seeded with pure application context and not depend on the
- * activity, but still provide some of the facilities that Activity has,
+ * Context for decor views which can be seeded with display context and not depend on the activity,
+ * but still provide some of the facilities that Activity has,
* e.g. themes, activity-based resources, etc.
*
* @hide
@@ -40,80 +38,93 @@
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public class DecorContext extends ContextThemeWrapper {
private PhoneWindow mPhoneWindow;
- private WindowManager mWindowManager;
- private Resources mActivityResources;
+ private Resources mResources;
private ContentCaptureManager mContentCaptureManager;
- private WeakReference<Context> mActivityContext;
+ private WeakReference<Context> mContext;
- // TODO(b/149928768): Non-activity context can be passed.
@VisibleForTesting
- public DecorContext(Context context, Context activityContext) {
- super(context.createDisplayContext(activityContext.getDisplayNoVerify()), null);
- mActivityContext = new WeakReference<>(activityContext);
- mActivityResources = activityContext.getResources();
+ public DecorContext(Context baseContext, PhoneWindow phoneWindow) {
+ super(null /* base */, null);
+ setPhoneWindow(phoneWindow);
+ final Context displayContext = baseContext.createDisplayContext(
+ // TODO(b/149790106): Non-activity context can be passed.
+ phoneWindow.getContext().getDisplayNoVerify());
+ attachBaseContext(displayContext);
}
void setPhoneWindow(PhoneWindow phoneWindow) {
mPhoneWindow = phoneWindow;
- mWindowManager = null;
+ final Context context = phoneWindow.getContext();
+ mContext = new WeakReference<>(context);
+ mResources = context.getResources();
}
@Override
public Object getSystemService(String name) {
if (Context.WINDOW_SERVICE.equals(name)) {
- if (mWindowManager == null) {
- WindowManagerImpl wm =
- (WindowManagerImpl) super.getSystemService(Context.WINDOW_SERVICE);
- mWindowManager = wm.createLocalWindowManager(mPhoneWindow);
- }
- return mWindowManager;
+ return mPhoneWindow.getWindowManager();
}
+ final Context context = mContext.get();
if (Context.CONTENT_CAPTURE_MANAGER_SERVICE.equals(name)) {
- if (mContentCaptureManager == null) {
- Context activityContext = mActivityContext.get();
- if (activityContext != null) {
- mContentCaptureManager = (ContentCaptureManager) activityContext
- .getSystemService(name);
- }
+ if (context != null && mContentCaptureManager == null) {
+ mContentCaptureManager = (ContentCaptureManager) context.getSystemService(name);
}
return mContentCaptureManager;
}
- return super.getSystemService(name);
+ // TODO(b/154191411): Try to revisit this issue in S.
+ // We use application to get DisplayManager here because ViewRootImpl holds reference of
+ // DisplayManager and implicitly holds reference of mContext, which makes activity cannot
+ // be GC'd even after destroyed if mContext is an activity object.
+ if (Context.DISPLAY_SERVICE.equals(name)) {
+ return super.getSystemService(name);
+ }
+ // LayoutInflater and WallpaperManagerService should also be obtained from visual context
+ // instead of base context.
+ return (context != null) ? context.getSystemService(name) : super.getSystemService(name);
}
@Override
public Resources getResources() {
- Context activityContext = mActivityContext.get();
+ Context context = mContext.get();
// Attempt to update the local cached Resources from the activity context. If the activity
// is no longer around, return the old cached values.
- if (activityContext != null) {
- mActivityResources = activityContext.getResources();
+ if (context != null) {
+ mResources = context.getResources();
}
- return mActivityResources;
+ return mResources;
}
@Override
public AssetManager getAssets() {
- return mActivityResources.getAssets();
+ return mResources.getAssets();
}
@Override
public AutofillOptions getAutofillOptions() {
- Context activityContext = mActivityContext.get();
- if (activityContext != null) {
- return activityContext.getAutofillOptions();
+ Context context = mContext.get();
+ if (context != null) {
+ return context.getAutofillOptions();
}
return null;
}
@Override
public ContentCaptureOptions getContentCaptureOptions() {
- Context activityContext = mActivityContext.get();
- if (activityContext != null) {
- return activityContext.getContentCaptureOptions();
+ Context context = mContext.get();
+ if (context != null) {
+ return context.getContentCaptureOptions();
}
return null;
}
+
+ @Override
+ public boolean isUiContext() {
+ Context context = mContext.get();
+ if (context != null) {
+ return context.isUiContext();
+ }
+ return false;
+ }
}
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 23ba653..aa75d40 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -2358,7 +2358,7 @@
if (applicationContext == null) {
context = getContext();
} else {
- context = new DecorContext(applicationContext, getContext());
+ context = new DecorContext(applicationContext, this);
if (mTheme != -1) {
context.setTheme(mTheme);
}
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index d06bc3b..dfd729e 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -724,7 +724,7 @@
</string-array>
<string-array name="emailAddressTypes">
<item msgid="7786349763648997741">"المنزل"</item>
- <item msgid="435564470865989199">"عمل"</item>
+ <item msgid="435564470865989199">"العمل"</item>
<item msgid="4199433197875490373">"آخر"</item>
<item msgid="3233938986670468328">"مخصص"</item>
</string-array>
@@ -778,7 +778,7 @@
<string name="phoneTypeMms" msgid="1799747455131365989">"رسالة وسائط متعددة"</string>
<string name="eventTypeCustom" msgid="3257367158986466481">"مخصص"</string>
<string name="eventTypeBirthday" msgid="7770026752793912283">"عيد ميلاد"</string>
- <string name="eventTypeAnniversary" msgid="4684702412407916888">"الذكرى السنوية"</string>
+ <string name="eventTypeAnniversary" msgid="4684702412407916888">"ذكرى سنوية"</string>
<string name="eventTypeOther" msgid="530671238533887997">"غير ذلك"</string>
<string name="emailTypeCustom" msgid="1809435350482181786">"مخصص"</string>
<string name="emailTypeHome" msgid="1597116303154775999">"المنزل"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 5c38284..569b284 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1806,7 +1806,7 @@
<item quantity="other">%1$d मिनट के लिए (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> तक)</item>
</plurals>
<plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="7725354244196466758">
- <item quantity="one">%1$d घंटों के लिए (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> तक)</item>
+ <item quantity="one">%1$d घंटे के लिए (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> तक)</item>
<item quantity="other">%1$d घंटों के लिए (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> तक)</item>
</plurals>
<plurals name="zen_mode_duration_hours_summary_short" formatted="false" msgid="588719069121765642">
@@ -1822,7 +1822,7 @@
<item quantity="other">%d मिनट के लिए</item>
</plurals>
<plurals name="zen_mode_duration_hours" formatted="false" msgid="525401855645490022">
- <item quantity="one">%d घंटों के लिए</item>
+ <item quantity="one">%d घंटे के लिए</item>
<item quantity="other">%d घंटों के लिए</item>
</plurals>
<plurals name="zen_mode_duration_hours_short" formatted="false" msgid="7644653189680911640">
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 1ba41b3..73c0c0c 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1403,8 +1403,8 @@
<string name="ime_action_default" msgid="8265027027659800121">"Կատարել"</string>
<string name="dial_number_using" msgid="6060769078933953531">"Հավաքել հեռախոսահամարը`\nօգտագործելով <xliff:g id="NUMBER">%s</xliff:g>-ը"</string>
<string name="create_contact_using" msgid="6200708808003692594">"Ստեղծել կոնտակտ`\nօգտագործելով <xliff:g id="NUMBER">%s</xliff:g>-ը"</string>
- <string name="grant_credentials_permission_message_header" msgid="5365733888842570481">"Հետևյալ մեկ կամ ավել հավելվածներ մուտքի թույլտվության հարցում են անում` այժմ և հետագայում ձեր հաշվին մուտք ունենալու համար:"</string>
- <string name="grant_credentials_permission_message_footer" msgid="1886710210516246461">"Ցանկանու՞մ եք թույլատրել այս հարցումը:"</string>
+ <string name="grant_credentials_permission_message_header" msgid="5365733888842570481">"Հետևյալ մեկ կամ մի քանի հավելվածներին թույլտվություն է անհրաժեշտ՝ այժմ և հետագայում ձեր հաշվի տվյալներն օգտագործելու համար։"</string>
+ <string name="grant_credentials_permission_message_footer" msgid="1886710210516246461">"Թույլատրե՞լ"</string>
<string name="grant_permissions_header_text" msgid="3420736827804657201">"Մուտքի հարցում"</string>
<string name="allow" msgid="6195617008611933762">"Թույլատրել"</string>
<string name="deny" msgid="6632259981847676572">"Մերժել"</string>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 0e40c98..9c93c3e 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4410,6 +4410,12 @@
shortcut enabled. [CHAR LIMIT=none] -->
<string name="accessibility_shortcut_off">Don’t turn on</string>
+ <!-- Text for a feature status that is enabled. [CHAR LIMIT=10] -->
+ <string name="accessibility_shortcut_menu_item_status_on">ON</string>
+
+ <!-- Text for a feature status that is disabled. [CHAR LIMIT=10] -->
+ <string name="accessibility_shortcut_menu_item_status_off">OFF</string>
+
<!-- Title for a warning about security implications of enabling an accessibility
service. [CHAR LIMIT=NONE] -->
<string name="accessibility_enable_service_title">Allow
diff --git a/core/tests/coretests/src/com/android/internal/policy/DecorContextTest.java b/core/tests/coretests/src/com/android/internal/policy/DecorContextTest.java
index 3e40466..02870a5 100644
--- a/core/tests/coretests/src/com/android/internal/policy/DecorContextTest.java
+++ b/core/tests/coretests/src/com/android/internal/policy/DecorContextTest.java
@@ -19,20 +19,26 @@
import static android.view.Display.DEFAULT_DISPLAY;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import android.app.Activity;
+import android.app.EmptyActivity;
import android.content.Context;
import android.hardware.display.DisplayManagerGlobal;
import android.platform.test.annotations.Presubmit;
import android.view.Display;
import android.view.DisplayAdjustments;
import android.view.DisplayInfo;
+import android.view.WindowManager;
+import android.view.WindowManagerImpl;
-import androidx.test.InstrumentationRegistry;
+import androidx.test.core.app.ApplicationProvider;
import androidx.test.filters.SmallTest;
+import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;
-
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -46,17 +52,22 @@
private Context mContext;
private static final int EXTERNAL_DISPLAY = DEFAULT_DISPLAY + 1;
+ @Rule
+ public ActivityTestRule<EmptyActivity> mActivityRule =
+ new ActivityTestRule<>(EmptyActivity.class);
+
@Before
- public void setUp() throws Exception {
- mContext = InstrumentationRegistry.getContext();
+ public void setUp() {
+ mContext = ApplicationProvider.getApplicationContext();
}
@Test
public void testDecorContextWithDefaultDisplay() {
Display defaultDisplay = new Display(DisplayManagerGlobal.getInstance(), DEFAULT_DISPLAY,
new DisplayInfo(), DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
- DecorContext context = new DecorContext(mContext.getApplicationContext(),
- mContext.createDisplayContext(defaultDisplay));
+ final Context defaultDisplayContext = mContext.createDisplayContext(defaultDisplay);
+ final PhoneWindow window = new PhoneWindow(defaultDisplayContext);
+ DecorContext context = new DecorContext(mContext.getApplicationContext(), window);
assertDecorContextDisplay(DEFAULT_DISPLAY, context);
}
@@ -65,8 +76,9 @@
public void testDecorContextWithExternalDisplay() {
Display display = new Display(DisplayManagerGlobal.getInstance(), EXTERNAL_DISPLAY,
new DisplayInfo(), DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
- DecorContext context = new DecorContext(mContext.getApplicationContext(),
- mContext.createDisplayContext(display));
+ final Context defaultDisplayContext = mContext.createDisplayContext(display);
+ final PhoneWindow window = new PhoneWindow(defaultDisplayContext);
+ DecorContext context = new DecorContext(mContext.getApplicationContext(), window);
assertDecorContextDisplay(EXTERNAL_DISPLAY, context);
}
@@ -76,4 +88,29 @@
Display associatedDisplay = decorContext.getDisplay();
assertEquals(expectedDisplayId, associatedDisplay.getDisplayId());
}
+
+ @Test
+ public void testGetWindowManagerFromVisualDecorContext() throws Throwable {
+ mActivityRule.runOnUiThread(() -> {
+ Activity activity = mActivityRule.getActivity();
+ final DecorContext decorContext = new DecorContext(mContext.getApplicationContext(),
+ (PhoneWindow) activity.getWindow());
+ WindowManagerImpl actualWm = (WindowManagerImpl)
+ decorContext.getSystemService(WindowManager.class);
+ WindowManagerImpl expectedWm = (WindowManagerImpl)
+ activity.getSystemService(WindowManager.class);
+ // Verify that window manager is from activity not application context.
+ assertEquals(expectedWm.mContext, actualWm.mContext);
+ });
+ }
+
+ @Test
+ public void testIsUiContextFromVisualDecorContext() throws Throwable {
+ mActivityRule.runOnUiThread(() -> {
+ Activity activity = mActivityRule.getActivity();
+ final DecorContext decorContext = new DecorContext(mContext.getApplicationContext(),
+ (PhoneWindow) activity.getWindow());
+ assertTrue(decorContext.isUiContext());
+ });
+ }
}
diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
index 2141b81..7cd2f3b 100644
--- a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
+++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
@@ -354,6 +354,15 @@
@Override
public void askRemoteDeviceToBecomeActiveSource(int physicalAddress) {
}
+
+ @Override
+ public void setHdmiCecVolumeControlEnabled(boolean isHdmiCecVolumeControlEnabled) {
+ }
+
+ @Override
+ public boolean isHdmiCecVolumeControlEnabled() {
+ return true;
+ }
}
}
diff --git a/packages/DynamicSystemInstallationService/res/values/strings.xml b/packages/DynamicSystemInstallationService/res/values/strings.xml
index e124be6..719fc73 100644
--- a/packages/DynamicSystemInstallationService/res/values/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values/strings.xml
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
- <!-- application name [CHAR LIMIT=32] -->
+ <!-- application name [DO NOT TRANSLATE] -->
<string name="app_name">Dynamic System Updates</string>
- <!-- notification channel name [CHAR LIMIT=32] -->
+ <!-- notification channel name [DO NOT TRANSLATE] -->
<string name="notification_channel_name">Dynamic System Updates</string>
- <!-- password page title [CHAR LIMIT=32] -->
+ <!-- password page title [DO NOT TRANSLATE] -->
<string name="keyguard_title">Dynamic System Updates</string>
<!-- password page description [CHAR LIMIT=128] -->
@@ -23,19 +23,19 @@
<!-- Displayed on notification: We are running in Dynamic System [CHAR LIMIT=128] -->
<string name="notification_dynsystem_in_use">Currently running a dynamic system. Restart to use the original Android version.</string>
- <!-- Action on notification: Cancel installation [CHAR LIMIT=16] -->
+ <!-- Action on notification: Cancel installation [CHAR LIMIT=24] -->
<string name="notification_action_cancel">Cancel</string>
- <!-- Action on notification: Discard installation [CHAR LIMIT=16] -->
+ <!-- Action on notification: Discard installation [CHAR LIMIT=24] -->
<string name="notification_action_discard">Discard</string>
- <!-- Action on notification: Restart to Dynamic System [CHAR LIMIT=16] -->
+ <!-- Action on notification: Restart to Dynamic System [CHAR LIMIT=24] -->
<string name="notification_action_reboot_to_dynsystem">Restart</string>
- <!-- Action on notification: Restart to original Android version [CHAR LIMIT=16] -->
+ <!-- Action on notification: Restart to original Android version [CHAR LIMIT=24] -->
<string name="notification_action_reboot_to_origin">Restart</string>
- <!-- Toast when installed Dynamic System is discarded [CHAR LIMIT=64] -->
+ <!-- Toast when installed Dynamic System is discarded [CHAR LIMIT=128] -->
<string name="toast_dynsystem_discarded">Discarded dynamic system</string>
- <!-- Toast when we fail to launch into Dynamic System [CHAR LIMIT=64] -->
+ <!-- Toast when we fail to launch into Dynamic System [CHAR LIMIT=128] -->
<string name="toast_failed_to_reboot_to_dynsystem">Can\u2019t restart or load dynamic system</string>
<!-- URL of Dynamic System Key Revocation List [DO NOT TRANSLATE] -->
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 03f6df0..0dd7fb8 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -296,6 +296,7 @@
Settings.Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED,
Settings.Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED,
Settings.Global.HDMI_CONTROL_ENABLED,
+ Settings.Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED,
Settings.Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED,
Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED,
Settings.Global.HIDDEN_API_POLICY,
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 0c7aef9..03af224 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -416,7 +416,7 @@
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Ноќно светло"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Вклуч. на зајдисонце"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"До изгрејсонце"</string>
- <string name="quick_settings_night_secondary_label_on_at" msgid="3584738542293528235">"Ќе се вклучи во <xliff:g id="TIME">%s</xliff:g>"</string>
+ <string name="quick_settings_night_secondary_label_on_at" msgid="3584738542293528235">"Вклучување: <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_secondary_label_until" msgid="1883981263191927372">"До <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_ui_mode_night_label" msgid="1398928270610780470">"Темна тема"</string>
<string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"Штедач на батерија"</string>
diff --git a/packages/Tethering/res/values-mcc310-mnc004-ne/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-ne/strings.xml
index 2a73300..12d6c2c 100644
--- a/packages/Tethering/res/values-mcc310-mnc004-ne/strings.xml
+++ b/packages/Tethering/res/values-mcc310-mnc004-ne/strings.xml
@@ -16,13 +16,9 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for no_upstream_notification_title (5030042590486713460) -->
- <skip />
- <!-- no translation found for no_upstream_notification_message (3843613362272973447) -->
- <skip />
- <!-- no translation found for no_upstream_notification_disable_button (6385491461813507624) -->
- <skip />
- <!-- no translation found for upstream_roaming_notification_title (3015912166812283303) -->
- <skip />
+ <string name="no_upstream_notification_title" msgid="5030042590486713460">"Tethering has no internet"</string>
+ <string name="no_upstream_notification_message" msgid="3843613362272973447">"यन्त्रहरू कनेक्ट गर्न सकिएन"</string>
+ <string name="no_upstream_notification_disable_button" msgid="6385491461813507624">"टेदरिङ निष्क्रिय पार्नुहोस्"</string>
+ <string name="upstream_roaming_notification_title" msgid="3015912166812283303">"हटस्पट वा टेदरिङ सक्रिय छ"</string>
<string name="upstream_roaming_notification_message" msgid="6724434706748439902">"रोमिङ सेवा प्रयोग गर्दा अतिरिक्त शुल्क लाग्न सक्छ"</string>
</resources>
diff --git a/packages/Tethering/res/values-mcc310-mnc004-ta/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-ta/strings.xml
index ea04821..f4b15aa 100644
--- a/packages/Tethering/res/values-mcc310-mnc004-ta/strings.xml
+++ b/packages/Tethering/res/values-mcc310-mnc004-ta/strings.xml
@@ -16,13 +16,9 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for no_upstream_notification_title (5030042590486713460) -->
- <skip />
- <!-- no translation found for no_upstream_notification_message (3843613362272973447) -->
- <skip />
- <!-- no translation found for no_upstream_notification_disable_button (6385491461813507624) -->
- <skip />
- <!-- no translation found for upstream_roaming_notification_title (3015912166812283303) -->
- <skip />
+ <string name="no_upstream_notification_title" msgid="5030042590486713460">"இணைப்பு முறைக்கு இணைய இணைப்பு இல்லை"</string>
+ <string name="no_upstream_notification_message" msgid="3843613362272973447">"சாதனங்களால் இணைய முடியவில்லை"</string>
+ <string name="no_upstream_notification_disable_button" msgid="6385491461813507624">"இணைப்பு முறையை ஆஃப் செய்"</string>
+ <string name="upstream_roaming_notification_title" msgid="3015912166812283303">"ஹாட்ஸ்பாட் அல்லது இணைப்பு முறை ஆன் செய்யப்பட்டுள்ளது"</string>
<string name="upstream_roaming_notification_message" msgid="6724434706748439902">"ரோமிங்கின்போது கூடுதல் கட்டணங்கள் விதிக்கப்படக்கூடும்"</string>
</resources>
diff --git a/packages/Tethering/res/values-mcc311-mnc480-ne/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-ne/strings.xml
index 617c50d..0a0aa21 100644
--- a/packages/Tethering/res/values-mcc311-mnc480-ne/strings.xml
+++ b/packages/Tethering/res/values-mcc311-mnc480-ne/strings.xml
@@ -16,13 +16,9 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for no_upstream_notification_title (611650570559011140) -->
- <skip />
- <!-- no translation found for no_upstream_notification_message (6508394877641864863) -->
- <skip />
- <!-- no translation found for no_upstream_notification_disable_button (7609346639290990508) -->
- <skip />
- <!-- no translation found for upstream_roaming_notification_title (6032901176124830787) -->
- <skip />
+ <string name="no_upstream_notification_title" msgid="611650570559011140">"Tethering has no internet"</string>
+ <string name="no_upstream_notification_message" msgid="6508394877641864863">"यन्त्रहरू कनेक्ट गर्न सकिएन"</string>
+ <string name="no_upstream_notification_disable_button" msgid="7609346639290990508">"टेदरिङ निष्क्रिय पार्नुहोस्"</string>
+ <string name="upstream_roaming_notification_title" msgid="6032901176124830787">"हटस्पट वा टेदरिङ सक्रिय छ"</string>
<string name="upstream_roaming_notification_message" msgid="7599056263326217523">"रोमिङ सेवा प्रयोग गर्दा अतिरिक्त शुल्क लाग्न सक्छ"</string>
</resources>
diff --git a/packages/Tethering/res/values-mcc311-mnc480-ta/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-ta/strings.xml
index 0e43759..2ea2467 100644
--- a/packages/Tethering/res/values-mcc311-mnc480-ta/strings.xml
+++ b/packages/Tethering/res/values-mcc311-mnc480-ta/strings.xml
@@ -16,13 +16,9 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for no_upstream_notification_title (611650570559011140) -->
- <skip />
- <!-- no translation found for no_upstream_notification_message (6508394877641864863) -->
- <skip />
- <!-- no translation found for no_upstream_notification_disable_button (7609346639290990508) -->
- <skip />
- <!-- no translation found for upstream_roaming_notification_title (6032901176124830787) -->
- <skip />
+ <string name="no_upstream_notification_title" msgid="611650570559011140">"இணைப்பு முறைக்கு இணைய இணைப்பு இல்லை"</string>
+ <string name="no_upstream_notification_message" msgid="6508394877641864863">"சாதனங்களால் இணைய முடியவில்லை"</string>
+ <string name="no_upstream_notification_disable_button" msgid="7609346639290990508">"இணைப்பு முறையை ஆஃப் செய்"</string>
+ <string name="upstream_roaming_notification_title" msgid="6032901176124830787">"ஹாட்ஸ்பாட் அல்லது இணைப்பு முறை ஆன் செய்யப்பட்டுள்ளது"</string>
<string name="upstream_roaming_notification_message" msgid="7599056263326217523">"ரோமிங்கின்போது கூடுதல் கட்டணங்கள் விதிக்கப்படக்கூடும்"</string>
</resources>
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java b/packages/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java
index 55344fc..c4a1078 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java
@@ -41,6 +41,7 @@
import java.net.SocketAddress;
import java.net.SocketException;
import java.util.ArrayList;
+import java.util.NoSuchElementException;
/**
@@ -143,7 +144,7 @@
IOffloadConfig offloadConfig;
try {
offloadConfig = IOffloadConfig.getService(true /*retry*/);
- } catch (RemoteException e) {
+ } catch (RemoteException | NoSuchElementException e) {
mLog.e("getIOffloadConfig error " + e);
return false;
}
@@ -239,8 +240,8 @@
if (mOffloadControl == null) {
try {
- mOffloadControl = IOffloadControl.getService();
- } catch (RemoteException e) {
+ mOffloadControl = IOffloadControl.getService(true /*retry*/);
+ } catch (RemoteException | NoSuchElementException e) {
mLog.e("tethering offload control not supported: " + e);
return false;
}
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 992e984..dc35c77 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -318,6 +318,9 @@
private static final String SERIAL_ID_FILE = "serial_id";
+ private static final String SKIP_USER_FACING_DATA = "backup_skip_user_facing_data";
+ private static final String WALLPAPER_PACKAGE = "com.android.wallpaperbackup";
+
private final @UserIdInt int mUserId;
private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
private final TransportManager mTransportManager;
@@ -3553,6 +3556,40 @@
}
}
+ /**
+ * We want to skip backup/restore of certain packages if 'backup_skip_user_facing_data' is
+ * set to true in secure settings. See b/153940088 for details.
+ *
+ * TODO(b/154822946): Remove this logic in the next release.
+ */
+ public List<PackageInfo> filterUserFacingPackages(List<PackageInfo> packages) {
+ if (!shouldSkipUserFacingData()) {
+ return packages;
+ }
+
+ List<PackageInfo> filteredPackages = new ArrayList<>(packages.size());
+ for (PackageInfo packageInfo : packages) {
+ if (!shouldSkipPackage(packageInfo.packageName)) {
+ filteredPackages.add(packageInfo);
+ } else {
+ Slog.i(TAG, "Will skip backup/restore for " + packageInfo.packageName);
+ }
+ }
+
+ return filteredPackages;
+ }
+
+ @VisibleForTesting
+ public boolean shouldSkipUserFacingData() {
+ return Settings.Secure.getInt(mContext.getContentResolver(), SKIP_USER_FACING_DATA,
+ /* def */ 0) != 0;
+ }
+
+ @VisibleForTesting
+ public boolean shouldSkipPackage(String packageName) {
+ return WALLPAPER_PACKAGE.equals(packageName);
+ }
+
private void updateStateForTransport(String newTransportName) {
// Publish the name change
Settings.Secure.putStringForUser(mContext.getContentResolver(),
diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
index f7f0138..738dd9bf 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
@@ -61,6 +61,7 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.List;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -131,7 +132,7 @@
private UserBackupManagerService mUserBackupManagerService;
private final Object mCancelLock = new Object();
- ArrayList<PackageInfo> mPackages;
+ List<PackageInfo> mPackages;
PackageInfo mCurrentPackage;
boolean mUpdateSchedule;
CountDownLatch mLatch;
@@ -249,6 +250,8 @@
null);
}
}
+
+ mPackages = backupManagerService.filterUserFacingPackages(mPackages);
}
private void registerTask() {
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index e434be6..12113fe 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -270,6 +270,8 @@
}
}
+ mAcceptSet = backupManagerService.filterUserFacingPackages(mAcceptSet);
+
if (MORE_DEBUG) {
Slog.v(TAG, "Restore; accept set size is " + mAcceptSet.size());
for (PackageInfo info : mAcceptSet) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index a358707..3ff6ec1 100755
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -32,6 +32,7 @@
import android.view.KeyEvent;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.hdmi.Constants.LocalActivePort;
import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
@@ -144,7 +145,8 @@
// A collection of FeatureAction.
// Note that access to this collection should happen in service thread.
- private final ArrayList<HdmiCecFeatureAction> mActions = new ArrayList<>();
+ @VisibleForTesting
+ final ArrayList<HdmiCecFeatureAction> mActions = new ArrayList<>();
private final Handler mHandler =
new Handler() {
@@ -544,6 +546,8 @@
} else if (mService.isPowerStandbyOrTransient() && isPowerOnOrToggleCommand(message)) {
mService.wakeUp();
return true;
+ } else if (!mService.isHdmiCecVolumeControlEnabled() && isVolumeOrMuteCommand(message)) {
+ return false;
}
final long downTime = SystemClock.uptimeMillis();
@@ -618,6 +622,16 @@
|| params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER_TOGGLE_FUNCTION);
}
+ static boolean isVolumeOrMuteCommand(HdmiCecMessage message) {
+ byte[] params = message.getParams();
+ return message.getOpcode() == Constants.MESSAGE_USER_CONTROL_PRESSED
+ && (params[0] == HdmiCecKeycode.CEC_KEYCODE_VOLUME_DOWN
+ || params[0] == HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP
+ || params[0] == HdmiCecKeycode.CEC_KEYCODE_MUTE
+ || params[0] == HdmiCecKeycode.CEC_KEYCODE_MUTE_FUNCTION
+ || params[0] == HdmiCecKeycode.CEC_KEYCODE_RESTORE_VOLUME_FUNCTION);
+ }
+
protected boolean handleTextViewOn(HdmiCecMessage message) {
return false;
}
@@ -1038,6 +1052,9 @@
@ServiceThreadOnly
protected void sendVolumeKeyEvent(int keyCode, boolean isPressed) {
assertRunOnServiceThread();
+ if (!mService.isHdmiCecVolumeControlEnabled()) {
+ return;
+ }
if (!HdmiCecKeycode.isVolumeKeycode(keyCode)) {
Slog.w(TAG, "Not a volume key: " + keyCode);
return;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index e5a08d3..611b8c6 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -575,7 +575,7 @@
@ServiceThreadOnly
protected boolean handleGiveAudioStatus(HdmiCecMessage message) {
assertRunOnServiceThread();
- if (isSystemAudioControlFeatureEnabled()) {
+ if (isSystemAudioControlFeatureEnabled() && mService.isHdmiCecVolumeControlEnabled()) {
reportAudioStatus(message.getSource());
} else {
mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
@@ -930,6 +930,9 @@
void reportAudioStatus(int source) {
assertRunOnServiceThread();
+ if (!mService.isHdmiCecVolumeControlEnabled()) {
+ return;
+ }
int volume = mService.getAudioManager().getStreamVolume(AudioManager.STREAM_MUSIC);
boolean mute = mService.getAudioManager().isStreamMute(AudioManager.STREAM_MUSIC);
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index a702ce5..0ac4f9e 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -678,6 +678,9 @@
@ServiceThreadOnly
protected boolean handleReportAudioStatus(HdmiCecMessage message) {
assertRunOnServiceThread();
+ if (!mService.isHdmiCecVolumeControlEnabled()) {
+ return false;
+ }
boolean mute = HdmiUtils.isAudioStatusMute(message);
int volume = HdmiUtils.getAudioStatusVolume(message);
@@ -987,7 +990,7 @@
}
void setAudioStatus(boolean mute, int volume) {
- if (!isSystemAudioActivated()) {
+ if (!isSystemAudioActivated() || !mService.isHdmiCecVolumeControlEnabled()) {
return;
}
synchronized (mLock) {
@@ -1009,7 +1012,7 @@
// On initialization process, getAvrDeviceInfo() may return null and cause exception
return;
}
- if (delta == 0 || !isSystemAudioActivated()) {
+ if (delta == 0 || !isSystemAudioActivated() || !mService.isHdmiCecVolumeControlEnabled()) {
return;
}
@@ -1038,7 +1041,7 @@
@ServiceThreadOnly
void changeMute(boolean mute) {
assertRunOnServiceThread();
- if (getAvrDeviceInfo() == null) {
+ if (getAvrDeviceInfo() == null || !mService.isHdmiCecVolumeControlEnabled()) {
// On initialization process, getAvrDeviceInfo() may return null and cause exception
return;
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index d9e3025..53f9ebc 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -177,6 +177,10 @@
@GuardedBy("mLock")
protected final ActiveSource mActiveSource = new ActiveSource();
+ // Whether HDMI CEC volume control is enabled or not.
+ @GuardedBy("mLock")
+ private boolean mHdmiCecVolumeControlEnabled;
+
// Whether System Audio Mode is activated or not.
@GuardedBy("mLock")
private boolean mSystemAudioActivated = false;
@@ -497,6 +501,8 @@
mPowerStatus = getInitialPowerStatus();
mProhibitMode = false;
mHdmiControlEnabled = readBooleanSetting(Global.HDMI_CONTROL_ENABLED, true);
+ mHdmiCecVolumeControlEnabled = readBooleanSetting(
+ Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED, true);
mMhlInputChangeEnabled = readBooleanSetting(Global.MHL_INPUT_SWITCHING_ENABLED, true);
if (mCecController == null) {
@@ -646,6 +652,7 @@
ContentResolver resolver = getContext().getContentResolver();
String[] settings = new String[] {
Global.HDMI_CONTROL_ENABLED,
+ Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED,
Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED,
Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED,
Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED,
@@ -674,6 +681,9 @@
case Global.HDMI_CONTROL_ENABLED:
setControlEnabled(enabled);
break;
+ case Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED:
+ setHdmiCecVolumeControlEnabled(enabled);
+ break;
case Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED:
if (isTvDeviceEnabled()) {
tv().setAutoWakeup(enabled);
@@ -1273,7 +1283,9 @@
}
void setAudioStatus(boolean mute, int volume) {
- if (!isTvDeviceEnabled() || !tv().isSystemAudioActivated()) {
+ if (!isTvDeviceEnabled()
+ || !tv().isSystemAudioActivated()
+ || !isHdmiCecVolumeControlEnabled()) {
return;
}
AudioManager audioManager = getAudioManager();
@@ -2187,6 +2199,24 @@
}
@Override
+ public boolean isHdmiCecVolumeControlEnabled() {
+ enforceAccessPermission();
+ return HdmiControlService.this.isHdmiCecVolumeControlEnabled();
+ }
+
+ @Override
+ public void setHdmiCecVolumeControlEnabled(final boolean isHdmiCecVolumeControlEnabled) {
+ enforceAccessPermission();
+ runOnServiceThread(new Runnable() {
+ @Override
+ public void run() {
+ HdmiControlService.this.setHdmiCecVolumeControlEnabled(
+ isHdmiCecVolumeControlEnabled);
+ }
+ });
+ }
+
+ @Override
public void reportAudioStatus(final int deviceType, final int volume, final int maxVolume,
final boolean isMute) {
enforceAccessPermission();
@@ -2250,6 +2280,7 @@
pw.println("mHdmiControlEnabled: " + mHdmiControlEnabled);
pw.println("mMhlInputChangeEnabled: " + mMhlInputChangeEnabled);
pw.println("mSystemAudioActivated: " + isSystemAudioActivated());
+ pw.println("mHdmiCecVolumeControlEnabled " + mHdmiCecVolumeControlEnabled);
pw.decreaseIndent();
pw.println("mMhlController: ");
@@ -2982,6 +3013,29 @@
}
}
+ void setHdmiCecVolumeControlEnabled(boolean isHdmiCecVolumeControlEnabled) {
+ assertRunOnServiceThread();
+ synchronized (mLock) {
+ mHdmiCecVolumeControlEnabled = isHdmiCecVolumeControlEnabled;
+
+ boolean storedValue = readBooleanSetting(Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED,
+ true);
+ if (storedValue != isHdmiCecVolumeControlEnabled) {
+ HdmiLogger.debug("Changing HDMI CEC volume control feature state: %s",
+ isHdmiCecVolumeControlEnabled);
+ writeBooleanSetting(Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED,
+ isHdmiCecVolumeControlEnabled);
+ }
+ }
+ }
+
+ boolean isHdmiCecVolumeControlEnabled() {
+ assertRunOnServiceThread();
+ synchronized (mLock) {
+ return mHdmiCecVolumeControlEnabled;
+ }
+ }
+
boolean isProhibitMode() {
synchronized (mLock) {
return mProhibitMode;
@@ -3022,8 +3076,12 @@
if (enabled) {
enableHdmiControlService();
+ setHdmiCecVolumeControlEnabled(
+ readBooleanSetting(Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED, true));
return;
}
+
+ setHdmiCecVolumeControlEnabled(false);
// Call the vendor handler before the service is disabled.
invokeVendorCommandListenersOnControlStateChanged(false,
HdmiControlManager.CONTROL_STATE_CHANGED_REASON_SETTING);
diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
index 393e8db..2cae1d6 100644
--- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -360,7 +360,7 @@
* Verify the UID and return the installer package name.
*
* @return the package name of the installer, or null if it cannot be determined or it is
- * installed via adb.
+ * installed via adb.
*/
@Nullable
private String getInstallerPackageName(Intent intent) {
@@ -568,7 +568,10 @@
try (PackageParser2 parser = mParserSupplier.get()) {
ParsedPackage pkg = parser.parsePackage(installationPath, 0, false);
int flags = PackageManager.GET_SIGNING_CERTIFICATES | PackageManager.GET_META_DATA;
- pkg.setSigningDetails(ParsingPackageUtils.collectCertificates(pkg, false));
+ // APK signatures is already verified elsewhere in PackageManager. We do not need to
+ // verify it again since it could cause a timeout for large APKs.
+ pkg.setSigningDetails(
+ ParsingPackageUtils.collectCertificates(pkg, /* skipVerify= */ true));
return PackageInfoUtils.generate(
pkg,
null,
@@ -709,7 +712,7 @@
// Filter out the rule provider packages that are not system apps.
List<String> systemAppRuleProviders = new ArrayList<>();
- for (String ruleProvider: integrityRuleProviders) {
+ for (String ruleProvider : integrityRuleProviders) {
if (isSystemApp(ruleProvider)) {
systemAppRuleProviders.add(ruleProvider);
}
diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java
index 537ca08..5efc924 100644
--- a/services/core/java/com/android/server/wm/Dimmer.java
+++ b/services/core/java/com/android/server/wm/Dimmer.java
@@ -382,8 +382,8 @@
@Override
public void apply(SurfaceControl.Transaction t, SurfaceControl sc, long currentPlayTime) {
- float alpha = ((float) currentPlayTime / getDuration()) * (mToAlpha - mFromAlpha)
- + mFromAlpha;
+ final float fraction = getFraction(currentPlayTime);
+ final float alpha = fraction * (mToAlpha - mFromAlpha) + mFromAlpha;
t.setAlpha(sc, alpha);
}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 656dca5..1b1898b 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -27,7 +27,6 @@
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.graphics.Rect;
@@ -38,7 +37,6 @@
import android.os.Trace;
import android.os.UserHandle;
import android.util.ArrayMap;
-import android.util.Log;
import android.util.Slog;
import android.view.InputApplicationHandle;
import android.view.InputChannel;
@@ -138,18 +136,6 @@
// If there's a drag in flight, provide a pseudo-window to catch drag input
final boolean inDrag = mService.mDragDropController.dragDropActiveLocked();
- final boolean inPositioning =
- mService.mTaskPositioningController.isPositioningLocked();
- if (inPositioning) {
- if (DEBUG_TASK_POSITIONING) {
- Log.d(TAG_WM, "Inserting window handle for repositioning");
- }
- mService.mTaskPositioningController.showInputSurface(mInputTransaction,
- mDisplayId);
- } else {
- mService.mTaskPositioningController.hideInputSurface(mInputTransaction,
- mDisplayId);
- }
// Add all windows on the default display.
mUpdateInputForAllWindowsConsumer.updateInputWindows(inDrag);
diff --git a/services/core/java/com/android/server/wm/LocalAnimationAdapter.java b/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
index 7c1a616..f0629fa 100644
--- a/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
@@ -130,6 +130,16 @@
*/
default boolean needsEarlyWakeup() { return false; }
+ /**
+ * @return The fraction of the animation, returns 1 if duration is 0.
+ *
+ * @param currentPlayTime The current play time.
+ */
+ default float getFraction(float currentPlayTime) {
+ final float duration = getDuration();
+ return duration > 0 ? currentPlayTime / duration : 1.0f;
+ }
+
void dump(PrintWriter pw, String prefix);
default void dumpDebug(ProtoOutputStream proto, long fieldId) {
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index 86e0818..90936ef 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -646,8 +646,8 @@
@Override
public void apply(SurfaceControl.Transaction t, SurfaceControl leash,
long currentPlayTime) {
- float fraction = (float)currentPlayTime / (float)getDuration();
- int color = (Integer) va.evaluate(fraction, startColor, endColor);
+ final float fraction = getFraction(currentPlayTime);
+ final int color = (Integer) va.evaluate(fraction, startColor, endColor);
Color middleColor = Color.valueOf(color);
rgbTmpFloat[0] = middleColor.red();
rgbTmpFloat[1] = middleColor.green();
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index be0d6f8..c68b660 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -53,7 +53,6 @@
import android.view.InputEvent;
import android.view.InputWindowHandle;
import android.view.MotionEvent;
-import android.view.SurfaceControl;
import android.view.WindowManager;
import com.android.internal.annotations.VisibleForTesting;
@@ -268,9 +267,7 @@
mDisplayContent.getDisplayRotation().pause();
// Notify InputMonitor to take mDragWindowHandle.
- final SurfaceControl.Transaction t = mService.mTransactionFactory.get();
- mDisplayContent.getInputMonitor().updateInputWindowsImmediately(t);
- t.syncInputWindows().apply();
+ mService.mTaskPositioningController.showInputSurface(win.getDisplayId());
final DisplayMetrics displayMetrics = displayContent.getDisplayMetrics();
mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, displayMetrics);
@@ -301,6 +298,7 @@
return;
}
+ mService.mTaskPositioningController.hideInputSurface(mDisplayContent.getDisplayId());
mService.mInputManager.unregisterInputChannel(mServerChannel);
mInputEventReceiver.dispose();
diff --git a/services/core/java/com/android/server/wm/TaskPositioningController.java b/services/core/java/com/android/server/wm/TaskPositioningController.java
index 2d303fa..d343daf 100644
--- a/services/core/java/com/android/server/wm/TaskPositioningController.java
+++ b/services/core/java/com/android/server/wm/TaskPositioningController.java
@@ -55,6 +55,8 @@
return mTaskPositioner != null;
}
+ final SurfaceControl.Transaction mTransaction;
+
InputWindowHandle getDragWindowHandleLocked() {
return mTaskPositioner != null ? mTaskPositioner.mDragWindowHandle : null;
}
@@ -65,16 +67,18 @@
mInputManager = inputManager;
mActivityManager = activityManager;
mHandler = new Handler(looper);
+ mTransaction = service.mTransactionFactory.get();
}
- void hideInputSurface(SurfaceControl.Transaction t, int displayId) {
+ void hideInputSurface(int displayId) {
if (mPositioningDisplay != null && mPositioningDisplay.getDisplayId() == displayId
&& mInputSurface != null) {
- t.hide(mInputSurface);
+ mTransaction.hide(mInputSurface);
+ mTransaction.syncInputWindows().apply();
}
}
- void showInputSurface(SurfaceControl.Transaction t, int displayId) {
+ void showInputSurface(int displayId) {
if (mPositioningDisplay == null || mPositioningDisplay.getDisplayId() != displayId) {
return;
}
@@ -92,16 +96,17 @@
return;
}
- t.show(mInputSurface);
- t.setInputWindowInfo(mInputSurface, h);
- t.setLayer(mInputSurface, Integer.MAX_VALUE);
+ mTransaction.show(mInputSurface);
+ mTransaction.setInputWindowInfo(mInputSurface, h);
+ mTransaction.setLayer(mInputSurface, Integer.MAX_VALUE);
final Display display = dc.getDisplay();
final Point p = new Point();
display.getRealSize(p);
mTmpClipRect.set(0, 0, p.x, p.y);
- t.setWindowCrop(mInputSurface, mTmpClipRect);
+ mTransaction.setWindowCrop(mInputSurface, mTmpClipRect);
+ mTransaction.syncInputWindows().apply();
}
boolean startMovingTask(IWindow window, float startX, float startY) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 706dcba..a3387ab 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2491,6 +2491,23 @@
}
/**
+ * Expands the given rectangle by the region of window resize handle for freeform window.
+ * @param inOutRect The rectangle to update.
+ */
+ private void adjustRegionInFreefromWindowMode(Rect inOutRect) {
+ if (!inFreeformWindowingMode()) {
+ return;
+ }
+
+ // For freeform windows, we need the touch region to include the whole
+ // surface for the shadows.
+ final DisplayMetrics displayMetrics = getDisplayContent().getDisplayMetrics();
+ final int delta = WindowManagerService.dipToPixel(
+ RESIZE_HANDLE_WIDTH_IN_DP, displayMetrics);
+ inOutRect.inset(-delta, -delta);
+ }
+
+ /**
* Updates the region for a window in an Activity that was a touch modal. This will limit
* the outer touch to the activity stack region.
* @param outRegion The region to update.
@@ -2513,14 +2530,7 @@
getRootTask().getDimBounds(mTmpRect);
}
}
- if (inFreeformWindowingMode()) {
- // For freeform windows, we need the touch region to include the whole
- // surface for the shadows.
- final DisplayMetrics displayMetrics = getDisplayContent().getDisplayMetrics();
- final int delta = WindowManagerService.dipToPixel(
- RESIZE_HANDLE_WIDTH_IN_DP, displayMetrics);
- mTmpRect.inset(-delta, -delta);
- }
+ adjustRegionInFreefromWindowMode(mTmpRect);
outRegion.set(mTmpRect);
cropRegionToStackBoundsIfNeeded(outRegion);
}
@@ -3335,7 +3345,7 @@
}
final ActivityStack stack = task.getStack();
- if (stack == null) {
+ if (stack == null || inFreeformWindowingMode()) {
return;
}
@@ -3354,6 +3364,7 @@
}
stack.getDimBounds(mTmpRect);
+ adjustRegionInFreefromWindowMode(mTmpRect);
region.op(mTmpRect, Region.Op.INTERSECT);
}
@@ -5595,7 +5606,7 @@
@Override
public void apply(Transaction t, SurfaceControl leash, long currentPlayTime) {
- final float fraction = (float) currentPlayTime / getDuration();
+ final float fraction = getFraction(currentPlayTime);
final float v = mInterpolator.getInterpolation(fraction);
t.setPosition(leash, mFrom.x + (mTo.x - mFrom.x) * v,
mFrom.y + (mTo.y - mFrom.y) * v);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 5d5e424..7e4c8f3 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -7326,13 +7326,23 @@
return admin != null ? admin.mFactoryResetProtectionPolicy : null;
}
- private int getFrpManagementAgentUidOrThrow() {
+ private int getFrpManagementAgentUid() {
PersistentDataBlockManagerInternal pdb = mInjector.getPersistentDataBlockManagerInternal();
- if ((pdb == null) || (pdb.getAllowedUid() == -1)) {
+ return pdb != null ? pdb.getAllowedUid() : -1;
+ }
+
+ private int getFrpManagementAgentUidOrThrow() {
+ int uid = getFrpManagementAgentUid();
+ if (uid == -1) {
throw new UnsupportedOperationException(
"The persistent data block service is not supported on this device");
}
- return pdb.getAllowedUid();
+ return uid;
+ }
+
+ @Override
+ public boolean isFactoryResetProtectionPolicySupported() {
+ return getFrpManagementAgentUid() != -1;
}
@Override
diff --git a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
index fea61aa..dfe75ed 100644
--- a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
@@ -30,10 +30,13 @@
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.robolectric.Shadows.shadowOf;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
import static org.testng.Assert.expectThrows;
import android.app.backup.BackupManager;
@@ -86,6 +89,7 @@
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
@@ -104,6 +108,7 @@
private static final String TAG = "BMSTest";
private static final String PACKAGE_1 = "some.package.1";
private static final String PACKAGE_2 = "some.package.2";
+ private static final String USER_FACING_PACKAGE = "user.facing.package";
private static final int USER_ID = 10;
@Mock private TransportManager mTransportManager;
@@ -1186,6 +1191,47 @@
eq(packageTrackingReceiver), eq(UserHandle.of(USER_ID)), any(), any(), any());
}
+ @Test
+ public void testFilterUserFacingPackages_shouldSkipUserFacing_filtersUserFacing() {
+ List<PackageInfo> packages = Arrays.asList(getPackageInfo(USER_FACING_PACKAGE),
+ getPackageInfo(PACKAGE_1));
+ UserBackupManagerService backupManagerService = spy(
+ createUserBackupManagerServiceAndRunTasks());
+ when(backupManagerService.shouldSkipUserFacingData()).thenReturn(true);
+ when(backupManagerService.shouldSkipPackage(eq(USER_FACING_PACKAGE))).thenReturn(true);
+
+ List<PackageInfo> filteredPackages = backupManagerService.filterUserFacingPackages(
+ packages);
+
+ assertFalse(containsPackage(filteredPackages, USER_FACING_PACKAGE));
+ assertTrue(containsPackage(filteredPackages, PACKAGE_1));
+ }
+
+ @Test
+ public void testFilterUserFacingPackages_shouldNotSkipUserFacing_doesNotFilterUserFacing() {
+ List<PackageInfo> packages = Arrays.asList(getPackageInfo(USER_FACING_PACKAGE),
+ getPackageInfo(PACKAGE_1));
+ UserBackupManagerService backupManagerService = spy(
+ createUserBackupManagerServiceAndRunTasks());
+ when(backupManagerService.shouldSkipUserFacingData()).thenReturn(false);
+ when(backupManagerService.shouldSkipPackage(eq(USER_FACING_PACKAGE))).thenReturn(true);
+
+ List<PackageInfo> filteredPackages = backupManagerService.filterUserFacingPackages(
+ packages);
+
+ assertTrue(containsPackage(filteredPackages, USER_FACING_PACKAGE));
+ assertTrue(containsPackage(filteredPackages, PACKAGE_1));
+ }
+
+ private static boolean containsPackage(List<PackageInfo> packages, String targetPackage) {
+ for (PackageInfo packageInfo : packages) {
+ if (targetPackage.equals(packageInfo.packageName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private UserBackupManagerService createUserBackupManagerServiceAndRunTasks() {
return BackupManagerServiceTestUtils.createUserBackupManagerServiceAndRunTasks(
USER_ID, mContext, mBackupThread, mBaseStateDir, mDataDir, mTransportManager);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
index a587029..28887fd 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
@@ -24,6 +24,7 @@
import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_2;
import static com.android.server.hdmi.Constants.ADDR_TUNER_1;
import static com.android.server.hdmi.Constants.ADDR_TV;
+import static com.android.server.hdmi.Constants.MESSAGE_GIVE_AUDIO_STATUS;
import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
import static com.android.server.hdmi.HdmiControlService.STANDBY_SCREEN_OFF;
@@ -47,6 +48,7 @@
import org.junit.runners.JUnit4;
import java.util.ArrayList;
+
@SmallTest
@RunWith(JUnit4.class)
/** Tests for {@link HdmiCecLocalDeviceAudioSystem} class. */
@@ -167,6 +169,8 @@
}
};
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
+
mMyLooper = mTestLooper.getLooper();
mHdmiCecLocalDeviceAudioSystem = new HdmiCecLocalDeviceAudioSystem(mHdmiControlService);
mHdmiCecLocalDevicePlayback = new HdmiCecLocalDevicePlayback(mHdmiControlService) {
@@ -717,4 +721,112 @@
mHdmiCecLocalDeviceAudioSystem.onHotplug(0, false);
assertThat(mWokenUp).isFalse();
}
+
+ @Test
+ public void giveAudioStatus_volumeEnabled() {
+ mMusicVolume = 50;
+ mMusicMaxVolume = 100;
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
+ mHdmiCecLocalDeviceAudioSystem.setSystemAudioControlFeatureEnabled(true);
+
+ int volume = mHdmiControlService.getAudioManager()
+ .getStreamVolume(AudioManager.STREAM_MUSIC);
+ boolean mute = mHdmiControlService.getAudioManager()
+ .isStreamMute(AudioManager.STREAM_MUSIC);
+ int maxVolume = mHdmiControlService.getAudioManager()
+ .getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+ int scaledVolume = VolumeControlAction.scaleToCecVolume(volume, maxVolume);
+ HdmiCecMessage expected = HdmiCecMessageBuilder.buildReportAudioStatus(ADDR_AUDIO_SYSTEM,
+ ADDR_TV, scaledVolume, mute);
+ HdmiCecMessage featureAbort = HdmiCecMessageBuilder.buildFeatureAbortCommand(
+ ADDR_AUDIO_SYSTEM, ADDR_TV, MESSAGE_GIVE_AUDIO_STATUS, Constants.ABORT_REFUSED);
+
+ HdmiCecMessage giveAudioStatus = HdmiCecMessageBuilder.buildGiveAudioStatus(ADDR_TV,
+ ADDR_AUDIO_SYSTEM);
+ mNativeWrapper.clearResultMessages();
+ boolean handled = mHdmiCecLocalDeviceAudioSystem.handleGiveAudioStatus(giveAudioStatus);
+ mTestLooper.dispatchAll();
+
+ assertThat(mNativeWrapper.getResultMessages()).contains(expected);
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(featureAbort);
+ assertThat(handled).isTrue();
+ }
+
+ @Test
+ public void giveAudioStatus_volumeDisabled() {
+ mMusicVolume = 50;
+ mMusicMaxVolume = 100;
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(false);
+ mHdmiCecLocalDeviceAudioSystem.setSystemAudioControlFeatureEnabled(true);
+
+ int volume = mHdmiControlService.getAudioManager()
+ .getStreamVolume(AudioManager.STREAM_MUSIC);
+ boolean mute = mHdmiControlService.getAudioManager()
+ .isStreamMute(AudioManager.STREAM_MUSIC);
+ int maxVolume = mHdmiControlService.getAudioManager()
+ .getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+ int scaledVolume = VolumeControlAction.scaleToCecVolume(volume, maxVolume);
+ HdmiCecMessage unexpected = HdmiCecMessageBuilder.buildReportAudioStatus(ADDR_AUDIO_SYSTEM,
+ ADDR_TV, scaledVolume, mute);
+ HdmiCecMessage featureAbort = HdmiCecMessageBuilder.buildFeatureAbortCommand(
+ ADDR_AUDIO_SYSTEM, ADDR_TV, MESSAGE_GIVE_AUDIO_STATUS, Constants.ABORT_REFUSED);
+
+ HdmiCecMessage giveAudioStatus = HdmiCecMessageBuilder.buildGiveAudioStatus(ADDR_TV,
+ ADDR_AUDIO_SYSTEM);
+ mNativeWrapper.clearResultMessages();
+ boolean handled = mHdmiCecLocalDeviceAudioSystem.handleGiveAudioStatus(giveAudioStatus);
+ mTestLooper.dispatchAll();
+
+ assertThat(mNativeWrapper.getResultMessages()).contains(featureAbort);
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(unexpected);
+ assertThat(handled).isTrue();
+ }
+
+ @Test
+ public void reportAudioStatus_volumeEnabled() {
+ mMusicVolume = 50;
+ mMusicMaxVolume = 100;
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
+ mHdmiCecLocalDeviceAudioSystem.setSystemAudioControlFeatureEnabled(true);
+
+ int volume = mHdmiControlService.getAudioManager()
+ .getStreamVolume(AudioManager.STREAM_MUSIC);
+ boolean mute = mHdmiControlService.getAudioManager()
+ .isStreamMute(AudioManager.STREAM_MUSIC);
+ int maxVolume = mHdmiControlService.getAudioManager()
+ .getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+ int scaledVolume = VolumeControlAction.scaleToCecVolume(volume, maxVolume);
+ HdmiCecMessage expected = HdmiCecMessageBuilder.buildReportAudioStatus(ADDR_AUDIO_SYSTEM,
+ ADDR_TV, scaledVolume, mute);
+
+ mNativeWrapper.clearResultMessages();
+ mHdmiCecLocalDeviceAudioSystem.reportAudioStatus(ADDR_TV);
+ mTestLooper.dispatchAll();
+
+ assertThat(mNativeWrapper.getResultMessages()).contains(expected);
+ }
+
+ @Test
+ public void reportAudioStatus_volumeDisabled() {
+ mMusicVolume = 50;
+ mMusicMaxVolume = 100;
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(false);
+ mHdmiCecLocalDeviceAudioSystem.setSystemAudioControlFeatureEnabled(true);
+
+ int volume = mHdmiControlService.getAudioManager()
+ .getStreamVolume(AudioManager.STREAM_MUSIC);
+ boolean mute = mHdmiControlService.getAudioManager()
+ .isStreamMute(AudioManager.STREAM_MUSIC);
+ int maxVolume = mHdmiControlService.getAudioManager()
+ .getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+ int scaledVolume = VolumeControlAction.scaleToCecVolume(volume, maxVolume);
+ HdmiCecMessage unexpected = HdmiCecMessageBuilder.buildReportAudioStatus(ADDR_AUDIO_SYSTEM,
+ ADDR_TV, scaledVolume, mute);
+
+ mNativeWrapper.clearResultMessages();
+ mHdmiCecLocalDeviceAudioSystem.reportAudioStatus(ADDR_TV);
+ mTestLooper.dispatchAll();
+
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(unexpected);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index f72d622..b8394e3 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -22,6 +22,7 @@
import android.os.Looper;
import android.os.test.TestLooper;
+import android.view.KeyEvent;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -153,4 +154,75 @@
mHdmiCecLocalDevicePlayback.onHotplug(0, false);
assertThat(mWokenUp).isFalse();
}
+
+ @Test
+ @Ignore("b/151147315")
+ public void sendVolumeKeyEvent_up_volumeEnabled() {
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
+ mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, true);
+ mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, false);
+
+ assertThat(hasSendKeyAction()).isTrue();
+ }
+
+ @Test
+ @Ignore("b/151147315")
+ public void sendVolumeKeyEvent_down_volumeEnabled() {
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
+ mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_DOWN, true);
+ mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_DOWN, false);
+
+ assertThat(hasSendKeyAction()).isTrue();
+ }
+
+ @Test
+ @Ignore("b/151147315")
+ public void sendVolumeKeyEvent_mute_volumeEnabled() {
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
+ mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_MUTE, true);
+ mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_MUTE, false);
+
+ assertThat(hasSendKeyAction()).isTrue();
+ }
+
+ @Test
+ @Ignore("b/151147315")
+ public void sendVolumeKeyEvent_up_volumeDisabled() {
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(false);
+ mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, true);
+ mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, false);
+
+ assertThat(hasSendKeyAction()).isFalse();
+ }
+
+ @Test
+ @Ignore("b/151147315")
+ public void sendVolumeKeyEvent_down_volumeDisabled() {
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(false);
+ mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_DOWN, true);
+ mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_DOWN, false);
+
+ assertThat(hasSendKeyAction()).isFalse();
+ }
+
+ @Test
+ @Ignore("b/151147315")
+ public void sendVolumeKeyEvent_mute_volumeDisabled() {
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(false);
+ mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_MUTE, true);
+ mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_MUTE, false);
+
+ assertThat(hasSendKeyAction()).isFalse();
+ }
+
+ private boolean hasSendKeyAction() {
+ boolean match = false;
+ for (HdmiCecFeatureAction action : mHdmiCecLocalDevicePlayback.mActions) {
+ if (action instanceof SendKeyAction) {
+ match = true;
+ break;
+ }
+ }
+ return match;
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
index 039b904..e0bada31 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
@@ -19,6 +19,7 @@
import static com.android.server.hdmi.Constants.ADDR_AUDIO_SYSTEM;
import static com.android.server.hdmi.Constants.ADDR_BROADCAST;
+import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1;
import static com.android.server.hdmi.Constants.ADDR_TV;
import static com.android.server.hdmi.Constants.ADDR_UNREGISTERED;
import static com.android.server.hdmi.Constants.MESSAGE_DEVICE_VENDOR_ID;
@@ -185,4 +186,64 @@
HdmiCecMessageBuilder.buildStandby(ADDR_TV, ADDR_AUDIO_SYSTEM));
assertTrue(mStandbyMessageReceived);
}
+
+ @Test
+ public void handleUserControlPressed_volumeUp() {
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
+ boolean result = mHdmiLocalDevice.handleUserControlPressed(
+ HdmiCecMessageBuilder.buildUserControlPressed(ADDR_PLAYBACK_1, ADDR_TV,
+ HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP));
+
+ assertTrue(result);
+ }
+
+ @Test
+ public void handleUserControlPressed_volumeDown() {
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
+ boolean result = mHdmiLocalDevice.handleUserControlPressed(
+ HdmiCecMessageBuilder.buildUserControlPressed(ADDR_PLAYBACK_1, ADDR_TV,
+ HdmiCecKeycode.CEC_KEYCODE_VOLUME_DOWN));
+
+ assertTrue(result);
+ }
+
+ @Test
+ public void handleUserControlPressed_volumeMute() {
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
+ boolean result = mHdmiLocalDevice.handleUserControlPressed(
+ HdmiCecMessageBuilder.buildUserControlPressed(ADDR_PLAYBACK_1, ADDR_TV,
+ HdmiCecKeycode.CEC_KEYCODE_MUTE));
+
+ assertTrue(result);
+ }
+
+ @Test
+ public void handleUserControlPressed_volumeUp_disabled() {
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(false);
+ boolean result = mHdmiLocalDevice.handleUserControlPressed(
+ HdmiCecMessageBuilder.buildUserControlPressed(ADDR_PLAYBACK_1, ADDR_TV,
+ HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP));
+
+ assertFalse(result);
+ }
+
+ @Test
+ public void handleUserControlPressed_volumeDown_disabled() {
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(false);
+ boolean result = mHdmiLocalDevice.handleUserControlPressed(
+ HdmiCecMessageBuilder.buildUserControlPressed(ADDR_PLAYBACK_1, ADDR_TV,
+ HdmiCecKeycode.CEC_KEYCODE_VOLUME_DOWN));
+
+ assertFalse(result);
+ }
+
+ @Test
+ public void handleUserControlPressed_volumeMute_disabled() {
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(false);
+ boolean result = mHdmiLocalDevice.handleUserControlPressed(
+ HdmiCecMessageBuilder.buildUserControlPressed(ADDR_PLAYBACK_1, ADDR_TV,
+ HdmiCecKeycode.CEC_KEYCODE_MUTE));
+
+ assertFalse(result);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index fa19814..7af7a23 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -252,4 +252,13 @@
assertThat(mHdmiControlService.getPowerStatus()).isEqualTo(
HdmiControlManager.POWER_STATUS_STANDBY);
}
+
+ @Test
+ public void setAndGetCecVolumeControlEnabled_isApi() {
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(false);
+ assertThat(mHdmiControlService.isHdmiCecVolumeControlEnabled()).isFalse();
+
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
+ assertThat(mHdmiControlService.isHdmiCecVolumeControlEnabled()).isTrue();
+ }
}