Merge "Fix tts span on Editable"
diff --git a/apex/jobscheduler/framework/java/android/app/IAlarmManager.aidl b/apex/jobscheduler/framework/java/android/app/IAlarmManager.aidl
index 9d11ca4..25caf4b 100644
--- a/apex/jobscheduler/framework/java/android/app/IAlarmManager.aidl
+++ b/apex/jobscheduler/framework/java/android/app/IAlarmManager.aidl
@@ -40,7 +40,6 @@
long getNextWakeFromIdleTime();
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
AlarmManager.AlarmClockInfo getNextAlarmClock(int userId);
- long currentNetworkTimeMillis();
boolean canScheduleExactAlarms(String packageName);
boolean hasScheduleExactAlarm(String packageName, int userId);
int getConfigVersion();
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index 296c89c..c053b2e 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -90,7 +90,6 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
-import android.os.ParcelableException;
import android.os.PowerExemptionManager;
import android.os.PowerManager;
import android.os.Process;
@@ -116,7 +115,6 @@
import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.LongArrayQueue;
-import android.util.NtpTrustedTime;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
@@ -161,7 +159,6 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
-import java.time.DateTimeException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
@@ -3008,17 +3005,6 @@
}
@Override
- public long currentNetworkTimeMillis() {
- final NtpTrustedTime time = NtpTrustedTime.getInstance(getContext());
- NtpTrustedTime.TimeResult ntpResult = time.getCachedTimeResult();
- if (ntpResult != null) {
- return ntpResult.currentTimeMillis();
- } else {
- throw new ParcelableException(new DateTimeException("Missing NTP fix"));
- }
- }
-
- @Override
public int getConfigVersion() {
getContext().enforceCallingOrSelfPermission(Manifest.permission.DUMP,
"getConfigVersion");
diff --git a/core/java/android/accounts/AbstractAccountAuthenticator.java b/core/java/android/accounts/AbstractAccountAuthenticator.java
index a3a3615..f29998a 100644
--- a/core/java/android/accounts/AbstractAccountAuthenticator.java
+++ b/core/java/android/accounts/AbstractAccountAuthenticator.java
@@ -290,10 +290,10 @@
}
}
+ @android.annotation.EnforcePermission(android.Manifest.permission.ACCOUNT_MANAGER)
@Override
public void editProperties(IAccountAuthenticatorResponse response,
String accountType) throws RemoteException {
- checkBinderPermission();
try {
final Bundle result = AbstractAccountAuthenticator.this.editProperties(
new AccountAuthenticatorResponse(response), accountType);
@@ -305,10 +305,10 @@
}
}
+ @android.annotation.EnforcePermission(android.Manifest.permission.ACCOUNT_MANAGER)
@Override
public void hasFeatures(IAccountAuthenticatorResponse response,
Account account, String[] features) throws RemoteException {
- checkBinderPermission();
try {
final Bundle result = AbstractAccountAuthenticator.this.hasFeatures(
new AccountAuthenticatorResponse(response), account, features);
@@ -320,10 +320,10 @@
}
}
+ @android.annotation.EnforcePermission(android.Manifest.permission.ACCOUNT_MANAGER)
@Override
public void getAccountRemovalAllowed(IAccountAuthenticatorResponse response,
Account account) throws RemoteException {
- checkBinderPermission();
try {
final Bundle result = AbstractAccountAuthenticator.this.getAccountRemovalAllowed(
new AccountAuthenticatorResponse(response), account);
@@ -335,10 +335,10 @@
}
}
+ @android.annotation.EnforcePermission(android.Manifest.permission.ACCOUNT_MANAGER)
@Override
public void getAccountCredentialsForCloning(IAccountAuthenticatorResponse response,
Account account) throws RemoteException {
- checkBinderPermission();
try {
final Bundle result =
AbstractAccountAuthenticator.this.getAccountCredentialsForCloning(
@@ -351,11 +351,11 @@
}
}
+ @android.annotation.EnforcePermission(android.Manifest.permission.ACCOUNT_MANAGER)
@Override
public void addAccountFromCredentials(IAccountAuthenticatorResponse response,
Account account,
Bundle accountCredentials) throws RemoteException {
- checkBinderPermission();
try {
final Bundle result =
AbstractAccountAuthenticator.this.addAccountFromCredentials(
@@ -465,12 +465,12 @@
}
}
+ @android.annotation.EnforcePermission(android.Manifest.permission.ACCOUNT_MANAGER)
@Override
public void isCredentialsUpdateSuggested(
IAccountAuthenticatorResponse response,
Account account,
String statusToken) throws RemoteException {
- checkBinderPermission();
try {
final Bundle result = AbstractAccountAuthenticator.this
.isCredentialsUpdateSuggested(
diff --git a/core/java/android/accounts/IAccountAuthenticator.aidl b/core/java/android/accounts/IAccountAuthenticator.aidl
index 701cecf..0575c07 100644
--- a/core/java/android/accounts/IAccountAuthenticator.aidl
+++ b/core/java/android/accounts/IAccountAuthenticator.aidl
@@ -62,6 +62,7 @@
/**
* launches an activity that lets the user edit and set the properties for an authenticator
*/
+ @EnforcePermission("ACCOUNT_MANAGER")
@UnsupportedAppUsage
void editProperties(in IAccountAuthenticatorResponse response, String accountType);
@@ -69,6 +70,7 @@
* returns a Bundle where the boolean value BOOLEAN_RESULT_KEY is set if the account has the
* specified features
*/
+ @EnforcePermission("ACCOUNT_MANAGER")
@UnsupportedAppUsage
void hasFeatures(in IAccountAuthenticatorResponse response, in Account account,
in String[] features);
@@ -76,12 +78,14 @@
/**
* Gets whether or not the account is allowed to be removed.
*/
+ @EnforcePermission("ACCOUNT_MANAGER")
@UnsupportedAppUsage
void getAccountRemovalAllowed(in IAccountAuthenticatorResponse response, in Account account);
/**
* Returns a Bundle containing the required credentials to copy the account across users.
*/
+ @EnforcePermission("ACCOUNT_MANAGER")
void getAccountCredentialsForCloning(in IAccountAuthenticatorResponse response,
in Account account);
@@ -89,6 +93,7 @@
* Uses the Bundle containing credentials from another instance of the authenticator to create
* a copy of the account on this user.
*/
+ @EnforcePermission("ACCOUNT_MANAGER")
void addAccountFromCredentials(in IAccountAuthenticatorResponse response, in Account account,
in Bundle accountCredentials);
@@ -116,6 +121,7 @@
/**
* Checks if the credentials of the provided account should be updated.
*/
+ @EnforcePermission("ACCOUNT_MANAGER")
void isCredentialsUpdateSuggested(in IAccountAuthenticatorResponse response, in Account account,
String statusToken);
}
diff --git a/core/java/android/app/timedetector/ITimeDetectorService.aidl b/core/java/android/app/timedetector/ITimeDetectorService.aidl
index fc7afb4..b441359 100644
--- a/core/java/android/app/timedetector/ITimeDetectorService.aidl
+++ b/core/java/android/app/timedetector/ITimeDetectorService.aidl
@@ -24,6 +24,7 @@
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.TelephonyTimeSuggestion;
+import android.app.timedetector.TimePoint;
/**
* System private API to communicate with time detector service.
@@ -45,9 +46,11 @@
boolean updateConfiguration(in TimeConfiguration timeConfiguration);
- void suggestExternalTime( in ExternalTimeSuggestion timeSuggestion);
+ void suggestExternalTime(in ExternalTimeSuggestion timeSuggestion);
void suggestGnssTime(in GnssTimeSuggestion timeSuggestion);
boolean suggestManualTime(in ManualTimeSuggestion timeSuggestion);
void suggestNetworkTime(in NetworkTimeSuggestion timeSuggestion);
void suggestTelephonyTime(in TelephonyTimeSuggestion timeSuggestion);
+
+ TimePoint latestNetworkTime();
}
diff --git a/core/java/android/app/timedetector/TimePoint.aidl b/core/java/android/app/timedetector/TimePoint.aidl
new file mode 100644
index 0000000..80d4bc1
--- /dev/null
+++ b/core/java/android/app/timedetector/TimePoint.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.timedetector;
+
+parcelable TimePoint;
diff --git a/core/java/android/app/timedetector/TimePoint.java b/core/java/android/app/timedetector/TimePoint.java
new file mode 100644
index 0000000..aa079a9
--- /dev/null
+++ b/core/java/android/app/timedetector/TimePoint.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.timedetector;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Data class for passing a Unix epoch time anchored to the elapsed realtime clock.
+ *
+ * @hide
+ */
+public final class TimePoint implements Parcelable {
+
+ private final long mUnixEpochTimeMillis;
+ private final long mElapsedRealtimeMillis;
+
+ public TimePoint(long unixEpochTimeMillis, long elapsedRealtimeMillis) {
+ mUnixEpochTimeMillis = unixEpochTimeMillis;
+ mElapsedRealtimeMillis = elapsedRealtimeMillis;
+ }
+
+ /**
+ * The current Unix epoch time, according to the external source.
+ */
+ public long getUnixEpochTimeMillis() {
+ return mUnixEpochTimeMillis;
+ }
+
+ /**
+ * The elapsed millis since boot when {@link #getUnixEpochTimeMillis} was computed.
+ */
+ public long getElapsedRealtimeMillis() {
+ return mElapsedRealtimeMillis;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeLong(mUnixEpochTimeMillis);
+ out.writeLong(mElapsedRealtimeMillis);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof TimePoint)) {
+ return false;
+ }
+ TimePoint timePoint = (TimePoint) o;
+ return mUnixEpochTimeMillis == timePoint.mUnixEpochTimeMillis
+ && mElapsedRealtimeMillis == timePoint.mElapsedRealtimeMillis;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mUnixEpochTimeMillis, mElapsedRealtimeMillis);
+ }
+
+ @Override
+ public String toString() {
+ return "TimePoint{"
+ + "mUnixEpochTimeMillis=" + mUnixEpochTimeMillis
+ + ", mElapsedRealtimeMillis=" + mElapsedRealtimeMillis
+ + '}';
+ }
+
+ public static final @NonNull Creator<TimePoint> CREATOR =
+ new Creator<TimePoint>() {
+ public TimePoint createFromParcel(Parcel in) {
+ long unixEpochTime = in.readLong();
+ long elapsedRealtimeMillis = in.readLong();
+ return new TimePoint(unixEpochTime, elapsedRealtimeMillis);
+ }
+
+ public TimePoint[] newArray(int size) {
+ return new TimePoint[size];
+ }
+ };
+}
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
index 4d0ba63..336ef7a 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
@@ -1739,6 +1739,20 @@
// abruptly.
Log.w(TAG, "Output surface likely abandoned, dropping buffer!");
img.close();
+ } catch (RuntimeException e) {
+ // NOTE: This is intended to catch RuntimeException from ImageReader.detachImage
+ // ImageReader.detachImage is not supposed to throw RuntimeExceptions but the
+ // bug went unchecked for a few years and now its behavior cannot be changed
+ // without breaking backwards compatibility.
+
+ if (!e.getClass().equals(RuntimeException.class)) {
+ // re-throw any exceptions that aren't base RuntimeException since they are
+ // coming from elsewhere, and we shouldn't silently drop those.
+ throw e;
+ }
+
+ Log.w(TAG, "Output surface likely abandoned, dropping buffer!");
+ img.close();
}
}
}
@@ -1773,9 +1787,23 @@
}
try {
reader.detachImage(img);
- } catch (Exception e) {
- Log.e(TAG,
- "Failed to detach image!");
+ } catch (IllegalStateException e) {
+ Log.e(TAG, "Failed to detach image!");
+ img.close();
+ return;
+ } catch (RuntimeException e) {
+ // NOTE: This is intended to catch RuntimeException from ImageReader.detachImage
+ // ImageReader.detachImage is not supposed to throw RuntimeExceptions but the
+ // bug went unchecked for a few years and now its behavior cannot be changed
+ // without breaking backwards compatibility.
+
+ if (!e.getClass().equals(RuntimeException.class)) {
+ // re-throw any exceptions that aren't base RuntimeException since they are
+ // coming from elsewhere, and we shouldn't silently drop those.
+ throw e;
+ }
+
+ Log.e(TAG, "Failed to detach image!");
img.close();
return;
}
diff --git a/core/java/android/hardware/location/ActivityRecognitionHardware.java b/core/java/android/hardware/location/ActivityRecognitionHardware.java
index 8acd1ff..20d6338 100644
--- a/core/java/android/hardware/location/ActivityRecognitionHardware.java
+++ b/core/java/android/hardware/location/ActivityRecognitionHardware.java
@@ -88,34 +88,34 @@
return nativeIsSupported();
}
+ @android.annotation.EnforcePermission(android.Manifest.permission.LOCATION_HARDWARE)
@Override
public String[] getSupportedActivities() {
- checkPermissions();
return mSupportedActivities;
}
+ @android.annotation.EnforcePermission(android.Manifest.permission.LOCATION_HARDWARE)
@Override
public boolean isActivitySupported(String activity) {
- checkPermissions();
int activityType = getActivityType(activity);
return activityType != INVALID_ACTIVITY_TYPE;
}
+ @android.annotation.EnforcePermission(android.Manifest.permission.LOCATION_HARDWARE)
@Override
public boolean registerSink(IActivityRecognitionHardwareSink sink) {
- checkPermissions();
return mSinks.register(sink);
}
+ @android.annotation.EnforcePermission(android.Manifest.permission.LOCATION_HARDWARE)
@Override
public boolean unregisterSink(IActivityRecognitionHardwareSink sink) {
- checkPermissions();
return mSinks.unregister(sink);
}
+ @android.annotation.EnforcePermission(android.Manifest.permission.LOCATION_HARDWARE)
@Override
public boolean enableActivityEvent(String activity, int eventType, long reportLatencyNs) {
- checkPermissions();
int activityType = getActivityType(activity);
if (activityType == INVALID_ACTIVITY_TYPE) {
@@ -130,9 +130,9 @@
return false;
}
+ @android.annotation.EnforcePermission(android.Manifest.permission.LOCATION_HARDWARE)
@Override
public boolean disableActivityEvent(String activity, int eventType) {
- checkPermissions();
int activityType = getActivityType(activity);
if (activityType == INVALID_ACTIVITY_TYPE) {
@@ -147,9 +147,9 @@
return false;
}
+ @android.annotation.EnforcePermission(android.Manifest.permission.LOCATION_HARDWARE)
@Override
public boolean flush() {
- checkPermissions();
int result = nativeFlush();
return result == NATIVE_SUCCESS_RESULT;
}
diff --git a/core/java/android/hardware/location/GeofenceHardwareService.java b/core/java/android/hardware/location/GeofenceHardwareService.java
index c0bcb27..106bfd5 100644
--- a/core/java/android/hardware/location/GeofenceHardwareService.java
+++ b/core/java/android/hardware/location/GeofenceHardwareService.java
@@ -75,76 +75,68 @@
mGeofenceHardwareImpl.setFusedGeofenceHardware(service);
}
+ @android.annotation.EnforcePermission(android.Manifest.permission.LOCATION_HARDWARE)
@Override
public int[] getMonitoringTypes() {
- mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
- "Location Hardware permission not granted to access hardware geofence");
return mGeofenceHardwareImpl.getMonitoringTypes();
}
+ @android.annotation.EnforcePermission(android.Manifest.permission.LOCATION_HARDWARE)
@Override
public int getStatusOfMonitoringType(int monitoringType) {
- mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
- "Location Hardware permission not granted to access hardware geofence");
return mGeofenceHardwareImpl.getStatusOfMonitoringType(monitoringType);
}
+ @android.annotation.EnforcePermission(android.Manifest.permission.LOCATION_HARDWARE)
@Override
public boolean addCircularFence(
int monitoringType,
GeofenceHardwareRequestParcelable request,
IGeofenceHardwareCallback callback) {
- mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
- "Location Hardware permission not granted to access hardware geofence");
checkPermission(Binder.getCallingPid(), Binder.getCallingUid(), monitoringType);
return mGeofenceHardwareImpl.addCircularFence(monitoringType, request, callback);
}
+ @android.annotation.EnforcePermission(android.Manifest.permission.LOCATION_HARDWARE)
@Override
public boolean removeGeofence(int id, int monitoringType) {
- mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
- "Location Hardware permission not granted to access hardware geofence");
checkPermission(Binder.getCallingPid(), Binder.getCallingUid(), monitoringType);
return mGeofenceHardwareImpl.removeGeofence(id, monitoringType);
}
+ @android.annotation.EnforcePermission(android.Manifest.permission.LOCATION_HARDWARE)
@Override
public boolean pauseGeofence(int id, int monitoringType) {
- mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
- "Location Hardware permission not granted to access hardware geofence");
checkPermission(Binder.getCallingPid(), Binder.getCallingUid(), monitoringType);
return mGeofenceHardwareImpl.pauseGeofence(id, monitoringType);
}
+ @android.annotation.EnforcePermission(android.Manifest.permission.LOCATION_HARDWARE)
@Override
public boolean resumeGeofence(int id, int monitoringType, int monitorTransitions) {
- mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
- "Location Hardware permission not granted to access hardware geofence");
checkPermission(Binder.getCallingPid(), Binder.getCallingUid(), monitoringType);
return mGeofenceHardwareImpl.resumeGeofence(id, monitoringType, monitorTransitions);
}
+ @android.annotation.EnforcePermission(android.Manifest.permission.LOCATION_HARDWARE)
@Override
public boolean registerForMonitorStateChangeCallback(int monitoringType,
IGeofenceHardwareMonitorCallback callback) {
- mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
- "Location Hardware permission not granted to access hardware geofence");
checkPermission(Binder.getCallingPid(), Binder.getCallingUid(), monitoringType);
return mGeofenceHardwareImpl.registerForMonitorStateChangeCallback(monitoringType,
callback);
}
+ @android.annotation.EnforcePermission(android.Manifest.permission.LOCATION_HARDWARE)
@Override
public boolean unregisterForMonitorStateChangeCallback(int monitoringType,
IGeofenceHardwareMonitorCallback callback) {
- mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
- "Location Hardware permission not granted to access hardware geofence");
checkPermission(Binder.getCallingPid(), Binder.getCallingUid(), monitoringType);
return mGeofenceHardwareImpl.unregisterForMonitorStateChangeCallback(monitoringType,
diff --git a/core/java/android/hardware/location/IActivityRecognitionHardware.aidl b/core/java/android/hardware/location/IActivityRecognitionHardware.aidl
index bc6b183..f093cd5 100644
--- a/core/java/android/hardware/location/IActivityRecognitionHardware.aidl
+++ b/core/java/android/hardware/location/IActivityRecognitionHardware.aidl
@@ -28,35 +28,42 @@
/**
* Gets an array of supported activities by hardware.
*/
+ @EnforcePermission("LOCATION_HARDWARE")
String[] getSupportedActivities();
/**
* Returns true if the given activity is supported, false otherwise.
*/
+ @EnforcePermission("LOCATION_HARDWARE")
boolean isActivitySupported(in String activityType);
/**
* Registers a sink with Hardware Activity-Recognition.
*/
+ @EnforcePermission("LOCATION_HARDWARE")
boolean registerSink(in IActivityRecognitionHardwareSink sink);
/**
* Unregisters a sink with Hardware Activity-Recognition.
*/
+ @EnforcePermission("LOCATION_HARDWARE")
boolean unregisterSink(in IActivityRecognitionHardwareSink sink);
/**
* Enables tracking of a given activity/event type, if the activity is supported.
*/
+ @EnforcePermission("LOCATION_HARDWARE")
boolean enableActivityEvent(in String activityType, int eventType, long reportLatencyNs);
/**
* Disables tracking of a given activity/eventy type.
*/
+ @EnforcePermission("LOCATION_HARDWARE")
boolean disableActivityEvent(in String activityType, int eventType);
/**
* Requests hardware for all the activity events detected up to the given point in time.
*/
+ @EnforcePermission("LOCATION_HARDWARE")
boolean flush();
}
\ No newline at end of file
diff --git a/core/java/android/hardware/location/IGeofenceHardware.aidl b/core/java/android/hardware/location/IGeofenceHardware.aidl
index 0e840c4..41804ad 100644
--- a/core/java/android/hardware/location/IGeofenceHardware.aidl
+++ b/core/java/android/hardware/location/IGeofenceHardware.aidl
@@ -26,17 +26,25 @@
interface IGeofenceHardware {
void setGpsGeofenceHardware(in IGpsGeofenceHardware service);
void setFusedGeofenceHardware(in IFusedGeofenceHardware service);
+ @EnforcePermission("LOCATION_HARDWARE")
int[] getMonitoringTypes();
+ @EnforcePermission("LOCATION_HARDWARE")
int getStatusOfMonitoringType(int monitoringType);
+ @EnforcePermission("LOCATION_HARDWARE")
boolean addCircularFence(
int monitoringType,
in GeofenceHardwareRequestParcelable request,
in IGeofenceHardwareCallback callback);
+ @EnforcePermission("LOCATION_HARDWARE")
boolean removeGeofence(int id, int monitoringType);
+ @EnforcePermission("LOCATION_HARDWARE")
boolean pauseGeofence(int id, int monitoringType);
+ @EnforcePermission("LOCATION_HARDWARE")
boolean resumeGeofence(int id, int monitoringType, int monitorTransitions);
+ @EnforcePermission("LOCATION_HARDWARE")
boolean registerForMonitorStateChangeCallback(int monitoringType,
IGeofenceHardwareMonitorCallback callback);
+ @EnforcePermission("LOCATION_HARDWARE")
boolean unregisterForMonitorStateChangeCallback(int monitoringType,
IGeofenceHardwareMonitorCallback callback);
}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index c02f870..c6fc9ec 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -2163,13 +2163,13 @@
mCandidatesVisibility = vis;
}
}
-
+
/**
* Returns the visibility mode (either {@link View#INVISIBLE View.INVISIBLE}
* or {@link View#GONE View.GONE}) of the candidates view when it is not
* shown. The default implementation returns GONE when
* {@link #isExtractViewShown} returns true,
- * otherwise VISIBLE. Be careful if you change this to return GONE in
+ * otherwise INVISIBLE. Be careful if you change this to return GONE in
* other situations -- if showing or hiding the candidates view causes
* your window to resize, this can cause temporary drawing artifacts as
* the resize takes place.
diff --git a/core/java/android/os/SystemClock.java b/core/java/android/os/SystemClock.java
index 7379443..ecea054 100644
--- a/core/java/android/os/SystemClock.java
+++ b/core/java/android/os/SystemClock.java
@@ -18,6 +18,8 @@
import android.annotation.NonNull;
import android.app.IAlarmManager;
+import android.app.timedetector.ITimeDetectorService;
+import android.app.timedetector.TimePoint;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.location.ILocationManager;
@@ -170,6 +172,14 @@
return false;
}
+ private static IAlarmManager getIAlarmManager() {
+ if (sIAlarmManager == null) {
+ sIAlarmManager = IAlarmManager.Stub
+ .asInterface(ServiceManager.getService(Context.ALARM_SERVICE));
+ }
+ return sIAlarmManager;
+ }
+
/**
* Returns milliseconds since boot, not counting time spent in deep sleep.
*
@@ -269,56 +279,71 @@
* <p>
* While the time returned by {@link System#currentTimeMillis()} can be
* adjusted by the user, the time returned by this method cannot be adjusted
- * by the user. Note that synchronization may occur using an insecure
- * network protocol, so the returned time should not be used for security
- * purposes.
+ * by the user.
* <p>
* This performs no blocking network operations and returns values based on
* a recent successful synchronization event; it will either return a valid
* time or throw.
+ * <p>
+ * Note that synchronization may occur using an insecure network protocol,
+ * so the returned time should not be used for security purposes.
+ * The device may resynchronize with the same or different network source
+ * at any time. Due to network delays, variations between servers, or local
+ * (client side) clock drift, the accuracy of the returned times cannot be
+ * guaranteed. In extreme cases, consecutive calls to {@link
+ * #currentNetworkTimeMillis()} could return times that are out of order.
*
- * @throws DateTimeException when no accurate network time can be provided.
+ * @throws DateTimeException when no network time can be provided.
* @hide
*/
public static long currentNetworkTimeMillis() {
- final IAlarmManager mgr = getIAlarmManager();
- if (mgr != null) {
+ ITimeDetectorService timeDetectorService = ITimeDetectorService.Stub
+ .asInterface(ServiceManager.getService(Context.TIME_DETECTOR_SERVICE));
+ if (timeDetectorService != null) {
+ TimePoint time;
try {
- return mgr.currentNetworkTimeMillis();
+ time = timeDetectorService.latestNetworkTime();
} catch (ParcelableException e) {
e.maybeRethrow(DateTimeException.class);
throw new RuntimeException(e);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
+
+ if (time == null) {
+ // This is not expected.
+ throw new DateTimeException("Network based time is not available.");
+ }
+ long currentMillis = elapsedRealtime();
+ long deltaMs = currentMillis - time.getElapsedRealtimeMillis();
+ return time.getUnixEpochTimeMillis() + deltaMs;
} else {
throw new RuntimeException(new DeadSystemException());
}
}
- private static IAlarmManager getIAlarmManager() {
- if (sIAlarmManager == null) {
- sIAlarmManager = IAlarmManager.Stub
- .asInterface(ServiceManager.getService(Context.ALARM_SERVICE));
- }
- return sIAlarmManager;
- }
-
- /**
+ /**
* Returns a {@link Clock} that starts at January 1, 1970 00:00:00.0 UTC,
* synchronized using a remote network source outside the device.
* <p>
* While the time returned by {@link System#currentTimeMillis()} can be
* adjusted by the user, the time returned by this method cannot be adjusted
- * by the user. Note that synchronization may occur using an insecure
- * network protocol, so the returned time should not be used for security
- * purposes.
+ * by the user.
* <p>
* This performs no blocking network operations and returns values based on
* a recent successful synchronization event; it will either return a valid
* time or throw.
+ * <p>
+ * Note that synchronization may occur using an insecure network protocol,
+ * so the returned time should not be used for security purposes.
+ * The device may resynchronize with the same or different network source
+ * at any time. Due to network delays, variations between servers, or local
+ * (client side) clock drift, the accuracy of the returned times cannot be
+ * guaranteed. In extreme cases, consecutive calls to {@link
+ * Clock#millis()} on the returned {@link Clock}could return times that are
+ * out of order.
*
- * @throws DateTimeException when no accurate network time can be provided.
+ * @throws DateTimeException when no network time can be provided.
*/
public static @NonNull Clock currentNetworkTimeClock() {
return new SimpleClock(ZoneOffset.UTC) {
diff --git a/core/java/android/util/NtpTrustedTime.java b/core/java/android/util/NtpTrustedTime.java
index 4e7b3a5..4a3f772 100644
--- a/core/java/android/util/NtpTrustedTime.java
+++ b/core/java/android/util/NtpTrustedTime.java
@@ -55,18 +55,19 @@
* @hide
*/
public static class TimeResult {
- private final long mTimeMillis;
+ private final long mUnixEpochTimeMillis;
private final long mElapsedRealtimeMillis;
private final long mCertaintyMillis;
- public TimeResult(long timeMillis, long elapsedRealtimeMillis, long certaintyMillis) {
- mTimeMillis = timeMillis;
+ public TimeResult(
+ long unixEpochTimeMillis, long elapsedRealtimeMillis, long certaintyMillis) {
+ mUnixEpochTimeMillis = unixEpochTimeMillis;
mElapsedRealtimeMillis = elapsedRealtimeMillis;
mCertaintyMillis = certaintyMillis;
}
public long getTimeMillis() {
- return mTimeMillis;
+ return mUnixEpochTimeMillis;
}
public long getElapsedRealtimeMillis() {
@@ -77,9 +78,11 @@
return mCertaintyMillis;
}
- /** Calculates and returns the current time accounting for the age of this result. */
+ /**
+ * Calculates and returns the current Unix epoch time accounting for the age of this result.
+ */
public long currentTimeMillis() {
- return mTimeMillis + getAgeMillis();
+ return mUnixEpochTimeMillis + getAgeMillis();
}
/** Calculates and returns the age of this result. */
@@ -99,7 +102,7 @@
@Override
public String toString() {
return "TimeResult{"
- + "mTimeMillis=" + Instant.ofEpochMilli(mTimeMillis)
+ + "mUnixEpochTimeMillis=" + Instant.ofEpochMilli(mUnixEpochTimeMillis)
+ ", mElapsedRealtimeMillis=" + Duration.ofMillis(mElapsedRealtimeMillis)
+ ", mCertaintyMillis=" + mCertaintyMillis
+ '}';
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index 872e65a..07dfce7 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -61,22 +61,32 @@
import com.android.internal.R;
/**
- * A Switch is a two-state toggle switch widget that can select between two
- * options. The user may drag the "thumb" back and forth to choose the selected option,
- * or simply tap to toggle as if it were a checkbox. The {@link #setText(CharSequence) text}
- * property controls the text displayed in the label for the switch, whereas the
- * {@link #setTextOff(CharSequence) off} and {@link #setTextOn(CharSequence) on} text
- * controls the text on the thumb. Similarly, the
- * {@link #setTextAppearance(android.content.Context, int) textAppearance} and the related
- * setTypeface() methods control the typeface and style of label text, whereas the
- * {@link #setSwitchTextAppearance(android.content.Context, int) switchTextAppearance} and
- * the related setSwitchTypeface() methods control that of the thumb.
+ * A Switch is a two-state toggle widget. Users can drag the switch "thumb" back
+ * and forth to select either of two options or simply tap the switch to toggle
+ * between options.
*
- * <p>{@link androidx.recyclerview.widget.RecyclerView} is a version of
- * the Switch widget which runs on devices back to API 7.</p>
+ * <p>The {@link #setText(CharSequence) text} property controls
+ * the text of the switch label. The {@link #setTextOn(CharSequence) textOn} and
+ * {@link #setTextOff(CharSequence) textOff} properties control the text of the
+ * thumb. The {@link #setTextAppearance(int) textAppearance} property and the
+ * related {@link #setTypeface(android.graphics.Typeface) setTypeface()} methods
+ * control the typeface and style of the switch label. The
+ * {@link #setSwitchTextAppearance(android.content.Context, int)
+ * switchTextAppearance} property and the related
+ * {@link #setSwitchTypeface(android.graphics.Typeface) setSwitchTypeface()}
+ * methods control the typeface and style of the thumb text.</p>
*
- * <p>See the <a href="{@docRoot}guide/topics/ui/controls/togglebutton.html">Toggle Buttons</a>
- * guide.</p>
+ * <p class="note"><b>Note:</b> The thumb text is displayed only if the
+ * <a href="{@docRoot}reference/android/widget/Switch#attr_android:showText">
+ * <code>showText</code></a> attribute is set to {@code true}. See also
+ * {@link #setShowText(boolean)} and {@link #getShowText()}.</p>
+ *
+ * <p>{@link androidx.appcompat.widget.SwitchCompat} provides backward
+ * compatibility down to Android 4.0 (API level 14).</p>
+ *
+ * <p>For more information, see the
+ * <a href="{@docRoot}guide/topics/ui/controls/togglebutton.html">
+ * Toggle Buttons</a> guide.</p>
*
* @attr ref android.R.styleable#Switch_textOn
* @attr ref android.R.styleable#Switch_textOff
diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp
index acadac7..bb4ab39 100644
--- a/core/jni/android_os_Parcel.cpp
+++ b/core/jni/android_os_Parcel.cpp
@@ -549,6 +549,11 @@
return NULL;
}
+ if (parcel->isForRpc()) {
+ jniThrowException(env, "java/lang/RuntimeException", "Tried to marshall an RPC Parcel.");
+ return NULL;
+ }
+
if (parcel->objectsCount())
{
jniThrowException(env, "java/lang/RuntimeException",
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java
index 14ba9df..764e650 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java
@@ -85,6 +85,8 @@
}
mDisplayAreasInfo.remove(displayId);
+ mLeashes.get(displayId).release();
+ mLeashes.remove(displayId);
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index fb61861..9df8251 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -530,7 +530,8 @@
}
final int taskId = taskInfo.taskId;
- final TaskListener listener = getTaskListener(mTasks.get(taskId).getTaskInfo());
+ final TaskAppearedInfo appearedInfo = mTasks.get(taskId);
+ final TaskListener listener = getTaskListener(appearedInfo.getTaskInfo());
mTasks.remove(taskId);
if (listener != null) {
listener.onTaskVanished(taskInfo);
@@ -540,6 +541,10 @@
notifyCompatUI(taskInfo, null /* taskListener */);
// Notify the recent tasks that a task has been removed
mRecentTasks.ifPresent(recentTasks -> recentTasks.onTaskRemoved(taskInfo));
+
+ if (appearedInfo.getLeash() != null) {
+ appearedInfo.getLeash().release();
+ }
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index f061f8b..e35e4ac 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -406,7 +406,9 @@
private boolean shouldDispatchToLauncher(int backType) {
return backType == BackNavigationInfo.TYPE_RETURN_TO_HOME
&& mBackToLauncherCallback != null
- && mEnableAnimations.get();
+ && mEnableAnimations.get()
+ && mBackNavigationInfo != null
+ && mBackNavigationInfo.getDepartingAnimationTarget() != null;
}
private static void dispatchOnBackStarted(IOnBackInvokedCallback callback) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java
index 3f7d78d..9478b34 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java
@@ -128,9 +128,10 @@
final WindowContainerTransaction wct = new WindowContainerTransaction();
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
- applyBoundsAndOffsets(
- displayAreaInfo.token, mDisplayAreaMap.get(displayAreaInfo.token), wct, t);
+ final SurfaceControl leash = mDisplayAreaMap.get(displayAreaInfo.token);
+ applyBoundsAndOffsets(displayAreaInfo.token, leash, wct, t);
applyTransaction(wct, t);
+ leash.release();
mDisplayAreaMap.remove(displayAreaInfo.token);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
index f61d1b9..451afa0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
@@ -159,6 +159,10 @@
@Override
public void onDisplayAreaVanished(@NonNull DisplayAreaInfo displayAreaInfo) {
+ final SurfaceControl leash = mDisplayAreaTokenMap.get(displayAreaInfo.token);
+ if (leash != null) {
+ leash.release();
+ }
mDisplayAreaTokenMap.remove(displayAreaInfo.token);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 22b0ccb..da88c2d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -943,6 +943,7 @@
mPipBoundsState.setBounds(new Rect());
mPipUiEventLoggerLogger.setTaskInfo(null);
mMainExecutor.executeDelayed(() -> mPipMenuController.detach(), 0);
+ mLeash = null;
if (info.displayId != Display.DEFAULT_DISPLAY && mOnDisplayIdChangeCallback != null) {
mOnDisplayIdChangeCallback.accept(Display.DEFAULT_DISPLAY);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 046b1a2..c8ee010 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -486,7 +486,15 @@
}
RemoteAnimationTarget[] onStartingSplitLegacy(RemoteAnimationTarget[] apps) {
- return reparentSplitTasksForAnimation(apps, false /*splitExpectedToBeVisible*/);
+ try {
+ return reparentSplitTasksForAnimation(apps, false /*splitExpectedToBeVisible*/);
+ } finally {
+ for (RemoteAnimationTarget appTarget : apps) {
+ if (appTarget.leash != null) {
+ appTarget.leash.release();
+ }
+ }
+ }
}
private RemoteAnimationTarget[] reparentSplitTasksForAnimation(RemoteAnimationTarget[] apps,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 55e7dac..70d728d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -1024,6 +1024,7 @@
}
mRootTaskInfo = null;
+ mRootTaskLeash = null;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index 99e7506..cb9e1a3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -243,6 +243,7 @@
if (mRootTaskInfo.taskId == taskId) {
mCallbacks.onRootTaskVanished();
mRootTaskInfo = null;
+ mRootLeash = null;
mSyncQueue.runInSync(t -> {
t.remove(mDimLayer);
mSplitDecorManager.release(t);
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
index 2b6c0da..ce624f2 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
@@ -16,7 +16,7 @@
package com.android.wm.shell.flicker.pip
-import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.launcher3.tapl.LauncherInstrumentation
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -51,7 +51,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Postsubmit
+@FlakyTest(bugId = 238367575)
@Group3
class AutoEnterPipOnGoToHomeTest(testSpec: FlickerTestParameter) : EnterPipTest(testSpec) {
protected val taplInstrumentation = LauncherInstrumentation()
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
index 0b53c40..4948158 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
@@ -46,6 +46,7 @@
import android.os.RemoteException;
import android.util.SparseArray;
import android.view.SurfaceControl;
+import android.view.SurfaceSession;
import android.window.ITaskOrganizer;
import android.window.ITaskOrganizerController;
import android.window.TaskAppearedInfo;
@@ -137,13 +138,25 @@
}
@Test
- public void registerOrganizer_sendRegisterTaskOrganizer() throws RemoteException {
+ public void testRegisterOrganizer_sendRegisterTaskOrganizer() throws RemoteException {
mOrganizer.registerOrganizer();
verify(mTaskOrganizerController).registerTaskOrganizer(any(ITaskOrganizer.class));
}
@Test
+ public void testTaskLeashReleasedAfterVanished() throws RemoteException {
+ RunningTaskInfo taskInfo = createTaskInfo(1, WINDOWING_MODE_MULTI_WINDOW);
+ SurfaceControl taskLeash = new SurfaceControl.Builder(new SurfaceSession())
+ .setName("task").build();
+ mOrganizer.registerOrganizer();
+ mOrganizer.onTaskAppeared(taskInfo, taskLeash);
+ assertTrue(taskLeash.isValid());
+ mOrganizer.onTaskVanished(taskInfo);
+ assertTrue(!taskLeash.isValid());
+ }
+
+ @Test
public void testOneListenerPerType() {
mOrganizer.addListenerForType(new TrackingTaskListener(), TASK_LISTENER_TYPE_MULTI_WINDOW);
try {
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index ded9597..546f0c6 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -1286,6 +1286,8 @@
/**
* Specifying if haptic should be muted or not when playing audio-haptic coupled data.
* By default, haptic channels are disabled.
+ * <p>This will be ignored if the caller doesn't have the
+ * {@link android.Manifest.permission#VIBRATE} permission.
* @param muted true to force muting haptic channels.
* @return the same Builder instance.
*/
diff --git a/media/java/android/media/audiofx/HapticGenerator.java b/media/java/android/media/audiofx/HapticGenerator.java
index fe7f29e..d2523ef 100644
--- a/media/java/android/media/audiofx/HapticGenerator.java
+++ b/media/java/android/media/audiofx/HapticGenerator.java
@@ -91,7 +91,8 @@
}
/**
- * Enable or disable the effect.
+ * Enable or disable the effect. The effect can only be enabled if the caller has the
+ * {@link android.Manifest.permission#VIBRATE} permission.
*
* @param enabled the requested enable state
* @return {@link #SUCCESS} in case of success, {@link #ERROR_INVALID_OPERATION}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
index db41601..a66dc77 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
@@ -427,18 +427,14 @@
mPipTransaction = null;
}
}
- // Release surface references now. This is apparently to free GPU
- // memory while doing quick operations (eg. during CTS).
- for (int i = 0; i < mLeashMap.size(); ++i) {
- if (mLeashMap.keyAt(i) == mLeashMap.valueAt(i)) continue;
- t.remove(mLeashMap.valueAt(i));
- }
try {
mFinishCB.onTransitionFinished(wct.isEmpty() ? null : wct, t);
} catch (RemoteException e) {
Log.e("RemoteTransitionCompat", "Failed to call animation finish callback", e);
t.apply();
}
+ // Only release the non-local created surface references. The animator is responsible
+ // for releasing the leashes created by local.
for (int i = 0; i < mInfo.getChanges().size(); ++i) {
mInfo.getChanges().get(i).getLeash().release();
}
diff --git a/packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt b/packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt
index 4986fe8..99267e8 100644
--- a/packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt
@@ -125,6 +125,13 @@
// launched from behind the lock-screen.
activityStarter.startActivity(intent, false /* dismissShade */)
}
+
+ // Call this to make sure that the keyguard returns if the app that is being launched
+ // crashes after a timeout.
+ centralSurfaces.startLaunchTransitionTimeout()
+ // Call this to make sure the keyguard is ready to be dismissed once the next intent is
+ // handled by the OS (in our case it is the activity we started right above)
+ centralSurfaces.readyForKeyguardDone()
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index 2fa104a..e73eaa1 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -176,7 +176,7 @@
// 1000 - dock
public static final BooleanFlag SIMULATE_DOCK_THROUGH_CHARGING =
new BooleanFlag(1000, true);
- public static final BooleanFlag DOCK_SETUP_ENABLED = new BooleanFlag(1001, false);
+ public static final BooleanFlag DOCK_SETUP_ENABLED = new BooleanFlag(1001, true);
// 1100 - windowing
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
index 2f732de..458ed40 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
@@ -144,8 +144,7 @@
animatedFraction)
// When crossfading, let's keep the bounds at the right location during fading
boundsProgress = if (animationCrossFadeProgress < 0.5f) 0.0f else 1.0f
- currentAlpha = calculateAlphaFromCrossFade(animationCrossFadeProgress,
- instantlyShowAtEnd = false)
+ currentAlpha = calculateAlphaFromCrossFade(animationCrossFadeProgress)
} else {
// If we're not crossfading, let's interpolate from the start alpha to 1.0f
currentAlpha = MathUtils.lerp(animationStartAlpha, 1.0f, animatedFraction)
@@ -276,7 +275,7 @@
if (value >= 0) {
updateTargetState()
// Setting the alpha directly, as the below call will use it to update the alpha
- carouselAlpha = calculateAlphaFromCrossFade(field, instantlyShowAtEnd = true)
+ carouselAlpha = calculateAlphaFromCrossFade(field)
applyTargetStateIfNotAnimating()
}
}
@@ -414,18 +413,10 @@
* @param crossFadeProgress The current cross fade progress. 0.5f means it's just switching
* between the start and the end location and the content is fully faded, while 0.75f means
* that we're halfway faded in again in the target state.
- *
- * @param instantlyShowAtEnd should the view be instantly shown at the end. This is needed
- * to avoid fadinging in when the target was hidden anyway.
*/
- private fun calculateAlphaFromCrossFade(
- crossFadeProgress: Float,
- instantlyShowAtEnd: Boolean
- ): Float {
+ private fun calculateAlphaFromCrossFade(crossFadeProgress: Float): Float {
if (crossFadeProgress <= 0.5f) {
return 1.0f - crossFadeProgress / 0.5f
- } else if (instantlyShowAtEnd) {
- return 1.0f
} else {
return (crossFadeProgress - 0.5f) / 0.5f
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 5f52485..281ef94 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -626,6 +626,7 @@
}
}, mainExecutor, bgExecutor);
+ mView.setBackgroundExecutor(bgExecutor);
mView.setEdgeBackGestureHandler(mEdgeBackGestureHandler);
mNavBarMode = mNavigationModeController.addListener(mModeChangedListener);
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index ad3cfa3..b01dca1 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -88,6 +88,7 @@
import java.io.PrintWriter;
import java.util.Map;
import java.util.Optional;
+import java.util.concurrent.Executor;
import java.util.function.Consumer;
/** */
@@ -97,6 +98,8 @@
final static boolean ALTERNATE_CAR_MODE_UI = false;
+ private Executor mBgExecutor;
+
// The current view is one of mHorizontal or mVertical depending on the current configuration
View mCurrentView = null;
private View mVertical;
@@ -349,6 +352,10 @@
notifyVerticalChangedListener(mIsVertical);
}
+ public void setBackgroundExecutor(Executor bgExecutor) {
+ mBgExecutor = bgExecutor;
+ }
+
public void setTouchHandler(Gefingerpoken touchHandler) {
mTouchHandler = touchHandler;
}
@@ -768,8 +775,8 @@
updateSlippery();
reloadNavIcons();
updateNavButtonIcons();
- WindowManagerWrapper.getInstance().setNavBarVirtualKeyHapticFeedbackEnabled(
- !mShowSwipeUpUi);
+ mBgExecutor.execute(() -> WindowManagerWrapper.getInstance()
+ .setNavBarVirtualKeyHapticFeedbackEnabled(!mShowSwipeUpUi));
getHomeButton().setAccessibilityDelegate(
mShowSwipeUpUi ? mQuickStepAccessibilityDelegate : null);
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt
index 8179d17..a833670 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt
@@ -321,7 +321,10 @@
velocityTracker = null
}
MotionEvent.ACTION_CANCEL -> {
- updateArrowState(GestureState.CANCELLED)
+ // Receiving a CANCEL implies that something else intercepted
+ // the gesture, i.e., the user did not cancel their gesture.
+ // Therefore, disappear immediately, with minimum fanfare.
+ updateArrowState(GestureState.GONE)
velocityTracker = null
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index fcafead..0697133 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -15,6 +15,7 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.Interpolator;
import android.view.animation.OvershootInterpolator;
@@ -626,6 +627,16 @@
}
}
+ @Override
+ public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+ super.onInitializeAccessibilityEvent(event);
+ if (mAdapter != null && mAdapter.getCount() > 0) {
+ event.setItemCount(mAdapter.getCount());
+ event.setFromIndex(getCurrentPageNumber());
+ event.setToIndex(getCurrentPageNumber());
+ }
+ }
+
private static Animator setupBounceAnimator(View view, int ordinal) {
view.setAlpha(0f);
view.setScaleX(0f);
diff --git a/services/core/java/com/android/server/notification/PermissionHelper.java b/services/core/java/com/android/server/notification/PermissionHelper.java
index 09ed567..1b66932 100644
--- a/services/core/java/com/android/server/notification/PermissionHelper.java
+++ b/services/core/java/com/android/server/notification/PermissionHelper.java
@@ -16,6 +16,7 @@
package com.android.server.notification;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -175,12 +176,15 @@
mPermManager.revokeRuntimePermission(packageName, NOTIFICATION_PERMISSION,
userId, TAG);
}
+ int flagMask = userSet || !grant
+ ? FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_GRANTED_BY_DEFAULT :
+ FLAG_PERMISSION_USER_SET;
if (userSet) {
mPermManager.updatePermissionFlags(packageName, NOTIFICATION_PERMISSION,
- FLAG_PERMISSION_USER_SET, FLAG_PERMISSION_USER_SET, true, userId);
+ flagMask, FLAG_PERMISSION_USER_SET, true, userId);
} else {
mPermManager.updatePermissionFlags(packageName, NOTIFICATION_PERMISSION,
- 0, FLAG_PERMISSION_USER_SET, true, userId);
+ flagMask, 0, true, userId);
}
} catch (RemoteException e) {
Slog.e(TAG, "Could not reach system server", e);
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index d68cecb..89bb17f3 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -473,9 +473,13 @@
mApexManager.registerApkInApex(pkg);
}
- // Add the package's KeySets to the global KeySetManagerService
- KeySetManagerService ksms = mPm.mSettings.getKeySetManagerService();
- ksms.addScannedPackageLPw(pkg);
+ // Don't add keysets for APEX as their package settings are not persisted and will
+ // result in orphaned keysets.
+ if ((scanFlags & SCAN_AS_APEX) == 0) {
+ // Add the package's KeySets to the global KeySetManagerService
+ KeySetManagerService ksms = mPm.mSettings.getKeySetManagerService();
+ ksms.addScannedPackageLPw(pkg);
+ }
final Computer snapshot = mPm.snapshotComputer();
mPm.mComponentResolver.addAllComponents(pkg, chatty, mPm.mSetupWizardPackage, snapshot);
@@ -3464,8 +3468,9 @@
}
// Sort the list to ensure we always process factory packages first
Collections.sort(parseResults, (a, b) -> {
- ApexInfo ai = parsingApexInfo.get(a.scanFile);
- return ai.isFactory ? -1 : 1;
+ ApexInfo i1 = parsingApexInfo.get(a.scanFile);
+ ApexInfo i2 = parsingApexInfo.get(b.scanFile);
+ return Boolean.compare(i2.isFactory, i1.isFactory);
});
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorInternal.java b/services/core/java/com/android/server/timedetector/TimeDetectorInternal.java
new file mode 100644
index 0000000..181f5ad
--- /dev/null
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorInternal.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timedetector;
+
+/**
+ * The internal (in-process) system server API for the {@link
+ * com.android.server.timedetector.TimeDetectorService}.
+ *
+ * <p>The methods on this class can be called from any thread.
+ * @hide
+ */
+public interface TimeDetectorInternal {
+
+}
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorInternalImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorInternalImpl.java
new file mode 100644
index 0000000..1b47ebb
--- /dev/null
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorInternalImpl.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timedetector;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.os.Handler;
+
+import java.util.Objects;
+
+/**
+ * The real {@link TimeDetectorInternal} local service implementation.
+ *
+ * @hide
+ */
+public class TimeDetectorInternalImpl implements TimeDetectorInternal {
+
+ @NonNull private final Context mContext;
+ @NonNull private final Handler mHandler;
+ @NonNull private final TimeDetectorStrategy mTimeDetectorStrategy;
+
+ public TimeDetectorInternalImpl(@NonNull Context context, @NonNull Handler handler,
+ @NonNull TimeDetectorStrategy timeDetectorStrategy) {
+ mContext = Objects.requireNonNull(context);
+ mHandler = Objects.requireNonNull(handler);
+ mTimeDetectorStrategy = Objects.requireNonNull(timeDetectorStrategy);
+ }
+}
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorService.java b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
index 105cd78..02d3487 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorService.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
@@ -29,15 +29,18 @@
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.TelephonyTimeSuggestion;
+import android.app.timedetector.TimePoint;
import android.content.Context;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
+import android.os.ParcelableException;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.util.ArrayMap;
import android.util.IndentingPrintWriter;
+import android.util.NtpTrustedTime;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
@@ -49,6 +52,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.time.DateTimeException;
import java.util.Objects;
/**
@@ -79,6 +83,11 @@
TimeDetectorStrategy timeDetectorStrategy =
TimeDetectorStrategyImpl.create(context, handler, serviceConfigAccessor);
+ // Create and publish the local service for use by internal callers.
+ TimeDetectorInternal internal =
+ new TimeDetectorInternalImpl(context, handler, timeDetectorStrategy);
+ publishLocalService(TimeDetectorInternal.class, internal);
+
TimeDetectorService service = new TimeDetectorService(
context, handler, serviceConfigAccessor, timeDetectorStrategy);
@@ -93,6 +102,7 @@
@NonNull private final CallerIdentityInjector mCallerIdentityInjector;
@NonNull private final ServiceConfigAccessor mServiceConfigAccessor;
@NonNull private final TimeDetectorStrategy mTimeDetectorStrategy;
+ @NonNull private final NtpTrustedTime mNtpTrustedTime;
/**
* Holds the listeners. The key is the {@link IBinder} associated with the listener, the value
@@ -107,19 +117,21 @@
@NonNull ServiceConfigAccessor serviceConfigAccessor,
@NonNull TimeDetectorStrategy timeDetectorStrategy) {
this(context, handler, serviceConfigAccessor, timeDetectorStrategy,
- CallerIdentityInjector.REAL);
+ CallerIdentityInjector.REAL, NtpTrustedTime.getInstance(context));
}
@VisibleForTesting
public TimeDetectorService(@NonNull Context context, @NonNull Handler handler,
@NonNull ServiceConfigAccessor serviceConfigAccessor,
@NonNull TimeDetectorStrategy timeDetectorStrategy,
- @NonNull CallerIdentityInjector callerIdentityInjector) {
+ @NonNull CallerIdentityInjector callerIdentityInjector,
+ @NonNull NtpTrustedTime ntpTrustedTime) {
mContext = Objects.requireNonNull(context);
mHandler = Objects.requireNonNull(handler);
mServiceConfigAccessor = Objects.requireNonNull(serviceConfigAccessor);
mTimeDetectorStrategy = Objects.requireNonNull(timeDetectorStrategy);
mCallerIdentityInjector = Objects.requireNonNull(callerIdentityInjector);
+ mNtpTrustedTime = Objects.requireNonNull(ntpTrustedTime);
// Wire up a change listener so that ITimeZoneDetectorListeners can be notified when
// the configuration changes for any reason.
@@ -308,6 +320,19 @@
}
@Override
+ public TimePoint latestNetworkTime() {
+ // TODO(b/222295093): Return the latest network time from mTimeDetectorStrategy once we can
+ // be sure that all uses of NtpTrustedTime results in a suggestion being made to the time
+ // detector. mNtpTrustedTime can be removed once this happens.
+ NtpTrustedTime.TimeResult ntpResult = mNtpTrustedTime.getCachedTimeResult();
+ if (ntpResult != null) {
+ return new TimePoint(ntpResult.getTimeMillis(), ntpResult.getElapsedRealtimeMillis());
+ } else {
+ throw new ParcelableException(new DateTimeException("Missing network time fix"));
+ }
+ }
+
+ @Override
protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw,
@Nullable String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index c2b6b19..fa8ea76 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -7733,9 +7733,6 @@
// relatively fixed.
overrideConfig.colorMode = fullConfig.colorMode;
overrideConfig.densityDpi = fullConfig.densityDpi;
- // The smallest screen width is the short side of screen bounds. Because the bounds
- // and density won't be changed, smallestScreenWidthDp is also fixed.
- overrideConfig.smallestScreenWidthDp = fullConfig.smallestScreenWidthDp;
if (info.isFixedOrientation()) {
// lock rotation too. When in size-compat, onConfigurationChanged will watch for and
// apply runtime rotation changes.
@@ -7832,7 +7829,7 @@
// computed accordingly.
if (!matchParentBounds()) {
getTaskFragment().computeConfigResourceOverrides(resolvedConfig,
- newParentConfiguration);
+ newParentConfiguration, areBoundsLetterboxed());
}
// If activity in fullscreen mode is letterboxed because of fixed orientation then bounds
// are already calculated in resolveFixedOrientationConfiguration.
@@ -8003,7 +8000,8 @@
}
// Since bounds has changed, the configuration needs to be computed accordingly.
- getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration);
+ getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
+ areBoundsLetterboxed());
}
void recomputeConfiguration() {
@@ -8219,7 +8217,7 @@
// Calculate app bounds using fixed orientation bounds because they will be needed later
// for comparison with size compat app bounds in {@link resolveSizeCompatModeConfiguration}.
getTaskFragment().computeConfigResourceOverrides(getResolvedOverrideConfiguration(),
- newParentConfig);
+ newParentConfig, mCompatDisplayInsets, areBoundsLetterboxed());
mLetterboxBoundsForFixedOrientationAndAspectRatio = new Rect(resolvedBounds);
}
@@ -8247,7 +8245,7 @@
// Compute the configuration based on the resolved bounds. If aspect ratio doesn't
// restrict, the bounds should be the requested override bounds.
getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
- getFixedRotationTransformDisplayInfo());
+ getFixedRotationTransformDisplayInfo(), areBoundsLetterboxed());
}
}
@@ -8311,7 +8309,7 @@
// are calculated in compat container space. The actual position on screen will be applied
// later, so the calculation is simpler that doesn't need to involve offset from parent.
getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
- mCompatDisplayInsets);
+ mCompatDisplayInsets, areBoundsLetterboxed());
// Use current screen layout as source because the size of app is independent to parent.
resolvedConfig.screenLayout = TaskFragment.computeScreenLayoutOverride(
getConfiguration().screenLayout, resolvedConfig.screenWidthDp,
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index d07cc68..9295c18 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -112,6 +112,7 @@
RemoteAnimationTarget topAppTarget = null;
int prevTaskId;
int prevUserId;
+ boolean prepareAnimation;
BackNavigationInfo.Builder infoBuilder = new BackNavigationInfo.Builder();
synchronized (wmService.mGlobalLock) {
@@ -257,7 +258,8 @@
BackNavigationInfo.typeToString(backType));
// For now, we only animate when going home.
- boolean prepareAnimation = backType == BackNavigationInfo.TYPE_RETURN_TO_HOME
+ prepareAnimation = backType == BackNavigationInfo.TYPE_RETURN_TO_HOME
+ && requestAnimation
// Only create a new leash if no leash has been created.
// Otherwise return null for animation target to avoid conflict.
&& !removedWindowContainer.hasCommittedReparentToAnimationLeash();
@@ -292,7 +294,7 @@
}
// Special handling for back to home animation
- if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && requestAnimation
+ if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && prepareAnimation
&& prevTask != null) {
currentTask.mBackGestureStarted = true;
// Make launcher show from behind by marking its top activity as visible and
@@ -347,7 +349,7 @@
Task finalTask = currentTask;
RemoteCallback onBackNavigationDone = new RemoteCallback(result -> onBackNavigationDone(
result, finalRemovedWindowContainer, finalBackType, finalTask,
- finalprevActivity, requestAnimation));
+ finalprevActivity, prepareAnimation));
infoBuilder.setOnBackNavigationDone(onBackNavigationDone);
}
@@ -381,14 +383,14 @@
private void onBackNavigationDone(
Bundle result, WindowContainer<?> windowContainer, int backType,
- Task task, ActivityRecord prevActivity, boolean requestAnimation) {
+ Task task, ActivityRecord prevActivity, boolean prepareAnimation) {
SurfaceControl surfaceControl = windowContainer.getSurfaceControl();
boolean triggerBack = result != null && result.getBoolean(
BackNavigationInfo.KEY_TRIGGER_BACK);
ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "onBackNavigationDone backType=%s, "
+ "task=%s, prevActivity=%s", backType, task, prevActivity);
- if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && requestAnimation) {
+ if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && prepareAnimation) {
if (triggerBack) {
if (surfaceControl != null && surfaceControl.isValid()) {
// When going back to home, hide the task surface before it is re-parented to
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 3e6546e..23adee6 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -1957,29 +1957,37 @@
void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
@NonNull Configuration parentConfig) {
computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */,
- null /* compatInsets */);
+ null /* compatInsets */, false /* areBoundsLetterboxed */);
}
void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
- @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo) {
+ @NonNull Configuration parentConfig, boolean areBoundsLetterboxed) {
+ computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */,
+ null /* compatInsets */, areBoundsLetterboxed);
+ }
+
+ void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
+ @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo,
+ boolean areBoundsLetterboxed) {
if (overrideDisplayInfo != null) {
// Make sure the screen related configs can be computed by the provided display info.
inOutConfig.screenLayout = Configuration.SCREENLAYOUT_UNDEFINED;
invalidateAppBoundsConfig(inOutConfig);
}
computeConfigResourceOverrides(inOutConfig, parentConfig, overrideDisplayInfo,
- null /* compatInsets */);
+ null /* compatInsets */, areBoundsLetterboxed);
}
void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
@NonNull Configuration parentConfig,
- @Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
+ @Nullable ActivityRecord.CompatDisplayInsets compatInsets,
+ boolean areBoundsLetterboxed) {
if (compatInsets != null) {
// Make sure the app bounds can be computed by the compat insets.
invalidateAppBoundsConfig(inOutConfig);
}
computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */,
- compatInsets);
+ compatInsets, areBoundsLetterboxed);
}
/**
@@ -2006,7 +2014,8 @@
**/
void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
@NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo,
- @Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
+ @Nullable ActivityRecord.CompatDisplayInsets compatInsets,
+ boolean areBoundsLetterboxed) {
int windowingMode = inOutConfig.windowConfiguration.getWindowingMode();
if (windowingMode == WINDOWING_MODE_UNDEFINED) {
windowingMode = parentConfig.windowConfiguration.getWindowingMode();
@@ -2113,6 +2122,7 @@
: overrideScreenHeightDp;
}
+ // TODO(b/238331848): Consider simplifying logic that computes smallestScreenWidthDp.
if (inOutConfig.smallestScreenWidthDp
== Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
// When entering to or exiting from Pip, the PipTaskOrganizer will set the
@@ -2128,9 +2138,10 @@
// task, because they should not be affected by insets.
inOutConfig.smallestScreenWidthDp = (int) (0.5f
+ Math.min(mTmpFullBounds.width(), mTmpFullBounds.height()) / density);
- } else if (isEmbedded()) {
- // For embedded TFs, the smallest width should be updated. Otherwise, inherit
- // from the parent task would result in applications loaded wrong resource.
+ } else if (isEmbedded() || areBoundsLetterboxed || customContainerPolicy) {
+ // For embedded TFs and activities that are letteboxed or eligible for size
+ // compat mode, the smallest width should be updated. Otherwise, inherit from
+ // the parent task would result in applications loaded wrong resource.
inOutConfig.smallestScreenWidthDp =
Math.min(inOutConfig.screenWidthDp, inOutConfig.screenHeightDp);
}
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 27d181f..8b71a34 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -527,11 +527,12 @@
mService.mRootWindowContainer.forAllTasks((task) -> {
boolean returnTask = !task.mCreatedByOrganizer;
task.updateTaskOrganizerState(returnTask /* skipTaskAppeared */);
- if (returnTask) {
- SurfaceControl outSurfaceControl = state.addTaskWithoutCallback(task,
+ // It is possible for the task to not yet have a surface control, so ensure that
+ // the update succeeded in setting the organizer for the task before returning
+ if (task.isOrganized() && returnTask) {
+ SurfaceControl taskLeash = state.addTaskWithoutCallback(task,
"TaskOrganizerController.registerTaskOrganizer");
- taskInfos.add(
- new TaskAppearedInfo(task.getTaskInfo(), outSurfaceControl));
+ taskInfos.add(new TaskAppearedInfo(task.getTaskInfo(), taskLeash));
}
});
};
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 24a478e..33b4982 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -3756,6 +3756,15 @@
* hierarchy change implies a configuration change.
*/
private void onSyncReparent(WindowContainer oldParent, WindowContainer newParent) {
+ // Check if this is changing displays. If so, mark the old display as "ready" for
+ // transitions. This is to work around the problem where setting readiness against this
+ // container will only set the new display as ready and leave the old display as unready.
+ if (mSyncState != SYNC_STATE_NONE && oldParent != null
+ && oldParent.getDisplayContent() != null && (newParent == null
+ || oldParent.getDisplayContent() != newParent.getDisplayContent())) {
+ mTransitionController.setReady(oldParent.getDisplayContent());
+ }
+
if (newParent == null || newParent.mSyncState == SYNC_STATE_NONE) {
if (mSyncState == SYNC_STATE_NONE) {
return;
diff --git a/services/tests/apexsystemservices/Android.bp b/services/tests/apexsystemservices/Android.bp
index a6ed1ae..e724e804 100644
--- a/services/tests/apexsystemservices/Android.bp
+++ b/services/tests/apexsystemservices/Android.bp
@@ -39,6 +39,6 @@
],
test_suites: [
"device-tests",
- "mts-core",
+ "mts-mainline-infra",
],
}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/FakeTimeDetectorStrategy.java b/services/tests/servicestests/src/com/android/server/timedetector/FakeTimeDetectorStrategy.java
new file mode 100644
index 0000000..d016d7e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timedetector/FakeTimeDetectorStrategy.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timedetector;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.annotation.UserIdInt;
+import android.app.time.ExternalTimeSuggestion;
+import android.app.timedetector.GnssTimeSuggestion;
+import android.app.timedetector.ManualTimeSuggestion;
+import android.app.timedetector.NetworkTimeSuggestion;
+import android.app.timedetector.TelephonyTimeSuggestion;
+import android.util.IndentingPrintWriter;
+
+/**
+ * A fake implementation of {@link com.android.server.timedetector.TimeDetectorStrategy} for use
+ * in tests.
+ */
+class FakeTimeDetectorStrategy implements TimeDetectorStrategy {
+
+ // Call tracking.
+ private TelephonyTimeSuggestion mLastTelephonySuggestion;
+ private @UserIdInt Integer mLastManualSuggestionUserId;
+ private ManualTimeSuggestion mLastManualSuggestion;
+ private NetworkTimeSuggestion mLastNetworkSuggestion;
+ private GnssTimeSuggestion mLastGnssSuggestion;
+ private ExternalTimeSuggestion mLastExternalSuggestion;
+ private boolean mDumpCalled;
+
+ @Override
+ public void suggestTelephonyTime(TelephonyTimeSuggestion timeSuggestion) {
+ mLastTelephonySuggestion = timeSuggestion;
+ }
+
+ @Override
+ public boolean suggestManualTime(@UserIdInt int userId, ManualTimeSuggestion timeSuggestion) {
+ mLastManualSuggestionUserId = userId;
+ mLastManualSuggestion = timeSuggestion;
+ return true;
+ }
+
+ @Override
+ public void suggestNetworkTime(NetworkTimeSuggestion timeSuggestion) {
+ mLastNetworkSuggestion = timeSuggestion;
+ }
+
+ @Override
+ public void suggestGnssTime(GnssTimeSuggestion timeSuggestion) {
+ mLastGnssSuggestion = timeSuggestion;
+ }
+
+ @Override
+ public void suggestExternalTime(ExternalTimeSuggestion timeSuggestion) {
+ mLastExternalSuggestion = timeSuggestion;
+ }
+
+ @Override
+ public void dump(IndentingPrintWriter pw, String[] args) {
+ mDumpCalled = true;
+ }
+
+ void resetCallTracking() {
+ mLastTelephonySuggestion = null;
+ mLastManualSuggestionUserId = null;
+ mLastManualSuggestion = null;
+ mLastNetworkSuggestion = null;
+ mLastGnssSuggestion = null;
+ mLastExternalSuggestion = null;
+ mDumpCalled = false;
+ }
+
+ void verifySuggestTelephonyTimeCalled(TelephonyTimeSuggestion expectedSuggestion) {
+ assertEquals(expectedSuggestion, mLastTelephonySuggestion);
+ }
+
+ void verifySuggestManualTimeCalled(
+ @UserIdInt int expectedUserId, ManualTimeSuggestion expectedSuggestion) {
+ assertEquals((Integer) expectedUserId, mLastManualSuggestionUserId);
+ assertEquals(expectedSuggestion, mLastManualSuggestion);
+ }
+
+ void verifySuggestNetworkTimeCalled(NetworkTimeSuggestion expectedSuggestion) {
+ assertEquals(expectedSuggestion, mLastNetworkSuggestion);
+ }
+
+ void verifySuggestGnssTimeCalled(GnssTimeSuggestion expectedSuggestion) {
+ assertEquals(expectedSuggestion, mLastGnssSuggestion);
+ }
+
+ void verifySuggestExternalTimeCalled(ExternalTimeSuggestion expectedSuggestion) {
+ assertEquals(expectedSuggestion, mLastExternalSuggestion);
+ }
+
+ void verifyDumpCalled() {
+ assertTrue(mDumpCalled);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorInternalImplTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorInternalImplTest.java
new file mode 100644
index 0000000..06512fb
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorInternalImplTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timedetector;
+
+import static org.mockito.Mockito.mock;
+
+import android.content.Context;
+import android.os.HandlerThread;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.timezonedetector.TestHandler;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class TimeDetectorInternalImplTest {
+
+ private Context mMockContext;
+ private FakeTimeDetectorStrategy mFakeTimeDetectorStrategy;
+
+ private TimeDetectorInternalImpl mTimeDetectorInternal;
+ private HandlerThread mHandlerThread;
+ private TestHandler mTestHandler;
+
+ @Before
+ public void setUp() {
+ mMockContext = mock(Context.class);
+
+ // Create a thread + handler for processing the work that the service posts.
+ mHandlerThread = new HandlerThread("TimeDetectorInternalTest");
+ mHandlerThread.start();
+ mTestHandler = new TestHandler(mHandlerThread.getLooper());
+
+ mFakeTimeDetectorStrategy = new FakeTimeDetectorStrategy();
+
+ mTimeDetectorInternal = new TimeDetectorInternalImpl(
+ mMockContext, mTestHandler, mFakeTimeDetectorStrategy);
+ }
+
+ @Test
+ public void placeholder() {
+ // A placeholder test until there are real methods to test.
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mHandlerThread.quit();
+ mHandlerThread.join();
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
index e9617e9..702ebeb 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
@@ -19,6 +19,7 @@
import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_NETWORK;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
@@ -41,12 +42,14 @@
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.TelephonyTimeSuggestion;
+import android.app.timedetector.TimePoint;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.HandlerThread;
import android.os.IBinder;
+import android.os.ParcelableException;
import android.os.TimestampedValue;
-import android.util.IndentingPrintWriter;
+import android.util.NtpTrustedTime;
import androidx.test.runner.AndroidJUnit4;
@@ -77,7 +80,8 @@
private TestHandler mTestHandler;
private TestCallerIdentityInjector mTestCallerIdentityInjector;
private FakeServiceConfigAccessor mFakeServiceConfigAccessor;
- private StubbedTimeDetectorStrategy mStubbedTimeDetectorStrategy;
+ private NtpTrustedTime mMockNtpTrustedTime;
+ private FakeTimeDetectorStrategy mFakeTimeDetectorStrategy;
@Before
@@ -92,12 +96,13 @@
mTestCallerIdentityInjector = new TestCallerIdentityInjector();
mTestCallerIdentityInjector.initializeCallingUserId(ARBITRARY_USER_ID);
- mStubbedTimeDetectorStrategy = new StubbedTimeDetectorStrategy();
+ mFakeTimeDetectorStrategy = new FakeTimeDetectorStrategy();
mFakeServiceConfigAccessor = new FakeServiceConfigAccessor();
+ mMockNtpTrustedTime = mock(NtpTrustedTime.class);
mTimeDetectorService = new TimeDetectorService(
mMockContext, mTestHandler, mFakeServiceConfigAccessor,
- mStubbedTimeDetectorStrategy, mTestCallerIdentityInjector);
+ mFakeTimeDetectorStrategy, mTestCallerIdentityInjector, mMockNtpTrustedTime);
}
@After
@@ -275,7 +280,7 @@
anyString());
mTestHandler.waitForMessagesToBeProcessed();
- mStubbedTimeDetectorStrategy.verifySuggestTelephonyTimeCalled(timeSuggestion);
+ mFakeTimeDetectorStrategy.verifySuggestTelephonyTimeCalled(timeSuggestion);
}
@Test(expected = SecurityException.class)
@@ -301,7 +306,8 @@
ManualTimeSuggestion manualTimeSuggestion = createManualTimeSuggestion();
assertTrue(mTimeDetectorService.suggestManualTime(manualTimeSuggestion));
- mStubbedTimeDetectorStrategy.verifySuggestManualTimeCalled(manualTimeSuggestion);
+ mFakeTimeDetectorStrategy.verifySuggestManualTimeCalled(
+ mTestCallerIdentityInjector.getCallingUserId(), manualTimeSuggestion);
verify(mMockContext).enforceCallingOrSelfPermission(
eq(android.Manifest.permission.SUGGEST_MANUAL_TIME_AND_ZONE),
@@ -336,7 +342,7 @@
eq(android.Manifest.permission.SET_TIME), anyString());
mTestHandler.waitForMessagesToBeProcessed();
- mStubbedTimeDetectorStrategy.verifySuggestNetworkTimeCalled(NetworkTimeSuggestion);
+ mFakeTimeDetectorStrategy.verifySuggestNetworkTimeCalled(NetworkTimeSuggestion);
}
@Test(expected = SecurityException.class)
@@ -366,7 +372,7 @@
eq(android.Manifest.permission.SET_TIME), anyString());
mTestHandler.waitForMessagesToBeProcessed();
- mStubbedTimeDetectorStrategy.verifySuggestGnssTimeCalled(gnssTimeSuggestion);
+ mFakeTimeDetectorStrategy.verifySuggestGnssTimeCalled(gnssTimeSuggestion);
}
@Test(expected = SecurityException.class)
@@ -396,7 +402,24 @@
eq(android.Manifest.permission.SUGGEST_EXTERNAL_TIME), anyString());
mTestHandler.waitForMessagesToBeProcessed();
- mStubbedTimeDetectorStrategy.verifySuggestExternalTimeCalled(externalTimeSuggestion);
+ mFakeTimeDetectorStrategy.verifySuggestExternalTimeCalled(externalTimeSuggestion);
+ }
+
+ @Test
+ public void testLatestNetworkTime() {
+ NtpTrustedTime.TimeResult latestNetworkTime =
+ new NtpTrustedTime.TimeResult(1234L, 54321L, 999L);
+ when(mMockNtpTrustedTime.getCachedTimeResult())
+ .thenReturn(latestNetworkTime);
+ TimePoint expected = new TimePoint(latestNetworkTime.getTimeMillis(),
+ latestNetworkTime.getElapsedRealtimeMillis());
+ assertEquals(expected, mTimeDetectorService.latestNetworkTime());
+ }
+
+ @Test
+ public void testLatestNetworkTime_noTimeAvailable() {
+ when(mMockNtpTrustedTime.getCachedTimeResult()).thenReturn(null);
+ assertThrows(ParcelableException.class, () -> mTimeDetectorService.latestNetworkTime());
}
@Test
@@ -408,7 +431,7 @@
mTimeDetectorService.dump(null, pw, null);
verify(mMockContext).checkCallingOrSelfPermission(eq(android.Manifest.permission.DUMP));
- mStubbedTimeDetectorStrategy.verifyDumpCalled();
+ mFakeTimeDetectorStrategy.verifyDumpCalled();
}
private static TimeConfiguration createTimeConfiguration(boolean autoDetectionEnabled) {
@@ -455,79 +478,4 @@
private static ExternalTimeSuggestion createExternalTimeSuggestion() {
return new ExternalTimeSuggestion(100L, 1_000_000L);
}
-
- private static class StubbedTimeDetectorStrategy implements TimeDetectorStrategy {
-
- // Call tracking.
- private TelephonyTimeSuggestion mLastTelephonySuggestion;
- private ManualTimeSuggestion mLastManualSuggestion;
- private NetworkTimeSuggestion mLastNetworkSuggestion;
- private GnssTimeSuggestion mLastGnssSuggestion;
- private ExternalTimeSuggestion mLastExternalSuggestion;
- private boolean mDumpCalled;
-
- @Override
- public void suggestTelephonyTime(TelephonyTimeSuggestion timeSuggestion) {
- mLastTelephonySuggestion = timeSuggestion;
- }
-
- @Override
- public boolean suggestManualTime(int userId, ManualTimeSuggestion timeSuggestion) {
- mLastManualSuggestion = timeSuggestion;
- return true;
- }
-
- @Override
- public void suggestNetworkTime(NetworkTimeSuggestion timeSuggestion) {
- mLastNetworkSuggestion = timeSuggestion;
- }
-
- @Override
- public void suggestGnssTime(GnssTimeSuggestion timeSuggestion) {
- mLastGnssSuggestion = timeSuggestion;
- }
-
- @Override
- public void suggestExternalTime(ExternalTimeSuggestion timeSuggestion) {
- mLastExternalSuggestion = timeSuggestion;
- }
-
- @Override
- public void dump(IndentingPrintWriter pw, String[] args) {
- mDumpCalled = true;
- }
-
- void resetCallTracking() {
- mLastTelephonySuggestion = null;
- mLastManualSuggestion = null;
- mLastNetworkSuggestion = null;
- mLastGnssSuggestion = null;
- mLastExternalSuggestion = null;
- mDumpCalled = false;
- }
-
- void verifySuggestTelephonyTimeCalled(TelephonyTimeSuggestion expectedSuggestion) {
- assertEquals(expectedSuggestion, mLastTelephonySuggestion);
- }
-
- void verifySuggestManualTimeCalled(ManualTimeSuggestion expectedSuggestion) {
- assertEquals(expectedSuggestion, mLastManualSuggestion);
- }
-
- void verifySuggestNetworkTimeCalled(NetworkTimeSuggestion expectedSuggestion) {
- assertEquals(expectedSuggestion, mLastNetworkSuggestion);
- }
-
- void verifySuggestGnssTimeCalled(GnssTimeSuggestion expectedSuggestion) {
- assertEquals(expectedSuggestion, mLastGnssSuggestion);
- }
-
- void verifySuggestExternalTimeCalled(ExternalTimeSuggestion expectedSuggestion) {
- assertEquals(expectedSuggestion, mLastExternalSuggestion);
- }
-
- void verifyDumpCalled() {
- assertTrue(mDumpCalled);
- }
- }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java
index 4c7e843..d4886e4 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java
@@ -183,7 +183,8 @@
verify(mPermManager).grantRuntimePermission(
"pkg", Manifest.permission.POST_NOTIFICATIONS, 10);
verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS,
- FLAG_PERMISSION_USER_SET, FLAG_PERMISSION_USER_SET, true, 10);
+ FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_GRANTED_BY_DEFAULT,
+ FLAG_PERMISSION_USER_SET, true, 10);
}
@Test
@@ -201,7 +202,8 @@
verify(mPermManager).grantRuntimePermission(
"pkg", Manifest.permission.POST_NOTIFICATIONS, 10);
verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS,
- FLAG_PERMISSION_USER_SET, FLAG_PERMISSION_USER_SET, true, 10);
+ FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_GRANTED_BY_DEFAULT,
+ FLAG_PERMISSION_USER_SET, true, 10);
}
@Test
@@ -214,7 +216,8 @@
verify(mPermManager).revokeRuntimePermission(
eq("pkg"), eq(Manifest.permission.POST_NOTIFICATIONS), eq(10), anyString());
verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS,
- FLAG_PERMISSION_USER_SET, FLAG_PERMISSION_USER_SET, true, 10);
+ FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_GRANTED_BY_DEFAULT,
+ FLAG_PERMISSION_USER_SET, true, 10);
}
@Test
@@ -227,7 +230,7 @@
verify(mPermManager).grantRuntimePermission(
"pkg", Manifest.permission.POST_NOTIFICATIONS, 10);
verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS,
- 0, FLAG_PERMISSION_USER_SET, true, 10);
+ FLAG_PERMISSION_USER_SET, 0, true, 10);
}
@Test
@@ -240,7 +243,8 @@
verify(mPermManager).revokeRuntimePermission(
eq("pkg"), eq(Manifest.permission.POST_NOTIFICATIONS), eq(10), anyString());
verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS,
- 0, FLAG_PERMISSION_USER_SET, true, 10);
+ FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_GRANTED_BY_DEFAULT, 0,
+ true, 10);
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 324e244..f2640d2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -1496,6 +1496,79 @@
}
@Test
+ public void testComputeConfigResourceOverrides_unresizableApp() {
+ // Set up a display in landscape and ignoring orientation request.
+ setUpDisplaySizeWithApp(2800, 1400);
+ mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+
+ prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
+
+ final Rect activityBounds = new Rect(mActivity.getBounds());
+
+ int originalScreenWidthDp = mActivity.getConfiguration().screenWidthDp;
+ int originalScreenHeighthDp = mActivity.getConfiguration().screenHeightDp;
+
+ // App should launch in fixed orientation letterbox.
+ // Activity bounds should be 700x1400 with the ratio as the display.
+ assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertFitted();
+ assertEquals(originalScreenWidthDp, mActivity.getConfiguration().smallestScreenWidthDp);
+ assertTrue(originalScreenWidthDp < originalScreenHeighthDp);
+
+ // Rotate display to portrait.
+ rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
+
+ // After we rotate, the activity should go in the size-compat mode and report the same
+ // configuration values.
+ assertScaled();
+ assertEquals(originalScreenWidthDp, mActivity.getConfiguration().smallestScreenWidthDp);
+ assertEquals(originalScreenWidthDp, mActivity.getConfiguration().screenWidthDp);
+ assertEquals(originalScreenHeighthDp, mActivity.getConfiguration().screenHeightDp);
+
+ // Restart activity
+ mActivity.restartProcessIfVisible();
+
+ // Now configuration should be updated
+ assertFitted();
+ assertNotEquals(originalScreenWidthDp, mActivity.getConfiguration().screenWidthDp);
+ assertNotEquals(originalScreenHeighthDp, mActivity.getConfiguration().screenHeightDp);
+ assertEquals(mActivity.getConfiguration().screenWidthDp,
+ mActivity.getConfiguration().smallestScreenWidthDp);
+ }
+
+ @Test
+ public void testComputeConfigResourceOverrides_resizableFixedOrientationActivity() {
+ // Set up a display in landscape and ignoring orientation request.
+ setUpDisplaySizeWithApp(2800, 1400);
+ mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+
+ // Portrait fixed app without max aspect.
+ prepareLimitedBounds(mActivity, SCREEN_ORIENTATION_PORTRAIT, false /* isUnresizable */);
+
+ final Rect activityBounds = new Rect(mActivity.getBounds());
+
+ int originalScreenWidthDp = mActivity.getConfiguration().screenWidthDp;
+ int originalScreenHeighthDp = mActivity.getConfiguration().screenHeightDp;
+
+ // App should launch in fixed orientation letterbox.
+ // Activity bounds should be 700x1400 with the ratio as the display.
+ assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertFitted();
+ assertEquals(originalScreenWidthDp, mActivity.getConfiguration().smallestScreenWidthDp);
+ assertTrue(originalScreenWidthDp < originalScreenHeighthDp);
+
+ // Rotate display to portrait.
+ rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
+
+ // Now configuration should be updated
+ assertFitted();
+ assertNotEquals(originalScreenWidthDp, mActivity.getConfiguration().screenWidthDp);
+ assertNotEquals(originalScreenHeighthDp, mActivity.getConfiguration().screenHeightDp);
+ assertEquals(mActivity.getConfiguration().screenWidthDp,
+ mActivity.getConfiguration().smallestScreenWidthDp);
+ }
+
+ @Test
public void testSplitAspectRatioForUnresizablePortraitApps() {
// Set up a display in landscape and ignoring orientation request.
int screenWidth = 1600;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index 46e21f1..e2fe1b1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -691,7 +691,8 @@
final ActivityRecord.CompatDisplayInsets compatInsets =
new ActivityRecord.CompatDisplayInsets(
display, activity, /* fixedOrientationBounds= */ null);
- task.computeConfigResourceOverrides(inOutConfig, parentConfig, compatInsets);
+ task.computeConfigResourceOverrides(
+ inOutConfig, parentConfig, compatInsets, /* areBoundsLetterboxed */ true);
assertEquals(largerLandscapeBounds, inOutConfig.windowConfiguration.getAppBounds());
final float density = parentConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index 9c2aac0..5407412 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -459,6 +459,23 @@
}
@Test
+ public void testRegisterTaskOrganizerWithExistingTasks_noSurfaceControl()
+ throws RemoteException {
+ final Task rootTask = createRootTask();
+ final Task task = createTask(rootTask);
+ final Task rootTask2 = createRootTask();
+ final Task task2 = createTask(rootTask2);
+ rootTask2.setSurfaceControl(null);
+ ArrayList<TaskAppearedInfo> existingTasks = new ArrayList<>();
+ final ITaskOrganizer organizer = registerMockOrganizer(existingTasks);
+ assertContainsTasks(existingTasks, rootTask);
+
+ // Verify we don't get onTaskAppeared if we are returned the tasks
+ verify(organizer, never())
+ .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
+ }
+
+ @Test
public void testTaskTransaction() {
removeGlobalMinSizeRestriction();
final Task rootTask = new TaskBuilder(mSupervisor)
diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp
index 7731e09..855d3c1 100644
--- a/tests/FlickerTests/Android.bp
+++ b/tests/FlickerTests/Android.bp
@@ -46,6 +46,7 @@
"launcher-helper-lib",
"launcher-aosp-tapl",
"platform-test-annotations",
+ "wm-flicker-window-extensions",
],
}
@@ -83,5 +84,21 @@
"flickertestapplib",
"truth-prebuilt",
"app-helpers-core",
+ "wm-flicker-window-extensions",
],
}
+
+android_library_import {
+ name: "wm-flicker-window-extensions_nodeps",
+ aars: ["libs/window-extensions-release.aar"],
+ sdk_version: "current",
+}
+
+java_library {
+ name: "wm-flicker-window-extensions",
+ sdk_version: "current",
+ static_libs: [
+ "wm-flicker-window-extensions_nodeps",
+ ],
+ installable: false,
+}
diff --git a/tests/FlickerTests/AndroidManifest.xml b/tests/FlickerTests/AndroidManifest.xml
index fda6091..e173eba0 100644
--- a/tests/FlickerTests/AndroidManifest.xml
+++ b/tests/FlickerTests/AndroidManifest.xml
@@ -43,6 +43,7 @@
<!-- Allow the test to write directly to /sdcard/ -->
<application android:requestLegacyExternalStorage="true">
<uses-library android:name="android.test.runner"/>
+ <uses-library android:name="androidx.window.extensions" android:required="false"/>
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/tests/FlickerTests/libs/window-extensions-release.aar b/tests/FlickerTests/libs/window-extensions-release.aar
new file mode 100644
index 0000000..6fc9a67
--- /dev/null
+++ b/tests/FlickerTests/libs/window-extensions-release.aar
Binary files differ
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt
new file mode 100644
index 0000000..ed411b5
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.activityembedding
+
+import android.app.Instrumentation
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
+import org.junit.Before
+
+abstract class ActivityEmbeddingTestBase {
+ val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ val testApp = ActivityEmbeddingAppHelper(instrumentation)
+
+ @Before
+ fun assumeActivityEmbeddingSupported() {
+ // The test should only be run on devices that support ActivityEmbedding.
+ ActivityEmbeddingAppHelper.assumeActivityEmbeddingSupportedDevice()
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/OpenActivityEmbeddingPlaceholderSplit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/OpenActivityEmbeddingPlaceholderSplit.kt
new file mode 100644
index 0000000..28a72f4
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/OpenActivityEmbeddingPlaceholderSplit.kt
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.activityembedding
+
+import android.platform.test.annotations.Presubmit
+import android.view.Surface
+import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test opening an activity that will launch another activity as ActivityEmbedding placeholder in
+ * split.
+ *
+ * To run this test: `atest FlickerTests:OpenActivityEmbeddingPlaceholderSplit`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class OpenActivityEmbeddingPlaceholderSplit(private val testSpec: FlickerTestParameter) :
+ ActivityEmbeddingTestBase() {
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ setup {
+ eachRun {
+ testApp.launchViaIntent(wmHelper)
+ }
+ }
+ transitions {
+ testApp.launchPlaceholderSplit(wmHelper)
+ }
+ teardown {
+ test {
+ device.pressHome()
+ testApp.exit(wmHelper)
+ }
+ }
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun mainActivityBecomesInvisible() {
+ testSpec.assertLayers {
+ isVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ .then()
+ .isInvisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun placeholderSplitBecomesVisible() {
+ testSpec.assertLayers {
+ isInvisible(ActivityEmbeddingAppHelper.PLACEHOLDER_PRIMARY_COMPONENT)
+ .then()
+ .isVisible(ActivityEmbeddingAppHelper.PLACEHOLDER_PRIMARY_COMPONENT)
+ }
+ testSpec.assertLayers {
+ isInvisible(ActivityEmbeddingAppHelper.PLACEHOLDER_SECONDARY_COMPONENT)
+ .then()
+ .isVisible(ActivityEmbeddingAppHelper.PLACEHOLDER_SECONDARY_COMPONENT)
+ }
+ }
+
+ companion object {
+ /**
+ * Creates the test configurations.
+ *
+ * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring
+ * repetitions, screen orientation and navigation modes.
+ */
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(
+ repetitions = 1,
+ supportedRotations = listOf(Surface.ROTATION_0, Surface.ROTATION_90),
+ supportedNavigationModes = listOf(
+ WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
+ WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
+ )
+ )
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
new file mode 100644
index 0000000..a01f633
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.helpers
+
+import android.app.Instrumentation
+import android.support.test.launcherhelper.ILauncherStrategy
+import android.support.test.launcherhelper.LauncherStrategyFactory
+import android.util.Log
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.Until
+import androidx.window.extensions.WindowExtensions
+import androidx.window.extensions.WindowExtensionsProvider
+import androidx.window.extensions.embedding.ActivityEmbeddingComponent
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.server.wm.traces.common.FlickerComponentName
+import com.android.server.wm.traces.common.windowmanager.WindowManagerState.Companion.STATE_RESUMED
+import com.android.server.wm.traces.parser.toFlickerComponent
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+import org.junit.Assume.assumeNotNull
+
+class ActivityEmbeddingAppHelper @JvmOverloads constructor(
+ instr: Instrumentation,
+ launcherName: String = ActivityOptions.ACTIVITY_EMBEDDING_LAUNCHER_NAME,
+ component: FlickerComponentName = MAIN_ACTIVITY_COMPONENT,
+ launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
+ .getInstance(instr)
+ .launcherStrategy
+) : StandardAppHelper(instr, launcherName, component, launcherStrategy) {
+
+ /**
+ * Clicks the button to launch the placeholder primary activity, which should launch the
+ * placeholder secondary activity based on the placeholder rule.
+ */
+ fun launchPlaceholderSplit(wmHelper: WindowManagerStateHelper) {
+ val launchButton = uiDevice.wait(
+ Until.findObject(By.res(getPackage(), "launch_placeholder_split_button")),
+ FIND_TIMEOUT)
+ require(launchButton != null) {
+ "Can't find launch placeholder split button on screen."
+ }
+ launchButton.click()
+ wmHelper.StateSyncBuilder()
+ .withActivityState(PLACEHOLDER_PRIMARY_COMPONENT, STATE_RESUMED)
+ .withActivityState(PLACEHOLDER_SECONDARY_COMPONENT, STATE_RESUMED)
+ .waitForAndVerify()
+ }
+
+ companion object {
+ private const val TAG = "ActivityEmbeddingAppHelper"
+
+ val MAIN_ACTIVITY_COMPONENT = ActivityOptions
+ .ACTIVITY_EMBEDDING_MAIN_ACTIVITY_COMPONENT_NAME.toFlickerComponent()
+
+ val PLACEHOLDER_PRIMARY_COMPONENT = ActivityOptions
+ .ACTIVITY_EMBEDDING_PLACEHOLDER_PRIMARY_ACTIVITY_COMPONENT_NAME.toFlickerComponent()
+
+ val PLACEHOLDER_SECONDARY_COMPONENT = ActivityOptions
+ .ACTIVITY_EMBEDDING_PLACEHOLDER_SECONDARY_ACTIVITY_COMPONENT_NAME
+ .toFlickerComponent()
+
+ @JvmStatic
+ fun getWindowExtensions(): WindowExtensions? {
+ try {
+ return WindowExtensionsProvider.getWindowExtensions()
+ } catch (e: NoClassDefFoundError) {
+ Log.d(TAG, "Extension implementation not found")
+ } catch (e: UnsupportedOperationException) {
+ Log.d(TAG, "Stub Extension")
+ }
+ return null
+ }
+
+ @JvmStatic
+ fun getActivityEmbeddingComponent(): ActivityEmbeddingComponent? {
+ return getWindowExtensions()?.activityEmbeddingComponent
+ }
+
+ @JvmStatic
+ fun assumeActivityEmbeddingSupportedDevice() {
+ assumeNotNull(getActivityEmbeddingComponent())
+ }
+ }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/Android.bp b/tests/FlickerTests/test-apps/flickerapp/Android.bp
index 78660c0..0c698ab 100644
--- a/tests/FlickerTests/test-apps/flickerapp/Android.bp
+++ b/tests/FlickerTests/test-apps/flickerapp/Android.bp
@@ -26,6 +26,11 @@
srcs: ["**/*.java"],
sdk_version: "current",
test_suites: ["device-tests"],
+ static_libs: [
+ "androidx.test.ext.junit",
+ "wm-flicker-common-app-helpers",
+ "wm-flicker-window-extensions",
+ ],
}
java_library {
diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
index 3e2130d..387f19b 100644
--- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
@@ -15,12 +15,14 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.wm.flicker.testapp">
+ package="com.android.server.wm.flicker.testapp">
<uses-sdk android:minSdkVersion="29"
android:targetSdkVersion="29"/>
<application android:allowBackup="false"
android:supportsRtl="true">
+ <uses-library android:name="androidx.window.extensions" android:required="false"/>
+
<activity android:name=".SimpleActivity"
android:taskAffinity="com.android.server.wm.flicker.testapp.SimpleActivity"
android:theme="@style/CutoutShortEdges"
@@ -163,5 +165,33 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
+
+ <activity
+ android:name=".ActivityEmbeddingMainActivity"
+ android:label="ActivityEmbedding Main"
+ android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding"
+ android:theme="@style/CutoutShortEdges"
+ android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".ActivityEmbeddingPlaceholderPrimaryActivity"
+ android:label="ActivityEmbedding Placeholder Primary"
+ android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding"
+ android:theme="@style/CutoutShortEdges"
+ android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
+ android:exported="false">
+ </activity>
+ <activity
+ android:name=".ActivityEmbeddingPlaceholderSecondaryActivity"
+ android:label="ActivityEmbedding Placeholder Secondary"
+ android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding"
+ android:theme="@style/CutoutShortEdges"
+ android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
+ android:exported="false"/>
</application>
</manifest>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_base_layout.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_base_layout.xml
new file mode 100644
index 0000000..3a02cad
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_base_layout.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/root_activity_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+</LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml
new file mode 100644
index 0000000..19c81a8
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:background="@android:color/holo_orange_light">
+
+ <Button
+ android:id="@+id/launch_placeholder_split_button"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:layout_centerHorizontal="true"
+ android:onClick="launchPlaceholderSplit"
+ android:text="Launch Placeholder Split" />
+
+</LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingBaseActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingBaseActivity.java
new file mode 100644
index 0000000..cd23e9f
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingBaseActivity.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.testapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/** Base activity of ActivityEmbedding split activities. */
+public abstract class ActivityEmbeddingBaseActivity extends Activity {
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_embedding_base_layout);
+ findViewById(R.id.root_activity_layout).setBackgroundColor(getBackgroundColor());
+ }
+
+ /** Sets different colors to visually distinguish split pairs. */
+ abstract int getBackgroundColor();
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingMainActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingMainActivity.java
new file mode 100644
index 0000000..166e3ca
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingMainActivity.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.testapp;
+
+import static com.android.server.wm.flicker.testapp.ActivityOptions.ACTIVITY_EMBEDDING_PLACEHOLDER_PRIMARY_ACTIVITY_COMPONENT_NAME;
+import static com.android.server.wm.flicker.testapp.ActivityOptions.ACTIVITY_EMBEDDING_PLACEHOLDER_SECONDARY_ACTIVITY_COMPONENT_NAME;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.ArraySet;
+import android.util.Log;
+import android.view.View;
+
+import androidx.window.extensions.embedding.ActivityEmbeddingComponent;
+import androidx.window.extensions.embedding.EmbeddingRule;
+import androidx.window.extensions.embedding.SplitPlaceholderRule;
+
+import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper;
+
+import java.util.Set;
+
+/** Main activity of the ActivityEmbedding test app to launch other embedding activities. */
+public class ActivityEmbeddingMainActivity extends Activity {
+ private static final String TAG = "ActivityEmbeddingMainActivity";
+ private static final float DEFAULT_SPLIT_RATIO = 0.5f;
+
+ private ActivityEmbeddingComponent mEmbeddingComponent;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_embedding_main_layout);
+
+ initializeSplitRules();
+ }
+
+ /** R.id.launch_placeholder_split_button onClick */
+ public void launchPlaceholderSplit(View view) {
+ startActivity(new Intent().setComponent(
+ ACTIVITY_EMBEDDING_PLACEHOLDER_PRIMARY_ACTIVITY_COMPONENT_NAME));
+ }
+
+ private void initializeSplitRules() {
+ mEmbeddingComponent = ActivityEmbeddingAppHelper.getActivityEmbeddingComponent();
+ if (mEmbeddingComponent == null) {
+ // Embedding not supported
+ Log.d(TAG, "ActivityEmbedding is not supported on this device");
+ finish();
+ return;
+ }
+
+ mEmbeddingComponent.setEmbeddingRules(getSplitRules());
+ }
+
+ private Set<EmbeddingRule> getSplitRules() {
+ final Set<EmbeddingRule> rules = new ArraySet<>();
+
+ final SplitPlaceholderRule placeholderRule = new SplitPlaceholderRule.Builder(
+ new Intent().setComponent(
+ ACTIVITY_EMBEDDING_PLACEHOLDER_SECONDARY_ACTIVITY_COMPONENT_NAME),
+ activity -> activity instanceof ActivityEmbeddingPlaceholderPrimaryActivity,
+ intent -> intent.getComponent().equals(
+ ACTIVITY_EMBEDDING_PLACEHOLDER_PRIMARY_ACTIVITY_COMPONENT_NAME),
+ windowMetrics -> true)
+ .setSplitRatio(DEFAULT_SPLIT_RATIO)
+ .build();
+ rules.add(placeholderRule);
+ return rules;
+ }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingPlaceholderPrimaryActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingPlaceholderPrimaryActivity.java
new file mode 100644
index 0000000..05c7a0b
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingPlaceholderPrimaryActivity.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.testapp;
+
+import android.graphics.Color;
+
+/**
+ * Primary activity that will launch {@link ActivityEmbeddingPlaceholderSecondaryActivity} to split
+ * as placeholder based on the placeholder rule.
+ */
+public class ActivityEmbeddingPlaceholderPrimaryActivity extends ActivityEmbeddingBaseActivity {
+ @Override
+ int getBackgroundColor() {
+ return Color.BLUE;
+ }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingPlaceholderSecondaryActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingPlaceholderSecondaryActivity.java
new file mode 100644
index 0000000..a9a51cd
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingPlaceholderSecondaryActivity.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.testapp;
+
+import android.graphics.Color;
+
+/**
+ * Activity to be used as the secondary placeholder activity to split with
+ * {@link ActivityEmbeddingPlaceholderPrimaryActivity}.
+ */
+public class ActivityEmbeddingPlaceholderSecondaryActivity extends ActivityEmbeddingBaseActivity {
+ @Override
+ int getBackgroundColor() {
+ return Color.GREEN;
+ }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
index 6cda482..19fafb7 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
@@ -87,4 +87,17 @@
public static final ComponentName NOTIFICATION_ACTIVITY_COMPONENT_NAME =
new ComponentName(FLICKER_APP_PACKAGE,
FLICKER_APP_PACKAGE + ".NotificationActivity");
+
+ public static final String ACTIVITY_EMBEDDING_LAUNCHER_NAME = "ActivityEmbeddingMainActivity";
+ public static final ComponentName ACTIVITY_EMBEDDING_MAIN_ACTIVITY_COMPONENT_NAME =
+ new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".ActivityEmbeddingMainActivity");
+ public static final ComponentName
+ ACTIVITY_EMBEDDING_PLACEHOLDER_PRIMARY_ACTIVITY_COMPONENT_NAME = new ComponentName(
+ FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".ActivityEmbeddingPlaceholderPrimaryActivity");
+ public static final ComponentName
+ ACTIVITY_EMBEDDING_PLACEHOLDER_SECONDARY_ACTIVITY_COMPONENT_NAME = new ComponentName(
+ FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".ActivityEmbeddingPlaceholderSecondaryActivity");
}
diff --git a/tests/UsbManagerTests/lib/src/com/android/server/usblib/UsbManagerTestLib.java b/tests/UsbManagerTests/lib/src/com/android/server/usblib/UsbManagerTestLib.java
index 782439f..d133f6f 100644
--- a/tests/UsbManagerTests/lib/src/com/android/server/usblib/UsbManagerTestLib.java
+++ b/tests/UsbManagerTests/lib/src/com/android/server/usblib/UsbManagerTestLib.java
@@ -117,6 +117,7 @@
testGetCurrentFunctionsMock_Matched(UsbManager.FUNCTION_PTP);
testGetCurrentFunctionsMock_Matched(UsbManager.FUNCTION_MIDI);
testGetCurrentFunctionsMock_Matched(UsbManager.FUNCTION_RNDIS);
+ testGetCurrentFunctionsMock_Matched(UsbManager.FUNCTION_NCM);
}
public void testSetCurrentFunctions_shouldMatched() {
@@ -125,5 +126,6 @@
testSetCurrentFunctionsMock_Matched(UsbManager.FUNCTION_PTP);
testSetCurrentFunctionsMock_Matched(UsbManager.FUNCTION_MIDI);
testSetCurrentFunctionsMock_Matched(UsbManager.FUNCTION_RNDIS);
+ testSetCurrentFunctionsMock_Matched(UsbManager.FUNCTION_NCM);
}
}
diff --git a/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java b/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java
index 861d221..86bcb72 100644
--- a/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java
+++ b/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java
@@ -182,6 +182,14 @@
@SmallTest
@Test
+ public void setFunctionsNcm() {
+ mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_SET_CURRENT_FUNCTIONS,
+ UsbManager.FUNCTION_NCM));
+ assertNotEquals(mUsbHandler.getEnabledFunctions() & UsbManager.FUNCTION_NCM, 0);
+ }
+
+ @SmallTest
+ @Test
public void setFunctionsNcmAndRndis() {
final long rndisPlusNcm = UsbManager.FUNCTION_RNDIS | UsbManager.FUNCTION_NCM;