Merge "Watch app ops for all runtime permissions."
diff --git a/Android.bp b/Android.bp
index 594126f..1eba3e2 100644
--- a/Android.bp
+++ b/Android.bp
@@ -170,6 +170,15 @@
}
filegroup {
+ name: "framework-mms-sources",
+ srcs: [
+ "mms/java/**/*.java",
+ "mms/java/**/*.aidl",
+ ],
+ path: "mms/java",
+}
+
+filegroup {
name: "framework-wifi-sources",
srcs: [
"wifi/java/**/*.java",
@@ -193,6 +202,7 @@
":framework-mca-filterfw-sources",
":framework-mca-filterpacks-sources",
":framework-mime-sources",
+ ":framework-mms-sources",
":framework-opengl-sources",
":framework-rs-sources",
":framework-sax-sources",
@@ -252,6 +262,7 @@
"media/mca/effect/java",
"media/mca/filterfw/java",
"media/mca/filterpacks/java",
+ "mms/java",
"opengl/java",
"rs/java",
"sax/java",
@@ -415,7 +426,7 @@
java_library {
name: "framework-annotation-proc",
- defaults: ["framework-defaults"],
+ defaults: ["framework-aidl-export-defaults"],
srcs: [":framework-all-sources"],
installable: false,
plugins: [
@@ -820,6 +831,7 @@
"media/mca/filterfw/java",
"media/mca/filterpacks/java",
"drm/java",
+ "mms/java",
"opengl/java",
"sax/java",
"telecomm/java",
@@ -941,6 +953,7 @@
"test-base/src/**/*.java",
":opt-telephony-srcs",
":opt-net-voip-srcs",
+ ":core-current-stubs-source",
":core_public_api_files",
":updatable-media-srcs",
"test-mock/src/**/*.java",
@@ -1005,6 +1018,7 @@
"core/java/**/*.logtags",
":opt-telephony-srcs",
":opt-net-voip-srcs",
+ ":core-current-stubs-source",
":core_public_api_files",
":updatable-media-srcs",
":jobscheduler-framework-source",
@@ -1558,3 +1572,14 @@
],
}
+// Avoid including Parcelable classes as we don't want to have two copies of
+// Parcelable cross the process.
+filegroup {
+ name: "framework-cellbroadcast-shared-srcs",
+ srcs: [
+ "core/java/android/util/LocalLog.java",
+ "core/java/android/util/Slog.java",
+ "core/java/com/android/internal/util/State.java",
+ "core/java/com/android/internal/util/StateMachine.java",
+ ],
+}
\ No newline at end of file
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index 65aaf20..3dc9a28 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -48,7 +48,6 @@
import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
-import android.os.FileUtils;
import android.os.Handler;
import android.os.IDeviceIdleController;
import android.os.Looper;
@@ -1684,7 +1683,7 @@
static class Injector {
private final Context mContext;
- private ConnectivityService mConnectivityService;
+ private ConnectivityManager mConnectivityManager;
private Constants mConstants;
private LocationManager mLocationManager;
@@ -1705,12 +1704,11 @@
return new AppStateTracker(ctx, looper);
}
- ConnectivityService getConnectivityService() {
- if (mConnectivityService == null) {
- mConnectivityService = (ConnectivityService) ServiceManager.getService(
- Context.CONNECTIVITY_SERVICE);
+ ConnectivityManager getConnectivityManager() {
+ if (mConnectivityManager == null) {
+ mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
}
- return mConnectivityService;
+ return mConnectivityManager;
}
Constants getConstants(DeviceIdleController controller, Handler handler,
@@ -1909,7 +1907,7 @@
if (getContext().getResources().getBoolean(
com.android.internal.R.bool.config_autoPowerModePrefetchLocation)) {
- mLocationRequest = new LocationRequest()
+ mLocationRequest = LocationRequest.create()
.setQuality(LocationRequest.ACCURACY_FINE)
.setInterval(0)
.setFastestInterval(0)
@@ -2497,9 +2495,9 @@
}
void updateConnectivityState(Intent connIntent) {
- ConnectivityService cm;
+ ConnectivityManager cm;
synchronized (this) {
- cm = mInjector.getConnectivityService();
+ cm = mInjector.getConnectivityManager();
}
if (cm == null) {
return;
@@ -3598,9 +3596,6 @@
try {
stream = mConfigFile.startWrite();
memStream.writeTo(stream);
- stream.flush();
- FileUtils.sync(stream);
- stream.close();
mConfigFile.finishWrite(stream);
} catch (IOException e) {
Slog.w(TAG, "Error writing config file", e);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 329d4b7..7273ea7 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -109,6 +109,9 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.time.Clock;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -144,10 +147,53 @@
@VisibleForTesting
public static Clock sSystemClock = Clock.systemUTC();
+
+ private abstract static class MySimpleClock extends Clock {
+ private final ZoneId mZoneId;
+
+ MySimpleClock(ZoneId zoneId) {
+ this.mZoneId = zoneId;
+ }
+
+ @Override
+ public ZoneId getZone() {
+ return mZoneId;
+ }
+
+ @Override
+ public Clock withZone(ZoneId zone) {
+ return new MySimpleClock(zone) {
+ @Override
+ public long millis() {
+ return MySimpleClock.this.millis();
+ }
+ };
+ }
+
+ @Override
+ public abstract long millis();
+
+ @Override
+ public Instant instant() {
+ return Instant.ofEpochMilli(millis());
+ }
+ }
+
@VisibleForTesting
- public static Clock sUptimeMillisClock = SystemClock.uptimeClock();
+ public static Clock sUptimeMillisClock = new MySimpleClock(ZoneOffset.UTC) {
+ @Override
+ public long millis() {
+ return SystemClock.uptimeMillis();
+ }
+ };
+
@VisibleForTesting
- public static Clock sElapsedRealtimeClock = SystemClock.elapsedRealtimeClock();
+ public static Clock sElapsedRealtimeClock = new MySimpleClock(ZoneOffset.UTC) {
+ @Override
+ public long millis() {
+ return SystemClock.elapsedRealtime();
+ }
+ };
/** Global local for all job scheduler state. */
final Object mLock = new Object();
@@ -2126,7 +2172,7 @@
job.getServiceComponent(), PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
job.getUserId());
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw new RuntimeException(e);
}
if (service == null) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
index 43e8dfb..7d36303 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
@@ -34,6 +34,7 @@
import android.os.Message;
import android.os.UserHandle;
import android.text.format.DateUtils;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.DataUnit;
import android.util.Log;
@@ -441,7 +442,7 @@
synchronized (mLock) {
// Since this is a really hot codepath, temporarily cache any
// answers that we get from ConnectivityManager.
- final SparseArray<NetworkCapabilities> networkToCapabilities = new SparseArray<>();
+ final ArrayMap<Network, NetworkCapabilities> networkToCapabilities = new ArrayMap<>();
boolean changed = false;
if (filterUid == -1) {
@@ -460,17 +461,16 @@
}
private boolean updateTrackedJobsLocked(ArraySet<JobStatus> jobs, Network filterNetwork,
- SparseArray<NetworkCapabilities> networkToCapabilities) {
+ ArrayMap<Network, NetworkCapabilities> networkToCapabilities) {
if (jobs == null || jobs.size() == 0) {
return false;
}
final Network network = mConnManager.getActiveNetworkForUid(jobs.valueAt(0).getSourceUid());
- final int netId = network != null ? network.netId : -1;
- NetworkCapabilities capabilities = networkToCapabilities.get(netId);
+ NetworkCapabilities capabilities = networkToCapabilities.get(network);
if (capabilities == null) {
capabilities = mConnManager.getNetworkCapabilities(network);
- networkToCapabilities.put(netId, capabilities);
+ networkToCapabilities.put(network, capabilities);
}
final boolean networkMatch = (filterNetwork == null
|| Objects.equals(filterNetwork, network));
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index adb4314..c76346f 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -28,7 +28,7 @@
import android.net.Uri;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.text.format.TimeMigrationUtils;
+import android.text.format.DateFormat;
import android.util.ArraySet;
import android.util.Pair;
import android.util.Slog;
@@ -1518,7 +1518,7 @@
if (job.getClipData() != null) {
pw.print(prefix); pw.print(" Clip data: ");
StringBuilder b = new StringBuilder(128);
- job.getClipData().toShortString(b);
+ b.append(job.getClipData());
pw.println(b);
}
if (uriPerms != null) {
@@ -1659,14 +1659,18 @@
}
if (mLastSuccessfulRunTime != 0) {
pw.print(prefix); pw.print("Last successful run: ");
- pw.println(TimeMigrationUtils.formatMillisWithFixedFormat(mLastSuccessfulRunTime));
+ pw.println(formatTime(mLastSuccessfulRunTime));
}
if (mLastFailedRunTime != 0) {
pw.print(prefix); pw.print("Last failed run: ");
- pw.println(TimeMigrationUtils.formatMillisWithFixedFormat(mLastFailedRunTime));
+ pw.println(formatTime(mLastFailedRunTime));
}
}
+ private static CharSequence formatTime(long time) {
+ return DateFormat.format("yyyy-MM-dd HH:mm:ss", time);
+ }
+
public void dump(ProtoOutputStream proto, long fieldId, boolean full, long elapsedRealtimeMillis) {
final long token = proto.start(fieldId);
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index df5d6ae..7c472a9 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -872,64 +872,66 @@
public void reportEvent(UsageEvents.Event event, long elapsedRealtime, int userId) {
if (!mAppIdleEnabled) return;
synchronized (mAppIdleLock) {
+ final String pkg = event.getPackageName();
+ final int eventType = event.getEventType();
// TODO: Ideally this should call isAppIdleFiltered() to avoid calling back
// about apps that are on some kind of whitelist anyway.
final boolean previouslyIdle = mAppIdleHistory.isIdle(
- event.mPackage, userId, elapsedRealtime);
+ pkg, userId, elapsedRealtime);
// Inform listeners if necessary
- if ((event.mEventType == UsageEvents.Event.ACTIVITY_RESUMED
- || event.mEventType == UsageEvents.Event.ACTIVITY_PAUSED
- || event.mEventType == UsageEvents.Event.SYSTEM_INTERACTION
- || event.mEventType == UsageEvents.Event.USER_INTERACTION
- || event.mEventType == UsageEvents.Event.NOTIFICATION_SEEN
- || event.mEventType == UsageEvents.Event.SLICE_PINNED
- || event.mEventType == UsageEvents.Event.SLICE_PINNED_PRIV
- || event.mEventType == UsageEvents.Event.FOREGROUND_SERVICE_START)) {
+ if ((eventType == UsageEvents.Event.ACTIVITY_RESUMED
+ || eventType == UsageEvents.Event.ACTIVITY_PAUSED
+ || eventType == UsageEvents.Event.SYSTEM_INTERACTION
+ || eventType == UsageEvents.Event.USER_INTERACTION
+ || eventType == UsageEvents.Event.NOTIFICATION_SEEN
+ || eventType == UsageEvents.Event.SLICE_PINNED
+ || eventType == UsageEvents.Event.SLICE_PINNED_PRIV
+ || eventType == UsageEvents.Event.FOREGROUND_SERVICE_START)) {
final AppUsageHistory appHistory = mAppIdleHistory.getAppUsageHistory(
- event.mPackage, userId, elapsedRealtime);
+ pkg, userId, elapsedRealtime);
final int prevBucket = appHistory.currentBucket;
final int prevBucketReason = appHistory.bucketingReason;
final long nextCheckTime;
- final int subReason = usageEventToSubReason(event.mEventType);
+ final int subReason = usageEventToSubReason(eventType);
final int reason = REASON_MAIN_USAGE | subReason;
- if (event.mEventType == UsageEvents.Event.NOTIFICATION_SEEN
- || event.mEventType == UsageEvents.Event.SLICE_PINNED) {
+ if (eventType == UsageEvents.Event.NOTIFICATION_SEEN
+ || eventType == UsageEvents.Event.SLICE_PINNED) {
// Mild usage elevates to WORKING_SET but doesn't change usage time.
- mAppIdleHistory.reportUsage(appHistory, event.mPackage,
+ mAppIdleHistory.reportUsage(appHistory, pkg,
STANDBY_BUCKET_WORKING_SET, subReason,
0, elapsedRealtime + mNotificationSeenTimeoutMillis);
nextCheckTime = mNotificationSeenTimeoutMillis;
- } else if (event.mEventType == UsageEvents.Event.SYSTEM_INTERACTION) {
- mAppIdleHistory.reportUsage(appHistory, event.mPackage,
+ } else if (eventType == UsageEvents.Event.SYSTEM_INTERACTION) {
+ mAppIdleHistory.reportUsage(appHistory, pkg,
STANDBY_BUCKET_ACTIVE, subReason,
0, elapsedRealtime + mSystemInteractionTimeoutMillis);
nextCheckTime = mSystemInteractionTimeoutMillis;
- } else if (event.mEventType == UsageEvents.Event.FOREGROUND_SERVICE_START) {
+ } else if (eventType == UsageEvents.Event.FOREGROUND_SERVICE_START) {
// Only elevate bucket if this is the first usage of the app
if (prevBucket != STANDBY_BUCKET_NEVER) return;
- mAppIdleHistory.reportUsage(appHistory, event.mPackage,
+ mAppIdleHistory.reportUsage(appHistory, pkg,
STANDBY_BUCKET_ACTIVE, subReason,
0, elapsedRealtime + mInitialForegroundServiceStartTimeoutMillis);
nextCheckTime = mInitialForegroundServiceStartTimeoutMillis;
} else {
- mAppIdleHistory.reportUsage(appHistory, event.mPackage,
+ mAppIdleHistory.reportUsage(appHistory, pkg,
STANDBY_BUCKET_ACTIVE, subReason,
elapsedRealtime, elapsedRealtime + mStrongUsageTimeoutMillis);
nextCheckTime = mStrongUsageTimeoutMillis;
}
mHandler.sendMessageDelayed(mHandler.obtainMessage
- (MSG_CHECK_PACKAGE_IDLE_STATE, userId, -1, event.mPackage),
+ (MSG_CHECK_PACKAGE_IDLE_STATE, userId, -1, pkg),
nextCheckTime);
final boolean userStartedInteracting =
appHistory.currentBucket == STANDBY_BUCKET_ACTIVE &&
prevBucket != appHistory.currentBucket &&
(prevBucketReason & REASON_MAIN_MASK) != REASON_MAIN_USAGE;
- maybeInformListeners(event.mPackage, userId, elapsedRealtime,
+ maybeInformListeners(pkg, userId, elapsedRealtime,
appHistory.currentBucket, reason, userStartedInteracting);
if (previouslyIdle) {
- notifyBatteryStats(event.mPackage, userId, false);
+ notifyBatteryStats(pkg, userId, false);
}
}
}
@@ -1849,16 +1851,6 @@
* Observe settings changes for {@link Global#APP_IDLE_CONSTANTS}.
*/
private class SettingsObserver extends ContentObserver {
- /**
- * This flag has been used to disable app idle on older builds with bug b/26355386.
- */
- @Deprecated
- private static final String KEY_IDLE_DURATION_OLD = "idle_duration";
- @Deprecated
- private static final String KEY_IDLE_DURATION = "idle_duration2";
- @Deprecated
- private static final String KEY_WALLCLOCK_THRESHOLD = "wallclock_threshold";
-
private static final String KEY_PAROLE_INTERVAL = "parole_interval";
private static final String KEY_PAROLE_WINDOW = "parole_window";
private static final String KEY_PAROLE_DURATION = "parole_duration";
@@ -1993,7 +1985,7 @@
: DEFAULT_EXEMPTED_SYNC_START_TIMEOUT);
mUnexemptedSyncScheduledTimeoutMillis = mParser.getDurationMillis(
- KEY_EXEMPTED_SYNC_SCHEDULED_DOZE_HOLD_DURATION,
+ KEY_UNEXEMPTED_SYNC_SCHEDULED_HOLD_DURATION,
COMPRESS_TIME ? ONE_MINUTE
: DEFAULT_UNEXEMPTED_SYNC_SCHEDULED_TIMEOUT); // TODO
diff --git a/api/current.txt b/api/current.txt
index 6126e90..e6e2b40 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -25387,6 +25387,7 @@
method public android.graphics.Bitmap getFrameAtIndex(int, @NonNull android.media.MediaMetadataRetriever.BitmapParams);
method public android.graphics.Bitmap getFrameAtIndex(int);
method public android.graphics.Bitmap getFrameAtTime(long, int);
+ method public android.graphics.Bitmap getFrameAtTime(long, int, @NonNull android.media.MediaMetadataRetriever.BitmapParams);
method public android.graphics.Bitmap getFrameAtTime(long);
method public android.graphics.Bitmap getFrameAtTime();
method @NonNull public java.util.List<android.graphics.Bitmap> getFramesAtIndex(int, int, @NonNull android.media.MediaMetadataRetriever.BitmapParams);
@@ -25396,6 +25397,7 @@
method public android.graphics.Bitmap getPrimaryImage(@NonNull android.media.MediaMetadataRetriever.BitmapParams);
method public android.graphics.Bitmap getPrimaryImage();
method public android.graphics.Bitmap getScaledFrameAtTime(long, int, int, int);
+ method public android.graphics.Bitmap getScaledFrameAtTime(long, int, int, int, @NonNull android.media.MediaMetadataRetriever.BitmapParams);
method public void release();
method public void setDataSource(String) throws java.lang.IllegalArgumentException;
method public void setDataSource(String, java.util.Map<java.lang.String,java.lang.String>) throws java.lang.IllegalArgumentException;
@@ -28809,6 +28811,7 @@
method @Nullable public String getPrivateDnsServerName();
method @NonNull public java.util.List<android.net.RouteInfo> getRoutes();
method public boolean isPrivateDnsActive();
+ method public boolean isWakeOnLanSupported();
method public void setDnsServers(@NonNull java.util.Collection<java.net.InetAddress>);
method public void setDomains(@Nullable String);
method public void setHttpProxy(@Nullable android.net.ProxyInfo);
@@ -45110,7 +45113,7 @@
method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getMeid(int);
method public String getMmsUAProfUrl();
method public String getMmsUserAgent();
- method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getNai();
+ method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getNai();
method public String getNetworkCountryIso();
method public String getNetworkOperator();
method public String getNetworkOperatorName();
@@ -45169,6 +45172,7 @@
method @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void sendUssdRequest(String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler);
method public void sendVisualVoicemailSms(String, int, String, android.app.PendingIntent);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(boolean);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setForbiddenPlmns(@NonNull java.util.List<java.lang.String>);
method public boolean setLine1NumberForDisplay(String, String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setNetworkSelectionModeAutomatic();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setNetworkSelectionModeManual(String, boolean);
@@ -45183,6 +45187,7 @@
method public void updateAvailableNetworks(@NonNull java.util.List<android.telephony.AvailableNetworkInfo>, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>);
field public static final String ACTION_CARRIER_MESSAGING_CLIENT_SERVICE = "android.telephony.action.CARRIER_MESSAGING_CLIENT_SERVICE";
field public static final String ACTION_CONFIGURE_VOICEMAIL = "android.telephony.action.CONFIGURE_VOICEMAIL";
+ field public static final String ACTION_MULTI_SIM_CONFIG_CHANGED = "android.telephony.action.MULTI_SIM_CONFIG_CHANGED";
field public static final String ACTION_NETWORK_COUNTRY_CHANGED = "android.telephony.action.NETWORK_COUNTRY_CHANGED";
field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE";
field public static final String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE";
@@ -45223,6 +45228,7 @@
field public static final String EXTRA_LAUNCH_VOICEMAIL_SETTINGS_INTENT = "android.telephony.extra.LAUNCH_VOICEMAIL_SETTINGS_INTENT";
field public static final String EXTRA_NETWORK_COUNTRY = "android.telephony.extra.NETWORK_COUNTRY";
field public static final String EXTRA_NOTIFICATION_COUNT = "android.telephony.extra.NOTIFICATION_COUNT";
+ field public static final String EXTRA_NUM_OF_ACTIVE_SIM_SUPPORTED = "android.telephony.extra.NUM_OF_ACTIVE_SIM_SUPPORTED";
field public static final String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telephony.extra.PHONE_ACCOUNT_HANDLE";
field public static final String EXTRA_SPECIFIC_CARRIER_ID = "android.telephony.extra.SPECIFIC_CARRIER_ID";
field public static final String EXTRA_SPECIFIC_CARRIER_NAME = "android.telephony.extra.SPECIFIC_CARRIER_NAME";
@@ -47134,7 +47140,9 @@
public abstract class ReplacementSpan extends android.text.style.MetricAffectingSpan {
ctor public ReplacementSpan();
method public abstract void draw(@NonNull android.graphics.Canvas, CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, float, int, int, int, @NonNull android.graphics.Paint);
+ method @Nullable public CharSequence getContentDescription();
method public abstract int getSize(@NonNull android.graphics.Paint, CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, @Nullable android.graphics.Paint.FontMetricsInt);
+ method public void setContentDescription(@Nullable CharSequence);
method public void updateDrawState(android.text.TextPaint);
method public void updateMeasureState(android.text.TextPaint);
}
@@ -47908,6 +47916,7 @@
ctor public ArraySet(int);
ctor public ArraySet(android.util.ArraySet<E>);
ctor public ArraySet(java.util.Collection<? extends E>);
+ ctor public ArraySet(@Nullable E[]);
method public boolean add(E);
method public void addAll(android.util.ArraySet<? extends E>);
method public boolean addAll(java.util.Collection<? extends E>);
diff --git a/api/system-current.txt b/api/system-current.txt
index fc48845..4db7f4a 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6557,7 +6557,8 @@
method public abstract int onDeleteSubscription(int, String);
method public android.service.euicc.DownloadSubscriptionResult onDownloadSubscription(int, @NonNull android.telephony.euicc.DownloadableSubscription, boolean, boolean, @Nullable android.os.Bundle);
method @Deprecated public int onDownloadSubscription(int, @NonNull android.telephony.euicc.DownloadableSubscription, boolean, boolean);
- method public abstract int onEraseSubscriptions(int);
+ method @Deprecated public abstract int onEraseSubscriptions(int);
+ method public int onEraseSubscriptionsWithOptions(int, @android.telephony.euicc.EuiccCardManager.ResetOption int);
method public abstract android.service.euicc.GetDefaultDownloadableSubscriptionListResult onGetDefaultDownloadableSubscriptionList(int, boolean);
method public abstract android.service.euicc.GetDownloadableSubscriptionMetadataResult onGetDownloadableSubscriptionMetadata(int, android.telephony.euicc.DownloadableSubscription, boolean);
method public abstract String onGetEid(int);
@@ -8114,7 +8115,7 @@
}
public final class SmsCbMessage implements android.os.Parcelable {
- ctor public SmsCbMessage(int, int, int, @NonNull android.telephony.SmsCbLocation, int, @Nullable String, @Nullable String, int, @Nullable android.telephony.SmsCbEtwsInfo, @Nullable android.telephony.SmsCbCmasInfo);
+ ctor public SmsCbMessage(int, int, int, @NonNull android.telephony.SmsCbLocation, int, @Nullable String, @Nullable String, int, @Nullable android.telephony.SmsCbEtwsInfo, @Nullable android.telephony.SmsCbCmasInfo, int);
method @NonNull public static android.telephony.SmsCbMessage createFromCursor(@NonNull android.database.Cursor);
method public int describeContents();
method @Nullable public android.telephony.SmsCbCmasInfo getCmasWarningInfo();
@@ -8129,6 +8130,7 @@
method public long getReceivedTime();
method public int getSerialNumber();
method public int getServiceCategory();
+ method public int getSlotIndex();
method public boolean isCmasMessage();
method public boolean isEmergencyMessage();
method public boolean isEtwsMessage();
@@ -8276,6 +8278,7 @@
method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduLogicalChannelBySlot(int, int, int, int, int, int, int, @Nullable String);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApplicationOnUicc(int);
method public boolean isDataConnectivityPossible();
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataEnabledForApn(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isEmergencyAssistanceEnabled();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isIdle();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isOffhook();
@@ -8618,7 +8621,8 @@
public class EuiccManager {
method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void continueOperation(android.content.Intent, android.os.Bundle);
- method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void eraseSubscriptions(android.app.PendingIntent);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void eraseSubscriptions(@NonNull android.app.PendingIntent);
+ method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void eraseSubscriptionsWithOptions(@android.telephony.euicc.EuiccCardManager.ResetOption int, @NonNull android.app.PendingIntent);
method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void getDefaultDownloadableSubscriptionList(android.app.PendingIntent);
method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void getDownloadableSubscriptionMetadata(android.telephony.euicc.DownloadableSubscription, android.app.PendingIntent);
method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public int getOtaStatus();
diff --git a/api/test-current.txt b/api/test-current.txt
index d709886ef..70837a8 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -2034,10 +2034,18 @@
public final class UserHandle implements android.os.Parcelable {
method public static int getAppId(int);
method public int getIdentifier();
+ method public static int getUid(int, int);
+ method public static int getUserId(int);
method public static boolean isApp(int);
+ method public static int myUserId();
+ method public static android.os.UserHandle of(int);
field @NonNull public static final android.os.UserHandle ALL;
field @NonNull public static final android.os.UserHandle CURRENT;
+ field public static final int MIN_SECONDARY_USER_ID = 10; // 0xa
field @NonNull public static final android.os.UserHandle SYSTEM;
+ field public static final int USER_ALL = -1; // 0xffffffff
+ field public static final int USER_NULL = -10000; // 0xffffd8f0
+ field public static final int USER_SYSTEM = 0; // 0x0
}
public class UserManager {
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index f0db1b0..3d002d2 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -248,19 +248,6 @@
FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm);
FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents_WithActivation);
- FRIEND_TEST(DimensionInConditionE2eTest, TestCreateCountMetric_NoLink_OR_CombinationCondition);
- FRIEND_TEST(DimensionInConditionE2eTest, TestCreateCountMetric_Link_OR_CombinationCondition);
- FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_OR_CombinationCondition);
- FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_OR_CombinationCondition);
-
- FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_SimpleCondition);
- FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_SimpleCondition);
- FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_PartialLink_SimpleCondition);
-
- FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_PartialLink_AND_CombinationCondition);
- FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_AND_CombinationCondition);
- FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_AND_CombinationCondition);
-
FRIEND_TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_single_bucket);
FRIEND_TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_multiple_buckets);
FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket);
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index 23d025f..b5c8e35 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -37,6 +37,7 @@
using std::string;
using std::unordered_map;
using std::vector;
+using std::shared_ptr;
namespace android {
namespace os {
@@ -67,8 +68,13 @@
CountMetricProducer::CountMetricProducer(const ConfigKey& key, const CountMetric& metric,
const int conditionIndex,
const sp<ConditionWizard>& wizard,
- const int64_t timeBaseNs, const int64_t startTimeNs)
- : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, wizard) {
+ const int64_t timeBaseNs, const int64_t startTimeNs,
+ const unordered_map<int, shared_ptr<Activation>>&
+ eventActivationMap,
+ const unordered_map<int, vector<shared_ptr<Activation>>>&
+ eventDeactivationMap)
+ : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, wizard, eventActivationMap,
+ eventDeactivationMap) {
if (metric.has_bucket()) {
mBucketSizeNs =
TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket()) * 1000000;
@@ -251,6 +257,7 @@
if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
ALOGE("CountMetric %lld dropping data for dimension key %s",
(long long)mMetricId, newKey.toString().c_str());
+ StatsdStats::getInstance().noteHardDimensionLimitReached(mMetricId);
return true;
}
}
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index b4a910c..61913c7 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -42,7 +42,11 @@
public:
CountMetricProducer(const ConfigKey& key, const CountMetric& countMetric,
const int conditionIndex, const sp<ConditionWizard>& wizard,
- const int64_t timeBaseNs, const int64_t startTimeNs);
+ const int64_t timeBaseNs, const int64_t startTimeNs,
+ const std::unordered_map<int, std::shared_ptr<Activation>>&
+ eventActivationMap = {},
+ const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
+ eventDeactivationMap = {});
virtual ~CountMetricProducer();
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index cca793b..31b90f3 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -36,6 +36,7 @@
using std::string;
using std::unordered_map;
using std::vector;
+using std::shared_ptr;
namespace android {
namespace os {
@@ -62,14 +63,15 @@
const int FIELD_ID_START_BUCKET_ELAPSED_MILLIS = 5;
const int FIELD_ID_END_BUCKET_ELAPSED_MILLIS = 6;
-DurationMetricProducer::DurationMetricProducer(const ConfigKey& key, const DurationMetric& metric,
- const int conditionIndex, const size_t startIndex,
- const size_t stopIndex, const size_t stopAllIndex,
- const bool nesting,
- const sp<ConditionWizard>& wizard,
- const FieldMatcher& internalDimensions,
- const int64_t timeBaseNs, const int64_t startTimeNs)
- : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, wizard),
+DurationMetricProducer::DurationMetricProducer(
+ const ConfigKey& key, const DurationMetric& metric, const int conditionIndex,
+ const size_t startIndex, const size_t stopIndex, const size_t stopAllIndex,
+ const bool nesting, const sp<ConditionWizard>& wizard,
+ const FieldMatcher& internalDimensions, const int64_t timeBaseNs, const int64_t startTimeNs,
+ const unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
+ const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap)
+ : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, wizard, eventActivationMap,
+ eventDeactivationMap),
mAggregationType(metric.aggregation_type()),
mStartIndex(startIndex),
mStopIndex(stopIndex),
@@ -491,6 +493,7 @@
if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
ALOGE("DurationMetric %lld dropping data for condition dimension key %s",
(long long)mMetricId, newKey.getDimensionKeyInCondition().toString().c_str());
+ StatsdStats::getInstance().noteHardDimensionLimitReached(mMetricId);
return true;
}
}
@@ -504,6 +507,7 @@
if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
ALOGE("DurationMetric %lld dropping data for what dimension key %s",
(long long)mMetricId, newKey.getDimensionKeyInWhat().toString().c_str());
+ StatsdStats::getInstance().noteHardDimensionLimitReached(mMetricId);
return true;
}
}
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index 56c9fd6..0592b18 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -42,7 +42,12 @@
const int conditionIndex, const size_t startIndex,
const size_t stopIndex, const size_t stopAllIndex, const bool nesting,
const sp<ConditionWizard>& wizard,
- const FieldMatcher& internalDimensions, const int64_t timeBaseNs, const int64_t startTimeNs);
+ const FieldMatcher& internalDimensions, const int64_t timeBaseNs,
+ const int64_t startTimeNs,
+ const unordered_map<int, shared_ptr<Activation>>&
+ eventActivationMap = {},
+ const unordered_map<int, vector<shared_ptr<Activation>>>&
+ eventDeactivationMap = {});
virtual ~DurationMetricProducer();
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index 96133bd..a60a916 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -36,6 +36,7 @@
using std::string;
using std::unordered_map;
using std::vector;
+using std::shared_ptr;
namespace android {
namespace os {
@@ -54,8 +55,13 @@
EventMetricProducer::EventMetricProducer(const ConfigKey& key, const EventMetric& metric,
const int conditionIndex,
const sp<ConditionWizard>& wizard,
- const int64_t startTimeNs)
- : MetricProducer(metric.id(), key, startTimeNs, conditionIndex, wizard) {
+ const int64_t startTimeNs,
+ const unordered_map<int, shared_ptr<Activation>>&
+ eventActivationMap,
+ const unordered_map<int, vector<shared_ptr<Activation>>>&
+ eventDeactivationMap)
+ : MetricProducer(metric.id(), key, startTimeNs, conditionIndex, wizard, eventActivationMap,
+ eventDeactivationMap) {
if (metric.links().size() > 0) {
for (const auto& link : metric.links()) {
Metric2Condition mc;
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h
index 74e6bc8..aab53c8 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.h
+++ b/cmds/statsd/src/metrics/EventMetricProducer.h
@@ -35,7 +35,11 @@
public:
EventMetricProducer(const ConfigKey& key, const EventMetric& eventMetric,
const int conditionIndex, const sp<ConditionWizard>& wizard,
- const int64_t startTimeNs);
+ const int64_t startTimeNs,
+ const std::unordered_map<int, std::shared_ptr<Activation>>&
+ eventActivationMap = {},
+ const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
+ eventDeactivationMap = {});
virtual ~EventMetricProducer();
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index 1f423cd..e409b6fb 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -72,8 +72,11 @@
const sp<ConditionWizard>& wizard, const int whatMatcherIndex,
const sp<EventMatcherWizard>& matcherWizard, const int pullTagId, const int triggerAtomId,
const int atomId, const int64_t timeBaseNs, const int64_t startTimeNs,
- const sp<StatsPullerManager>& pullerManager)
- : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, wizard),
+ const sp<StatsPullerManager>& pullerManager,
+ const unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
+ const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap)
+ : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, wizard, eventActivationMap,
+ eventDeactivationMap),
mWhatMatcherIndex(whatMatcherIndex),
mEventMatcherWizard(matcherWizard),
mPullerManager(pullerManager),
@@ -133,8 +136,11 @@
mBucketSizeNs);
}
- // Adjust start for partial bucket
+ // Adjust start for partial first bucket and then pull if needed
mCurrentBucketStartTimeNs = startTimeNs;
+ if (mIsActive && mIsPulled && mSamplingType == GaugeMetric::RANDOM_ONE_SAMPLE) {
+ pullAndMatchEventsLocked(mCurrentBucketStartTimeNs);
+ }
VLOG("Gauge metric %lld created. bucket size %lld start_time: %lld sliced %d",
(long long)metric.id(), (long long)mBucketSizeNs, (long long)mTimeBaseNs,
@@ -295,11 +301,6 @@
}
}
-void GaugeMetricProducer::prepareFirstBucketLocked() {
- if (mIsActive && mIsPulled && mSamplingType == GaugeMetric::RANDOM_ONE_SAMPLE) {
- pullAndMatchEventsLocked(mCurrentBucketStartTimeNs);
- }
-}
void GaugeMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs) {
bool triggerPuller = false;
@@ -439,6 +440,7 @@
if (newTupleCount > mDimensionHardLimit) {
ALOGE("GaugeMetric %lld dropping data for dimension key %s",
(long long)mMetricId, newKey.toString().c_str());
+ StatsdStats::getInstance().noteHardDimensionLimitReached(mMetricId);
return true;
}
}
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
index a612adf..dfe1d56 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -58,11 +58,14 @@
public:
GaugeMetricProducer(const ConfigKey& key, const GaugeMetric& gaugeMetric,
const int conditionIndex, const sp<ConditionWizard>& conditionWizard,
- const int whatMatcherIndex,
- const sp<EventMatcherWizard>& matcherWizard,
+ const int whatMatcherIndex,const sp<EventMatcherWizard>& matcherWizard,
const int pullTagId, const int triggerAtomId, const int atomId,
const int64_t timeBaseNs, const int64_t startTimeNs,
- const sp<StatsPullerManager>& pullerManager);
+ const sp<StatsPullerManager>& pullerManager,
+ const std::unordered_map<int, std::shared_ptr<Activation>>&
+ eventActivationMap = {},
+ const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
+ eventDeactivationMap = {});
virtual ~GaugeMetricProducer();
@@ -125,8 +128,6 @@
void flushCurrentBucketLocked(const int64_t& eventTimeNs,
const int64_t& nextBucketStartTimeNs) override;
- void prepareFirstBucketLocked() override;
-
void pullAndMatchEventsLocked(const int64_t timestampNs);
const int mWhatMatcherIndex;
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index 1ab4fdf..3426a19 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -40,6 +40,29 @@
const int FIELD_ID_ACTIVE_EVENT_ACTIVATION_REMAINING_TTL_NANOS = 2;
const int FIELD_ID_ACTIVE_EVENT_ACTIVATION_STATE = 3;
+MetricProducer::MetricProducer(
+ const int64_t& metricId, const ConfigKey& key, const int64_t timeBaseNs,
+ const int conditionIndex, const sp<ConditionWizard>& wizard,
+ const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap,
+ const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
+ eventDeactivationMap)
+ : mMetricId(metricId),
+ mConfigKey(key),
+ mTimeBaseNs(timeBaseNs),
+ mCurrentBucketStartTimeNs(timeBaseNs),
+ mCurrentBucketNum(0),
+ mCondition(initialCondition(conditionIndex)),
+ mConditionTrackerIndex(conditionIndex),
+ mConditionSliced(false),
+ mWizard(wizard),
+ mContainANYPositionInDimensionsInWhat(false),
+ mSliceByPositionALL(false),
+ mHasLinksToAllConditionDimensionsInTracker(false),
+ mEventActivationMap(eventActivationMap),
+ mEventDeactivationMap(eventDeactivationMap),
+ mIsActive(mEventActivationMap.empty()) {
+ }
+
void MetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event) {
if (!mIsActive) {
return;
@@ -97,24 +120,6 @@
}
}
-void MetricProducer::addActivation(int activationTrackerIndex, const ActivationType& activationType,
- int64_t ttl_seconds, int deactivationTrackerIndex) {
- std::lock_guard<std::mutex> lock(mMutex);
- // When a metric producer does not depend on any activation, its mIsActive is true.
- // Therefore, if this is the 1st activation, mIsActive will turn to false. Otherwise it does not
- // change.
- if (mEventActivationMap.empty()) {
- mIsActive = false;
- }
- std::shared_ptr<Activation> activation =
- std::make_shared<Activation>(activationType, ttl_seconds * NS_PER_SEC);
- mEventActivationMap.emplace(activationTrackerIndex, activation);
- if (-1 != deactivationTrackerIndex) {
- auto& deactivationList = mEventDeactivationMap[deactivationTrackerIndex];
- deactivationList.push_back(activation);
- }
-}
-
void MetricProducer::activateLocked(int activationTrackerIndex, int64_t elapsedTimestampNs) {
auto it = mEventActivationMap.find(activationTrackerIndex);
if (it == mEventActivationMap.end()) {
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index fdbdc83..1e1eb69 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -69,6 +69,19 @@
NO_TIME_CONSTRAINTS = 2
};
+struct Activation {
+ Activation(const ActivationType& activationType, const int64_t ttlNs)
+ : ttl_ns(ttlNs),
+ start_ns(0),
+ state(ActivationState::kNotActive),
+ activationType(activationType) {}
+
+ const int64_t ttl_ns;
+ int64_t start_ns;
+ ActivationState state;
+ const ActivationType activationType;
+};
+
// A MetricProducer is responsible for compute one single metrics, creating stats log report, and
// writing the report to dropbox. MetricProducers should respond to package changes as required in
// PackageInfoListener, but if none of the metrics are slicing by package name, then the update can
@@ -76,21 +89,10 @@
class MetricProducer : public virtual PackageInfoListener {
public:
MetricProducer(const int64_t& metricId, const ConfigKey& key, const int64_t timeBaseNs,
- const int conditionIndex, const sp<ConditionWizard>& wizard)
- : mMetricId(metricId),
- mConfigKey(key),
- mTimeBaseNs(timeBaseNs),
- mCurrentBucketStartTimeNs(timeBaseNs),
- mCurrentBucketNum(0),
- mCondition(initialCondition(conditionIndex)),
- mConditionTrackerIndex(conditionIndex),
- mConditionSliced(false),
- mWizard(wizard),
- mContainANYPositionInDimensionsInWhat(false),
- mSliceByPositionALL(false),
- mHasLinksToAllConditionDimensionsInTracker(false),
- mIsActive(true) {
- }
+ const int conditionIndex, const sp<ConditionWizard>& wizard,
+ const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap,
+ const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
+ eventDeactivationMap);
virtual ~MetricProducer(){};
@@ -188,11 +190,6 @@
dropDataLocked(dropTimeNs);
}
- void prepareFirstBucket() {
- std::lock_guard<std::mutex> lock(mMutex);
- prepareFirstBucketLocked();
- }
-
void loadActiveMetric(const ActiveMetric& activeMetric, int64_t currentTimeNs) {
std::lock_guard<std::mutex> lock(mMutex);
loadActiveMetricLocked(activeMetric, currentTimeNs);
@@ -215,9 +212,6 @@
void flushIfExpire(int64_t elapsedTimestampNs);
- void addActivation(int activationTrackerIndex, const ActivationType& activationType,
- int64_t ttl_seconds, int deactivationTrackerIndex = -1);
-
void writeActiveMetricToProtoOutputStream(
int64_t currentTimeNs, const DumpReportReason reason, ProtoOutputStream* proto);
@@ -310,7 +304,6 @@
virtual size_t byteSizeLocked() const = 0;
virtual void dumpStatesLocked(FILE* out, bool verbose) const = 0;
virtual void dropDataLocked(const int64_t dropTimeNs) = 0;
- virtual void prepareFirstBucketLocked() {};
void loadActiveMetricLocked(const ActiveMetric& activeMetric, int64_t currentTimeNs);
void activateLocked(int activationTrackerIndex, int64_t elapsedTimestampNs);
void cancelEventActivationLocked(int deactivationTrackerIndex);
@@ -379,19 +372,6 @@
mutable std::mutex mMutex;
- struct Activation {
- Activation(const ActivationType& activationType, const int64_t ttlNs)
- : ttl_ns(ttlNs),
- start_ns(0),
- state(ActivationState::kNotActive),
- activationType(activationType) {}
-
- const int64_t ttl_ns;
- int64_t start_ns;
- ActivationState state;
- const ActivationType activationType;
- };
-
// When the metric producer has multiple activations, these activations are ORed to determine
// whether the metric producer is ready to generate metrics.
std::unordered_map<int, std::shared_ptr<Activation>> mEventActivationMap;
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index bc16024..7fe5a83 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -81,8 +81,11 @@
const ConfigKey& key, const ValueMetric& metric, const int conditionIndex,
const sp<ConditionWizard>& conditionWizard, const int whatMatcherIndex,
const sp<EventMatcherWizard>& matcherWizard, const int pullTagId, const int64_t timeBaseNs,
- const int64_t startTimeNs, const sp<StatsPullerManager>& pullerManager)
- : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, conditionWizard),
+ const int64_t startTimeNs, const sp<StatsPullerManager>& pullerManager,
+ const unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
+ const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap)
+ : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, conditionWizard,
+ eventActivationMap, eventDeactivationMap),
mWhatMatcherIndex(whatMatcherIndex),
mEventMatcherWizard(matcherWizard),
mPullerManager(pullerManager),
@@ -108,7 +111,7 @@
mMaxPullDelayNs(metric.max_pull_delay_sec() > 0 ? metric.max_pull_delay_sec() * NS_PER_SEC
: StatsdStats::kPullMaxDelayNs),
mSplitBucketForAppUpgrade(metric.split_bucket_for_app_upgrade()),
- // Condition timer will be set in prepareFirstBucketLocked.
+ // Condition timer will be set later within the constructor after pulling events
mConditionTimer(false, timeBaseNs) {
int64_t bucketSizeMills = 0;
if (metric.has_bucket()) {
@@ -154,6 +157,15 @@
// Adjust start for partial bucket
mCurrentBucketStartTimeNs = startTimeNs;
mConditionTimer.newBucketStart(mCurrentBucketStartTimeNs);
+
+ // Kicks off the puller immediately if condition is true and diff based.
+ if (mIsActive && mIsPulled && mCondition == ConditionState::kTrue && mUseDiff) {
+ pullAndMatchEventsLocked(mCurrentBucketStartTimeNs, mCondition);
+ }
+ // Now that activations are processed, start the condition timer if needed.
+ mConditionTimer.onConditionChanged(mIsActive && mCondition == ConditionState::kTrue,
+ mCurrentBucketStartTimeNs);
+
VLOG("value metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
(long long)mBucketSizeNs, (long long)mTimeBaseNs);
}
@@ -165,16 +177,6 @@
}
}
-void ValueMetricProducer::prepareFirstBucketLocked() {
- // Kicks off the puller immediately if condition is true and diff based.
- if (mIsActive && mIsPulled && mCondition == ConditionState::kTrue && mUseDiff) {
- pullAndMatchEventsLocked(mCurrentBucketStartTimeNs, mCondition);
- }
- // Now that activations are processed, start the condition timer if needed.
- mConditionTimer.onConditionChanged(mIsActive && mCondition == ConditionState::kTrue,
- mCurrentBucketStartTimeNs);
-}
-
void ValueMetricProducer::onSlicedConditionMayChangeLocked(bool overallCondition,
const int64_t eventTime) {
VLOG("Metric %lld onSlicedConditionMayChange", (long long)mMetricId);
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 739f6ef..d7cd397 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -54,10 +54,13 @@
public:
ValueMetricProducer(const ConfigKey& key, const ValueMetric& valueMetric,
const int conditionIndex, const sp<ConditionWizard>& conditionWizard,
- const int whatMatcherIndex,
- const sp<EventMatcherWizard>& matcherWizard,
+ const int whatMatcherIndex, const sp<EventMatcherWizard>& matcherWizard,
const int pullTagId, const int64_t timeBaseNs, const int64_t startTimeNs,
- const sp<StatsPullerManager>& pullerManager);
+ const sp<StatsPullerManager>& pullerManager,
+ const std::unordered_map<int, std::shared_ptr<Activation>>&
+ eventActivationMap = {},
+ const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
+ eventDeactivationMap = {});
virtual ~ValueMetricProducer();
@@ -116,8 +119,6 @@
void flushCurrentBucketLocked(const int64_t& eventTimeNs,
const int64_t& nextBucketStartTimeNs) override;
- void prepareFirstBucketLocked() override;
-
void dropDataLocked(const int64_t dropTimeNs) override;
// Calculate previous bucket end time based on current time.
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 40484f4..0fee71e 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -18,6 +18,7 @@
#include "Log.h"
#include "metrics_manager_util.h"
+#include "MetricProducer.h"
#include "../condition/CombinationConditionTracker.h"
#include "../condition/SimpleConditionTracker.h"
@@ -137,6 +138,62 @@
return true;
}
+// Validates a metricActivation and populates state.
+// EventActivationMap and EventDeactivationMap are supplied to a MetricProducer
+// to provide the producer with state about its activators and deactivators.
+// Returns false if there are errors.
+bool handleMetricActivation(
+ const StatsdConfig& config,
+ const int64_t metricId,
+ const int metricIndex,
+ const unordered_map<int64_t, int>& metricToActivationMap,
+ const unordered_map<int64_t, int>& logTrackerMap,
+ unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
+ unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
+ vector<int>& metricsWithActivation,
+ unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
+ unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap) {
+ // Check if metric has an associated activation
+ auto itr = metricToActivationMap.find(metricId);
+ if (itr == metricToActivationMap.end()) return true;
+
+ int activationIndex = itr->second;
+ const MetricActivation& metricActivation = config.metric_activation(activationIndex);
+
+ for (int i = 0; i < metricActivation.event_activation_size(); i++) {
+ const EventActivation& activation = metricActivation.event_activation(i);
+
+ auto itr = logTrackerMap.find(activation.atom_matcher_id());
+ if (itr == logTrackerMap.end()) {
+ ALOGE("Atom matcher not found for event activation.");
+ return false;
+ }
+
+ ActivationType activationType = (activation.has_activation_type()) ?
+ activation.activation_type() : metricActivation.activation_type();
+ std::shared_ptr<Activation> activationWrapper = std::make_shared<Activation>(
+ activationType, activation.ttl_seconds() * NS_PER_SEC);
+
+ int atomMatcherIndex = itr->second;
+ activationAtomTrackerToMetricMap[atomMatcherIndex].push_back(metricIndex);
+ eventActivationMap.emplace(atomMatcherIndex, activationWrapper);
+
+ if (activation.has_deactivation_atom_matcher_id()) {
+ itr = logTrackerMap.find(activation.deactivation_atom_matcher_id());
+ if (itr == logTrackerMap.end()) {
+ ALOGE("Atom matcher not found for event deactivation.");
+ return false;
+ }
+ int deactivationAtomMatcherIndex = itr->second;
+ deactivationAtomTrackerToMetricMap[deactivationAtomMatcherIndex].push_back(metricIndex);
+ eventDeactivationMap[deactivationAtomMatcherIndex].push_back(activationWrapper);
+ }
+ }
+
+ metricsWithActivation.push_back(metricIndex);
+ return true;
+}
+
bool initLogTrackers(const StatsdConfig& config, const UidMap& uidMap,
unordered_map<int64_t, int>& logTrackerMap,
vector<sp<LogMatchingTracker>>& allAtomMatchers, set<int>& allTagIds) {
@@ -293,16 +350,33 @@
const vector<sp<LogMatchingTracker>>& allAtomMatchers,
vector<sp<ConditionTracker>>& allConditionTrackers,
vector<sp<MetricProducer>>& allMetricProducers,
- unordered_map<int, std::vector<int>>& conditionToMetricMap,
- unordered_map<int, std::vector<int>>& trackerToMetricMap,
- unordered_map<int64_t, int>& metricMap, std::set<int64_t>& noReportMetricIds) {
+ unordered_map<int, vector<int>>& conditionToMetricMap,
+ unordered_map<int, vector<int>>& trackerToMetricMap,
+ unordered_map<int64_t, int>& metricMap, std::set<int64_t>& noReportMetricIds,
+ unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
+ unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
+ vector<int>& metricsWithActivation) {
sp<ConditionWizard> wizard = new ConditionWizard(allConditionTrackers);
sp<EventMatcherWizard> matcherWizard = new EventMatcherWizard(allAtomMatchers);
const int allMetricsCount = config.count_metric_size() + config.duration_metric_size() +
- config.event_metric_size() + config.value_metric_size();
+ config.event_metric_size() + config.gauge_metric_size() +
+ config.value_metric_size();
allMetricProducers.reserve(allMetricsCount);
StatsPullerManager statsPullerManager;
+ // Construct map from metric id to metric activation index. The map will be used to determine
+ // the metric activation corresponding to a metric.
+ unordered_map<int64_t, int> metricToActivationMap;
+ for (int i = 0; i < config.metric_activation_size(); i++) {
+ const MetricActivation& metricActivation = config.metric_activation(i);
+ int64_t metricId = metricActivation.metric_id();
+ if (metricToActivationMap.find(metricId) != metricToActivationMap.end()) {
+ ALOGE("Metric %lld has multiple MetricActivations", (long long) metricId);
+ return false;
+ }
+ metricToActivationMap.insert({metricId, i});
+ }
+
// Build MetricProducers for each metric defined in config.
// build CountMetricProducer
for (int i = 0; i < config.count_metric_size(); i++) {
@@ -337,8 +411,17 @@
}
}
- sp<MetricProducer> countProducer =
- new CountMetricProducer(key, metric, conditionIndex, wizard, timeBaseTimeNs, currentTimeNs);
+ unordered_map<int, shared_ptr<Activation>> eventActivationMap;
+ unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
+ bool success = handleMetricActivation(config, metric.id(), metricIndex,
+ metricToActivationMap, logTrackerMap, activationAtomTrackerToMetricMap,
+ deactivationAtomTrackerToMetricMap, metricsWithActivation, eventActivationMap,
+ eventDeactivationMap);
+ if (!success) return false;
+
+ sp<MetricProducer> countProducer = new CountMetricProducer(
+ key, metric, conditionIndex, wizard, timeBaseTimeNs, currentTimeNs,
+ eventActivationMap, eventDeactivationMap);
allMetricProducers.push_back(countProducer);
}
@@ -406,9 +489,18 @@
}
}
+ unordered_map<int, shared_ptr<Activation>> eventActivationMap;
+ unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
+ bool success = handleMetricActivation(config, metric.id(), metricIndex,
+ metricToActivationMap, logTrackerMap, activationAtomTrackerToMetricMap,
+ deactivationAtomTrackerToMetricMap, metricsWithActivation, eventActivationMap,
+ eventDeactivationMap);
+ if (!success) return false;
+
sp<MetricProducer> durationMetric = new DurationMetricProducer(
key, metric, conditionIndex, trackerIndices[0], trackerIndices[1],
- trackerIndices[2], nesting, wizard, internalDimensions, timeBaseTimeNs, currentTimeNs);
+ trackerIndices[2], nesting, wizard, internalDimensions, timeBaseTimeNs,
+ currentTimeNs, eventActivationMap, eventDeactivationMap);
allMetricProducers.push_back(durationMetric);
}
@@ -443,8 +535,17 @@
}
}
- sp<MetricProducer> eventMetric =
- new EventMetricProducer(key, metric, conditionIndex, wizard, timeBaseTimeNs);
+ unordered_map<int, shared_ptr<Activation>> eventActivationMap;
+ unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
+ bool success = handleMetricActivation(config, metric.id(), metricIndex,
+ metricToActivationMap, logTrackerMap, activationAtomTrackerToMetricMap,
+ deactivationAtomTrackerToMetricMap, metricsWithActivation, eventActivationMap,
+ eventDeactivationMap);
+ if (!success) return false;
+
+ sp<MetricProducer> eventMetric = new EventMetricProducer(
+ key, metric, conditionIndex, wizard, timeBaseTimeNs, eventActivationMap,
+ eventDeactivationMap);
allMetricProducers.push_back(eventMetric);
}
@@ -500,9 +601,18 @@
}
}
+ unordered_map<int, shared_ptr<Activation>> eventActivationMap;
+ unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
+ bool success = handleMetricActivation(config, metric.id(), metricIndex,
+ metricToActivationMap, logTrackerMap, activationAtomTrackerToMetricMap,
+ deactivationAtomTrackerToMetricMap, metricsWithActivation, eventActivationMap,
+ eventDeactivationMap);
+ if (!success) return false;
+
sp<MetricProducer> valueProducer = new ValueMetricProducer(
key, metric, conditionIndex, wizard, trackerIndex, matcherWizard, pullTagId,
- timeBaseTimeNs, currentTimeNs, pullerManager);
+ timeBaseTimeNs, currentTimeNs, pullerManager, eventActivationMap,
+ eventDeactivationMap);
allMetricProducers.push_back(valueProducer);
}
@@ -586,10 +696,19 @@
}
}
+ unordered_map<int, shared_ptr<Activation>> eventActivationMap;
+ unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
+ bool success = handleMetricActivation(config, metric.id(), metricIndex,
+ metricToActivationMap, logTrackerMap, activationAtomTrackerToMetricMap,
+ deactivationAtomTrackerToMetricMap, metricsWithActivation, eventActivationMap,
+ eventDeactivationMap);
+ if (!success) return false;
+
sp<MetricProducer> gaugeProducer = new GaugeMetricProducer(
key, metric, conditionIndex, wizard,
trackerIndex, matcherWizard, pullTagId, triggerAtomId, atomTagId,
- timeBaseTimeNs, currentTimeNs, pullerManager);
+ timeBaseTimeNs, currentTimeNs, pullerManager,
+ eventActivationMap, eventDeactivationMap);
allMetricProducers.push_back(gaugeProducer);
}
for (int i = 0; i < config.no_report_metric_size(); ++i) {
@@ -707,73 +826,6 @@
return true;
}
-bool initMetricActivations(const ConfigKey& key, const StatsdConfig& config,
- const int64_t currentTimeNs,
- const unordered_map<int64_t, int> &logEventTrackerMap,
- const unordered_map<int64_t, int> &metricProducerMap,
- vector<sp<MetricProducer>>& allMetricProducers,
- unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
- unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
- vector<int>& metricsWithActivation) {
- for (int i = 0; i < config.metric_activation_size(); ++i) {
- const MetricActivation& metric_activation = config.metric_activation(i);
- auto itr = metricProducerMap.find(metric_activation.metric_id());
- if (itr == metricProducerMap.end()) {
- ALOGE("Metric id not found in metric activation: %lld",
- (long long)metric_activation.metric_id());
- return false;
- }
- const int metricTrackerIndex = itr->second;
- if (metricTrackerIndex < 0 || metricTrackerIndex >= (int)allMetricProducers.size()) {
- ALOGE("Invalid metric tracker index.");
- return false;
- }
- const sp<MetricProducer>& metric = allMetricProducers[metricTrackerIndex];
- metricsWithActivation.push_back(metricTrackerIndex);
- for (int j = 0; j < metric_activation.event_activation_size(); ++j) {
- const EventActivation& activation = metric_activation.event_activation(j);
- auto logTrackerIt = logEventTrackerMap.find(activation.atom_matcher_id());
- if (logTrackerIt == logEventTrackerMap.end()) {
- ALOGE("Atom matcher not found for event activation.");
- return false;
- }
- const int atomMatcherIndex = logTrackerIt->second;
- activationAtomTrackerToMetricMap[atomMatcherIndex].push_back(
- metricTrackerIndex);
-
- ActivationType activationType;
- if (activation.has_activation_type()) {
- activationType = activation.activation_type();
- } else {
- activationType = metric_activation.activation_type();
- }
-
- if (activation.has_deactivation_atom_matcher_id()) {
- auto deactivationAtomMatcherIt =
- logEventTrackerMap.find(activation.deactivation_atom_matcher_id());
- if (deactivationAtomMatcherIt == logEventTrackerMap.end()) {
- ALOGE("Atom matcher not found for event deactivation.");
- return false;
- }
- const int deactivationMatcherIndex = deactivationAtomMatcherIt->second;
- deactivationAtomTrackerToMetricMap[deactivationMatcherIndex]
- .push_back(metricTrackerIndex);
- metric->addActivation(atomMatcherIndex, activationType, activation.ttl_seconds(),
- deactivationMatcherIndex);
- } else {
- metric->addActivation(atomMatcherIndex, activationType, activation.ttl_seconds());
- }
- }
- }
- return true;
-}
-
-void prepareFirstBucket(const vector<sp<MetricProducer>>& allMetricProducers) {
- for (const auto& metric: allMetricProducers) {
- metric->prepareFirstBucket();
- }
-}
-
bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap& uidMap,
const sp<StatsPullerManager>& pullerManager,
const sp<AlarmMonitor>& anomalyAlarmMonitor,
@@ -810,7 +862,8 @@
if (!initMetrics(key, config, timeBaseNs, currentTimeNs, uidMap, pullerManager, logTrackerMap,
conditionTrackerMap, allAtomMatchers, allConditionTrackers, allMetricProducers,
conditionToMetricMap, trackerToMetricMap, metricProducerMap,
- noReportMetricIds)) {
+ noReportMetricIds, activationAtomTrackerToMetricMap,
+ deactivationAtomTrackerToMetricMap, metricsWithActivation)) {
ALOGE("initMetricProducers failed");
return false;
}
@@ -824,14 +877,6 @@
ALOGE("initAlarms failed");
return false;
}
- if (!initMetricActivations(key, config, currentTimeNs, logTrackerMap, metricProducerMap,
- allMetricProducers, activationAtomTrackerToMetricMap,
- deactivationAtomTrackerToMetricMap, metricsWithActivation)) {
- ALOGE("initMetricActivations failed");
- return false;
- }
-
- prepareFirstBucket(allMetricProducers);
return true;
}
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/metrics_manager_util.h
index 3704969..3802948 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.h
+++ b/cmds/statsd/src/metrics/metrics_manager_util.h
@@ -91,7 +91,10 @@
std::vector<sp<MetricProducer>>& allMetricProducers,
std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
- std::set<int64_t>& noReportMetricIds);
+ std::set<int64_t>& noReportMetricIds,
+ std::unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
+ std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
+ std::vector<int>& metricsWithActivation);
// Initialize MetricsManager from StatsdConfig.
// Parameters are the members of MetricsManager. See MetricsManager for declaration.
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index 47c21aa..b027e8e 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -79,8 +79,6 @@
logEventMatcherIndex, eventMatcherWizard,
-1, -1, tagId, 5, 600 * NS_PER_SEC + NS_PER_SEC / 2,
pullerManager);
- gaugeProducer.prepareFirstBucket();
-
EXPECT_EQ(600500000000, gaugeProducer.mCurrentBucketStartTimeNs);
EXPECT_EQ(10, gaugeProducer.mCurrentBucketNum);
@@ -126,8 +124,6 @@
tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- gaugeProducer.prepareFirstBucket();
-
vector<shared_ptr<LogEvent>> allData;
allData.clear();
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
@@ -211,7 +207,6 @@
logEventMatcherIndex, eventMatcherWizard,
-1 /* -1 means no pulling */, -1, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
- gaugeProducer.prepareFirstBucket();
sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert, alarmMonitor);
EXPECT_TRUE(anomalyTracker != nullptr);
@@ -303,7 +298,6 @@
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
bucketStartTimeNs, bucketStartTimeNs, pullerManager);
- gaugeProducer.prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
@@ -370,7 +364,6 @@
logEventMatcherIndex, eventMatcherWizard,
tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- gaugeProducer.prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
@@ -431,7 +424,6 @@
GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard,
logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
bucketStartTimeNs, bucketStartTimeNs, pullerManager);
- gaugeProducer.prepareFirstBucket();
gaugeProducer.onConditionChanged(true, bucketStartTimeNs + 8);
EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
@@ -521,7 +513,6 @@
GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard,
logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
bucketStartTimeNs, bucketStartTimeNs, pullerManager);
- gaugeProducer.prepareFirstBucket();
gaugeProducer.onSlicedConditionMayChange(true, bucketStartTimeNs + 8);
@@ -572,7 +563,6 @@
logEventMatcherIndex, eventMatcherWizard,
tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- gaugeProducer.prepareFirstBucket();
Alert alert;
alert.set_id(101);
@@ -681,7 +671,6 @@
logEventMatcherIndex, eventMatcherWizard,
tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- gaugeProducer.prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
@@ -766,7 +755,6 @@
logEventMatcherIndex, eventMatcherWizard,
tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- gaugeProducer.prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 2262c76..4b9d0c0 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -105,7 +105,6 @@
kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
logEventMatcherIndex, eventMatcherWizard, tagId,
bucketStartTimeNs, bucketStartTimeNs, pullerManager);
- valueProducer->prepareFirstBucket();
return valueProducer;
}
@@ -125,7 +124,6 @@
new ValueMetricProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
- valueProducer->prepareFirstBucket();
valueProducer->mCondition = ConditionState::kFalse;
return valueProducer;
}
@@ -169,7 +167,6 @@
ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
logEventMatcherIndex, eventMatcherWizard, -1, startTimeBase,
22, pullerManager);
- valueProducer.prepareFirstBucket();
EXPECT_EQ(startTimeBase, valueProducer.calcPreviousBucketEndTime(60 * NS_PER_SEC + 10));
EXPECT_EQ(startTimeBase, valueProducer.calcPreviousBucketEndTime(60 * NS_PER_SEC + 10));
@@ -199,7 +196,6 @@
ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
logEventMatcherIndex, eventMatcherWizard, -1, 5,
600 * NS_PER_SEC + NS_PER_SEC / 2, pullerManager);
- valueProducer.prepareFirstBucket();
EXPECT_EQ(600500000000, valueProducer.mCurrentBucketStartTimeNs);
EXPECT_EQ(10, valueProducer.mCurrentBucketNum);
@@ -381,7 +377,6 @@
kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
logEventMatcherIndex, eventMatcherWizard, tagId,
bucketStartTimeNs, bucketStartTimeNs, pullerManager);
- valueProducer->prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -670,7 +665,6 @@
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- valueProducer.prepareFirstBucket();
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -728,7 +722,6 @@
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
- valueProducer.prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -779,7 +772,6 @@
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
- valueProducer.prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -854,7 +846,6 @@
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- valueProducer.prepareFirstBucket();
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -897,7 +888,6 @@
ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- valueProducer.prepareFirstBucket();
valueProducer.mCondition = ConditionState::kFalse;
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
@@ -972,7 +962,6 @@
ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
logEventMatcherIndex, eventMatcherWizard, -1 /*not pulled*/,
bucketStartTimeNs, bucketStartTimeNs, pullerManager);
- valueProducer.prepareFirstBucket();
sp<AnomalyTracker> anomalyTracker = valueProducer.addAnomalyTracker(alert, alarmMonitor);
@@ -1269,7 +1258,6 @@
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- valueProducer.prepareFirstBucket();
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -1314,7 +1302,6 @@
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- valueProducer.prepareFirstBucket();
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -1361,7 +1348,6 @@
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- valueProducer.prepareFirstBucket();
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -1412,7 +1398,6 @@
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- valueProducer.prepareFirstBucket();
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -1458,7 +1443,6 @@
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- valueProducer.prepareFirstBucket();
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -1532,7 +1516,6 @@
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- valueProducer.prepareFirstBucket();
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -2081,7 +2064,6 @@
ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, bucket2StartTimeNs,
bucket2StartTimeNs, pullerManager);
- valueProducer.prepareFirstBucket();
valueProducer.mCondition = ConditionState::kFalse;
// Event should be skipped since it is from previous bucket.
@@ -2862,7 +2844,6 @@
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
- valueProducer.prepareFirstBucket();
ProtoOutputStream output;
std::set<string> strSet;
@@ -2905,7 +2886,6 @@
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
- valueProducer.prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -2969,7 +2949,6 @@
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
- valueProducer.prepareFirstBucket();
ProtoOutputStream output;
std::set<string> strSet;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 38aac1b..7f27368 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1163,6 +1163,10 @@
sendMessage(H.ATTACH_AGENT, agent);
}
+ public void attachStartupAgents(String dataDir) {
+ sendMessage(H.ATTACH_STARTUP_AGENTS, dataDir);
+ }
+
public void setSchedulingGroup(int group) {
// Note: do this immediately, since going into the foreground
// should happen regardless of what pending work we have to do
@@ -1812,6 +1816,7 @@
public static final int EXECUTE_TRANSACTION = 159;
public static final int RELAUNCH_ACTIVITY = 160;
public static final int PURGE_RESOURCES = 161;
+ public static final int ATTACH_STARTUP_AGENTS = 162;
String codeToString(int code) {
if (DEBUG_MESSAGES) {
@@ -1855,6 +1860,7 @@
case EXECUTE_TRANSACTION: return "EXECUTE_TRANSACTION";
case RELAUNCH_ACTIVITY: return "RELAUNCH_ACTIVITY";
case PURGE_RESOURCES: return "PURGE_RESOURCES";
+ case ATTACH_STARTUP_AGENTS: return "ATTACH_STARTUP_AGENTS";
}
}
return Integer.toString(code);
@@ -2043,6 +2049,9 @@
case PURGE_RESOURCES:
schedulePurgeIdler();
break;
+ case ATTACH_STARTUP_AGENTS:
+ handleAttachStartupAgents((String) msg.obj);
+ break;
}
Object obj = msg.obj;
if (obj instanceof SomeArgs) {
@@ -3779,6 +3788,27 @@
}
}
+ static void handleAttachStartupAgents(String dataDir) {
+ try {
+ Path code_cache = ContextImpl.getCodeCacheDirBeforeBind(new File(dataDir)).toPath();
+ if (!Files.exists(code_cache)) {
+ return;
+ }
+ Path startup_path = code_cache.resolve("startup_agents");
+ if (Files.exists(startup_path)) {
+ for (Path p : Files.newDirectoryStream(startup_path)) {
+ handleAttachAgent(
+ p.toAbsolutePath().toString()
+ + "="
+ + dataDir,
+ null);
+ }
+ }
+ } catch (Exception e) {
+ // Ignored.
+ }
+ }
+
private static final ThreadLocal<Intent> sCurrentBroadcastIntent = new ThreadLocal<Intent>();
/**
@@ -6427,26 +6457,6 @@
NetworkSecurityConfigProvider.install(appContext);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
-
- if (isAppDebuggable) {
- try {
- // Load all the agents in the code_cache/startup_agents directory.
- // We pass the absolute path to the data_dir as an argument.
- Path startup_path = appContext.getCodeCacheDir().toPath().resolve("startup_agents");
- if (Files.exists(startup_path)) {
- for (Path p : Files.newDirectoryStream(startup_path)) {
- handleAttachAgent(
- p.toAbsolutePath().toString()
- + "="
- + appContext.getDataDir().toPath().toAbsolutePath().toString(),
- data.info);
- }
- }
- } catch (Exception e) {
- // Ignored.
- }
- }
-
// Continue loading instrumentation.
if (ii != null) {
ApplicationInfo instrApp;
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index a201307..86bf20a 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -3169,6 +3169,15 @@
}
@Override
+ public String getSetupWizardPackageName() {
+ try {
+ return mPM.getSetupWizardPackageName();
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ @Override
public String getIncidentReportApproverPackageName() {
try {
return mPM.getIncidentReportApproverPackageName();
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index ef23d5e..5b211e14 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -741,12 +741,21 @@
public File getCodeCacheDir() {
synchronized (mSync) {
if (mCodeCacheDir == null) {
- mCodeCacheDir = new File(getDataDir(), "code_cache");
+ mCodeCacheDir = getCodeCacheDirBeforeBind(getDataDir());
}
return ensurePrivateCacheDirExists(mCodeCacheDir, XATTR_INODE_CODE_CACHE);
}
}
+ /**
+ * Helper for getting code-cache dir potentially before application bind.
+ *
+ * @hide
+ */
+ static File getCodeCacheDirBeforeBind(File dataDir) {
+ return new File(dataDir, "code_cache");
+ }
+
@Override
public File getExternalCacheDir() {
// Operates on primary external storage
diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl
index cfa065b..51a64ff 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -137,6 +137,7 @@
IVoiceInteractor voiceInteractor);
void handleTrustStorageUpdate();
void attachAgent(String path);
+ void attachStartupAgents(String dataDir);
void scheduleApplicationInfoChanged(in ApplicationInfo ai);
void setNetworkBlockSeq(long procStateSeq);
void scheduleTransaction(in ClientTransaction transaction);
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
index 750020e..0ba1989 100644
--- a/core/java/android/app/ITaskStackListener.aidl
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -197,4 +197,11 @@
* Called when any additions or deletions to the recent tasks list have been made.
*/
void onRecentTaskListUpdated();
+
+ /**
+ * Called when Recent Tasks list is frozen or unfrozen.
+ *
+ * @param frozen if true, Recents Tasks list is currently frozen, false otherwise
+ */
+ void onRecentTaskListFrozenChanged(boolean frozen);
}
diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java
index 46045fa..f21aaf3 100644
--- a/core/java/android/app/TaskStackListener.java
+++ b/core/java/android/app/TaskStackListener.java
@@ -190,4 +190,8 @@
@Override
public void onRecentTaskListUpdated() throws RemoteException {
}
+
+ @Override
+ public void onRecentTaskListFrozenChanged(boolean frozen) {
+ }
}
diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java
index b873be3..713126e 100644
--- a/core/java/android/app/admin/DevicePolicyManagerInternal.java
+++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java
@@ -24,6 +24,10 @@
/**
* Device policy manager local system service interface.
*
+ * Maintenance note: if you need to expose information from DPMS to lower level services such as
+ * PM/UM/AM/etc, then exposing it from DevicePolicyManagerInternal is not safe because it may cause
+ * lock order inversion. Consider using {@link DevicePolicyCache} instead.
+ *
* @hide Only for use within the system server.
*/
public abstract class DevicePolicyManagerInternal {
@@ -81,6 +85,16 @@
public abstract boolean isActiveAdminWithPolicy(int uid, int reqPolicy);
/**
+ * Checks if an app with given uid is the active supervision admin.
+ *
+ * <p>This takes the DPMS lock. DO NOT call from PM/UM/AM with their lock held.
+ *
+ * @param uid App uid.
+ * @return true if the uid is the active supervision app.
+ */
+ public abstract boolean isActiveSupervisionApp(int uid);
+
+ /**
* Creates an intent to show the admin support dialog to say that an action is disallowed by
* the device/profile owner.
*
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 656f474..1f13a1e 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -801,8 +801,8 @@
* {@link #EXTRA_TIME_USED}. Cannot be {@code null} unless the observer is
* being registered with a {@code timeUsed} equal to or greater than
* {@code timeLimit}.
- * @throws SecurityException if the caller doesn't have both SUSPEND_APPS and OBSERVE_APP_USAGE
- * permissions.
+ * @throws SecurityException if the caller is neither the active supervision app nor does it
+ * have both SUSPEND_APPS and OBSERVE_APP_USAGE permissions.
* @hide
*/
@SystemApi
@@ -827,8 +827,8 @@
* an observer that was already unregistered or never registered will have no effect.
*
* @param observerId The id of the observer that was previously registered.
- * @throws SecurityException if the caller doesn't have both SUSPEND_APPS and OBSERVE_APP_USAGE
- * permissions.
+ * @throws SecurityException if the caller is neither the active supervision app nor does it
+ * have both SUSPEND_APPS and OBSERVE_APP_USAGE permissions.
* @hide
*/
@SystemApi
diff --git a/core/java/android/content/pm/AndroidTestBaseUpdater.java b/core/java/android/content/pm/AndroidTestBaseUpdater.java
index da1a693..8fcfe71 100644
--- a/core/java/android/content/pm/AndroidTestBaseUpdater.java
+++ b/core/java/android/content/pm/AndroidTestBaseUpdater.java
@@ -18,10 +18,17 @@
import static android.content.pm.SharedLibraryNames.ANDROID_TEST_BASE;
import static android.content.pm.SharedLibraryNames.ANDROID_TEST_RUNNER;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
+import android.content.Context;
import android.content.pm.PackageParser.Package;
import android.os.Build;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.compat.IPlatformCompat;
/**
* Updates a package to ensure that if it targets <= Q that the android.test.base library is
@@ -37,10 +44,26 @@
*/
@VisibleForTesting
public class AndroidTestBaseUpdater extends PackageSharedLibraryUpdater {
+ private static final String TAG = "AndroidTestBaseUpdater";
- private static boolean apkTargetsApiLevelLessThanOrEqualToQ(Package pkg) {
- int targetSdkVersion = pkg.applicationInfo.targetSdkVersion;
- return targetSdkVersion <= Build.VERSION_CODES.Q;
+ /**
+ * Remove android.test.base library for apps that target SDK R or more and do not depend on
+ * android.test.runner (as it depends on classes from the android.test.base library).
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
+ private static final long REMOVE_ANDROID_TEST_BASE = 133396946L;
+
+ private static boolean isChangeEnabled(Package pkg) {
+ IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface(
+ ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
+ try {
+ return platformCompat.isChangeEnabled(REMOVE_ANDROID_TEST_BASE, pkg.applicationInfo);
+ } catch (RemoteException | NullPointerException e) {
+ Log.e(TAG, "Failed to get a response from PLATFORM_COMPAT_SERVICE", e);
+ }
+ // Fall back to previous behaviour.
+ return pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.Q;
}
@Override
@@ -48,7 +71,7 @@
// Packages targeted at <= Q expect the classes in the android.test.base library
// to be accessible so this maintains backward compatibility by adding the
// android.test.base library to those packages.
- if (apkTargetsApiLevelLessThanOrEqualToQ(pkg)) {
+ if (!isChangeEnabled(pkg)) {
prefixRequiredLibrary(pkg, ANDROID_TEST_BASE);
} else {
// If a package already depends on android.test.runner then add a dependency on
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 4d7c43a..19d8edf 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -686,6 +686,8 @@
String getSystemCaptionsServicePackageName();
+ String getSetupWizardPackageName();
+
String getIncidentReportApproverPackageName();
boolean isPackageStateProtected(String packageName, int userId);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index fd14d23..9513ce8 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -7427,6 +7427,17 @@
}
/**
+ * @return the system defined setup wizard package name, or null if there's none.
+ *
+ * @hide
+ */
+ @Nullable
+ public String getSetupWizardPackageName() {
+ throw new UnsupportedOperationException(
+ "getSetupWizardPackageName not implemented in subclass");
+ }
+
+ /**
* @return the incident report approver app package name, or null if it's not defined
* by the OEM.
*
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index 9f0bade..ccfa184 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -350,7 +350,7 @@
@UnsupportedAppUsage
public UserHandle getUserHandle() {
- return new UserHandle(id);
+ return UserHandle.of(id);
}
@Override
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 111a8c4..5c65238 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -3265,42 +3265,77 @@
/**
* Called when the framework connects and has declared a new network ready for use.
- * This callback may be called more than once if the {@link Network} that is
- * satisfying the request changes. This will always immediately be followed by a
- * call to {@link #onCapabilitiesChanged(Network, NetworkCapabilities)} then by a
- * call to {@link #onLinkPropertiesChanged(Network, LinkProperties)}, and a call to
- * {@link #onBlockedStatusChanged(Network, boolean)}.
+ *
+ * <p>For callbacks registered with {@link #registerNetworkCallback}, multiple networks may
+ * be available at the same time, and onAvailable will be called for each of these as they
+ * appear.
+ *
+ * <p>For callbacks registered with {@link #requestNetwork} and
+ * {@link #registerDefaultNetworkCallback}, this means the network passed as an argument
+ * is the new best network for this request and is now tracked by this callback ; this
+ * callback will no longer receive method calls about other networks that may have been
+ * passed to this method previously. The previously-best network may have disconnected, or
+ * it may still be around and the newly-best network may simply be better.
+ *
+ * <p>Starting with {@link android.os.Build.VERSION_CODES#O}, this will always immediately
+ * be followed by a call to {@link #onCapabilitiesChanged(Network, NetworkCapabilities)}
+ * then by a call to {@link #onLinkPropertiesChanged(Network, LinkProperties)}, and a call
+ * to {@link #onBlockedStatusChanged(Network, boolean)}.
+ *
+ * <p>Do NOT call {@link #getNetworkCapabilities(Network)} or
+ * {@link #getLinkProperties(Network)} or other synchronous ConnectivityManager methods in
+ * this callback as this is prone to race conditions (there is no guarantee the objects
+ * returned by these methods will be current). Instead, wait for a call to
+ * {@link #onCapabilitiesChanged(Network, NetworkCapabilities)} and
+ * {@link #onLinkPropertiesChanged(Network, LinkProperties)} whose arguments are guaranteed
+ * to be well-ordered with respect to other callbacks.
*
* @param network The {@link Network} of the satisfying network.
*/
public void onAvailable(@NonNull Network network) {}
/**
- * Called when the network is about to be disconnected. Often paired with an
- * {@link NetworkCallback#onAvailable} call with the new replacement network
- * for graceful handover. This may not be called if we have a hard loss
- * (loss without warning). This may be followed by either a
- * {@link NetworkCallback#onLost} call or a
- * {@link NetworkCallback#onAvailable} call for this network depending
- * on whether we lose or regain it.
+ * Called when the network is about to be lost, typically because there are no outstanding
+ * requests left for it. This may be paired with a {@link NetworkCallback#onAvailable} call
+ * with the new replacement network for graceful handover. This method is not guaranteed
+ * to be called before {@link NetworkCallback#onLost} is called, for example in case a
+ * network is suddenly disconnected.
*
- * @param network The {@link Network} that is about to be disconnected.
- * @param maxMsToLive The time in ms the framework will attempt to keep the
- * network connected. Note that the network may suffer a
- * hard loss at any time.
+ * <p>Do NOT call {@link #getNetworkCapabilities(Network)} or
+ * {@link #getLinkProperties(Network)} or other synchronous ConnectivityManager methods in
+ * this callback as this is prone to race conditions ; calling these methods while in a
+ * callback may return an outdated or even a null object.
+ *
+ * @param network The {@link Network} that is about to be lost.
+ * @param maxMsToLive The time in milliseconds the system intends to keep the network
+ * connected for graceful handover; note that the network may still
+ * suffer a hard loss at any time.
*/
public void onLosing(@NonNull Network network, int maxMsToLive) {}
/**
- * Called when the framework has a hard loss of the network or when the
- * graceful failure ends.
+ * Called when a network disconnects or otherwise no longer satisfies this request or
+ * callback.
+ *
+ * <p>If the callback was registered with requestNetwork() or
+ * registerDefaultNetworkCallback(), it will only be invoked against the last network
+ * returned by onAvailable() when that network is lost and no other network satisfies
+ * the criteria of the request.
+ *
+ * <p>If the callback was registered with registerNetworkCallback() it will be called for
+ * each network which no longer satisfies the criteria of the callback.
+ *
+ * <p>Do NOT call {@link #getNetworkCapabilities(Network)} or
+ * {@link #getLinkProperties(Network)} or other synchronous ConnectivityManager methods in
+ * this callback as this is prone to race conditions ; calling these methods while in a
+ * callback may return an outdated or even a null object.
*
* @param network The {@link Network} lost.
*/
public void onLost(@NonNull Network network) {}
/**
- * Called if no network is found in the timeout time specified in
+ * Called if no network is found within the timeout time specified in
* {@link #requestNetwork(NetworkRequest, NetworkCallback, int)} call or if the
* requested network request cannot be fulfilled (whether or not a timeout was
* specified). When this callback is invoked the associated
@@ -3310,8 +3345,15 @@
public void onUnavailable() {}
/**
- * Called when the network the framework connected to for this request
- * changes capabilities but still satisfies the stated need.
+ * Called when the network corresponding to this request changes capabilities but still
+ * satisfies the requested criteria.
+ *
+ * <p>Starting with {@link android.os.Build.VERSION_CODES#O} this method is guaranteed
+ * to be called immediately after {@link #onAvailable}.
+ *
+ * <p>Do NOT call {@link #getLinkProperties(Network)} or other synchronous
+ * ConnectivityManager methods in this callback as this is prone to race conditions :
+ * calling these methods while in a callback may return an outdated or even a null object.
*
* @param network The {@link Network} whose capabilities have changed.
* @param networkCapabilities The new {@link android.net.NetworkCapabilities} for this
@@ -3321,8 +3363,14 @@
@NonNull NetworkCapabilities networkCapabilities) {}
/**
- * Called when the network the framework connected to for this request
- * changes {@link LinkProperties}.
+ * Called when the network corresponding to this request changes {@link LinkProperties}.
+ *
+ * <p>Starting with {@link android.os.Build.VERSION_CODES#O} this method is guaranteed
+ * to be called immediately after {@link #onAvailable}.
+ *
+ * <p>Do NOT call {@link #getNetworkCapabilities(Network)} or other synchronous
+ * ConnectivityManager methods in this callback as this is prone to race conditions :
+ * calling these methods while in a callback may return an outdated or even a null object.
*
* @param network The {@link Network} whose link properties have changed.
* @param linkProperties The new {@link LinkProperties} for this network.
@@ -3331,12 +3379,20 @@
@NonNull LinkProperties linkProperties) {}
/**
- * Called when the network the framework connected to for this request
- * goes into {@link NetworkInfo.State#SUSPENDED}.
- * This generally means that while the TCP connections are still live,
- * temporarily network data fails to transfer. Specifically this is used
- * on cellular networks to mask temporary outages when driving through
- * a tunnel, etc.
+ * Called when the network the framework connected to for this request suspends data
+ * transmission temporarily.
+ *
+ * <p>This generally means that while the TCP connections are still live temporarily
+ * network data fails to transfer. To give a specific example, this is used on cellular
+ * networks to mask temporary outages when driving through a tunnel, etc. In general this
+ * means read operations on sockets on this network will block once the buffers are
+ * drained, and write operations will block once the buffers are full.
+ *
+ * <p>Do NOT call {@link #getNetworkCapabilities(Network)} or
+ * {@link #getLinkProperties(Network)} or other synchronous ConnectivityManager methods in
+ * this callback as this is prone to race conditions (there is no guarantee the objects
+ * returned by these methods will be current).
+ *
* @hide
*/
public void onNetworkSuspended(@NonNull Network network) {}
@@ -3345,6 +3401,12 @@
* Called when the network the framework connected to for this request
* returns from a {@link NetworkInfo.State#SUSPENDED} state. This should always be
* preceded by a matching {@link NetworkCallback#onNetworkSuspended} call.
+
+ * <p>Do NOT call {@link #getNetworkCapabilities(Network)} or
+ * {@link #getLinkProperties(Network)} or other synchronous ConnectivityManager methods in
+ * this callback as this is prone to race conditions : calling these methods while in a
+ * callback may return an outdated or even a null object.
+ *
* @hide
*/
public void onNetworkResumed(@NonNull Network network) {}
@@ -3352,6 +3414,11 @@
/**
* Called when access to the specified network is blocked or unblocked.
*
+ * <p>Do NOT call {@link #getNetworkCapabilities(Network)} or
+ * {@link #getLinkProperties(Network)} or other synchronous ConnectivityManager methods in
+ * this callback as this is prone to race conditions : calling these methods while in a
+ * callback may return an outdated or even a null object.
+ *
* @param network The {@link Network} whose blocked status has changed.
* @param blocked The blocked status of this {@link Network}.
*/
@@ -3588,13 +3655,51 @@
/**
* Request a network to satisfy a set of {@link android.net.NetworkCapabilities}.
*
- * This {@link NetworkRequest} will live until released via
- * {@link #unregisterNetworkCallback(NetworkCallback)} or the calling application exits. A
- * version of the method which takes a timeout is
- * {@link #requestNetwork(NetworkRequest, NetworkCallback, int)}.
- * Status of the request can be followed by listening to the various
- * callbacks described in {@link NetworkCallback}. The {@link Network}
- * can be used to direct traffic to the network.
+ * <p>This method will attempt to find the best network that matches the passed
+ * {@link NetworkRequest}, and to bring up one that does if none currently satisfies the
+ * criteria. The platform will evaluate which network is the best at its own discretion.
+ * Throughput, latency, cost per byte, policy, user preference and other considerations
+ * may be factored in the decision of what is considered the best network.
+ *
+ * <p>As long as this request is outstanding, the platform will try to maintain the best network
+ * matching this request, while always attempting to match the request to a better network if
+ * possible. If a better match is found, the platform will switch this request to the now-best
+ * network and inform the app of the newly best network by invoking
+ * {@link NetworkCallback#onAvailable(Network)} on the provided callback. Note that the platform
+ * will not try to maintain any other network than the best one currently matching the request:
+ * a network not matching any network request may be disconnected at any time.
+ *
+ * <p>For example, an application could use this method to obtain a connected cellular network
+ * even if the device currently has a data connection over Ethernet. This may cause the cellular
+ * radio to consume additional power. Or, an application could inform the system that it wants
+ * a network supporting sending MMSes and have the system let it know about the currently best
+ * MMS-supporting network through the provided {@link NetworkCallback}.
+ *
+ * <p>The status of the request can be followed by listening to the various callbacks described
+ * in {@link NetworkCallback}. The {@link Network} object passed to the callback methods can be
+ * used to direct traffic to the network (although accessing some networks may be subject to
+ * holding specific permissions). Callers will learn about the specific characteristics of the
+ * network through
+ * {@link NetworkCallback#onCapabilitiesChanged(Network, NetworkCapabilities)} and
+ * {@link NetworkCallback#onLinkPropertiesChanged(Network, LinkProperties)}. The methods of the
+ * provided {@link NetworkCallback} will only be invoked due to changes in the best network
+ * matching the request at any given time; therefore when a better network matching the request
+ * becomes available, the {@link NetworkCallback#onAvailable(Network)} method is called
+ * with the new network after which no further updates are given about the previously-best
+ * network, unless it becomes the best again at some later time. All callbacks are invoked
+ * in order on the same thread, which by default is a thread created by the framework running
+ * in the app.
+ * {@see #requestNetwork(NetworkRequest, NetworkCallback, Handler)} to change where the
+ * callbacks are invoked.
+ *
+ * <p>This{@link NetworkRequest} will live until released via
+ * {@link #unregisterNetworkCallback(NetworkCallback)} or the calling application exits, at
+ * which point the system may let go of the network at any time.
+ *
+ * <p>A version of this method which takes a timeout is
+ * {@link #requestNetwork(NetworkRequest, NetworkCallback, int)}, that an app can use to only
+ * wait for a limited amount of time for the network to become unavailable.
+ *
* <p>It is presently unsupported to request a network with mutable
* {@link NetworkCapabilities} such as
* {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED} or
@@ -3602,7 +3707,7 @@
* as these {@code NetworkCapabilities} represent states that a particular
* network may never attain, and whether a network will attain these states
* is unknown prior to bringing up the network so the framework does not
- * know how to go about satisfing a request with these capabilities.
+ * know how to go about satisfying a request with these capabilities.
*
* <p>This method requires the caller to hold either the
* {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
@@ -3625,34 +3730,17 @@
/**
* Request a network to satisfy a set of {@link android.net.NetworkCapabilities}.
*
- * This {@link NetworkRequest} will live until released via
- * {@link #unregisterNetworkCallback(NetworkCallback)} or the calling application exits. A
- * version of the method which takes a timeout is
- * {@link #requestNetwork(NetworkRequest, NetworkCallback, int)}.
- * Status of the request can be followed by listening to the various
- * callbacks described in {@link NetworkCallback}. The {@link Network}
- * can be used to direct traffic to the network.
- * <p>It is presently unsupported to request a network with mutable
- * {@link NetworkCapabilities} such as
- * {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED} or
- * {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL}
- * as these {@code NetworkCapabilities} represent states that a particular
- * network may never attain, and whether a network will attain these states
- * is unknown prior to bringing up the network so the framework does not
- * know how to go about satisfying a request with these capabilities.
+ * This method behaves identically to {@link #requestNetwork(NetworkRequest, NetworkCallback)}
+ * but runs all the callbacks on the passed Handler.
*
- * <p>This method requires the caller to hold either the
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
- * or the ability to modify system settings as determined by
- * {@link android.provider.Settings.System#canWrite}.</p>
+ * <p>This method has the same permission requirements as
+ * {@link #requestNetwork(NetworkRequest, NetworkCallback)} and throws the same exceptions in
+ * the same conditions.
*
* @param request {@link NetworkRequest} describing this request.
* @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
* the callback must not be shared - it uniquely specifies this request.
* @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
- * @throws IllegalArgumentException if {@code request} contains invalid network capabilities.
- * @throws SecurityException if missing the appropriate permissions.
- * @throws RuntimeException if request limit per UID is exceeded.
*/
public void requestNetwork(@NonNull NetworkRequest request,
@NonNull NetworkCallback networkCallback, @NonNull Handler handler) {
@@ -3677,10 +3765,9 @@
* timeout) - {@link #registerNetworkCallback(NetworkRequest, NetworkCallback)} is provided
* for that purpose. Calling this method will attempt to bring up the requested network.
*
- * <p>This method requires the caller to hold either the
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
- * or the ability to modify system settings as determined by
- * {@link android.provider.Settings.System#canWrite}.</p>
+ * <p>This method has the same permission requirements as
+ * {@link #requestNetwork(NetworkRequest, NetworkCallback)} and throws the same exceptions in
+ * the same conditions.
*
* @param request {@link NetworkRequest} describing this request.
* @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
@@ -3688,9 +3775,6 @@
* @param timeoutMs The time in milliseconds to attempt looking for a suitable network
* before {@link NetworkCallback#onUnavailable()} is called. The timeout must
* be a positive value (i.e. >0).
- * @throws IllegalArgumentException if {@code request} contains invalid network capabilities.
- * @throws SecurityException if missing the appropriate permissions.
- * @throws RuntimeException if request limit per UID is exceeded.
*/
public void requestNetwork(@NonNull NetworkRequest request,
@NonNull NetworkCallback networkCallback, int timeoutMs) {
@@ -3703,21 +3787,13 @@
* Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, limited
* by a timeout.
*
- * This function behaves identically to the version without timeout, but if a suitable
- * network is not found within the given time (in milliseconds) the
- * {@link NetworkCallback#onUnavailable} callback is called. The request can still be
- * released normally by calling {@link #unregisterNetworkCallback(NetworkCallback)} but does
- * not have to be released if timed-out (it is automatically released). Unregistering a
- * request that timed out is not an error.
+ * This method behaves identically to
+ * {@link #requestNetwork(NetworkRequest, NetworkCallback, int)} but runs all the callbacks
+ * on the passed Handler.
*
- * <p>Do not use this method to poll for the existence of specific networks (e.g. with a small
- * timeout) - {@link #registerNetworkCallback(NetworkRequest, NetworkCallback)} is provided
- * for that purpose. Calling this method will attempt to bring up the requested network.
- *
- * <p>This method requires the caller to hold either the
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
- * or the ability to modify system settings as determined by
- * {@link android.provider.Settings.System#canWrite}.</p>
+ * <p>This method has the same permission requirements as
+ * {@link #requestNetwork(NetworkRequest, NetworkCallback, int)} and throws the same exceptions
+ * in the same conditions.
*
* @param request {@link NetworkRequest} describing this request.
* @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
@@ -3725,9 +3801,6 @@
* @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
* @param timeoutMs The time in milliseconds to attempt looking for a suitable network
* before {@link NetworkCallback#onUnavailable} is called.
- * @throws IllegalArgumentException if {@code request} contains invalid network capabilities.
- * @throws SecurityException if missing the appropriate permissions.
- * @throws RuntimeException if request limit per UID is exceeded.
*/
public void requestNetwork(@NonNull NetworkRequest request,
@NonNull NetworkCallback networkCallback, @NonNull Handler handler, int timeoutMs) {
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index d3f48ac..3ec0aea 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -68,6 +68,7 @@
// in the format "rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max"
private String mTcpBufferSizes;
private IpPrefix mNat64Prefix;
+ private boolean mWakeOnLanSupported;
private static final int MIN_MTU = 68;
private static final int MIN_MTU_V6 = 1280;
@@ -193,6 +194,7 @@
setMtu(source.mMtu);
mTcpBufferSizes = source.mTcpBufferSizes;
mNat64Prefix = source.mNat64Prefix;
+ mWakeOnLanSupported = source.mWakeOnLanSupported;
}
}
@@ -852,6 +854,7 @@
mMtu = 0;
mTcpBufferSizes = null;
mNat64Prefix = null;
+ mWakeOnLanSupported = false;
}
/**
@@ -913,6 +916,10 @@
resultJoiner.add("MTU:");
resultJoiner.add(Integer.toString(mMtu));
+ if (mWakeOnLanSupported) {
+ resultJoiner.add("WakeOnLanSupported: true");
+ }
+
if (mTcpBufferSizes != null) {
resultJoiner.add("TcpBufferSizes:");
resultJoiner.add(mTcpBufferSizes);
@@ -1425,6 +1432,37 @@
}
/**
+ * Compares this {@code LinkProperties} WakeOnLan supported against the target.
+ *
+ * @param target LinkProperties to compare.
+ * @return {@code true} if both are identical, {@code false} otherwise.
+ * @hide
+ */
+ public boolean isIdenticalWakeOnLan(LinkProperties target) {
+ return isWakeOnLanSupported() == target.isWakeOnLanSupported();
+ }
+
+ /**
+ * Set whether the network interface supports WakeOnLAN
+ *
+ * @param supported WakeOnLAN supported value
+ *
+ * @hide
+ */
+ public void setWakeOnLanSupported(boolean supported) {
+ mWakeOnLanSupported = supported;
+ }
+
+ /**
+ * Returns whether the network interface supports WakeOnLAN
+ *
+ * @return {@code true} if interface supports WakeOnLAN, {@code false} otherwise.
+ */
+ public boolean isWakeOnLanSupported() {
+ return mWakeOnLanSupported;
+ }
+
+ /**
* Compares this {@code LinkProperties} instance against the target
* LinkProperties in {@code obj}. Two LinkPropertieses are equal if
* all their fields are equal in values.
@@ -1461,7 +1499,8 @@
&& isIdenticalStackedLinks(target)
&& isIdenticalMtu(target)
&& isIdenticalTcpBufferSizes(target)
- && isIdenticalNat64Prefix(target);
+ && isIdenticalNat64Prefix(target)
+ && isIdenticalWakeOnLan(target);
}
/**
@@ -1577,7 +1616,8 @@
+ (mUsePrivateDns ? 57 : 0)
+ mPcscfs.size() * 67
+ ((null == mPrivateDnsServerName) ? 0 : mPrivateDnsServerName.hashCode())
- + Objects.hash(mNat64Prefix);
+ + Objects.hash(mNat64Prefix)
+ + (mWakeOnLanSupported ? 71 : 0);
}
/**
@@ -1622,6 +1662,8 @@
ArrayList<LinkProperties> stackedLinks = new ArrayList<>(mStackedLinks.values());
dest.writeList(stackedLinks);
+
+ dest.writeBoolean(mWakeOnLanSupported);
}
/**
@@ -1677,6 +1719,7 @@
for (LinkProperties stackedLink: stackedLinks) {
netProp.addStackedLink(stackedLink);
}
+ netProp.setWakeOnLanSupported(in.readBoolean());
return netProp;
}
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index b3125d8..6a709b5 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -243,7 +243,8 @@
public static final String BASE_OS = SystemProperties.get("ro.build.version.base_os", "");
/**
- * The user-visible security patch level.
+ * The user-visible security patch level. This value represents the date when the device
+ * most recently applied a security patch.
*/
public static final String SECURITY_PATCH = SystemProperties.get(
"ro.build.version.security_patch", "");
diff --git a/core/java/android/os/HwParcel.java b/core/java/android/os/HwParcel.java
index cfb582e..5e8929c 100644
--- a/core/java/android/os/HwParcel.java
+++ b/core/java/android/os/HwParcel.java
@@ -23,6 +23,8 @@
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
+import dalvik.annotation.optimization.FastNative;
+
import libcore.util.NativeAllocationRegistry;
import java.lang.annotation.Retention;
@@ -72,46 +74,54 @@
/**
* Writes an interface token into the parcel used to verify that
- * a transaction has made it to the write type of interface.
+ * a transaction has made it to the right type of interface.
*
* @param interfaceName fully qualified name of interface message
* is being sent to.
*/
+ @FastNative
public native final void writeInterfaceToken(String interfaceName);
/**
* Writes a boolean value to the end of the parcel.
* @param val to write
*/
+ @FastNative
public native final void writeBool(boolean val);
/**
* Writes a byte value to the end of the parcel.
* @param val to write
*/
+ @FastNative
public native final void writeInt8(byte val);
/**
* Writes a short value to the end of the parcel.
* @param val to write
*/
+ @FastNative
public native final void writeInt16(short val);
/**
* Writes a int value to the end of the parcel.
* @param val to write
*/
+ @FastNative
public native final void writeInt32(int val);
/**
* Writes a long value to the end of the parcel.
* @param val to write
*/
+ @FastNative
public native final void writeInt64(long val);
/**
* Writes a float value to the end of the parcel.
* @param val to write
*/
+ @FastNative
public native final void writeFloat(float val);
/**
* Writes a double value to the end of the parcel.
* @param val to write
*/
+ @FastNative
public native final void writeDouble(double val);
/**
* Writes a String value to the end of the parcel.
@@ -120,6 +130,7 @@
*
* @param val to write
*/
+ @FastNative
public native final void writeString(String val);
/**
* Writes a native handle (without duplicating the underlying
@@ -127,42 +138,50 @@
*
* @param val to write
*/
+ @FastNative
public native final void writeNativeHandle(@Nullable NativeHandle val);
/**
* Writes an array of boolean values to the end of the parcel.
* @param val to write
*/
+ @FastNative
private native final void writeBoolVector(boolean[] val);
/**
* Writes an array of byte values to the end of the parcel.
* @param val to write
*/
+ @FastNative
private native final void writeInt8Vector(byte[] val);
/**
* Writes an array of short values to the end of the parcel.
* @param val to write
*/
+ @FastNative
private native final void writeInt16Vector(short[] val);
/**
* Writes an array of int values to the end of the parcel.
* @param val to write
*/
+ @FastNative
private native final void writeInt32Vector(int[] val);
/**
* Writes an array of long values to the end of the parcel.
* @param val to write
*/
+ @FastNative
private native final void writeInt64Vector(long[] val);
/**
* Writes an array of float values to the end of the parcel.
* @param val to write
*/
+ @FastNative
private native final void writeFloatVector(float[] val);
/**
* Writes an array of double values to the end of the parcel.
* @param val to write
*/
+ @FastNative
private native final void writeDoubleVector(double[] val);
/**
* Writes an array of String values to the end of the parcel.
@@ -171,6 +190,7 @@
*
* @param val to write
*/
+ @FastNative
private native final void writeStringVector(String[] val);
/**
* Writes an array of native handles to the end of the parcel.
@@ -179,6 +199,7 @@
*
* @param val array of {@link NativeHandle} objects to write
*/
+ @FastNative
private native final void writeNativeHandleVector(NativeHandle[] val);
/**
@@ -299,6 +320,7 @@
* Write a hwbinder object to the end of the parcel.
* @param binder value to write
*/
+ @FastNative
public native final void writeStrongBinder(IHwBinder binder);
/**
@@ -314,48 +336,56 @@
* @return value parsed from the parcel
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
public native final boolean readBool();
/**
* Reads a byte value from the current location in the parcel.
* @return value parsed from the parcel
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
public native final byte readInt8();
/**
* Reads a short value from the current location in the parcel.
* @return value parsed from the parcel
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
public native final short readInt16();
/**
* Reads a int value from the current location in the parcel.
* @return value parsed from the parcel
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
public native final int readInt32();
/**
* Reads a long value from the current location in the parcel.
* @return value parsed from the parcel
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
public native final long readInt64();
/**
* Reads a float value from the current location in the parcel.
* @return value parsed from the parcel
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
public native final float readFloat();
/**
* Reads a double value from the current location in the parcel.
* @return value parsed from the parcel
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
public native final double readDouble();
/**
* Reads a String value from the current location in the parcel.
* @return value parsed from the parcel
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
public native final String readString();
/**
* Reads a native handle (without duplicating the underlying file
@@ -366,6 +396,7 @@
* @return a {@link NativeHandle} instance parsed from the parcel
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
public native final @Nullable NativeHandle readNativeHandle();
/**
* Reads an embedded native handle (without duplicating the underlying
@@ -379,6 +410,7 @@
* @return a {@link NativeHandle} instance parsed from the parcel
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
public native final @Nullable NativeHandle readEmbeddedNativeHandle(
long parentHandle, long offset);
@@ -387,54 +419,63 @@
* @return array of parsed values
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
private native final boolean[] readBoolVectorAsArray();
/**
* Reads an array of byte values from the parcel.
* @return array of parsed values
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
private native final byte[] readInt8VectorAsArray();
/**
* Reads an array of short values from the parcel.
* @return array of parsed values
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
private native final short[] readInt16VectorAsArray();
/**
* Reads an array of int values from the parcel.
* @return array of parsed values
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
private native final int[] readInt32VectorAsArray();
/**
* Reads an array of long values from the parcel.
* @return array of parsed values
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
private native final long[] readInt64VectorAsArray();
/**
* Reads an array of float values from the parcel.
* @return array of parsed values
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
private native final float[] readFloatVectorAsArray();
/**
* Reads an array of double values from the parcel.
* @return array of parsed values
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
private native final double[] readDoubleVectorAsArray();
/**
* Reads an array of String values from the parcel.
* @return array of parsed values
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
private native final String[] readStringVectorAsArray();
/**
* Reads an array of native handles from the parcel.
* @return array of {@link NativeHandle} objects
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
private native final NativeHandle[] readNativeHandleAsArray();
/**
@@ -537,6 +578,7 @@
* @return binder object read from parcel or null if no binder can be read
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
public native final IHwBinder readStrongBinder();
/**
@@ -544,6 +586,7 @@
* @return blob of size expectedSize
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
public native final HwBlob readBuffer(long expectedSize);
/**
@@ -559,6 +602,7 @@
* @throws NullPointerException if the transaction specified the blob to be null
* but nullable is false
*/
+ @FastNative
public native final HwBlob readEmbeddedBuffer(
long expectedSize, long parentHandle, long offset,
boolean nullable);
@@ -567,26 +611,31 @@
* Write a buffer into the transaction.
* @param blob blob to write into the parcel.
*/
+ @FastNative
public native final void writeBuffer(HwBlob blob);
/**
* Write a status value into the blob.
* @param status value to write
*/
+ @FastNative
public native final void writeStatus(int status);
/**
* @throws IllegalArgumentException if a success vaue cannot be read
* @throws RemoteException if success value indicates a transaction error
*/
+ @FastNative
public native final void verifySuccess();
/**
* Should be called to reduce memory pressure when this object no longer needs
* to be written to.
*/
+ @FastNative
public native final void releaseTemporaryStorage();
/**
* Should be called when object is no longer needed to reduce possible memory
* pressure if the Java GC does not get to this object in time.
*/
+ @FastNative
public native final void release();
/**
@@ -597,6 +646,7 @@
// Returns address of the "freeFunction".
private static native final long native_init();
+ @FastNative
private native final void native_setup(boolean allocate);
static {
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 50487e9..783ab44 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -305,8 +305,11 @@
private static native void nativeWriteFloat(long nativePtr, float val);
@FastNative
private static native void nativeWriteDouble(long nativePtr, double val);
+ @FastNative
static native void nativeWriteString(long nativePtr, String val);
+ @FastNative
private static native void nativeWriteStrongBinder(long nativePtr, IBinder val);
+ @FastNative
private static native long nativeWriteFileDescriptor(long nativePtr, FileDescriptor val);
private static native byte[] nativeCreateByteArray(long nativePtr);
@@ -320,8 +323,11 @@
private static native float nativeReadFloat(long nativePtr);
@CriticalNative
private static native double nativeReadDouble(long nativePtr);
+ @FastNative
static native String nativeReadString(long nativePtr);
+ @FastNative
private static native IBinder nativeReadStrongBinder(long nativePtr);
+ @FastNative
private static native FileDescriptor nativeReadFileDescriptor(long nativePtr);
private static native long nativeCreate();
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 76e728a..43b9c67 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -420,10 +420,9 @@
* Background thread group - All threads in
* this group are scheduled with a reduced share of the CPU.
* Value is same as constant SP_BACKGROUND of enum SchedPolicy.
- * FIXME rename to THREAD_GROUP_BACKGROUND.
* @hide
*/
- public static final int THREAD_GROUP_BG_NONINTERACTIVE = 0;
+ public static final int THREAD_GROUP_BACKGROUND = 0;
/**
* Foreground thread group - All threads in
@@ -809,7 +808,7 @@
*
* group == THREAD_GROUP_DEFAULT means to move all non-background priority
* threads to the foreground scheduling group, but to leave background
- * priority threads alone. group == THREAD_GROUP_BG_NONINTERACTIVE moves all
+ * priority threads alone. group == THREAD_GROUP_BACKGROUND moves all
* threads, regardless of priority, to the background scheduling group.
* group == THREAD_GROUP_FOREGROUND is not allowed.
*
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 0754dc7..3558fcd 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -39,6 +39,7 @@
/** @hide A user id to indicate all users on the device */
@UnsupportedAppUsage
+ @TestApi
public static final @UserIdInt int USER_ALL = -1;
/** @hide A user handle to indicate all users on the device */
@@ -69,8 +70,11 @@
/** @hide An undefined user id */
@UnsupportedAppUsage
+ @TestApi
public static final @UserIdInt int USER_NULL = -10000;
+ private static final @NonNull UserHandle NULL = new UserHandle(USER_NULL);
+
/**
* @hide A user id constant to indicate the "owner" user of the device
* @deprecated Consider using either {@link UserHandle#USER_SYSTEM} constant or
@@ -91,6 +95,7 @@
/** @hide A user id constant to indicate the "system" user of the device */
@UnsupportedAppUsage
+ @TestApi
public static final @UserIdInt int USER_SYSTEM = 0;
/** @hide A user serial constant to indicate the "system" user of the device */
@@ -110,6 +115,27 @@
public static final boolean MU_ENABLED = true;
/** @hide */
+ @TestApi
+ public static final int MIN_SECONDARY_USER_ID = 10;
+
+ /**
+ * Arbitrary user handle cache size. We use the cache even when {@link #MU_ENABLED} is false
+ * anyway, so we can always assume in CTS that UserHandle.of(10) returns a cached instance
+ * even on non-multiuser devices.
+ */
+ private static final int NUM_CACHED_USERS = 4;
+
+ private static final UserHandle[] CACHED_USER_INFOS = new UserHandle[NUM_CACHED_USERS];
+
+ static {
+ // Not lazily initializing the cache, so that we can share them across processes.
+ // (We'll create them in zygote.)
+ for (int i = 0; i < CACHED_USER_INFOS.length; i++) {
+ CACHED_USER_INFOS[i] = new UserHandle(MIN_SECONDARY_USER_ID + i);
+ }
+ }
+
+ /** @hide */
@UnsupportedAppUsage
public static final int ERR_GID = -1;
/** @hide */
@@ -209,6 +235,7 @@
* @hide
*/
@UnsupportedAppUsage
+ @TestApi
public static @UserIdInt int getUserId(int uid) {
if (MU_ENABLED) {
return uid / PER_USER_RANGE;
@@ -229,9 +256,31 @@
}
/** @hide */
+ @TestApi
@SystemApi
public static UserHandle of(@UserIdInt int userId) {
- return userId == USER_SYSTEM ? SYSTEM : new UserHandle(userId);
+ if (userId == USER_SYSTEM) {
+ return SYSTEM; // Most common.
+ }
+ // These are sequential; so use a switch. Maybe they'll be optimized to a table lookup.
+ switch (userId) {
+ case USER_ALL:
+ return ALL;
+
+ case USER_CURRENT:
+ return CURRENT;
+
+ case USER_CURRENT_OR_SELF:
+ return CURRENT_OR_SELF;
+ }
+ if (userId >= MIN_SECONDARY_USER_ID
+ && userId < (MIN_SECONDARY_USER_ID + CACHED_USER_INFOS.length)) {
+ return CACHED_USER_INFOS[userId - MIN_SECONDARY_USER_ID];
+ }
+ if (userId == USER_NULL) { // Not common.
+ return NULL;
+ }
+ return new UserHandle(userId);
}
/**
@@ -239,6 +288,7 @@
* @hide
*/
@UnsupportedAppUsage
+ @TestApi
public static int getUid(@UserIdInt int userId, @AppIdInt int appId) {
if (MU_ENABLED) {
return userId * PER_USER_RANGE + (appId % PER_USER_RANGE);
@@ -404,6 +454,7 @@
* @hide
*/
@SystemApi
+ @TestApi
public static @UserIdInt int myUserId() {
return getUserId(Process.myUid());
}
@@ -513,7 +564,9 @@
public static final @android.annotation.NonNull Parcelable.Creator<UserHandle> CREATOR
= new Parcelable.Creator<UserHandle>() {
public UserHandle createFromParcel(Parcel in) {
- return new UserHandle(in);
+ // Try to avoid allocation; use of() here. Keep this and the constructor below
+ // in sync.
+ return UserHandle.of(in.readInt());
}
public UserHandle[] newArray(int size) {
@@ -532,6 +585,6 @@
* positioned at the location in the buffer where it was written.
*/
public UserHandle(Parcel in) {
- mHandle = in.readInt();
+ mHandle = in.readInt(); // Keep this and createFromParcel() in sync.
}
}
diff --git a/core/java/android/service/euicc/EuiccService.java b/core/java/android/service/euicc/EuiccService.java
index ff8b135..8a9f689 100644
--- a/core/java/android/service/euicc/EuiccService.java
+++ b/core/java/android/service/euicc/EuiccService.java
@@ -15,6 +15,8 @@
*/
package android.service.euicc;
+import static android.telephony.euicc.EuiccCardManager.ResetOption;
+
import android.annotation.CallSuper;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -503,7 +505,7 @@
String nickname);
/**
- * Erase all of the subscriptions on the device.
+ * Erase all operational subscriptions on the device.
*
* <p>This is intended to be used for device resets. As such, the reset should be performed even
* if an active SIM must be deactivated in order to access the eUICC.
@@ -512,10 +514,31 @@
* @return the result of the erase operation. May be one of the predefined {@code RESULT_}
* constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}.
* @see android.telephony.euicc.EuiccManager#eraseSubscriptions
+ *
+ * @deprecated From R, callers should specify a flag for specific set of subscriptions to erase
+ * and use @link{onEraseSubscriptionsWithOptions} instead
*/
+ @Deprecated
public abstract int onEraseSubscriptions(int slotId);
/**
+ * Erase specific subscriptions on the device.
+ *
+ * <p>This is intended to be used for device resets. As such, the reset should be performed even
+ * if an active SIM must be deactivated in order to access the eUICC.
+ *
+ * @param slotIndex index of the SIM slot to use for the operation.
+ * @param options flag for specific group of subscriptions to erase
+ * @return the result of the erase operation. May be one of the predefined {@code RESULT_}
+ * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}.
+ * @see android.telephony.euicc.EuiccManager#eraseSubscriptionsWithOptions
+ */
+ public int onEraseSubscriptionsWithOptions(int slotIndex, @ResetOption int options) {
+ throw new UnsupportedOperationException(
+ "This method must be overridden to enable the ResetOption parameter");
+ }
+
+ /**
* Ensure that subscriptions will be retained on the next factory reset.
*
* <p>Called directly before a factory reset. Assumes that a normal factory reset will lead to
@@ -751,6 +774,23 @@
}
@Override
+ public void eraseSubscriptionsWithOptions(
+ int slotIndex, @ResetOption int options, IEraseSubscriptionsCallback callback) {
+ mExecutor.execute(new Runnable() {
+ @Override
+ public void run() {
+ int result = EuiccService.this.onEraseSubscriptionsWithOptions(
+ slotIndex, options);
+ try {
+ callback.onComplete(result);
+ } catch (RemoteException e) {
+ // Can't communicate with the phone process; ignore.
+ }
+ }
+ });
+ }
+
+ @Override
public void retainSubscriptionsForFactoryReset(int slotId,
IRetainSubscriptionsForFactoryResetCallback callback) {
mExecutor.execute(new Runnable() {
diff --git a/core/java/android/service/euicc/IEuiccService.aidl b/core/java/android/service/euicc/IEuiccService.aidl
index c2cdf09..2acc47a 100644
--- a/core/java/android/service/euicc/IEuiccService.aidl
+++ b/core/java/android/service/euicc/IEuiccService.aidl
@@ -52,6 +52,8 @@
void updateSubscriptionNickname(int slotId, String iccid, String nickname,
in IUpdateSubscriptionNicknameCallback callback);
void eraseSubscriptions(int slotId, in IEraseSubscriptionsCallback callback);
+ void eraseSubscriptionsWithOptions(
+ int slotIndex, int options, in IEraseSubscriptionsCallback callback);
void retainSubscriptionsForFactoryReset(
int slotId, in IRetainSubscriptionsForFactoryResetCallback callback);
}
\ No newline at end of file
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 81643e9..5bda867 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -36,6 +36,7 @@
import android.sysprop.DisplayProperties;
import android.text.style.AbsoluteSizeSpan;
import android.text.style.AccessibilityClickableSpan;
+import android.text.style.AccessibilityReplacementSpan;
import android.text.style.AccessibilityURLSpan;
import android.text.style.AlignmentSpan;
import android.text.style.BackgroundColorSpan;
@@ -735,6 +736,8 @@
/** @hide */
public static final int LINE_HEIGHT_SPAN = 28;
/** @hide */
+ public static final int ACCESSIBILITY_REPLACEMENT_SPAN = 29;
+ /** @hide */
public static final int LAST_SPAN = LINE_HEIGHT_SPAN;
/**
@@ -860,7 +863,7 @@
case LEADING_MARGIN_SPAN:
readSpan(p, sp, new LeadingMarginSpan.Standard(p));
- break;
+ break;
case URL_SPAN:
readSpan(p, sp, new URLSpan(p));
@@ -933,7 +936,11 @@
case LINE_HEIGHT_SPAN:
readSpan(p, sp, new LineHeightSpan.Standard(p));
break;
-
+
+ case ACCESSIBILITY_REPLACEMENT_SPAN:
+ readSpan(p, sp, new AccessibilityReplacementSpan(p));
+ break;
+
default:
throw new RuntimeException("bogus span encoding " + kind);
}
diff --git a/core/java/android/text/style/AccessibilityReplacementSpan.java b/core/java/android/text/style/AccessibilityReplacementSpan.java
new file mode 100644
index 0000000..07b0975
--- /dev/null
+++ b/core/java/android/text/style/AccessibilityReplacementSpan.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2019 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.text.style;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.ParcelableSpan;
+import android.text.TextUtils;
+
+/**
+ * This class serves as a parcelable placeholder for the ReplacementSpans.
+ *
+ * This span contains content description of original span to let Accessibility service to do the
+ * substitution for it.
+ *
+ * @hide
+ */
+public class AccessibilityReplacementSpan extends ReplacementSpan
+ implements ParcelableSpan {
+ // The content description of the span this one replaces
+ private CharSequence mContentDescription;
+
+ /**
+ * @param contentDescription The content description of the span this one replaces
+ */
+ public AccessibilityReplacementSpan(CharSequence contentDescription) {
+ this.setContentDescription(contentDescription);
+ mContentDescription = contentDescription;
+ }
+
+ public AccessibilityReplacementSpan(Parcel p) {
+ mContentDescription = p.readCharSequence();
+ }
+
+ @Override
+ public int getSpanTypeId() {
+ return getSpanTypeIdInternal();
+ }
+
+ @Override
+ public int getSpanTypeIdInternal() {
+ return TextUtils.ACCESSIBILITY_REPLACEMENT_SPAN;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ writeToParcelInternal(dest, flags);
+ }
+
+ @Override
+ public void writeToParcelInternal(Parcel dest, int flags) {
+ dest.writeCharSequence(mContentDescription);
+ }
+
+ @Override
+ public int getSize(Paint paint, CharSequence text, int start, int end,
+ Paint.FontMetricsInt fm) {
+ return 0;
+ }
+
+ @Override
+ public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y,
+ int bottom, Paint paint) {
+ }
+
+ public static final @android.annotation.NonNull
+ Parcelable.Creator<AccessibilityReplacementSpan> CREATOR =
+ new Parcelable.Creator<AccessibilityReplacementSpan>() {
+ @Override
+ public AccessibilityReplacementSpan createFromParcel(Parcel parcel) {
+ return new AccessibilityReplacementSpan(parcel);
+ }
+
+ @Override
+ public AccessibilityReplacementSpan[] newArray(int size) {
+ return new AccessibilityReplacementSpan[size];
+ }
+ };
+}
diff --git a/core/java/android/text/style/ReplacementSpan.java b/core/java/android/text/style/ReplacementSpan.java
index 5f94ad0..0553232 100644
--- a/core/java/android/text/style/ReplacementSpan.java
+++ b/core/java/android/text/style/ReplacementSpan.java
@@ -25,6 +25,8 @@
public abstract class ReplacementSpan extends MetricAffectingSpan {
+ private CharSequence mContentDescription = null;
+
/**
* Returns the width of the span. Extending classes can set the height of the span by updating
* attributes of {@link android.graphics.Paint.FontMetricsInt}. If the span covers the whole
@@ -61,6 +63,27 @@
int top, int y, int bottom, @NonNull Paint paint);
/**
+ * Gets a brief description of this ImageSpan for use in accessibility support.
+ *
+ * @return The content description.
+ */
+ @Nullable
+ public CharSequence getContentDescription() {
+ return mContentDescription;
+ }
+
+ /**
+ * Sets the specific content description into ImageSpan.
+ * ReplacementSpans are shared with accessibility services,
+ * but only the content description is available from them.
+ *
+ * @param contentDescription content description. The default value is null.
+ */
+ public void setContentDescription(@Nullable CharSequence contentDescription) {
+ mContentDescription = contentDescription;
+ }
+
+ /**
* This method does nothing, since ReplacementSpans are measured
* explicitly instead of affecting Paint properties.
*/
diff --git a/core/java/android/util/ArraySet.java b/core/java/android/util/ArraySet.java
index 44c5af2..4dda709 100644
--- a/core/java/android/util/ArraySet.java
+++ b/core/java/android/util/ArraySet.java
@@ -16,6 +16,7 @@
package android.util;
+import android.annotation.Nullable;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
@@ -329,6 +330,18 @@
}
/**
+ * Create a new ArraySet with items from the given array
+ */
+ public ArraySet(@Nullable E[] array) {
+ this();
+ if (array != null) {
+ for (E value : array) {
+ add(value);
+ }
+ }
+ }
+
+ /**
* Make the array map empty. All storage is released.
*/
@Override
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index b66764e..1be57dd 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -59,6 +59,7 @@
DEFAULT_FLAGS.put("settings_wifi_details_datausage_header", "false");
DEFAULT_FLAGS.put("settings_skip_direction_mutable", "true");
DEFAULT_FLAGS.put(SETTINGS_WIFITRACKER2, "false");
+ DEFAULT_FLAGS.put("settings_work_profile", "false");
}
/**
diff --git a/core/java/android/util/OWNERS b/core/java/android/util/OWNERS
index 98297fb..8f3d9f6 100644
--- a/core/java/android/util/OWNERS
+++ b/core/java/android/util/OWNERS
@@ -1,3 +1,3 @@
per-file FeatureFlagUtils.java = sbasi@google.com
-per-file FeatureFlagUtils.java = zhfan@google.com
+per-file FeatureFlagUtils.java = tmfang@google.com
per-file FeatureFlagUtils.java = asapperstein@google.com
diff --git a/core/java/android/util/StatsEvent.java b/core/java/android/util/StatsEvent.java
new file mode 100644
index 0000000..91a5ec0
--- /dev/null
+++ b/core/java/android/util/StatsEvent.java
@@ -0,0 +1,331 @@
+/*
+ * Copyright (C) 2019 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.util;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.internal.annotations.GuardedBy;
+
+/**
+ * StatsEvent builds and stores the buffer sent over the statsd socket.
+ * This class defines and encapsulates the socket protocol.
+ * @hide
+ **/
+public final class StatsEvent implements AutoCloseable {
+ private static final int POS_NUM_ELEMENTS = 1;
+ private static final int POS_TIMESTAMP = POS_NUM_ELEMENTS + 1;
+
+ private static final int LOGGER_ENTRY_MAX_PAYLOAD = 4068;
+
+ // Max payload size is 4 KB less 4 bytes which are reserved for statsEventTag.
+ // See android_util_StatsLog.cpp.
+ private static final int MAX_EVENT_PAYLOAD = LOGGER_ENTRY_MAX_PAYLOAD - 4;
+
+ private static final byte INT_TYPE = 0;
+ private static final byte LONG_TYPE = 1;
+ private static final byte STRING_TYPE = 2;
+ private static final byte LIST_TYPE = 3;
+ private static final byte FLOAT_TYPE = 4;
+
+ private static final int INT_TYPE_SIZE = 5;
+ private static final int FLOAT_TYPE_SIZE = 5;
+ private static final int LONG_TYPE_SIZE = 9;
+
+ private static final int STRING_TYPE_OVERHEAD = 5;
+ private static final int LIST_TYPE_OVERHEAD = 2;
+
+ public static final int SUCCESS = 0;
+ public static final int ERROR_BUFFER_LIMIT_EXCEEDED = -1;
+ public static final int ERROR_NO_TIMESTAMP = -2;
+ public static final int ERROR_TIMESTAMP_ALREADY_WRITTEN = -3;
+ public static final int ERROR_NO_ATOM_ID = -4;
+ public static final int ERROR_ATOM_ID_ALREADY_WRITTEN = -5;
+ public static final int ERROR_UID_TAG_COUNT_MISMATCH = -6;
+
+ private static Object sLock = new Object();
+
+ @GuardedBy("sLock")
+ private static StatsEvent sPool;
+
+ private final byte[] mBuffer = new byte[MAX_EVENT_PAYLOAD];
+ private int mPos;
+ private int mNumElements;
+ private int mAtomId;
+
+ private StatsEvent() {
+ // Write LIST_TYPE to buffer
+ mBuffer[0] = LIST_TYPE;
+ reset();
+ }
+
+ private void reset() {
+ // Reset state.
+ mPos = POS_TIMESTAMP;
+ mNumElements = 0;
+ mAtomId = 0;
+ }
+
+ /**
+ * Returns a StatsEvent object from the pool.
+ **/
+ @NonNull
+ public static StatsEvent obtain() {
+ final StatsEvent statsEvent;
+ synchronized (sLock) {
+ statsEvent = null == sPool ? new StatsEvent() : sPool;
+ sPool = null;
+ }
+ statsEvent.reset();
+ return statsEvent;
+ }
+
+ @Override
+ public void close() {
+ synchronized (sLock) {
+ if (null == sPool) {
+ sPool = this;
+ }
+ }
+ }
+
+ /**
+ * Writes the event timestamp to the buffer.
+ **/
+ public int writeTimestampNs(final long timestampNs) {
+ if (hasTimestamp()) {
+ return ERROR_TIMESTAMP_ALREADY_WRITTEN;
+ }
+ return writeLong(timestampNs);
+ }
+
+ private boolean hasTimestamp() {
+ return mPos > POS_TIMESTAMP;
+ }
+
+ private boolean hasAtomId() {
+ return mAtomId != 0;
+ }
+
+ /**
+ * Writes the atom id to the buffer.
+ **/
+ public int writeAtomId(final int atomId) {
+ if (!hasTimestamp()) {
+ return ERROR_NO_TIMESTAMP;
+ } else if (hasAtomId()) {
+ return ERROR_ATOM_ID_ALREADY_WRITTEN;
+ }
+
+ final int writeResult = writeInt(atomId);
+ if (SUCCESS == writeResult) {
+ mAtomId = atomId;
+ }
+ return writeResult;
+ }
+
+ /**
+ * Appends the given int to the StatsEvent buffer.
+ **/
+ public int writeInt(final int value) {
+ if (!hasTimestamp()) {
+ return ERROR_NO_TIMESTAMP;
+ } else if (!hasAtomId()) {
+ return ERROR_NO_ATOM_ID;
+ } else if (mPos + INT_TYPE_SIZE > MAX_EVENT_PAYLOAD) {
+ return ERROR_BUFFER_LIMIT_EXCEEDED;
+ }
+
+ mBuffer[mPos] = INT_TYPE;
+ copyInt(mBuffer, mPos + 1, value);
+ mPos += INT_TYPE_SIZE;
+ mNumElements++;
+ return SUCCESS;
+ }
+
+ /**
+ * Appends the given long to the StatsEvent buffer.
+ **/
+ public int writeLong(final long value) {
+ if (!hasTimestamp()) {
+ return ERROR_NO_TIMESTAMP;
+ } else if (!hasAtomId()) {
+ return ERROR_NO_ATOM_ID;
+ } else if (mPos + LONG_TYPE_SIZE > MAX_EVENT_PAYLOAD) {
+ return ERROR_BUFFER_LIMIT_EXCEEDED;
+ }
+
+ mBuffer[mPos] = LONG_TYPE;
+ copyLong(mBuffer, mPos + 1, value);
+ mPos += LONG_TYPE_SIZE;
+ mNumElements++;
+ return SUCCESS;
+ }
+
+ /**
+ * Appends the given float to the StatsEvent buffer.
+ **/
+ public int writeFloat(final float value) {
+ if (!hasTimestamp()) {
+ return ERROR_NO_TIMESTAMP;
+ } else if (!hasAtomId()) {
+ return ERROR_NO_ATOM_ID;
+ } else if (mPos + FLOAT_TYPE_SIZE > MAX_EVENT_PAYLOAD) {
+ return ERROR_BUFFER_LIMIT_EXCEEDED;
+ }
+
+ mBuffer[mPos] = FLOAT_TYPE;
+ copyInt(mBuffer, mPos + 1, Float.floatToIntBits(value));
+ mPos += FLOAT_TYPE_SIZE;
+ mNumElements++;
+ return SUCCESS;
+ }
+
+ /**
+ * Appends the given boolean to the StatsEvent buffer.
+ **/
+ public int writeBoolean(final boolean value) {
+ return writeInt(value ? 1 : 0);
+ }
+
+ /**
+ * Appends the given byte array to the StatsEvent buffer.
+ **/
+ public int writeByteArray(@NonNull final byte[] value) {
+ if (!hasTimestamp()) {
+ return ERROR_NO_TIMESTAMP;
+ } else if (!hasAtomId()) {
+ return ERROR_NO_ATOM_ID;
+ } else if (mPos + STRING_TYPE_OVERHEAD + value.length > MAX_EVENT_PAYLOAD) {
+ return ERROR_BUFFER_LIMIT_EXCEEDED;
+ }
+
+ mBuffer[mPos] = STRING_TYPE;
+ copyInt(mBuffer, mPos + 1, value.length);
+ System.arraycopy(value, 0, mBuffer, mPos + STRING_TYPE_OVERHEAD, value.length);
+ mPos += STRING_TYPE_OVERHEAD + value.length;
+ mNumElements++;
+ return SUCCESS;
+ }
+
+ /**
+ * Appends the given String to the StatsEvent buffer.
+ **/
+ public int writeString(@NonNull final String value) {
+ final byte[] valueBytes = stringToBytes(value);
+ return writeByteArray(valueBytes);
+ }
+
+ /**
+ * Appends the AttributionNode specified as array of uids and array of tags.
+ **/
+ public int writeAttributionNode(@NonNull final int[] uids, @NonNull final String[] tags) {
+ if (!hasTimestamp()) {
+ return ERROR_NO_TIMESTAMP;
+ } else if (!hasAtomId()) {
+ return ERROR_NO_ATOM_ID;
+ } else if (mPos + LIST_TYPE_OVERHEAD > MAX_EVENT_PAYLOAD) {
+ return ERROR_BUFFER_LIMIT_EXCEEDED;
+ }
+
+ final int numTags = tags.length;
+ final int numUids = uids.length;
+ if (numTags != numUids) {
+ return ERROR_UID_TAG_COUNT_MISMATCH;
+ }
+
+ int pos = mPos;
+ mBuffer[pos] = LIST_TYPE;
+ mBuffer[pos + 1] = (byte) numTags;
+ pos += LIST_TYPE_OVERHEAD;
+ for (int i = 0; i < numTags; i++) {
+ final byte[] tagBytes = stringToBytes(tags[i]);
+
+ if (pos + LIST_TYPE_OVERHEAD + INT_TYPE_SIZE
+ + STRING_TYPE_OVERHEAD + tagBytes.length > MAX_EVENT_PAYLOAD) {
+ return ERROR_BUFFER_LIMIT_EXCEEDED;
+ }
+
+ mBuffer[pos] = LIST_TYPE;
+ mBuffer[pos + 1] = 2;
+ pos += LIST_TYPE_OVERHEAD;
+ mBuffer[pos] = INT_TYPE;
+ copyInt(mBuffer, pos + 1, uids[i]);
+ pos += INT_TYPE_SIZE;
+ mBuffer[pos] = STRING_TYPE;
+ copyInt(mBuffer, pos + 1, tagBytes.length);
+ System.arraycopy(tagBytes, 0, mBuffer, pos + STRING_TYPE_OVERHEAD, tagBytes.length);
+ pos += STRING_TYPE_OVERHEAD + tagBytes.length;
+ }
+ mPos = pos;
+ mNumElements++;
+ return SUCCESS;
+ }
+
+ /**
+ * Returns the byte array containing data in the statsd socket format.
+ * @hide
+ **/
+ @NonNull
+ public byte[] getBuffer() {
+ // Encode number of elements in the buffer.
+ mBuffer[POS_NUM_ELEMENTS] = (byte) mNumElements;
+ return mBuffer;
+ }
+
+ /**
+ * Returns number of bytes used by the buffer.
+ * @hide
+ **/
+ public int size() {
+ return mPos;
+ }
+
+ /**
+ * Getter for atom id.
+ * @hide
+ **/
+ public int getAtomId() {
+ return mAtomId;
+ }
+
+ @NonNull
+ private static byte[] stringToBytes(@Nullable final String value) {
+ return (null == value ? "" : value).getBytes(UTF_8);
+ }
+
+ // Helper methods for copying primitives
+ private static void copyInt(@NonNull byte[] buff, int pos, int value) {
+ buff[pos] = (byte) (value);
+ buff[pos + 1] = (byte) (value >> 8);
+ buff[pos + 2] = (byte) (value >> 16);
+ buff[pos + 3] = (byte) (value >> 24);
+ }
+
+ private static void copyLong(@NonNull byte[] buff, int pos, long value) {
+ buff[pos] = (byte) (value);
+ buff[pos + 1] = (byte) (value >> 8);
+ buff[pos + 2] = (byte) (value >> 16);
+ buff[pos + 3] = (byte) (value >> 24);
+ buff[pos + 4] = (byte) (value >> 32);
+ buff[pos + 5] = (byte) (value >> 40);
+ buff[pos + 6] = (byte) (value >> 48);
+ buff[pos + 7] = (byte) (value >> 56);
+ }
+}
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index b685cf0..6637c5b0 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -181,7 +181,6 @@
private static native void nativeSeverChildren(long transactionObj, long nativeObject);
private static native void nativeSetOverrideScalingMode(long transactionObj, long nativeObject,
int scalingMode);
- private static native boolean nativeGetTransformToDisplayInverse(long nativeObject);
private static native Display.HdrCapabilities nativeGetHdrCapabilities(IBinder displayToken);
@@ -303,8 +302,8 @@
/**
* Surface creation flag: Creates a Dim surface.
* Everything behind this surface is dimmed by the amount specified
- * in {@link #setAlpha}. It is an error to lock a Dim surface, since it
- * doesn't have a backing store.
+ * in {@link Transaction#setAlpha(SurfaceControl, float)}. It is an error to lock a Dim
+ * surface, since it doesn't have a backing store.
*
* @hide
*/
@@ -740,20 +739,20 @@
* <p>
* Good practice is to first create the surface with the {@link #HIDDEN} flag
* specified, open a transaction, set the surface layer, layer stack, alpha,
- * and position, call {@link #show} if appropriate, and close the transaction.
+ * and position, call {@link Transaction#show(SurfaceControl)} if appropriate, and close the
+ * transaction.
* <p>
* Bounds of the surface is determined by its crop and its buffer size. If the
* surface has no buffer or crop, the surface is boundless and only constrained
* by the size of its parent bounds.
*
- * @param session The surface session, must not be null.
- * @param name The surface name, must not be null.
- * @param w The surface initial width.
- * @param h The surface initial height.
- * @param flags The surface creation flags. Should always include {@link #HIDDEN}
- * in the creation flags.
+ * @param session The surface session, must not be null.
+ * @param name The surface name, must not be null.
+ * @param w The surface initial width.
+ * @param h The surface initial height.
+ * @param flags The surface creation flags. Should always include {@link #HIDDEN}
+ * in the creation flags.
* @param metadata Initial metadata.
- *
* @throws throws OutOfResourcesException If the SurfaceControl cannot be created.
*/
private SurfaceControl(SurfaceSession session, String name, int w, int h, int format, int flags,
@@ -1014,15 +1013,6 @@
/**
* @hide
*/
- public void deferTransactionUntil(Surface barrier, long frame) {
- synchronized(SurfaceControl.class) {
- sGlobalTransaction.deferTransactionUntilSurface(this, barrier, frame);
- }
- }
-
- /**
- * @hide
- */
public void reparentChildren(SurfaceControl newParent) {
synchronized(SurfaceControl.class) {
sGlobalTransaction.reparentChildren(this, newParent);
@@ -1032,15 +1022,6 @@
/**
* @hide
*/
- public void reparent(SurfaceControl newParent) {
- synchronized(SurfaceControl.class) {
- sGlobalTransaction.reparent(this, newParent);
- }
- }
-
- /**
- * @hide
- */
public void detachChildren() {
synchronized(SurfaceControl.class) {
sGlobalTransaction.detachChildren(this);
@@ -1060,15 +1041,6 @@
/**
* @hide
*/
- public static void setAnimationTransaction() {
- synchronized (SurfaceControl.class) {
- sGlobalTransaction.setAnimationTransaction();
- }
- }
-
- /**
- * @hide
- */
@UnsupportedAppUsage
public void setLayer(int zorder) {
checkNotReleased();
@@ -1080,16 +1052,6 @@
/**
* @hide
*/
- public void setRelativeLayer(SurfaceControl relativeTo, int zorder) {
- checkNotReleased();
- synchronized(SurfaceControl.class) {
- sGlobalTransaction.setRelativeLayer(this, relativeTo, zorder);
- }
- }
-
- /**
- * @hide
- */
@UnsupportedAppUsage
public void setPosition(float x, float y) {
checkNotReleased();
@@ -1183,16 +1145,6 @@
/**
* @hide
*/
- public void setColor(@Size(3) float[] color) {
- checkNotReleased();
- synchronized (SurfaceControl.class) {
- sGlobalTransaction.setColor(this, color);
- }
- }
-
- /**
- * @hide
- */
public void setMatrix(float dsdx, float dtdx, float dtdy, float dsdy) {
checkNotReleased();
synchronized(SurfaceControl.class) {
@@ -1201,36 +1153,6 @@
}
/**
- * Sets the transform and position of a {@link SurfaceControl} from a 3x3 transformation matrix.
- *
- * @param matrix The matrix to apply.
- * @param float9 An array of 9 floats to be used to extract the values from the matrix.
- * @hide
- */
- public void setMatrix(Matrix matrix, float[] float9) {
- checkNotReleased();
- matrix.getValues(float9);
- synchronized (SurfaceControl.class) {
- sGlobalTransaction.setMatrix(this, float9[MSCALE_X], float9[MSKEW_Y],
- float9[MSKEW_X], float9[MSCALE_Y]);
- sGlobalTransaction.setPosition(this, float9[MTRANS_X], float9[MTRANS_Y]);
- }
- }
-
- /**
- * Sets the color transform for the Surface.
- * @param matrix A float array with 9 values represents a 3x3 transform matrix
- * @param translation A float array with 3 values represents a translation vector
- * @hide
- */
- public void setColorTransform(@Size(9) float[] matrix, @Size(3) float[] translation) {
- checkNotReleased();
- synchronized (SurfaceControl.class) {
- sGlobalTransaction.setColorTransform(this, matrix, translation);
- }
- }
-
- /**
* Sets the Surface to be color space agnostic. If a surface is color space agnostic,
* the color can be interpreted in any color space.
* @param agnostic A boolean to indicate whether the surface is color space agnostic
@@ -1260,43 +1182,6 @@
}
/**
- * Same as {@link SurfaceControl#setWindowCrop(Rect)} but sets the crop rect top left at 0, 0.
- *
- * @param width width of crop rect
- * @param height height of crop rect
- * @hide
- */
- public void setWindowCrop(int width, int height) {
- checkNotReleased();
- synchronized (SurfaceControl.class) {
- sGlobalTransaction.setWindowCrop(this, width, height);
- }
- }
-
- /**
- * Sets the corner radius of a {@link SurfaceControl}.
- *
- * @param cornerRadius Corner radius in pixels.
- * @hide
- */
- public void setCornerRadius(float cornerRadius) {
- checkNotReleased();
- synchronized (SurfaceControl.class) {
- sGlobalTransaction.setCornerRadius(this, cornerRadius);
- }
- }
-
- /**
- * @hide
- */
- public void setLayerStack(int layerStack) {
- checkNotReleased();
- synchronized(SurfaceControl.class) {
- sGlobalTransaction.setLayerStack(this, layerStack);
- }
- }
-
- /**
* @hide
*/
public void setOpaque(boolean isOpaque) {
@@ -2302,6 +2187,12 @@
}
/**
+ * Sets the transform and position of a {@link SurfaceControl} from a 3x3 transformation
+ * matrix.
+ *
+ * @param sc SurfaceControl to set matrix of
+ * @param matrix The matrix to apply.
+ * @param float9 An array of 9 floats to be used to extract the values from the matrix.
* @hide
*/
@UnsupportedAppUsage
@@ -2315,7 +2206,9 @@
/**
* Sets the color transform for the Surface.
- * @param matrix A float array with 9 values represents a 3x3 transform matrix
+ *
+ * @param sc SurfaceControl to set color transform of
+ * @param matrix A float array with 9 values represents a 3x3 transform matrix
* @param translation A float array with 3 values represents a translation vector
* @hide
*/
@@ -2339,6 +2232,13 @@
}
/**
+ * Bounds the surface and its children to the bounds specified. Size of the surface will be
+ * ignored and only the crop and buffer size will be used to determine the bounds of the
+ * surface. If no crop is specified and the surface has no buffer, the surface bounds is
+ * only constrained by the size of its parent bounds.
+ *
+ * @param sc SurfaceControl to set crop of.
+ * @param crop Bounds of the crop to apply.
* @hide
*/
@UnsupportedAppUsage
@@ -2355,6 +2255,12 @@
}
/**
+ * Same as {@link Transaction#setWindowCrop(SurfaceControl, Rect)} but sets the crop rect
+ * top left at 0, 0.
+ *
+ * @param sc SurfaceControl to set crop of.
+ * @param width width of crop rect
+ * @param height height of crop rect
* @hide
*/
public Transaction setWindowCrop(SurfaceControl sc, int width, int height) {
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index a858300..2f0a4eb 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -418,12 +418,7 @@
Log.d(TAG, System.identityHashCode(this)
+ " updateSurfaceAlpha: set alpha=" + alpha);
}
- SurfaceControl.openTransaction();
- try {
- mSurfaceControl.setAlpha(alpha);
- } finally {
- SurfaceControl.closeTransaction();
- }
+ mTmpTransaction.setAlpha(mSurfaceControl, alpha).apply();
}
mSurfaceAlpha = alpha;
}
@@ -701,17 +696,18 @@
}
}
- private void updateBackgroundVisibilityInTransaction() {
+ private void updateBackgroundVisibility(Transaction t) {
if (mBackgroundControl == null) {
return;
}
if ((mSubLayer < 0) && ((mSurfaceFlags & SurfaceControl.OPAQUE) != 0)) {
- mBackgroundControl.show();
+ t.show(mBackgroundControl);
} else {
- mBackgroundControl.hide();
+ t.hide(mBackgroundControl);
}
}
+
private void releaseSurfaces() {
mSurfaceAlpha = 1f;
@@ -853,60 +849,60 @@
if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ "Cur surface: " + mSurface);
- SurfaceControl.openTransaction();
- try {
- // If we are creating the surface control or the parent surface has not
- // changed, then set relative z. Otherwise allow the parent
- // SurfaceChangedCallback to update the relative z. This is needed so that
- // we do not change the relative z before the server is ready to swap the
- // parent surface.
- if (creating || (mParentSurfaceGenerationId
- == viewRoot.mSurface.getGenerationId())) {
- SurfaceControl.mergeToGlobalTransaction(updateRelativeZ());
- }
- mParentSurfaceGenerationId = viewRoot.mSurface.getGenerationId();
-
- if (mViewVisibility) {
- mSurfaceControl.show();
- } else {
- mSurfaceControl.hide();
- }
- updateBackgroundVisibilityInTransaction();
- if (mUseAlpha) {
- mSurfaceControl.setAlpha(alpha);
- mSurfaceAlpha = alpha;
- }
-
- // While creating the surface, we will set it's initial
- // geometry. Outside of that though, we should generally
- // leave it to the RenderThread.
- //
- // There is one more case when the buffer size changes we aren't yet
- // prepared to sync (as even following the transaction applying
- // we still need to latch a buffer).
- // b/28866173
- if (sizeChanged || creating || !mRtHandlingPositionUpdates) {
- mSurfaceControl.setPosition(mScreenRect.left, mScreenRect.top);
- mSurfaceControl.setMatrix(mScreenRect.width() / (float) mSurfaceWidth,
- 0.0f, 0.0f,
- mScreenRect.height() / (float) mSurfaceHeight);
- // Set a window crop when creating the surface or changing its size to
- // crop the buffer to the surface size since the buffer producer may
- // use SCALING_MODE_SCALE and submit a larger size than the surface
- // size.
- if (mClipSurfaceToBounds && mClipBounds != null) {
- mSurfaceControl.setWindowCrop(mClipBounds);
- } else {
- mSurfaceControl.setWindowCrop(mSurfaceWidth, mSurfaceHeight);
- }
- }
- mSurfaceControl.setCornerRadius(mCornerRadius);
- if (sizeChanged && !creating) {
- mSurfaceControl.setBufferSize(mSurfaceWidth, mSurfaceHeight);
- }
- } finally {
- SurfaceControl.closeTransaction();
+ // If we are creating the surface control or the parent surface has not
+ // changed, then set relative z. Otherwise allow the parent
+ // SurfaceChangedCallback to update the relative z. This is needed so that
+ // we do not change the relative z before the server is ready to swap the
+ // parent surface.
+ if (creating || (mParentSurfaceGenerationId
+ == viewRoot.mSurface.getGenerationId())) {
+ updateRelativeZ(mTmpTransaction);
}
+ mParentSurfaceGenerationId = viewRoot.mSurface.getGenerationId();
+
+ if (mViewVisibility) {
+ mTmpTransaction.show(mSurfaceControl);
+ } else {
+ mTmpTransaction.hide(mSurfaceControl);
+ }
+ updateBackgroundVisibility(mTmpTransaction);
+ if (mUseAlpha) {
+ mTmpTransaction.setAlpha(mSurfaceControl, alpha);
+ mSurfaceAlpha = alpha;
+ }
+
+ // While creating the surface, we will set it's initial
+ // geometry. Outside of that though, we should generally
+ // leave it to the RenderThread.
+ //
+ // There is one more case when the buffer size changes we aren't yet
+ // prepared to sync (as even following the transaction applying
+ // we still need to latch a buffer).
+ // b/28866173
+ if (sizeChanged || creating || !mRtHandlingPositionUpdates) {
+ mTmpTransaction.setPosition(mSurfaceControl, mScreenRect.left,
+ mScreenRect.top);
+ mTmpTransaction.setMatrix(mSurfaceControl,
+ mScreenRect.width() / (float) mSurfaceWidth, 0.0f, 0.0f,
+ mScreenRect.height() / (float) mSurfaceHeight);
+ // Set a window crop when creating the surface or changing its size to
+ // crop the buffer to the surface size since the buffer producer may
+ // use SCALING_MODE_SCALE and submit a larger size than the surface
+ // size.
+ if (mClipSurfaceToBounds && mClipBounds != null) {
+ mTmpTransaction.setWindowCrop(mSurfaceControl, mClipBounds);
+ } else {
+ mTmpTransaction.setWindowCrop(mSurfaceControl, mSurfaceWidth,
+ mSurfaceHeight);
+ }
+ }
+ mTmpTransaction.setCornerRadius(mSurfaceControl, mCornerRadius);
+ if (sizeChanged && !creating) {
+ mTmpTransaction.setBufferSize(mSurfaceControl, mSurfaceWidth,
+ mSurfaceHeight);
+ }
+
+ mTmpTransaction.apply();
if (sizeChanged || creating) {
redrawNeeded = true;
@@ -1260,12 +1256,7 @@
final float[] colorComponents = new float[] { Color.red(bgColor) / 255.f,
Color.green(bgColor) / 255.f, Color.blue(bgColor) / 255.f };
- SurfaceControl.openTransaction();
- try {
- mBackgroundControl.setColor(colorComponents);
- } finally {
- SurfaceControl.closeTransaction();
- }
+ mTmpTransaction.setColor(mBackgroundControl, colorComponents).apply();
}
@UnsupportedAppUsage
@@ -1480,15 +1471,13 @@
@Override
public void surfaceReplaced(Transaction t) {
if (mSurfaceControl != null && mBackgroundControl != null) {
- t.merge(updateRelativeZ());
+ updateRelativeZ(t);
}
}
- private Transaction updateRelativeZ() {
- Transaction t = new Transaction();
+ private void updateRelativeZ(Transaction t) {
SurfaceControl viewRoot = getViewRootImpl().getSurfaceControl();
t.setRelativeLayer(mBackgroundControl, viewRoot, Integer.MIN_VALUE);
t.setRelativeLayer(mSurfaceControl, viewRoot, mSubLayer);
- return t;
}
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index cfb6a79a..c5d0a9b0 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4496,8 +4496,9 @@
* When non-null and valid, this is expected to contain an up-to-date copy
* of the background drawable. It is cleared on temporary detach, and reset
* on cleanup.
+ * @hide
*/
- private RenderNode mBackgroundRenderNode;
+ RenderNode mBackgroundRenderNode;
@UnsupportedAppUsage
private int mBackgroundResource;
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 82a5fa9..853a302 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2615,7 +2615,9 @@
|| actionMasked == MotionEvent.ACTION_CANCEL;
// Update list of touch targets for pointer down, if needed.
- final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0;
+ final boolean isMouseEvent = ev.getSource() == InputDevice.SOURCE_MOUSE;
+ final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0
+ && !isMouseEvent;
TouchTarget newTouchTarget = null;
boolean alreadyDispatchedToNewTouchTarget = false;
if (!canceled && !intercepted) {
@@ -2632,8 +2634,10 @@
final int childrenCount = mChildrenCount;
if (newTouchTarget == null && childrenCount != 0) {
- final float x = ev.getX(actionIndex);
- final float y = ev.getY(actionIndex);
+ final float x =
+ isMouseEvent ? ev.getXCursorPosition() : ev.getX(actionIndex);
+ final float y =
+ isMouseEvent ? ev.getYCursorPosition() : ev.getY(actionIndex);
// Find a child that can receive the event.
// Scan children from front to back.
final ArrayList<View> preorderedList = buildTouchDispatchChildList();
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index fedd6fb..cf06985 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -7297,26 +7297,42 @@
}
}
- public void dumpGfxInfo(int[] info) {
- info[0] = info[1] = 0;
- if (mView != null) {
- getGfxInfo(mView, info);
+ static final class GfxInfo {
+ public int viewCount;
+ public long renderNodeMemoryUsage;
+ public long renderNodeMemoryAllocated;
+
+ void add(GfxInfo other) {
+ viewCount += other.viewCount;
+ renderNodeMemoryUsage += other.renderNodeMemoryUsage;
+ renderNodeMemoryAllocated += other.renderNodeMemoryAllocated;
}
}
- private static void getGfxInfo(View view, int[] info) {
- RenderNode renderNode = view.mRenderNode;
- info[0]++;
- if (renderNode != null) {
- info[1] += (int) renderNode.computeApproximateMemoryUsage();
+ GfxInfo getGfxInfo() {
+ GfxInfo info = new GfxInfo();
+ if (mView != null) {
+ appendGfxInfo(mView, info);
}
+ return info;
+ }
+ private static void computeRenderNodeUsage(RenderNode node, GfxInfo info) {
+ if (node == null) return;
+ info.renderNodeMemoryUsage += node.computeApproximateMemoryUsage();
+ info.renderNodeMemoryAllocated += node.computeApproximateMemoryAllocated();
+ }
+
+ private static void appendGfxInfo(View view, GfxInfo info) {
+ info.viewCount++;
+ computeRenderNodeUsage(view.mRenderNode, info);
+ computeRenderNodeUsage(view.mBackgroundRenderNode, info);
if (view instanceof ViewGroup) {
ViewGroup group = (ViewGroup) view;
int count = group.getChildCount();
for (int i = 0; i < count; i++) {
- getGfxInfo(group.getChildAt(i), info);
+ appendGfxInfo(group.getChildAt(i), info);
}
}
}
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 379acbe..55b2a2a 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -604,26 +604,24 @@
pw.println("\nView hierarchy:\n");
- int viewsCount = 0;
- int displayListsSize = 0;
- int[] info = new int[2];
+ ViewRootImpl.GfxInfo totals = new ViewRootImpl.GfxInfo();
for (int i = 0; i < count; i++) {
ViewRootImpl root = mRoots.get(i);
- root.dumpGfxInfo(info);
+ ViewRootImpl.GfxInfo info = root.getGfxInfo();
+ totals.add(info);
String name = getWindowName(root);
- pw.printf(" %s\n %d views, %.2f kB of display lists",
- name, info[0], info[1] / 1024.0f);
+ pw.printf(" %s\n %d views, %.2f kB of render nodes",
+ name, info.viewCount, info.renderNodeMemoryUsage / 1024.f);
pw.printf("\n\n");
-
- viewsCount += info[0];
- displayListsSize += info[1];
}
- pw.printf("\nTotal ViewRootImpl: %d\n", count);
- pw.printf("Total Views: %d\n", viewsCount);
- pw.printf("Total DisplayList: %.2f kB\n\n", displayListsSize / 1024.0f);
+ pw.printf("\nTotal %-15s: %d\n", "ViewRootImpl", count);
+ pw.printf("Total %-15s: %d\n", "attached Views", totals.viewCount);
+ pw.printf("Total %-15s: %.2f kB (used) / %.2f kB (capacity)\n\n", "RenderNode",
+ totals.renderNodeMemoryUsage / 1024.0f,
+ totals.renderNodeMemoryAllocated / 1024.0f);
}
} finally {
pw.flush();
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index cf29ed7..06e9d0d 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -39,8 +39,10 @@
import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.AccessibilityClickableSpan;
+import android.text.style.AccessibilityReplacementSpan;
import android.text.style.AccessibilityURLSpan;
import android.text.style.ClickableSpan;
+import android.text.style.ReplacementSpan;
import android.text.style.URLSpan;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -2641,37 +2643,86 @@
public void setText(CharSequence text) {
enforceNotSealed();
mOriginalText = text;
- // Replace any ClickableSpans in mText with placeholders
if (text instanceof Spanned) {
- ClickableSpan[] spans =
- ((Spanned) text).getSpans(0, text.length(), ClickableSpan.class);
- if (spans.length > 0) {
- Spannable spannable = new SpannableStringBuilder(text);
- for (int i = 0; i < spans.length; i++) {
- ClickableSpan span = spans[i];
- if ((span instanceof AccessibilityClickableSpan)
- || (span instanceof AccessibilityURLSpan)) {
- // We've already done enough
- break;
- }
- int spanToReplaceStart = spannable.getSpanStart(span);
- int spanToReplaceEnd = spannable.getSpanEnd(span);
- int spanToReplaceFlags = spannable.getSpanFlags(span);
- spannable.removeSpan(span);
- ClickableSpan replacementSpan = (span instanceof URLSpan)
- ? new AccessibilityURLSpan((URLSpan) span)
- : new AccessibilityClickableSpan(span.getId());
- spannable.setSpan(replacementSpan, spanToReplaceStart, spanToReplaceEnd,
- spanToReplaceFlags);
- }
- mText = spannable;
- return;
- }
+ CharSequence tmpText = text;
+ tmpText = replaceClickableSpan(tmpText);
+ tmpText = replaceReplacementSpan(tmpText);
+ mText = tmpText;
+ return;
}
mText = (text == null) ? null : text.subSequence(0, text.length());
}
/**
+ * Replaces any ClickableSpans in mText with placeholders.
+ *
+ * @param text The text.
+ *
+ * @return The spannable with ClickableSpan replacement.
+ */
+ private CharSequence replaceClickableSpan(CharSequence text) {
+ ClickableSpan[] clickableSpans =
+ ((Spanned) text).getSpans(0, text.length(), ClickableSpan.class);
+ Spannable spannable = new SpannableStringBuilder(text);
+ if (clickableSpans.length == 0) {
+ return text;
+ }
+ for (int i = 0; i < clickableSpans.length; i++) {
+ ClickableSpan span = clickableSpans[i];
+ if ((span instanceof AccessibilityClickableSpan)
+ || (span instanceof AccessibilityURLSpan)) {
+ // We've already done enough
+ break;
+ }
+ int spanToReplaceStart = spannable.getSpanStart(span);
+ int spanToReplaceEnd = spannable.getSpanEnd(span);
+ int spanToReplaceFlags = spannable.getSpanFlags(span);
+ spannable.removeSpan(span);
+ ClickableSpan replacementSpan = (span instanceof URLSpan)
+ ? new AccessibilityURLSpan((URLSpan) span)
+ : new AccessibilityClickableSpan(span.getId());
+ spannable.setSpan(replacementSpan, spanToReplaceStart, spanToReplaceEnd,
+ spanToReplaceFlags);
+ }
+ return spannable;
+ }
+
+ /**
+ * Replace any ImageSpans in mText with its content description.
+ *
+ * @param text The text.
+ *
+ * @return The spannable with ReplacementSpan replacement.
+ */
+ private CharSequence replaceReplacementSpan(CharSequence text) {
+ ReplacementSpan[] replacementSpans =
+ ((Spanned) text).getSpans(0, text.length(), ReplacementSpan.class);
+ SpannableStringBuilder spannable = new SpannableStringBuilder(text);
+ if (replacementSpans.length == 0) {
+ return text;
+ }
+ for (int i = 0; i < replacementSpans.length; i++) {
+ ReplacementSpan span = replacementSpans[i];
+ CharSequence replacementText = span.getContentDescription();
+ if (span instanceof AccessibilityReplacementSpan) {
+ // We've already done enough
+ break;
+ }
+ if (replacementText == null) {
+ continue;
+ }
+ int spanToReplaceStart = spannable.getSpanStart(span);
+ int spanToReplaceEnd = spannable.getSpanEnd(span);
+ int spanToReplaceFlags = spannable.getSpanFlags(span);
+ spannable.removeSpan(span);
+ ReplacementSpan replacementSpan = new AccessibilityReplacementSpan(replacementText);
+ spannable.setSpan(replacementSpan, spanToReplaceStart, spanToReplaceEnd,
+ spanToReplaceFlags);
+ }
+ return spannable;
+ }
+
+ /**
* Gets the hint text of this node. Only applies to nodes where text can be entered.
*
* @return The hint text.
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index fe88a91..6d60366 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2569,7 +2569,8 @@
if (isItemClickable(view)) {
addAccessibilityActionIfEnabled(info, isItemEnabled, AccessibilityAction.ACTION_CLICK);
- info.setClickable(true);
+ // A disabled item is a separator which should not be clickable.
+ info.setClickable(isItemEnabled);
}
if (isLongClickable()) {
diff --git a/core/java/com/android/internal/app/ResolverListController.java b/core/java/com/android/internal/app/ResolverListController.java
index 5f92cdd..a390611b 100644
--- a/core/java/com/android/internal/app/ResolverListController.java
+++ b/core/java/com/android/internal/app/ResolverListController.java
@@ -115,14 +115,6 @@
flags |= PackageManager.MATCH_INSTANT;
}
final List<ResolveInfo> infos = mpm.queryIntentActivities(intent, flags);
- // Remove any activities that are not exported.
- int totalSize = infos.size();
- for (int j = totalSize - 1; j >= 0 ; j--) {
- ResolveInfo info = infos.get(j);
- if (info.activityInfo != null && !info.activityInfo.exported) {
- infos.remove(j);
- }
- }
if (infos != null) {
if (resolvedComponents == null) {
resolvedComponents = new ArrayList<>();
diff --git a/core/java/com/android/internal/os/KernelWakelockReader.java b/core/java/com/android/internal/os/KernelWakelockReader.java
index e09e0e6..cffb0ad 100644
--- a/core/java/com/android/internal/os/KernelWakelockReader.java
+++ b/core/java/com/android/internal/os/KernelWakelockReader.java
@@ -29,6 +29,7 @@
import java.io.File;
import java.io.FileInputStream;
+import java.util.Arrays;
import java.util.Iterator;
/**
@@ -66,6 +67,7 @@
private final String[] mProcWakelocksName = new String[3];
private final long[] mProcWakelocksData = new long[3];
private ISuspendControlService mSuspendControlService = null;
+ private byte[] mKernelWakelockBuffer = new byte[32 * 1024];
/**
* Reads kernel wakelock stats and updates the staleStats with the new information.
@@ -84,7 +86,7 @@
}
return removeOldStats(staleStats);
} else {
- byte[] buffer = new byte[32*1024];
+ Arrays.fill(mKernelWakelockBuffer, (byte) 0);
int len = 0;
boolean wakeup_sources;
final long startTime = SystemClock.uptimeMillis();
@@ -107,7 +109,8 @@
}
int cnt;
- while ((cnt = is.read(buffer, len, buffer.length - len)) > 0) {
+ while ((cnt = is.read(mKernelWakelockBuffer, len,
+ mKernelWakelockBuffer.length - len)) > 0) {
len += cnt;
}
@@ -125,12 +128,13 @@
}
if (len > 0) {
- if (len >= buffer.length) {
- Slog.wtf(TAG, "Kernel wake locks exceeded buffer size " + buffer.length);
+ if (len >= mKernelWakelockBuffer.length) {
+ Slog.wtf(TAG, "Kernel wake locks exceeded mKernelWakelockBuffer size "
+ + mKernelWakelockBuffer.length);
}
int i;
for (i=0; i<len; i++) {
- if (buffer[i] == '\0') {
+ if (mKernelWakelockBuffer[i] == '\0') {
len = i;
break;
}
@@ -143,7 +147,7 @@
Slog.w(TAG, "Failed to get Native wakelock stats from SystemSuspend");
}
// Get kernel wakelock stats
- parseProcWakelocks(buffer, len, wakeup_sources, staleStats);
+ parseProcWakelocks(mKernelWakelockBuffer, len, wakeup_sources, staleStats);
return removeOldStats(staleStats);
}
}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 0505fe3..0feab7f 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -257,8 +257,6 @@
"libnativeloader_lazy",
"libmemunreachable",
"libhidlbase",
- "libhidltransport",
- "libhwbinder",
"libvintf",
"libnativewindow",
"libdl",
diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp
index d80c071..483b455 100644
--- a/core/jni/android_os_Parcel.cpp
+++ b/core/jni/android_os_Parcel.cpp
@@ -721,8 +721,11 @@
{"nativeWriteFloat", "(JF)V", (void*)android_os_Parcel_writeFloat},
// @FastNative
{"nativeWriteDouble", "(JD)V", (void*)android_os_Parcel_writeDouble},
+ // @FastNative
{"nativeWriteString", "(JLjava/lang/String;)V", (void*)android_os_Parcel_writeString},
+ // @FastNative
{"nativeWriteStrongBinder", "(JLandroid/os/IBinder;)V", (void*)android_os_Parcel_writeStrongBinder},
+ // @FastNative
{"nativeWriteFileDescriptor", "(JLjava/io/FileDescriptor;)J", (void*)android_os_Parcel_writeFileDescriptor},
{"nativeCreateByteArray", "(J)[B", (void*)android_os_Parcel_createByteArray},
@@ -736,8 +739,11 @@
{"nativeReadFloat", "(J)F", (void*)android_os_Parcel_readFloat},
// @CriticalNative
{"nativeReadDouble", "(J)D", (void*)android_os_Parcel_readDouble},
+ // @FastNative
{"nativeReadString", "(J)Ljava/lang/String;", (void*)android_os_Parcel_readString},
+ // @FastNative
{"nativeReadStrongBinder", "(J)Landroid/os/IBinder;", (void*)android_os_Parcel_readStrongBinder},
+ // @FastNative
{"nativeReadFileDescriptor", "(J)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_readFileDescriptor},
{"nativeCreate", "()J", (void*)android_os_Parcel_create},
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 0afbaa0e..e406e22 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -697,6 +697,9 @@
// same IBinder, and the original BinderProxy is still alive, return the same BinderProxy.
jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
+ // N.B. This function is called from a @FastNative JNI method, so don't take locks around
+ // calls to Java code or block the calling thread for a long time for any reason.
+
if (val == NULL) return NULL;
if (val->checkSubclass(&gBinderOffsets)) {
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 3cefeea..0fada1b 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -35,6 +35,7 @@
#include <limits>
#include <memory>
#include <string>
+#include <unordered_map>
#include <vector>
#include "core_jni_helpers.h"
@@ -81,6 +82,25 @@
static pthread_key_t gBgKey = -1;
#endif
+/*
+ * cpuset/sched aggregate profile mappings
+ */
+static const std::unordered_map<int, std::string> kCpusetProfileMap = {
+ {SP_DEFAULT, "CPUSET_SP_DEFAULT"}, {SP_BACKGROUND, "CPUSET_SP_BACKGROUND"},
+ {SP_FOREGROUND, "CPUSET_SP_FOREGROUND"},{SP_SYSTEM, "CPUSET_SP_SYSTEM"},
+ {SP_AUDIO_APP, "CPUSET_SP_FOREGROUND"}, {SP_AUDIO_SYS, "CPUSET_SP_FOREGROUND"},
+ {SP_TOP_APP, "CPUSET_SP_TOP_APP"}, {SP_RT_APP, "CPUSET_SP_DEFAULT"},
+ {SP_RESTRICTED, "CPUSET_SP_RESTRICTED"}
+};
+
+static const std::unordered_map<int, std::string> kSchedProfileMap = {
+ {SP_DEFAULT, "SCHED_SP_DEFAULT"}, {SP_BACKGROUND, "SCHED_SP_BACKGROUND"},
+ {SP_FOREGROUND, "SCHED_SP_FOREGROUND"}, {SP_SYSTEM, "SCHED_SP_DEFAULT"},
+ {SP_AUDIO_APP, "SCHED_SP_FOREGROUND"}, {SP_AUDIO_SYS, "SCHED_SP_FOREGROUND"},
+ {SP_TOP_APP, "SCHED_SP_TOP_APP"}, {SP_RT_APP, "SCHED_SP_RT_APP"},
+ {SP_RESTRICTED, "SCHED_SP_DEFAULT"}
+};
+
// For both of these, err should be in the errno range (positive), not a status_t (negative)
static void signalExceptionForError(JNIEnv* env, int err, int tid) {
switch (err) {
@@ -206,8 +226,9 @@
if (!verifyGroup(env, grp)) {
return;
}
- SchedPolicy sp = (SchedPolicy) grp;
- int res = set_sched_policy(tid, sp);
+
+ int res = SetTaskProfiles(tid, {kSchedProfileMap.at(grp)}, true) ? 0 : -1;
+
if (res != NO_ERROR) {
signalExceptionForGroupError(env, -res, tid);
}
@@ -219,14 +240,9 @@
if (!verifyGroup(env, grp)) {
return;
}
- SchedPolicy sp = (SchedPolicy) grp;
- int res = set_sched_policy(tid, sp);
- if (res != NO_ERROR) {
- signalExceptionForGroupError(env, -res, tid);
- }
+ int res = SetTaskProfiles(tid, {kCpusetProfileMap.at(grp)}, true) ? 0 : -1;
- res = set_cpuset_policy(tid, sp);
if (res != NO_ERROR) {
signalExceptionForGroupError(env, -res, tid);
}
@@ -239,7 +255,11 @@
char proc_path[255];
struct dirent *de;
- if ((grp == SP_FOREGROUND) || (grp > SP_MAX)) {
+ if (!verifyGroup(env, grp)) {
+ return;
+ }
+
+ if (grp == SP_FOREGROUND) {
signalExceptionForGroupError(env, EINVAL, pid);
return;
}
@@ -249,10 +269,6 @@
grp = SP_FOREGROUND;
isDefault = true;
}
- if (!verifyGroup(env, grp)) {
- return;
- }
- SchedPolicy sp = (SchedPolicy) grp;
if (kDebugPolicy) {
char cmdline[32];
@@ -268,7 +284,7 @@
close(fd);
}
- if (sp == SP_BACKGROUND) {
+ if (grp == SP_BACKGROUND) {
ALOGD("setProcessGroup: vvv pid %d (%s)", pid, cmdline);
} else {
ALOGD("setProcessGroup: ^^^ pid %d (%s)", pid, cmdline);
@@ -286,6 +302,7 @@
while ((de = readdir(d))) {
int t_pid;
int t_pri;
+ int err;
if (de->d_name[0] == '.')
continue;
@@ -311,28 +328,16 @@
if (t_pri >= ANDROID_PRIORITY_BACKGROUND) {
// This task wants to stay at background
// update its cpuset so it doesn't only run on bg core(s)
- if (cpusets_enabled()) {
- int err = set_cpuset_policy(t_pid, sp);
- if (err != NO_ERROR) {
- signalExceptionForGroupError(env, -err, t_pid);
- break;
- }
+ err = SetTaskProfiles(t_pid, {kCpusetProfileMap.at(grp)}, true) ? 0 : -1;
+ if (err != NO_ERROR) {
+ signalExceptionForGroupError(env, -err, t_pid);
+ break;
}
continue;
}
}
- int err;
- if (cpusets_enabled()) {
- // set both cpuset and cgroup for general threads
- err = set_cpuset_policy(t_pid, sp);
- if (err != NO_ERROR) {
- signalExceptionForGroupError(env, -err, t_pid);
- break;
- }
- }
-
- err = set_sched_policy(t_pid, sp);
+ err = SetTaskProfiles(t_pid, {kCpusetProfileMap.at(grp)}, true) ? 0 : -1;
if (err != NO_ERROR) {
signalExceptionForGroupError(env, -err, t_pid);
break;
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index 222a873..538861e 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -52,9 +52,14 @@
renderNode->output();
}
-static jint android_view_RenderNode_getDebugSize(JNIEnv* env, jobject clazz, jlong renderNodePtr) {
+static jint android_view_RenderNode_getUsageSize(JNIEnv* env, jobject clazz, jlong renderNodePtr) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
- return renderNode->getDebugSize();
+ return renderNode->getUsageSize();
+}
+
+static jint android_view_RenderNode_getAllocatedSize(JNIEnv* env, jobject clazz, jlong renderNodePtr) {
+ RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+ return renderNode->getAllocatedSize();
}
static jlong android_view_RenderNode_create(JNIEnv* env, jobject, jstring name) {
@@ -647,7 +652,8 @@
{ "nCreate", "(Ljava/lang/String;)J", (void*) android_view_RenderNode_create },
{ "nGetNativeFinalizer", "()J", (void*) android_view_RenderNode_getNativeFinalizer },
{ "nOutput", "(J)V", (void*) android_view_RenderNode_output },
- { "nGetDebugSize", "(J)I", (void*) android_view_RenderNode_getDebugSize },
+ { "nGetUsageSize", "(J)I", (void*) android_view_RenderNode_getUsageSize },
+ { "nGetAllocatedSize", "(J)I", (void*) android_view_RenderNode_getAllocatedSize },
{ "nAddAnimator", "(JJ)V", (void*) android_view_RenderNode_addAnimator },
{ "nEndAllAnimators", "(J)V", (void*) android_view_RenderNode_endAllAnimators },
{ "nRequestPositionUpdates", "(JLandroid/graphics/RenderNode$PositionUpdateListener;)V", (void*) android_view_RenderNode_requestPositionUpdates },
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 18f8d7b..b030b33 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -798,7 +798,7 @@
broadcast module. This is required in order to bind to the cell broadcast service, and
ensures that only the system can forward messages to it.
- <p>Protection level: signature|privileged
+ <p>Protection level: signature
@hide -->
<permission android:name="android.permission.BIND_CELL_BROADCAST_SERVICE"
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 3ea8a77..381ed7f 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -349,10 +349,10 @@
will be given a single shared user ID, so they can for example run
in the same process. Note that for them to actually get the same
user ID, they must also be signed with the same signature.
- @deprecated Shared user id's cause non-deterministic behaviour within the
- package manager. As such, it's use is discouraged, deprecated, and will
- be removed altogether in a future version of Android. Instead, proper
- communication mechanisms such as services and providers should be used
+ @deprecated Shared user IDs cause non-deterministic behavior within the
+ package manager. As such, its use is strongly discouraged and may be
+ removed in a future version of Android. Instead, apps should use proper
+ communication mechanisms, such as services and content providers,
to facilitate interoperability between shared components. -->
<attr name="sharedUserId" format="string" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 7eca699..3fef7a2d 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -433,6 +433,14 @@
-->
</string-array>
+ <!-- Configuration of network interfaces that support WakeOnLAN -->
+ <string-array translatable="false" name="config_wakeonlan_supported_interfaces">
+ <!--
+ <item>wlan0</item>
+ <item>eth0</item>
+ -->
+ </string-array>
+
<!-- Package name for the default CellBroadcastService module [DO NOT TRANSLATE] -->
<string name="cellbroadcast_default_package" translatable="false">com.android.cellbroadcastreceiver
</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a8b5340..363bc9d 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -747,6 +747,7 @@
<java-symbol type="string" name="config_default_dns_server" />
<java-symbol type="string" name="config_ethernet_iface_regex" />
<java-symbol type="array" name="config_ethernet_interfaces" />
+ <java-symbol type="array" name="config_wakeonlan_supported_interfaces" />
<java-symbol type="string" name="cellbroadcast_default_package" />
<java-symbol type="string" name="config_forceVoiceInteractionServicePackage" />
<java-symbol type="string" name="config_mms_user_agent" />
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index 51da0c8..39bf742 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -611,6 +611,10 @@
}
@Override
+ public void attachStartupAgents(String s) throws RemoteException {
+ }
+
+ @Override
public void scheduleApplicationInfoChanged(ApplicationInfo applicationInfo)
throws RemoteException {
}
diff --git a/core/tests/coretests/src/android/view/ViewGroupTest.java b/core/tests/coretests/src/android/view/ViewGroupTest.java
index 979a839..506cc2d 100644
--- a/core/tests/coretests/src/android/view/ViewGroupTest.java
+++ b/core/tests/coretests/src/android/view/ViewGroupTest.java
@@ -16,9 +16,14 @@
package android.view;
-import static androidx.test.InstrumentationRegistry.getContext;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
import android.content.Context;
import android.graphics.Region;
@@ -39,6 +44,60 @@
@SmallTest
public class ViewGroupTest {
+ @Test
+ public void testDispatchMouseEventsUnderCursor() {
+ final Context context = getInstrumentation().getContext();
+ final TestView viewGroup = new TestView(context, 0 /* left */, 0 /* top */,
+ 200 /* right */, 200 /* bottom */);
+ final TestView viewA = spy(new TestView(context, 0 /* left */, 0 /* top */,
+ 100 /* right */, 200 /* bottom */));
+ final TestView viewB = spy(new TestView(context, 100 /* left */, 0 /* top */,
+ 200 /* right */, 200 /* bottom */));
+
+ viewGroup.addView(viewA);
+ viewGroup.addView(viewB);
+
+ // Make sure all of them handle touch events dispatched to them.
+ doReturn(true).when(viewA).dispatchTouchEvent(any());
+ doReturn(true).when(viewB).dispatchTouchEvent(any());
+
+ MotionEvent.PointerProperties[] properties = new MotionEvent.PointerProperties[2];
+ properties[0] = new MotionEvent.PointerProperties();
+ properties[0].id = 0;
+ properties[0].toolType = MotionEvent.TOOL_TYPE_FINGER;
+ properties[1] = new MotionEvent.PointerProperties();
+ properties[1].id = 1;
+ properties[1].toolType = MotionEvent.TOOL_TYPE_FINGER;
+
+ MotionEvent.PointerCoords[] coords = new MotionEvent.PointerCoords[2];
+ coords[0] = new MotionEvent.PointerCoords();
+ coords[0].x = 80;
+ coords[0].y = 100;
+ coords[1] = new MotionEvent.PointerCoords();
+ coords[1].x = 240;
+ coords[1].y = 100;
+
+ MotionEvent event;
+ // Make sure the down event is active with a pointer which coordinate is different from the
+ // cursor position, which is the midpoint of all 2 pointers above.
+ event = MotionEvent.obtain(0 /* downTime */, 0 /* eventTime */, MotionEvent.ACTION_DOWN,
+ 2 /* pointerCount */, properties, coords, 0 /* metaState */, 0 /* buttonState */,
+ 0 /* xPrecision */, 0 /* yPrecision */, 0 /* deviceId */, 0 /* edgeFlags */,
+ InputDevice.SOURCE_MOUSE, 0 /* flags */);
+ viewGroup.dispatchTouchEvent(event);
+ verify(viewB).dispatchTouchEvent(event);
+
+ event = MotionEvent.obtain(0 /* downTime */, 0 /* eventTime */,
+ MotionEvent.ACTION_POINTER_DOWN | (1 << MotionEvent.ACTION_POINTER_INDEX_SHIFT),
+ 2 /* pointerCount */, properties, coords, 0 /* metaState */, 0 /* buttonState */,
+ 0 /* xPrecision */, 0 /* yPrecision */, 0 /* deviceId */, 0 /* edgeFlags */,
+ InputDevice.SOURCE_MOUSE, 0 /* flags */);
+ viewGroup.dispatchTouchEvent(event);
+ verify(viewB).dispatchTouchEvent(event);
+
+ verify(viewA, never()).dispatchTouchEvent(any());
+ }
+
/**
* Test if {@link ViewGroup#subtractObscuredTouchableRegion} works as expected.
*
@@ -59,7 +118,7 @@
*/
@Test
public void testSubtractObscuredTouchableRegion() {
- final Context context = getContext();
+ final Context context = getInstrumentation().getContext();
final TestView viewA = new TestView(context, 8 /* right */);
final TestView viewB = new TestView(context, 6 /* right */);
final TestView viewC = new TestView(context, 10 /* right */);
@@ -119,10 +178,14 @@
(contain ? "" : " not"), x), contain, region.contains(x, 0 /* y */));
}
- private static class TestView extends ViewGroup {
+ public static class TestView extends ViewGroup {
TestView(Context context, int right) {
+ this(context, 0 /* left */, 0 /* top */, right, 1 /* bottom */);
+ }
+
+ TestView(Context context, int left, int top, int right, int bottom) {
super(context);
- setFrame(0 /* left */, 0 /* top */, right, 1 /* bottom */);
+ setFrame(left, top, right, bottom);
}
@Override
diff --git a/core/tests/featureflagtests/OWNERS b/core/tests/featureflagtests/OWNERS
index 1a8fd2b..2ff4f5a 100644
--- a/core/tests/featureflagtests/OWNERS
+++ b/core/tests/featureflagtests/OWNERS
@@ -1,2 +1,2 @@
sbasi@google.com
-zhfan@google.com
\ No newline at end of file
+tmfang@google.com
\ No newline at end of file
diff --git a/graphics/java/android/graphics/RenderNode.java b/graphics/java/android/graphics/RenderNode.java
index 0e635c7..17e3b44 100644
--- a/graphics/java/android/graphics/RenderNode.java
+++ b/graphics/java/android/graphics/RenderNode.java
@@ -1380,7 +1380,22 @@
* @return Approximate memory usage in bytes.
*/
public @BytesLong long computeApproximateMemoryUsage() {
- return nGetDebugSize(mNativeRenderNode);
+ return nGetUsageSize(mNativeRenderNode);
+ }
+
+ /**
+ * Gets the approximate amount of memory allocated for the RenderNode for debug purposes.
+ * Does not include the memory allocated by any child RenderNodes nor any bitmaps, only the
+ * memory allocated for this RenderNode and any data it owns.
+ *
+ * The difference between this and {@link #computeApproximateMemoryUsage()} is this includes
+ * memory allocated but not used. In particular structures such as DisplayLists are similar
+ * to things like ArrayLists - they need to resize as commands are added to them. As such,
+ * memory used can be less than memory allocated.
+ *
+ * @hide */
+ public @BytesLong long computeApproximateMemoryAllocated() {
+ return nGetAllocatedSize(mNativeRenderNode);
}
/**
@@ -1485,7 +1500,8 @@
private static native void nOutput(long renderNode);
- private static native int nGetDebugSize(long renderNode);
+ private static native int nGetUsageSize(long renderNode);
+ private static native int nGetAllocatedSize(long renderNode);
private static native void nRequestPositionUpdates(long renderNode,
PositionUpdateListener callback);
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index a79b7c0..322eff2 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -69,6 +69,7 @@
bool hasText() const { return mHasText; }
size_t usedSize() const { return fUsed; }
+ size_t allocatedSize() const { return fReserved; }
private:
friend class RecordingCanvas;
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 8eb5e3d..6761435 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -108,7 +108,7 @@
output << std::endl;
}
-int RenderNode::getDebugSize() {
+int RenderNode::getUsageSize() {
int size = sizeof(RenderNode);
if (mStagingDisplayList) {
size += mStagingDisplayList->getUsedSize();
@@ -119,6 +119,18 @@
return size;
}
+int RenderNode::getAllocatedSize() {
+ int size = sizeof(RenderNode);
+ if (mStagingDisplayList) {
+ size += mStagingDisplayList->getAllocatedSize();
+ }
+ if (mDisplayList && mDisplayList != mStagingDisplayList) {
+ size += mDisplayList->getAllocatedSize();
+ }
+ return size;
+}
+
+
void RenderNode::prepareTree(TreeInfo& info) {
ATRACE_CALL();
LOG_ALWAYS_FATAL_IF(!info.damageAccumulator, "DamageAccumulator missing");
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index c6db7f1..d55e5b0 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -102,7 +102,8 @@
ANDROID_API void setStagingDisplayList(DisplayList* newData);
ANDROID_API void output();
- ANDROID_API int getDebugSize();
+ ANDROID_API int getUsageSize();
+ ANDROID_API int getAllocatedSize();
bool isRenderable() const { return mDisplayList && !mDisplayList->isEmpty(); }
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h
index e3c3273..cdd00db 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.h
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h
@@ -47,6 +47,7 @@
class SkiaDisplayList {
public:
size_t getUsedSize() { return allocator.usedSize() + mDisplayList.usedSize(); }
+ size_t getAllocatedSize() { return allocator.allocatedSize() + mDisplayList.allocatedSize(); }
~SkiaDisplayList() {
/* Given that we are using a LinearStdAllocator to store some of the
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index dc07f0d..8eb8153 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -135,7 +135,7 @@
return;
}
mGrContext->flush();
- mGrContext->performDeferredCleanup(std::chrono::seconds(30));
+ mGrContext->purgeResourcesNotUsedInMs(std::chrono::seconds(30));
}
sp<skiapipeline::VectorDrawableAtlas> CacheManager::acquireVectorDrawableAtlas() {
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 93fd0c8..30cc007 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -646,11 +646,11 @@
ATRACE_CALL();
if (!thread.getGrContext()) return;
ATRACE_CALL();
- if (level >= TRIM_MEMORY_UI_HIDDEN) {
- thread.cacheManager().trimMemory(CacheManager::TrimMemoryMode::Complete);
- }
if (level >= TRIM_MEMORY_COMPLETE) {
+ thread.cacheManager().trimMemory(CacheManager::TrimMemoryMode::Complete);
thread.destroyRenderingContext();
+ } else if (level >= TRIM_MEMORY_UI_HIDDEN) {
+ thread.cacheManager().trimMemory(CacheManager::TrimMemoryMode::UiHidden);
}
}
diff --git a/libs/hwui/utils/LinearAllocator.h b/libs/hwui/utils/LinearAllocator.h
index 9c4a1be..539e654 100644
--- a/libs/hwui/utils/LinearAllocator.h
+++ b/libs/hwui/utils/LinearAllocator.h
@@ -115,6 +115,7 @@
* wasted)
*/
size_t usedSize() const { return mTotalAllocated - mWastedSpace; }
+ size_t allocatedSize() const { return mTotalAllocated; }
private:
LinearAllocator(const LinearAllocator& other);
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index f3d6875..90e29df 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -145,7 +145,7 @@
* Key used for an extra holding a boolean enabled/disabled status value when a provider
* enabled/disabled event is broadcast using a PendingIntent.
*
- * @see #requestLocationUpdates(String, long, long, PendingIntent)
+ * @see #requestLocationUpdates(String, long, float, PendingIntent)
*/
public static final String KEY_PROVIDER_ENABLED = "providerEnabled";
@@ -153,7 +153,7 @@
* Key used for an extra holding a {@link Location} value when a location change is broadcast
* using a PendingIntent.
*
- * @see #requestLocationUpdates(String, long, long, PendingIntent)
+ * @see #requestLocationUpdates(String, long, float, PendingIntent)
*/
public static final String KEY_LOCATION_CHANGED = "location";
@@ -1256,44 +1256,46 @@
}
/**
- * Creates a mock location provider and adds it to the set of active providers.
+ * Creates a test location provider and adds it to the set of active providers. This provider
+ * will replace any provider with the same name that exists prior to this call.
*
- * @param name the provider name
+ * @param provider the provider name
*
+ * @throws IllegalArgumentException if provider is null
* @throws SecurityException if {@link android.app.AppOpsManager#OPSTR_MOCK_LOCATION
* mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
* allowed} for your app.
- * @throws IllegalArgumentException if a provider with the given name already exists
*/
public void addTestProvider(
- @NonNull String name, boolean requiresNetwork, boolean requiresSatellite,
+ @NonNull String provider, boolean requiresNetwork, boolean requiresSatellite,
boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude,
boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) {
+ Preconditions.checkArgument(provider != null, "invalid null provider");
+
ProviderProperties properties = new ProviderProperties(requiresNetwork,
requiresSatellite, requiresCell, hasMonetaryCost, supportsAltitude, supportsSpeed,
supportsBearing, powerRequirement, accuracy);
- if (name.matches(LocationProvider.BAD_CHARS_REGEX)) {
- throw new IllegalArgumentException("provider name contains illegal character: " + name);
- }
-
try {
- mService.addTestProvider(name, properties, mContext.getOpPackageName());
+ mService.addTestProvider(provider, properties, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Removes the mock location provider with the given name.
+ * Removes the test location provider with the given name or does nothing if no such test
+ * location provider exists.
*
* @param provider the provider name
*
+ * @throws IllegalArgumentException if provider is null
* @throws SecurityException if {@link android.app.AppOpsManager#OPSTR_MOCK_LOCATION
* mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
* allowed} for your app.
- * @throws IllegalArgumentException if no provider with the given name exists
*/
public void removeTestProvider(@NonNull String provider) {
+ Preconditions.checkArgument(provider != null, "invalid null provider");
+
try {
mService.removeTestProvider(provider, mContext.getOpPackageName());
} catch (RemoteException e) {
@@ -1302,60 +1304,53 @@
}
/**
- * Sets a mock location for the given provider.
- * <p>This location will be used in place of any actual location from the provider.
- * The location object must have a minimum number of fields set to be
- * considered a valid LocationProvider Location, as per documentation
- * on {@link Location} class.
+ * Sets a new location for the given test provider. This location will be identiable as a mock
+ * location to all clients via {@link Location#isFromMockProvider()}.
+ *
+ * <p>The location object must have a minimum number of fields set to be considered valid, as
+ * per documentation on {@link Location} class.
*
* @param provider the provider name
- * @param loc the mock location
+ * @param location the mock location
*
* @throws SecurityException if {@link android.app.AppOpsManager#OPSTR_MOCK_LOCATION
* mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
* allowed} for your app.
- * @throws IllegalArgumentException if no provider with the given name exists
- * @throws IllegalArgumentException if the location is incomplete
+ * @throws IllegalArgumentException if the provider is null or not a test provider
+ * @throws IllegalArgumentException if the location is null or incomplete
*/
- public void setTestProviderLocation(@NonNull String provider, @NonNull Location loc) {
- if (!loc.isComplete()) {
+ public void setTestProviderLocation(@NonNull String provider, @NonNull Location location) {
+ Preconditions.checkArgument(provider != null, "invalid null provider");
+ Preconditions.checkArgument(location != null, "invalid null location");
+
+ if (!location.isComplete()) {
IllegalArgumentException e = new IllegalArgumentException(
- "Incomplete location object, missing timestamp or accuracy? " + loc);
+ "Incomplete location object, missing timestamp or accuracy? " + location);
if (mContext.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN) {
- // just log on old platform (for backwards compatibility)
Log.w(TAG, e);
- loc.makeComplete();
+ location.makeComplete();
} else {
- // really throw it!
throw e;
}
}
try {
- mService.setTestProviderLocation(provider, loc, mContext.getOpPackageName());
+ mService.setTestProviderLocation(provider, location, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Removes any mock location associated with the given provider.
+ * Does nothing.
*
- * @param provider the provider name
- *
- * @throws SecurityException if {@link android.app.AppOpsManager#OPSTR_MOCK_LOCATION
- * mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
- * allowed} for your app.
- * @throws IllegalArgumentException if no provider with the given name exists
- *
- * @deprecated This function has always been a no-op, and may be removed in the future.
+ * @deprecated This method has always been a no-op, and may be removed in the future.
*/
@Deprecated
public void clearTestProviderLocation(@NonNull String provider) {}
/**
- * Sets a mock enabled value for the given provider. This value will be used in place
- * of any actual value from the provider.
+ * Sets the given test provider to be enabled or disabled.
*
* @param provider the provider name
* @param enabled the mock enabled value
@@ -1363,9 +1358,11 @@
* @throws SecurityException if {@link android.app.AppOpsManager#OPSTR_MOCK_LOCATION
* mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
* allowed} for your app.
- * @throws IllegalArgumentException if no provider with the given name exists
+ * @throws IllegalArgumentException if provider is null or not a test provider
*/
public void setTestProviderEnabled(@NonNull String provider, boolean enabled) {
+ Preconditions.checkArgument(provider != null, "invalid null provider");
+
try {
mService.setTestProviderEnabled(provider, enabled, mContext.getOpPackageName());
} catch (RemoteException e) {
@@ -1374,14 +1371,8 @@
}
/**
- * Removes any mock enabled value associated with the given provider.
- *
- * @param provider the provider name
- *
- * @throws SecurityException if {@link android.app.AppOpsManager#OPSTR_MOCK_LOCATION
- * mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
- * allowed} for your app.
- * @throws IllegalArgumentException if no provider with the given name exists
+ * Equivalent to calling {@link #setTestProviderEnabled(String, boolean)} to disable a test
+ * provider.
*
* @deprecated Use {@link #setTestProviderEnabled(String, boolean)} instead.
*/
diff --git a/location/java/android/location/LocationProvider.java b/location/java/android/location/LocationProvider.java
index b69a9d7..52a03b6 100644
--- a/location/java/android/location/LocationProvider.java
+++ b/location/java/android/location/LocationProvider.java
@@ -53,28 +53,10 @@
@Deprecated
public static final int AVAILABLE = 2;
- /**
- * A regular expression matching characters that may not appear
- * in the name of a LocationProvider
- * @hide
- */
- public static final String BAD_CHARS_REGEX = "[^a-zA-Z0-9]";
-
private final String mName;
private final ProviderProperties mProperties;
- /**
- * Constructs a LocationProvider with the given name. Provider names must
- * consist only of the characters [a-zA-Z0-9].
- *
- * @throws IllegalArgumentException if name contains an illegal character
- *
- * @hide
- */
- public LocationProvider(String name, ProviderProperties properties) {
- if (name.matches(BAD_CHARS_REGEX)) {
- throw new IllegalArgumentException("provider name contains illegal character: " + name);
- }
+ LocationProvider(String name, ProviderProperties properties) {
mName = name;
mProperties = properties;
}
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 0346010..f421029 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -227,6 +227,44 @@
public native String extractMetadata(int keyCode);
/**
+ * This method is similar to {@link #getFrameAtTime(long, int, BitmapParams)}
+ * except that the device will choose the actual {@link Bitmap.Config} to use.
+ *
+ * @param timeUs The time position where the frame will be retrieved.
+ * When retrieving the frame at the given time position, there is no
+ * guarantee that the data source has a frame located at the position.
+ * When this happens, a frame nearby will be returned. If timeUs is
+ * negative, time position and option will ignored, and any frame
+ * that the implementation considers as representative may be returned.
+ *
+ * @param option a hint on how the frame is found. Use
+ * {@link #OPTION_PREVIOUS_SYNC} if one wants to retrieve a sync frame
+ * that has a timestamp earlier than or the same as timeUs. Use
+ * {@link #OPTION_NEXT_SYNC} if one wants to retrieve a sync frame
+ * that has a timestamp later than or the same as timeUs. Use
+ * {@link #OPTION_CLOSEST_SYNC} if one wants to retrieve a sync frame
+ * that has a timestamp closest to or the same as timeUs. Use
+ * {@link #OPTION_CLOSEST} if one wants to retrieve a frame that may
+ * or may not be a sync frame but is closest to or the same as timeUs.
+ * {@link #OPTION_CLOSEST} often has larger performance overhead compared
+ * to the other options if there is no sync frame located at timeUs.
+ *
+ * @return A Bitmap containing a representative video frame, which can be null,
+ * if such a frame cannot be retrieved. {@link Bitmap#getConfig()} can
+ * be used to query the actual {@link Bitmap.Config}.
+ *
+ * @see {@link #getFrameAtTime(long, int, BitmapParams)}
+ */
+ public Bitmap getFrameAtTime(long timeUs, @Option int option) {
+ if (option < OPTION_PREVIOUS_SYNC ||
+ option > OPTION_CLOSEST) {
+ throw new IllegalArgumentException("Unsupported option: " + option);
+ }
+
+ return _getFrameAtTime(timeUs, option, -1 /*dst_width*/, -1 /*dst_height*/, null);
+ }
+
+ /**
* Call this method after setDataSource(). This method finds a
* representative frame close to the given time position by considering
* the given option if possible, and returns it as a bitmap.
@@ -255,16 +293,60 @@
* {@link #OPTION_CLOSEST} often has larger performance overhead compared
* to the other options if there is no sync frame located at timeUs.
*
+ * @param params BitmapParams that controls the returned bitmap config
+ * (such as pixel formats).
+ *
* @return A Bitmap containing a representative video frame, which
* can be null, if such a frame cannot be retrieved.
+ *
+ * @see {@link #getFrameAtTime(long, int)}
*/
- public Bitmap getFrameAtTime(long timeUs, @Option int option) {
+ public Bitmap getFrameAtTime(
+ long timeUs, @Option int option, @NonNull BitmapParams params) {
if (option < OPTION_PREVIOUS_SYNC ||
option > OPTION_CLOSEST) {
throw new IllegalArgumentException("Unsupported option: " + option);
}
- return _getFrameAtTime(timeUs, option, -1 /*dst_width*/, -1 /*dst_height*/);
+ return _getFrameAtTime(timeUs, option, -1 /*dst_width*/, -1 /*dst_height*/, params);
+ }
+
+ /**
+ * This method is similar to {@link #getScaledFrameAtTime(long, int, int, int, BitmapParams)}
+ * except that the device will choose the actual {@link Bitmap.Config} to use.
+ *
+ * @param timeUs The time position in microseconds where the frame will be retrieved.
+ * When retrieving the frame at the given time position, there is no
+ * guarantee that the data source has a frame located at the position.
+ * When this happens, a frame nearby will be returned. If timeUs is
+ * negative, time position and option will ignored, and any frame
+ * that the implementation considers as representative may be returned.
+ *
+ * @param option a hint on how the frame is found. Use
+ * {@link #OPTION_PREVIOUS_SYNC} if one wants to retrieve a sync frame
+ * that has a timestamp earlier than or the same as timeUs. Use
+ * {@link #OPTION_NEXT_SYNC} if one wants to retrieve a sync frame
+ * that has a timestamp later than or the same as timeUs. Use
+ * {@link #OPTION_CLOSEST_SYNC} if one wants to retrieve a sync frame
+ * that has a timestamp closest to or the same as timeUs. Use
+ * {@link #OPTION_CLOSEST} if one wants to retrieve a frame that may
+ * or may not be a sync frame but is closest to or the same as timeUs.
+ * {@link #OPTION_CLOSEST} often has larger performance overhead compared
+ * to the other options if there is no sync frame located at timeUs.
+ *
+ * @param dstWidth expected output bitmap width
+ * @param dstHeight expected output bitmap height
+ * @return A Bitmap containing a representative video frame, which can be null,
+ * if such a frame cannot be retrieved. {@link Bitmap#getConfig()} can
+ * be used to query the actual {@link Bitmap.Config}.
+ * @throws IllegalArgumentException if passed in invalid option or width by height
+ * is less than or equal to 0.
+ * @see {@link #getScaledFrameAtTime(long, int, int, int, BitmapParams)}
+ */
+ public Bitmap getScaledFrameAtTime(
+ long timeUs, @Option int option, int dstWidth, int dstHeight) {
+ validate(option, dstWidth, dstHeight);
+ return _getFrameAtTime(timeUs, option, dstWidth, dstHeight, null);
}
/**
@@ -297,15 +379,23 @@
*
* @param dstWidth expected output bitmap width
* @param dstHeight expected output bitmap height
+ * @param params BitmapParams that controls the returned bitmap config
+ * (such as pixel formats).
+ *
* @return A Bitmap of size not larger than dstWidth by dstHeight containing a
* scaled video frame, which can be null, if such a frame cannot be retrieved.
* @throws IllegalArgumentException if passed in invalid option or width by height
* is less than or equal to 0.
+ * @see {@link #getScaledFrameAtTime(long, int, int, int)}
*/
- public Bitmap getScaledFrameAtTime(
- long timeUs, @Option int option, int dstWidth, int dstHeight) {
- if (option < OPTION_PREVIOUS_SYNC ||
- option > OPTION_CLOSEST) {
+ public Bitmap getScaledFrameAtTime(long timeUs, @Option int option,
+ int dstWidth, int dstHeight, @NonNull BitmapParams params) {
+ validate(option, dstWidth, dstHeight);
+ return _getFrameAtTime(timeUs, option, dstWidth, dstHeight, params);
+ }
+
+ private void validate(@Option int option, int dstWidth, int dstHeight) {
+ if (option < OPTION_PREVIOUS_SYNC || option > OPTION_CLOSEST) {
throw new IllegalArgumentException("Unsupported option: " + option);
}
if (dstWidth <= 0) {
@@ -314,8 +404,6 @@
if (dstHeight <= 0) {
throw new IllegalArgumentException("Invalid height: " + dstHeight);
}
-
- return _getFrameAtTime(timeUs, option, dstWidth, dstHeight);
}
/**
@@ -365,10 +453,12 @@
* @see #getFrameAtTime(long, int)
*/
public Bitmap getFrameAtTime() {
- return _getFrameAtTime(-1, OPTION_CLOSEST_SYNC, -1 /*dst_width*/, -1 /*dst_height*/);
+ return _getFrameAtTime(
+ -1, OPTION_CLOSEST_SYNC, -1 /*dst_width*/, -1 /*dst_height*/, null);
}
- private native Bitmap _getFrameAtTime(long timeUs, int option, int width, int height);
+ private native Bitmap _getFrameAtTime(
+ long timeUs, int option, int width, int height, @Nullable BitmapParams params);
public static final class BitmapParams {
private Bitmap.Config inPreferredConfig = Bitmap.Config.ARGB_8888;
diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java
index 5dcbb05..abd774d 100644
--- a/media/java/android/media/MediaRoute2Info.java
+++ b/media/java/android/media/MediaRoute2Info.java
@@ -46,6 +46,21 @@
}
};
+ /**
+ * Playback information indicating the playback volume is fixed, i.e. it cannot be
+ * controlled from this object. An example of fixed playback volume is a remote player,
+ * playing over HDMI where the user prefers to control the volume on the HDMI sink, rather
+ * than attenuate at the source.
+ * @see #getVolumeHandling()
+ */
+ public static final int PLAYBACK_VOLUME_FIXED = 0;
+ /**
+ * Playback information indicating the playback volume is variable and can be controlled
+ * from this object.
+ * @see #getVolumeHandling()
+ */
+ public static final int PLAYBACK_VOLUME_VARIABLE = 1;
+
@NonNull
final String mId;
@Nullable
@@ -58,6 +73,9 @@
final String mClientPackageName;
@NonNull
final List<String> mSupportedCategories;
+ final int mVolume;
+ final int mVolumeMax;
+ final int mVolumeHandling;
@Nullable
final Bundle mExtras;
@@ -68,6 +86,9 @@
mDescription = builder.mDescription;
mClientPackageName = builder.mClientPackageName;
mSupportedCategories = builder.mSupportedCategories;
+ mVolume = builder.mVolume;
+ mVolumeMax = builder.mVolumeMax;
+ mVolumeHandling = builder.mVolumeHandling;
mExtras = builder.mExtras;
}
@@ -78,6 +99,9 @@
mDescription = in.readString();
mClientPackageName = in.readString();
mSupportedCategories = in.createStringArrayList();
+ mVolume = in.readInt();
+ mVolumeMax = in.readInt();
+ mVolumeHandling = in.readInt();
mExtras = in.readBundle();
}
@@ -111,6 +135,9 @@
&& Objects.equals(mDescription, other.mDescription)
&& Objects.equals(mClientPackageName, other.mClientPackageName)
&& Objects.equals(mSupportedCategories, other.mSupportedCategories)
+ && (mVolume == other.mVolume)
+ && (mVolumeMax == other.mVolumeMax)
+ && (mVolumeHandling == other.mVolumeHandling)
//TODO: This will be evaluated as false in most cases. Try not to.
&& Objects.equals(mExtras, other.mExtras);
}
@@ -162,6 +189,29 @@
return mSupportedCategories;
}
+ /**
+ * Gets the current volume of the route. This may be invalid if the route is not selected.
+ */
+ public int getVolume() {
+ return mVolume;
+ }
+
+ /**
+ * Gets the maximum volume of the route.
+ */
+ public int getVolumeMax() {
+ return mVolumeMax;
+ }
+
+ /**
+ * Gets information about how volume is handled on the route.
+ *
+ * @return {@link #PLAYBACK_VOLUME_FIXED} or {@link #PLAYBACK_VOLUME_VARIABLE}
+ */
+ public int getVolumeHandling() {
+ return mVolumeHandling;
+ }
+
@Nullable
public Bundle getExtras() {
return mExtras;
@@ -199,6 +249,9 @@
dest.writeString(mDescription);
dest.writeString(mClientPackageName);
dest.writeStringList(mSupportedCategories);
+ dest.writeInt(mVolume);
+ dest.writeInt(mVolumeMax);
+ dest.writeInt(mVolumeHandling);
dest.writeBundle(mExtras);
}
@@ -209,6 +262,9 @@
.append("id=").append(getId())
.append(", name=").append(getName())
.append(", description=").append(getDescription())
+ .append(", volume=").append(getVolume())
+ .append(", volumeMax=").append(getVolumeMax())
+ .append(", volumeHandling=").append(getVolumeHandling())
.append(", providerId=").append(getProviderId())
.append(" }");
return result.toString();
@@ -224,6 +280,9 @@
String mDescription;
String mClientPackageName;
List<String> mSupportedCategories;
+ int mVolume;
+ int mVolumeMax;
+ int mVolumeHandling;
Bundle mExtras;
public Builder(@NonNull String id, @NonNull String name) {
@@ -251,6 +310,9 @@
mDescription = routeInfo.mDescription;
setClientPackageName(routeInfo.mClientPackageName);
setSupportedCategories(routeInfo.mSupportedCategories);
+ setVolume(routeInfo.mVolume);
+ setVolumeMax(routeInfo.mVolumeMax);
+ setVolumeHandling(routeInfo.mVolumeHandling);
if (routeInfo.mExtras != null) {
mExtras = new Bundle(routeInfo.mExtras);
}
@@ -345,6 +407,32 @@
}
/**
+ * Sets the route's current volume, or 0 if unknown.
+ */
+ @NonNull
+ public Builder setVolume(int volume) {
+ mVolume = volume;
+ return this;
+ }
+
+ /**
+ * Sets the route's maximum volume, or 0 if unknown.
+ */
+ @NonNull
+ public Builder setVolumeMax(int volumeMax) {
+ mVolumeMax = volumeMax;
+ return this;
+ }
+
+ /**
+ * Sets the route's volume handling.
+ */
+ @NonNull
+ public Builder setVolumeHandling(int volumeHandling) {
+ mVolumeHandling = volumeHandling;
+ return this;
+ }
+ /**
* Sets a bundle of extras for the route.
*/
@NonNull
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index 18fd1a0..bc4bceb 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -350,9 +350,10 @@
return jBitmap;
}
-static int getColorFormat(JNIEnv *env, jobject options) {
+static int getColorFormat(JNIEnv *env, jobject options,
+ int defaultPreferred = HAL_PIXEL_FORMAT_RGBA_8888) {
if (options == NULL) {
- return HAL_PIXEL_FORMAT_RGBA_8888;
+ return defaultPreferred;
}
ScopedLocalRef<jobject> inConfig(env, env->GetObjectField(options, fields.inPreferredConfig));
@@ -383,7 +384,8 @@
}
static jobject android_media_MediaMetadataRetriever_getFrameAtTime(
- JNIEnv *env, jobject thiz, jlong timeUs, jint option, jint dst_width, jint dst_height)
+ JNIEnv *env, jobject thiz, jlong timeUs, jint option,
+ jint dst_width, jint dst_height, jobject params)
{
ALOGV("getFrameAtTime: %lld us option: %d dst width: %d heigh: %d",
(long long)timeUs, option, dst_width, dst_height);
@@ -392,10 +394,13 @@
jniThrowException(env, "java/lang/IllegalStateException", "No retriever available");
return NULL;
}
+ // For getFrameAtTime family of calls, default to HAL_PIXEL_FORMAT_RGB_565
+ // to keep the behavior consistent with older releases
+ int colorFormat = getColorFormat(env, params, HAL_PIXEL_FORMAT_RGB_565);
// Call native method to retrieve a video frame
VideoFrame *videoFrame = NULL;
- sp<IMemory> frameMemory = retriever->getFrameAtTime(timeUs, option);
+ sp<IMemory> frameMemory = retriever->getFrameAtTime(timeUs, option, colorFormat);
// TODO: Using unsecurePointer() has some associated security pitfalls
// (see declaration for details).
// Either document why it is safe in this case or address the
@@ -408,7 +413,9 @@
return NULL;
}
- return getBitmapFromVideoFrame(env, videoFrame, dst_width, dst_height, kRGB_565_SkColorType);
+ SkColorType outColorType = setOutColorType(env, colorFormat, params);
+
+ return getBitmapFromVideoFrame(env, videoFrame, dst_width, dst_height, outColorType);
}
static jobject android_media_MediaMetadataRetriever_getImageAtIndex(
@@ -739,7 +746,7 @@
(void *)android_media_MediaMetadataRetriever_setDataSourceFD},
{"_setDataSource", "(Landroid/media/MediaDataSource;)V",
(void *)android_media_MediaMetadataRetriever_setDataSourceCallback},
- {"_getFrameAtTime", "(JIII)Landroid/graphics/Bitmap;",
+ {"_getFrameAtTime", "(JIIILandroid/media/MediaMetadataRetriever$BitmapParams;)Landroid/graphics/Bitmap;",
(void *)android_media_MediaMetadataRetriever_getFrameAtTime},
{
"_getImageAtIndex",
diff --git a/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java b/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
index 1267aa8..8d39a93 100644
--- a/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
+++ b/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
@@ -36,6 +36,12 @@
public static final String ROUTE_ID_SPECIAL_CATEGORY = "route_special_category";
public static final String ROUTE_NAME_SPECIAL_CATEGORY = "Special Category Route";
+ public static final int VOLUME_MAX = 100;
+ public static final String ROUTE_ID_FIXED_VOLUME = "route_fixed_volume";
+ public static final String ROUTE_NAME_FIXED_VOLUME = "Fixed Volume Route";
+ public static final String ROUTE_ID_VARIABLE_VOLUME = "route_variable_volume";
+ public static final String ROUTE_NAME_VARIABLE_VOLUME = "Variable Volume Route";
+
public static final String ACTION_REMOVE_ROUTE =
"com.android.mediarouteprovider.action_remove_route";
@@ -58,9 +64,23 @@
.addSupportedCategory(CATEGORY_SAMPLE)
.addSupportedCategory(CATEGORY_SPECIAL)
.build();
+ MediaRoute2Info fixedVolumeRoute =
+ new MediaRoute2Info.Builder(ROUTE_ID_FIXED_VOLUME, ROUTE_NAME_FIXED_VOLUME)
+ .addSupportedCategory(CATEGORY_SAMPLE)
+ .setVolumeHandling(MediaRoute2Info.PLAYBACK_VOLUME_FIXED)
+ .build();
+ MediaRoute2Info variableVolumeRoute =
+ new MediaRoute2Info.Builder(ROUTE_ID_VARIABLE_VOLUME, ROUTE_NAME_VARIABLE_VOLUME)
+ .addSupportedCategory(CATEGORY_SAMPLE)
+ .setVolumeHandling(MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE)
+ .setVolumeMax(VOLUME_MAX)
+ .build();
+
mRoutes.put(route1.getId(), route1);
mRoutes.put(route2.getId(), route2);
mRoutes.put(routeSpecial.getId(), routeSpecial);
+ mRoutes.put(fixedVolumeRoute.getId(), fixedVolumeRoute);
+ mRoutes.put(variableVolumeRoute.getId(), variableVolumeRoute);
}
@Override
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
index a3ed07a..da832ac 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
@@ -16,6 +16,9 @@
package com.android.mediaroutertest;
+import static android.media.MediaRoute2Info.PLAYBACK_VOLUME_FIXED;
+import static android.media.MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
@@ -61,6 +64,12 @@
public static final String ROUTE_ID_SPECIAL_CATEGORY = "route_special_category";
public static final String ROUTE_NAME_SPECIAL_CATEGORY = "Special Category Route";
+ public static final int VOLUME_MAX = 100;
+ public static final String ROUTE_ID_FIXED_VOLUME = "route_fixed_volume";
+ public static final String ROUTE_NAME_FIXED_VOLUME = "Fixed Volume Route";
+ public static final String ROUTE_ID_VARIABLE_VOLUME = "route_variable_volume";
+ public static final String ROUTE_NAME_VARIABLE_VOLUME = "Variable Volume Route";
+
public static final String ACTION_REMOVE_ROUTE =
"com.android.mediarouteprovider.action_remove_route";
@@ -98,7 +107,7 @@
mPackageName = mContext.getPackageName();
}
- //TODO: Move to a seperate file
+ //TODO: Move to a separate file
@Test
public void testMediaRoute2Info() {
MediaRoute2Info routeInfo1 = new MediaRoute2Info.Builder("id", "name")
@@ -281,6 +290,26 @@
mManager.unregisterCallback(managerCallback);
}
+ @Test
+ public void testVolumeHandling() {
+ MediaRouter2.Callback mockCallback = mock(MediaRouter2.Callback.class);
+
+ mRouter2.setControlCategories(CONTROL_CATEGORIES_ALL);
+ mRouter2.registerCallback(mExecutor, mockCallback);
+ verify(mockCallback, timeout(TIMEOUT_MS).atLeastOnce())
+ .onRoutesChanged(argThat(routes -> routes.size() > 0));
+ Map<String, MediaRoute2Info> routes = createRouteMap(mRouter2.getRoutes());
+
+ MediaRoute2Info fixedVolumeRoute = routes.get(ROUTE_ID_FIXED_VOLUME);
+ MediaRoute2Info variableVolumeRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME);
+
+ assertEquals(PLAYBACK_VOLUME_FIXED, fixedVolumeRoute.getVolumeHandling());
+ assertEquals(PLAYBACK_VOLUME_VARIABLE, variableVolumeRoute.getVolumeHandling());
+ assertEquals(VOLUME_MAX, variableVolumeRoute.getVolumeMax());
+
+ mRouter2.unregisterCallback(mockCallback);
+ }
+
// Helper for getting routes easily
static Map<String, MediaRoute2Info> createRouteMap(List<MediaRoute2Info> routes) {
Map<String, MediaRoute2Info> routeMap = new HashMap<>();
diff --git a/mime/Android.bp b/mime/Android.bp
index 8b2b059..23a8fbf 100644
--- a/mime/Android.bp
+++ b/mime/Android.bp
@@ -60,7 +60,7 @@
tools: [
"soong_zip",
],
- srcs: [":mime.types"],
+ srcs: [":mime.types.minimized"],
out: ["mimemap-res.jar"],
cmd: "mkdir $(genDir)/res/ && cp $(in) $(genDir)/res/ && $(location soong_zip) -C $(genDir) -o $(out) -D $(genDir)/res/",
}
@@ -73,42 +73,49 @@
tools: [
"soong_zip",
],
- srcs: [":mime.types"],
+ srcs: [":mime.types.minimized"],
out: ["mimemap-testing-res.jar"],
cmd: "mkdir $(genDir)/testres/ && cp $(in) $(genDir)/testres/ && $(location soong_zip) -C $(genDir) -o $(out) -D $(genDir)/testres/",
}
-// Combination of all *mime.types resources.
+// Combination of all *mime.types.minimized resources.
filegroup {
- name: "mime.types",
+ name: "mime.types.minimized",
visibility: [
"//visibility:private",
],
srcs: [
- ":debian.mime.types",
- ":android.mime.types",
- ":vendor.mime.types",
+ ":debian.mime.types.minimized",
+ ":android.mime.types.minimized",
+ ":vendor.mime.types.minimized",
],
}
-filegroup {
- name: "android.mime.types",
+java_genrule {
+ name: "android.mime.types.minimized",
visibility: [
"//visibility:private",
],
- path: "java-res/",
+ out: ["android.mime.types"],
srcs: [
"java-res/android.mime.types",
],
+ // strip comments normalize whitepace drop empty lines
+ cmd: "awk '{gsub(/#.*$$/,\"\"); $$1=$$1; print;}' $(in) | grep ' ' > $(out)",
}
-filegroup {
- name: "vendor.mime.types",
+// Unlike the other *mime.types files, vendor.mime.types gets '?' prepended to
+// every field so that its mappings will never overwrite earlier mappings by
+// the other resource files. http://b/141842825
+java_genrule {
+ name: "vendor.mime.types.minimized",
visibility: [
"//visibility:private",
],
- path: "java-res/",
+ out: ["vendor.mime.types"],
srcs: [
"java-res/vendor.mime.types",
],
+ // strip comments normalize whitepace drop empty lines prepend ? to fields that are missing it
+ cmd: "awk '{gsub(/#.*$$/,\"\"); $$1=$$1; print;}' $(in) | grep ' ' | awk '{for(i=1;i<=NF;i++) { sub(/^\\??/, \"?\", $$i); }; print}' > $(out)",
}
diff --git a/mime/java/android/content/type/DefaultMimeMapFactory.java b/mime/java/android/content/type/DefaultMimeMapFactory.java
index 03b685d..11d20d4 100644
--- a/mime/java/android/content/type/DefaultMimeMapFactory.java
+++ b/mime/java/android/content/type/DefaultMimeMapFactory.java
@@ -23,11 +23,9 @@
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
-import java.util.regex.Pattern;
/**
* Creates the framework default {@link MimeMap}, a bidirectional mapping
@@ -53,8 +51,6 @@
return create(resourceName -> c.getResourceAsStream("/res/" + resourceName));
}
- private static final Pattern SPLIT_PATTERN = Pattern.compile("\\s+");
-
/**
* Creates a {@link MimeMap} instance whose resources are loaded from the
* InputStreams looked up in {@code resourceSupplier}.
@@ -63,33 +59,43 @@
*/
public static MimeMap create(Function<String, InputStream> resourceSupplier) {
MimeMap.Builder builder = MimeMap.builder();
- parseTypes(builder, true, resourceSupplier, "mime.types");
- parseTypes(builder, true, resourceSupplier, "android.mime.types");
- parseTypes(builder, false, resourceSupplier, "vendor.mime.types");
+ // The files loaded here must be in minimized format with lines of the
+ // form "mime/type ext1 ext2 ext3", i.e. no comments, no empty lines, no
+ // leading/trailing whitespace and with a single space between entries on
+ // each line. See http://b/142267887
+ //
+ // Note: the order here matters - later entries can overwrite earlier ones
+ // (except that vendor.mime.types entries are prefixed with '?' which makes
+ // them never overwrite).
+ parseTypes(builder, resourceSupplier, "debian.mime.types");
+ parseTypes(builder, resourceSupplier, "android.mime.types");
+ parseTypes(builder, resourceSupplier, "vendor.mime.types");
return builder.build();
}
- private static void parseTypes(MimeMap.Builder builder, boolean allowOverwrite,
+ private static void parseTypes(MimeMap.Builder builder,
Function<String, InputStream> resourceSupplier, String resourceName) {
try (InputStream inputStream = Objects.requireNonNull(resourceSupplier.apply(resourceName));
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
String line;
+ List<String> specs = new ArrayList<>(10); // re-use for each line
while ((line = reader.readLine()) != null) {
- int commentPos = line.indexOf('#');
- if (commentPos >= 0) {
- line = line.substring(0, commentPos);
- }
- line = line.trim();
- if (line.isEmpty()) {
- continue;
- }
- List<String> specs = Arrays.asList(SPLIT_PATTERN.split(line));
- if (!allowOverwrite) {
- // Pretend that the mimeType and each file extension listed in the line
- // carries a "?" prefix, which means that it can add new mappings but
- // not modify existing mappings (putIfAbsent() semantics).
- specs = ensurePrefix("?", specs);
- }
+ specs.clear();
+ // Lines are of the form "mimeSpec extSpec extSpec[...]" with a single space
+ // separating them and no leading/trailing spaces and no empty lines.
+ int startIdx = 0;
+ do {
+ int endIdx = line.indexOf(' ', startIdx);
+ if (endIdx < 0) {
+ endIdx = line.length();
+ }
+ String spec = line.substring(startIdx, endIdx);
+ if (spec.isEmpty()) {
+ throw new IllegalArgumentException("Malformed line: " + line);
+ }
+ specs.add(spec);
+ startIdx = endIdx + 1; // skip over the space
+ } while (startIdx < line.length());
builder.put(specs.get(0), specs.subList(1, specs.size()));
}
} catch (IOException | RuntimeException e) {
@@ -97,15 +103,4 @@
}
}
- private static List<String> ensurePrefix(String prefix, List<String> strings) {
- List<String> result = new ArrayList<>(strings.size());
- for (String s : strings) {
- if (!s.startsWith(prefix)) {
- s = prefix + s;
- }
- result.add(s);
- }
- return result;
- }
-
}
diff --git a/mms/OWNERS b/mms/OWNERS
new file mode 100644
index 0000000..ba00d5d
--- /dev/null
+++ b/mms/OWNERS
@@ -0,0 +1,14 @@
+set noparent
+
+tgunn@google.com
+breadley@google.com
+hallliu@google.com
+rgreenwalt@google.com
+amitmahajan@google.com
+fionaxu@google.com
+jackyu@google.com
+jminjie@google.com
+satk@google.com
+shuoq@google.com
+refuhoo@google.com
+nazaninb@google.com
diff --git a/telephony/java/android/telephony/MmsManager.java b/mms/java/android/telephony/MmsManager.java
similarity index 100%
rename from telephony/java/android/telephony/MmsManager.java
rename to mms/java/android/telephony/MmsManager.java
diff --git a/telephony/java/com/android/internal/telephony/IMms.aidl b/mms/java/com/android/internal/telephony/IMms.aidl
similarity index 100%
rename from telephony/java/com/android/internal/telephony/IMms.aidl
rename to mms/java/com/android/internal/telephony/IMms.aidl
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/StreamUtils.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/StreamUtils.java
index 91b2926..66be25b 100644
--- a/packages/BackupEncryption/src/com/android/server/backup/encryption/StreamUtils.java
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/StreamUtils.java
@@ -18,9 +18,13 @@
import java.io.Closeable;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
/** Utility methods for dealing with Streams */
public class StreamUtils {
+ private static final int MAX_COPY_BUFFER_SIZE = 1024; // 1k copy buffer size.
+
/**
* Close a Closeable and silently ignore any IOExceptions.
*
@@ -33,4 +37,28 @@
// Silently ignore
}
}
+
+ /**
+ * Copy data from an InputStream to an OutputStream upto a given number of bytes.
+ *
+ * @param in The source InputStream
+ * @param out The destination OutputStream
+ * @param limit The maximum number of bytes to copy
+ * @throws IOException Thrown if there is a problem performing the copy.
+ */
+ public static void copyStream(InputStream in, OutputStream out, int limit) throws IOException {
+ int bufferSize = Math.min(MAX_COPY_BUFFER_SIZE, limit);
+ byte[] buffer = new byte[bufferSize];
+
+ int copied = 0;
+ while (copied < limit) {
+ int maxReadSize = Math.min(bufferSize, limit - copied);
+ int read = in.read(buffer, 0, maxReadSize);
+ if (read < 0) {
+ return; // Reached the stream end before the limit
+ }
+ out.write(buffer, 0, read);
+ copied += read;
+ }
+ }
}
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/EncryptedFullBackupDataProcessor.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/EncryptedFullBackupDataProcessor.java
new file mode 100644
index 0000000..0baec8b
--- /dev/null
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/EncryptedFullBackupDataProcessor.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2019 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.backup.encryption.tasks;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+import static com.android.internal.util.Preconditions.checkState;
+
+import android.annotation.Nullable;
+import android.app.backup.BackupTransport;
+import android.content.Context;
+import android.util.Slog;
+
+import com.android.server.backup.encryption.FullBackupDataProcessor;
+import com.android.server.backup.encryption.StreamUtils;
+import com.android.server.backup.encryption.client.CryptoBackupServer;
+import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKey;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.security.SecureRandom;
+import java.util.Optional;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+
+/**
+ * Accepts backup data from a {@link InputStream} and passes it to the encrypted full data backup
+ * path.
+ */
+public class EncryptedFullBackupDataProcessor implements FullBackupDataProcessor {
+
+ private static final String TAG = "EncryptedFullBackupDP";
+
+ private final Context mContext;
+ private final ExecutorService mExecutorService;
+ private final CryptoBackupServer mCryptoBackupServer;
+ private final SecureRandom mSecureRandom;
+ private final RecoverableKeyStoreSecondaryKey mSecondaryKey;
+ private final String mPackageName;
+
+ @Nullable private InputStream mInputStream;
+ @Nullable private PipedOutputStream mOutputStream;
+ @Nullable private EncryptedFullBackupTask mBackupTask;
+ @Nullable private Future<Void> mBackupTaskFuture;
+ @Nullable private FullBackupCallbacks mFullBackupCallbacks;
+
+ public EncryptedFullBackupDataProcessor(
+ Context context,
+ ExecutorService executorService,
+ CryptoBackupServer cryptoBackupServer,
+ SecureRandom secureRandom,
+ RecoverableKeyStoreSecondaryKey secondaryKey,
+ String packageName) {
+ mContext = checkNotNull(context);
+ mExecutorService = checkNotNull(executorService);
+ mCryptoBackupServer = checkNotNull(cryptoBackupServer);
+ mSecureRandom = checkNotNull(secureRandom);
+ mSecondaryKey = checkNotNull(secondaryKey);
+ mPackageName = checkNotNull(packageName);
+ }
+
+ @Override
+ public boolean initiate(InputStream inputStream) throws IOException {
+ checkState(mBackupTask == null, "initiate() twice");
+
+ this.mInputStream = inputStream;
+ mOutputStream = new PipedOutputStream();
+
+ mBackupTask =
+ EncryptedFullBackupTask.newInstance(
+ mContext,
+ mCryptoBackupServer,
+ mSecureRandom,
+ mSecondaryKey,
+ mPackageName,
+ new PipedInputStream(mOutputStream));
+
+ return true;
+ }
+
+ @Override
+ public void start() {
+ checkState(mBackupTask != null, "start() before initiate()");
+ mBackupTaskFuture = mExecutorService.submit(mBackupTask);
+ }
+
+ @Override
+ public int pushData(int numBytes) {
+ checkState(
+ mBackupTaskFuture != null && mInputStream != null && mOutputStream != null,
+ "pushData() before start()");
+
+ // If the upload has failed then stop without pushing any more bytes.
+ if (mBackupTaskFuture.isDone()) {
+ Optional<Exception> exception = getTaskException();
+ Slog.e(TAG, "Encrypted upload failed", exception.orElse(null));
+ if (exception.isPresent()) {
+ reportNetworkFailureIfNecessary(exception.get());
+
+ if (exception.get().getCause() instanceof SizeQuotaExceededException) {
+ return BackupTransport.TRANSPORT_QUOTA_EXCEEDED;
+ }
+ }
+
+ return BackupTransport.TRANSPORT_ERROR;
+ }
+
+ try {
+ StreamUtils.copyStream(mInputStream, mOutputStream, numBytes);
+ } catch (IOException e) {
+ Slog.e(TAG, "IOException when processing backup", e);
+ return BackupTransport.TRANSPORT_ERROR;
+ }
+
+ return BackupTransport.TRANSPORT_OK;
+ }
+
+ @Override
+ public void cancel() {
+ checkState(mBackupTaskFuture != null && mBackupTask != null, "cancel() before start()");
+ mBackupTask.cancel();
+ closeStreams();
+ }
+
+ @Override
+ public int finish() {
+ checkState(mBackupTaskFuture != null, "finish() before start()");
+
+ // getTaskException() waits for the task to finish. We must close the streams first, which
+ // causes the task to finish, otherwise it will block forever.
+ closeStreams();
+ Optional<Exception> exception = getTaskException();
+
+ if (exception.isPresent()) {
+ Slog.e(TAG, "Exception during encrypted full backup", exception.get());
+ reportNetworkFailureIfNecessary(exception.get());
+
+ if (exception.get().getCause() instanceof SizeQuotaExceededException) {
+ return BackupTransport.TRANSPORT_QUOTA_EXCEEDED;
+ }
+ return BackupTransport.TRANSPORT_ERROR;
+
+ } else {
+ if (mFullBackupCallbacks != null) {
+ mFullBackupCallbacks.onSuccess();
+ }
+
+ return BackupTransport.TRANSPORT_OK;
+ }
+ }
+
+ private void closeStreams() {
+ StreamUtils.closeQuietly(mInputStream);
+ StreamUtils.closeQuietly(mOutputStream);
+ }
+
+ @Override
+ public void handleCheckSizeRejectionZeroBytes() {
+ cancel();
+ }
+
+ @Override
+ public void handleCheckSizeRejectionQuotaExceeded() {
+ cancel();
+ }
+
+ @Override
+ public void handleSendBytesQuotaExceeded() {
+ cancel();
+ }
+
+ @Override
+ public void attachCallbacks(FullBackupCallbacks fullBackupCallbacks) {
+ this.mFullBackupCallbacks = fullBackupCallbacks;
+ }
+
+ private void reportNetworkFailureIfNecessary(Exception exception) {
+ if (!(exception.getCause() instanceof SizeQuotaExceededException)
+ && mFullBackupCallbacks != null) {
+ mFullBackupCallbacks.onTransferFailed();
+ }
+ }
+
+ private Optional<Exception> getTaskException() {
+ if (mBackupTaskFuture != null) {
+ try {
+ mBackupTaskFuture.get();
+ } catch (InterruptedException | ExecutionException e) {
+ return Optional.of(e);
+ }
+ }
+ return Optional.empty();
+ }
+}
diff --git a/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/StreamUtilsTest.java b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/StreamUtilsTest.java
new file mode 100644
index 0000000..a95e87e
--- /dev/null
+++ b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/StreamUtilsTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2019 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.backup.encryption;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+@RunWith(RobolectricTestRunner.class)
+public class StreamUtilsTest {
+ private static final int SOURCE_DATA_SIZE = 64;
+
+ private byte[] mSourceData;
+
+ private InputStream mSource;
+ private ByteArrayOutputStream mDestination;
+
+ @Before
+ public void setUp() {
+ mSourceData = new byte[SOURCE_DATA_SIZE];
+ for (byte i = 0; i < SOURCE_DATA_SIZE; i++) {
+ mSourceData[i] = i;
+ }
+ mSource = new ByteArrayInputStream(mSourceData);
+ mDestination = new ByteArrayOutputStream();
+ }
+
+ @Test
+ public void copyStream_copiesAllBytesIfAsked() throws IOException {
+ StreamUtils.copyStream(mSource, mDestination, mSourceData.length);
+ assertOutputHasBytes(mSourceData.length);
+ }
+
+ @Test
+ public void copyStream_stopsShortIfAsked() throws IOException {
+ StreamUtils.copyStream(mSource, mDestination, mSourceData.length - 10);
+ assertOutputHasBytes(mSourceData.length - 10);
+ }
+
+ @Test
+ public void copyStream_stopsShortIfAskedToCopyMoreThanAvailable() throws IOException {
+ StreamUtils.copyStream(mSource, mDestination, mSourceData.length + 10);
+ assertOutputHasBytes(mSourceData.length);
+ }
+
+ private void assertOutputHasBytes(int count) {
+ byte[] output = mDestination.toByteArray();
+ assertThat(output.length).isEqualTo(count);
+ for (int i = 0; i < count; i++) {
+ assertThat(output[i]).isEqualTo(mSourceData[i]);
+ }
+ }
+}
diff --git a/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedFullBackupDataProcessorTest.java b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedFullBackupDataProcessorTest.java
new file mode 100644
index 0000000..675d03f
--- /dev/null
+++ b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedFullBackupDataProcessorTest.java
@@ -0,0 +1,387 @@
+/*
+ * Copyright (C) 2019 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.backup.encryption.tasks;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.testng.Assert.assertThrows;
+
+import android.annotation.Nullable;
+import android.app.backup.BackupTransport;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.server.backup.encryption.FullBackupDataProcessor;
+import com.android.server.backup.encryption.chunking.ProtoStore;
+import com.android.server.backup.encryption.client.CryptoBackupServer;
+import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKey;
+import com.android.server.backup.encryption.keys.TertiaryKeyManager;
+import com.android.server.backup.encryption.protos.nano.ChunksMetadataProto;
+import com.android.server.backup.encryption.testing.QueuingNonAutomaticExecutorService;
+
+import com.google.common.io.ByteStreams;
+import com.google.common.primitives.Bytes;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.GeneralSecurityException;
+import java.security.SecureRandom;
+
+import javax.crypto.spec.SecretKeySpec;
+
+@RunWith(RobolectricTestRunner.class)
+@Presubmit
+@Config(
+ shadows = {
+ EncryptedFullBackupDataProcessorTest.ShadowEncryptedFullBackupTask.class,
+ })
+public class EncryptedFullBackupDataProcessorTest {
+
+ private static final String KEY_GENERATOR_ALGORITHM = "AES";
+
+ private static final String TEST_PACKAGE = "com.example.app1";
+ private static final byte[] TEST_DATA_1 = {1, 2, 3, 4};
+ private static final byte[] TEST_DATA_2 = {5, 6, 7, 8};
+
+ private final RecoverableKeyStoreSecondaryKey mTestSecondaryKey =
+ new RecoverableKeyStoreSecondaryKey(
+ /*alias=*/ "test_key",
+ new SecretKeySpec(
+ new byte[] {
+ 1, 2, 3,
+ },
+ KEY_GENERATOR_ALGORITHM));
+
+ private QueuingNonAutomaticExecutorService mExecutorService;
+ private FullBackupDataProcessor mFullBackupDataProcessor;
+ @Mock private FullBackupDataProcessor.FullBackupCallbacks mFullBackupCallbacks;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mExecutorService = new QueuingNonAutomaticExecutorService();
+ mFullBackupDataProcessor =
+ new EncryptedFullBackupDataProcessor(
+ ApplicationProvider.getApplicationContext(),
+ mExecutorService,
+ mock(CryptoBackupServer.class),
+ new SecureRandom(),
+ mTestSecondaryKey,
+ TEST_PACKAGE);
+ }
+
+ @After
+ public void tearDown() {
+ ShadowEncryptedFullBackupTask.reset();
+ }
+
+ @Test
+ public void initiate_callTwice_throws() throws Exception {
+ mFullBackupDataProcessor.initiate(new ByteArrayInputStream(new byte[10]));
+
+ assertThrows(
+ IllegalStateException.class,
+ () -> mFullBackupDataProcessor.initiate(new ByteArrayInputStream(new byte[10])));
+ }
+
+ @Test
+ public void pushData_writesDataToTask() throws Exception {
+ byte[] inputData = Bytes.concat(TEST_DATA_1, TEST_DATA_2);
+
+ mFullBackupDataProcessor.initiate(new ByteArrayInputStream(inputData));
+ mFullBackupDataProcessor.start();
+ mFullBackupDataProcessor.pushData(TEST_DATA_1.length);
+ mFullBackupDataProcessor.pushData(TEST_DATA_2.length);
+ finishBackupTask();
+ mFullBackupDataProcessor.finish();
+
+ byte[] result = ByteStreams.toByteArray(ShadowEncryptedFullBackupTask.sInputStream);
+ assertThat(result).isEqualTo(Bytes.concat(TEST_DATA_1, TEST_DATA_2));
+ }
+
+ @Test
+ public void pushData_noError_returnsOk() throws Exception {
+ mFullBackupDataProcessor.initiate(new ByteArrayInputStream(TEST_DATA_1));
+ mFullBackupDataProcessor.start();
+ int result = mFullBackupDataProcessor.pushData(TEST_DATA_1.length);
+ finishBackupTask();
+ mFullBackupDataProcessor.finish();
+
+ assertThat(result).isEqualTo(BackupTransport.TRANSPORT_OK);
+ }
+
+ @Test
+ public void pushData_ioExceptionOnCopy_returnsError() throws Exception {
+ mFullBackupDataProcessor.initiate(new ByteArrayInputStream(TEST_DATA_1));
+ mFullBackupDataProcessor.start();
+
+ // Close the stream so there's an IO error when the processor tries to write to it.
+ ShadowEncryptedFullBackupTask.sInputStream.close();
+ int result = mFullBackupDataProcessor.pushData(TEST_DATA_1.length);
+
+ finishBackupTask();
+ mFullBackupDataProcessor.finish();
+
+ assertThat(result).isEqualTo(BackupTransport.TRANSPORT_ERROR);
+ }
+
+ @Test
+ public void pushData_exceptionDuringUpload_returnsError() throws Exception {
+ byte[] inputData = Bytes.concat(TEST_DATA_1, TEST_DATA_2);
+
+ mFullBackupDataProcessor.initiate(new ByteArrayInputStream(inputData));
+ mFullBackupDataProcessor.start();
+ mFullBackupDataProcessor.pushData(TEST_DATA_1.length);
+ finishBackupTaskWithException(new IOException("Test exception"));
+ int result = mFullBackupDataProcessor.pushData(TEST_DATA_2.length);
+
+ assertThat(result).isEqualTo(BackupTransport.TRANSPORT_ERROR);
+ }
+
+ @Test
+ public void pushData_quotaExceptionDuringUpload_doesNotLogAndReturnsQuotaExceeded()
+ throws Exception {
+ mFullBackupDataProcessor.attachCallbacks(mFullBackupCallbacks);
+ byte[] inputData = Bytes.concat(TEST_DATA_1, TEST_DATA_2);
+
+ mFullBackupDataProcessor.initiate(new ByteArrayInputStream(inputData));
+ mFullBackupDataProcessor.start();
+ mFullBackupDataProcessor.pushData(TEST_DATA_1.length);
+ finishBackupTaskWithException(new SizeQuotaExceededException());
+ int result = mFullBackupDataProcessor.pushData(TEST_DATA_2.length);
+
+ assertThat(result).isEqualTo(BackupTransport.TRANSPORT_QUOTA_EXCEEDED);
+
+ verify(mFullBackupCallbacks, never()).onSuccess();
+ verify(mFullBackupCallbacks, never())
+ .onTransferFailed(); // FullBackupSession will handle this.
+ }
+
+ @Test
+ public void pushData_unexpectedEncryptedBackup_logs() throws Exception {
+ byte[] inputData = Bytes.concat(TEST_DATA_1, TEST_DATA_2);
+
+ mFullBackupDataProcessor.initiate(new ByteArrayInputStream(inputData));
+ mFullBackupDataProcessor.start();
+ mFullBackupDataProcessor.pushData(TEST_DATA_1.length);
+ finishBackupTaskWithException(new GeneralSecurityException());
+ int result = mFullBackupDataProcessor.pushData(TEST_DATA_2.length);
+
+ assertThat(result).isEqualTo(BackupTransport.TRANSPORT_ERROR);
+ }
+
+ @Test
+ public void pushData_permanentExceptionDuringUpload_callsErrorCallback() throws Exception {
+ mFullBackupDataProcessor.attachCallbacks(mFullBackupCallbacks);
+ byte[] inputData = Bytes.concat(TEST_DATA_1, TEST_DATA_2);
+
+ mFullBackupDataProcessor.initiate(new ByteArrayInputStream(inputData));
+ mFullBackupDataProcessor.start();
+ mFullBackupDataProcessor.pushData(TEST_DATA_1.length);
+ finishBackupTaskWithException(new IOException());
+ mFullBackupDataProcessor.pushData(TEST_DATA_2.length);
+
+ verify(mFullBackupCallbacks, never()).onSuccess();
+ verify(mFullBackupCallbacks).onTransferFailed();
+ }
+
+ @Test
+ public void pushData_beforeInitiate_throws() {
+ assertThrows(
+ IllegalStateException.class,
+ () -> mFullBackupDataProcessor.pushData(/*numBytes=*/ 10));
+ }
+
+ @Test
+ public void cancel_cancelsTask() throws Exception {
+ mFullBackupDataProcessor.initiate(new ByteArrayInputStream(TEST_DATA_1));
+ mFullBackupDataProcessor.start();
+ mFullBackupDataProcessor.pushData(TEST_DATA_1.length);
+ mFullBackupDataProcessor.cancel();
+
+ assertThat(ShadowEncryptedFullBackupTask.sCancelled).isTrue();
+ }
+
+ @Test
+ public void cancel_beforeInitiate_throws() {
+ assertThrows(IllegalStateException.class, () -> mFullBackupDataProcessor.cancel());
+ }
+
+ @Test
+ public void finish_noException_returnsTransportOk() throws Exception {
+ mFullBackupDataProcessor.initiate(new ByteArrayInputStream(TEST_DATA_1));
+ mFullBackupDataProcessor.start();
+ mFullBackupDataProcessor.pushData(TEST_DATA_1.length);
+ finishBackupTask();
+ int result = mFullBackupDataProcessor.finish();
+
+ assertThat(result).isEqualTo(BackupTransport.TRANSPORT_OK);
+ }
+
+ @Test
+ public void finish_exceptionDuringUpload_returnsTransportError() throws Exception {
+ mFullBackupDataProcessor.initiate(new ByteArrayInputStream(TEST_DATA_1));
+ mFullBackupDataProcessor.start();
+ mFullBackupDataProcessor.pushData(TEST_DATA_1.length);
+ finishBackupTaskWithException(new IOException("Test exception"));
+ int result = mFullBackupDataProcessor.finish();
+
+ assertThat(result).isEqualTo(BackupTransport.TRANSPORT_ERROR);
+ }
+
+ @Test
+ public void finish_successfulBackup_callsSuccessCallback() throws Exception {
+ mFullBackupDataProcessor.attachCallbacks(mFullBackupCallbacks);
+
+ mFullBackupDataProcessor.initiate(new ByteArrayInputStream(TEST_DATA_1));
+ mFullBackupDataProcessor.start();
+ mFullBackupDataProcessor.pushData(TEST_DATA_1.length);
+ finishBackupTask();
+ mFullBackupDataProcessor.finish();
+
+ verify(mFullBackupCallbacks).onSuccess();
+ verify(mFullBackupCallbacks, never()).onTransferFailed();
+ }
+
+ @Test
+ public void finish_backupFailedWithPermanentError_callsErrorCallback() throws Exception {
+ mFullBackupDataProcessor.attachCallbacks(mFullBackupCallbacks);
+
+ mFullBackupDataProcessor.initiate(new ByteArrayInputStream(TEST_DATA_1));
+ mFullBackupDataProcessor.start();
+ mFullBackupDataProcessor.pushData(TEST_DATA_1.length);
+ finishBackupTaskWithException(new IOException());
+ mFullBackupDataProcessor.finish();
+
+ verify(mFullBackupCallbacks, never()).onSuccess();
+ verify(mFullBackupCallbacks).onTransferFailed();
+ }
+
+ @Test
+ public void finish_backupFailedWithQuotaException_doesNotCallbackAndReturnsQuotaExceeded()
+ throws Exception {
+ mFullBackupDataProcessor.attachCallbacks(mFullBackupCallbacks);
+
+ mFullBackupDataProcessor.initiate(new ByteArrayInputStream(TEST_DATA_1));
+ mFullBackupDataProcessor.start();
+ mFullBackupDataProcessor.pushData(TEST_DATA_1.length);
+ finishBackupTaskWithException(new SizeQuotaExceededException());
+ int result = mFullBackupDataProcessor.finish();
+
+ assertThat(result).isEqualTo(BackupTransport.TRANSPORT_QUOTA_EXCEEDED);
+ verify(mFullBackupCallbacks, never()).onSuccess();
+ verify(mFullBackupCallbacks, never())
+ .onTransferFailed(); // FullBackupSession will handle this.
+ }
+
+ @Test
+ public void finish_beforeInitiate_throws() {
+ assertThrows(IllegalStateException.class, () -> mFullBackupDataProcessor.finish());
+ }
+
+ @Test
+ public void handleCheckSizeRejectionZeroBytes_cancelsTask() throws Exception {
+ mFullBackupDataProcessor.initiate(new ByteArrayInputStream(new byte[10]));
+ mFullBackupDataProcessor.start();
+ mFullBackupDataProcessor.handleCheckSizeRejectionZeroBytes();
+
+ assertThat(ShadowEncryptedFullBackupTask.sCancelled).isTrue();
+ }
+
+ @Test
+ public void handleCheckSizeRejectionQuotaExceeded_cancelsTask() throws Exception {
+ mFullBackupDataProcessor.initiate(new ByteArrayInputStream(TEST_DATA_1));
+ mFullBackupDataProcessor.start();
+ mFullBackupDataProcessor.pushData(TEST_DATA_1.length);
+ mFullBackupDataProcessor.handleCheckSizeRejectionQuotaExceeded();
+
+ assertThat(ShadowEncryptedFullBackupTask.sCancelled).isTrue();
+ }
+
+ @Test
+ public void handleSendBytesQuotaExceeded_cancelsTask() throws Exception {
+ mFullBackupDataProcessor.initiate(new ByteArrayInputStream(TEST_DATA_1));
+ mFullBackupDataProcessor.start();
+ mFullBackupDataProcessor.pushData(TEST_DATA_1.length);
+ mFullBackupDataProcessor.handleSendBytesQuotaExceeded();
+
+ assertThat(ShadowEncryptedFullBackupTask.sCancelled).isTrue();
+ }
+
+ private void finishBackupTask() {
+ mExecutorService.runNext();
+ }
+
+ private void finishBackupTaskWithException(Exception exception) {
+ ShadowEncryptedFullBackupTask.sOnCallException = exception;
+ finishBackupTask();
+ }
+
+ @Implements(EncryptedFullBackupTask.class)
+ public static class ShadowEncryptedFullBackupTask {
+
+ private static InputStream sInputStream;
+ @Nullable private static Exception sOnCallException;
+ private static boolean sCancelled;
+
+ public void __constructor__(
+ ProtoStore<ChunksMetadataProto.ChunkListing> chunkListingStore,
+ TertiaryKeyManager tertiaryKeyManager,
+ EncryptedBackupTask task,
+ InputStream inputStream,
+ String packageName,
+ SecureRandom secureRandom) {
+ sInputStream = inputStream;
+ }
+
+ @Implementation
+ public Void call() throws Exception {
+ if (sOnCallException != null) {
+ throw sOnCallException;
+ }
+
+ return null;
+ }
+
+ @Implementation
+ public void cancel() {
+ sCancelled = true;
+ }
+
+ public static void reset() {
+ sOnCallException = null;
+ sCancelled = false;
+ }
+ }
+}
diff --git a/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/testing/QueuingNonAutomaticExecutorService.java b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/testing/QueuingNonAutomaticExecutorService.java
new file mode 100644
index 0000000..9d2272e
--- /dev/null
+++ b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/testing/QueuingNonAutomaticExecutorService.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2019 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.backup.encryption.testing;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.AbstractExecutorService;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * ExecutorService which needs to be stepped through the jobs in its' queue.
+ *
+ * <p>This is a deliberately simple implementation because it's only used in testing. The queued
+ * jobs are run on the main thread to eliminate any race condition bugs.
+ */
+public class QueuingNonAutomaticExecutorService extends AbstractExecutorService {
+
+ private List<Runnable> mWaitingJobs = new ArrayList<>();
+ private int mWaitingJobCount = 0;
+
+ @Override
+ public void shutdown() {
+ mWaitingJobCount = mWaitingJobs.size();
+ mWaitingJobs = null; // This will force an error if jobs are submitted after shutdown
+ }
+
+ @Override
+ public List<Runnable> shutdownNow() {
+ List<Runnable> queuedJobs = mWaitingJobs;
+ shutdown();
+ return queuedJobs;
+ }
+
+ @Override
+ public boolean isShutdown() {
+ return mWaitingJobs == null;
+ }
+
+ @Override
+ public boolean isTerminated() {
+ return mWaitingJobs == null && mWaitingJobCount == 0;
+ }
+
+ @Override
+ public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
+ long expiry = System.currentTimeMillis() + unit.toMillis(timeout);
+ for (Runnable job : mWaitingJobs) {
+ if (System.currentTimeMillis() > expiry) {
+ return false;
+ }
+
+ job.run();
+ }
+ return true;
+ }
+
+ @Override
+ public void execute(Runnable command) {
+ mWaitingJobs.add(command);
+ }
+
+ public void runNext() {
+ if (mWaitingJobs.isEmpty()) {
+ throw new IllegalStateException("Attempted to run jobs on an empty paused executor");
+ }
+
+ mWaitingJobs.remove(0).run();
+ }
+}
diff --git a/packages/CarSystemUI/res/layout/super_status_bar.xml b/packages/CarSystemUI/res/layout/super_status_bar.xml
index e1bcc2e..08d48bf 100644
--- a/packages/CarSystemUI/res/layout/super_status_bar.xml
+++ b/packages/CarSystemUI/res/layout/super_status_bar.xml
@@ -93,7 +93,7 @@
android:layout_height="match_parent"
android:visibility="invisible"/>
- <include layout="@layout/status_bar_expanded"
+ <ViewStub android:id="@+id/status_bar_expanded"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible"/>
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
index c205bb4..53a88a9 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
@@ -20,6 +20,7 @@
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.logging.NotifLog;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -34,8 +35,8 @@
public class CarNotificationEntryManager extends NotificationEntryManager {
@Inject
- public CarNotificationEntryManager(NotificationData notificationData) {
- super(notificationData);
+ public CarNotificationEntryManager(NotificationData notificationData, NotifLog notifLog) {
+ super(notificationData, notifLog);
}
@Override
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index cc6e842..681d8f5 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -108,6 +108,7 @@
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.logging.NotifLog;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.phone.AutoHideController;
@@ -296,7 +297,8 @@
NotificationListener notificationListener,
ConfigurationController configurationController,
StatusBarWindowController statusBarWindowController,
- StatusBarWindowViewController.Builder statusBarWindowViewControllerBuild) {
+ StatusBarWindowViewController.Builder statusBarWindowViewControllerBuild,
+ NotifLog notifLog) {
super(
lightBarController,
autoHideController,
@@ -350,7 +352,8 @@
notificationListener,
configurationController,
statusBarWindowController,
- statusBarWindowViewControllerBuild);
+ statusBarWindowViewControllerBuild,
+ notifLog);
mNavigationBarController = navigationBarController;
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 67062b7..8c97057 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -107,9 +107,6 @@
Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD,
Settings.Secure.FACE_UNLOCK_APP_ENABLED,
Settings.Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION,
- Settings.Secure.ASSIST_GESTURE_ENABLED,
- Settings.Secure.ASSIST_GESTURE_SILENCE_ALERTS_ENABLED,
- Settings.Secure.ASSIST_GESTURE_WAKE_ENABLED,
Settings.Secure.VR_DISPLAY_MODE,
Settings.Secure.NOTIFICATION_BADGING,
Settings.Secure.NOTIFICATION_DISMISS_RTL,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index c05c4cdf..de6a3a8 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -24,7 +24,6 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
import android.content.pm.Signature;
import android.os.Binder;
import android.os.Build;
@@ -49,7 +48,6 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ArrayUtils;
-import com.android.server.LocalServices;
import libcore.io.IoUtils;
@@ -1175,9 +1173,8 @@
}
// If SetupWizard, done.
- PackageManagerInternal packageManagerInternal = LocalServices.getService(
- PackageManagerInternal.class);
- if (packageName.equals(packageManagerInternal.getSetupWizardPackageName())) {
+ String setupWizPackage = context.getPackageManager().getSetupWizardPackageName();
+ if (packageName.equals(setupWizPackage)) {
sSystemUids.put(uid, uid);
return true;
}
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index ebb9e86..8437eae 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -594,7 +594,10 @@
Settings.Secure.ANR_SHOW_BACKGROUND,
Settings.Secure.ASSISTANT,
Settings.Secure.ASSIST_DISCLOSURE_ENABLED,
+ Settings.Secure.ASSIST_GESTURE_ENABLED,
Settings.Secure.ASSIST_GESTURE_SENSITIVITY,
+ Settings.Secure.ASSIST_GESTURE_WAKE_ENABLED,
+ Settings.Secure.ASSIST_GESTURE_SILENCE_ALERTS_ENABLED,
Settings.Secure.ASSIST_GESTURE_SETUP_COMPLETE,
Settings.Secure.ASSIST_SCREENSHOT_ENABLED,
Settings.Secure.ASSIST_STRUCTURE_ENABLED,
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index d71d009..a097249 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -381,6 +381,7 @@
private final class BugreportCallbackImpl extends BugreportCallback {
+ @GuardedBy("mLock")
private final BugreportInfo mInfo;
BugreportCallbackImpl(BugreportInfo info) {
@@ -389,10 +390,12 @@
@Override
public void onProgress(float progress) {
- if (progress == 0) {
- trackInfoWithId();
+ synchronized (mLock) {
+ if (progress == 0) {
+ trackInfoWithIdLocked();
+ }
+ checkProgressUpdatedLocked(mInfo, (int) progress);
}
- checkProgressUpdated(mInfo, (int) progress);
}
/**
@@ -401,18 +404,21 @@
*/
@Override
public void onError(@BugreportErrorCode int errorCode) {
- trackInfoWithId();
- stopProgress(mInfo.id);
+ synchronized (mLock) {
+ trackInfoWithIdLocked();
+ stopProgressLocked(mInfo.id);
+ }
Log.e(TAG, "Bugreport API callback onError() errorCode = " + errorCode);
return;
}
@Override
public void onFinished() {
- // TODO: Make all callback functions lock protected.
mInfo.renameBugreportFile();
mInfo.renameScreenshots(mScreenshotsDir);
- sendBugreportFinishedBroadcast();
+ synchronized (mLock) {
+ sendBugreportFinishedBroadcastLocked();
+ }
}
/**
@@ -421,7 +427,8 @@
* when dumpstate calls one of the callback functions (onProgress, onFinished, onError)
* after the id has been incremented.
*/
- private void trackInfoWithId() {
+ @GuardedBy("mLock")
+ private void trackInfoWithIdLocked() {
final int id = SystemProperties.getInt(PROPERTY_LAST_ID, 1);
if (mBugreportInfos.get(id) == null) {
mInfo.id = id;
@@ -430,74 +437,75 @@
return;
}
- private void sendBugreportFinishedBroadcast() {
+ @GuardedBy("mLock")
+ private void sendBugreportFinishedBroadcastLocked() {
final String bugreportFilePath = mInfo.bugreportFile.getAbsolutePath();
if (mInfo.bugreportFile.length() == 0) {
Log.e(TAG, "Bugreport file empty. File path = " + bugreportFilePath);
return;
}
if (mInfo.type == BugreportParams.BUGREPORT_MODE_REMOTE) {
- sendRemoteBugreportFinishedBroadcast(bugreportFilePath, mInfo.bugreportFile);
+ sendRemoteBugreportFinishedBroadcast(mContext, bugreportFilePath,
+ mInfo.bugreportFile);
} else {
- trackInfoWithId();
+ trackInfoWithIdLocked();
cleanupOldFiles(MIN_KEEP_COUNT, MIN_KEEP_AGE);
final Intent intent = new Intent(INTENT_BUGREPORT_FINISHED);
intent.putExtra(EXTRA_BUGREPORT, bugreportFilePath);
- addScreenshotToIntent(intent);
+ addScreenshotToIntent(intent, mInfo);
mContext.sendBroadcast(intent, android.Manifest.permission.DUMP);
onBugreportFinished(mInfo.id);
}
}
+ }
- private void sendRemoteBugreportFinishedBroadcast(String bugreportFileName,
- File bugreportFile) {
- cleanupOldFiles(REMOTE_BUGREPORT_FILES_AMOUNT, REMOTE_MIN_KEEP_AGE);
- final Intent intent = new Intent(DevicePolicyManager.ACTION_REMOTE_BUGREPORT_DISPATCH);
- final Uri bugreportUri = getUri(mContext, bugreportFile);
- final String bugreportHash = generateFileHash(bugreportFileName);
- if (bugreportHash == null) {
- Log.e(TAG, "Error generating file hash for remote bugreport");
- return;
- }
- intent.setDataAndType(bugreportUri, BUGREPORT_MIMETYPE);
- intent.putExtra(DevicePolicyManager.EXTRA_REMOTE_BUGREPORT_HASH, bugreportHash);
- intent.putExtra(EXTRA_BUGREPORT, bugreportFileName);
- mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM,
- android.Manifest.permission.DUMP);
+ private static void sendRemoteBugreportFinishedBroadcast(Context context,
+ String bugreportFileName, File bugreportFile) {
+ cleanupOldFiles(REMOTE_BUGREPORT_FILES_AMOUNT, REMOTE_MIN_KEEP_AGE);
+ final Intent intent = new Intent(DevicePolicyManager.ACTION_REMOTE_BUGREPORT_DISPATCH);
+ final Uri bugreportUri = getUri(context, bugreportFile);
+ final String bugreportHash = generateFileHash(bugreportFileName);
+ if (bugreportHash == null) {
+ Log.e(TAG, "Error generating file hash for remote bugreport");
}
+ intent.setDataAndType(bugreportUri, BUGREPORT_MIMETYPE);
+ intent.putExtra(DevicePolicyManager.EXTRA_REMOTE_BUGREPORT_HASH, bugreportHash);
+ intent.putExtra(EXTRA_BUGREPORT, bugreportFileName);
+ context.sendBroadcastAsUser(intent, UserHandle.SYSTEM,
+ android.Manifest.permission.DUMP);
+ }
- private void addScreenshotToIntent(Intent intent) {
- final File screenshotFile = mInfo.screenshotFiles.isEmpty()
- ? null : mInfo.screenshotFiles.get(0);
- if (screenshotFile != null && screenshotFile.length() > 0) {
- final String screenshotFilePath = screenshotFile.getAbsolutePath();
- intent.putExtra(EXTRA_SCREENSHOT, screenshotFilePath);
- }
- return;
+ private static void addScreenshotToIntent(Intent intent, BugreportInfo info) {
+ final String screenshotFileName = info.name + ".png";
+ final File screenshotFile = new File(BUGREPORT_DIR, screenshotFileName);
+ final String screenshotFilePath = screenshotFile.getAbsolutePath();
+ if (screenshotFile.length() > 0) {
+ intent.putExtra(EXTRA_SCREENSHOT, screenshotFilePath);
}
+ return;
+ }
- private String generateFileHash(String fileName) {
- String fileHash = null;
- try {
- MessageDigest md = MessageDigest.getInstance("SHA-256");
- FileInputStream input = new FileInputStream(new File(fileName));
- byte[] buffer = new byte[65536];
- int size;
- while ((size = input.read(buffer)) > 0) {
- md.update(buffer, 0, size);
- }
- input.close();
- byte[] hashBytes = md.digest();
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < hashBytes.length; i++) {
- sb.append(String.format("%02x", hashBytes[i]));
- }
- fileHash = sb.toString();
- } catch (IOException | NoSuchAlgorithmException e) {
- Log.e(TAG, "generating file hash for bugreport file failed " + fileName, e);
+ private static String generateFileHash(String fileName) {
+ String fileHash = null;
+ try {
+ MessageDigest md = MessageDigest.getInstance("SHA-256");
+ FileInputStream input = new FileInputStream(new File(fileName));
+ byte[] buffer = new byte[65536];
+ int size;
+ while ((size = input.read(buffer)) > 0) {
+ md.update(buffer, 0, size);
}
- return fileHash;
+ input.close();
+ byte[] hashBytes = md.digest();
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < hashBytes.length; i++) {
+ sb.append(String.format("%02x", hashBytes[i]));
+ }
+ fileHash = sb.toString();
+ } catch (IOException | NoSuchAlgorithmException e) {
+ Log.e(TAG, "generating file hash for bugreport file failed " + fileName, e);
}
+ return fileHash;
}
static void cleanupOldFiles(final int minCount, final long minAge) {
@@ -852,7 +860,8 @@
/**
* Finalizes the progress on a given bugreport and cancel its notification.
*/
- private void stopProgress(int id) {
+ @GuardedBy("mLock")
+ private void stopProgressLocked(int id) {
if (mBugreportInfos.indexOfKey(id) < 0) {
Log.w(TAG, "ID not watched: " + id);
} else {
@@ -883,7 +892,9 @@
}
deleteScreenshots(info);
}
- stopProgress(id);
+ synchronized (mLock) {
+ stopProgressLocked(id);
+ }
}
/**
@@ -1178,7 +1189,9 @@
if (!info.bugreportFile.exists() || !info.bugreportFile.canRead()) {
Log.e(TAG, "Could not read bugreport file " + info.bugreportFile);
Toast.makeText(context, R.string.bugreport_unreadable_text, Toast.LENGTH_LONG).show();
- stopProgress(info.id);
+ synchronized (mLock) {
+ stopProgressLocked(info.id);
+ }
return;
}
@@ -1290,7 +1303,9 @@
final Intent sendIntent = buildSendIntent(mContext, info);
if (sendIntent == null) {
Log.w(TAG, "Stopping progres on ID " + id + " because share intent could not be built");
- stopProgress(id);
+ synchronized (mLock) {
+ stopProgressLocked(id);
+ }
return;
}
@@ -1313,9 +1328,10 @@
} else {
mContext.startActivity(notifIntent);
}
-
- // ... and stop watching this process.
- stopProgress(id);
+ synchronized (mLock) {
+ // ... and stop watching this process.
+ stopProgressLocked(id);
+ }
}
static void sendShareIntent(Context context, Intent intent) {
@@ -2361,14 +2377,18 @@
// The right, long-term solution is to provide an onFinished() callback
// on IDumpstateListener and call it instead of using a broadcast.
Log.w(TAG, "Dumpstate process died:\n" + info);
- stopProgress(info.id);
+ synchronized (mLock) {
+ stopProgressLocked(info.id);
+ }
}
token.asBinder().unlinkToDeath(this, 0);
}
@Override
public void onProgress(int progress) throws RemoteException {
- checkProgressUpdated(info, progress);
+ synchronized (mLock) {
+ checkProgressUpdatedLocked(info, progress);
+ }
}
@Override
@@ -2387,7 +2407,8 @@
}
- private void checkProgressUpdated(BugreportInfo info, int progress) {
+ @GuardedBy("mLock")
+ private void checkProgressUpdatedLocked(BugreportInfo info, int progress) {
if (progress > CAPPED_PROGRESS) {
progress = CAPPED_PROGRESS;
}
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 403e894..b288eb7 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -243,6 +243,9 @@
<!-- Permission to change the display color -->
<uses-permission android:name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS" />
+ <!-- Query all packages on device on R+ -->
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
+
<protected-broadcast android:name="com.android.settingslib.action.REGISTER_SLICE_RECEIVER" />
<protected-broadcast android:name="com.android.settingslib.action.UNREGISTER_SLICE_RECEIVER" />
<protected-broadcast android:name="com.android.settings.flashlight.action.FLASHLIGHT_CHANGED" />
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
index 5ddf89c..6186589 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
@@ -17,6 +17,7 @@
package com.android.systemui.shared.system;
import android.app.ActivityManager.RunningTaskInfo;
+import android.app.ITaskStackListener;
import android.content.ComponentName;
import android.os.IBinder;
import android.os.UserHandle;
@@ -106,6 +107,9 @@
*/
public void onRecentTaskListUpdated() { }
+ /** @see ITaskStackListener#onRecentTaskListFrozenChanged(boolean) */
+ public void onRecentTaskListFrozenChanged(boolean frozen) { }
+
/**
* Checks that the current user matches the process. Since
* {@link android.app.ITaskStackListener} is not multi-user aware, handlers of
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
index 820057a..8d823ca 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
@@ -224,6 +224,12 @@
mHandler.obtainMessage(H.ON_TASK_LIST_UPDATED).sendToTarget();
}
+ @Override
+ public void onRecentTaskListFrozenChanged(boolean frozen) {
+ mHandler.obtainMessage(H.ON_TASK_LIST_FROZEN_UNFROZEN, frozen ? 1 : 0, 0 /* unused */)
+ .sendToTarget();
+ }
+
private final class H extends Handler {
private static final int ON_TASK_STACK_CHANGED = 1;
private static final int ON_TASK_SNAPSHOT_CHANGED = 2;
@@ -247,6 +253,7 @@
private static final int ON_TASK_DISPLAY_CHANGED = 20;
private static final int ON_TASK_LIST_UPDATED = 21;
private static final int ON_SINGLE_TASK_DISPLAY_EMPTY = 22;
+ private static final int ON_TASK_LIST_FROZEN_UNFROZEN = 23;
public H(Looper looper) {
@@ -408,6 +415,12 @@
}
break;
}
+ case ON_TASK_LIST_FROZEN_UNFROZEN: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onRecentTaskListFrozenChanged(msg.arg1 != 0);
+ }
+ break;
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index dc8ee16..9bcccbc 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -118,12 +118,14 @@
import javax.inject.Inject;
import javax.inject.Named;
+import javax.inject.Singleton;
/**
* Watches for updates that may be interesting to the keyguard, and provides
* the up to date information as well as a registration for callbacks that care
* to be updated.
*/
+@Singleton
public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
private static final String TAG = "KeyguardUpdateMonitor";
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleViewController.java b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleViewController.java
index f9ffb80..5010f31 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleViewController.java
@@ -43,6 +43,7 @@
private Handler mHandler;
private CornerHandleView mAssistHintLeft;
private CornerHandleView mAssistHintRight;
+ private int mBottomOffset;
@VisibleForTesting
boolean mAssistHintVisible;
@@ -62,6 +63,23 @@
}
/**
+ * Set the bottom offset.
+ *
+ * @param bottomOffset the bottom offset to translate.
+ */
+ public void setBottomOffset(int bottomOffset) {
+ if (mBottomOffset != bottomOffset) {
+ mBottomOffset = bottomOffset;
+ if (mAssistHintVisible) {
+ // If assist handles are visible, hide them without animation and then make them
+ // show once again (with corrected bottom offset).
+ hideAssistHandles();
+ setAssistHintVisible(true);
+ }
+ }
+ }
+
+ /**
* Controls the visibility of the assist gesture handles.
*
* @param visible whether the handles should be shown
@@ -126,7 +144,8 @@
xDirection * translationStart * view.getWidth(),
xDirection * translationEnd * view.getWidth());
Animator translateY = ObjectAnimator.ofFloat(view, View.TRANSLATION_Y,
- translationStart * view.getHeight(), translationEnd * view.getHeight());
+ translationStart * view.getHeight() + mBottomOffset,
+ translationEnd * view.getHeight() + mBottomOffset);
AnimatorSet set = new AnimatorSet();
set.play(scaleX).with(scaleY);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 8240345..cc548d0 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -569,7 +569,8 @@
if (mStackView != null) {
mStackView.updateDotVisibility(entry.key);
}
- mNotificationEntryManager.updateNotifications();
+ mNotificationEntryManager.updateNotifications(
+ "BubbleController.onNotificationRemoveRequested");
return true;
} else if (!userRemovedNotif && entry != null) {
// This wasn't a user removal so we should remove the bubble as well
@@ -609,7 +610,8 @@
mBubbleData.addSummaryToSuppress(summary.notification.getGroupKey(),
summary.key);
// Tell shade to update for the suppression
- mNotificationEntryManager.updateNotifications();
+ mNotificationEntryManager.updateNotifications(
+ "BubbleController.handleSummaryRemovalInterception");
}
return !isAutogroupSummary;
} else {
@@ -760,7 +762,8 @@
mStackView.setExpanded(true);
}
- mNotificationEntryManager.updateNotifications();
+ mNotificationEntryManager.updateNotifications(
+ "BubbleData.Listener.applyUpdate");
updateStack();
if (DEBUG_BUBBLE_CONTROLLER) {
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
index 1e0a9f1..176676f 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
@@ -152,6 +152,20 @@
private final Runnable mStartListeningRunnable = new Runnable() {
@Override
public void run() {
+ if (mListening) {
+ return;
+ }
+ mListening = true;
+
+ if (mVrManager != null) {
+ try {
+ mVrManager.registerListener(mVrStateCallbacks);
+ mIsVrModeEnabled = mVrManager.getVrModeState();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to register VR mode state listener: ", e);
+ }
+ }
+
mBrightnessObserver.startObserving();
mUserTracker.startTracking();
@@ -167,6 +181,19 @@
private final Runnable mStopListeningRunnable = new Runnable() {
@Override
public void run() {
+ if (!mListening) {
+ return;
+ }
+ mListening = false;
+
+ if (mVrManager != null) {
+ try {
+ mVrManager.unregisterListener(mVrStateCallbacks);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to unregister VR mode state listener: ", e);
+ }
+ }
+
mBrightnessObserver.stopObserving();
mUserTracker.stopTracking();
@@ -297,39 +324,12 @@
}
public void registerCallbacks() {
- if (mListening) {
- return;
- }
-
- if (mVrManager != null) {
- try {
- mVrManager.registerListener(mVrStateCallbacks);
- mIsVrModeEnabled = mVrManager.getVrModeState();
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to register VR mode state listener: ", e);
- }
- }
-
mBackgroundHandler.post(mStartListeningRunnable);
- mListening = true;
}
/** Unregister all call backs, both to and from the controller */
public void unregisterCallbacks() {
- if (!mListening) {
- return;
- }
-
- if (mVrManager != null) {
- try {
- mVrManager.unregisterListener(mVrStateCallbacks);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to unregister VR mode state listener: ", e);
- }
- }
-
mBackgroundHandler.post(mStopListeningRunnable);
- mListening = false;
mControlValueInitialized = false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
index 6c0f90a..c4de2d3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
@@ -127,7 +127,7 @@
mEntryManager.removeNotification(key, rankingMap, UNDEFINED_DISMISS_REASON);
} else {
mEntryManager.getNotificationData()
- .updateRanking(rankingMap);
+ .updateRanking(rankingMap, "onNotificationPosted");
}
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 4ba1114..6ffea79 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -106,7 +106,7 @@
isCurrentProfile(getSendingUserId())) {
mUsersAllowingPrivateNotifications.clear();
updateLockscreenNotificationSetting();
- getEntryManager().updateNotifications();
+ getEntryManager().updateNotifications("ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED");
}
}
};
@@ -124,7 +124,7 @@
updatePublicMode();
// The filtering needs to happen before the update call below in order to make sure
// the presenter has the updated notifications from the new user
- getEntryManager().getNotificationData().filterAndSort();
+ getEntryManager().getNotificationData().filterAndSort("user switched");
mPresenter.onUserSwitched(mCurrentUserId);
for (UserChangedListener listener : mListeners) {
@@ -205,7 +205,8 @@
mUsersAllowingNotifications.clear();
// ... and refresh all the notifications
updateLockscreenNotificationSetting();
- getEntryManager().updateNotifications();
+ getEntryManager().updateNotifications("LOCK_SCREEN_SHOW_NOTIFICATIONS,"
+ + " or LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS change");
}
};
@@ -214,7 +215,8 @@
public void onChange(boolean selfChange) {
updateLockscreenNotificationSetting();
if (mDeviceProvisionedController.isDeviceProvisioned()) {
- getEntryManager().updateNotifications();
+ getEntryManager().updateNotifications("LOCK_SCREEN_ALLOW_REMOTE_INPUT"
+ + " or ZEN_MODE change");
}
}
};
@@ -532,7 +534,7 @@
setLockscreenPublicMode(isProfilePublic, userId);
mUsersWithSeperateWorkChallenge.put(userId, needsSeparateChallenge);
}
- getEntryManager().updateNotifications();
+ getEntryManager().updateNotifications("NotificationLockscreenUserManager.updatePublicMode");
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index c50fb3d..3616b54 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -361,7 +361,7 @@
}
if (metaDataChanged) {
- mEntryManager.updateNotifications();
+ mEntryManager.updateNotifications("NotificationMediaManager - metaDataChanged");
}
dispatchUpdateMediaMetaData(metaDataChanged, true /* allowEnterAnimation */);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index 148a1a8..01c79b3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -40,6 +40,8 @@
import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationRowBinder;
+import com.android.systemui.statusbar.notification.logging.NotifEvent;
+import com.android.systemui.statusbar.notification.logging.NotifLog;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationContentInflater;
import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag;
@@ -92,6 +94,7 @@
private NotificationListenerService.RankingMap mLatestRankingMap;
@VisibleForTesting
protected NotificationData mNotificationData;
+ private NotifLog mNotifLog;
@VisibleForTesting
final ArrayList<NotificationLifetimeExtender> mNotificationLifetimeExtenders
@@ -123,8 +126,9 @@
}
@Inject
- public NotificationEntryManager(NotificationData notificationData) {
+ public NotificationEntryManager(NotificationData notificationData, NotifLog notifLog) {
mNotificationData = notificationData;
+ mNotifLog = notifLog;
}
/** Adds a {@link NotificationEntryListener}. */
@@ -178,7 +182,7 @@
@Override
public void onReorderingAllowed() {
- updateNotifications();
+ updateNotifications("reordering is now allowed");
}
/**
@@ -203,15 +207,19 @@
return NotificationVisibility.obtain(key, rank, count, true, location);
}
- private void abortExistingInflation(String key) {
+ private void abortExistingInflation(String key, String reason) {
if (mPendingNotifications.containsKey(key)) {
NotificationEntry entry = mPendingNotifications.get(key);
entry.abortTask();
mPendingNotifications.remove(key);
+ mNotifLog.log(NotifEvent.INFLATION_ABORTED, entry.sbn(), null,
+ "PendingNotification aborted. " + reason);
}
NotificationEntry addedEntry = mNotificationData.get(key);
if (addedEntry != null) {
addedEntry.abortTask();
+ mNotifLog.log(NotifEvent.INFLATION_ABORTED, addedEntry.sbn(),
+ null, reason);
}
}
@@ -247,7 +255,7 @@
for (NotificationEntryListener listener : mNotificationEntryListeners) {
listener.onBeforeNotificationAdded(entry);
}
- updateNotifications();
+ updateNotifications("onAsyncInflationFinished");
for (NotificationEntryListener listener : mNotificationEntryListeners) {
listener.onNotificationAdded(entry);
}
@@ -276,7 +284,8 @@
if (mRemoveInterceptor != null
&& mRemoveInterceptor.onNotificationRemoveRequested(key, reason)) {
- // Remove intercepted; skip
+ // Remove intercepted; log and skip
+ mNotifLog.log(NotifEvent.REMOVE_INTERCEPTED);
return;
}
@@ -291,13 +300,17 @@
if (extender.shouldExtendLifetimeForPendingNotification(pendingEntry)) {
extendLifetime(pendingEntry, extender);
lifetimeExtended = true;
+ mNotifLog.log(
+ NotifEvent.LIFETIME_EXTENDED,
+ pendingEntry.sbn(),
+ "pendingEntry extendedBy=" + extender.toString());
}
}
}
}
if (!lifetimeExtended) {
- abortExistingInflation(key);
+ abortExistingInflation(key, "removeNotification");
}
if (entry != null) {
@@ -310,6 +323,10 @@
mLatestRankingMap = ranking;
extendLifetime(entry, extender);
lifetimeExtended = true;
+ mNotifLog.log(
+ NotifEvent.LIFETIME_EXTENDED,
+ entry.sbn(),
+ "entry extendedBy=" + extender.toString());
break;
}
}
@@ -329,10 +346,12 @@
handleGroupSummaryRemoved(key);
mNotificationData.remove(key, ranking);
- updateNotifications();
+ updateNotifications("removeNotificationInternal");
Dependency.get(LeakDetector.class).trackGarbage(entry);
removedByUser |= entryDismissed;
+ mNotifLog.log(NotifEvent.NOTIF_REMOVED, entry.sbn(),
+ "removedByUser=" + removedByUser);
for (NotificationEntryListener listener : mNotificationEntryListeners) {
listener.onEntryRemoved(entry, visibility, removedByUser);
}
@@ -389,7 +408,7 @@
Log.d(TAG, "addNotification key=" + key);
}
- mNotificationData.updateRanking(rankingMap);
+ mNotificationData.updateRanking(rankingMap, "addNotificationInternal");
Ranking ranking = new Ranking();
rankingMap.getRanking(key, ranking);
@@ -400,9 +419,9 @@
requireBinder().inflateViews(entry, () -> performRemoveNotification(notification,
REASON_CANCEL));
- abortExistingInflation(key);
-
+ abortExistingInflation(key, "addNotification");
mPendingNotifications.put(key, entry);
+ mNotifLog.log(NotifEvent.NOTIF_ADDED, entry.sbn());
for (NotificationEntryListener listener : mNotificationEntryListeners) {
listener.onPendingEntryAdded(entry);
}
@@ -423,7 +442,7 @@
if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")");
final String key = notification.getKey();
- abortExistingInflation(key);
+ abortExistingInflation(key, "updateNotification");
NotificationEntry entry = mNotificationData.get(key);
if (entry == null) {
return;
@@ -433,15 +452,15 @@
// to keep its lifetime extended.
cancelLifetimeExtension(entry);
- mNotificationData.update(entry, ranking, notification);
-
+ mNotificationData.update(entry, ranking, notification, "updateNotificationInternal");
+ mNotifLog.log(NotifEvent.NOTIF_UPDATED, entry.sbn(), entry.ranking());
for (NotificationEntryListener listener : mNotificationEntryListeners) {
listener.onPreEntryUpdated(entry);
}
requireBinder().inflateViews(entry, () -> performRemoveNotification(notification,
REASON_CANCEL));
- updateNotifications();
+ updateNotifications("updateNotificationInternal");
if (DEBUG) {
// Is this for you?
@@ -465,8 +484,12 @@
}
}
- public void updateNotifications() {
- mNotificationData.filterAndSort();
+ /**
+ * Update the notifications
+ * @param reason why the notifications are updating
+ */
+ public void updateNotifications(String reason) {
+ mNotificationData.filterAndSort(reason);
if (mPresenter != null) {
mPresenter.updateNotificationViews();
}
@@ -489,7 +512,7 @@
}
// Populate notification entries from the new rankings.
- mNotificationData.updateRanking(rankingMap);
+ mNotificationData.updateRanking(rankingMap, "updateNotificationRanking");
updateRankingOfPendingNotifications(rankingMap);
// By comparing the old and new UI adjustments, reinflate the view accordingly.
@@ -501,7 +524,7 @@
NotificationUiAdjustment.extractFromNotificationEntry(entry));
}
- updateNotifications();
+ updateNotifications("updateNotificationRanking");
for (NotificationEntryListener listener : mNotificationEntryListeners) {
listener.onNotificationRankingUpdated(rankingMap);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java
index 769cbb7..970cbf9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java
@@ -81,7 +81,7 @@
new DeviceProvisionedListener() {
@Override
public void onDeviceProvisionedChanged() {
- mEntryManager.updateNotifications();
+ mEntryManager.updateNotifications("device provisioned changed");
}
};
@@ -106,7 +106,7 @@
if (foregroundKey != null) {
mEntryManager
.getNotificationData().updateAppOp(appOp, uid, pkg, foregroundKey, showIcon);
- mEntryManager.updateNotifications();
+ mEntryManager.updateNotifications("app opp changed pkg=" + pkg);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
index cf0fbbb..a98fa66 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
@@ -35,6 +35,8 @@
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.notification.NotificationFilter;
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
+import com.android.systemui.statusbar.notification.logging.NotifEvent;
+import com.android.systemui.statusbar.notification.logging.NotifLog;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -73,10 +75,13 @@
private RankingMap mRankingMap;
private final Ranking mTmpRanking = new Ranking();
private final boolean mUsePeopleFiltering;
+ private final NotifLog mNotifLog;
@Inject
- public NotificationData(NotificationSectionsFeatureManager sectionsFeatureManager) {
+ public NotificationData(NotificationSectionsFeatureManager sectionsFeatureManager,
+ NotifLog notifLog) {
mUsePeopleFiltering = sectionsFeatureManager.isFilteringEnabled();
+ mNotifLog = notifLog;
}
public void setHeadsUpManager(HeadsUpManager headsUpManager) {
@@ -179,7 +184,7 @@
}
mGroupManager.onEntryAdded(entry);
- updateRankingAndSort(mRankingMap);
+ updateRankingAndSort(mRankingMap, "addEntry=" + entry.sbn());
}
public NotificationEntry remove(String key, RankingMap ranking) {
@@ -189,7 +194,7 @@
}
if (removed == null) return null;
mGroupManager.onEntryRemoved(removed);
- updateRankingAndSort(ranking);
+ updateRankingAndSort(ranking, "removeEntry=" + removed.sbn());
return removed;
}
@@ -197,15 +202,19 @@
public void update(
NotificationEntry entry,
RankingMap ranking,
- StatusBarNotification notification) {
- updateRanking(ranking);
+ StatusBarNotification notification,
+ String reason) {
+ updateRanking(ranking, reason);
final StatusBarNotification oldNotification = entry.notification;
entry.setNotification(notification);
mGroupManager.onEntryUpdated(entry, oldNotification);
}
- public void updateRanking(RankingMap ranking) {
- updateRankingAndSort(ranking);
+ /**
+ * Update ranking and trigger a re-sort
+ */
+ public void updateRanking(RankingMap ranking, String reason) {
+ updateRankingAndSort(ranking, reason);
}
public void updateAppOp(int appOp, int uid, String pkg, String key, boolean showIcon) {
@@ -352,7 +361,7 @@
return false;
}
- private void updateRankingAndSort(RankingMap rankingMap) {
+ private void updateRankingAndSort(RankingMap rankingMap, String reason) {
if (rankingMap != null) {
mRankingMap = rankingMap;
synchronized (mEntries) {
@@ -375,7 +384,7 @@
}
}
}
- filterAndSort();
+ filterAndSort(reason);
}
/**
@@ -393,7 +402,11 @@
// TODO: This should not be public. Instead the Environment should notify this class when
// anything changed, and this class should call back the UI so it updates itself.
- public void filterAndSort() {
+ /**
+ * Filters and sorts the list of notification entries
+ */
+ public void filterAndSort(String reason) {
+ mNotifLog.log(NotifEvent.FILTER_AND_SORT, reason);
mSortedAndFiltered.clear();
synchronized (mEntries) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
index 60cf995..e5571b6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
@@ -41,6 +41,8 @@
import com.android.systemui.statusbar.notification.InflationException;
import com.android.systemui.statusbar.notification.NotificationClicker;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
+import com.android.systemui.statusbar.notification.logging.NotifEvent;
+import com.android.systemui.statusbar.notification.logging.NotifLog;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationContentInflater;
@@ -72,6 +74,7 @@
private final boolean mAllowLongPress;
private final KeyguardBypassController mKeyguardBypassController;
private final StatusBarStateController mStatusBarStateController;
+ private final NotifLog mNotifLog;
private NotificationRemoteInputManager mRemoteInputManager;
private NotificationPresenter mPresenter;
@@ -85,12 +88,14 @@
public NotificationRowBinderImpl(Context context, boolean allowLongPress,
KeyguardBypassController keyguardBypassController,
- StatusBarStateController statusBarStateController) {
+ StatusBarStateController statusBarStateController,
+ NotifLog notifLog) {
mContext = context;
mMessagingUtil = new NotificationMessagingUtil(context);
mAllowLongPress = allowLongPress;
mKeyguardBypassController = keyguardBypassController;
mStatusBarStateController = statusBarStateController;
+ mNotifLog = notifLog;
}
private NotificationRemoteInputManager getRemoteInputManager() {
@@ -143,6 +148,7 @@
row -> {
bindRow(entry, pmUser, sbn, row, onDismissRunnable);
updateNotification(entry, pmUser, sbn, row);
+ mNotifLog.log(NotifEvent.INFLATED, sbn);
});
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java
index 2396d28..7703cbd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java
@@ -30,9 +30,9 @@
* and triaging purposes.
*/
public class NotifEvent extends RichEvent {
- public static final int TOTAL_EVENT_TYPES = 8;
- private StatusBarNotification mSbn;
- private Ranking mRanking;
+ public static final int TOTAL_EVENT_TYPES = 11;
+ private final StatusBarNotification mSbn;
+ private final Ranking mRanking;
/**
* Creates a NotifEvent with an event type that matches with an index in the array
@@ -44,9 +44,20 @@
public NotifEvent(int logLevel, int type, String reason, StatusBarNotification sbn,
Ranking ranking) {
super(logLevel, type, reason);
- mSbn = sbn.clone();
- mRanking = new Ranking();
- mRanking.populate(ranking);
+
+ if (sbn != null) {
+ mSbn = sbn.cloneLight();
+ } else {
+ mSbn = null;
+ }
+
+ if (ranking != null) {
+ mRanking = new Ranking();
+ mRanking.populate(ranking);
+ } else {
+ mRanking = null;
+ }
+
mMessage += getExtraInfo();
}
@@ -76,11 +87,14 @@
"NotifAdded",
"NotifRemoved",
"NotifUpdated",
- "HeadsUpStarted",
- "HeadsUpEnded",
"Filter",
"Sort",
+ "FilterAndSort",
"NotifVisibilityChanged",
+ "LifetimeExtended",
+ "RemoveIntercepted",
+ "InflationAborted",
+ "Inflated"
};
if (events.length != TOTAL_EVENT_TYPES) {
@@ -135,8 +149,19 @@
}
}
- @IntDef({NOTIF_ADDED, NOTIF_REMOVED, NOTIF_UPDATED, HEADS_UP_STARTED, HEADS_UP_ENDED, FILTER,
- SORT, NOTIF_VISIBILITY_CHANGED})
+ @IntDef({NOTIF_ADDED,
+ NOTIF_REMOVED,
+ NOTIF_UPDATED,
+ FILTER,
+ SORT,
+ FILTER_AND_SORT,
+ NOTIF_VISIBILITY_CHANGED,
+ LIFETIME_EXTENDED,
+ REMOVE_INTERCEPTED,
+ INFLATION_ABORTED,
+ INFLATED
+ })
+
/**
* Types of NotifEvents
*/
@@ -145,9 +170,13 @@
public static final int NOTIF_ADDED = 0;
public static final int NOTIF_REMOVED = 1;
public static final int NOTIF_UPDATED = 2;
- public static final int HEADS_UP_STARTED = 3;
- public static final int HEADS_UP_ENDED = 4;
- public static final int FILTER = 5;
- public static final int SORT = 6;
- public static final int NOTIF_VISIBILITY_CHANGED = 7;
+ public static final int FILTER = 3;
+ public static final int SORT = 4;
+ public static final int FILTER_AND_SORT = 5;
+ public static final int NOTIF_VISIBILITY_CHANGED = 6;
+ public static final int LIFETIME_EXTENDED = 7;
+ // unable to remove notif - removal intercepted by {@link NotificationRemoveInterceptor}
+ public static final int REMOVE_INTERCEPTED = 8;
+ public static final int INFLATION_ABORTED = 9;
+ public static final int INFLATED = 10;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifLog.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifLog.java
index d42cd82..8466d2e8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifLog.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifLog.java
@@ -82,6 +82,14 @@
}
/**
+ * Logs a {@link NotifEvent} with a notification
+ * @return true if successfully logged, else false
+ */
+ public boolean log(@NotifEvent.EventType int eventType, StatusBarNotification sbn, String msg) {
+ return log(eventType, sbn, null, msg);
+ }
+
+ /**
* Logs a {@link NotifEvent} with a ranking
* @return true if successfully logged, else false
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 9f4b026..924a347 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -1447,6 +1447,7 @@
}
setDismissed(fromAccessibility);
if (mEntry.isClearable()) {
+ // TODO: beverlyt, log dismissal
// TODO: track dismiss sentiment
if (mOnDismissRunnable != null) {
mOnDismissRunnable.run();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManager.java
index 73093c6f..37f63c9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManager.java
@@ -139,7 +139,8 @@
mBlockingHelperRow.setBlockingHelperShowing(false);
if (mBlockingHelperRow.isAttachedToWindow()) {
- Dependency.get(NotificationEntryManager.class).updateNotifications();
+ Dependency.get(NotificationEntryManager.class).updateNotifications(
+ "dismissCurrentBlockingHelper");
}
mBlockingHelperRow = null;
return true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index f5705c5..7bbe818 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -5333,7 +5333,7 @@
requestChildrenUpdate();
onUpdateRowStates();
- mEntryManager.updateNotifications();
+ mEntryManager.updateNotifications("StatusBar state changed");
updateVisibility();
}
@@ -6492,12 +6492,12 @@
@Override
public void onGroupCreatedFromChildren(NotificationGroupManager.NotificationGroup group) {
- mStatusBar.requestNotificationUpdate();
+ mStatusBar.requestNotificationUpdate("onGroupCreatedFromChildren");
}
@Override
public void onGroupsChanged() {
- mStatusBar.requestNotificationUpdate();
+ mStatusBar.requestNotificationUpdate("onGroupsChanged");
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
index 4cd3ad2..ca7c227 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.phone;
import static android.view.Display.INVALID_DISPLAY;
+import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+import static android.view.View.NAVIGATION_BAR_TRANSIENT;
import android.content.Context;
import android.content.res.Resources;
@@ -131,6 +133,7 @@
private boolean mIsAttached;
private boolean mIsGesturalModeEnabled;
private boolean mIsEnabled;
+ private boolean mIsInTransientImmersiveStickyState;
private InputMonitor mInputMonitor;
private InputEventReceiver mInputEventReceiver;
@@ -195,6 +198,12 @@
updateCurrentUserResources(currentUserContext.getResources());
}
+ public void onSystemUiVisibilityChanged(int systemUiVisibility) {
+ mIsInTransientImmersiveStickyState =
+ (systemUiVisibility & SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0
+ && (systemUiVisibility & NAVIGATION_BAR_TRANSIENT) != 0;
+ }
+
private void disposeInputChannel() {
if (mInputEventReceiver != null) {
mInputEventReceiver.dispose();
@@ -296,13 +305,21 @@
}
private boolean isWithinTouchRegion(int x, int y) {
+ // Disallow if over the IME
if (y > (mDisplaySize.y - Math.max(mImeHeight, mNavBarHeight))) {
return false;
}
+ // Disallow if too far from the edge
if (x > mEdgeWidth + mLeftInset && x < (mDisplaySize.x - mEdgeWidth - mRightInset)) {
return false;
}
+
+ // Always allow if the user is in a transient sticky immersive state
+ if (mIsInTransientImmersiveStickyState) {
+ return true;
+ }
+
boolean isInExcludedRegion = mExcludeRegion.contains(x, y);
if (isInExcludedRegion) {
mOverviewProxyService.notifyBackAction(false /* completed */, -1, -1,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 6e61d7c..38dc5ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -560,6 +560,9 @@
}
mAutoHideController.touchAutoHide();
}
+ if (mNavigationBarView != null) {
+ mNavigationBarView.onSystemUiVisibilityChanged(mSystemUiVisibility);
+ }
}
mLightBarController.onNavigationVisibilityChanged(
vis, mask, nbModeChanged, mNavigationBarMode, navbarColorManagedByIme);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index a1a47e1..9804f9f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -67,6 +67,7 @@
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.assist.AssistHandleViewController;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.model.SysUiState;
import com.android.systemui.recents.OverviewProxyService;
@@ -75,6 +76,7 @@
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.WindowManagerWrapper;
+import com.android.systemui.statusbar.NavigationBarController;
import com.android.systemui.statusbar.policy.DeadZone;
import com.android.systemui.statusbar.policy.KeyButtonDrawable;
@@ -364,6 +366,10 @@
return super.onTouchEvent(event);
}
+ void onSystemUiVisibilityChanged(int systemUiVisibility) {
+ mEdgeBackGestureHandler.onSystemUiVisibilityChanged(systemUiVisibility);
+ }
+
void onBarTransition(int newMode) {
if (newMode == MODE_OPAQUE) {
// If the nav bar background is opaque, stop auto tinting since we know the icons are
@@ -1198,6 +1204,19 @@
// we're passing the insets onto the gesture handler since the back arrow is only
// conditionally added and doesn't always get all the insets.
mEdgeBackGestureHandler.setInsets(leftInset, rightInset);
+
+ // this allows assist handle to be drawn outside its bound so that it can align screen
+ // bottom by translating its y position.
+ final boolean shouldClip =
+ !isGesturalMode(mNavBarMode) || insets.getSystemWindowInsetBottom() == 0;
+ setClipChildren(shouldClip);
+ setClipToPadding(shouldClip);
+
+ AssistHandleViewController controller = Dependency.get(NavigationBarController.class)
+ .getAssistHandlerViewController();
+ if (controller != null) {
+ controller.setBottomOffset(insets.getSystemWindowInsetBottom());
+ }
return super.onApplyWindowInsets(insets);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index c7fe4a8..00736b7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -518,6 +518,7 @@
* Call after this view has been fully inflated and had its children attached.
*/
public void onChildrenAttached() {
+ loadDimens();
mKeyguardStatusBar = findViewById(R.id.keyguard_header);
mKeyguardStatusView = findViewById(R.id.keyguard_status_view);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 6ce6dfa..2b80d22 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -210,6 +210,7 @@
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
+import com.android.systemui.statusbar.notification.logging.NotifLog;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -385,6 +386,7 @@
private final BroadcastDispatcher mBroadcastDispatcher;
private final ConfigurationController mConfigurationController;
private final StatusBarWindowViewController.Builder mStatusBarWindowViewControllerBuilder;
+ private final NotifLog mNotifLog;
// expanded notifications
protected NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
@@ -585,7 +587,7 @@
@Override
public void onStrongAuthStateChanged(int userId) {
super.onStrongAuthStateChanged(userId);
- mEntryManager.updateNotifications();
+ mEntryManager.updateNotifications("onStrongAuthStateChanged");
}
};
private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
@@ -599,6 +601,7 @@
private boolean mPulsing;
private final BubbleController mBubbleController;
private final BubbleController.BubbleExpandListener mBubbleExpandListener;
+
private ActivityIntentHelper mActivityIntentHelper;
@Override
@@ -669,7 +672,8 @@
NotificationListener notificationListener,
ConfigurationController configurationController,
StatusBarWindowController statusBarWindowController,
- StatusBarWindowViewController.Builder statusBarWindowViewControllerBuilder) {
+ StatusBarWindowViewController.Builder statusBarWindowViewControllerBuilder,
+ NotifLog notifLog) {
mLightBarController = lightBarController;
mAutoHideController = autoHideController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
@@ -723,10 +727,11 @@
mConfigurationController = configurationController;
mStatusBarWindowController = statusBarWindowController;
mStatusBarWindowViewControllerBuilder = statusBarWindowViewControllerBuilder;
+ mNotifLog = notifLog;
mBubbleExpandListener =
(isExpanding, key) -> {
- mEntryManager.updateNotifications();
+ mEntryManager.updateNotifications("onBubbleExpandChanged");
updateScrimController();
};
}
@@ -1160,7 +1165,8 @@
mContext,
mAllowNotificationLongPress,
mKeyguardBypassController,
- mStatusBarStateController);
+ mStatusBarStateController,
+ mNotifLog);
mPresenter = new StatusBarNotificationPresenter(mContext, mNotificationPanel,
mHeadsUpManager, mStatusBarWindow, mStackScroller, mDozeScrimController,
@@ -1443,8 +1449,12 @@
return mZenController.areNotificationsHiddenInShade();
}
- public void requestNotificationUpdate() {
- mEntryManager.updateNotifications();
+ /**
+ * Request a notification update
+ * @param reason why we're requesting a notification update
+ */
+ public void requestNotificationUpdate(String reason) {
+ mEntryManager.updateNotifications(reason);
}
/**
@@ -1685,7 +1695,7 @@
@Override
public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
- mEntryManager.updateNotifications();
+ mEntryManager.updateNotifications("onHeadsUpStateChanged");
if (isDozing() && isHeadsUp) {
entry.setPulseSuppressed(false);
mDozeServiceHost.fireNotificationPulse(entry);
@@ -3566,7 +3576,7 @@
updateQsExpansionEnabled();
mKeyguardViewMediator.setDozing(mDozing);
- mEntryManager.updateNotifications();
+ mEntryManager.updateNotifications("onDozingChanged");
updateDozingState();
updateScrimController();
updateReportRejectedTouchVisibility();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
index cc91bc0..392094d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
@@ -154,13 +154,17 @@
}
private void notifyKeyguardChanged() {
+ Trace.beginSection("KeyguardStateController#notifyKeyguardChanged");
// Copy the list to allow removal during callback.
new ArrayList<>(mCallbacks).forEach(Callback::onKeyguardShowingChanged);
+ Trace.endSection();
}
private void notifyUnlockedChanged() {
+ Trace.beginSection("KeyguardStateController#notifyUnlockedChanged");
// Copy the list to allow removal during callback.
new ArrayList<>(mCallbacks).forEach(Callback::onUnlockedChanged);
+ Trace.endSection();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/DumpTruck.java b/packages/SystemUI/src/com/android/systemui/util/leak/DumpTruck.java
index fa7af0b..be5e0a0 100644
--- a/packages/SystemUI/src/com/android/systemui/util/leak/DumpTruck.java
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/DumpTruck.java
@@ -36,6 +36,7 @@
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
@@ -53,7 +54,7 @@
private final Context context;
private Uri hprofUri;
- private long pss;
+ private long rss;
final StringBuilder body = new StringBuilder();
public DumpTruck(Context context) {
@@ -66,7 +67,7 @@
* @param pids
* @return this, for chaining
*/
- public DumpTruck captureHeaps(int[] pids) {
+ public DumpTruck captureHeaps(List<Long> pids) {
final GarbageMonitor gm = Dependency.get(GarbageMonitor.class);
final File dumpDir = new File(context.getCacheDir(), FILEPROVIDER_PATH);
@@ -79,8 +80,8 @@
final ArrayList<String> paths = new ArrayList<String>();
final int myPid = android.os.Process.myPid();
- final int[] pids_copy = Arrays.copyOf(pids, pids.length);
- for (int pid : pids_copy) {
+ for (Long pidL : pids) {
+ final int pid = pidL.intValue();
body.append(" pid ").append(pid);
if (gm != null) {
GarbageMonitor.ProcessMemInfo info = gm.getMemInfo(pid);
@@ -88,11 +89,9 @@
body.append(":")
.append(" up=")
.append(info.getUptime())
- .append(" pss=")
- .append(info.currentPss)
- .append(" uss=")
- .append(info.currentUss);
- pss = info.currentPss;
+ .append(" rss=")
+ .append(info.currentRss);
+ rss = info.currentRss;
}
}
if (pid == myPid) {
@@ -147,7 +146,7 @@
shareIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
shareIntent.putExtra(Intent.EXTRA_SUBJECT,
- String.format("SystemUI memory dump (pss=%dM)", pss / 1024));
+ String.format("SystemUI memory dump (rss=%dM)", rss / 1024));
shareIntent.putExtra(Intent.EXTRA_TEXT, body.toString());
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
index db43906..2d5ebc4 100644
--- a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
@@ -35,7 +35,6 @@
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
-import android.os.Debug;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -57,6 +56,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.List;
import javax.inject.Inject;
import javax.inject.Named;
@@ -102,7 +102,6 @@
private final LongSparseArray<ProcessMemInfo> mData = new LongSparseArray<>();
private final ArrayList<Long> mPids = new ArrayList<>();
- private int[] mPidsArray = new int[1];
private long mHeapLimit;
@@ -164,8 +163,8 @@
return mData.get(pid);
}
- public int[] getTrackedProcesses() {
- return mPidsArray;
+ public List<Long> getTrackedProcesses() {
+ return mPids;
}
public void startTrackingProcess(long pid, String name, long start) {
@@ -173,43 +172,40 @@
if (mPids.contains(pid)) return;
mPids.add(pid);
- updatePidsArrayL();
+ logPids();
mData.put(pid, new ProcessMemInfo(pid, name, start));
}
}
- private void updatePidsArrayL() {
- final int N = mPids.size();
- mPidsArray = new int[N];
- StringBuffer sb = new StringBuffer("Now tracking processes: ");
- for (int i = 0; i < N; i++) {
- final int p = mPids.get(i).intValue();
- mPidsArray[i] = p;
- sb.append(p);
- sb.append(" ");
+ private void logPids() {
+ if (DEBUG) {
+ StringBuffer sb = new StringBuffer("Now tracking processes: ");
+ for (int i = 0; i < mPids.size(); i++) {
+ final int p = mPids.get(i).intValue();
+ sb.append(" ");
+ }
+ Log.v(TAG, sb.toString());
}
- if (DEBUG) Log.v(TAG, sb.toString());
}
private void update() {
synchronized (mPids) {
- Debug.MemoryInfo[] dinfos = mAm.getProcessMemoryInfo(mPidsArray);
- for (int i = 0; i < dinfos.length; i++) {
- Debug.MemoryInfo dinfo = dinfos[i];
- if (i > mPids.size()) {
- if (DEBUG) Log.e(TAG, "update: unknown process info received: " + dinfo);
+ for (int i = 0; i < mPids.size(); i++) {
+ final int pid = mPids.get(i).intValue();
+ // rssValues contains [VmRSS, RssFile, RssAnon, VmSwap].
+ long[] rssValues = Process.getRss(pid);
+ if (rssValues == null && rssValues.length == 0) {
+ if (DEBUG) Log.e(TAG, "update: Process.getRss() didn't provide any values.");
break;
}
- final long pid = mPids.get(i).intValue();
+ long rss = rssValues[0];
final ProcessMemInfo info = mData.get(pid);
- info.pss[info.head] = info.currentPss = dinfo.getTotalPss();
- info.uss[info.head] = info.currentUss = dinfo.getTotalPrivateDirty();
- info.head = (info.head + 1) % info.pss.length;
- if (info.currentPss > info.max) info.max = info.currentPss;
- if (info.currentUss > info.max) info.max = info.currentUss;
- if (info.currentPss == 0) {
- if (DEBUG) Log.v(TAG, "update: pid " + pid + " has pss=0, it probably died");
+ info.rss[info.head] = info.currentRss = rss;
+ info.head = (info.head + 1) % info.rss.length;
+ if (info.currentRss > info.max) info.max = info.currentRss;
+ if (info.currentRss == 0) {
+ if (DEBUG) Log.v(TAG, "update: pid " + pid + " has rss=0, it probably died");
mData.remove(pid);
}
}
@@ -217,7 +213,7 @@
final long pid = mPids.get(i).intValue();
if (mData.get(pid) == null) {
mPids.remove(i);
- updatePidsArrayL();
+ logPids();
}
}
}
@@ -270,7 +266,7 @@
private static class MemoryIconDrawable extends Drawable {
- long pss, limit;
+ long rss, limit;
final Drawable baseIcon;
final Paint paint = new Paint();
final float dp;
@@ -281,9 +277,9 @@
paint.setColor(QSTileImpl.getColorForState(context, STATE_ACTIVE));
}
- public void setPss(long pss) {
- if (pss != this.pss) {
- this.pss = pss;
+ public void setRss(long rss) {
+ if (rss != this.rss) {
+ this.rss = rss;
invalidateSelf();
}
}
@@ -299,8 +295,8 @@
public void draw(Canvas canvas) {
baseIcon.draw(canvas);
- if (limit > 0 && pss > 0) {
- float frac = Math.min(1f, (float) pss / limit);
+ if (limit > 0 && rss > 0) {
+ float frac = Math.min(1f, (float) rss / limit);
final Rect bounds = getBounds();
canvas.translate(bounds.left + 8 * dp, bounds.top + 5 * dp);
@@ -361,10 +357,10 @@
}
private static class MemoryGraphIcon extends QSTile.Icon {
- long pss, limit;
+ long rss, limit;
- public void setPss(long pss) {
- this.pss = pss;
+ public void setRss(long rss) {
+ this.rss = rss;
}
public void setHeapLimit(long limit) {
@@ -374,7 +370,7 @@
@Override
public Drawable getDrawable(Context context) {
final MemoryIconDrawable drawable = new MemoryIconDrawable(context);
- drawable.setPss(pss);
+ drawable.setRss(rss);
drawable.setLimit(limit);
return drawable;
}
@@ -464,14 +460,14 @@
? "Dumping..."
: mContext.getString(R.string.heap_dump_tile_name);
if (pmi != null) {
- icon.setPss(pmi.currentPss);
+ icon.setRss(pmi.currentRss);
state.secondaryLabel =
String.format(
- "pss: %s / %s",
- formatBytes(pmi.currentPss * 1024),
+ "rss: %s / %s",
+ formatBytes(pmi.currentRss * 1024),
formatBytes(gm.mHeapLimit * 1024));
} else {
- icon.setPss(0);
+ icon.setRss(0);
state.secondaryLabel = null;
}
state.icon = icon;
@@ -481,8 +477,8 @@
refreshState();
}
- public long getPss() {
- return pmi != null ? pmi.currentPss : 0;
+ public long getRss() {
+ return pmi != null ? pmi.currentRss : 0;
}
public long getHeapLimit() {
@@ -495,9 +491,8 @@
public long pid;
public String name;
public long startTime;
- public long currentPss, currentUss;
- public long[] pss = new long[HEAP_TRACK_HISTORY_LEN];
- public long[] uss = new long[HEAP_TRACK_HISTORY_LEN];
+ public long currentRss;
+ public long[] rss = new long[HEAP_TRACK_HISTORY_LEN];
public long max = 1;
public int head = 0;
@@ -519,17 +514,12 @@
pw.print(name.replace('"', '-'));
pw.print("\", \"start\": ");
pw.print(startTime);
- pw.print(", \"pss\": [");
- // write pss values starting from the oldest, which is pss[head], wrapping around to
- // pss[(head-1) % pss.length]
- for (int i = 0; i < pss.length; i++) {
+ pw.print(", \"rss\": [");
+ // write rss values starting from the oldest, which is rss[head], wrapping around to
+ // rss[(head-1) % rss.length]
+ for (int i = 0; i < rss.length; i++) {
if (i > 0) pw.print(",");
- pw.print(pss[(head + i) % pss.length]);
- }
- pw.print("], \"uss\": [");
- for (int i = 0; i < uss.length; i++) {
- if (i > 0) pw.print(",");
- pw.print(uss[(head + i) % uss.length]);
+ pw.print(rss[(head + i) % rss.length]);
}
pw.println("] }");
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index 2798c6b..5a2b5e3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -33,6 +33,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -91,7 +92,6 @@
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class BubbleControllerTest extends SysuiTestCase {
-
@Mock
private NotificationEntryManager mNotificationEntryManager;
@Mock
@@ -223,13 +223,13 @@
mBubbleController.updateBubble(mRow.getEntry());
assertNotNull(mBubbleData.getBubbleWithKey(mRow.getEntry().key));
assertTrue(mBubbleController.hasBubbles());
- verify(mNotificationEntryManager).updateNotifications();
+ verify(mNotificationEntryManager).updateNotifications(any());
verify(mBubbleStateChangeListener).onHasBubblesChanged(true);
mBubbleController.removeBubble(mRow.getEntry().key, BubbleController.DISMISS_USER_GESTURE);
assertFalse(mStatusBarWindowController.getBubblesShowing());
assertNull(mBubbleData.getBubbleWithKey(mRow.getEntry().key));
- verify(mNotificationEntryManager, times(2)).updateNotifications();
+ verify(mNotificationEntryManager, times(2)).updateNotifications(anyString());
verify(mBubbleStateChangeListener).onHasBubblesChanged(false);
}
@@ -257,16 +257,16 @@
@Test
public void testDismissStack() {
mBubbleController.updateBubble(mRow.getEntry());
- verify(mNotificationEntryManager, times(1)).updateNotifications();
+ verify(mNotificationEntryManager, times(1)).updateNotifications(any());
assertNotNull(mBubbleData.getBubbleWithKey(mRow.getEntry().key));
mBubbleController.updateBubble(mRow2.getEntry());
- verify(mNotificationEntryManager, times(2)).updateNotifications();
+ verify(mNotificationEntryManager, times(2)).updateNotifications(any());
assertNotNull(mBubbleData.getBubbleWithKey(mRow2.getEntry().key));
assertTrue(mBubbleController.hasBubbles());
mBubbleController.dismissStack(BubbleController.DISMISS_USER_GESTURE);
assertFalse(mStatusBarWindowController.getBubblesShowing());
- verify(mNotificationEntryManager, times(3)).updateNotifications();
+ verify(mNotificationEntryManager, times(3)).updateNotifications(any());
assertNull(mBubbleData.getBubbleWithKey(mRow.getEntry().key));
assertNull(mBubbleData.getBubbleWithKey(mRow2.getEntry().key));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
index 07fbbcf..7752014 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
@@ -60,6 +60,7 @@
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.List;
+import java.util.Objects;
import javax.inject.Provider;
@@ -190,8 +191,7 @@
// changed
String newSetting = Settings.Secure.getStringForUser(getContext().getContentResolver(),
TILES_SETTING, ActivityManager.getCurrentUser());
- // newSetting is not null, as it has just been set.
- if (!newSetting.equals(previousSetting)) {
+ if (!Objects.equals(newSetting, previousSetting)) {
onTuningChanged(TILES_SETTING, newSetting);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java
index 618272c..cfa4065a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java
@@ -23,6 +23,7 @@
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
@@ -31,15 +32,10 @@
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-import android.content.Context;
-import android.hardware.display.DisplayManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
import android.util.SparseArray;
-import android.view.Display;
-import android.view.WindowManager;
import androidx.test.filters.SmallTest;
@@ -59,7 +55,6 @@
public class NavigationBarControllerTest extends SysuiTestCase {
private NavigationBarController mNavigationBarController;
- private Display mDisplay;
private NavigationBarFragment mDefaultNavBar;
private NavigationBarFragment mSecondaryNavBar;
@@ -89,37 +84,28 @@
@After
public void tearDown() {
mNavigationBarController = null;
- mDisplay = null;
mDefaultNavBar = null;
mSecondaryNavBar = null;
}
@Test
public void testCreateNavigationBarsIncludeDefaultTrue() {
- initializeDisplayManager();
doNothing().when(mNavigationBarController).createNavigationBar(any(), any());
mNavigationBarController.createNavigationBars(true, null);
- verify(mNavigationBarController).createNavigationBar(any(Display.class), any());
+ verify(mNavigationBarController).createNavigationBar(
+ argThat(display -> display.getDisplayId() == DEFAULT_DISPLAY), any());
}
@Test
public void testCreateNavigationBarsIncludeDefaultFalse() {
- initializeDisplayManager();
doNothing().when(mNavigationBarController).createNavigationBar(any(), any());
mNavigationBarController.createNavigationBars(false, null);
- verify(mNavigationBarController, never()).createNavigationBar(any(), any());
- }
-
- private void initializeDisplayManager() {
- DisplayManager displayManager = mock(DisplayManager.class);
- mDisplay = mContext.getSystemService(WindowManager.class).getDefaultDisplay();
- Display[] displays = {mDisplay};
- when(displayManager.getDisplays()).thenReturn(displays);
- mContext.addMockSystemService(Context.DISPLAY_SERVICE, displayManager);
+ verify(mNavigationBarController, never()).createNavigationBar(
+ argThat(display -> display.getDisplayId() == DEFAULT_DISPLAY), any());
}
// Tests if NPE occurs when call checkNavBarModes() with invalid display.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
index a027643..0569c55 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
@@ -25,6 +25,7 @@
import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -99,7 +100,7 @@
@Test
public void testLockScreenShowNotificationsChangeUpdatesNotifications() {
mLockscreenUserManager.getLockscreenSettingsObserverForTest().onChange(false);
- verify(mEntryManager, times(1)).updateNotifications();
+ verify(mEntryManager, times(1)).updateNotifications(anyString());
}
@Test
@@ -138,7 +139,7 @@
public void testSettingsObserverUpdatesNotifications() {
when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
mLockscreenUserManager.getSettingsObserverForTest().onChange(false);
- verify(mEntryManager, times(1)).updateNotifications();
+ verify(mEntryManager, times(1)).updateNotifications(anyString());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index 52f7e67..e52a258 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -28,6 +28,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
@@ -68,6 +69,7 @@
import com.android.systemui.statusbar.NotificationLifetimeExtender;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationRemoveInterceptor;
@@ -79,6 +81,7 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationRowBinder;
import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
+import com.android.systemui.statusbar.notification.logging.NotifLog;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -145,7 +148,8 @@
private final CountDownLatch mCountDownLatch;
TestableNotificationEntryManager() {
- super(new NotificationData(mock(NotificationSectionsFeatureManager.class)));
+ super(new NotificationData(mock(NotificationSectionsFeatureManager.class),
+ mock(NotifLog.class)), mock(NotifLog.class));
mCountDownLatch = new CountDownLatch(1);
}
@@ -224,6 +228,7 @@
mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
mDependency.injectTestDependency(SmartReplyController.class, mSmartReplyController);
mDependency.injectTestDependency(KeyguardEnvironment.class, mEnvironment);
+ mDependency.injectMockDependency(NotificationMediaManager.class);
mCountDownLatch = new CountDownLatch(1);
@@ -257,7 +262,9 @@
NotificationRowBinderImpl notificationRowBinder =
new NotificationRowBinderImpl(mContext, true, /* allowLongPress */
- mock(KeyguardBypassController.class), mock(StatusBarStateController.class));
+ mock(KeyguardBypassController.class),
+ mock(StatusBarStateController.class),
+ mock(NotifLog.class));
notificationRowBinder.setUpWithPresenter(
mPresenter, mListContainer, mHeadsUpManager, mEntryManager, mBindCallback);
notificationRowBinder.setNotificationClicker(mock(NotificationClicker.class));
@@ -348,7 +355,7 @@
// Ensure that update callbacks happen in correct order
InOrder order = inOrder(mEntryListener, notifData, mPresenter, mEntryListener);
order.verify(mEntryListener).onPreEntryUpdated(mEntry);
- order.verify(notifData).filterAndSort();
+ order.verify(notifData).filterAndSort(anyString());
order.verify(mPresenter).updateNotificationViews();
order.verify(mEntryListener).onPostEntryUpdated(mEntry);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java
index 6d275419..8207a04 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java
@@ -21,6 +21,7 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -43,6 +44,7 @@
import com.android.systemui.statusbar.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.collection.NotificationData;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.logging.NotifLog;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
@@ -76,7 +78,7 @@
// TODO: Remove this once EntryManager no longer needs to be mocked
private NotificationData mNotificationData =
new NotificationData(new NotificationSectionsFeatureManager(
- new DeviceConfigProxyFake(), mContext));
+ new DeviceConfigProxyFake(), mContext), mock(NotifLog.class));
private int mNextNotifId = 0;
@@ -113,7 +115,7 @@
@Test
public void testCallUpdateNotificationsOnDeviceProvisionedChange() {
mProvisionedListener.onDeviceProvisionedChanged();
- verify(mEntryManager).updateNotifications();
+ verify(mEntryManager).updateNotifications(anyString());
}
@Test
@@ -133,8 +135,8 @@
// THEN the app op is added to the entry
assertTrue(entry.mActiveAppOps.contains(AppOpsManager.OP_CAMERA));
- // THEN updateNotifications() is called
- verify(mEntryManager, times(1)).updateNotifications();
+ // THEN updateNotifications(TEST) is called
+ verify(mEntryManager, times(1)).updateNotifications(anyString());
}
@Test
@@ -146,8 +148,8 @@
// WHEN An unrelated notification gets a new app op
mController.updateNotificationsForAppOp(AppOpsManager.OP_CAMERA, 1000, "pkg", true);
- // THEN We never call updateNotifications()
- verify(mEntryManager, never()).updateNotifications();
+ // THEN We never call updateNotifications(TEST)
+ verify(mEntryManager, never()).updateNotifications(anyString());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
index 5fbacb1..59c76a8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
@@ -79,6 +79,7 @@
import com.android.systemui.statusbar.SbnBuilder;
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
+import com.android.systemui.statusbar.notification.logging.NotifLog;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -141,7 +142,7 @@
when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true);
mNotificationData = new TestableNotificationData(
mock(NotificationSectionsFeatureManager.class));
- mNotificationData.updateRanking(mock(NotificationListenerService.RankingMap.class));
+ mNotificationData.updateRanking(mock(NotificationListenerService.RankingMap.class), "");
mRow = new NotificationTestHelper(getContext()).createRow();
Dependency.get(InitController.class).executePostInitTasks();
}
@@ -633,7 +634,7 @@
public static class TestableNotificationData extends NotificationData {
public TestableNotificationData(NotificationSectionsFeatureManager sectionsFeatureManager) {
- super(sectionsFeatureManager);
+ super(sectionsFeatureManager, mock(NotifLog.class));
}
public static final String OVERRIDE_RANK = "r";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java
index 6d64395..cc89504 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java
@@ -27,6 +27,7 @@
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
@@ -62,7 +63,6 @@
@org.junit.runner.RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class NotificationBlockingHelperManagerTest extends SysuiTestCase {
-
private NotificationBlockingHelperManager mBlockingHelperManager;
private NotificationTestHelper mHelper;
@@ -112,7 +112,7 @@
assertTrue(mBlockingHelperManager.dismissCurrentBlockingHelper());
assertTrue(mBlockingHelperManager.isBlockingHelperRowNull());
- verify(mEntryManager, times(0)).updateNotifications();
+ verify(mEntryManager, times(0)).updateNotifications(anyString());
}
@Test
@@ -125,7 +125,7 @@
assertTrue(mBlockingHelperManager.dismissCurrentBlockingHelper());
assertTrue(mBlockingHelperManager.isBlockingHelperRowNull());
- verify(mEntryManager).updateNotifications();
+ verify(mEntryManager).updateNotifications(anyString());
}
@Test
@@ -267,7 +267,7 @@
assertTrue(mBlockingHelperManager.dismissCurrentBlockingHelper());
assertTrue(mBlockingHelperManager.isBlockingHelperRowNull());
- verify(mEntryManager).updateNotifications();
+ verify(mEntryManager).updateNotifications(anyString());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 98485b3..95e9e67 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -56,6 +56,7 @@
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.logging.NotifLog;
import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -232,7 +233,8 @@
mock(ShadeController.class),
mock(NotificationLockscreenUserManager.class),
new NotificationEntryManager(new NotificationData(mock(
- NotificationSectionsFeatureManager.class))),
+ NotificationSectionsFeatureManager.class), mock(NotifLog.class)),
+ mock(NotifLog.class)),
mock(DozeLog.class));
mNotificationStackScroller = mNotificationStackScrollLayout;
mKeyguardStatusView = NotificationPanelViewTest.this.mKeyguardStatusView;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 914717c..12e9be1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -117,6 +117,7 @@
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationData;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.logging.NotifLog;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
@@ -218,6 +219,7 @@
@Mock private NotificationIconAreaController mNotificationIconAreaController;
@Mock private StatusBarWindowViewController.Builder mStatusBarWindowViewControllerBuilder;
@Mock private StatusBarWindowViewController mStatusBarWindowViewController;
+ @Mock private NotifLog mNotifLog;
@Before
public void setup() throws Exception {
@@ -339,7 +341,8 @@
mNotificationListener,
configurationController,
mStatusBarWindowController,
- mStatusBarWindowViewControllerBuilder);
+ mStatusBarWindowViewControllerBuilder,
+ mNotifLog);
// TODO: we should be able to call mStatusBar.start() and have all the below values
// initialized automatically.
mStatusBar.mContext = mContext;
@@ -873,7 +876,7 @@
public static class TestableNotificationEntryManager extends NotificationEntryManager {
public TestableNotificationEntryManager(NotificationData notificationData) {
- super(notificationData);
+ super(notificationData, mock(NotifLog.class));
}
public void setUpForTest(NotificationPresenter presenter,
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
similarity index 99%
rename from core/java/android/content/pm/PackageManagerInternal.java
rename to services/core/java/android/content/pm/PackageManagerInternal.java
index 3eef92f..1d666ad 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -33,6 +33,8 @@
import android.util.ArraySet;
import android.util.SparseArray;
+import com.android.server.pm.PackageList;
+
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 9acafae..e0f60b4 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -579,6 +579,8 @@
// the set of network types that can only be enabled by system/sig apps
private List mProtectedNetworks;
+ private Set<String> mWolSupportedInterfaces;
+
private TelephonyManager mTelephonyManager;
private KeepaliveTracker mKeepaliveTracker;
@@ -1055,6 +1057,10 @@
}
}
+ mWolSupportedInterfaces = new ArraySet(
+ mContext.getResources().getStringArray(
+ com.android.internal.R.array.config_wakeonlan_supported_interfaces));
+
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
mTethering = deps.makeTethering(mContext, mNMS, mStatsService, mPolicyManager,
@@ -3268,7 +3274,8 @@
final NetworkRequestInfo nri = mNetworkRequests.get(request);
if (nri != null) {
- if (Process.SYSTEM_UID != callingUid && nri.mUid != callingUid) {
+ if (Process.SYSTEM_UID != callingUid && Process.NETWORK_STACK_UID != callingUid
+ && nri.mUid != callingUid) {
log(String.format("UID %d attempted to %s for unowned request %s",
callingUid, requestedOperation, nri));
return null;
@@ -5599,6 +5606,9 @@
} else {
updateProxy(newLp, oldLp);
}
+
+ updateWakeOnLan(newLp);
+
// TODO - move this check to cover the whole function
if (!Objects.equals(newLp, oldLp)) {
synchronized (networkAgent) {
@@ -5769,6 +5779,10 @@
}
}
+ private void updateWakeOnLan(@NonNull LinkProperties lp) {
+ lp.setWakeOnLanSupported(mWolSupportedInterfaces.contains(lp.getInterfaceName()));
+ }
+
private int getNetworkPermission(NetworkCapabilities nc) {
if (!nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) {
return INetd.PERMISSION_SYSTEM;
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 35a06a9..09f62ff 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -3064,11 +3064,6 @@
try {
LocationProvider oldProvider = getLocationProviderLocked(name);
if (oldProvider != null) {
- if (oldProvider.isMock()) {
- throw new IllegalArgumentException(
- "Provider \"" + name + "\" already exists");
- }
-
removeProviderLocked(oldProvider);
}
@@ -3093,7 +3088,7 @@
try {
LocationProvider testProvider = getLocationProviderLocked(name);
if (testProvider == null || !testProvider.isMock()) {
- throw new IllegalArgumentException("Provider \"" + name + "\" unknown");
+ return;
}
removeProviderLocked(testProvider);
diff --git a/services/core/java/com/android/server/SystemServerInitThreadPool.java b/services/core/java/com/android/server/SystemServerInitThreadPool.java
index ff6a537..19f4089 100644
--- a/services/core/java/com/android/server/SystemServerInitThreadPool.java
+++ b/services/core/java/com/android/server/SystemServerInitThreadPool.java
@@ -16,10 +16,12 @@
package com.android.server;
+import android.annotation.NonNull;
import android.os.Build;
import android.os.Process;
import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ConcurrentUtils;
import com.android.internal.util.Preconditions;
import com.android.server.am.ActivityManagerService;
@@ -32,9 +34,11 @@
/**
* Thread pool used during initialization of system server.
+ *
* <p>System services can {@link #submit(Runnable)} tasks for execution during boot.
* The pool will be shut down after {@link SystemService#PHASE_BOOT_COMPLETED}.
- * New tasks <em>should not</em> be submitted afterwards.
+ *
+ * <p>New tasks <em>should not</em> be submitted afterwards.
*
* @hide
*/
@@ -42,26 +46,46 @@
private static final String TAG = SystemServerInitThreadPool.class.getSimpleName();
private static final int SHUTDOWN_TIMEOUT_MILLIS = 20000;
private static final boolean IS_DEBUGGABLE = Build.IS_DEBUGGABLE;
+ private static final Object LOCK = new Object();
+ @GuardedBy("LOCK")
private static SystemServerInitThreadPool sInstance;
- private ExecutorService mService = ConcurrentUtils.newFixedThreadPool(
- Runtime.getRuntime().availableProcessors(),
- "system-server-init-thread", Process.THREAD_PRIORITY_FOREGROUND);
+ private final ExecutorService mService;
- private List<String> mPendingTasks = new ArrayList<>();
+ @GuardedBy("mPendingTasks")
+ private final List<String> mPendingTasks = new ArrayList<>();
- public static synchronized SystemServerInitThreadPool get() {
- if (sInstance == null) {
- sInstance = new SystemServerInitThreadPool();
- }
- Preconditions.checkState(sInstance.mService != null, "Cannot get " + TAG
- + " - it has been shut down");
- return sInstance;
+ @GuardedBy("mPendingTasks")
+ private boolean mShutDown;
+
+ private SystemServerInitThreadPool() {
+ final int size = Runtime.getRuntime().availableProcessors();
+ Slog.i(TAG, "Creating instance with " + size + " threads");
+ mService = ConcurrentUtils.newFixedThreadPool(size,
+ "system-server-init-thread", Process.THREAD_PRIORITY_FOREGROUND);
}
- public Future<?> submit(Runnable runnable, String description) {
+ /**
+ * Gets the singleton.
+ *
+ * @throws IllegalStateException if it hasn't been started or has been shut down already.
+ */
+ public static SystemServerInitThreadPool get() {
+ synchronized (LOCK) {
+ Preconditions.checkState(sInstance != null, "Cannot get " + TAG
+ + " - it has been shut down");
+ return sInstance;
+ }
+ }
+
+ /**
+ * Submits a task for execution.
+ */
+ public @NonNull Future<?> submit(@NonNull Runnable runnable, @NonNull String description) {
+ Preconditions.checkNotNull(description, "description cannot be null");
synchronized (mPendingTasks) {
+ Preconditions.checkState(!mShutDown, TAG + " already shut down");
mPendingTasks.add(description);
}
return mService.submit(() -> {
@@ -83,10 +107,36 @@
});
}
- static synchronized void shutdown() {
- if (sInstance != null && sInstance.mService != null) {
+ /**
+ * Starts it.
+ *
+ * <p>Note:</p> should only be called by {@link SystemServer}.
+ *
+ * @throws IllegalStateException if it has been started already without being shut down yet.
+ */
+ static void start() {
+ synchronized (LOCK) {
+ Preconditions.checkState(sInstance == null, TAG + " already started");
+ sInstance = new SystemServerInitThreadPool();
+ }
+ }
+
+ /**
+ * Shuts it down.
+ *
+ * <p>Note:</p> should only be called by {@link SystemServer}.
+ */
+ static void shutdown() {
+ synchronized (LOCK) {
+ if (sInstance == null) {
+ Slog.wtf(TAG, "Already shutdown", new Exception());
+ return;
+ }
+ synchronized (sInstance.mPendingTasks) {
+ sInstance.mShutDown = true;
+ }
sInstance.mService.shutdown();
- boolean terminated;
+ final boolean terminated;
try {
terminated = sInstance.mService.awaitTermination(SHUTDOWN_TIMEOUT_MILLIS,
TimeUnit.MILLISECONDS);
@@ -100,7 +150,7 @@
// in the thread pool.
dumpStackTraces();
}
- List<Runnable> unstartedRunnables = sInstance.mService.shutdownNow();
+ final List<Runnable> unstartedRunnables = sInstance.mService.shutdownNow();
if (!terminated) {
final List<String> copy = new ArrayList<>();
synchronized (sInstance.mPendingTasks) {
@@ -109,8 +159,7 @@
throw new IllegalStateException("Cannot shutdown. Unstarted tasks "
+ unstartedRunnables + " Unfinished tasks " + copy);
}
- sInstance.mService = null; // Make mService eligible for GC
- sInstance.mPendingTasks = null;
+ sInstance = null; // Make eligible for GC
Slog.d(TAG, "Shutdown successful");
}
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 08f75e6..9209a21 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -192,34 +192,38 @@
@Override
public void stopForegroundServicesForUidPackage(final int uid, final String packageName) {
synchronized (mAm) {
- final ServiceMap smap = getServiceMapLocked(UserHandle.getUserId(uid));
- final int N = smap.mServicesByInstanceName.size();
- final ArrayList<ServiceRecord> toStop = new ArrayList<>(N);
- for (int i = 0; i < N; i++) {
- final ServiceRecord r = smap.mServicesByInstanceName.valueAt(i);
- if (uid == r.serviceInfo.applicationInfo.uid
- || packageName.equals(r.serviceInfo.packageName)) {
- if (r.isForeground) {
- toStop.add(r);
- }
- }
- }
+ stopAllForegroundServicesLocked(uid, packageName);
+ }
+ }
+ }
- // Now stop them all
- final int numToStop = toStop.size();
- if (numToStop > 0 && DEBUG_FOREGROUND_SERVICE) {
- Slog.i(TAG, "Package " + packageName + "/" + uid
- + " entering FAS with foreground services");
- }
- for (int i = 0; i < numToStop; i++) {
- final ServiceRecord r = toStop.get(i);
- if (DEBUG_FOREGROUND_SERVICE) {
- Slog.i(TAG, " Stopping fg for service " + r);
- }
- setServiceForegroundInnerLocked(r, 0, null, 0, 0);
+ void stopAllForegroundServicesLocked(final int uid, final String packageName) {
+ final ServiceMap smap = getServiceMapLocked(UserHandle.getUserId(uid));
+ final int N = smap.mServicesByInstanceName.size();
+ final ArrayList<ServiceRecord> toStop = new ArrayList<>(N);
+ for (int i = 0; i < N; i++) {
+ final ServiceRecord r = smap.mServicesByInstanceName.valueAt(i);
+ if (uid == r.serviceInfo.applicationInfo.uid
+ || packageName.equals(r.serviceInfo.packageName)) {
+ if (r.isForeground) {
+ toStop.add(r);
}
}
}
+
+ // Now stop them all
+ final int numToStop = toStop.size();
+ if (numToStop > 0 && DEBUG_FOREGROUND_SERVICE) {
+ Slog.i(TAG, "Package " + packageName + "/" + uid
+ + " in FAS with foreground services");
+ }
+ for (int i = 0; i < numToStop; i++) {
+ final ServiceRecord r = toStop.get(i);
+ if (DEBUG_FOREGROUND_SERVICE) {
+ Slog.i(TAG, " Stopping fg for service " + r);
+ }
+ setServiceForegroundInnerLocked(r, 0, null, 0, 0);
+ }
}
/**
@@ -1019,12 +1023,23 @@
}
}
if (!aa.mAppOnTop) {
- if (active == null) {
- active = new ArrayList<>();
+ // Transitioning a fg-service host app out of top: if it's bg restricted,
+ // it loses the fg service state now.
+ if (!appRestrictedAnyInBackground(aa.mUid, aa.mPackageName)) {
+ if (active == null) {
+ active = new ArrayList<>();
+ }
+ if (DEBUG_FOREGROUND_SERVICE) Slog.d(TAG, "Adding active: pkg="
+ + aa.mPackageName + ", uid=" + aa.mUid);
+ active.add(aa);
+ } else {
+ if (DEBUG_FOREGROUND_SERVICE) {
+ Slog.d(TAG, "bg-restricted app "
+ + aa.mPackageName + "/" + aa.mUid
+ + " exiting top; demoting fg services ");
+ }
+ stopAllForegroundServicesLocked(aa.mUid, aa.mPackageName);
}
- if (DEBUG_FOREGROUND_SERVICE) Slog.d(TAG, "Adding active: pkg="
- + aa.mPackageName + ", uid=" + aa.mUid);
- active.add(aa);
}
}
smap.removeMessages(ServiceMap.MSG_UPDATE_FOREGROUND_APPS);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7cbd1fc..4bca7a1 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5015,7 +5015,9 @@
if (preBindAgent != null) {
thread.attachAgent(preBindAgent);
}
-
+ if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
+ thread.attachStartupAgents(app.info.dataDir);
+ }
// Figure out whether the app needs to run in autofill compat mode.
AutofillOptions autofillOptions = null;
@@ -18353,7 +18355,7 @@
@Override
public int getCurrentUserId() {
- return mUserController.getCurrentUserIdLU();
+ return mUserController.getCurrentUserId();
}
@Override
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 3c2aee4..bb214bd 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -30,7 +30,7 @@
import static android.app.ActivityManager.PROCESS_STATE_TOP;
import static android.app.ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
import static android.os.Process.SCHED_OTHER;
-import static android.os.Process.THREAD_GROUP_BG_NONINTERACTIVE;
+import static android.os.Process.THREAD_GROUP_BACKGROUND;
import static android.os.Process.THREAD_GROUP_DEFAULT;
import static android.os.Process.THREAD_GROUP_RESTRICTED;
import static android.os.Process.THREAD_GROUP_TOP_APP;
@@ -1759,7 +1759,7 @@
int processGroup;
switch (curSchedGroup) {
case ProcessList.SCHED_GROUP_BACKGROUND:
- processGroup = THREAD_GROUP_BG_NONINTERACTIVE;
+ processGroup = THREAD_GROUP_BACKGROUND;
break;
case ProcessList.SCHED_GROUP_TOP_APP:
case ProcessList.SCHED_GROUP_TOP_APP_BOUND:
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index c0af814..af126f2 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -215,7 +215,7 @@
// Memory pages are 4K.
static final int PAGE_SIZE = 4 * 1024;
- // Activity manager's version of Process.THREAD_GROUP_BG_NONINTERACTIVE
+ // Activity manager's version of Process.THREAD_GROUP_BACKGROUND
static final int SCHED_GROUP_BACKGROUND = 0;
// Activity manager's version of Process.THREAD_GROUP_RESTRICTED
static final int SCHED_GROUP_RESTRICTED = 1;
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 798185a..6c4cc2d 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -65,7 +65,6 @@
import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.hardware.camera2.CameraDevice.CAMERA_AUDIO_RESTRICTION;
-import android.media.AudioAttributes;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Binder;
@@ -109,6 +108,7 @@
import com.android.internal.app.IAppOpsService;
import com.android.internal.os.Zygote;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.Preconditions;
@@ -257,6 +257,9 @@
@GuardedBy("this")
private CheckOpsDelegate mCheckOpsDelegate;
+ @GuardedBy("this")
+ private SparseArray<List<Integer>> mSwitchOpToOps;
+
/**
* All times are in milliseconds. These constants are kept synchronized with the system
* global Settings. Any access to this class or its fields should be done while
@@ -1291,6 +1294,8 @@
verifyIncomingOp(code);
code = AppOpsManager.opToSwitch(code);
+ updatePermissionRevokedCompat(uid, code, mode);
+
synchronized (this) {
final int defaultMode = AppOpsManager.opToDefaultMode(code);
@@ -1392,6 +1397,86 @@
notifyOpChangedSync(code, uid, null, mode);
}
+ private void updatePermissionRevokedCompat(int uid, int switchCode, int mode) {
+ PackageManager packageManager = mContext.getPackageManager();
+ String[] packageNames = packageManager.getPackagesForUid(uid);
+ if (ArrayUtils.isEmpty(packageNames)) {
+ return;
+ }
+ String packageName = packageNames[0];
+
+ List<Integer> ops = getSwitchOpToOps().get(switchCode);
+ int opsSize = CollectionUtils.size(ops);
+ for (int i = 0; i < opsSize; i++) {
+ int code = ops.get(i);
+
+ String permissionName = AppOpsManager.opToPermission(code);
+ if (permissionName == null) {
+ continue;
+ }
+
+ PermissionInfo permissionInfo;
+ try {
+ permissionInfo = packageManager.getPermissionInfo(permissionName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ continue;
+ }
+
+ if (!permissionInfo.isRuntime()) {
+ continue;
+ }
+
+ UserHandle user = UserHandle.getUserHandleForUid(uid);
+ boolean isRevokedCompat;
+ if (permissionInfo.backgroundPermission != null) {
+ boolean isBackgroundRevokedCompat = mode != AppOpsManager.MODE_ALLOWED;
+ long identity = Binder.clearCallingIdentity();
+ try {
+ packageManager.updatePermissionFlags(permissionInfo.backgroundPermission,
+ packageName, PackageManager.FLAG_PERMISSION_REVOKED_COMPAT,
+ isBackgroundRevokedCompat
+ ? PackageManager.FLAG_PERMISSION_REVOKED_COMPAT : 0, user);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+
+ isRevokedCompat = mode != AppOpsManager.MODE_ALLOWED
+ && mode != AppOpsManager.MODE_FOREGROUND;
+ } else {
+ isRevokedCompat = mode != AppOpsManager.MODE_ALLOWED;
+ }
+
+ long identity = Binder.clearCallingIdentity();
+ try {
+ packageManager.updatePermissionFlags(permissionName, packageName,
+ PackageManager.FLAG_PERMISSION_REVOKED_COMPAT, isRevokedCompat
+ ? PackageManager.FLAG_PERMISSION_REVOKED_COMPAT : 0, user);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
+
+ @NonNull
+ private SparseArray<List<Integer>> getSwitchOpToOps() {
+ synchronized (this) {
+ if (mSwitchOpToOps == null) {
+ mSwitchOpToOps = new SparseArray<>();
+ for (int op = 0; op < _NUM_OP; op++) {
+ int switchOp = AppOpsManager.opToSwitch(op);
+ List<Integer> ops = mSwitchOpToOps.get(switchOp);
+ if (ops == null) {
+ ops = new ArrayList<>();
+ mSwitchOpToOps.put(switchOp, ops);
+ }
+ ops.add(op);
+ }
+ }
+ return mSwitchOpToOps;
+ }
+ }
+
private void notifyOpChangedSync(int code, int uid, @NonNull String packageName, int mode) {
final StorageManagerInternal storageManagerInternal =
LocalServices.getService(StorageManagerInternal.class);
diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index c46fc20..29026e8 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -114,6 +114,8 @@
private final FloatBuffer mVertexBuffer = createNativeFloatBuffer(8);
private final FloatBuffer mTexCoordBuffer = createNativeFloatBuffer(8);
+ private final Transaction mTransaction = new Transaction();
+
/**
* Animates an color fade warming up.
*/
@@ -659,14 +661,10 @@
private boolean showSurface(float alpha) {
if (!mSurfaceVisible || mSurfaceAlpha != alpha) {
- SurfaceControl.openTransaction();
- try {
- mSurfaceControl.setLayer(COLOR_FADE_LAYER);
- mSurfaceControl.setAlpha(alpha);
- mSurfaceControl.show();
- } finally {
- SurfaceControl.closeTransaction();
- }
+ mTransaction.setLayer(mSurfaceControl, COLOR_FADE_LAYER)
+ .setAlpha(mSurfaceControl, alpha)
+ .show(mSurfaceControl)
+ .apply();
mSurfaceVisible = true;
mSurfaceAlpha = alpha;
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index f20003a2..b7fcd3f 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -3569,9 +3569,15 @@
if (!calledWithValidTokenLocked(token)) {
return;
}
- if (mCurClient != null && mCurClient.client != null) {
- executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
- MSG_APPLY_IME_VISIBILITY, setVisible ? 1 : 0, mCurClient));
+ if (!setVisible) {
+ // Client hides the IME directly.
+ if (mCurClient != null && mCurClient.client != null) {
+ executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
+ MSG_APPLY_IME_VISIBILITY, setVisible ? 1 : 0, mCurClient));
+ }
+ } else {
+ // Send to window manager to show IME after IME layout finishes.
+ mWindowManagerInternal.showImePostLayout(mLastImeTargetWindow);
}
}
}
diff --git a/services/core/java/com/android/server/integrity/model/AtomicFormula.java b/services/core/java/com/android/server/integrity/model/AtomicFormula.java
index 38c9b57..a9cc62a4da 100644
--- a/services/core/java/com/android/server/integrity/model/AtomicFormula.java
+++ b/services/core/java/com/android/server/integrity/model/AtomicFormula.java
@@ -16,6 +16,9 @@
package com.android.server.integrity.model;
+import static com.android.internal.util.Preconditions.checkArgument;
+import static com.android.internal.util.Preconditions.checkNotNull;
+
import android.annotation.Nullable;
/**
@@ -48,37 +51,45 @@
// The value of a key can take either 1 of 3 forms: String, Integer, or Boolean.
// It cannot have multiple values.
@Nullable
- final String mStringValue;
+ private final String mStringValue;
@Nullable
- final Integer mIntValue;
+ private final Integer mIntValue;
@Nullable
- final Boolean mBoolValue;
+ private final Boolean mBoolValue;
public AtomicFormula(Key key, Operator operator, String stringValue) {
- // TODO: Add validators
- this.mKey = key;
- this.mOperator = operator;
- this.mStringValue = stringValue;
+ validateOperator(key, operator);
+ checkArgument(
+ key == Key.PACKAGE_NAME || key == Key.APP_CERTIFICATE || key == Key.INSTALLER_NAME
+ || key == Key.INSTALLER_CERTIFICATE,
+ String.format("Key %s cannot have string value", key));
+ this.mKey = checkNotNull(key);
+ this.mOperator = checkNotNull(operator);
+ this.mStringValue = checkNotNull(stringValue);
this.mIntValue = null;
this.mBoolValue = null;
}
public AtomicFormula(Key key, Operator operator, Integer intValue) {
- // TODO: Add validators
- this.mKey = key;
- this.mOperator = operator;
+ validateOperator(key, operator);
+ checkArgument(key == Key.VERSION_CODE,
+ String.format("Key %s cannot have integer value", key));
+ this.mKey = checkNotNull(key);
+ this.mOperator = checkNotNull(operator);
this.mStringValue = null;
- this.mIntValue = intValue;
+ this.mIntValue = checkNotNull(intValue);
this.mBoolValue = null;
}
public AtomicFormula(Key key, Operator operator, Boolean boolValue) {
- // TODO: Add validators
- this.mKey = key;
- this.mOperator = operator;
+ validateOperator(key, operator);
+ checkArgument(key == Key.PRE_INSTALLED,
+ String.format("Key %s cannot have boolean value", key));
+ this.mKey = checkNotNull(key);
+ this.mOperator = checkNotNull(operator);
this.mStringValue = null;
this.mIntValue = null;
- this.mBoolValue = boolValue;
+ this.mBoolValue = checkNotNull(boolValue);
}
public Key getKey() {
@@ -100,4 +111,26 @@
public Boolean getBoolValue() {
return mBoolValue;
}
+
+ private void validateOperator(Key key, Operator operator) {
+ boolean validOperator;
+ switch (key) {
+ case PACKAGE_NAME:
+ case APP_CERTIFICATE:
+ case INSTALLER_NAME:
+ case INSTALLER_CERTIFICATE:
+ case PRE_INSTALLED:
+ validOperator = (operator == Operator.EQ);
+ break;
+ case VERSION_CODE:
+ validOperator = true;
+ break;
+ default:
+ validOperator = false;
+ }
+ if (!validOperator) {
+ throw new IllegalArgumentException(
+ String.format("Invalid operator %s used for key %s", operator, key));
+ }
+ }
}
diff --git a/services/core/java/com/android/server/integrity/model/EvaluationOutcome.java b/services/core/java/com/android/server/integrity/model/EvaluationOutcome.java
new file mode 100644
index 0000000..dc30dc3
--- /dev/null
+++ b/services/core/java/com/android/server/integrity/model/EvaluationOutcome.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2019 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.integrity.model;
+
+/**
+ * A class encapsulating the result from the evaluation engine after evaluating rules against app
+ * install metadata.
+ *
+ * <p>It contains the outcome effect (whether to allow or block the install), and the rule causing
+ * that effect.
+ */
+public final class EvaluationOutcome {
+
+ public enum Effect {
+ ALLOW,
+ DENY
+ }
+
+ private final Effect mEffect;
+ private final Rule mRule;
+
+ private EvaluationOutcome(Effect effect, Rule rule) {
+ this.mEffect = effect;
+ this.mRule = rule;
+ }
+
+ public Effect getEffect() {
+ return mEffect;
+ }
+
+ public Rule getRule() {
+ return mRule;
+ }
+
+ /**
+ * Create an ALLOW evaluation outcome.
+ *
+ * @return An evaluation outcome with ALLOW effect and empty rule.
+ */
+ public static EvaluationOutcome allow() {
+ return new EvaluationOutcome(Effect.ALLOW, Rule.EMPTY);
+ }
+
+ /**
+ * Create a DENY evaluation outcome.
+ *
+ * @param rule Rule causing the DENY effect.
+ * @return An evaluation outcome with DENY effect and rule causing that effect.
+ */
+ public static EvaluationOutcome deny(Rule rule) {
+ return new EvaluationOutcome(Effect.DENY, rule);
+ }
+}
diff --git a/services/core/java/com/android/server/integrity/model/OpenFormula.java b/services/core/java/com/android/server/integrity/model/OpenFormula.java
index 6b80f87..e9fa1a3 100644
--- a/services/core/java/com/android/server/integrity/model/OpenFormula.java
+++ b/services/core/java/com/android/server/integrity/model/OpenFormula.java
@@ -16,9 +16,11 @@
package com.android.server.integrity.model;
+import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.internal.util.Preconditions.checkNotNull;
-import android.annotation.Nullable;
+import java.util.Collections;
+import java.util.List;
/**
* Represents a complex formula consisting of other simple and complex formulas.
@@ -34,25 +36,33 @@
}
private final Connector mConnector;
- private final Formula mMainFormula;
- private final Formula mAuxiliaryFormula;
+ private final List<Formula> mFormulas;
- public OpenFormula(Connector connector, Formula mainFormula,
- @Nullable Formula auxiliaryFormula) {
+ public OpenFormula(Connector connector, List<Formula> formulas) {
+ validateFormulas(connector, formulas);
this.mConnector = checkNotNull(connector);
- this.mMainFormula = checkNotNull(mainFormula);
- this.mAuxiliaryFormula = auxiliaryFormula;
+ this.mFormulas = Collections.unmodifiableList(checkNotNull(formulas));
}
public Connector getConnector() {
return mConnector;
}
- public Formula getMainFormula() {
- return mMainFormula;
+ public List<Formula> getFormulas() {
+ return mFormulas;
}
- public Formula getAuxiliaryFormula() {
- return mAuxiliaryFormula;
+ private void validateFormulas(Connector connector, List<Formula> formulas) {
+ switch (connector) {
+ case AND:
+ case OR:
+ checkArgument(formulas.size() >= 2,
+ String.format("Connector %s must have at least 2 formulas", connector));
+ break;
+ case NOT:
+ checkArgument(formulas.size() == 1,
+ String.format("Connector %s must have 1 formula only", connector));
+ break;
+ }
}
}
diff --git a/services/core/java/com/android/server/integrity/model/Rule.java b/services/core/java/com/android/server/integrity/model/Rule.java
index 4fd40c1..3d233ab 100644
--- a/services/core/java/com/android/server/integrity/model/Rule.java
+++ b/services/core/java/com/android/server/integrity/model/Rule.java
@@ -25,7 +25,7 @@
*/
public final class Rule {
- enum Effect {
+ public enum Effect {
DENY
}
diff --git a/services/core/java/com/android/server/notification/GroupHelper.java b/services/core/java/com/android/server/notification/GroupHelper.java
index b1cd627..9cb8a01 100644
--- a/services/core/java/com/android/server/notification/GroupHelper.java
+++ b/services/core/java/com/android/server/notification/GroupHelper.java
@@ -16,9 +16,13 @@
package com.android.server.notification;
import android.service.notification.StatusBarNotification;
+import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
@@ -37,6 +41,11 @@
private final Callback mCallback;
private final int mAutoGroupAtCount;
+ // count the number of ongoing notifications per group
+ // userId -> (package name -> (group Id -> (set of notification keys)))
+ final ArrayMap<String, ArraySet<String>>
+ mOngoingGroupCount = new ArrayMap<>();
+
// Map of user : <Map of package : notification keys>. Only contains notifications that are not
// grouped by the app (aka no group or sort key).
Map<Integer, Map<String, LinkedHashSet<String>>> mUngroupedNotifications = new HashMap<>();
@@ -46,10 +55,52 @@
mCallback = callback;
}
+ private String generatePackageGroupKey(int userId, String pkg, String group) {
+ return userId + "|" + pkg + "|" + group;
+ }
+
+ @VisibleForTesting
+ protected int getOngoingGroupCount(int userId, String pkg, String group) {
+ String key = generatePackageGroupKey(userId, pkg, group);
+ return mOngoingGroupCount.getOrDefault(key, new ArraySet<>(0)).size();
+ }
+
+ private void addToOngoingGroupCount(StatusBarNotification sbn, boolean add) {
+ if (sbn.getNotification().isGroupSummary()) return;
+ if (!sbn.isOngoing() && add) return;
+ String group = sbn.getGroup();
+ if (group == null) return;
+ int userId = sbn.getUser().getIdentifier();
+ String key = generatePackageGroupKey(userId, sbn.getPackageName(), group);
+ ArraySet<String> notifications = mOngoingGroupCount.getOrDefault(key, new ArraySet<>(0));
+ if (add) {
+ notifications.add(sbn.getKey());
+ mOngoingGroupCount.put(key, notifications);
+ } else {
+ notifications.remove(sbn.getKey());
+ // we dont need to put it back if it is default
+ }
+ String combinedKey = generatePackageGroupKey(userId, sbn.getPackageName(), group);
+ boolean needsOngoingFlag = notifications.size() > 0;
+ mCallback.updateAutogroupSummary(sbn.getKey(), needsOngoingFlag);
+ }
+
+ public void onNotificationUpdated(StatusBarNotification childSbn,
+ boolean autogroupSummaryExists) {
+ if (childSbn.getGroup() != AUTOGROUP_KEY
+ || childSbn.getNotification().isGroupSummary()) return;
+ if (childSbn.isOngoing()) {
+ addToOngoingGroupCount(childSbn, true);
+ } else {
+ addToOngoingGroupCount(childSbn, false);
+ }
+ }
+
public void onNotificationPosted(StatusBarNotification sbn, boolean autogroupSummaryExists) {
if (DEBUG) Log.i(TAG, "POSTED " + sbn.getKey());
try {
List<String> notificationsToGroup = new ArrayList<>();
+ if (autogroupSummaryExists) addToOngoingGroupCount(sbn, true);
if (!sbn.isAppGroup()) {
// Not grouped by the app, add to the list of notifications for the app;
// send grouping update if app exceeds the autogrouping limit.
@@ -90,6 +141,7 @@
public void onNotificationRemoved(StatusBarNotification sbn) {
try {
+ addToOngoingGroupCount(sbn, false);
maybeUngroup(sbn, true, sbn.getUserId());
} catch (Exception e) {
Slog.e(TAG, "Error processing canceled notification", e);
@@ -159,5 +211,6 @@
void removeAutoGroup(String key);
void addAutoGroupSummary(int userId, String pkg, String triggeringKey);
void removeAutoGroupSummary(int user, String pkg);
+ void updateAutogroupSummary(String key, boolean needsOngoingFlag);
}
}
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 48b0fd6..8560ae6 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -185,7 +185,7 @@
}
protected void addDefaultComponentOrPackage(String packageOrComponent) {
- if (packageOrComponent != null) {
+ if (!TextUtils.isEmpty(packageOrComponent)) {
synchronized (mDefaultsLock) {
ComponentName cn = ComponentName.unflattenFromString(packageOrComponent);
if (cn == null) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 3341991..d7efa1b 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -522,7 +522,6 @@
}
-
void loadDefaultApprovedServices(int userId) {
String defaultListenerAccess = getContext().getResources().getString(
com.android.internal.R.string.config_defaultListenerAccessPackages);
@@ -530,6 +529,9 @@
String[] listeners =
defaultListenerAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR);
for (int i = 0; i < listeners.length; i++) {
+ if (TextUtils.isEmpty(listeners[i])) {
+ continue;
+ }
ArraySet<ComponentName> approvedListeners =
mListeners.queryPackageForServices(listeners[i],
MATCH_DIRECT_BOOT_AWARE
@@ -546,6 +548,9 @@
if (defaultDndAccess != null) {
String[] dnds = defaultDndAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR);
for (int i = 0; i < dnds.length; i++) {
+ if (TextUtils.isEmpty(dnds[i])) {
+ continue;
+ }
mConditionProviders.addDefaultComponentOrPackage(dnds[i]);
}
}
@@ -564,12 +569,14 @@
.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)));
for (int i = 0; i < assistants.size(); i++) {
String cnString = assistants.valueAt(i);
+ if (TextUtils.isEmpty(cnString)) {
+ continue;
+ }
mAssistants.addDefaultComponentOrPackage(cnString);
}
}
protected void allowDefaultApprovedServices(int userId) {
-
ArraySet<ComponentName> defaultListeners = mListeners.getDefaultComponents();
for (int i = 0; i < defaultListeners.size(); i++) {
ComponentName cn = defaultListeners.valueAt(i);
@@ -594,6 +601,40 @@
}
}
+ /**
+ * This method will update the flags of the summary.
+ * It will set it to FLAG_ONGOING_EVENT if any of its group members
+ * has the same flag. It will delete the flag otherwise
+ * @param userId user id of the autogroup summary
+ * @param pkg package of the autogroup summary
+ * @param needsOngoingFlag true if the group has at least one ongoing notification
+ */
+ @GuardedBy("mNotificationLock")
+ protected void updateAutobundledSummaryFlags(int userId, String pkg, boolean needsOngoingFlag) {
+ ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
+ if (summaries == null) {
+ return;
+ }
+ String summaryKey = summaries.get(pkg);
+ if (summaryKey == null) {
+ return;
+ }
+ NotificationRecord summary = mNotificationsByKey.get(summaryKey);
+ if (summary == null) {
+ return;
+ }
+ int oldFlags = summary.sbn.getNotification().flags;
+ if (needsOngoingFlag) {
+ summary.sbn.getNotification().flags |= FLAG_ONGOING_EVENT;
+ } else {
+ summary.sbn.getNotification().flags &= ~FLAG_ONGOING_EVENT;
+ }
+
+ if (summary.sbn.getNotification().flags != oldFlags) {
+ mHandler.post(new EnqueueNotificationRunnable(userId, summary));
+ }
+ }
+
private void allowDndPackage(String packageName) {
try {
getBinderService().setNotificationPolicyAccessGranted(packageName, true);
@@ -1910,7 +1951,6 @@
});
}
-
private GroupHelper getGroupHelper() {
mAutoGroupAtCount =
getContext().getResources().getInteger(R.integer.config_autoGroupAtCount);
@@ -1940,6 +1980,15 @@
clearAutogroupSummaryLocked(userId, pkg);
}
}
+
+ @Override
+ public void updateAutogroupSummary(String key, boolean needsOngoingFlag) {
+ synchronized (mNotificationLock) {
+ NotificationRecord r = mNotificationsByKey.get(key);
+ updateAutobundledSummaryFlags(r.getUser().getIdentifier(),
+ r.sbn.getPackageName(), needsOngoingFlag);
+ }
+ }
});
}
@@ -5007,12 +5056,13 @@
final int contentViewSize = contentView.estimateMemoryUsage();
if (contentViewSize > mWarnRemoteViewsSizeBytes
&& contentViewSize < mStripRemoteViewsSizeBytes) {
- Slog.w(TAG, "RemoteViews too large on tag: " + tag + " id: " + id
+ Slog.w(TAG, "RemoteViews too large on pkg: " + pkg + " tag: " + tag + " id: " + id
+ " this might be stripped in a future release");
}
if (contentViewSize >= mStripRemoteViewsSizeBytes) {
mUsageStats.registerImageRemoved(pkg);
- Slog.w(TAG, "Removed too large RemoteViews on tag: " + tag + " id: " + id);
+ Slog.w(TAG,
+ "Removed too large RemoteViews on pkg: " + pkg + " tag: " + tag + " id: " + id);
return true;
}
return false;
@@ -5754,6 +5804,10 @@
n, hasAutoGroupSummaryLocked(n));
}
});
+ } else if (oldSbn != null) {
+ final NotificationRecord finalRecord = r;
+ mHandler.post(() -> mGroupHelper.onNotificationUpdated(
+ finalRecord.sbn, hasAutoGroupSummaryLocked(n)));
}
} else {
Slog.e(TAG, "Not posting notification without small icon: " + notification);
diff --git a/services/core/java/com/android/server/pm/ComponentResolver.java b/services/core/java/com/android/server/pm/ComponentResolver.java
index 8facce1..976cdfb 100644
--- a/services/core/java/com/android/server/pm/ComponentResolver.java
+++ b/services/core/java/com/android/server/pm/ComponentResolver.java
@@ -23,6 +23,7 @@
import static com.android.server.pm.PackageManagerService.DEBUG_REMOVE;
import static com.android.server.pm.PackageManagerService.fixProcessName;
+import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
@@ -219,12 +220,14 @@
}
}
+ @Nullable
List<ResolveInfo> queryActivities(Intent intent, String resolvedType, int flags, int userId) {
synchronized (mLock) {
return mActivities.queryIntent(intent, resolvedType, flags, userId);
}
}
+ @Nullable
List<ResolveInfo> queryActivities(Intent intent, String resolvedType, int flags,
List<PackageParser.Activity> activities, int userId) {
synchronized (mLock) {
@@ -233,12 +236,14 @@
}
}
+ @Nullable
List<ResolveInfo> queryProviders(Intent intent, String resolvedType, int flags, int userId) {
synchronized (mLock) {
return mProviders.queryIntent(intent, resolvedType, flags, userId);
}
}
+ @Nullable
List<ResolveInfo> queryProviders(Intent intent, String resolvedType, int flags,
List<PackageParser.Provider> providers, int userId) {
synchronized (mLock) {
@@ -246,6 +251,7 @@
}
}
+ @Nullable
List<ProviderInfo> queryProviders(String processName, String metaDataKey, int uid, int flags,
int userId) {
if (!sUserManager.exists(userId)) {
@@ -285,6 +291,7 @@
return providerList;
}
+ @Nullable
ProviderInfo queryProvider(String authority, int flags, int userId) {
synchronized (mLock) {
final PackageParser.Provider p = mProvidersByAuthority.get(authority);
@@ -326,12 +333,14 @@
}
}
+ @Nullable
List<ResolveInfo> queryReceivers(Intent intent, String resolvedType, int flags, int userId) {
synchronized (mLock) {
return mReceivers.queryIntent(intent, resolvedType, flags, userId);
}
}
+ @Nullable
List<ResolveInfo> queryReceivers(Intent intent, String resolvedType, int flags,
List<PackageParser.Activity> receivers, int userId) {
synchronized (mLock) {
@@ -339,12 +348,14 @@
}
}
+ @Nullable
List<ResolveInfo> queryServices(Intent intent, String resolvedType, int flags, int userId) {
synchronized (mLock) {
return mServices.queryIntent(intent, resolvedType, flags, userId);
}
}
+ @Nullable
List<ResolveInfo> queryServices(Intent intent, String resolvedType, int flags,
List<PackageParser.Service> services, int userId) {
synchronized (mLock) {
@@ -1355,6 +1366,7 @@
return super.queryIntent(intent, resolvedType, defaultOnly, userId);
}
+ @Nullable
List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags,
int userId) {
if (!sUserManager.exists(userId)) {
@@ -1366,6 +1378,7 @@
userId);
}
+ @Nullable
List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType,
int flags, List<PackageParser.Provider> packageProviders, int userId) {
if (!sUserManager.exists(userId)) {
diff --git a/core/java/android/content/pm/PackageList.java b/services/core/java/com/android/server/pm/PackageList.java
similarity index 96%
rename from core/java/android/content/pm/PackageList.java
rename to services/core/java/com/android/server/pm/PackageList.java
index e3eb2c5..60bc8a8 100644
--- a/core/java/android/content/pm/PackageList.java
+++ b/services/core/java/com/android/server/pm/PackageList.java
@@ -14,10 +14,11 @@
* limitations under the License.
*/
-package android.content.pm;
+package com.android.server.pm;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageManagerInternal.PackageListObserver;
import com.android.server.LocalServices;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index b85009b..67339c8 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -162,7 +162,6 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageInfoLite;
import android.content.pm.PackageInstaller;
-import android.content.pm.PackageList;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.LegacyPackageDeleteObserver;
import android.content.pm.PackageManager.ModuleInfoFlags;
@@ -3048,7 +3047,7 @@
// Resolve protected action filters. Only the setup wizard is allowed to
// have a high priority filter for these actions.
- mSetupWizardPackage = getSetupWizardPackageName();
+ mSetupWizardPackage = getSetupWizardPackageNameImpl();
mComponentResolver.fixProtectedFilterPriorities();
mSystemTextClassifierPackage = getSystemTextClassifierPackageName();
@@ -6976,7 +6975,7 @@
* @param intent
* @return A filtered list of resolved activities.
*/
- private List<ResolveInfo> applyPostResolutionFilter(List<ResolveInfo> resolveInfos,
+ private List<ResolveInfo> applyPostResolutionFilter(@NonNull List<ResolveInfo> resolveInfos,
String ephemeralPkgName, boolean allowDynamicSplits, int filterCallingUid,
boolean resolveForStart, int userId, Intent intent) {
final boolean blockInstant = intent.isWebIntent() && areWebInstantAppsDisabled(userId);
@@ -7633,6 +7632,9 @@
if (pkgName == null) {
final List<ResolveInfo> result =
mComponentResolver.queryReceivers(intent, resolvedType, flags, userId);
+ if (result == null) {
+ return Collections.emptyList();
+ }
return applyPostResolutionFilter(
result, instantAppPkgName, allowDynamicSplits, callingUid, false, userId,
intent);
@@ -7641,6 +7643,9 @@
if (pkg != null) {
final List<ResolveInfo> result = mComponentResolver.queryReceivers(
intent, resolvedType, flags, pkg.receivers, userId);
+ if (result == null) {
+ return Collections.emptyList();
+ }
return applyPostResolutionFilter(
result, instantAppPkgName, allowDynamicSplits, callingUid, false, userId,
intent);
@@ -7735,15 +7740,25 @@
synchronized (mLock) {
String pkgName = intent.getPackage();
if (pkgName == null) {
+ final List<ResolveInfo> resolveInfos = mComponentResolver.queryServices(intent,
+ resolvedType, flags, userId);
+ if (resolveInfos == null) {
+ return Collections.emptyList();
+ }
return applyPostServiceResolutionFilter(
- mComponentResolver.queryServices(intent, resolvedType, flags, userId),
+ resolveInfos,
instantAppPkgName);
}
final PackageParser.Package pkg = mPackages.get(pkgName);
if (pkg != null) {
+ final List<ResolveInfo> resolveInfos = mComponentResolver.queryServices(intent,
+ resolvedType, flags, pkg.services,
+ userId);
+ if (resolveInfos == null) {
+ return Collections.emptyList();
+ }
return applyPostServiceResolutionFilter(
- mComponentResolver.queryServices(intent, resolvedType, flags, pkg.services,
- userId),
+ resolveInfos,
instantAppPkgName);
}
return Collections.emptyList();
@@ -7853,15 +7868,25 @@
synchronized (mLock) {
String pkgName = intent.getPackage();
if (pkgName == null) {
+ final List<ResolveInfo> resolveInfos = mComponentResolver.queryProviders(intent,
+ resolvedType, flags, userId);
+ if (resolveInfos == null) {
+ return Collections.emptyList();
+ }
return applyPostContentProviderResolutionFilter(
- mComponentResolver.queryProviders(intent, resolvedType, flags, userId),
+ resolveInfos,
instantAppPkgName);
}
final PackageParser.Package pkg = mPackages.get(pkgName);
if (pkg != null) {
+ final List<ResolveInfo> resolveInfos = mComponentResolver.queryProviders(intent,
+ resolvedType, flags,
+ pkg.providers, userId);
+ if (resolveInfos == null) {
+ return Collections.emptyList();
+ }
return applyPostContentProviderResolutionFilter(
- mComponentResolver.queryProviders(intent, resolvedType, flags,
- pkg.providers, userId),
+ resolveInfos,
instantAppPkgName);
}
return Collections.emptyList();
@@ -13247,22 +13272,18 @@
return false;
}
- boolean ensureVerifyAppsEnabled = isUserRestricted(userId, UserManager.ENSURE_VERIFY_APPS);
-
// Check if installing from ADB
if ((installFlags & PackageManager.INSTALL_FROM_ADB) != 0) {
// Do not run verification in a test harness environment
if (ActivityManager.isRunningInTestHarness()) {
return false;
}
- if (ensureVerifyAppsEnabled) {
+ if (isUserRestricted(userId, UserManager.ENSURE_VERIFY_APPS)) {
return true;
}
// Check if the developer does not want package verification for ADB installs
- if (android.provider.Settings.Global.getInt(mContext.getContentResolver(),
- android.provider.Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, 1) == 0) {
- return false;
- }
+ return Global.getInt(mContext.getContentResolver(),
+ Global.PACKAGE_VERIFIER_INCLUDE_ADB, 1) != 0;
} else {
// only when not installed from ADB, skip verification for instant apps when
// the installer and verifier are the same.
@@ -13280,14 +13301,8 @@
} catch (SecurityException ignore) { }
}
}
- }
-
- if (ensureVerifyAppsEnabled) {
return true;
}
-
- return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
- android.provider.Settings.Global.PACKAGE_VERIFIER_ENABLE, 1) == 1;
}
@Override
@@ -15080,19 +15095,6 @@
return disabled;
}
- @GuardedBy("mLock")
- private void setInstallerPackageNameLPw(PackageParser.Package pkg,
- String installerPackageName) {
- // Enable the parent package
- mSettings.setInstallerPackageName(pkg.packageName, installerPackageName);
- // Enable the child packages
- final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
- for (int i = 0; i < childCount; i++) {
- PackageParser.Package childPkg = pkg.childPackages.get(i);
- mSettings.setInstallerPackageName(childPkg.packageName, installerPackageName);
- }
- }
-
private void updateSettingsLI(PackageParser.Package newPackage, String installerPackageName,
int[] allUsers, PackageInstalledInfo res, UserHandle user, int installReason) {
// Update the parent package setting
@@ -19675,7 +19677,7 @@
set, comp, userId);
}
- private @Nullable String getSetupWizardPackageName() {
+ private @Nullable String getSetupWizardPackageNameImpl() {
final Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_SETUP_WIZARD);
@@ -19782,6 +19784,14 @@
return systemCaptionsServiceComponentName.getPackageName();
}
+ @Override
+ public String getSetupWizardPackageName() {
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ throw new SecurityException("Non-system caller");
+ }
+ return mPmInternal.getSetupWizardPackageName();
+ }
+
public String getIncidentReportApproverPackageName() {
return mContext.getString(R.string.config_incidentReportApproverPackage);
}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index ebba128..8253b392 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -1200,12 +1200,20 @@
return mUsers.get(userId) != null;
}
+ private int mLastLockedUser = -1;
+
/** Return the per-user state. */
@GuardedBy("mLock")
@NonNull
ShortcutUser getUserShortcutsLocked(@UserIdInt int userId) {
if (!isUserUnlockedL(userId)) {
- wtf("User still locked");
+ // Only do wtf once for each user. (until the user is unlocked)
+ if (userId != mLastLockedUser) {
+ wtf("User still locked");
+ mLastLockedUser = userId;
+ }
+ } else {
+ mLastLockedUser = -1;
}
ShortcutUser userPackages = mUsers.get(userId);
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 8431fa3..95baa01 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -209,7 +209,8 @@
| UserInfo.FLAG_DEMO;
@VisibleForTesting
- static final int MIN_USER_ID = 10;
+ static final int MIN_USER_ID = UserHandle.MIN_SECONDARY_USER_ID;
+
// We need to keep process uid within Integer.MAX_VALUE.
@VisibleForTesting
static final int MAX_USER_ID = Integer.MAX_VALUE / UserHandle.PER_USER_RANGE;
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 4213168..89908f0 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -53,7 +53,6 @@
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
-import android.app.AppOpsManager;
import android.app.ApplicationPackageManager;
import android.app.IActivityManager;
import android.content.Context;
@@ -793,13 +792,13 @@
final CheckPermissionDelegate checkPermissionDelegate;
synchronized (mLock) {
- if (mCheckPermissionDelegate == null) {
- return checkPermissionImpl(permName, pkgName, userId);
- }
checkPermissionDelegate = mCheckPermissionDelegate;
}
+ if (checkPermissionDelegate == null) {
+ return checkPermissionImpl(permName, pkgName, userId);
+ }
return checkPermissionDelegate.checkPermission(permName, pkgName, userId,
- PermissionManagerService.this::checkPermissionImpl);
+ this::checkPermissionImpl);
}
private int checkPermissionImpl(String permName, String pkgName, int userId) {
@@ -845,23 +844,7 @@
private boolean checkSinglePermissionInternal(int uid,
@NonNull PermissionsState permissionsState, @NonNull String permissionName) {
- boolean hasPermission = permissionsState.hasPermission(permissionName,
- UserHandle.getUserId(uid));
-
- if (!hasPermission && mSettings.isPermissionRuntime(permissionName)) {
- final String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid);
- final int packageNamesSize = packageNames != null ? packageNames.length : 0;
- for (int i = 0; i < packageNamesSize; i++) {
- final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageNames[i]);
- if (pkg != null && pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M
- && pkg.requestedPermissions.contains(permissionName)) {
- hasPermission = true;
- break;
- }
- }
- }
-
- if (!hasPermission) {
+ if (!permissionsState.hasPermission(permissionName, UserHandle.getUserId(uid))) {
return false;
}
@@ -885,13 +868,13 @@
final CheckPermissionDelegate checkPermissionDelegate;
synchronized (mLock) {
- if (mCheckPermissionDelegate == null) {
- return checkUidPermissionImpl(permName, uid);
- }
checkPermissionDelegate = mCheckPermissionDelegate;
}
+ if (checkPermissionDelegate == null) {
+ return checkUidPermissionImpl(permName, uid);
+ }
return checkPermissionDelegate.checkUidPermission(permName, uid,
- PermissionManagerService.this::checkUidPermissionImpl);
+ this::checkUidPermissionImpl);
}
private int checkUidPermissionImpl(String permName, int uid) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 88b1793..c851cc6 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -23,6 +23,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.content.Context.CONTEXT_RESTRICTED;
import static android.content.Context.WINDOW_SERVICE;
+import static android.content.pm.PackageManager.FEATURE_AUTOMOTIVE;
import static android.content.pm.PackageManager.FEATURE_HDMI_CEC;
import static android.content.pm.PackageManager.FEATURE_LEANBACK;
import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
@@ -385,6 +386,7 @@
BurnInProtectionHelper mBurnInProtectionHelper;
private DisplayFoldController mDisplayFoldController;
AppOpsManager mAppOpsManager;
+ private boolean mHasFeatureAuto;
private boolean mHasFeatureWatch;
private boolean mHasFeatureLeanback;
private boolean mHasFeatureHdmiCec;
@@ -1753,6 +1755,7 @@
mDisplayManager = mContext.getSystemService(DisplayManager.class);
mHasFeatureWatch = mContext.getPackageManager().hasSystemFeature(FEATURE_WATCH);
mHasFeatureLeanback = mContext.getPackageManager().hasSystemFeature(FEATURE_LEANBACK);
+ mHasFeatureAuto = mContext.getPackageManager().hasSystemFeature(FEATURE_AUTOMOTIVE);
mHasFeatureHdmiCec = mContext.getPackageManager().hasSystemFeature(FEATURE_HDMI_CEC);
mAccessibilityShortcutController =
new AccessibilityShortcutController(mContext, new Handler(), mCurrentUserId);
@@ -4540,6 +4543,12 @@
private void wakeUpFromPowerKey(long eventTime) {
wakeUp(eventTime, mAllowTheaterModeWakeFromPowerKey,
PowerManager.WAKE_REASON_POWER_BUTTON, "android.policy:POWER");
+
+ // Turn on the connected TV and switch HDMI input if we're a HDMI playback device.
+ final HdmiControl hdmiControl = getHdmiControl();
+ if (hdmiControl != null) {
+ hdmiControl.turnOnTv();
+ }
}
private boolean wakeUp(long wakeTime, boolean wakeInTheaterMode, @WakeReason int reason,
@@ -4572,7 +4581,7 @@
// ... eventually calls finishWindowsDrawn which will finalize our screen turn on
// as well as enabling the orientation change logic/sensor.
mWindowManagerInternal.waitForAllWindowsDrawn(mWindowManagerDrawCallback,
- WAITING_FOR_DRAWN_TIMEOUT);
+ WAITING_FOR_DRAWN_TIMEOUT, INVALID_DISPLAY);
}
// Called on the DisplayManager's DisplayPowerController thread.
@@ -5222,7 +5231,7 @@
awakenDreams();
}
- if (!isUserSetupComplete()) {
+ if (!mHasFeatureAuto && !isUserSetupComplete()) {
Slog.i(TAG, "Not going home because user setup is in progress.");
return;
}
diff --git a/services/core/java/com/android/server/slice/SliceManagerService.java b/services/core/java/com/android/server/slice/SliceManagerService.java
index 5fd2ab87..3b2f324 100644
--- a/services/core/java/com/android/server/slice/SliceManagerService.java
+++ b/services/core/java/com/android/server/slice/SliceManagerService.java
@@ -180,8 +180,13 @@
verifyCaller(pkg);
enforceAccess(pkg, uri);
uri = maybeAddUserId(uri, Binder.getCallingUserHandle().getIdentifier());
- if (getPinnedSlice(uri).unpin(pkg, token)) {
- removePinnedSlice(uri);
+ try {
+ PinnedSliceState slice = getPinnedSlice(uri);
+ if (slice != null && slice.unpin(pkg, token)) {
+ removePinnedSlice(uri);
+ }
+ } catch (IllegalStateException exception) {
+ Slog.w(TAG, exception.getMessage());
}
}
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 59f051b..10415f5 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -271,11 +271,11 @@
}
}
- /** NOTE: This has to be called within a surface transaction. */
- public void drawMagnifiedRegionBorderIfNeededLocked(int displayId) {
+ public void drawMagnifiedRegionBorderIfNeededLocked(int displayId,
+ SurfaceControl.Transaction t) {
final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
if (displayMagnifier != null) {
- displayMagnifier.drawMagnifiedRegionBorderIfNeededLocked();
+ displayMagnifier.drawMagnifiedRegionBorderIfNeededLocked(t);
}
// Not relevant for the window observer.
}
@@ -431,7 +431,7 @@
Slog.i(LOG_TAG, "Rotation: " + Surface.rotationToString(rotation)
+ " displayId: " + displayContent.getDisplayId());
}
- mMagnifedViewport.onRotationChangedLocked();
+ mMagnifedViewport.onRotationChangedLocked(displayContent.getPendingTransaction());
mHandler.sendEmptyMessage(MyHandler.MESSAGE_NOTIFY_ROTATION_CHANGED);
}
@@ -536,9 +536,8 @@
.sendToTarget();
}
- /** NOTE: This has to be called within a surface transaction. */
- public void drawMagnifiedRegionBorderIfNeededLocked() {
- mMagnifedViewport.drawWindowIfNeededLocked();
+ public void drawMagnifiedRegionBorderIfNeededLocked(SurfaceControl.Transaction t) {
+ mMagnifedViewport.drawWindowIfNeededLocked(t);
}
private final class MagnifiedViewport {
@@ -744,7 +743,7 @@
return letterboxBounds;
}
- public void onRotationChangedLocked() {
+ public void onRotationChangedLocked(SurfaceControl.Transaction t) {
// If we are showing the magnification border, hide it immediately so
// the user does not see strange artifacts during rotation. The screenshot
// used for rotation already has the border. After the rotation is complete
@@ -758,7 +757,7 @@
mHandler.sendMessageDelayed(message, delay);
}
recomputeBoundsLocked();
- mWindow.updateSize();
+ mWindow.updateSize(t);
}
public void setMagnifiedRegionBorderShownLocked(boolean shown, boolean animate) {
@@ -784,10 +783,9 @@
return mMagnificationSpec;
}
- /** NOTE: This has to be called within a surface transaction. */
- public void drawWindowIfNeededLocked() {
+ public void drawWindowIfNeededLocked(SurfaceControl.Transaction t) {
recomputeBoundsLocked();
- mWindow.drawIfNeeded();
+ mWindow.drawIfNeeded(t);
}
public void destroyWindow() {
@@ -837,10 +835,11 @@
/* ignore */
}
mSurfaceControl = surfaceControl;
- mSurfaceControl.setLayer(mService.mPolicy.getWindowLayerFromTypeLw(
- TYPE_MAGNIFICATION_OVERLAY)
- * WindowManagerService.TYPE_LAYER_MULTIPLIER);
- mSurfaceControl.setPosition(0, 0);
+ mService.mTransactionFactory.get().setLayer(mSurfaceControl,
+ mService.mPolicy.getWindowLayerFromTypeLw(TYPE_MAGNIFICATION_OVERLAY)
+ * WindowManagerService.TYPE_LAYER_MULTIPLIER)
+ .setPosition(mSurfaceControl, 0, 0)
+ .apply();
mSurface.copyFrom(mSurfaceControl);
mAnimationController = new AnimationController(context,
@@ -905,10 +904,10 @@
}
}
- public void updateSize() {
+ public void updateSize(SurfaceControl.Transaction t) {
synchronized (mService.mGlobalLock) {
mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
- mSurfaceControl.setBufferSize(mTempPoint.x, mTempPoint.y);
+ t.setBufferSize(mSurfaceControl, mTempPoint.x, mTempPoint.y);
invalidate(mDirtyRect);
}
}
@@ -923,8 +922,7 @@
mService.scheduleAnimationLocked();
}
- /** NOTE: This has to be called within a surface transaction. */
- public void drawIfNeeded() {
+ public void drawIfNeeded(SurfaceControl.Transaction t) {
synchronized (mService.mGlobalLock) {
if (!mInvalidated) {
return;
@@ -959,9 +957,9 @@
canvas.drawPath(path, mPaint);
mSurface.unlockCanvasAndPost(canvas);
- mSurfaceControl.show();
+ t.show(mSurfaceControl);
} else {
- mSurfaceControl.hide();
+ t.hide(mSurfaceControl);
}
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index e54daf2..4f52d9d 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -90,7 +90,6 @@
import static android.view.WindowManager.TRANSIT_TASK_CLOSE;
import static com.android.server.am.ActivityRecordProto.APP_WINDOW_TOKEN;
-import static com.android.server.am.ActivityRecordProto.CONFIGURATION_CONTAINER;
import static com.android.server.am.ActivityRecordProto.FRONT_OF_TASK;
import static com.android.server.am.ActivityRecordProto.IDENTIFIER;
import static com.android.server.am.ActivityRecordProto.PROC_ID;
@@ -145,9 +144,6 @@
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
-import static com.android.server.wm.IdentifierProto.HASH_CODE;
-import static com.android.server.wm.IdentifierProto.TITLE;
-import static com.android.server.wm.IdentifierProto.USER_ID;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW;
@@ -1578,7 +1574,7 @@
final TaskRecord task = getTaskRecord();
EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
mUserId, System.identityHashCode(this),
- task.taskId, shortComponentName, reason);
+ task.mTaskId, shortComponentName, reason);
final ArrayList<ActivityRecord> activities = task.mActivities;
final int index = activities.indexOf(this);
if (index < (activities.size() - 1)) {
@@ -1727,25 +1723,27 @@
// implied that the current finishing activity should be added into stopping list rather
// than destroy immediately.
final boolean isNextNotYetVisible = next != null && (!next.nowVisible || !next.visible);
- final ActivityStack stack = getActivityStack();
- final boolean notFocusedStack = stack != mRootActivityContainer.getTopDisplayFocusedStack();
+ final boolean notGlobalFocusedStack =
+ getActivityStack() != mRootActivityContainer.getTopDisplayFocusedStack();
if (isVisible && isNextNotYetVisible) {
+ // Add this activity to the list of stopping activities. It will be processed and
+ // destroyed when the next activity reports idle.
addToStopping(false /* scheduleIdle */, false /* idleDelayed */,
"completeFinishing");
- if (DEBUG_STATES) {
- Slog.v(TAG_STATES, "Moving to STOPPING: " + this + " (finish requested)");
- }
setState(STOPPING, "completeFinishing");
- if (notFocusedStack) {
+ if (notGlobalFocusedStack) {
+ // Ensuring visibility and configuration only for non-focused stacks since this
+ // method call is relatively expensive and not necessary for focused stacks.
mRootActivityContainer.ensureVisibilityAndConfig(next, getDisplayId(),
false /* markFrozenIfConfigChanged */, true /* deferResume */);
}
- } else if (isVisible && isState(PAUSED) && getActivityStack().isFocusedStackOnDisplay()
- && !inPinnedWindowingMode()) {
- // TODO(b/137329632): Currently non-focused stack is handled differently.
- addToFinishingAndWaitForIdle();
+ } else if (addToFinishingAndWaitForIdle()) {
+ // We added this activity to the finishing list and something else is becoming resumed.
+ // The activity will complete finishing when the next activity reports idle. No need to
+ // do anything else here.
} else {
- // Not waiting for the next one to become visible - finish right away.
+ // Not waiting for the next one to become visible, and nothing else will be resumed in
+ // place of this activity - requesting destruction right away.
activityRemoved = destroyIfPossible(reason);
}
@@ -1802,13 +1800,20 @@
return activityRemoved;
}
+ /**
+ * Add this activity to the list of finishing and trigger resuming of activities in focused
+ * stacks.
+ * @return {@code true} if some other activity is being resumed as a result of this call.
+ */
@VisibleForTesting
- void addToFinishingAndWaitForIdle() {
+ boolean addToFinishingAndWaitForIdle() {
if (DEBUG_STATES) Slog.v(TAG, "Enqueueing pending finish: " + this);
setState(FINISHING, "addToFinishingAndWaitForIdle");
- mStackSupervisor.mFinishingActivities.add(this);
+ if (!mStackSupervisor.mFinishingActivities.contains(this)) {
+ mStackSupervisor.mFinishingActivities.add(this);
+ }
resumeKeyDispatchingLocked();
- mRootActivityContainer.resumeFocusedStacksTopActivities();
+ return mRootActivityContainer.resumeFocusedStacksTopActivities();
}
/**
@@ -1838,7 +1843,7 @@
}
EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY, mUserId,
- System.identityHashCode(this), getTaskRecord().taskId, shortComponentName, reason);
+ System.identityHashCode(this), getTaskRecord().mTaskId, shortComponentName, reason);
boolean removedFromHistory = false;
@@ -1976,7 +1981,7 @@
// work.
// TODO: If the callers to removeTask() changes such that we have multiple places
// where we are destroying the task, move this back into removeTask()
- mStackSupervisor.removeTaskByIdLocked(task.taskId, false /* killProcess */,
+ mStackSupervisor.removeTaskByIdLocked(task.mTaskId, false /* killProcess */,
!REMOVE_FROM_RECENTS, reason);
}
@@ -2090,7 +2095,7 @@
final String strData = data != null ? data.toSafeString() : null;
EventLog.writeEvent(tag,
- mUserId, System.identityHashCode(this), task.taskId,
+ mUserId, System.identityHashCode(this), task.mTaskId,
shortComponentName, intent.getAction(),
intent.getType(), strData, intent.getFlags());
}
@@ -3244,7 +3249,7 @@
|| (onlyRoot && activityNdx > task.findRootIndex(true /* effectiveRoot */))) {
return INVALID_TASK_ID;
}
- return task.taskId;
+ return task.mTaskId;
}
static ActivityRecord isInStackLocked(IBinder token) {
@@ -3299,8 +3304,8 @@
Bitmap icon;
if (_taskDescription.getIconFilename() == null &&
(icon = _taskDescription.getIcon()) != null) {
- final String iconFilename = createImageFilename(createTime, task.taskId);
- final File iconFile = new File(TaskPersister.getUserImagesDir(task.userId),
+ final String iconFilename = createImageFilename(createTime, task.mTaskId);
+ final File iconFile = new File(TaskPersister.getUserImagesDir(task.mUserId),
iconFilename);
final String iconFilePath = iconFile.getAbsolutePath();
mAtmService.getRecentTasks().saveImage(icon, iconFilePath);
@@ -3359,7 +3364,7 @@
void setRequestedOrientation(int requestedOrientation) {
setOrientation(requestedOrientation, mayFreezeScreenLocked());
mAtmService.getTaskChangeNotificationController().notifyActivityRequestedOrientationChanged(
- task.taskId, requestedOrientation);
+ task.mTaskId, requestedOrientation);
}
private void setOrientation(int requestedOrientation, boolean freezeScreenIfNeeded) {
@@ -4065,7 +4070,7 @@
+ " preserveWindow=" + preserveWindow);
EventLog.writeEvent(andResume ? AM_RELAUNCH_RESUME_ACTIVITY
: AM_RELAUNCH_ACTIVITY, mUserId, System.identityHashCode(this),
- task.taskId, shortComponentName);
+ task.mTaskId, shortComponentName);
startFreezingScreenLocked(0);
@@ -4400,7 +4405,7 @@
@Override
public String toString() {
if (stringName != null) {
- return stringName + " t" + (task == null ? INVALID_TASK_ID : task.taskId) +
+ return stringName + " t" + (task == null ? INVALID_TASK_ID : task.mTaskId) +
(finishing ? " f}" : "") + (mIsExiting ? " mIsExiting=" : "") + "}";
}
StringBuilder sb = new StringBuilder(128);
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 24f58f1..5959254 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -775,7 +775,7 @@
// multi-window mode.
final String packageName = topActivity.info.applicationInfo.packageName;
mService.getTaskChangeNotificationController().notifyActivityForcedResizable(
- topTask.taskId, FORCED_RESIZEABLE_REASON_SPLIT_SCREEN, packageName);
+ topTask.mTaskId, FORCED_RESIZEABLE_REASON_SPLIT_SCREEN, packageName);
}
mService.deferWindowLayout();
@@ -1114,7 +1114,7 @@
final ActivityRecord topRunningActivityLocked(IBinder token, int taskId) {
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
TaskRecord task = mTaskHistory.get(taskNdx);
- if (task.taskId == taskId) {
+ if (task.mTaskId == taskId) {
continue;
}
ArrayList<ActivityRecord> activities = task.mActivities;
@@ -1150,7 +1150,7 @@
TaskRecord taskForIdLocked(int id) {
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
final TaskRecord task = mTaskHistory.get(taskNdx);
- if (task.taskId == id) {
+ if (task.mTaskId == id) {
return task;
}
}
@@ -1345,7 +1345,7 @@
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": voice session");
continue;
}
- if (task.userId != userId) {
+ if (task.mUserId != userId) {
// Looking for a different task.
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": different user");
continue;
@@ -2863,7 +2863,7 @@
next.notifyAppResumed(next.stopped);
EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY, next.mUserId,
- System.identityHashCode(next), next.getTaskRecord().taskId,
+ System.identityHashCode(next), next.getTaskRecord().mTaskId,
next.shortComponentName);
next.sleeping = false;
@@ -2973,7 +2973,7 @@
// The task can't be shown, put non-current user tasks below current user tasks.
while (maxPosition > 0) {
final TaskRecord tmpTask = mTaskHistory.get(maxPosition - 1);
- if (!mStackSupervisor.isCurrentProfileLocked(tmpTask.userId)
+ if (!mStackSupervisor.isCurrentProfileLocked(tmpTask.mUserId)
|| tmpTask.topRunningActivityLocked() == null) {
break;
}
@@ -3026,7 +3026,7 @@
void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,
boolean newTask, boolean keepCurTransition, ActivityOptions options) {
TaskRecord rTask = r.getTaskRecord();
- final int taskId = rTask.taskId;
+ final int taskId = rTask.mTaskId;
final boolean allowMoveToFront = options == null || !options.getAvoidMoveToFront();
// mLaunchTaskBehind tasks get placed at the back of the task stack.
if (!r.mLaunchTaskBehind && allowMoveToFront
@@ -4098,7 +4098,7 @@
Slog.w(TAG, "Force removing " + r + ": app died, no saved state");
EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
r.mUserId, System.identityHashCode(r),
- r.getTaskRecord().taskId, r.shortComponentName,
+ r.getTaskRecord().mTaskId, r.shortComponentName,
"proc died without state saved");
}
} else {
@@ -4223,7 +4223,7 @@
}
mRootActivityContainer.resumeFocusedStacksTopActivities();
- EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, tr.userId, tr.taskId);
+ EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, tr.mUserId, tr.mTaskId);
mService.getTaskChangeNotificationController().notifyTaskMovedToFront(tr.getTaskInfo());
} finally {
getDisplay().continueUpdateImeTarget();
@@ -4520,7 +4520,7 @@
continue;
}
if (task.effectiveUid != callingUid) {
- if (task.userId != userId && !crossUser && !profileIds.contains(task.userId)) {
+ if (task.mUserId != userId && !crossUser && !profileIds.contains(task.mUserId)) {
// Skip if the caller does not have cross user permission or cannot access
// the task's profile
continue;
@@ -4545,7 +4545,7 @@
// For the focused stack top task, update the last stack active time so that it can
// be used to determine the order of the tasks (it may not be set for newly created
// tasks)
- task.lastActiveTime = SystemClock.elapsedRealtime();
+ task.touchActiveTime();
topTask = false;
}
tasksOut.add(task);
@@ -4654,7 +4654,7 @@
if (needSep) {
pw.println("");
}
- pw.println(prefix + "Task id #" + task.taskId);
+ pw.println(prefix + "Task id #" + task.mTaskId);
pw.println(prefix + "mBounds=" + task.getRequestedOverrideBounds());
pw.println(prefix + "mMinWidth=" + task.mMinWidth);
pw.println(prefix + "mMinHeight=" + task.mMinHeight);
@@ -4732,7 +4732,7 @@
final boolean removed = mTaskHistory.remove(task);
if (removed) {
- EventLog.writeEvent(EventLogTags.AM_REMOVE_TASK, task.taskId, getStackId());
+ EventLog.writeEvent(EventLogTags.AM_REMOVE_TASK, task.mTaskId, getStackId());
}
removeActivitiesFromLRUList(task);
@@ -4884,7 +4884,7 @@
mStackSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(task, prevStack);
} else if (task.voiceSession != null) {
try {
- task.voiceSession.taskStarted(task.intent, task.taskId);
+ task.voiceSession.taskStarted(task.intent, task.mTaskId);
} catch (RemoteException e) {
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 3dff51d..f1284d81 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -821,7 +821,7 @@
+ " with results=" + results + " newIntents=" + newIntents
+ " andResume=" + andResume);
EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY, r.mUserId,
- System.identityHashCode(r), task.taskId, r.shortComponentName);
+ System.identityHashCode(r), task.mTaskId, r.shortComponentName);
if (r.isActivityTypeHome()) {
// Home process is the root process of the task.
updateHomeProcess(task.mActivities.get(0).app);
@@ -1765,7 +1765,7 @@
moveTasksToFullscreenStackLocked(stack, !ON_TOP);
} else {
for (int i = tasks.size() - 1; i >= 0; i--) {
- removeTaskByIdLocked(tasks.get(i).taskId, true /* killProcess */,
+ removeTaskByIdLocked(tasks.get(i).mTaskId, true /* killProcess */,
REMOVE_FROM_RECENTS, "remove-stack");
}
}
@@ -1817,7 +1817,7 @@
// Find any running services associated with this app and stop if needed.
final Message msg = PooledLambda.obtainMessage(ActivityManagerInternal::cleanUpServices,
- mService.mAmInternal, tr.userId, component, new Intent(tr.getBaseIntent()));
+ mService.mAmInternal, tr.mUserId, component, new Intent(tr.getBaseIntent()));
mService.mH.sendMessage(msg);
if (!killProcess) {
@@ -1834,7 +1834,7 @@
SparseArray<WindowProcessController> uids = pmap.valueAt(i);
for (int j = 0; j < uids.size(); j++) {
WindowProcessController proc = uids.valueAt(j);
- if (proc.mUserId != tr.userId) {
+ if (proc.mUserId != tr.mUserId) {
// Don't kill process for a different user.
continue;
}
@@ -1916,7 +1916,7 @@
if (wasTrimmed) {
// Task was trimmed from the recent tasks list -- remove the active task record as well
// since the user won't really be able to go back to it
- removeTaskByIdLocked(task.taskId, killProcess, false /* removeFromRecents */,
+ removeTaskByIdLocked(task.mTaskId, killProcess, false /* removeFromRecents */,
"recent-task-trimmed");
}
task.removedFromRecents();
@@ -2477,7 +2477,7 @@
return;
}
mService.getTaskChangeNotificationController().notifyActivityForcedResizable(
- task.taskId, reason, topActivity.info.applicationInfo.packageName);
+ task.mTaskId, reason, topActivity.info.applicationInfo.packageName);
}
void activityRelaunchedLocked(IBinder token) {
@@ -2699,7 +2699,7 @@
* @param task The task to put into resizing mode
*/
void setResizingDuringAnimation(TaskRecord task) {
- mResizingTasksDuringAnimation.add(task.taskId);
+ mResizingTasksDuringAnimation.add(task.mTaskId);
task.setTaskDockedResizing(true);
}
@@ -2761,7 +2761,7 @@
// If the user must confirm credentials (e.g. when first launching a work app and the
// Work Challenge is present) let startActivityInPackage handle the intercepting.
- if (!mService.mAmInternal.shouldConfirmCredentials(task.userId)
+ if (!mService.mAmInternal.shouldConfirmCredentials(task.mUserId)
&& task.getRootActivity() != null) {
final ActivityRecord targetActivity = task.getTopActivity();
@@ -2770,7 +2770,7 @@
mActivityMetricsLogger.notifyActivityLaunching(task.intent);
try {
mService.moveTaskToFrontLocked(null /* appThread */, null /* callingPackage */,
- task.taskId, 0, options, true /* fromRecents */);
+ task.mTaskId, 0, options, true /* fromRecents */);
// Apply options to prevent pendingOptions be taken by client to make sure
// the override pending app transition will be applied immediately.
targetActivity.applyOptionsLocked();
@@ -2787,7 +2787,7 @@
callingPackage = task.mCallingPackage;
intent = task.intent;
intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
- userId = task.userId;
+ userId = task.mUserId;
return mService.getActivityStartController().startActivityInPackage(
task.mCallingUid, callingPid, callingUid, callingPackage, intent, null, null,
null, 0, 0, options, userId, task, "startActivityFromRecents",
diff --git a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
index cc69b5a..effd154a6 100644
--- a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
@@ -274,7 +274,7 @@
// ConfirmCredentials intent and unassign it, as otherwise the task will move to
// front even if ConfirmCredentials is cancelled.
if (mInTask != null) {
- mIntent.putExtra(EXTRA_TASK_ID, mInTask.taskId);
+ mIntent.putExtra(EXTRA_TASK_ID, mInTask.mTaskId);
mInTask = null;
}
if (mActivityOptions == null) {
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 38e5e3e..9397893 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1557,7 +1557,7 @@
);
if (newTask) {
EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, mStartActivity.mUserId,
- mStartActivity.getTaskRecord().taskId);
+ mStartActivity.getTaskRecord().mTaskId);
}
mStartActivity.logStartActivity(
EventLogTags.AM_CREATE_ACTIVITY, mStartActivity.getTaskRecord());
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 299ab8a..750fc68 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1618,7 +1618,7 @@
// because we don't support returning them across task boundaries. Also, to
// keep backwards compatibility we remove the task from recents when finishing
// task with root activity.
- res = mStackSupervisor.removeTaskByIdLocked(tr.taskId, false /* killProcess */,
+ res = mStackSupervisor.removeTaskByIdLocked(tr.mTaskId, false /* killProcess */,
finishWithRootActivity, "finish-activity");
if (!res) {
Slog.i(TAG, "Removing task failed to finish activity");
@@ -2233,7 +2233,7 @@
final TaskRecord tr = mRootActivityContainer.anyTaskForId(id,
MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
if (tr != null) {
- return tr.lastTaskDescription;
+ return tr.mTaskDescription;
}
}
return null;
@@ -3032,7 +3032,7 @@
}
if (structure != null) {
// Pre-fill the task/activity component for all assist data receivers
- structure.setTaskId(pae.activity.getTaskRecord().taskId);
+ structure.setTaskId(pae.activity.getTaskRecord().mTaskId);
structure.setActivityComponent(pae.activity.mActivityComponent);
structure.setHomeActivity(pae.isHome);
}
@@ -3059,7 +3059,7 @@
// Caller wants result sent back to them.
sendBundle = new Bundle();
sendBundle.putInt(ActivityTaskManagerInternal.ASSIST_TASK_ID,
- pae.activity.getTaskRecord().taskId);
+ pae.activity.getTaskRecord().mTaskId);
sendBundle.putBinder(ActivityTaskManagerInternal.ASSIST_ACTIVITY_ID,
pae.activity.assistToken);
sendBundle.putBundle(ASSIST_KEY_DATA, pae.extras);
@@ -3155,11 +3155,11 @@
stack.removeTask(task, "addAppTask", REMOVE_TASK_MODE_DESTROYING);
return INVALID_TASK_ID;
}
- task.lastTaskDescription.copyFrom(description);
+ task.mTaskDescription.copyFrom(description);
// TODO: Send the thumbnail to WM to store it.
- return task.taskId;
+ return task.mTaskId;
}
} finally {
Binder.restoreCallingIdentity(callingIdent);
@@ -4967,8 +4967,8 @@
if (lastTask != task) {
lastTask = task;
pw.print("TASK "); pw.print(lastTask.affinity);
- pw.print(" id="); pw.print(lastTask.taskId);
- pw.print(" userId="); pw.println(lastTask.userId);
+ pw.print(" id="); pw.print(lastTask.mTaskId);
+ pw.print(" userId="); pw.println(lastTask.mUserId);
if (dumpAll) {
lastTask.dump(pw, " ");
}
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 721de61..a261341 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -1735,13 +1735,13 @@
}
/** @return {@code true} if the compatibility bounds is taking effect. */
- boolean inSizeCompatMode() {
+ boolean hasSizeCompatBounds() {
return mSizeCompatBounds != null;
}
@Override
float getSizeCompatScale() {
- return inSizeCompatMode() ? mSizeCompatScale : super.getSizeCompatScale();
+ return hasSizeCompatBounds() ? mSizeCompatScale : super.getSizeCompatScale();
}
@Override
@@ -2930,7 +2930,7 @@
layer += Z_BOOST_BASE;
}
if (!mNeedsAnimationBoundsLayer) {
- leash.setLayer(layer);
+ t.setLayer(leash, layer);
}
final DisplayContent dc = getDisplayContent();
diff --git a/services/core/java/com/android/server/wm/CircularDisplayMask.java b/services/core/java/com/android/server/wm/CircularDisplayMask.java
index c1ca816..b73b481 100644
--- a/services/core/java/com/android/server/wm/CircularDisplayMask.java
+++ b/services/core/java/com/android/server/wm/CircularDisplayMask.java
@@ -56,7 +56,7 @@
private int mMaskThickness;
CircularDisplayMask(Supplier<Surface> surfaceFactory, DisplayContent dc, int zOrder,
- int screenOffset, int maskThickness) {
+ int screenOffset, int maskThickness, SurfaceControl.Transaction t) {
final Display display = dc.getDisplay();
mSurface = surfaceFactory.get();
mScreenSize = new Point();
@@ -75,10 +75,10 @@
.setFormat(PixelFormat.TRANSLUCENT)
.build();
- ctrl.setLayerStack(display.getLayerStack());
- ctrl.setLayer(zOrder);
- ctrl.setPosition(0, 0);
- ctrl.show();
+ t.setLayerStack(ctrl, display.getLayerStack());
+ t.setLayer(ctrl, zOrder);
+ t.setPosition(ctrl, 0, 0);
+ t.show(ctrl);
mSurface.copyFrom(ctrl);
} catch (OutOfResourcesException e) {
}
@@ -91,7 +91,7 @@
mMaskThickness = maskThickness;
}
- private void drawIfNeeded() {
+ private void drawIfNeeded(SurfaceControl.Transaction t) {
if (!mDrawNeeded || !mVisible || mDimensionsUnequal) {
return;
}
@@ -108,45 +108,46 @@
return;
}
switch (mRotation) {
- case Surface.ROTATION_0:
- case Surface.ROTATION_90:
- // chin bottom or right
- mSurfaceControl.setPosition(0, 0);
- break;
- case Surface.ROTATION_180:
- // chin top
- mSurfaceControl.setPosition(0, -mScreenOffset);
- break;
- case Surface.ROTATION_270:
- // chin left
- mSurfaceControl.setPosition(-mScreenOffset, 0);
- break;
+ case Surface.ROTATION_0:
+ case Surface.ROTATION_90:
+ // chin bottom or right
+ t.setPosition(mSurfaceControl, 0, 0);
+ break;
+ case Surface.ROTATION_180:
+ // chin top
+ t.setPosition(mSurfaceControl, 0, -mScreenOffset);
+ break;
+ case Surface.ROTATION_270:
+ // chin left
+ t.setPosition(mSurfaceControl, -mScreenOffset, 0);
+ break;
}
int circleRadius = mScreenSize.x / 2;
c.drawColor(Color.BLACK);
- // The radius is reduced by mMaskThickness to provide an anti aliasing effect on the display edges.
+ // The radius is reduced by mMaskThickness to provide an anti aliasing effect on the
+ // display edges.
c.drawCircle(circleRadius, circleRadius, circleRadius - mMaskThickness, mPaint);
mSurface.unlockCanvasAndPost(c);
}
// Note: caller responsible for being inside
// Surface.openTransaction() / closeTransaction()
- public void setVisibility(boolean on) {
+ public void setVisibility(boolean on, SurfaceControl.Transaction t) {
if (mSurfaceControl == null) {
return;
}
mVisible = on;
- drawIfNeeded();
+ drawIfNeeded(t);
if (on) {
- mSurfaceControl.show();
+ t.show(mSurfaceControl);
} else {
- mSurfaceControl.hide();
+ t.hide(mSurfaceControl);
}
}
- void positionSurface(int dw, int dh, int rotation) {
+ void positionSurface(int dw, int dh, int rotation, SurfaceControl.Transaction t) {
if (mLastDW == dw && mLastDH == dh && mRotation == rotation) {
return;
}
@@ -154,7 +155,7 @@
mLastDH = dh;
mDrawNeeded = true;
mRotation = rotation;
- drawIfNeeded();
+ drawIfNeeded(t);
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 3b90b7e..ac910cd 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -132,7 +132,6 @@
import static com.android.server.wm.WindowState.EXCLUSION_LEFT;
import static com.android.server.wm.WindowState.EXCLUSION_RIGHT;
import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
-import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW;
import static com.android.server.wm.utils.RegionUtils.forEachRectReverse;
import static com.android.server.wm.utils.RegionUtils.rectListToRegion;
@@ -221,7 +220,7 @@
* particular Display.
*/
class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowContainer>
- implements WindowManagerPolicy.DisplayContentInfo {
+ implements WindowManagerPolicy.DisplayContentInfo, ConfigurationContainerListener {
private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayContent" : TAG_WM;
/** The default scaling mode that scales content automatically. */
@@ -240,7 +239,7 @@
private final int mDisplayId;
// TODO: Remove once unification is complete.
- ActivityDisplay mAcitvityDisplay;
+ ActivityDisplay mActivityDisplay;
/** The containers below are the only child containers the display can have. */
// Contains all window containers that are related to apps (Activities)
@@ -332,7 +331,7 @@
/**
* For default display it contains real metrics, empty for others.
- * @see WindowManagerService#createWatermarkInTransaction()
+ * @see WindowManagerService#createWatermark()
*/
final DisplayMetrics mRealDisplayMetrics = new DisplayMetrics();
@@ -852,7 +851,7 @@
DisplayContent(Display display, WindowManagerService service,
ActivityDisplay activityDisplay) {
super(service);
- mAcitvityDisplay = activityDisplay;
+ mActivityDisplay = activityDisplay;
if (service.mRoot.getDisplayContent(display.getDisplayId()) != null) {
throw new IllegalArgumentException("Display with ID=" + display.getDisplayId()
+ " already exists=" + service.mRoot.getDisplayContent(display.getDisplayId())
@@ -1136,10 +1135,12 @@
* values from being replaced by the initializing {@link #ActivityDisplay}.
*/
void initializeDisplayOverrideConfiguration() {
- if (mAcitvityDisplay != null) {
- mAcitvityDisplay.getRequestedOverrideConfiguration()
- .updateFrom(getRequestedOverrideConfiguration());
+ if (mActivityDisplay == null) {
+ return;
}
+ mActivityDisplay.onRequestedOverrideConfigurationChanged(
+ getResolvedOverrideConfiguration());
+ mActivityDisplay.registerConfigurationChangeListener(this);
}
void reconfigureDisplayLocked() {
@@ -1165,10 +1166,10 @@
}
void sendNewConfiguration() {
- if (!isReady() || mAcitvityDisplay == null) {
+ if (!isReady() || mActivityDisplay == null) {
return;
}
- final boolean configUpdated = mAcitvityDisplay.updateDisplayOverrideConfigurationLocked();
+ final boolean configUpdated = mActivityDisplay.updateDisplayOverrideConfigurationLocked();
if (configUpdated) {
return;
}
@@ -1199,7 +1200,7 @@
if (handled && requestingContainer instanceof ActivityRecord) {
final ActivityRecord activityRecord = (ActivityRecord) requestingContainer;
- final boolean kept = mAcitvityDisplay.updateDisplayOverrideConfigurationLocked(
+ final boolean kept = mActivityDisplay.updateDisplayOverrideConfigurationLocked(
config, activityRecord, false /* deferResume */, null /* result */);
activityRecord.frozenBeforeDestroy = true;
if (!kept) {
@@ -1208,7 +1209,7 @@
} else {
// We have a new configuration to push so we need to update ATMS for now.
// TODO: Clean up display configuration push between ATMS and WMS after unification.
- mAcitvityDisplay.updateDisplayOverrideConfigurationLocked(
+ mActivityDisplay.updateDisplayOverrideConfigurationLocked(
config, null /* starting */, false /* deferResume */, null);
}
return handled;
@@ -2373,6 +2374,9 @@
void removeImmediately() {
mRemovingDisplay = true;
try {
+ if (mActivityDisplay != null) {
+ mActivityDisplay.unregisterConfigurationChangeListener(this);
+ }
if (mParentWindow != null) {
mParentWindow.removeEmbeddedDisplayContent(this);
}
@@ -3514,19 +3518,6 @@
mWmService.mWindowPlacerLocked.performSurfacePlacement();
}
- void waitForAllWindowsDrawn() {
- final WindowManagerPolicy policy = mWmService.mPolicy;
- forAllWindows(w -> {
- final boolean keyguard = policy.isKeyguardHostWindow(w.mAttrs);
- if (w.isVisibleLw() && (w.mAppToken != null || keyguard)) {
- w.mWinAnimator.mDrawState = DRAW_PENDING;
- // Force add to mResizingWindows.
- w.resetLastContentInsets();
- mWmService.mWaitingForDrawn.add(w);
- }
- }, true /* traverseTopToBottom */);
- }
-
// TODO: Super crazy long method that should be broken down...
void applySurfaceChangesTransaction(boolean recoveringMemory) {
final WindowSurfacePlacer surfacePlacer = mWmService.mWindowPlacerLocked;
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index ae3b5f2..d3e42901 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -819,9 +819,12 @@
// We put all tasks into drag resizing mode - wait until all of them have completed the
// drag resizing switch.
- if (!mService.mWaitingForDrawn.isEmpty()) {
- mService.mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);
- mService.mH.sendEmptyMessageDelayed(H.WAITING_FOR_DRAWN_TIMEOUT,
+ final Runnable existingWaitingForDrwanCallback =
+ mService.mWaitingForDrawnCallbacks.get(mService.mRoot);
+ if (existingWaitingForDrwanCallback != null) {
+ mService.mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, mService.mRoot);
+ mService.mH.sendMessageDelayed(mService.mH.obtainMessage(H.WAITING_FOR_DRAWN_TIMEOUT,
+ mService.mRoot),
IME_ADJUST_DRAWN_TIMEOUT);
mAnimationStartDelayed = true;
if (imeWin != null) {
@@ -838,10 +841,8 @@
// still gets executed.
// TODO: Have a real system where we can wait on different windows to be drawn with
// different callbacks.
- if (mService.mWaitingForDrawnCallback != null) {
- mService.mWaitingForDrawnCallback.run();
- }
- mService.mWaitingForDrawnCallback = () -> {
+ existingWaitingForDrwanCallback.run();
+ mService.mWaitingForDrawnCallbacks.put(mService.mRoot, () -> {
synchronized (mService.mGlobalLock) {
mAnimationStartDelayed = false;
if (mDelayedImeWin != null) {
@@ -863,7 +864,7 @@
notifyAdjustedForImeChanged(
mAdjustedForIme || mAdjustedForDivider, duration);
}
- };
+ });
} else {
notifyAdjustedForImeChanged(
adjustedForIme || adjustedForDivider, IME_ADJUST_ANIM_DURATION);
diff --git a/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java b/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java
index f64592f..2165b0e 100644
--- a/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java
+++ b/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java
@@ -50,7 +50,7 @@
private boolean mVisible;
EmulatorDisplayOverlay(Supplier<Surface> surfaceFactory, Context context, DisplayContent dc,
- int zOrder) {
+ int zOrder, SurfaceControl.Transaction t) {
mSurface = surfaceFactory.get();
final Display display = dc.getDisplay();
mScreenSize = new Point();
@@ -63,9 +63,9 @@
.setBufferSize(mScreenSize.x, mScreenSize.y)
.setFormat(PixelFormat.TRANSLUCENT)
.build();
- ctrl.setLayer(zOrder);
- ctrl.setPosition(0, 0);
- ctrl.show();
+ t.setLayer(ctrl, zOrder);
+ t.setPosition(ctrl, 0, 0);
+ t.show(ctrl);
mSurface.copyFrom(ctrl);
} catch (OutOfResourcesException e) {
}
@@ -75,7 +75,7 @@
com.android.internal.R.drawable.emulator_circular_window_overlay);
}
- private void drawIfNeeded() {
+ private void drawIfNeeded(SurfaceControl.Transaction t) {
if (!mDrawNeeded || !mVisible) {
return;
}
@@ -92,7 +92,7 @@
return;
}
c.drawColor(Color.TRANSPARENT, PorterDuff.Mode.SRC);
- mSurfaceControl.setPosition(0, 0);
+ t.setPosition(mSurfaceControl, 0, 0);
// Always draw the overlay with square dimensions
int size = Math.max(mScreenSize.x, mScreenSize.y);
mOverlay.setBounds(0, 0, size, size);
@@ -102,20 +102,20 @@
// Note: caller responsible for being inside
// Surface.openTransaction() / closeTransaction()
- public void setVisibility(boolean on) {
+ public void setVisibility(boolean on, SurfaceControl.Transaction t) {
if (mSurfaceControl == null) {
return;
}
mVisible = on;
- drawIfNeeded();
+ drawIfNeeded(t);
if (on) {
- mSurfaceControl.show();
+ t.show(mSurfaceControl);
} else {
- mSurfaceControl.hide();
+ t.hide(mSurfaceControl);
}
}
- void positionSurface(int dw, int dh, int rotation) {
+ void positionSurface(int dw, int dh, int rotation, SurfaceControl.Transaction t) {
if (mLastDW == dw && mLastDH == dh && mRotation == rotation) {
return;
}
@@ -123,7 +123,7 @@
mLastDH = dh;
mDrawNeeded = true;
mRotation = rotation;
- drawIfNeeded();
+ drawIfNeeded(t);
}
}
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
new file mode 100644
index 0000000..7e085f6
--- /dev/null
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2019 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;
+
+import android.view.InsetsSource;
+import android.view.WindowInsets;
+
+/**
+ * Controller for IME inset source on the server. It's called provider as it provides the
+ * {@link InsetsSource} to the client that uses it in {@link InsetsSourceConsumer}.
+ */
+class ImeInsetsSourceProvider extends InsetsSourceProvider {
+
+ private WindowState mCurImeTarget;
+ private Runnable mShowImeRunner;
+ private boolean mIsImeLayoutDrawn;
+
+ ImeInsetsSourceProvider(InsetsSource source,
+ InsetsStateController stateController, DisplayContent displayContent) {
+ super(source, stateController, displayContent);
+ }
+
+ /**
+ * Called when a layout pass has occurred.
+ */
+ void onPostLayout() {
+ super.onPostLayout();
+
+ if (mCurImeTarget != null
+ && mCurImeTarget == mDisplayContent.mInputMethodTarget
+ && mWin != null
+ && mWin.isDrawnLw()
+ && !mWin.mGivenInsetsPending) {
+ mIsImeLayoutDrawn = true;
+ }
+ }
+
+ /**
+ * Called when Insets have been dispatched to client.
+ */
+ void onPostInsetsDispatched() {
+ if (mIsImeLayoutDrawn && mShowImeRunner != null) {
+ // Show IME if InputMethodService requested to be shown and it's layout has finished.
+ mShowImeRunner.run();
+ mIsImeLayoutDrawn = false;
+ mShowImeRunner = null;
+ }
+ }
+
+ /**
+ * Called from {@link WindowManagerInternal#showImePostLayout} when {@link InputMethodService}
+ * requests to show IME on {@param imeTarget}.
+ * @param imeTarget imeTarget on which IME is displayed.
+ */
+ void scheduleShowImePostLayout(WindowState imeTarget) {
+ mCurImeTarget = imeTarget;
+ mShowImeRunner = () -> {
+ // Target should still be the same.
+ if (mCurImeTarget == mDisplayContent.mInputMethodTarget) {
+ mDisplayContent.mInputMethodTarget.showInsets(
+ WindowInsets.Type.ime(), true /* fromIme */);
+ }
+ mCurImeTarget = null;
+ };
+ }
+
+}
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 8426864..cc55e01 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -47,9 +47,11 @@
*/
class InsetsSourceProvider {
+ protected final DisplayContent mDisplayContent;
+ protected final @NonNull InsetsSource mSource;
+ protected WindowState mWin;
+
private final Rect mTmpRect = new Rect();
- private final @NonNull InsetsSource mSource;
- private final DisplayContent mDisplayContent;
private final InsetsStateController mStateController;
private final InsetsSourceControl mFakeControl;
private @Nullable InsetsSourceControl mControl;
@@ -57,7 +59,6 @@
private @Nullable InsetsControlTarget mFakeControlTarget;
private @Nullable ControlAdapter mAdapter;
- private WindowState mWin;
private TriConsumer<DisplayFrames, WindowState, Rect> mFrameProvider;
/** The visibility override from the current controlling window. */
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 4ebb553..b0410335c 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -108,8 +108,18 @@
* @return The provider of a specific type.
*/
InsetsSourceProvider getSourceProvider(@InternalInsetType int type) {
- return mProviders.computeIfAbsent(type,
- key -> new InsetsSourceProvider(mState.getSource(key), this, mDisplayContent));
+ if (type == TYPE_IME) {
+ return mProviders.computeIfAbsent(type,
+ key -> new ImeInsetsSourceProvider(
+ mState.getSource(key), this, mDisplayContent));
+ } else {
+ return mProviders.computeIfAbsent(type,
+ key -> new InsetsSourceProvider(mState.getSource(key), this, mDisplayContent));
+ }
+ }
+
+ ImeInsetsSourceProvider getImeSourceProvider() {
+ return (ImeInsetsSourceProvider) getSourceProvider(TYPE_IME);
}
/**
@@ -124,6 +134,7 @@
mLastState.set(mState, true /* copySources */);
notifyInsetsChanged();
}
+ getImeSourceProvider().onPostInsetsDispatched();
}
void onInsetsModified(WindowState windowState, InsetsState state) {
diff --git a/services/core/java/com/android/server/wm/LaunchParamsPersister.java b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
index d364a37..5d27390 100644
--- a/services/core/java/com/android/server/wm/LaunchParamsPersister.java
+++ b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
@@ -17,7 +17,6 @@
package com.android.server.wm;
import android.content.ComponentName;
-import android.content.pm.PackageList;
import android.content.pm.PackageManagerInternal;
import android.graphics.Rect;
import android.os.Environment;
@@ -32,6 +31,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FastXmlSerializer;
import com.android.server.LocalServices;
+import com.android.server.pm.PackageList;
import com.android.server.wm.LaunchParamsController.LaunchParams;
import libcore.io.IoUtils;
@@ -198,7 +198,7 @@
void saveTask(TaskRecord task) {
final ComponentName name = task.realActivity;
- final int userId = task.userId;
+ final int userId = task.mUserId;
PersistableLaunchParams params;
ArrayMap<ComponentName, PersistableLaunchParams> map = mMap.get(userId);
if (map == null) {
@@ -247,7 +247,7 @@
void getLaunchParams(TaskRecord task, ActivityRecord activity, LaunchParams outParams) {
final ComponentName name = task != null ? task.realActivity : activity.mActivityComponent;
- final int userId = task != null ? task.userId : activity.mUserId;
+ final int userId = task != null ? task.mUserId : activity.mUserId;
outParams.reset();
Map<ComponentName, PersistableLaunchParams> map = mMap.get(userId);
diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java
index 1bd2493..94d010e 100644
--- a/services/core/java/com/android/server/wm/Letterbox.java
+++ b/services/core/java/com/android/server/wm/Letterbox.java
@@ -247,12 +247,12 @@
mLayoutFrameRelative.offset(-surfaceOrigin.x, -surfaceOrigin.y);
}
- private void createSurface() {
+ private void createSurface(SurfaceControl.Transaction t) {
mSurface = mSurfaceControlFactory.get().setName("Letterbox - " + mType)
.setFlags(HIDDEN).setColorLayer().build();
- mSurface.setLayer(-1);
- mSurface.setColor(new float[]{0, 0, 0});
- mSurface.setColorSpaceAgnostic(true);
+ t.setLayer(mSurface, -1)
+ .setColor(mSurface, new float[]{0, 0, 0})
+ .setColorSpaceAgnostic(mSurface, true);
}
void attachInput(WindowState win) {
@@ -300,7 +300,7 @@
mSurfaceFrameRelative.set(mLayoutFrameRelative);
if (!mSurfaceFrameRelative.isEmpty()) {
if (mSurface == null) {
- createSurface();
+ createSurface(t);
}
t.setPosition(mSurface, mSurfaceFrameRelative.left, mSurfaceFrameRelative.top);
t.setWindowCrop(mSurface, mSurfaceFrameRelative.width(),
diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java
index b30da5e..dc45686 100644
--- a/services/core/java/com/android/server/wm/LockTaskController.java
+++ b/services/core/java/com/android/server/wm/LockTaskController.java
@@ -317,12 +317,12 @@
}
// Allow recents activity if enabled by policy
- if (task.isActivityTypeRecents() && isRecentsAllowed(task.userId)) {
+ if (task.isActivityTypeRecents() && isRecentsAllowed(task.mUserId)) {
return false;
}
// Allow emergency calling when the device is protected by a locked keyguard
- if (isKeyguardAllowed(task.userId) && isEmergencyCallTask(task)) {
+ if (isKeyguardAllowed(task.mUserId) && isEmergencyCallTask(task)) {
return false;
}
@@ -474,7 +474,7 @@
if (mLockTaskModeTasks.isEmpty()) {
if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "removeLockedTask: task=" + task +
" last task, reverting locktask mode. Callers=" + Debug.getCallers(3));
- mHandler.post(() -> performStopLockTask(task.userId));
+ mHandler.post(() -> performStopLockTask(task.mUserId));
}
}
@@ -537,7 +537,7 @@
StatusBarManagerInternal statusBarManager = LocalServices.getService(
StatusBarManagerInternal.class);
if (statusBarManager != null) {
- statusBarManager.showScreenPinningRequest(task.taskId);
+ statusBarManager.showScreenPinningRequest(task.mTaskId);
}
return;
}
@@ -570,11 +570,11 @@
final Intent taskIntent = task.intent;
if (mLockTaskModeTasks.isEmpty() && taskIntent != null) {
- mSupervisor.mRecentTasks.onLockTaskModeStateChanged(lockTaskModeState, task.userId);
+ mSupervisor.mRecentTasks.onLockTaskModeStateChanged(lockTaskModeState, task.mUserId);
// Start lock task on the handler thread
mHandler.post(() -> performStartLockTask(
taskIntent.getComponent().getPackageName(),
- task.userId,
+ task.mUserId,
lockTaskModeState));
}
if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "setLockTaskMode: Locking to " + task +
@@ -640,7 +640,7 @@
|| lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_WHITELISTED;
if (mLockTaskModeState != LOCK_TASK_MODE_LOCKED
- || lockedTask.userId != userId
+ || lockedTask.mUserId != userId
|| !wasWhitelisted || isWhitelisted) {
continue;
}
@@ -704,7 +704,7 @@
}
mLockTaskFeatures.put(userId, flags);
- if (!mLockTaskModeTasks.isEmpty() && userId == mLockTaskModeTasks.get(0).userId) {
+ if (!mLockTaskModeTasks.isEmpty() && userId == mLockTaskModeTasks.get(0).mUserId) {
mHandler.post(() -> {
if (mLockTaskModeState == LOCK_TASK_MODE_LOCKED) {
setStatusBarState(mLockTaskModeState, userId);
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index fb6b5da..7169677 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -120,7 +120,7 @@
// Comparator to sort by taskId
private static final Comparator<TaskRecord> TASK_ID_COMPARATOR =
- (lhs, rhs) -> rhs.taskId - lhs.taskId;
+ (lhs, rhs) -> rhs.mTaskId - lhs.mTaskId;
// Placeholder variables to keep track of activities/apps that are no longer avialble while
// iterating through the recents list
@@ -272,9 +272,14 @@
* app, or a timeout occurs.
*/
void setFreezeTaskListReordering() {
+ // Only fire the callback once per quickswitch session, not on every individual switch
+ if (!mFreezeTaskListReordering) {
+ mTaskNotificationController.notifyTaskListFrozen(true);
+ mFreezeTaskListReordering = true;
+ }
+
// Always update the reordering time when this is called to ensure that the timeout
// is reset
- mFreezeTaskListReordering = true;
mService.mH.removeCallbacks(mResetFreezeTaskListOnTimeoutRunnable);
mService.mH.postDelayed(mResetFreezeTaskListOnTimeoutRunnable, mFreezeTaskListTimeoutMs);
}
@@ -302,6 +307,7 @@
trimInactiveRecentTasks();
mTaskNotificationController.notifyTaskStackChanged();
+ mTaskNotificationController.notifyTaskListFrozen(false);
}
/**
@@ -458,8 +464,8 @@
// Check if any tasks are added before recents is loaded
final SparseBooleanArray preaddedTasks = new SparseBooleanArray();
for (final TaskRecord task : mTasks) {
- if (task.userId == userId && shouldPersistTaskLocked(task)) {
- preaddedTasks.put(task.taskId, true);
+ if (task.mUserId == userId && shouldPersistTaskLocked(task)) {
+ preaddedTasks.put(task.mTaskId, true);
}
}
@@ -527,12 +533,12 @@
if (shouldPersistTaskLocked(task)) {
// Set of persisted taskIds for task.userId should not be null here
// TODO Investigate why it can happen. For now initialize with an empty set
- if (mPersistedTaskIds.get(task.userId) == null) {
- Slog.wtf(TAG, "No task ids found for userId " + task.userId + ". task=" + task
+ if (mPersistedTaskIds.get(task.mUserId) == null) {
+ Slog.wtf(TAG, "No task ids found for userId " + task.mUserId + ". task=" + task
+ " mPersistedTaskIds=" + mPersistedTaskIds);
- mPersistedTaskIds.put(task.userId, new SparseBooleanArray());
+ mPersistedTaskIds.put(task.mUserId, new SparseBooleanArray());
}
- mPersistedTaskIds.get(task.userId).put(task.taskId, true);
+ mPersistedTaskIds.get(task.mUserId).put(task.mTaskId, true);
}
}
}
@@ -608,7 +614,7 @@
for (int i = mTasks.size() - 1; i >= 0; --i) {
TaskRecord tr = mTasks.get(i);
- if (tr.userId == userId) {
+ if (tr.mUserId == userId) {
if(DEBUG_TASKS) Slog.i(TAG_TASKS,
"remove RecentTask " + tr + " when finishing user" + userId);
remove(tr);
@@ -622,11 +628,11 @@
final TaskRecord tr = mTasks.get(i);
if (tr.realActivity != null
&& packageNames.contains(tr.realActivity.getPackageName())
- && tr.userId == userId
+ && tr.mUserId == userId
&& tr.realActivitySuspended != suspended) {
tr.realActivitySuspended = suspended;
if (suspended) {
- mSupervisor.removeTaskByIdLocked(tr.taskId, false,
+ mSupervisor.removeTaskByIdLocked(tr.mTaskId, false,
REMOVE_FROM_RECENTS, "suspended-package");
}
notifyTaskPersisterLocked(tr, false);
@@ -640,7 +646,7 @@
}
for (int i = mTasks.size() - 1; i >= 0; --i) {
final TaskRecord tr = mTasks.get(i);
- if (tr.userId == userId && !mService.getLockTaskController().isTaskWhitelisted(tr)) {
+ if (tr.mUserId == userId && !mService.getLockTaskController().isTaskWhitelisted(tr)) {
remove(tr);
}
}
@@ -651,10 +657,10 @@
final TaskRecord tr = mTasks.get(i);
final String taskPackageName =
tr.getBaseIntent().getComponent().getPackageName();
- if (tr.userId != userId) continue;
+ if (tr.mUserId != userId) continue;
if (!taskPackageName.equals(packageName)) continue;
- mSupervisor.removeTaskByIdLocked(tr.taskId, true, REMOVE_FROM_RECENTS,
+ mSupervisor.removeTaskByIdLocked(tr.mTaskId, true, REMOVE_FROM_RECENTS,
"remove-package-task");
}
}
@@ -663,7 +669,7 @@
Set<Integer> profileIds = getProfileIds(userId);
for (int i = mTasks.size() - 1; i >= 0; --i) {
final TaskRecord tr = mTasks.get(i);
- if (!profileIds.contains(tr.userId)) continue;
+ if (!profileIds.contains(tr.mUserId)) continue;
if (isVisibleRecentTask(tr)) {
mTasks.remove(i);
notifyTaskRemoved(tr, true /* wasTrimmed */, true /* killProcess */);
@@ -675,7 +681,7 @@
int userId) {
for (int i = mTasks.size() - 1; i >= 0; --i) {
final TaskRecord tr = mTasks.get(i);
- if (userId != UserHandle.USER_ALL && tr.userId != userId) {
+ if (userId != UserHandle.USER_ALL && tr.mUserId != userId) {
continue;
}
@@ -683,7 +689,7 @@
final boolean sameComponent = cn != null && cn.getPackageName().equals(packageName)
&& (filterByClasses == null || filterByClasses.contains(cn.getClassName()));
if (sameComponent) {
- mSupervisor.removeTaskByIdLocked(tr.taskId, false,
+ mSupervisor.removeTaskByIdLocked(tr.mTaskId, false,
REMOVE_FROM_RECENTS, "disabled-package");
}
}
@@ -709,7 +715,7 @@
final IPackageManager pm = AppGlobals.getPackageManager();
for (int i = recentsCount - 1; i >= 0; i--) {
final TaskRecord task = mTasks.get(i);
- if (userId != UserHandle.USER_ALL && task.userId != userId) {
+ if (userId != UserHandle.USER_ALL && task.mUserId != userId) {
// Only look at tasks for the user ID of interest.
continue;
}
@@ -826,7 +832,7 @@
if (intent == null || !callingPackage.equals(intent.getComponent().getPackageName())) {
continue;
}
- AppTaskImpl taskImpl = new AppTaskImpl(mService, tr.taskId, callingUid);
+ AppTaskImpl taskImpl = new AppTaskImpl(mService, tr.mTaskId, callingUid);
list.add(taskImpl.asBinder());
}
return list;
@@ -908,7 +914,7 @@
}
// Only add calling user or related users recent tasks
- if (!includedUsers.contains(Integer.valueOf(tr.userId))) {
+ if (!includedUsers.contains(Integer.valueOf(tr.mUserId))) {
if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not user: " + tr);
continue;
}
@@ -972,7 +978,7 @@
if ((task.isPersistable || task.inRecents)
&& (stack == null || !stack.isHomeOrRecentsStack())) {
if (TaskPersister.DEBUG) Slog.d(TAG, "adding to persistentTaskIds task=" + task);
- persistentTaskIds.add(task.taskId);
+ persistentTaskIds.add(task.mTaskId);
} else {
if (TaskPersister.DEBUG) Slog.d(TAG, "omitting from persistentTaskIds task="
+ task);
@@ -997,7 +1003,7 @@
if (isVisibleRecentTask(tr)) {
numVisibleTasks++;
if (isInVisibleRange(tr, i, numVisibleTasks, false /* skipExcludedCheck */)) {
- res.put(tr.taskId, true);
+ res.put(tr.mTaskId, true);
}
}
}
@@ -1011,7 +1017,7 @@
final int recentsCount = mTasks.size();
for (int i = 0; i < recentsCount; i++) {
TaskRecord tr = mTasks.get(i);
- if (tr.taskId == id) {
+ if (tr.mTaskId == id) {
return tr;
}
}
@@ -1024,7 +1030,7 @@
void add(TaskRecord task) {
if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "add: task=" + task);
- final boolean isAffiliated = task.mAffiliatedTaskId != task.taskId
+ final boolean isAffiliated = task.mAffiliatedTaskId != task.mTaskId
|| task.mNextAffiliateTaskId != INVALID_TASK_ID
|| task.mPrevAffiliateTaskId != INVALID_TASK_ID;
@@ -1138,7 +1144,7 @@
if (needAffiliationFix) {
if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: regrouping affiliations");
- cleanupLocked(task.userId);
+ cleanupLocked(task.mUserId);
}
// Trim the set of tasks to the active set
@@ -1248,13 +1254,13 @@
if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "isActiveRecentTask: task=" + task
+ " globalMax=" + mGlobalMaxNumTasks);
- if (quietProfileUserIds.get(task.userId)) {
+ if (quietProfileUserIds.get(task.mUserId)) {
// Quiet profile user's tasks are never active
if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "\tisQuietProfileTask=true");
return false;
}
- if (task.mAffiliatedTaskId != INVALID_TASK_ID && task.mAffiliatedTaskId != task.taskId) {
+ if (task.mAffiliatedTaskId != INVALID_TASK_ID && task.mAffiliatedTaskId != task.mTaskId) {
// Keep the task active if its affiliated task is also active
final TaskRecord affiliatedTask = getTask(task.mAffiliatedTaskId);
if (affiliatedTask != null) {
@@ -1430,7 +1436,7 @@
final TaskRecord tr = mTasks.get(i);
if (task != tr) {
if (!hasCompatibleActivityTypeAndWindowingMode(task, tr)
- || task.userId != tr.userId) {
+ || task.mUserId != tr.mUserId) {
continue;
}
final Intent trIntent = tr.intent;
@@ -1485,7 +1491,7 @@
final int affiliateId = startTask.mAffiliatedTaskId;
// Quick identification of isolated tasks. I.e. those not launched behind.
- if (startTask.taskId == affiliateId && startTask.mPrevAffiliate == null &&
+ if (startTask.mTaskId == affiliateId && startTask.mPrevAffiliate == null &&
startTask.mNextAffiliate == null) {
// There is still a slim chance that there are other tasks that point to this task
// and that the chain is so messed up that this task no longer points to them but
@@ -1581,7 +1587,7 @@
} else {
// Verify middle of the chain's next points back to the one before.
if (cur.mNextAffiliate != prev
- || cur.mNextAffiliateTaskId != prev.taskId) {
+ || cur.mNextAffiliateTaskId != prev.mTaskId) {
Slog.wtf(TAG, "Bad chain @" + endIndex
+ ": middle task " + cur + " @" + endIndex
+ " has bad next affiliate "
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 0075c15..062cdc5 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -492,7 +492,7 @@
for (int i = targetStack.getChildCount() - 1; i >= 0; i--) {
final TaskRecord task = targetStack.getChildAt(i);
- if (task.userId == mUserId
+ if (task.mUserId == mUserId
&& task.getBaseIntent().getComponent().equals(mTargetIntent.getComponent())) {
return task.getTopActivity();
}
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index 8a47c5a..d78d517 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -652,9 +652,9 @@
starting.frozenBeforeDestroy = true;
}
- if (displayContent != null && displayContent.mAcitvityDisplay != null) {
+ if (displayContent != null && displayContent.mActivityDisplay != null) {
// Update the configuration of the activities on the display.
- return displayContent.mAcitvityDisplay.updateDisplayOverrideConfigurationLocked(config,
+ return displayContent.mActivityDisplay.updateDisplayOverrideConfigurationLocked(config,
starting, deferResume, null /* result */);
} else {
return true;
@@ -1103,7 +1103,7 @@
}
}
}
- return finishedTask != null ? finishedTask.taskId : INVALID_TASK_ID;
+ return finishedTask != null ? finishedTask.mTaskId : INVALID_TASK_ID;
}
boolean resumeFocusedStacksTopActivities() {
@@ -1260,14 +1260,14 @@
int[] taskUserIds = new int[numTasks];
for (int i = 0; i < numTasks; ++i) {
final TaskRecord task = tasks.get(i);
- taskIds[i] = task.taskId;
+ taskIds[i] = task.mTaskId;
taskNames[i] = task.origActivity != null ? task.origActivity.flattenToString()
: task.realActivity != null ? task.realActivity.flattenToString()
: task.getTopActivity() != null ? task.getTopActivity().packageName
: "unknown";
taskBounds[i] = new Rect();
task.getWindowContainerBounds(taskBounds[i]);
- taskUserIds[i] = task.userId;
+ taskUserIds[i] = task.mUserId;
}
info.taskIds = taskIds;
info.taskNames = taskNames;
@@ -2103,7 +2103,7 @@
// picker for personal files, opened by a work app, should still get locked.
if (taskTopActivityIsUser(task, userId)) {
mService.getTaskChangeNotificationController().notifyTaskProfileLocked(
- task.taskId, userId);
+ task.mTaskId, userId);
}
}
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 78fcb37..b6a05d1 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -230,7 +230,7 @@
final DisplayContent existing = getDisplayContent(displayId);
if (existing != null) {
- existing.mAcitvityDisplay = activityDisplay;
+ existing.mActivityDisplay = activityDisplay;
existing.initializeDisplayOverrideConfiguration();
return existing;
}
@@ -720,7 +720,7 @@
mUpdateRotation = updateRotationUnchecked();
}
- if (mWmService.mWaitingForDrawnCallback != null
+ if (!mWmService.mWaitingForDrawnCallbacks.isEmpty()
|| (mOrientationChangeComplete && !isLayoutNeeded()
&& !mUpdateRotation)) {
mWmService.checkDrawnWindowsLocked();
@@ -813,18 +813,18 @@
final int defaultDw = defaultInfo.logicalWidth;
final int defaultDh = defaultInfo.logicalHeight;
if (mWmService.mWatermark != null) {
- mWmService.mWatermark.positionSurface(defaultDw, defaultDh);
+ mWmService.mWatermark.positionSurface(defaultDw, defaultDh, mDisplayTransaction);
}
if (mWmService.mStrictModeFlash != null) {
- mWmService.mStrictModeFlash.positionSurface(defaultDw, defaultDh);
+ mWmService.mStrictModeFlash.positionSurface(defaultDw, defaultDh, mDisplayTransaction);
}
if (mWmService.mCircularDisplayMask != null) {
mWmService.mCircularDisplayMask.positionSurface(defaultDw, defaultDh,
- mWmService.getDefaultDisplayRotation());
+ mWmService.getDefaultDisplayRotation(), mDisplayTransaction);
}
if (mWmService.mEmulatorDisplayOverlay != null) {
mWmService.mEmulatorDisplayOverlay.positionSurface(defaultDw, defaultDh,
- mWmService.getDefaultDisplayRotation());
+ mWmService.getDefaultDisplayRotation(), mDisplayTransaction);
}
final int count = mChildren.size();
@@ -1067,7 +1067,7 @@
void positionChildAt(int position, DisplayContent child, boolean includingParents) {
super.positionChildAt(position, child, includingParents);
if (mRootActivityContainer != null) {
- mRootActivityContainer.onChildPositionChanged(child.mAcitvityDisplay, position);
+ mRootActivityContainer.onChildPositionChanged(child.mActivityDisplay, position);
}
}
diff --git a/services/core/java/com/android/server/wm/SeamlessRotator.java b/services/core/java/com/android/server/wm/SeamlessRotator.java
index bcd90a1..ba31818 100644
--- a/services/core/java/com/android/server/wm/SeamlessRotator.java
+++ b/services/core/java/com/android/server/wm/SeamlessRotator.java
@@ -20,9 +20,10 @@
import static android.view.Surface.ROTATION_90;
import android.graphics.Matrix;
+import android.os.IBinder;
import android.view.DisplayInfo;
-import android.view.Surface;
import android.view.Surface.Rotation;
+import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import com.android.server.wm.utils.CoordinateTransforms;
@@ -35,7 +36,7 @@
*
* Works by transforming the {@link WindowState} back into the old display rotation.
*
- * Uses {@link android.view.SurfaceControl#deferTransactionUntil(Surface, long)} instead of
+ * Uses {@link Transaction#deferTransactionUntil(SurfaceControl, IBinder, long)} instead of
* latching on the buffer size to allow for seamless 180 degree rotations.
*/
public class SeamlessRotator {
diff --git a/services/core/java/com/android/server/wm/StrictModeFlash.java b/services/core/java/com/android/server/wm/StrictModeFlash.java
index 9e5d9ca..f537005 100644
--- a/services/core/java/com/android/server/wm/StrictModeFlash.java
+++ b/services/core/java/com/android/server/wm/StrictModeFlash.java
@@ -39,7 +39,8 @@
private boolean mDrawNeeded;
private final int mThickness = 20;
- StrictModeFlash(Supplier<Surface> surfaceFactory, DisplayContent dc) {
+ StrictModeFlash(Supplier<Surface> surfaceFactory, DisplayContent dc,
+ SurfaceControl.Transaction t) {
mSurface = surfaceFactory.get();
SurfaceControl ctrl = null;
try {
@@ -48,9 +49,11 @@
.setBufferSize(1, 1)
.setFormat(PixelFormat.TRANSLUCENT)
.build();
- ctrl.setLayer(WindowManagerService.TYPE_LAYER_MULTIPLIER * 101); // one more than Watermark? arbitrary.
- ctrl.setPosition(0, 0);
- ctrl.show();
+
+ // one more than Watermark? arbitrary.
+ t.setLayer(ctrl, WindowManagerService.TYPE_LAYER_MULTIPLIER * 101);
+ t.setPosition(ctrl, 0, 0);
+ t.show(ctrl);
mSurface.copyFrom(ctrl);
} catch (OutOfResourcesException e) {
}
@@ -103,25 +106,25 @@
// Note: caller responsible for being inside
// Surface.openTransaction() / closeTransaction()
- public void setVisibility(boolean on) {
+ public void setVisibility(boolean on, SurfaceControl.Transaction t) {
if (mSurfaceControl == null) {
return;
}
drawIfNeeded();
if (on) {
- mSurfaceControl.show();
+ t.show(mSurfaceControl);
} else {
- mSurfaceControl.hide();
+ t.hide(mSurfaceControl);
}
}
- void positionSurface(int dw, int dh) {
+ void positionSurface(int dw, int dh, SurfaceControl.Transaction t) {
if (mLastDW == dw && mLastDH == dh) {
return;
}
mLastDW = dw;
mLastDH = dh;
- mSurfaceControl.setBufferSize(dw, dh);
+ t.setBufferSize(mSurfaceControl, dw, dh);
mDrawNeeded = true;
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 2ad9102..a181c18 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -20,12 +20,8 @@
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.res.Configuration.EMPTY;
-import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
-import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.view.SurfaceControl.METADATA_TASK_ID;
import static com.android.server.EventLogTags.WM_TASK_REMOVED;
@@ -67,7 +63,9 @@
// TODO: Track parent marks like this in WindowContainer.
TaskStack mStack;
+ /* Unique identifier for this task. */
final int mTaskId;
+ /* User for which this task was created. */
final int mUserId;
private boolean mDeferRemoval = false;
@@ -101,6 +99,8 @@
private boolean mDragResizing;
private int mDragResizeMode;
+ // This represents the last resolved activity values for this task
+ // NOTE: This value needs to be persisted with each task
private TaskDescription mTaskDescription;
// If set to true, the task will report that it is not in the floating
@@ -135,26 +135,17 @@
mResizeMode = resizeMode;
mSupportsPictureInPicture = supportsPictureInPicture;
mTaskRecord = taskRecord;
+ mTaskDescription = taskDescription;
+
+ // Tasks have no set orientation value (including SCREEN_ORIENTATION_UNSPECIFIED).
+ setOrientation(SCREEN_ORIENTATION_UNSET);
if (mTaskRecord != null) {
// This can be null when we call createTaskInStack in WindowTestUtils. Remove this after
// unification.
mTaskRecord.registerConfigurationChangeListener(this);
+ } else {
+ setBounds(getResolvedOverrideBounds());
}
- setBounds(getResolvedOverrideBounds());
- mTaskDescription = taskDescription;
-
- // Tasks have no set orientation value (including SCREEN_ORIENTATION_UNSPECIFIED) not unless
- // set through the override configuration.
- int orientation = SCREEN_ORIENTATION_UNSET;
- switch (getResolvedOverrideConfiguration().orientation) {
- case ORIENTATION_PORTRAIT:
- orientation = SCREEN_ORIENTATION_PORTRAIT;
- break;
- case ORIENTATION_LANDSCAPE:
- orientation = SCREEN_ORIENTATION_LANDSCAPE;
- break;
- }
- setOrientation(orientation);
}
@Override
diff --git a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
index 5e8831d..a61c908 100644
--- a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
@@ -58,6 +58,7 @@
private static final int NOTIFY_TASK_DISPLAY_CHANGED_LISTENERS_MSG = 23;
private static final int NOTIFY_TASK_LIST_UPDATED_LISTENERS_MSG = 24;
private static final int NOTIFY_SINGLE_TASK_DISPLAY_EMPTY = 25;
+ private static final int NOTIFY_TASK_LIST_FROZEN_UNFROZEN_MSG = 26;
// Delay in notifying task stack change listeners (in millis)
private static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY = 100;
@@ -174,6 +175,10 @@
l.onRecentTaskListUpdated();
};
+ private final TaskStackConsumer mNotifyTaskListFrozen = (l, m) -> {
+ l.onRecentTaskListFrozenChanged(m.arg1 != 0);
+ };
+
@FunctionalInterface
public interface TaskStackConsumer {
void accept(ITaskStackListener t, Message m) throws RemoteException;
@@ -265,6 +270,9 @@
case NOTIFY_TASK_LIST_UPDATED_LISTENERS_MSG:
forAllRemoteListeners(mNotifyTaskListUpdated, msg);
break;
+ case NOTIFY_TASK_LIST_FROZEN_UNFROZEN_MSG:
+ forAllRemoteListeners(mNotifyTaskListFrozen, msg);
+ break;
}
}
}
@@ -342,7 +350,7 @@
void notifyActivityPinned(ActivityRecord r) {
mHandler.removeMessages(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG);
final Message msg = mHandler.obtainMessage(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG,
- r.getTaskRecord().taskId, r.getStackId(), r.packageName);
+ r.getTaskRecord().mTaskId, r.getStackId(), r.packageName);
msg.sendingUid = r.mUserId;
forAllLocalListeners(mNotifyActivityPinned, msg);
msg.sendToTarget();
@@ -549,4 +557,12 @@
forAllLocalListeners(mNotifyTaskListUpdated, msg);
msg.sendToTarget();
}
+
+ /** @see ITaskStackListener#onRecentTaskListFrozenChanged(boolean) */
+ void notifyTaskListFrozen(boolean frozen) {
+ final Message msg = mHandler.obtainMessage(NOTIFY_TASK_LIST_FROZEN_UNFROZEN_MSG,
+ frozen ? 1 : 0, 0 /* unused */);
+ forAllLocalListeners(mNotifyTaskListFrozen, msg);
+ msg.sendToTarget();
+ }
}
diff --git a/services/core/java/com/android/server/wm/TaskPersister.java b/services/core/java/com/android/server/wm/TaskPersister.java
index 06bdcc0..f9a75d3 100644
--- a/services/core/java/com/android/server/wm/TaskPersister.java
+++ b/services/core/java/com/android/server/wm/TaskPersister.java
@@ -122,7 +122,7 @@
mPersisterQueue.removeItems(
item -> {
File file = new File(item.mFilePath);
- return file.getName().startsWith(Integer.toString(task.taskId));
+ return file.getName().startsWith(Integer.toString(task.mTaskId));
},
ImageWriteQueueItem.class);
}
@@ -262,7 +262,7 @@
}
for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
final TaskRecord task = tasks.get(taskNdx);
- if (task.taskId == taskId) {
+ if (task.mTaskId == taskId) {
return task;
}
}
@@ -329,14 +329,14 @@
// read the same thing again.
// mWriteQueue.add(new TaskWriteQueueItem(task));
- final int taskId = task.taskId;
+ final int taskId = task.mTaskId;
if (mService.mRootActivityContainer.anyTaskForId(taskId,
MATCH_TASK_IN_STACKS_OR_RECENT_TASKS) != null) {
// Should not happen.
Slog.wtf(TAG, "Existing task with taskId " + taskId + "found");
- } else if (userId != task.userId) {
+ } else if (userId != task.mUserId) {
// Should not happen.
- Slog.wtf(TAG, "Task with userId " + task.userId + " found in "
+ Slog.wtf(TAG, "Task with userId " + task.mUserId + " found in "
+ userTasksDir.getAbsolutePath());
} else {
// Looks fine.
@@ -560,14 +560,14 @@
FileOutputStream file = null;
AtomicFile atomicFile = null;
try {
- File userTasksDir = getUserTasksDir(task.userId);
+ File userTasksDir = getUserTasksDir(task.mUserId);
if (!userTasksDir.isDirectory() && !userTasksDir.mkdirs()) {
- Slog.e(TAG, "Failure creating tasks directory for user " + task.userId
+ Slog.e(TAG, "Failure creating tasks directory for user " + task.mUserId
+ ": " + userTasksDir + " Dropping persistence for task " + task);
return;
}
atomicFile = new AtomicFile(new File(userTasksDir,
- String.valueOf(task.taskId) + TASK_FILENAME_SUFFIX));
+ String.valueOf(task.mTaskId) + TASK_FILENAME_SUFFIX));
file = atomicFile.startWrite();
file.write(stringWriter.toString().getBytes());
file.write('\n');
diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java
index 8b2ef7f..75333c7 100644
--- a/services/core/java/com/android/server/wm/TaskRecord.java
+++ b/services/core/java/com/android/server/wm/TaskRecord.java
@@ -208,7 +208,7 @@
*/
private static TaskRecordFactory sTaskRecordFactory;
- final int taskId; // Unique identifier for this task.
+ final int mTaskId; // Unique identifier for this task.
String affinity; // The affinity name for this task, or null; may change identity.
String rootAffinity; // Initial base affinity, or null; does not change from initial root.
final IVoiceInteractionSession voiceSession; // Voice interaction session driving task
@@ -234,7 +234,7 @@
boolean hasBeenVisible; // Set if any activities in the task have been visible to the user.
String stringName; // caching of toString() result.
- int userId; // user for which this task was created
+ int mUserId; // user for which this task was created
boolean mUserSetupComplete; // The user set-up is complete as of the last time the task activity
// was changed.
@@ -262,7 +262,7 @@
// This represents the last resolved activity values for this task
// NOTE: This value needs to be persisted with each task
- TaskDescription lastTaskDescription = new TaskDescription();
+ TaskDescription mTaskDescription;
/** List of all activities in the task arranged in history order */
final ArrayList<ActivityRecord> mActivities;
@@ -282,7 +282,7 @@
/** Only used for persistable tasks, otherwise 0. The last time this task was moved. Used for
* determining the order when restoring. Sign indicates whether last task movement was to front
* (positive) or back (negative). Absolute value indicates time. */
- long mLastTimeMoved = System.currentTimeMillis();
+ long mLastTimeMoved;
/** If original intent did not allow relinquishing task identity, save that information */
private boolean mNeverRelinquishIdentity = true;
@@ -304,7 +304,7 @@
int mCallingUid;
String mCallingPackage;
- final ActivityTaskManagerService mService;
+ final ActivityTaskManagerService mAtmService;
private final Rect mTmpStableBounds = new Rect();
private final Rect mTmpNonDecorBounds = new Rect();
@@ -342,60 +342,25 @@
* Don't use constructor directly. Use {@link #create(ActivityTaskManagerService, int,
* ActivityInfo, Intent, TaskDescription)} instead.
*/
- TaskRecord(ActivityTaskManagerService service, int _taskId, ActivityInfo info, Intent _intent,
- IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor) {
- mService = service;
- userId = UserHandle.getUserId(info.applicationInfo.uid);
- taskId = _taskId;
- lastActiveTime = SystemClock.elapsedRealtime();
- mAffiliatedTaskId = _taskId;
- voiceSession = _voiceSession;
- voiceInteractor = _voiceInteractor;
- isAvailable = true;
- mActivities = new ArrayList<>();
- mCallingUid = info.applicationInfo.uid;
- mCallingPackage = info.packageName;
- setIntent(_intent, info);
- setMinDimensions(info);
- touchActiveTime();
- mService.getTaskChangeNotificationController().notifyTaskCreated(_taskId, realActivity);
+ TaskRecord(ActivityTaskManagerService atmService, int _taskId, ActivityInfo info,
+ Intent _intent, IVoiceInteractionSession _voiceSession,
+ IVoiceInteractor _voiceInteractor, TaskDescription _taskDescription) {
+ this(atmService, _taskId, _intent, null /*_affinityIntent*/, null /*_affinity*/,
+ null /*_rootAffinity*/, null /*_realActivity*/, null /*_origActivity*/,
+ false /*_rootWasReset*/, false /*_autoRemoveRecents*/, false /*_askedCompatMode*/,
+ UserHandle.getUserId(info.applicationInfo.uid), 0 /*_effectiveUid*/,
+ null /*_lastDescription*/, new ArrayList<>(), System.currentTimeMillis(),
+ true /*neverRelinquishIdentity*/,
+ _taskDescription != null ? _taskDescription : new TaskDescription(),
+ _taskId, INVALID_TASK_ID, INVALID_TASK_ID, 0 /*taskAffiliationColor*/,
+ info.applicationInfo.uid, info.packageName, info.resizeMode,
+ info.supportsPictureInPicture(), false /*_realActivitySuspended*/,
+ false /*userSetupComplete*/, INVALID_MIN_SIZE, INVALID_MIN_SIZE, info,
+ _voiceSession, _voiceInteractor);
}
- /**
- * Don't use constructor directly.
- * Use {@link #create(ActivityTaskManagerService, int, ActivityInfo,
- * Intent, IVoiceInteractionSession, IVoiceInteractor)} instead.
- */
- TaskRecord(ActivityTaskManagerService service, int _taskId, ActivityInfo info, Intent _intent,
- TaskDescription _taskDescription) {
- mService = service;
- userId = UserHandle.getUserId(info.applicationInfo.uid);
- taskId = _taskId;
- lastActiveTime = SystemClock.elapsedRealtime();
- mAffiliatedTaskId = _taskId;
- voiceSession = null;
- voiceInteractor = null;
- isAvailable = true;
- mActivities = new ArrayList<>();
- mCallingUid = info.applicationInfo.uid;
- mCallingPackage = info.packageName;
- setIntent(_intent, info);
- setMinDimensions(info);
-
- isPersistable = true;
- // Clamp to [1, max].
- maxRecents = Math.min(Math.max(info.maxRecents, 1),
- ActivityTaskManager.getMaxAppRecentsLimitStatic());
-
- lastTaskDescription = _taskDescription;
- touchActiveTime();
- mService.getTaskChangeNotificationController().notifyTaskCreated(_taskId, realActivity);
- }
-
- /**
- * Don't use constructor directly. This is only used by XML parser.
- */
- TaskRecord(ActivityTaskManagerService service, int _taskId, Intent _intent,
+ /** Don't use constructor directly. This is only used by XML parser. */
+ TaskRecord(ActivityTaskManagerService atmService, int _taskId, Intent _intent,
Intent _affinityIntent, String _affinity, String _rootAffinity,
ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
boolean _autoRemoveRecents, boolean _askedCompatMode, int _userId,
@@ -404,15 +369,15 @@
TaskDescription _lastTaskDescription, int taskAffiliation, int prevTaskId,
int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
int resizeMode, boolean supportsPictureInPicture, boolean _realActivitySuspended,
- boolean userSetupComplete, int minWidth, int minHeight) {
- mService = service;
- taskId = _taskId;
- intent = _intent;
+ boolean userSetupComplete, int minWidth, int minHeight, ActivityInfo info,
+ IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor) {
+ mAtmService = atmService;
+ mTaskId = _taskId;
affinityIntent = _affinityIntent;
affinity = _affinity;
rootAffinity = _rootAffinity;
- voiceSession = null;
- voiceInteractor = null;
+ voiceSession = _voiceSession;
+ voiceInteractor = _voiceInteractor;
realActivity = _realActivity;
realActivitySuspended = _realActivitySuspended;
origActivity = _origActivity;
@@ -420,15 +385,15 @@
isAvailable = true;
autoRemoveRecents = _autoRemoveRecents;
askedCompatMode = _askedCompatMode;
- userId = _userId;
+ mUserId = _userId;
mUserSetupComplete = userSetupComplete;
effectiveUid = _effectiveUid;
- lastActiveTime = SystemClock.elapsedRealtime();
+ touchActiveTime();
lastDescription = _lastDescription;
mActivities = activities;
mLastTimeMoved = lastTimeMoved;
mNeverRelinquishIdentity = neverRelinquishIdentity;
- lastTaskDescription = _lastTaskDescription;
+ mTaskDescription = _lastTaskDescription;
mAffiliatedTaskId = taskAffiliation;
mAffiliatedTaskColor = taskAffiliationColor;
mPrevAffiliateTaskId = prevTaskId;
@@ -437,9 +402,15 @@
mCallingPackage = callingPackage;
mResizeMode = resizeMode;
mSupportsPictureInPicture = supportsPictureInPicture;
- mMinWidth = minWidth;
- mMinHeight = minHeight;
- mService.getTaskChangeNotificationController().notifyTaskCreated(_taskId, realActivity);
+ if (info != null) {
+ setIntent(_intent, info);
+ setMinDimensions(info);
+ } else {
+ intent = _intent;
+ mMinWidth = minWidth;
+ mMinHeight = minHeight;
+ }
+ mAtmService.getTaskChangeNotificationController().notifyTaskCreated(_taskId, realActivity);
}
Task getTask() {
@@ -458,9 +429,9 @@
if (stack == null) {
throw new IllegalArgumentException("TaskRecord: invalid stack=" + mStack);
}
- EventLog.writeEvent(WM_TASK_CREATED, taskId, stack.mStackId);
- mTask = new Task(taskId, stack, userId, mService.mWindowManager, mResizeMode,
- mSupportsPictureInPicture, lastTaskDescription, this);
+ EventLog.writeEvent(WM_TASK_CREATED, mTaskId, stack.mStackId);
+ mTask = new Task(mTaskId, stack, mUserId, mAtmService.mWindowManager, mResizeMode,
+ mSupportsPictureInPicture, mTaskDescription, this);
final int position = onTop ? POSITION_TOP : POSITION_BOTTOM;
if (!mDisplayedBounds.isEmpty()) {
@@ -487,14 +458,14 @@
final boolean isVoiceSession = voiceSession != null;
if (isVoiceSession) {
try {
- voiceSession.taskFinished(intent, taskId);
+ voiceSession.taskFinished(intent, mTaskId);
} catch (RemoteException e) {
}
}
if (autoRemoveFromRecents() || isVoiceSession) {
// Task creator asked to remove this when done, or this task was a voice
// interaction, so it should not remain on the recent tasks list.
- mService.mStackSupervisor.mRecentTasks.remove(this);
+ mAtmService.mStackSupervisor.mRecentTasks.remove(this);
}
removeWindowContainer();
@@ -502,9 +473,9 @@
@VisibleForTesting
void removeWindowContainer() {
- mService.getLockTaskController().clearLockedTask(this);
+ mAtmService.getLockTaskController().clearLockedTask(this);
if (mTask == null) {
- if (DEBUG_STACK) Slog.i(TAG_WM, "removeTask: could not find taskId=" + taskId);
+ if (DEBUG_STACK) Slog.i(TAG_WM, "removeTask: could not find taskId=" + mTaskId);
return;
}
mTask.removeIfPossible();
@@ -514,11 +485,11 @@
// default configuration the next time it launches.
setBounds(null);
}
- mService.getTaskChangeNotificationController().notifyTaskRemoved(taskId);
+ mAtmService.getTaskChangeNotificationController().notifyTaskRemoved(mTaskId);
}
- public void onSnapshotChanged(TaskSnapshot snapshot) {
- mService.getTaskChangeNotificationController().notifyTaskSnapshotChanged(taskId, snapshot);
+ void onSnapshotChanged(TaskSnapshot snapshot) {
+ mAtmService.getTaskChangeNotificationController().notifyTaskSnapshotChanged(mTaskId, snapshot);
}
void setResizeMode(int resizeMode) {
@@ -527,13 +498,13 @@
}
mResizeMode = resizeMode;
mTask.setResizeable(resizeMode);
- mService.mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
- mService.mRootActivityContainer.resumeFocusedStacksTopActivities();
+ mAtmService.mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
+ mAtmService.mRootActivityContainer.resumeFocusedStacksTopActivities();
}
void setTaskDockedResizing(boolean resizing) {
if (mTask == null) {
- Slog.w(TAG_WM, "setTaskDockedResizing: taskId " + taskId + " not found.");
+ Slog.w(TAG_WM, "setTaskDockedResizing: taskId " + mTaskId + " not found.");
return;
}
mTask.setTaskDockedResizing(resizing);
@@ -541,11 +512,11 @@
// TODO: Consolidate this with the resize() method below.
public void requestResize(Rect bounds, int resizeMode) {
- mService.resizeTask(taskId, bounds, resizeMode);
+ mAtmService.resizeTask(mTaskId, bounds, resizeMode);
}
boolean resize(Rect bounds, int resizeMode, boolean preserveWindow, boolean deferResume) {
- mService.deferWindowLayout();
+ mAtmService.deferWindowLayout();
try {
if (!isResizeable()) {
@@ -568,7 +539,7 @@
setBounds(bounds);
if (!inFreeformWindowingMode()) {
// re-restore the task so it can have the proper stack association.
- mService.mStackSupervisor.restoreRecentTaskLocked(this, null, !ON_TOP);
+ mAtmService.mStackSupervisor.restoreRecentTaskLocked(this, null, !ON_TOP);
}
return true;
}
@@ -582,7 +553,7 @@
// This method assumes that the task is already placed in the right stack.
// we do not mess with that decision and we only do the resize!
- Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeTask_" + taskId);
+ Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeTask_" + mTaskId);
boolean updatedConfig = false;
mTmpConfig.setTo(getResolvedOverrideConfiguration());
@@ -606,9 +577,9 @@
// this won't cause tons of irrelevant windows being preserved because only
// activities in this task may experience a bounds change. Configs for other
// activities stay the same.
- mService.mRootActivityContainer.ensureActivitiesVisible(r, 0, preserveWindow);
+ mAtmService.mRootActivityContainer.ensureActivitiesVisible(r, 0, preserveWindow);
if (!kept) {
- mService.mRootActivityContainer.resumeFocusedStacksTopActivities();
+ mAtmService.mRootActivityContainer.resumeFocusedStacksTopActivities();
}
}
}
@@ -619,7 +590,7 @@
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
return kept;
} finally {
- mService.continueWindowLayout();
+ mAtmService.continueWindowLayout();
}
}
@@ -687,9 +658,9 @@
boolean reparent(ActivityStack preferredStack, int position,
@ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
boolean schedulePictureInPictureModeChange, String reason) {
- final ActivityStackSupervisor supervisor = mService.mStackSupervisor;
- final RootActivityContainer root = mService.mRootActivityContainer;
- final WindowManagerService windowManager = mService.mWindowManager;
+ final ActivityStackSupervisor supervisor = mAtmService.mStackSupervisor;
+ final RootActivityContainer root = mAtmService.mRootActivityContainer;
+ final WindowManagerService windowManager = mAtmService.mWindowManager;
final ActivityStack sourceStack = getStack();
final ActivityStack toStack = supervisor.getReparentTargetStack(this, preferredStack,
position == MAX_VALUE);
@@ -725,7 +696,7 @@
windowManager.setWillReplaceWindow(topActivity.appToken, animate);
}
- mService.deferWindowLayout();
+ mAtmService.deferWindowLayout();
boolean kept = true;
try {
final ActivityRecord r = topRunningActivityLocked();
@@ -764,7 +735,7 @@
// Notify the voice session if required
if (voiceSession != null) {
try {
- voiceSession.taskStarted(intent, taskId);
+ voiceSession.taskStarted(intent, mTaskId);
} catch (RemoteException e) {
}
}
@@ -776,7 +747,7 @@
wasPaused, reason);
}
if (!animate) {
- mService.mStackSupervisor.mNoAnimActivities.add(topActivity);
+ mAtmService.mStackSupervisor.mNoAnimActivities.add(topActivity);
}
// We might trigger a configuration change. Save the current task bounds for freezing.
@@ -795,7 +766,7 @@
} else if (toStackWindowingMode == WINDOWING_MODE_FREEFORM) {
Rect bounds = getLaunchBounds();
if (bounds == null) {
- mService.mStackSupervisor.getLaunchParamsController().layoutTask(this, null);
+ mAtmService.mStackSupervisor.getLaunchParamsController().layoutTask(this, null);
bounds = configBounds;
}
kept = resize(bounds, RESIZE_MODE_FORCED, !mightReplaceWindow, deferResume);
@@ -803,13 +774,13 @@
if (toStackSplitScreenPrimary && moveStackMode == REPARENT_KEEP_STACK_AT_FRONT) {
// Move recents to front so it is not behind home stack when going into docked
// mode
- mService.mStackSupervisor.moveRecentsStackToFront(reason);
+ mAtmService.mStackSupervisor.moveRecentsStackToFront(reason);
}
kept = resize(toStack.getRequestedOverrideBounds(), RESIZE_MODE_SYSTEM,
!mightReplaceWindow, deferResume);
}
} finally {
- mService.continueWindowLayout();
+ mAtmService.continueWindowLayout();
}
if (mightReplaceWindow) {
@@ -846,7 +817,7 @@
void cancelWindowTransition() {
if (mTask == null) {
- Slog.w(TAG_WM, "cancelWindowTransition: taskId " + taskId + " not found.");
+ Slog.w(TAG_WM, "cancelWindowTransition: taskId " + mTaskId + " not found.");
return;
}
mTask.cancelTaskWindowTransition();
@@ -859,7 +830,7 @@
// TODO: Move this to {@link TaskWindowContainerController} once recent tasks are more
// synchronized between AM and WM.
- return mService.mWindowManager.getTaskSnapshot(taskId, userId, reducedResolution,
+ return mAtmService.mWindowManager.getTaskSnapshot(mTaskId, mUserId, reducedResolution,
restoreFromDisk);
}
@@ -938,9 +909,9 @@
// task as having a true root activity.
rootWasReset = true;
}
- userId = UserHandle.getUserId(info.applicationInfo.uid);
- mUserSetupComplete = Settings.Secure.getIntForUser(mService.mContext.getContentResolver(),
- USER_SETUP_COMPLETE, 0, userId) != 0;
+ mUserId = UserHandle.getUserId(info.applicationInfo.uid);
+ mUserSetupComplete = Settings.Secure.getIntForUser(
+ mAtmService.mContext.getContentResolver(), USER_SETUP_COMPLETE, 0, mUserId) != 0;
if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) {
// If the activity itself has requested auto-remove, then just always do it.
autoRemoveRecents = true;
@@ -993,12 +964,12 @@
void setPrevAffiliate(TaskRecord prevAffiliate) {
mPrevAffiliate = prevAffiliate;
- mPrevAffiliateTaskId = prevAffiliate == null ? INVALID_TASK_ID : prevAffiliate.taskId;
+ mPrevAffiliateTaskId = prevAffiliate == null ? INVALID_TASK_ID : prevAffiliate.mTaskId;
}
void setNextAffiliate(TaskRecord nextAffiliate) {
mNextAffiliate = nextAffiliate;
- mNextAffiliateTaskId = nextAffiliate == null ? INVALID_TASK_ID : nextAffiliate.taskId;
+ mNextAffiliateTaskId = nextAffiliate == null ? INVALID_TASK_ID : nextAffiliate.mTaskId;
}
<T extends ActivityStack> T getStack() {
@@ -1061,7 +1032,7 @@
@Override
protected void onParentChanged() {
super.onParentChanged();
- mService.mRootActivityContainer.updateUIDsPresentOnDisplay();
+ mAtmService.mRootActivityContainer.updateUIDsPresentOnDisplay();
}
// Close up recents linked list.
@@ -1080,13 +1051,13 @@
closeRecentsChain();
if (inRecents) {
inRecents = false;
- mService.notifyTaskPersisterLocked(this, false);
+ mAtmService.notifyTaskPersisterLocked(this, false);
}
clearRootProcess();
- mService.mWindowManager.mTaskSnapshotController.notifyTaskRemovedFromRecents(
- taskId, userId);
+ mAtmService.mWindowManager.mTaskSnapshotController.notifyTaskRemovedFromRecents(
+ mTaskId, mUserId);
}
void setTaskToAffiliateWith(TaskRecord taskToAffiliateWith) {
@@ -1235,7 +1206,7 @@
boolean okToShowLocked() {
// NOTE: If {@link TaskRecord#topRunningActivity} return is not null then it is
// okay to show the activity when locked.
- return mService.mStackSupervisor.isCurrentProfileLocked(userId)
+ return mAtmService.mStackSupervisor.isCurrentProfileLocked(mUserId)
|| topRunningActivityLocked() != null;
}
@@ -1324,7 +1295,7 @@
updateEffectiveIntent();
if (r.isPersistable()) {
- mService.notifyTaskPersisterLocked(this, false);
+ mAtmService.notifyTaskPersisterLocked(this, false);
}
if (r.getParent() != null) {
@@ -1335,7 +1306,7 @@
// Make sure the list of display UID whitelists is updated
// now that this record is in a new task.
- mService.mRootActivityContainer.updateUIDsPresentOnDisplay();
+ mAtmService.mRootActivityContainer.updateUIDsPresentOnDisplay();
}
/**
@@ -1360,14 +1331,14 @@
numFullscreen--;
}
if (r.isPersistable()) {
- mService.notifyTaskPersisterLocked(this, false);
+ mAtmService.notifyTaskPersisterLocked(this, false);
}
if (inPinnedWindowingMode()) {
// We normally notify listeners of task stack changes on pause, however pinned stack
// activities are normally in the paused state so no notification will be sent there
// before the activity is removed. We send it here so instead.
- mService.getTaskChangeNotificationController().notifyTaskStackChanged();
+ mAtmService.getTaskChangeNotificationController().notifyTaskStackChanged();
}
if (mActivities.isEmpty()) {
@@ -1530,10 +1501,10 @@
}
final String pkg = (realActivity != null) ? realActivity.getPackageName() : null;
- final LockTaskController lockTaskController = mService.getLockTaskController();
+ final LockTaskController lockTaskController = mAtmService.getLockTaskController();
switch (r.lockTaskLaunchMode) {
case LOCK_TASK_LAUNCH_MODE_DEFAULT:
- mLockTaskAuth = lockTaskController.isPackageWhitelisted(userId, pkg)
+ mLockTaskAuth = lockTaskController.isPackageWhitelisted(mUserId, pkg)
? LOCK_TASK_AUTH_WHITELISTED : LOCK_TASK_AUTH_PINNABLE;
break;
@@ -1546,7 +1517,7 @@
break;
case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED:
- mLockTaskAuth = lockTaskController.isPackageWhitelisted(userId, pkg)
+ mLockTaskAuth = lockTaskController.isPackageWhitelisted(mUserId, pkg)
? LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE;
break;
}
@@ -1555,7 +1526,7 @@
}
private boolean isResizeable(boolean checkSupportsPip) {
- return (mService.mForceResizableActivities || ActivityInfo.isResizeableMode(mResizeMode)
+ return (mAtmService.mForceResizableActivities || ActivityInfo.isResizeableMode(mResizeMode)
|| (checkSupportsPip && mSupportsPictureInPicture));
}
@@ -1568,8 +1539,8 @@
// A task can not be docked even if it is considered resizeable because it only supports
// picture-in-picture mode but has a non-resizeable resizeMode
return super.supportsSplitScreenWindowingMode()
- && mService.mSupportsSplitScreenMultiWindow
- && (mService.mForceResizableActivities
+ && mAtmService.mSupportsSplitScreenMultiWindow
+ && (mAtmService.mForceResizableActivities
|| (isResizeable(false /* checkSupportsPip */)
&& !ActivityInfo.isPreserveOrientationMode(mResizeMode)));
}
@@ -1582,7 +1553,7 @@
* secondary display.
*/
boolean canBeLaunchedOnDisplay(int displayId) {
- return mService.mStackSupervisor.canPlaceEntityOnDisplay(displayId,
+ return mAtmService.mStackSupervisor.canPlaceEntityOnDisplay(displayId,
-1 /* don't check PID */, -1 /* don't check UID */, null /* activityInfo */);
}
@@ -1700,15 +1671,15 @@
}
topActivity = false;
}
- lastTaskDescription = new TaskDescription(label, null, iconResource, iconFilename,
+ mTaskDescription = new TaskDescription(label, null, iconResource, iconFilename,
colorPrimary, colorBackground, statusBarColor, navigationBarColor,
statusBarContrastWhenTransparent, navigationBarContrastWhenTransparent);
if (mTask != null) {
- mTask.setTaskDescription(lastTaskDescription);
+ mTask.setTaskDescription(mTaskDescription);
}
// Update the task affiliation color if we are the parent of the group
- if (taskId == mAffiliatedTaskId) {
- mAffiliatedTaskColor = lastTaskDescription.getPrimaryColor();
+ if (mTaskId == mAffiliatedTaskId) {
+ mAffiliatedTaskColor = mTaskDescription.getPrimaryColor();
}
}
}
@@ -1767,9 +1738,9 @@
// to do this for the pinned stack as the bounds are controlled by the system.
if (!inPinnedWindowingMode() && mStack != null) {
final int defaultMinSizeDp =
- mService.mRootActivityContainer.mDefaultMinSizeOfResizeableTaskDp;
+ mAtmService.mRootActivityContainer.mDefaultMinSizeOfResizeableTaskDp;
final ActivityDisplay display =
- mService.mRootActivityContainer.getActivityDisplay(mStack.mDisplayId);
+ mAtmService.mRootActivityContainer.getActivityDisplay(mStack.mDisplayId);
final float density =
(float) display.getConfiguration().densityDpi / DisplayMetrics.DENSITY_DEFAULT;
final int defaultMinSize = (int) (defaultMinSizeDp * density);
@@ -1849,7 +1820,7 @@
final boolean wasInMultiWindowMode = inMultiWindowMode();
super.onConfigurationChanged(newParentConfig);
if (wasInMultiWindowMode != inMultiWindowMode()) {
- mService.mStackSupervisor.scheduleUpdateMultiWindowMode(this);
+ mAtmService.mStackSupervisor.scheduleUpdateMultiWindowMode(this);
}
// If the configuration supports persistent bounds (eg. Freeform), keep track of the
@@ -1890,7 +1861,7 @@
}
// Saves the new state so that we can launch the activity at the same location.
- mService.mStackSupervisor.mLaunchParamsPersister.saveTask(this);
+ mAtmService.mStackSupervisor.mLaunchParamsPersister.saveTask(this);
}
/**
@@ -2293,7 +2264,7 @@
if (mLastNonFullscreenBounds != null) {
setBounds(mLastNonFullscreenBounds);
} else {
- mService.mStackSupervisor.getLaunchParamsController().layoutTask(this, null);
+ mAtmService.mStackSupervisor.getLaunchParamsController().layoutTask(this, null);
}
} else {
setBounds(inStack.getRequestedOverrideBounds());
@@ -2354,9 +2325,9 @@
*/
void fillTaskInfo(TaskInfo info) {
getNumRunningActivities(mReuseActivitiesReport);
- info.userId = userId;
+ info.userId = mUserId;
info.stackId = getStackId();
- info.taskId = taskId;
+ info.taskId = mTaskId;
info.displayId = mStack == null ? Display.INVALID_DISPLAY : mStack.mDisplayId;
info.isRunning = getTopActivity() != null;
info.baseIntent = new Intent(getBaseIntent());
@@ -2370,7 +2341,7 @@
info.realActivity = realActivity;
info.numActivities = mReuseActivitiesReport.numActivities;
info.lastActiveTime = lastActiveTime;
- info.taskDescription = new ActivityManager.TaskDescription(lastTaskDescription);
+ info.taskDescription = new ActivityManager.TaskDescription(mTaskDescription);
info.supportsSplitScreenMultiWindow = supportsSplitScreenWindowingMode();
info.resizeMode = mResizeMode;
info.configuration.setTo(getConfiguration());
@@ -2386,7 +2357,7 @@
}
void dump(PrintWriter pw, String prefix) {
- pw.print(prefix); pw.print("userId="); pw.print(userId);
+ pw.print(prefix); pw.print("userId="); pw.print(mUserId);
pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid);
pw.print(" mCallingUid="); UserHandle.formatUid(pw, mCallingUid);
pw.print(" mUserSetupComplete="); pw.print(mUserSetupComplete);
@@ -2440,7 +2411,7 @@
pw.print(" mReuseTask="); pw.print(mReuseTask);
pw.print(" mLockTaskAuth="); pw.println(lockTaskAuthToString());
}
- if (mAffiliatedTaskId != taskId || mPrevAffiliateTaskId != INVALID_TASK_ID
+ if (mAffiliatedTaskId != mTaskId || mPrevAffiliateTaskId != INVALID_TASK_ID
|| mPrevAffiliate != null || mNextAffiliateTaskId != INVALID_TASK_ID
|| mNextAffiliate != null) {
pw.print(prefix); pw.print("affiliation="); pw.print(mAffiliatedTaskId);
@@ -2487,7 +2458,7 @@
if (stringName != null) {
sb.append(stringName);
sb.append(" U=");
- sb.append(userId);
+ sb.append(mUserId);
sb.append(" StackId=");
sb.append(getStackId());
sb.append(" sz=");
@@ -2498,7 +2469,7 @@
sb.append("TaskRecord{");
sb.append(Integer.toHexString(System.identityHashCode(this)));
sb.append(" #");
- sb.append(taskId);
+ sb.append(mTaskId);
if (affinity != null) {
sb.append(" A=");
sb.append(affinity);
@@ -2523,7 +2494,7 @@
final long token = proto.start(fieldId);
super.writeToProto(proto, CONFIGURATION_CONTAINER, logLevel);
- proto.write(ID, taskId);
+ proto.write(ID, mTaskId);
for (int i = mActivities.size() - 1; i >= 0; i--) {
ActivityRecord activity = mActivities.get(i);
activity.writeToProto(proto, ACTIVITIES);
@@ -2573,7 +2544,7 @@
void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
if (DEBUG_RECENTS) Slog.i(TAG_RECENTS, "Saving task=" + this);
- out.attribute(null, ATTR_TASKID, String.valueOf(taskId));
+ out.attribute(null, ATTR_TASKID, String.valueOf(mTaskId));
if (realActivity != null) {
out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString());
}
@@ -2596,7 +2567,7 @@
out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset));
out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents));
out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode));
- out.attribute(null, ATTR_USERID, String.valueOf(userId));
+ out.attribute(null, ATTR_USERID, String.valueOf(mUserId));
out.attribute(null, ATTR_USER_SETUP_COMPLETE, String.valueOf(mUserSetupComplete));
out.attribute(null, ATTR_EFFECTIVE_UID, String.valueOf(effectiveUid));
out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved));
@@ -2604,8 +2575,8 @@
if (lastDescription != null) {
out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString());
}
- if (lastTaskDescription != null) {
- lastTaskDescription.saveToXml(out);
+ if (mTaskDescription != null) {
+ mTaskDescription.saveToXml(out);
}
out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor));
out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId));
@@ -2692,13 +2663,14 @@
TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
Intent intent, IVoiceInteractionSession voiceSession,
IVoiceInteractor voiceInteractor) {
- return new TaskRecord(
- service, taskId, info, intent, voiceSession, voiceInteractor);
+ return new TaskRecord(service, taskId, info, intent, voiceSession, voiceInteractor,
+ null /*taskDescription*/);
}
TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
Intent intent, TaskDescription taskDescription) {
- return new TaskRecord(service, taskId, info, intent, taskDescription);
+ return new TaskRecord(service, taskId, info, intent, null /*voiceSession*/,
+ null /*voiceInteractor*/, taskDescription);
}
/**
@@ -2720,7 +2692,8 @@
lastTimeMoved, neverRelinquishIdentity, lastTaskDescription, taskAffiliation,
prevTaskId, nextTaskId, taskAffiliationColor, callingUid, callingPackage,
resizeMode, supportsPictureInPicture, realActivitySuspended, userSetupComplete,
- minWidth, minHeight);
+ minWidth, minHeight, null /*ActivityInfo*/, null /*_voiceSession*/,
+ null /*_voiceInteractor*/);
}
TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index d070850..172ebce 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -134,6 +134,7 @@
private final int mStatusBarColor;
@VisibleForTesting final SystemBarBackgroundPainter mSystemBarBackgroundPainter;
private final int mOrientationOnCreation;
+ private final SurfaceControl.Transaction mTransaction;
static TaskSnapshotSurface create(WindowManagerService service, AppWindowToken token,
TaskSnapshot snapshot) {
@@ -252,6 +253,7 @@
windowPrivateFlags, sysUiVis, taskDescription, 1f);
mStatusBarColor = taskDescription.getStatusBarColor();
mOrientationOnCreation = currentOrientation;
+ mTransaction = mService.mTransactionFactory.get();
}
@Override
@@ -336,27 +338,23 @@
surface.copyFrom(mChildSurfaceControl);
final Rect frame;
- SurfaceControl.openTransaction();
- try {
- // We can just show the surface here as it will still be hidden as the parent is
- // still hidden.
- mChildSurfaceControl.show();
- if (aspectRatioMismatch) {
- // Clip off ugly navigation bar.
- final Rect crop = calculateSnapshotCrop();
- frame = calculateSnapshotFrame(crop);
- mChildSurfaceControl.setWindowCrop(crop);
- mChildSurfaceControl.setPosition(frame.left, frame.top);
- } else {
- frame = null;
- }
-
- // Scale the mismatch dimensions to fill the task bounds
- final float scale = 1 / mSnapshot.getScale();
- mChildSurfaceControl.setMatrix(scale, 0, 0, scale);
- } finally {
- SurfaceControl.closeTransaction();
+ // We can just show the surface here as it will still be hidden as the parent is
+ // still hidden.
+ mTransaction.show(mChildSurfaceControl);
+ if (aspectRatioMismatch) {
+ // Clip off ugly navigation bar.
+ final Rect crop = calculateSnapshotCrop();
+ frame = calculateSnapshotFrame(crop);
+ mTransaction.setWindowCrop(mChildSurfaceControl, crop);
+ mTransaction.setPosition(mChildSurfaceControl, frame.left, frame.top);
+ } else {
+ frame = null;
}
+
+ // Scale the mismatch dimensions to fill the task bounds
+ final float scale = 1 / mSnapshot.getScale();
+ mTransaction.setMatrix(mChildSurfaceControl, scale, 0, 0, scale);
+ mTransaction.apply();
surface.attachAndQueueBufferWithColorSpace(buffer, mSnapshot.getColorSpace());
surface.release();
diff --git a/services/core/java/com/android/server/wm/Watermark.java b/services/core/java/com/android/server/wm/Watermark.java
index 729cfc0..725aaa48 100644
--- a/services/core/java/com/android/server/wm/Watermark.java
+++ b/services/core/java/com/android/server/wm/Watermark.java
@@ -55,7 +55,7 @@
private boolean mDrawNeeded;
Watermark(Supplier<Surface> surfaceFactory, DisplayContent dc, DisplayMetrics dm,
- String[] tokens) {
+ String[] tokens, SurfaceControl.Transaction t) {
if (false) {
Log.i(TAG_WM, "*********************** WATERMARK");
for (int i=0; i<tokens.length; i++) {
@@ -121,21 +121,21 @@
.setBufferSize(1, 1)
.setFormat(PixelFormat.TRANSLUCENT)
.build();
- ctrl.setLayerStack(mDisplay.getLayerStack());
- ctrl.setLayer(WindowManagerService.TYPE_LAYER_MULTIPLIER*100);
- ctrl.setPosition(0, 0);
- ctrl.show();
+ t.setLayerStack(ctrl, mDisplay.getLayerStack())
+ .setLayer(ctrl, WindowManagerService.TYPE_LAYER_MULTIPLIER * 100)
+ .setPosition(ctrl, 0, 0)
+ .show(ctrl);
mSurface.copyFrom(ctrl);
} catch (OutOfResourcesException e) {
}
mSurfaceControl = ctrl;
}
- void positionSurface(int dw, int dh) {
+ void positionSurface(int dw, int dh, SurfaceControl.Transaction t) {
if (mLastDW != dw || mLastDH != dh) {
mLastDW = dw;
mLastDH = dh;
- mSurfaceControl.setBufferSize(dw, dh);
+ t.setBufferSize(mSurfaceControl, dw, dh);
mDrawNeeded = true;
}
}
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index f437b28..3a1d6e0 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -161,7 +161,8 @@
dc.checkAppWindowsReadyToShow();
orAnimating(dc.getDockedDividerController().animate(mCurrentTime));
if (accessibilityController != null) {
- accessibilityController.drawMagnifiedRegionBorderIfNeededLocked(displayId);
+ accessibilityController.drawMagnifiedRegionBorderIfNeededLocked(displayId,
+ mTransaction);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 19fcb1b..a4ab66a 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -33,6 +33,7 @@
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
import android.annotation.CallSuper;
import android.annotation.IntDef;
@@ -54,9 +55,11 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ToBooleanFunction;
+import com.android.server.policy.WindowManagerPolicy;
import com.android.server.wm.SurfaceAnimator.Animatable;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.function.Consumer;
@@ -124,6 +127,11 @@
private final Transaction mPendingTransaction;
/**
+ * Windows that clients are waiting to have drawn.
+ */
+ final ArrayList<WindowState> mWaitingForDrawn = new ArrayList<>();
+
+ /**
* Applied as part of the animation pass in "prepareSurfaces".
*/
protected final SurfaceAnimator mSurfaceAnimator;
@@ -1434,6 +1442,19 @@
}
}
+ void waitForAllWindowsDrawn() {
+ final WindowManagerPolicy policy = mWmService.mPolicy;
+ forAllWindows(w -> {
+ final boolean keyguard = policy.isKeyguardHostWindow(w.mAttrs);
+ if (w.isVisibleLw() && (w.mAppToken != null || keyguard)) {
+ w.mWinAnimator.mDrawState = DRAW_PENDING;
+ // Force add to mResizingWindows.
+ w.resetLastContentInsets();
+ mWaitingForDrawn.add(w);
+ }
+ }, true /* traverseTopToBottom */);
+ }
+
Dimmer getDimmer() {
if (mParent == null) {
return null;
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index abbd1ab..f4b7672 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -313,10 +313,15 @@
public abstract void showGlobalActions();
/**
- * Invalidate all visible windows. Then report back on the callback once all windows have
- * redrawn.
+ * Invalidate all visible windows on a given display, and report back on the callback when all
+ * windows have redrawn.
+ *
+ * @param callback reporting callback to be called when all windows have redrawn.
+ * @param timeout calls the callback anyway after the timeout.
+ * @param displayId waits for the windows on the given display, INVALID_DISPLAY to wait for all
+ * windows on all displays.
*/
- public abstract void waitForAllWindowsDrawn(Runnable callback, long timeout);
+ public abstract void waitForAllWindowsDrawn(Runnable callback, long timeout, int displayId);
/**
* Overrides the display size.
@@ -502,6 +507,13 @@
public abstract boolean shouldShowIme(int displayId);
/**
+ * Show IME on imeTargetWindow once IME has finished layout.
+ *
+ * @param imeTargetWindowToken token of the (IME target) window on which IME should be shown.
+ */
+ public abstract void showImePostLayout(IBinder imeTargetWindowToken);
+
+ /**
* Tell window manager about a package that should not be running with high refresh rate
* setting until removeNonHighRefreshRatePackage is called for the same package.
*
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 1f45cfb..6f9f2c0 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -290,6 +290,7 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
@@ -568,13 +569,10 @@
final ArrayList<WindowState> mForceRemoves = new ArrayList<>();
/**
- * Windows that clients are waiting to have drawn.
+ * The callbacks to make when the windows all have been drawn for a given
+ * {@link WindowContainer}.
*/
- ArrayList<WindowState> mWaitingForDrawn = new ArrayList<>();
- /**
- * And the callback to make when they've all been drawn.
- */
- Runnable mWaitingForDrawnCallback;
+ final HashMap<WindowContainer, Runnable> mWaitingForDrawnCallbacks = new HashMap<>();
/** List of window currently causing non-system overlay windows to be hidden. */
private ArrayList<WindowState> mHidingNonSystemOverlayWindows = new ArrayList<>();
@@ -1271,14 +1269,7 @@
// Add ourself to the Watchdog monitors.
Watchdog.getInstance().addMonitor(this);
-
- openSurfaceTransaction();
- try {
- createWatermarkInTransaction();
- } finally {
- closeSurfaceTransaction("createWatermarkInTransaction");
- }
-
+ createWatermark();
showEmulatorDisplayOverlayIfNeeded();
}
@@ -3437,60 +3428,45 @@
public void showCircularMask(boolean visible) {
synchronized (mGlobalLock) {
+ if (visible) {
+ // TODO(multi-display): support multiple displays
+ if (mCircularDisplayMask == null) {
+ int screenOffset = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_windowOutsetBottom);
+ int maskThickness = mContext.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.circular_display_mask_thickness);
- if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM,
- ">>> OPEN TRANSACTION showCircularMask(visible=" + visible + ")");
- openSurfaceTransaction();
- try {
- if (visible) {
- // TODO(multi-display): support multiple displays
- if (mCircularDisplayMask == null) {
- int screenOffset = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_windowOutsetBottom);
- int maskThickness = mContext.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.circular_display_mask_thickness);
- mCircularDisplayMask = new CircularDisplayMask(mSurfaceFactory,
- getDefaultDisplayContentLocked(),
- mPolicy.getWindowLayerFromTypeLw(
- WindowManager.LayoutParams.TYPE_POINTER)
- * TYPE_LAYER_MULTIPLIER + 10, screenOffset, maskThickness);
+ if (SHOW_LIGHT_TRANSACTIONS) {
+ Slog.i(TAG_WM,
+ ">>> showCircularMask(visible=" + visible + ")");
}
- mCircularDisplayMask.setVisibility(true);
- } else if (mCircularDisplayMask != null) {
- mCircularDisplayMask.setVisibility(false);
- mCircularDisplayMask = null;
+ mCircularDisplayMask = new CircularDisplayMask(mSurfaceFactory,
+ getDefaultDisplayContentLocked(), mPolicy.getWindowLayerFromTypeLw(
+ WindowManager.LayoutParams.TYPE_POINTER) * TYPE_LAYER_MULTIPLIER
+ + 10, screenOffset, maskThickness, mTransaction);
}
- } finally {
- closeSurfaceTransaction("showCircularMask");
- if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM,
- "<<< CLOSE TRANSACTION showCircularMask(visible=" + visible + ")");
+ mCircularDisplayMask.setVisibility(true, mTransaction);
+ } else if (mCircularDisplayMask != null) {
+ mCircularDisplayMask.setVisibility(false, mTransaction);
+ mCircularDisplayMask = null;
}
+ mTransaction.apply();
}
}
public void showEmulatorDisplayOverlay() {
synchronized (mGlobalLock) {
- if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM,
- ">>> OPEN TRANSACTION showEmulatorDisplayOverlay");
- openSurfaceTransaction();
- try {
- if (mEmulatorDisplayOverlay == null) {
- mEmulatorDisplayOverlay = new EmulatorDisplayOverlay(
- mSurfaceFactory,
- mContext,
- getDefaultDisplayContentLocked(),
- mPolicy.getWindowLayerFromTypeLw(
- WindowManager.LayoutParams.TYPE_POINTER)
- * TYPE_LAYER_MULTIPLIER + 10);
- }
- mEmulatorDisplayOverlay.setVisibility(true);
- } finally {
- closeSurfaceTransaction("showEmulatorDisplayOverlay");
- if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM,
- "<<< CLOSE TRANSACTION showEmulatorDisplayOverlay");
+ if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM, ">>> showEmulatorDisplayOverlay");
+ if (mEmulatorDisplayOverlay == null) {
+ mEmulatorDisplayOverlay = new EmulatorDisplayOverlay(mSurfaceFactory, mContext,
+ getDefaultDisplayContentLocked(),
+ mPolicy.getWindowLayerFromTypeLw(WindowManager.LayoutParams.TYPE_POINTER)
+ * TYPE_LAYER_MULTIPLIER + 10, mTransaction);
}
+ mEmulatorDisplayOverlay.setVisibility(true, mTransaction);
+ mTransaction.apply();
}
}
@@ -3519,23 +3495,16 @@
return;
}
- if (SHOW_VERBOSE_TRANSACTIONS) Slog.i(TAG_WM,
- ">>> OPEN TRANSACTION showStrictModeViolation");
+ if (SHOW_VERBOSE_TRANSACTIONS) Slog.i(TAG_WM, ">>> showStrictModeViolation");
// TODO: Modify this to use the surface trace once it is not going crazy.
// b/31532461
- SurfaceControl.openTransaction();
- try {
- // TODO(multi-display): support multiple displays
- if (mStrictModeFlash == null) {
- mStrictModeFlash = new StrictModeFlash(mSurfaceFactory,
- getDefaultDisplayContentLocked());
- }
- mStrictModeFlash.setVisibility(on);
- } finally {
- SurfaceControl.closeTransaction();
- if (SHOW_VERBOSE_TRANSACTIONS) Slog.i(TAG_WM,
- "<<< CLOSE TRANSACTION showStrictModeViolation");
+ // TODO(multi-display): support multiple displays
+ if (mStrictModeFlash == null) {
+ mStrictModeFlash = new StrictModeFlash(mSurfaceFactory,
+ getDefaultDisplayContentLocked(), mTransaction);
}
+ mStrictModeFlash.setVisibility(on, mTransaction);
+ mTransaction.apply();
}
}
@@ -4736,12 +4705,12 @@
case WAITING_FOR_DRAWN_TIMEOUT: {
Runnable callback = null;
+ final WindowContainer container = (WindowContainer) msg.obj;
synchronized (mGlobalLock) {
ProtoLog.w(WM_ERROR, "Timeout waiting for drawn: undrawn=%s",
- mWaitingForDrawn);
- mWaitingForDrawn.clear();
- callback = mWaitingForDrawnCallback;
- mWaitingForDrawnCallback = null;
+ container.mWaitingForDrawn);
+ container.mWaitingForDrawn.clear();
+ callback = mWaitingForDrawnCallbacks.remove(container);
}
if (callback != null) {
callback.run();
@@ -4773,9 +4742,9 @@
}
case ALL_WINDOWS_DRAWN: {
Runnable callback;
+ final WindowContainer container = (WindowContainer) msg.obj;
synchronized (mGlobalLock) {
- callback = mWaitingForDrawnCallback;
- mWaitingForDrawnCallback = null;
+ callback = mWaitingForDrawnCallbacks.remove(container);
}
if (callback != null) {
callback.run();
@@ -5265,30 +5234,32 @@
}
void checkDrawnWindowsLocked() {
- if (mWaitingForDrawn.isEmpty() || mWaitingForDrawnCallback == null) {
+ if (mWaitingForDrawnCallbacks.isEmpty()) {
return;
}
- for (int j = mWaitingForDrawn.size() - 1; j >= 0; j--) {
- WindowState win = mWaitingForDrawn.get(j);
- ProtoLog.i(WM_DEBUG_SCREEN_ON,
+ mWaitingForDrawnCallbacks.forEach((container, callback) -> {
+ for (int j = container.mWaitingForDrawn.size() - 1; j >= 0; j--) {
+ final WindowState win = (WindowState) container.mWaitingForDrawn.get(j);
+ ProtoLog.i(WM_DEBUG_SCREEN_ON,
"Waiting for drawn %s: removed=%b visible=%b mHasSurface=%b drawState=%d",
win, win.mRemoved, win.isVisibleLw(), win.mHasSurface,
win.mWinAnimator.mDrawState);
- if (win.mRemoved || !win.mHasSurface || !win.isVisibleByPolicy()) {
- // Window has been removed or hidden; no draw will now happen, so stop waiting.
- ProtoLog.w(WM_DEBUG_SCREEN_ON, "Aborted waiting for drawn: %s", win);
- mWaitingForDrawn.remove(win);
- } else if (win.hasDrawnLw()) {
- // Window is now drawn (and shown).
- ProtoLog.d(WM_DEBUG_SCREEN_ON, "Window drawn win=%s", win);
- mWaitingForDrawn.remove(win);
+ if (win.mRemoved || !win.mHasSurface || !win.isVisibleByPolicy()) {
+ // Window has been removed or hidden; no draw will now happen, so stop waiting.
+ ProtoLog.w(WM_DEBUG_SCREEN_ON, "Aborted waiting for drawn: %s", win);
+ container.mWaitingForDrawn.remove(win);
+ } else if (win.hasDrawnLw()) {
+ // Window is now drawn (and shown).
+ ProtoLog.d(WM_DEBUG_SCREEN_ON, "Window drawn win=%s", win);
+ container.mWaitingForDrawn.remove(win);
+ }
}
- }
- if (mWaitingForDrawn.isEmpty()) {
- ProtoLog.d(WM_DEBUG_SCREEN_ON, "All windows drawn!");
- mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);
- mH.sendEmptyMessage(H.ALL_WINDOWS_DRAWN);
- }
+ if (container.mWaitingForDrawn.isEmpty()) {
+ ProtoLog.d(WM_DEBUG_SCREEN_ON, "All windows drawn!");
+ mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, container);
+ mH.sendMessage(mH.obtainMessage(H.ALL_WINDOWS_DRAWN, container));
+ }
+ });
}
void setHoldScreenLocked(final Session newHoldScreen) {
@@ -5520,7 +5491,7 @@
return val;
}
- void createWatermarkInTransaction() {
+ void createWatermark() {
if (mWatermark != null) {
return;
}
@@ -5538,8 +5509,8 @@
// TODO(multi-display): Show watermarks on secondary displays.
final DisplayContent displayContent = getDefaultDisplayContentLocked();
mWatermark = new Watermark(mSurfaceFactory, displayContent,
- displayContent.mRealDisplayMetrics,
- toks);
+ displayContent.mRealDisplayMetrics, toks, mTransaction);
+ mTransaction.apply();
}
}
} catch (FileNotFoundException e) {
@@ -5934,13 +5905,18 @@
}
}
}
- if (mWaitingForDrawn.size() > 0) {
+ if (!mWaitingForDrawnCallbacks.isEmpty()) {
pw.println();
pw.println(" Clients waiting for these windows to be drawn:");
- for (int i=mWaitingForDrawn.size()-1; i>=0; i--) {
- WindowState win = mWaitingForDrawn.get(i);
- pw.print(" Waiting #"); pw.print(i); pw.print(' '); pw.print(win);
- }
+ mWaitingForDrawnCallbacks.forEach((wc, callback) -> {
+ pw.print(" WindowContainer ");
+ pw.println(wc.getName());
+ for (int i = wc.mWaitingForDrawn.size() - 1; i >= 0; i--) {
+ final WindowState win = (WindowState) wc.mWaitingForDrawn.get(i);
+ pw.print(" Waiting #"); pw.print(i); pw.print(' '); pw.print(win);
+ }
+ });
+
}
pw.println();
pw.print(" mGlobalConfiguration="); pw.println(mRoot.getConfiguration());
@@ -7096,17 +7072,25 @@
}
@Override
- public void waitForAllWindowsDrawn(Runnable callback, long timeout) {
+ public void waitForAllWindowsDrawn(Runnable callback, long timeout, int displayId) {
+ final WindowContainer container = displayId == INVALID_DISPLAY
+ ? mRoot : mRoot.getDisplayContent(displayId);
+ if (container == null) {
+ // The waiting container doesn't exist, no need to wait to run the callback. Run and
+ // return;
+ callback.run();
+ return;
+ }
boolean allWindowsDrawn = false;
synchronized (mGlobalLock) {
- mWaitingForDrawnCallback = callback;
- getDefaultDisplayContentLocked().waitForAllWindowsDrawn();
+ container.waitForAllWindowsDrawn();
mWindowPlacerLocked.requestTraversal();
- mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);
- if (mWaitingForDrawn.isEmpty()) {
+ mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, container);
+ if (container.mWaitingForDrawn.isEmpty()) {
allWindowsDrawn = true;
} else {
- mH.sendEmptyMessageDelayed(H.WAITING_FOR_DRAWN_TIMEOUT, timeout);
+ mWaitingForDrawnCallbacks.put(container, callback);
+ mH.sendNewMessageDelayed(H.WAITING_FOR_DRAWN_TIMEOUT, container, timeout);
checkDrawnWindowsLocked();
}
}
@@ -7303,6 +7287,29 @@
}
@Override
+ public void showImePostLayout(IBinder imeTargetWindowToken) {
+ synchronized (mGlobalLock) {
+ final WindowState imeTarget = mWindowMap.get(imeTargetWindowToken);
+ if (imeTarget == null) {
+ return;
+ }
+ final DisplayContent displayContent = imeTarget.getDisplayContent();
+ if (displayContent == null) {
+ Slog.w(TAG_WM, "Attempted to show IME on an IME target that does not exist: "
+ + imeTarget.getName());
+ return;
+ }
+ if (displayContent.isUntrustedVirtualDisplay()) {
+ throw new SecurityException("Attempted to show IME on an untrusted "
+ + "virtual display: " + displayContent.getDisplayId());
+ }
+
+ displayContent.getInsetsStateController().getImeSourceProvider()
+ .scheduleShowImePostLayout(imeTarget);
+ }
+ }
+
+ @Override
public boolean isUidAllowedOnDisplay(int displayId, int uid) {
if (displayId == Display.DEFAULT_DISPLAY) {
return true;
@@ -7636,7 +7643,7 @@
// to do so because it seems possible to resume activities as part of a larger
// transaction and it's too early to resume based on current order when performing
// updateTopResumedActivityIfNeeded().
- displayContent.mAcitvityDisplay.ensureActivitiesVisible(null /* starting */,
+ displayContent.mActivityDisplay.ensureActivitiesVisible(null /* starting */,
0 /* configChanges */, !PRESERVE_WINDOWS, true /* notifyClients */);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index d7116d8..1c0d156 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -702,7 +702,7 @@
}
ActivityRecord hist = mActivities.get(0);
intent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_APP, hist.packageName);
- intent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK, hist.getTaskRecord().taskId);
+ intent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK, hist.getTaskRecord().mTaskId);
}
boolean shouldKillProcessForRemovedTask(TaskRecord tr) {
@@ -713,7 +713,7 @@
return false;
}
final TaskRecord otherTask = activity.getTaskRecord();
- if (tr.taskId != otherTask.taskId && otherTask.inRecents) {
+ if (tr.mTaskId != otherTask.mTaskId && otherTask.inRecents) {
// Don't kill process(es) that has an activity in a different task that is
// also in recents.
return false;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 1270658..56e08b2 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -836,7 +836,7 @@
*/
boolean inSizeCompatMode() {
return (mAttrs.privateFlags & PRIVATE_FLAG_COMPATIBLE_WINDOW) != 0
- || (mAppToken != null && mAppToken.inSizeCompatMode()
+ || (mAppToken != null && mAppToken.hasSizeCompatBounds()
// Exclude starting window because it is not displayed by the application.
&& mAttrs.type != TYPE_APPLICATION_STARTING);
}
@@ -2320,7 +2320,7 @@
}
// The offset of compatibility bounds is applied to surface of {@link #AppWindowToken}
// and frame, so it is unnecessary to translate twice in surface based coordinates.
- final int surfaceOffsetX = mAppToken.inSizeCompatMode()
+ final int surfaceOffsetX = mAppToken.hasSizeCompatBounds()
? mAppToken.getBounds().left : 0;
mTmpRect.offset(surfaceOffsetX - mWindowFrames.mFrame.left, -mWindowFrames.mFrame.top);
region.set(mTmpRect);
@@ -3497,7 +3497,7 @@
@Override
void setWaitingForDrawnIfResizingChanged() {
if (isDragResizeChanged()) {
- mWmService.mWaitingForDrawn.add(this);
+ mWmService.mRoot.mWaitingForDrawn.add(this);
}
super.setWaitingForDrawnIfResizingChanged();
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 3dcf6ec..1328273 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -506,9 +506,8 @@
flags |= SurfaceControl.OPAQUE;
}
- mSurfaceController = new WindowSurfaceController(mSession.mSurfaceSession,
- attrs.getTitle().toString(), width, height, format, flags, this,
- windowType, ownerUid);
+ mSurfaceController = new WindowSurfaceController(attrs.getTitle().toString(), width,
+ height, format, flags, this, windowType, ownerUid);
mSurfaceController.setColorSpaceAgnostic((attrs.privateFlags
& WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC) != 0);
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 49f27a1..7f68c48 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -37,7 +37,6 @@
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.SurfaceControl;
-import android.view.SurfaceSession;
import android.view.WindowContentFrameStats;
import com.android.server.protolog.common.ProtoLog;
@@ -85,7 +84,7 @@
private final SurfaceControl.Transaction mTmpTransaction;
- public WindowSurfaceController(SurfaceSession s, String name, int w, int h, int format,
+ WindowSurfaceController(String name, int w, int h, int format,
int flags, WindowStateAnimator animator, int windowType, int ownerUid) {
mAnimator = animator;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index b118cdf..47291cb 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -11320,6 +11320,28 @@
}
}
+ @Override
+ public boolean isActiveSupervisionApp(int uid) {
+ synchronized (getLockObject()) {
+ final ActiveAdmin admin = getActiveAdminWithPolicyForUidLocked(
+ null, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, uid);
+ if (admin == null) {
+ return false;
+ }
+
+ final String supervisionString = mContext.getResources().getString(
+ com.android.internal.R.string
+ .config_defaultSupervisionProfileOwnerComponent);
+ if (supervisionString == null) {
+ return false;
+ }
+
+ final ComponentName supervisorComponent = ComponentName.unflattenFromString(
+ supervisionString);
+ return admin.info.getComponent().equals(supervisorComponent);
+ }
+ }
+
private void notifyCrossProfileProvidersChanged(int userId, List<String> packages) {
final List<OnCrossProfileWidgetProvidersChangeListener> listeners;
synchronized (getLockObject()) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index de65002..a453164 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -501,7 +501,7 @@
mRuntimeStartElapsedTime, mRuntimeStartUptime);
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
// Prepare the thread pool for init tasks that can be parallelized
- SystemServerInitThreadPool.get();
+ SystemServerInitThreadPool.start();
} finally {
t.traceEnd(); // InitBeforeStartServices
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
index 108b017..2aa625a 100644
--- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
@@ -108,7 +108,7 @@
@Mock
private AlarmManager mAlarmManager;
@Mock
- private ConnectivityService mConnectivityService;
+ private ConnectivityManager mConnectivityManager;
@Mock
private ContentResolver mContentResolver;
@Mock
@@ -127,7 +127,7 @@
private SensorManager mSensorManager;
class InjectorForTest extends DeviceIdleController.Injector {
- ConnectivityService connectivityService;
+ ConnectivityManager connectivityManager;
LocationManager locationManager;
ConstraintController constraintController;
// Freeze time for testing.
@@ -155,8 +155,8 @@
}
@Override
- ConnectivityService getConnectivityService() {
- return connectivityService;
+ ConnectivityManager getConnectivityManager() {
+ return connectivityManager;
}
@Override
@@ -347,19 +347,19 @@
public void testUpdateConnectivityState() {
// No connectivity service
final boolean isConnected = mDeviceIdleController.isNetworkConnected();
- mInjector.connectivityService = null;
+ mInjector.connectivityManager = null;
mDeviceIdleController.updateConnectivityState(null);
assertEquals(isConnected, mDeviceIdleController.isNetworkConnected());
// No active network info
- mInjector.connectivityService = mConnectivityService;
- doReturn(null).when(mConnectivityService).getActiveNetworkInfo();
+ mInjector.connectivityManager = mConnectivityManager;
+ doReturn(null).when(mConnectivityManager).getActiveNetworkInfo();
mDeviceIdleController.updateConnectivityState(null);
assertFalse(mDeviceIdleController.isNetworkConnected());
// Active network info says connected.
final NetworkInfo ani = mock(NetworkInfo.class);
- doReturn(ani).when(mConnectivityService).getActiveNetworkInfo();
+ doReturn(ani).when(mConnectivityManager).getActiveNetworkInfo();
doReturn(true).when(ani).isConnected();
mDeviceIdleController.updateConnectivityState(null);
assertTrue(mDeviceIdleController.isNetworkConnected());
@@ -1827,10 +1827,10 @@
}
private void setNetworkConnected(boolean connected) {
- mInjector.connectivityService = mConnectivityService;
+ mInjector.connectivityManager = mConnectivityManager;
final NetworkInfo ani = mock(NetworkInfo.class);
doReturn(connected).when(ani).isConnected();
- doReturn(ani).when(mConnectivityService).getActiveNetworkInfo();
+ doReturn(ani).when(mConnectivityManager).getActiveNetworkInfo();
mDeviceIdleController.updateConnectivityState(null);
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java
index 4538cac..5c2b8ce 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java
@@ -20,6 +20,8 @@
import static com.google.common.truth.Truth.assertWithMessage;
+import static org.junit.Assert.assertArrayEquals;
+
import android.content.Context;
import android.content.res.Resources;
import android.os.Binder;
@@ -184,8 +186,56 @@
.isFalse();
}
+ /**
+ * Matrix should match the precalculated one for given cct and display primaries.
+ */
+ @Test
+ public void displayWhiteBalance_validateTransformMatrix() {
+ DisplayPrimaries displayPrimaries = new DisplayPrimaries();
+ displayPrimaries.red = new CieXyz();
+ displayPrimaries.red.X = 0.412315f;
+ displayPrimaries.red.Y = 0.212600f;
+ displayPrimaries.red.Z = 0.019327f;
+ displayPrimaries.green = new CieXyz();
+ displayPrimaries.green.X = 0.357600f;
+ displayPrimaries.green.Y = 0.715200f;
+ displayPrimaries.green.Z = 0.119200f;
+ displayPrimaries.blue = new CieXyz();
+ displayPrimaries.blue.X = 0.180500f;
+ displayPrimaries.blue.Y = 0.072200f;
+ displayPrimaries.blue.Z = 0.950633f;
+ displayPrimaries.white = new CieXyz();
+ displayPrimaries.white.X = 0.950456f;
+ displayPrimaries.white.Y = 1.000000f;
+ displayPrimaries.white.Z = 1.089058f;
+ doReturn(displayPrimaries)
+ .when(() -> SurfaceControl.getDisplayNativePrimaries(mDisplayToken));
+
+ setUpTintController();
+ assertWithMessage("Setup with valid SurfaceControl failed")
+ .that(mDisplayWhiteBalanceTintController.mSetUp)
+ .isTrue();
+
+ final int cct = 6500;
+ mDisplayWhiteBalanceTintController.setMatrix(cct);
+ assertWithMessage("Failed to set temperature")
+ .that(mDisplayWhiteBalanceTintController.mCurrentColorTemperature)
+ .isEqualTo(cct);
+
+ float[] matrixDwb = mDisplayWhiteBalanceTintController.getMatrix();
+ final float[] expectedMatrixDwb = {
+ 0.962880f, -0.001780f, -0.000158f, 0.0f,
+ 0.035765f, 0.929988f, 0.000858f, 0.0f,
+ 0.001354f, -0.000470f, 0.948327f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f
+ };
+ assertArrayEquals("Unexpected DWB matrix", matrixDwb, expectedMatrixDwb,
+ 1e-6f /* tolerance */);
+ }
+
private void setUpTintController() {
mDisplayWhiteBalanceTintController = new DisplayWhiteBalanceTintController();
mDisplayWhiteBalanceTintController.setUp(mMockedContext, true);
+ mDisplayWhiteBalanceTintController.setActivated(true);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index a25e40f..9a1fd9c 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -2650,6 +2650,21 @@
verifyStayOnWhilePluggedCleared(false);
}
+ public void testIsActiveSupervisionApp() throws Exception {
+ when(mServiceContext.resources
+ .getString(R.string.config_defaultSupervisionProfileOwnerComponent))
+ .thenReturn(admin1.flattenToString());
+
+ final int PROFILE_USER = 15;
+ final int PROFILE_ADMIN = UserHandle.getUid(PROFILE_USER, 19436);
+ addManagedProfile(admin1, PROFILE_ADMIN, admin1);
+ mContext.binder.callingUid = PROFILE_ADMIN;
+
+ final DevicePolicyManagerInternal dpmi =
+ LocalServices.getService(DevicePolicyManagerInternal.class);
+ assertTrue(dpmi.isActiveSupervisionApp(PROFILE_ADMIN));
+ }
+
// Test if lock timeout on managed profile is handled correctly depending on whether profile
// uses separate challenge.
public void testSetMaximumTimeToLockProfile() throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientLuxTest.java b/services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientLuxTest.java
index 0d5a7d6..acf2d0e 100644
--- a/services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientLuxTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientLuxTest.java
@@ -78,6 +78,8 @@
@Mock private TypedArray mBiases;
@Mock private TypedArray mHighLightBrightnesses;
@Mock private TypedArray mHighLightBiases;
+ @Mock private TypedArray mAmbientColorTemperatures;
+ @Mock private TypedArray mDisplayColorTemperatures;
@Before
public void setUp() throws Exception {
@@ -105,10 +107,10 @@
HIGH_LIGHT_AMBIENT_COLOR_TEMPERATURE);
when(mResourcesSpy.obtainTypedArray(
R.array.config_displayWhiteBalanceAmbientColorTemperatures))
- .thenReturn(createTypedArray());
+ .thenReturn(mAmbientColorTemperatures);
when(mResourcesSpy.obtainTypedArray(
R.array.config_displayWhiteBalanceDisplayColorTemperatures))
- .thenReturn(createTypedArray());
+ .thenReturn(mDisplayColorTemperatures);
when(mResourcesSpy.obtainTypedArray(
R.array.config_displayWhiteBalanceLowLightAmbientBrightnesses))
@@ -388,6 +390,16 @@
assertEquals(controller.mPendingAmbientColorTemperature, ambientColorTemperature, 0.001);
}
+ @Test
+ public void testWhiteBalance_updateWithEmptyFilter() throws Exception {
+ setAmbientColorTemperatures(5300.0f, 6000.0f, 7000.0f, 8000.0f);
+ setDisplayColorTemperatures(6300.0f, 6400.0f, 6850.0f, 7450.0f);
+ DisplayWhiteBalanceController controller =
+ DisplayWhiteBalanceFactory.create(mHandler, mSensorManagerMock, mResourcesSpy);
+ controller.updateAmbientColorTemperature();
+ assertEquals(-1.0f, controller.mPendingAmbientColorTemperature, 0);
+ }
+
void mockThrottler() {
when(mResourcesSpy.getInteger(
R.integer.config_displayWhiteBalanceDecreaseDebounce)).thenReturn(0);
@@ -455,6 +467,14 @@
setFloatArrayResource(mHighLightBiases, vals);
}
+ private void setAmbientColorTemperatures(float... vals) {
+ setFloatArrayResource(mAmbientColorTemperatures, vals);
+ }
+
+ private void setDisplayColorTemperatures(float... vals) {
+ setFloatArrayResource(mDisplayColorTemperatures, vals);
+ }
+
private void setFloatArrayResource(TypedArray array, float[] vals) {
when(array.length()).thenReturn(vals.length);
for (int i = 0; i < vals.length; i++) {
diff --git a/services/tests/servicestests/src/com/android/server/integrity/model/AtomicFormulaTest.java b/services/tests/servicestests/src/com/android/server/integrity/model/AtomicFormulaTest.java
new file mode 100644
index 0000000..1cb2fb3
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/integrity/model/AtomicFormulaTest.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2019 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.integrity.model;
+
+import static com.android.server.testutils.TestUtils.assertExpectException;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class AtomicFormulaTest {
+
+ @Test
+ public void testValidAtomicFormula_stringValue() {
+ AtomicFormula atomicFormula = new AtomicFormula(AtomicFormula.Key.PACKAGE_NAME,
+ AtomicFormula.Operator.EQ, "com.test.app");
+
+ assertEquals(AtomicFormula.Key.PACKAGE_NAME, atomicFormula.getKey());
+ assertEquals(AtomicFormula.Operator.EQ, atomicFormula.getOperator());
+ assertEquals("com.test.app", atomicFormula.getStringValue());
+ }
+
+ @Test
+ public void testValidAtomicFormula_intValue() {
+ AtomicFormula atomicFormula = new AtomicFormula(AtomicFormula.Key.VERSION_CODE,
+ AtomicFormula.Operator.LE, 1);
+
+ assertEquals(AtomicFormula.Key.VERSION_CODE, atomicFormula.getKey());
+ assertEquals(AtomicFormula.Operator.LE, atomicFormula.getOperator());
+ assertEquals(1, atomicFormula.getIntValue().intValue());
+ }
+
+ @Test
+ public void testValidAtomicFormula_boolValue() {
+ AtomicFormula atomicFormula = new AtomicFormula(AtomicFormula.Key.PRE_INSTALLED,
+ AtomicFormula.Operator.EQ, true);
+
+ assertEquals(AtomicFormula.Key.PRE_INSTALLED, atomicFormula.getKey());
+ assertEquals(AtomicFormula.Operator.EQ, atomicFormula.getOperator());
+ assertEquals(true, atomicFormula.getBoolValue());
+ }
+
+ @Test
+ public void testInvalidAtomicFormula_stringValue() {
+ assertExpectException(
+ IllegalArgumentException.class,
+ /* expectedExceptionMessageRegex */
+ String.format("Key %s cannot have string value", AtomicFormula.Key.VERSION_CODE),
+ () -> new AtomicFormula(AtomicFormula.Key.VERSION_CODE, AtomicFormula.Operator.EQ,
+ "test-value"));
+ }
+
+ @Test
+ public void testInvalidAtomicFormula_intValue() {
+ assertExpectException(
+ IllegalArgumentException.class,
+ /* expectedExceptionMessageRegex */
+ String.format("Key %s cannot have integer value", AtomicFormula.Key.PACKAGE_NAME),
+ () -> new AtomicFormula(AtomicFormula.Key.PACKAGE_NAME, AtomicFormula.Operator.EQ,
+ 1));
+ }
+
+ @Test
+ public void testInvalidAtomicFormula_boolValue() {
+ assertExpectException(
+ IllegalArgumentException.class,
+ /* expectedExceptionMessageRegex */
+ String.format("Key %s cannot have boolean value", AtomicFormula.Key.PACKAGE_NAME),
+ () -> new AtomicFormula(AtomicFormula.Key.PACKAGE_NAME, AtomicFormula.Operator.EQ,
+ true));
+ }
+
+ @Test
+ public void testValidateOperator_invalidKeyOperatorPair() {
+ assertExpectException(
+ IllegalArgumentException.class,
+ /* expectedExceptionMessageRegex */
+ String.format("Invalid operator %s used for key %s",
+ AtomicFormula.Operator.LE, AtomicFormula.Key.PACKAGE_NAME),
+ () -> new AtomicFormula(AtomicFormula.Key.PACKAGE_NAME, AtomicFormula.Operator.LE,
+ "test-value"));
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/integrity/model/OpenFormulaTest.java b/services/tests/servicestests/src/com/android/server/integrity/model/OpenFormulaTest.java
new file mode 100644
index 0000000..2133a7d
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/integrity/model/OpenFormulaTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2019 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.integrity.model;
+
+import static com.android.server.testutils.TestUtils.assertExpectException;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+@RunWith(JUnit4.class)
+public class OpenFormulaTest {
+
+ private static final AtomicFormula ATOMIC_FORMULA_1 = new AtomicFormula(
+ AtomicFormula.Key.PACKAGE_NAME, AtomicFormula.Operator.EQ, "test1");
+ private static final AtomicFormula ATOMIC_FORMULA_2 = new AtomicFormula(
+ AtomicFormula.Key.VERSION_CODE, AtomicFormula.Operator.EQ, 1);
+
+ @Test
+ public void testValidOpenFormula() {
+ OpenFormula openFormula = new OpenFormula(OpenFormula.Connector.AND,
+ Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
+
+ assertEquals(OpenFormula.Connector.AND, openFormula.getConnector());
+ assertEquals(Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2), openFormula.getFormulas());
+ }
+
+ @Test
+ public void testValidateAuxiliaryFormula_binaryConnectors() {
+ assertExpectException(
+ IllegalArgumentException.class,
+ /* expectedExceptionMessageRegex */
+ String.format("Connector %s must have at least 2 formulas",
+ OpenFormula.Connector.AND),
+ () -> new OpenFormula(OpenFormula.Connector.AND,
+ Collections.singletonList(ATOMIC_FORMULA_1)));
+ }
+
+ @Test
+ public void testValidateAuxiliaryFormula_unaryConnectors() {
+ assertExpectException(
+ IllegalArgumentException.class,
+ /* expectedExceptionMessageRegex */
+ String.format("Connector %s must have 1 formula only", OpenFormula.Connector.NOT),
+ () -> new OpenFormula(OpenFormula.Connector.NOT,
+ Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2)));
+ }
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
index f652c5af..721641a 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
@@ -15,6 +15,8 @@
*/
package com.android.server.notification;
+import static com.android.server.notification.GroupHelper.AUTOGROUP_KEY;
+
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
@@ -155,6 +157,196 @@
}
@Test
+ public void testAutoGroupCount_addingNoGroupSBN() {
+ final String pkg = "package";
+ ArrayList<StatusBarNotification> notifications = new ArrayList<>();
+ for (int i = 0; i < AUTOGROUP_AT_COUNT + 1; i++) {
+ notifications.add(getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM));
+ }
+
+ for (StatusBarNotification sbn: notifications) {
+ sbn.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
+ sbn.setOverrideGroupKey(AUTOGROUP_KEY);
+ }
+
+ for (StatusBarNotification sbn: notifications) {
+ mGroupHelper.onNotificationPosted(sbn, true);
+ }
+
+ verify(mCallback, times(AUTOGROUP_AT_COUNT + 1))
+ .updateAutogroupSummary(anyString(), eq(true));
+
+ int userId = UserHandle.SYSTEM.getIdentifier();
+ assertEquals(mGroupHelper.getOngoingGroupCount(
+ userId, pkg, AUTOGROUP_KEY), AUTOGROUP_AT_COUNT + 1);
+ }
+
+ @Test
+ public void testAutoGroupCount_UpdateNotification() {
+ final String pkg = "package";
+ ArrayList<StatusBarNotification> notifications = new ArrayList<>();
+ for (int i = 0; i < AUTOGROUP_AT_COUNT + 1; i++) {
+ notifications.add(getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM));
+ }
+
+ for (StatusBarNotification sbn: notifications) {
+ sbn.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
+ sbn.setOverrideGroupKey(AUTOGROUP_KEY);
+ }
+
+ for (StatusBarNotification sbn: notifications) {
+ mGroupHelper.onNotificationPosted(sbn, true);
+ }
+
+ notifications.get(0).getNotification().flags &= ~Notification.FLAG_ONGOING_EVENT;
+
+ mGroupHelper.onNotificationUpdated(notifications.get(0), true);
+
+ verify(mCallback, times(AUTOGROUP_AT_COUNT + 2))
+ .updateAutogroupSummary(anyString(), eq(true));
+
+ int userId = UserHandle.SYSTEM.getIdentifier();
+ assertEquals(mGroupHelper.getOngoingGroupCount(
+ userId, pkg, AUTOGROUP_KEY), AUTOGROUP_AT_COUNT);
+ }
+
+ @Test
+ public void testAutoGroupCount_UpdateNotificationAfterChanges() {
+ final String pkg = "package";
+ ArrayList<StatusBarNotification> notifications = new ArrayList<>();
+ for (int i = 0; i < AUTOGROUP_AT_COUNT + 1; i++) {
+ notifications.add(getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM));
+ }
+
+ for (StatusBarNotification sbn: notifications) {
+ sbn.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
+ sbn.setOverrideGroupKey(AUTOGROUP_KEY);
+ }
+
+ for (StatusBarNotification sbn: notifications) {
+ mGroupHelper.onNotificationPosted(sbn, true);
+ }
+
+ notifications.get(0).getNotification().flags &= ~Notification.FLAG_ONGOING_EVENT;
+
+ mGroupHelper.onNotificationUpdated(notifications.get(0), true);
+
+ notifications.get(0).getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
+
+ mGroupHelper.onNotificationUpdated(notifications.get(0), true);
+
+ verify(mCallback, times(AUTOGROUP_AT_COUNT + 3))
+ .updateAutogroupSummary(anyString(), eq(true));
+
+ int userId = UserHandle.SYSTEM.getIdentifier();
+ assertEquals(mGroupHelper.getOngoingGroupCount(
+ userId, pkg, AUTOGROUP_KEY), AUTOGROUP_AT_COUNT + 1);
+ }
+
+ @Test
+ public void testAutoGroupCount_RemoveNotification() {
+ final String pkg = "package";
+ ArrayList<StatusBarNotification> notifications = new ArrayList<>();
+ for (int i = 0; i < AUTOGROUP_AT_COUNT + 1; i++) {
+ notifications.add(getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM));
+ }
+
+ for (StatusBarNotification sbn: notifications) {
+ sbn.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
+ sbn.setOverrideGroupKey(AUTOGROUP_KEY);
+ }
+
+ for (StatusBarNotification sbn: notifications) {
+ mGroupHelper.onNotificationPosted(sbn, true);
+ }
+
+ mGroupHelper.onNotificationRemoved(notifications.get(0));
+
+ verify(mCallback, times(AUTOGROUP_AT_COUNT + 2))
+ .updateAutogroupSummary(anyString(), eq(true));
+
+ int userId = UserHandle.SYSTEM.getIdentifier();
+ assertEquals(mGroupHelper.getOngoingGroupCount(
+ userId, pkg, AUTOGROUP_KEY), AUTOGROUP_AT_COUNT);
+ }
+
+
+ @Test
+ public void testAutoGroupCount_UpdateToNoneOngoingNotification() {
+ final String pkg = "package";
+ ArrayList<StatusBarNotification> notifications = new ArrayList<>();
+ for (int i = 0; i < AUTOGROUP_AT_COUNT + 1; i++) {
+ notifications.add(getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM));
+ }
+
+ for (StatusBarNotification sbn: notifications) {
+ sbn.setOverrideGroupKey(AUTOGROUP_KEY);
+ }
+
+ for (StatusBarNotification sbn: notifications) {
+ mGroupHelper.onNotificationPosted(sbn, true);
+ }
+
+ notifications.get(0).getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
+ mGroupHelper.onNotificationUpdated(notifications.get(0), true);
+
+ verify(mCallback, times(1))
+ .updateAutogroupSummary(anyString(), eq(true));
+
+ int userId = UserHandle.SYSTEM.getIdentifier();
+ assertEquals(mGroupHelper.getOngoingGroupCount(
+ userId, pkg, AUTOGROUP_KEY), 1);
+ }
+
+ @Test
+ public void testAutoGroupCount_AddOneOngoingNotification() {
+ final String pkg = "package";
+ ArrayList<StatusBarNotification> notifications = new ArrayList<>();
+ for (int i = 0; i < AUTOGROUP_AT_COUNT + 1; i++) {
+ notifications.add(getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM));
+ }
+ StatusBarNotification sbn = notifications.get(0);
+ sbn.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
+ sbn.setOverrideGroupKey(AUTOGROUP_KEY);
+
+
+ for (StatusBarNotification current: notifications) {
+ mGroupHelper.onNotificationPosted(current, true);
+ }
+
+ verify(mCallback, times(1))
+ .updateAutogroupSummary(anyString(), eq(true));
+
+ int userId = UserHandle.SYSTEM.getIdentifier();
+ assertEquals(mGroupHelper.getOngoingGroupCount(
+ userId, pkg, AUTOGROUP_KEY), 1);
+ }
+
+ @Test
+ public void testAutoGroupCount_UpdateNoneOngoing() {
+ final String pkg = "package";
+ ArrayList<StatusBarNotification> notifications = new ArrayList<>();
+ for (int i = 0; i < AUTOGROUP_AT_COUNT + 1; i++) {
+ notifications.add(getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM));
+ }
+
+ for (StatusBarNotification sbn: notifications) {
+ sbn.setOverrideGroupKey(AUTOGROUP_KEY);
+ }
+
+ for (StatusBarNotification sbn: notifications) {
+ mGroupHelper.onNotificationPosted(sbn, true);
+ }
+
+ verify(mCallback, times(0))
+ .updateAutogroupSummary(anyString(), eq(true));
+
+ int userId = UserHandle.SYSTEM.getIdentifier();
+ assertEquals(mGroupHelper.getOngoingGroupCount(userId, pkg, AUTOGROUP_KEY), 0);
+ }
+
+
+ @Test
public void testDropToZeroRemoveGroup() throws Exception {
final String pkg = "package";
List<StatusBarNotification> posted = new ArrayList<>();
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index e80c629..4ea2fc0 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -44,6 +44,7 @@
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Build.VERSION_CODES.O_MR1;
import static android.os.Build.VERSION_CODES.P;
+import static android.os.UserHandle.USER_SYSTEM;
import static android.service.notification.Adjustment.KEY_IMPORTANCE;
import static android.service.notification.Adjustment.KEY_USER_SENTIMENT;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
@@ -129,6 +130,7 @@
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.testing.TestablePermissions;
+import android.testing.TestableResources;
import android.text.Html;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -1180,6 +1182,36 @@
}
@Test
+ public void testAutobundledSummary_notificationAdded() {
+ NotificationRecord summary =
+ generateNotificationRecord(mTestNotificationChannel, 0, "pkg", true);
+ summary.getNotification().flags |= Notification.FLAG_AUTOGROUP_SUMMARY;
+ mService.addNotification(summary);
+ mService.mSummaryByGroupKey.put("pkg", summary);
+ mService.mAutobundledSummaries.put(0, new ArrayMap<>());
+ mService.mAutobundledSummaries.get(0).put("pkg", summary.getKey());
+ mService.updateAutobundledSummaryFlags(0, "pkg", true);
+
+ assertTrue(summary.sbn.isOngoing());
+ }
+
+ @Test
+ public void testAutobundledSummary_notificationRemoved() {
+ NotificationRecord summary =
+ generateNotificationRecord(mTestNotificationChannel, 0, "pkg", true);
+ summary.getNotification().flags |= Notification.FLAG_AUTOGROUP_SUMMARY;
+ summary.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
+ mService.addNotification(summary);
+ mService.mAutobundledSummaries.put(0, new ArrayMap<>());
+ mService.mAutobundledSummaries.get(0).put("pkg", summary.getKey());
+ mService.mSummaryByGroupKey.put("pkg", summary);
+
+ mService.updateAutobundledSummaryFlags(0, "pkg", false);
+
+ assertFalse(summary.sbn.isOngoing());
+ }
+
+ @Test
public void testCancelAllNotifications_IgnoreForegroundService() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
@@ -3278,7 +3310,7 @@
@Test
public void testRestore() throws Exception {
int systemChecks = mService.countSystemChecks;
- mBinderService.applyRestore(null, UserHandle.USER_SYSTEM);
+ mBinderService.applyRestore(null, USER_SYSTEM);
assertEquals(1, mService.countSystemChecks - systemChecks);
}
@@ -3347,7 +3379,7 @@
reset(mUgmInternal);
when(mUgmInternal.newUriPermissionOwner(any())).thenReturn(new Binder());
mService.updateUriPermissions(recordA, null, mContext.getPackageName(),
- UserHandle.USER_SYSTEM);
+ USER_SYSTEM);
verify(mUgm, times(1)).grantUriPermissionFromOwner(any(), anyInt(), any(),
eq(message1.getDataUri()), anyInt(), anyInt(), anyInt());
verify(mUgm, times(1)).grantUriPermissionFromOwner(any(), anyInt(), any(),
@@ -3363,21 +3395,21 @@
// Update means we drop access to first
reset(mUgmInternal);
mService.updateUriPermissions(recordB, recordA, mContext.getPackageName(),
- UserHandle.USER_SYSTEM);
+ USER_SYSTEM);
verify(mUgmInternal, times(1)).revokeUriPermissionFromOwner(any(),
eq(message1.getDataUri()), anyInt(), anyInt());
// Update back means we grant access to first again
reset(mUgm);
mService.updateUriPermissions(recordA, recordB, mContext.getPackageName(),
- UserHandle.USER_SYSTEM);
+ USER_SYSTEM);
verify(mUgm, times(1)).grantUriPermissionFromOwner(any(), anyInt(), any(),
eq(message1.getDataUri()), anyInt(), anyInt(), anyInt());
// And update to empty means we drop everything
reset(mUgmInternal);
mService.updateUriPermissions(null, recordB, mContext.getPackageName(),
- UserHandle.USER_SYSTEM);
+ USER_SYSTEM);
verify(mUgmInternal, times(1)).revokeUriPermissionFromOwner(any(), eq(null),
anyInt(), anyInt());
}
@@ -4077,7 +4109,7 @@
public void testIsCallerInstantApp_userAllNotification() throws Exception {
ApplicationInfo info = new ApplicationInfo();
info.privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT;
- when(mPackageManager.getApplicationInfo(anyString(), anyInt(), eq(UserHandle.USER_SYSTEM)))
+ when(mPackageManager.getApplicationInfo(anyString(), anyInt(), eq(USER_SYSTEM)))
.thenReturn(info);
when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{"any"});
@@ -5666,4 +5698,33 @@
StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(PKG);
assertEquals(1, notifsAfter.length);
}
+
+ @Test
+ public void testLoadDefaultApprovedServices_emptyResources() {
+ TestableResources tr = mContext.getOrCreateTestableResources();
+ tr.addOverride(com.android.internal.R.string.config_defaultListenerAccessPackages, "");
+ tr.addOverride(com.android.internal.R.string.config_defaultDndAccessPackages, "");
+ tr.addOverride(com.android.internal.R.string.config_defaultAssistantAccessComponent, "");
+ setDefaultAssistantInDeviceConfig("");
+
+ mService.loadDefaultApprovedServices(USER_SYSTEM);
+
+ verify(mListeners, never()).addDefaultComponentOrPackage(anyString());
+ verify(mConditionProviders, never()).addDefaultComponentOrPackage(anyString());
+ verify(mAssistants, never()).addDefaultComponentOrPackage(anyString());
+ }
+
+ @Test
+ public void testLoadDefaultApprovedServices_dnd() {
+ TestableResources tr = mContext.getOrCreateTestableResources();
+ tr.addOverride(com.android.internal.R.string.config_defaultDndAccessPackages, "test");
+ when(mListeners.queryPackageForServices(anyString(), anyInt(), anyInt()))
+ .thenReturn(new ArraySet<>());
+
+ mService.loadDefaultApprovedServices(USER_SYSTEM);
+
+ verify(mConditionProviders, times(1)).addDefaultComponentOrPackage("test");
+ }
+
+ // TODO: add tests for the rest of the non-empty cases
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
index 69cc9b2..fff3221 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
@@ -317,24 +317,24 @@
doAnswer(invocation -> {
display.positionChildAtTop(stack3, false);
return true;
- }).when(mSupervisor).removeTaskByIdLocked(eq(task4.taskId), anyBoolean(), anyBoolean(),
+ }).when(mSupervisor).removeTaskByIdLocked(eq(task4.mTaskId), anyBoolean(), anyBoolean(),
any());
// Removing stacks from the display while removing stacks.
doAnswer(invocation -> {
display.removeChild(stack2);
return true;
- }).when(mSupervisor).removeTaskByIdLocked(eq(task2.taskId), anyBoolean(), anyBoolean(),
+ }).when(mSupervisor).removeTaskByIdLocked(eq(task2.mTaskId), anyBoolean(), anyBoolean(),
any());
runnable.run();
- verify(mSupervisor).removeTaskByIdLocked(eq(task4.taskId), anyBoolean(), anyBoolean(),
+ verify(mSupervisor).removeTaskByIdLocked(eq(task4.mTaskId), anyBoolean(), anyBoolean(),
any());
- verify(mSupervisor).removeTaskByIdLocked(eq(task3.taskId), anyBoolean(), anyBoolean(),
+ verify(mSupervisor).removeTaskByIdLocked(eq(task3.mTaskId), anyBoolean(), anyBoolean(),
any());
- verify(mSupervisor).removeTaskByIdLocked(eq(task2.taskId), anyBoolean(), anyBoolean(),
+ verify(mSupervisor).removeTaskByIdLocked(eq(task2.mTaskId), anyBoolean(), anyBoolean(),
any());
- verify(mSupervisor).removeTaskByIdLocked(eq(task1.taskId), anyBoolean(), anyBoolean(),
+ verify(mSupervisor).removeTaskByIdLocked(eq(task1.mTaskId), anyBoolean(), anyBoolean(),
any());
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
index 9e1df91..1eeca91 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
@@ -127,7 +127,7 @@
mSupervisor.handleNonResizableTaskIfNeeded(task, newDisplay.getWindowingMode(),
newDisplay.mDisplayId, stack);
// The top activity is unresizable, so it should notify the activity is forced resizing.
- verify(taskChangeNotifier).notifyActivityForcedResizable(eq(task.taskId),
+ verify(taskChangeNotifier).notifyActivityForcedResizable(eq(task.mTaskId),
eq(FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY),
eq(unresizableActivity.packageName));
reset(taskChangeNotifier);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index 668ad78..77fbdcf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -42,7 +42,6 @@
import android.os.Build;
import android.os.UserHandle;
import android.service.voice.IVoiceInteractionSession;
-import android.testing.DexmakerShareClassLoaderRule;
import android.util.Pair;
import android.view.DisplayInfo;
@@ -385,9 +384,10 @@
intent.setFlags(mFlags);
final TaskRecord task = new TaskRecord(mSupervisor.mService, mTaskId, aInfo,
- intent /*intent*/, mVoiceSession, null /*_voiceInteractor*/);
+ intent /*intent*/, mVoiceSession, null /*_voiceInteractor*/,
+ null /*taskDescription*/);
spyOn(task);
- task.userId = mUserId;
+ task.mUserId = mUserId;
if (mStack != null) {
mStack.moveToFront("test");
@@ -396,8 +396,6 @@
spyOn(task.mTask);
}
- task.touchActiveTime();
-
return task;
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index fcda494..2661735 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -221,7 +221,7 @@
containerBounds.set(0, 0, 600, 800);
mToken.onConfigurationChanged(newParentConfig);
- assertTrue(mToken.inSizeCompatMode());
+ assertTrue(mToken.hasSizeCompatBounds());
assertEquals(containerAppBounds, mToken.getBounds());
assertEquals((float) containerAppBounds.width() / fixedBounds.width(),
mToken.getSizeCompatScale(), 0.0001f /* delta */);
@@ -231,7 +231,7 @@
containerBounds.set(containerAppBounds);
mToken.onConfigurationChanged(newParentConfig);
- assertTrue(mToken.inSizeCompatMode());
+ assertTrue(mToken.hasSizeCompatBounds());
// Don't scale up, so the bounds keep the same as the fixed width.
assertEquals(fixedBounds.width(), mToken.getBounds().width());
// Assert the position is horizontal center.
@@ -243,7 +243,7 @@
containerBounds.set(0, 0, 1200, 2000);
mToken.onConfigurationChanged(newParentConfig);
// Assert don't use fixed bounds because the region is enough.
- assertFalse(mToken.inSizeCompatMode());
+ assertFalse(mToken.hasSizeCompatBounds());
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
index a98f79c..73420a0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
@@ -46,7 +46,7 @@
private static class TestWindowContainer extends WindowContainer<TestWindowContainer> {
final SurfaceControl mControl = mock(SurfaceControl.class);
- final SurfaceControl.Transaction mTransaction = mock(SurfaceControl.Transaction.class);
+ final SurfaceControl.Transaction mTransaction = spy(StubTransaction.class);
TestWindowContainer(WindowManagerService wm) {
super(wm);
@@ -66,7 +66,7 @@
private static class MockSurfaceBuildingContainer extends WindowContainer<TestWindowContainer> {
final SurfaceSession mSession = new SurfaceSession();
final SurfaceControl mHostControl = mock(SurfaceControl.class);
- final SurfaceControl.Transaction mHostTransaction = mock(SurfaceControl.Transaction.class);
+ final SurfaceControl.Transaction mHostTransaction = spy(StubTransaction.class);
MockSurfaceBuildingContainer(WindowManagerService wm) {
super(wm);
@@ -118,7 +118,7 @@
public void setUp() throws Exception {
mHost = new MockSurfaceBuildingContainer(mWm);
mSurfaceAnimatorStarter = spy(new SurfaceAnimatorStarterImpl());
- mTransaction = mock(SurfaceControl.Transaction.class);
+ mTransaction = spy(StubTransaction.class);
mDimmer = new Dimmer(mHost, mSurfaceAnimatorStarter);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index c48dc25..2ba3cbd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -706,13 +706,13 @@
final ActivityStack stack =
new ActivityTestsBase.StackBuilder(mWm.mAtmService.mRootActivityContainer)
- .setDisplay(dc.mAcitvityDisplay).build();
+ .setDisplay(dc.mActivityDisplay).build();
final ActivityRecord activity = stack.topTask().getTopActivity();
activity.setRequestedOrientation(newOrientation);
final ArgumentCaptor<Configuration> captor = ArgumentCaptor.forClass(Configuration.class);
- verify(dc.mAcitvityDisplay).updateDisplayOverrideConfigurationLocked(captor.capture(),
+ verify(dc.mActivityDisplay).updateDisplayOverrideConfigurationLocked(captor.capture(),
same(activity), anyBoolean(), same(null));
final Configuration newDisplayConfig = captor.getValue();
final int expectedOrientation = newOrientation == SCREEN_ORIENTATION_PORTRAIT
@@ -732,12 +732,12 @@
final ActivityStack stack =
new ActivityTestsBase.StackBuilder(mWm.mAtmService.mRootActivityContainer)
- .setDisplay(dc.mAcitvityDisplay).build();
+ .setDisplay(dc.mActivityDisplay).build();
final ActivityRecord activity = stack.topTask().getTopActivity();
activity.setRequestedOrientation(newOrientation);
- verify(dc.mAcitvityDisplay, never()).updateDisplayOverrideConfigurationLocked(any(),
+ verify(dc.mActivityDisplay, never()).updateDisplayOverrideConfigurationLocked(any(),
eq(activity), anyBoolean(), same(null));
assertEquals(dc.getDisplayRotation().getUserRotation(), dc.getRotation());
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
index be2ee29..46435eb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
@@ -422,7 +422,7 @@
@Override
void saveTask(TaskRecord task) {
- final int userId = task.userId;
+ final int userId = task.mUserId;
final ComponentName realActivity = task.realActivity;
mTmpParams.mPreferredDisplayId = task.getStack().mDisplayId;
mTmpParams.mWindowingMode = task.getWindowingMode();
@@ -436,7 +436,7 @@
@Override
void getLaunchParams(TaskRecord task, ActivityRecord activity, LaunchParams params) {
- final int userId = task != null ? task.userId : activity.mUserId;
+ final int userId = task != null ? task.mUserId : activity.mUserId;
final ComponentName name = task != null
? task.realActivity : activity.mActivityComponent;
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
index 49d778f..b9fef4b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
@@ -32,7 +32,6 @@
import static org.mockito.Matchers.any;
import android.content.ComponentName;
-import android.content.pm.PackageList;
import android.content.pm.PackageManagerInternal;
import android.graphics.Rect;
import android.os.UserHandle;
@@ -43,6 +42,7 @@
import androidx.test.filters.MediumTest;
import com.android.server.LocalServices;
+import com.android.server.pm.PackageList;
import com.android.server.wm.LaunchParamsController.LaunchParams;
import org.junit.Before;
@@ -115,16 +115,16 @@
ACTIVITY_TYPE_STANDARD, /* onTop */ true);
mTestTask = new TaskBuilder(mSupervisor).setComponent(TEST_COMPONENT).setStack(stack)
.build();
- mTestTask.userId = TEST_USER_ID;
+ mTestTask.mUserId = TEST_USER_ID;
mTestTask.mLastNonFullscreenBounds = TEST_BOUNDS;
mTestTask.hasBeenVisible = true;
mTaskWithDifferentComponent = new TaskBuilder(mSupervisor)
.setComponent(ALTERNATIVE_COMPONENT).build();
- mTaskWithDifferentComponent.userId = TEST_USER_ID;
+ mTaskWithDifferentComponent.mUserId = TEST_USER_ID;
mTaskWithDifferentUser = new TaskBuilder(mSupervisor).setComponent(TEST_COMPONENT).build();
- mTaskWithDifferentUser.userId = ALTERNATIVE_USER_ID;
+ mTaskWithDifferentUser.mUserId = ALTERNATIVE_USER_ID;
mTarget = new LaunchParamsPersister(mPersisterQueue, mSupervisor, mUserFolderGetter);
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
index 2d0416d..15417d7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
@@ -21,6 +21,7 @@
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -48,8 +49,8 @@
@Before
public void setUp() throws Exception {
mSurfaces = new SurfaceControlMocker();
- mLetterbox = new Letterbox(mSurfaces, () -> mock(SurfaceControl.Transaction.class));
- mTransaction = mock(SurfaceControl.Transaction.class);
+ mLetterbox = new Letterbox(mSurfaces, StubTransaction::new);
+ mTransaction = spy(StubTransaction.class);
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
index 47c76fc..05e173c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
@@ -707,7 +707,7 @@
TaskRecord tr = mock(TaskRecord.class);
tr.mLockTaskAuth = lockTaskAuth;
tr.intent = intent;
- tr.userId = TEST_USER_ID;
+ tr.mUserId = TEST_USER_ID;
return tr;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 445a5cc..cc598ff 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -882,7 +882,7 @@
@Test
public void testNotRestoreRecentTaskApis() {
final TaskRecord task = createTaskBuilder(".Task").build();
- final int taskId = task.taskId;
+ final int taskId = task.mTaskId;
mRecentTasks.add(task);
// Only keep the task in RecentTasks.
task.removeWindowContainer();
@@ -968,7 +968,7 @@
TEST_USER_0_ID, 0).getList();
assertTrue(expectedTasks.length == infos.size());
for (int i = 0; i < infos.size(); i++) {
- assertTrue(expectedTasks[i].taskId == infos.get(i).taskId);
+ assertTrue(expectedTasks[i].mTaskId == infos.get(i).taskId);
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index 6b28135..f353846 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -138,7 +138,7 @@
@Test
public void testIncludedApps_expectTargetAndVisible() {
mWm.setRecentsAnimationController(mController);
- final ActivityStack homeStack = mDisplayContent.mAcitvityDisplay.getOrCreateStack(
+ final ActivityStack homeStack = mDisplayContent.mActivityDisplay.getOrCreateStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
final AppWindowToken homeAppWindow =
new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
@@ -163,7 +163,7 @@
@Test
public void testWallpaperIncluded_expectTarget() throws Exception {
mWm.setRecentsAnimationController(mController);
- final ActivityStack homeStack = mDisplayContent.mAcitvityDisplay.getOrCreateStack(
+ final ActivityStack homeStack = mDisplayContent.mActivityDisplay.getOrCreateStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
final AppWindowToken homeAppWindow =
new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
@@ -192,7 +192,7 @@
@Test
public void testWallpaperAnimatorCanceled_expectAnimationKeepsRunning() throws Exception {
mWm.setRecentsAnimationController(mController);
- final ActivityStack homeStack = mDisplayContent.mAcitvityDisplay.getOrCreateStack(
+ final ActivityStack homeStack = mDisplayContent.mActivityDisplay.getOrCreateStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
final AppWindowToken homeAppWindow =
new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
@@ -223,7 +223,7 @@
@Test
public void testFinish_expectTargetAndWallpaperAdaptersRemoved() {
mWm.setRecentsAnimationController(mController);
- final ActivityStack homeStack = mDisplayContent.mAcitvityDisplay.getOrCreateStack(
+ final ActivityStack homeStack = mDisplayContent.mActivityDisplay.getOrCreateStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
final AppWindowToken homeAppWindow =
new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
index c6ffc46..ebedde7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -345,7 +345,7 @@
.setCreateTask(true)
.setComponent(new ComponentName(mContext.getPackageName(), "Home2"))
.build();
- otherUserHomeActivity.getTaskRecord().userId = TEST_USER_ID;
+ otherUserHomeActivity.getTaskRecord().mUserId = TEST_USER_ID;
ActivityStack fullscreenStack = display.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
diff --git a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
index 2ad40f2..f5d08dc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
+++ b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
@@ -239,4 +239,15 @@
public SurfaceControl.Transaction remove(SurfaceControl sc) {
return this;
}
+
+ @Override
+ public SurfaceControl.Transaction syncInputWindows() {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setColorSpaceAgnostic(SurfaceControl sc, boolean agnostic) {
+ return this;
+ }
+
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index 86e307b..0f8fb04 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -119,7 +119,7 @@
final byte[] serializedBytes = serializeToBytes(expected);
final TaskRecord actual = restoreFromBytes(serializedBytes);
- assertEquals(expected.taskId, actual.taskId);
+ assertEquals(expected.mTaskId, actual.mTaskId);
assertEquals(expected.mLastNonFullscreenBounds, actual.mLastNonFullscreenBounds);
}
@@ -132,7 +132,7 @@
@Test
public void testCopyBaseIntentForTaskInfo() {
final TaskRecord task = createTaskRecord(1);
- task.lastTaskDescription = new ActivityManager.TaskDescription();
+ task.mTaskDescription = new ActivityManager.TaskDescription();
final TaskInfo info = task.getTaskInfo();
// The intent of info should be a copy so assert that they are different instances.
@@ -648,9 +648,9 @@
final TaskRecord task1 = getTestTask();
final ActivityRecord activity1 = task1.getChildAt(0);
- assertEquals(task0.taskId,
+ assertEquals(task0.mTaskId,
ActivityRecord.getTaskForActivityLocked(activity0.appToken, false /* onlyRoot */));
- assertEquals(task1.taskId,
+ assertEquals(task1.mTaskId,
ActivityRecord.getTaskForActivityLocked(activity1.appToken, false /* onlyRoot */));
}
@@ -669,9 +669,9 @@
// Add one more on top
final ActivityRecord activity2 = new ActivityBuilder(mService).setTask(task).build();
- assertEquals(task.taskId,
+ assertEquals(task.mTaskId,
ActivityRecord.getTaskForActivityLocked(activity0.appToken, true /* onlyRoot */));
- assertEquals(task.taskId,
+ assertEquals(task.mTaskId,
ActivityRecord.getTaskForActivityLocked(activity1.appToken, true /* onlyRoot */));
assertEquals("No task must be reported for activity that is above root", INVALID_TASK_ID,
ActivityRecord.getTaskForActivityLocked(activity2.appToken, true /* onlyRoot */));
@@ -692,9 +692,9 @@
// Add one more on top
final ActivityRecord activity2 = new ActivityBuilder(mService).setTask(task).build();
- assertEquals(task.taskId,
+ assertEquals(task.mTaskId,
ActivityRecord.getTaskForActivityLocked(activity0.appToken, true /* onlyRoot */));
- assertEquals(task.taskId,
+ assertEquals(task.mTaskId,
ActivityRecord.getTaskForActivityLocked(activity1.appToken, true /* onlyRoot */));
assertEquals("No task must be reported for activity that is above root", INVALID_TASK_ID,
ActivityRecord.getTaskForActivityLocked(activity2.appToken, true /* onlyRoot */));
@@ -718,11 +718,11 @@
// Add one more activity on top
final ActivityRecord activity2 = new ActivityBuilder(mService).setTask(task).build();
- assertEquals(task.taskId,
+ assertEquals(task.mTaskId,
ActivityRecord.getTaskForActivityLocked(activity0.appToken, false /* onlyRoot */));
- assertEquals(task.taskId,
+ assertEquals(task.mTaskId,
ActivityRecord.getTaskForActivityLocked(activity1.appToken, false /* onlyRoot */));
- assertEquals(task.taskId,
+ assertEquals(task.mTaskId,
ActivityRecord.getTaskForActivityLocked(activity2.appToken, false /* onlyRoot */));
}
@@ -832,8 +832,8 @@
private TaskRecord createTaskRecord(int taskId) {
return new TaskRecord(mService, taskId, new Intent(), null, null, null,
ActivityBuilder.getDefaultComponent(), null, false, false, false, 0, 10050, null,
- new ArrayList<>(), 0, false, null, 0, 0, 0, 0, 0, null, 0, false, false, false, 0, 0
- );
+ new ArrayList<>(), 0, false, null, 0, 0, 0, 0, 0, null, 0, false, false, false, 0,
+ 0, null /*ActivityInfo*/, null /*_voiceSession*/, null /*_voiceInteractor*/);
}
private static class TestTaskRecordFactory extends TaskRecordFactory {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestActivityDisplay.java b/services/tests/wmtests/src/com/android/server/wm/TestActivityDisplay.java
index 778f0ca..9c3ff65 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestActivityDisplay.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestActivityDisplay.java
@@ -22,8 +22,11 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static org.mockito.ArgumentMatchers.any;
+
import android.hardware.display.DisplayManagerGlobal;
import android.view.Display;
import android.view.DisplayInfo;
@@ -85,6 +88,10 @@
displayRotation.setRotation(rotation);
return true;
}).when(displayRotation).updateRotationUnchecked(anyBoolean());
+
+ final InputMonitor inputMonitor = mDisplayContent.getInputMonitor();
+ spyOn(inputMonitor);
+ doNothing().when(inputMonitor).resumeDispatchingLw(any());
}
@SuppressWarnings("TypeParameterUnusedInFormals")
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowAnimationSpecTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowAnimationSpecTest.java
index 0330de8..bfc0741 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowAnimationSpecTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowAnimationSpecTest.java
@@ -27,6 +27,7 @@
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.graphics.Point;
@@ -50,7 +51,7 @@
@Presubmit
public class WindowAnimationSpecTest {
private final SurfaceControl mSurfaceControl = mock(SurfaceControl.class);
- private final SurfaceControl.Transaction mTransaction = mock(SurfaceControl.Transaction.class);
+ private final SurfaceControl.Transaction mTransaction = spy(StubTransaction.class);
private final Animation mAnimation = mock(Animation.class);
private final Rect mStackBounds = new Rect(0, 0, 10, 10);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index e5fb28d..a09253a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -452,7 +452,7 @@
@Test
public void testSeamlesslyRotateWindow() {
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
- final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
+ final SurfaceControl.Transaction t = spy(StubTransaction.class);
app.mHasSurface = true;
app.mSurfaceControl = mock(SurfaceControl.class);
@@ -536,7 +536,7 @@
final float[] values = new float[9];
final Matrix matrix = new Matrix();
- final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
+ final SurfaceControl.Transaction t = spy(StubTransaction.class);
final WindowState win1 = createWindow(null, TYPE_APPLICATION, dc, "win1");
win1.mHasSurface = true;
win1.mSurfaceControl = mock(SurfaceControl.class);
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 34eb3f1..ecee709 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -1733,10 +1733,13 @@
public void registerAppUsageLimitObserver(int observerId, String[] packages,
long timeLimitMs, long timeUsedMs, PendingIntent callbackIntent,
String callingPackage) {
+ final int callingUid = Binder.getCallingUid();
+ final DevicePolicyManagerInternal dpmInternal = getDpmInternal();
if (!hasPermissions(callingPackage,
- Manifest.permission.SUSPEND_APPS, Manifest.permission.OBSERVE_APP_USAGE)) {
- throw new SecurityException("Caller doesn't have both SUSPEND_APPS and "
- + "OBSERVE_APP_USAGE permissions");
+ Manifest.permission.SUSPEND_APPS, Manifest.permission.OBSERVE_APP_USAGE)
+ && (dpmInternal != null && !dpmInternal.isActiveSupervisionApp(callingUid))) {
+ throw new SecurityException("Caller must be the active supervision app or "
+ + "it must have both SUSPEND_APPS and OBSERVE_APP_USAGE permissions");
}
if (packages == null || packages.length == 0) {
@@ -1745,7 +1748,6 @@
if (callbackIntent == null && timeUsedMs < timeLimitMs) {
throw new NullPointerException("callbackIntent can't be null");
}
- final int callingUid = Binder.getCallingUid();
final int userId = UserHandle.getUserId(callingUid);
final long token = Binder.clearCallingIdentity();
try {
@@ -1758,13 +1760,15 @@
@Override
public void unregisterAppUsageLimitObserver(int observerId, String callingPackage) {
+ final int callingUid = Binder.getCallingUid();
+ final DevicePolicyManagerInternal dpmInternal = getDpmInternal();
if (!hasPermissions(callingPackage,
- Manifest.permission.SUSPEND_APPS, Manifest.permission.OBSERVE_APP_USAGE)) {
- throw new SecurityException("Caller doesn't have both SUSPEND_APPS and "
- + "OBSERVE_APP_USAGE permissions");
+ Manifest.permission.SUSPEND_APPS, Manifest.permission.OBSERVE_APP_USAGE)
+ && (dpmInternal != null && !dpmInternal.isActiveSupervisionApp(callingUid))) {
+ throw new SecurityException("Caller must be the active supervision app or "
+ + "it must have both SUSPEND_APPS and OBSERVE_APP_USAGE permissions");
}
- final int callingUid = Binder.getCallingUid();
final int userId = UserHandle.getUserId(callingUid);
final long token = Binder.clearCallingIdentity();
try {
diff --git a/startop/scripts/app_startup/app_startup_runner.py b/startop/scripts/app_startup/app_startup_runner.py
index fa1c4e6..25ee6f7 100755
--- a/startop/scripts/app_startup/app_startup_runner.py
+++ b/startop/scripts/app_startup/app_startup_runner.py
@@ -233,13 +233,17 @@
simulate: bool,
inodes_path: str,
timeout: int,
- compiler_type: CompilerType) -> DataFrame:
+ compiler_type: CompilerType,
+ requires_trace_collection: bool) -> DataFrame:
""" Executes run based on perfetto trace. """
- passed, perfetto_trace_file = run_perfetto_collector(collector_info,
- timeout,
- simulate)
- if not passed:
- raise RuntimeError('Cannot run perfetto collector!')
+ if requires_trace_collection:
+ passed, perfetto_trace_file = run_perfetto_collector(collector_info,
+ timeout,
+ simulate)
+ if not passed:
+ raise RuntimeError('Cannot run perfetto collector!')
+ else:
+ perfetto_trace_file = tempfile.NamedTemporaryFile()
with perfetto_trace_file:
for combos in run_combos:
@@ -271,7 +275,8 @@
simulate: bool,
inodes_path: str,
timeout: int,
- compiler_type: CompilerType):
+ compiler_type: CompilerType,
+ requires_trace_collection: bool):
# nothing will work if the screen isn't unlocked first.
cmd_utils.execute_arbitrary_command([_UNLOCK_SCREEN_SCRIPT],
timeout,
@@ -284,7 +289,8 @@
simulate,
inodes_path,
timeout,
- compiler_type)
+ compiler_type,
+ requires_trace_collection)
def gather_results(commands: Iterable[Tuple[DataFrame]],
key_list: List[str], value_list: List[Tuple[str, ...]]):
@@ -369,11 +375,13 @@
CollectorPackageInfo)
print_utils.debug_print_gen("grouped run combinations: ", grouped_combos())
+ requires_trace_collection = any(i in _TRACING_READAHEADS for i in opts.readaheads)
exec = execute_run_combos(grouped_combos(),
opts.simulate,
opts.inodes,
opts.timeout,
- opts.compiler_type)
+ opts.compiler_type,
+ requires_trace_collection)
results = gather_results(exec, _COMBINATORIAL_OPTIONS, combos())
diff --git a/startop/scripts/iorap/common b/startop/scripts/iorap/common
index 031dabf..387e45d 100755
--- a/startop/scripts/iorap/common
+++ b/startop/scripts/iorap/common
@@ -248,6 +248,6 @@
local remote_path="$(_iorapd_path_to_data_file "$package" "$activity" "compiled_trace.pb")"
# See 'read_ahead.cc' LOG(INFO).
- local pattern="ReadAhead completed ($remote_path)"
+ local pattern="Description = $remote_path"
logcat_wait_for_pattern "$timeout" "$timestamp" "$pattern"
}
diff --git a/telephony/common/com/android/internal/telephony/HbpcdLookup.java b/telephony/common/com/android/internal/telephony/HbpcdLookup.java
new file mode 100644
index 0000000..d9a3e72
--- /dev/null
+++ b/telephony/common/com/android/internal/telephony/HbpcdLookup.java
@@ -0,0 +1,124 @@
+/*
+**
+** Copyright 2014, 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.internal.telephony;
+
+import android.net.Uri;
+import android.provider.BaseColumns;
+
+/**
+ * @hide
+ */
+public class HbpcdLookup {
+ public static final String AUTHORITY = "hbpcd_lookup";
+
+ public static final Uri CONTENT_URI =
+ Uri.parse("content://" + AUTHORITY);
+
+ public static final String PATH_MCC_IDD = "idd";
+ public static final String PATH_MCC_LOOKUP_TABLE = "lookup";
+ public static final String PATH_MCC_SID_CONFLICT = "conflict";
+ public static final String PATH_MCC_SID_RANGE = "range";
+ public static final String PATH_NANP_AREA_CODE = "nanp";
+ public static final String PATH_ARBITRARY_MCC_SID_MATCH = "arbitrary";
+ public static final String PATH_USERADD_COUNTRY = "useradd";
+
+ public static final String ID = "_id";
+ public static final int IDINDEX = 0;
+
+ /**
+ * @hide
+ */
+ public static class MccIdd implements BaseColumns {
+ public static final Uri CONTENT_URI =
+ Uri.parse("content://" + AUTHORITY + "/" + PATH_MCC_IDD);
+ public static final String DEFAULT_SORT_ORDER = "MCC ASC";
+
+ public static final String MCC = "MCC";
+ public static final String IDD = "IDD";
+
+ }
+
+ /**
+ * @hide
+ */
+ public static class MccLookup implements BaseColumns {
+ public static final Uri CONTENT_URI =
+ Uri.parse("content://" + AUTHORITY + "/" + PATH_MCC_LOOKUP_TABLE);
+ public static final String DEFAULT_SORT_ORDER = "MCC ASC";
+
+ public static final String MCC = "MCC";
+ public static final String COUNTRY_CODE = "Country_Code";
+ public static final String COUNTRY_NAME = "Country_Name";
+ public static final String NDD = "NDD";
+ public static final String NANPS = "NANPS";
+ public static final String GMT_OFFSET_LOW = "GMT_Offset_Low";
+ public static final String GMT_OFFSET_HIGH = "GMT_Offset_High";
+ public static final String GMT_DST_LOW = "GMT_DST_Low";
+ public static final String GMT_DST_HIGH = "GMT_DST_High";
+
+ }
+
+ /**
+ * @hide
+ */
+ public static class MccSidConflicts implements BaseColumns {
+ public static final Uri CONTENT_URI =
+ Uri.parse("content://" + AUTHORITY + "/" + PATH_MCC_SID_CONFLICT);
+ public static final String DEFAULT_SORT_ORDER = "MCC ASC";
+
+ public static final String MCC = "MCC";
+ public static final String SID_CONFLICT = "SID_Conflict";
+
+ }
+
+ /**
+ * @hide
+ */
+ public static class MccSidRange implements BaseColumns {
+ public static final Uri CONTENT_URI =
+ Uri.parse("content://" + AUTHORITY + "/" + PATH_MCC_SID_RANGE);
+ public static final String DEFAULT_SORT_ORDER = "MCC ASC";
+
+ public static final String MCC = "MCC";
+ public static final String RANGE_LOW = "SID_Range_Low";
+ public static final String RANGE_HIGH = "SID_Range_High";
+ }
+
+ /**
+ * @hide
+ */
+ public static class ArbitraryMccSidMatch implements BaseColumns {
+ public static final Uri CONTENT_URI =
+ Uri.parse("content://" + AUTHORITY + "/" + PATH_ARBITRARY_MCC_SID_MATCH);
+ public static final String DEFAULT_SORT_ORDER = "MCC ASC";
+
+ public static final String MCC = "MCC";
+ public static final String SID = "SID";
+
+ }
+
+ /**
+ * @hide
+ */
+ public static class NanpAreaCode implements BaseColumns {
+ public static final Uri CONTENT_URI =
+ Uri.parse("content://" + AUTHORITY + "/" + PATH_NANP_AREA_CODE);
+ public static final String DEFAULT_SORT_ORDER = "Area_Code ASC";
+
+ public static final String AREA_CODE = "Area_Code";
+ }
+}
diff --git a/telephony/common/com/android/internal/telephony/HbpcdUtils.java b/telephony/common/com/android/internal/telephony/HbpcdUtils.java
new file mode 100644
index 0000000..2f31942
--- /dev/null
+++ b/telephony/common/com/android/internal/telephony/HbpcdUtils.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2014 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.internal.telephony;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.Cursor;
+import android.telephony.Rlog;
+
+import com.android.internal.telephony.HbpcdLookup.ArbitraryMccSidMatch;
+import com.android.internal.telephony.HbpcdLookup.MccIdd;
+import com.android.internal.telephony.HbpcdLookup.MccLookup;
+import com.android.internal.telephony.HbpcdLookup.MccSidConflicts;
+import com.android.internal.telephony.HbpcdLookup.MccSidRange;
+
+public final class HbpcdUtils {
+ private static final String LOG_TAG = "HbpcdUtils";
+ private static final boolean DBG = false;
+ private ContentResolver resolver = null;
+
+ public HbpcdUtils(Context context) {
+ resolver = context.getContentResolver();
+ }
+
+ /**
+ * Resolves the unknown MCC with SID and Timezone information.
+ */
+ public int getMcc(int sid, int tz, int DSTflag, boolean isNitzTimeZone) {
+ int tmpMcc = 0;
+
+ // check if SID exists in arbitrary_mcc_sid_match table.
+ // these SIDs are assigned to more than 1 operators, but they are known to
+ // be used by a specific operator, other operators having the same SID are
+ // not using it currently, if that SID is in this table, we don't need to
+ // check other tables.
+ String projection2[] = {ArbitraryMccSidMatch.MCC};
+ Cursor c2 = resolver.query(ArbitraryMccSidMatch.CONTENT_URI, projection2,
+ ArbitraryMccSidMatch.SID + "=" + sid, null, null);
+
+ if (c2 != null) {
+ int c2Counter = c2.getCount();
+ if (DBG) {
+ Rlog.d(LOG_TAG, "Query unresolved arbitrary table, entries are " + c2Counter);
+ }
+ if (c2Counter == 1) {
+ if (DBG) {
+ Rlog.d(LOG_TAG, "Query Unresolved arbitrary returned the cursor " + c2);
+ }
+ c2.moveToFirst();
+ tmpMcc = c2.getInt(0);
+ if (DBG) {
+ Rlog.d(LOG_TAG, "MCC found in arbitrary_mcc_sid_match: " + tmpMcc);
+ }
+ c2.close();
+ return tmpMcc;
+ }
+ c2.close();
+ }
+
+ // Then check if SID exists in mcc_sid_conflict table.
+ // and use the timezone in mcc_lookup table to check which MCC matches.
+ String projection3[] = {MccSidConflicts.MCC};
+ Cursor c3 = resolver.query(MccSidConflicts.CONTENT_URI, projection3,
+ MccSidConflicts.SID_CONFLICT + "=" + sid + " and (((" +
+ MccLookup.GMT_OFFSET_LOW + "<=" + tz + ") and (" + tz + "<=" +
+ MccLookup.GMT_OFFSET_HIGH + ") and (" + "0=" + DSTflag + ")) or ((" +
+ MccLookup.GMT_DST_LOW + "<=" + tz + ") and (" + tz + "<=" +
+ MccLookup.GMT_DST_HIGH + ") and (" + "1=" + DSTflag + ")))",
+ null, null);
+ if (c3 != null) {
+ int c3Counter = c3.getCount();
+ if (c3Counter > 0) {
+ if (c3Counter > 1) {
+ Rlog.w(LOG_TAG, "something wrong, get more results for 1 conflict SID: " + c3);
+ }
+ if (DBG) Rlog.d(LOG_TAG, "Query conflict sid returned the cursor " + c3);
+ c3.moveToFirst();
+ tmpMcc = c3.getInt(0);
+ if (DBG) {
+ Rlog.d(LOG_TAG, "MCC found in mcc_lookup_table. Return tmpMcc = " + tmpMcc);
+ }
+ if (!isNitzTimeZone) {
+ // time zone is not accurate, it may get wrong mcc, ignore it.
+ if (DBG) {
+ Rlog.d(LOG_TAG, "time zone is not accurate, mcc may be " + tmpMcc);
+ }
+ tmpMcc = 0;
+ }
+ c3.close();
+ return tmpMcc;
+ } else {
+ c3.close();
+ }
+ }
+
+ // if there is no conflict, then check if SID is in mcc_sid_range.
+ String projection5[] = {MccSidRange.MCC};
+ Cursor c5 = resolver.query(MccSidRange.CONTENT_URI, projection5,
+ MccSidRange.RANGE_LOW + "<=" + sid + " and " +
+ MccSidRange.RANGE_HIGH + ">=" + sid,
+ null, null);
+ if (c5 != null) {
+ if (c5.getCount() > 0) {
+ if (DBG) Rlog.d(LOG_TAG, "Query Range returned the cursor " + c5);
+ c5.moveToFirst();
+ tmpMcc = c5.getInt(0);
+ if (DBG) Rlog.d(LOG_TAG, "SID found in mcc_sid_range. Return tmpMcc = " + tmpMcc);
+ c5.close();
+ return tmpMcc;
+ }
+ c5.close();
+ }
+ if (DBG) Rlog.d(LOG_TAG, "SID NOT found in mcc_sid_range.");
+
+ if (DBG) Rlog.d(LOG_TAG, "Exit getMccByOtherFactors. Return tmpMcc = " + tmpMcc);
+ // If unknown MCC still could not be resolved,
+ return tmpMcc;
+ }
+
+ /**
+ * Gets country information with given MCC.
+ */
+ public String getIddByMcc(int mcc) {
+ if (DBG) Rlog.d(LOG_TAG, "Enter getHbpcdInfoByMCC.");
+ String idd = "";
+
+ Cursor c = null;
+
+ String projection[] = {MccIdd.IDD};
+ Cursor cur = resolver.query(MccIdd.CONTENT_URI, projection,
+ MccIdd.MCC + "=" + mcc, null, null);
+ if (cur != null) {
+ if (cur.getCount() > 0) {
+ if (DBG) Rlog.d(LOG_TAG, "Query Idd returned the cursor " + cur);
+ // TODO: for those country having more than 1 IDDs, need more information
+ // to decide which IDD would be used. currently just use the first 1.
+ cur.moveToFirst();
+ idd = cur.getString(0);
+ if (DBG) Rlog.d(LOG_TAG, "IDD = " + idd);
+
+ }
+ cur.close();
+ }
+ if (c != null) c.close();
+
+ if (DBG) Rlog.d(LOG_TAG, "Exit getHbpcdInfoByMCC.");
+ return idd;
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/SmsApplication.java b/telephony/common/com/android/internal/telephony/SmsApplication.java
similarity index 100%
rename from telephony/java/com/android/internal/telephony/SmsApplication.java
rename to telephony/common/com/android/internal/telephony/SmsApplication.java
diff --git a/telephony/common/com/android/internal/telephony/SmsNumberUtils.java b/telephony/common/com/android/internal/telephony/SmsNumberUtils.java
new file mode 100644
index 0000000..0d33af6
--- /dev/null
+++ b/telephony/common/com/android/internal/telephony/SmsNumberUtils.java
@@ -0,0 +1,627 @@
+/*
+ * Copyright (C) 2014 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.internal.telephony;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.database.SQLException;
+import android.os.Binder;
+import android.os.Build;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
+import android.telephony.PhoneNumberUtils;
+import android.telephony.Rlog;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+
+import com.android.internal.telephony.HbpcdLookup.MccIdd;
+import com.android.internal.telephony.HbpcdLookup.MccLookup;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+
+/**
+ * This class implements handle the MO SMS target address before sending.
+ * This is special for VZW requirement. Follow the specifications of assisted dialing
+ * of MO SMS while traveling on VZW CDMA, international CDMA or GSM markets.
+ * {@hide}
+ */
+public class SmsNumberUtils {
+ private static final String TAG = "SmsNumberUtils";
+ private static final boolean DBG = Build.IS_DEBUGGABLE;
+
+ private static final String PLUS_SIGN = "+";
+
+ private static final int NANP_SHORT_LENGTH = 7;
+ private static final int NANP_MEDIUM_LENGTH = 10;
+ private static final int NANP_LONG_LENGTH = 11;
+
+ private static final int NANP_CC = 1;
+ private static final String NANP_NDD = "1";
+ private static final String NANP_IDD = "011";
+
+ private static final int MIN_COUNTRY_AREA_LOCAL_LENGTH = 10;
+
+ private static final int GSM_UMTS_NETWORK = 0;
+ private static final int CDMA_HOME_NETWORK = 1;
+ private static final int CDMA_ROAMING_NETWORK = 2;
+
+ private static final int NP_NONE = 0;
+ private static final int NP_NANP_BEGIN = 1;
+
+ /* <Phone Number>, <NXX>-<XXXX> N[2-9] */
+ private static final int NP_NANP_LOCAL = NP_NANP_BEGIN;
+
+ /* <Area_code>-<Phone Number>, <NXX>-<NXX>-<XXXX> N[2-9] */
+ private static final int NP_NANP_AREA_LOCAL = NP_NANP_BEGIN + 1;
+
+ /* <1>-<Area_code>-<Phone Number>, 1-<NXX>-<NXX>-<XXXX> N[2-9] */
+ private static final int NP_NANP_NDD_AREA_LOCAL = NP_NANP_BEGIN + 2;
+
+ /* <+><U.S.Country_code><Area_code><Phone Number>, +1-<NXX>-<NXX>-<XXXX> N[2-9] */
+ private static final int NP_NANP_NBPCD_CC_AREA_LOCAL = NP_NANP_BEGIN + 3;
+
+ /* <Local_IDD><Country_code><Area_code><Phone Number>, 001-1-<NXX>-<NXX>-<XXXX> N[2-9] */
+ private static final int NP_NANP_LOCALIDD_CC_AREA_LOCAL = NP_NANP_BEGIN + 4;
+
+ /* <+><Home_IDD><Country_code><Area_code><Phone Number>, +011-1-<NXX>-<NXX>-<XXXX> N[2-9] */
+ private static final int NP_NANP_NBPCD_HOMEIDD_CC_AREA_LOCAL = NP_NANP_BEGIN + 5;
+
+ private static final int NP_INTERNATIONAL_BEGIN = 100;
+ /* <+>-<Home_IDD>-<Country_code>-<Area_code>-<Phone Number>, +011-86-25-86281234 */
+ private static final int NP_NBPCD_HOMEIDD_CC_AREA_LOCAL = NP_INTERNATIONAL_BEGIN;
+
+ /* <Home_IDD>-<Country_code>-<Area_code>-<Phone Number>, 011-86-25-86281234 */
+ private static final int NP_HOMEIDD_CC_AREA_LOCAL = NP_INTERNATIONAL_BEGIN + 1;
+
+ /* <NBPCD>-<Country_code>-<Area_code>-<Phone Number>, +1-86-25-86281234 */
+ private static final int NP_NBPCD_CC_AREA_LOCAL = NP_INTERNATIONAL_BEGIN + 2;
+
+ /* <Local_IDD>-<Country_code>-<Area_code>-<Phone Number>, 00-86-25-86281234 */
+ private static final int NP_LOCALIDD_CC_AREA_LOCAL = NP_INTERNATIONAL_BEGIN + 3;
+
+ /* <Country_code>-<Area_code>-<Phone Number>, 86-25-86281234*/
+ private static final int NP_CC_AREA_LOCAL = NP_INTERNATIONAL_BEGIN + 4;
+
+ private static int[] ALL_COUNTRY_CODES = null;
+ private static int MAX_COUNTRY_CODES_LENGTH;
+ private static HashMap<String, ArrayList<String>> IDDS_MAPS =
+ new HashMap<String, ArrayList<String>>();
+
+ private static class NumberEntry {
+ public String number;
+ public String IDD;
+ public int countryCode;
+ public NumberEntry(String number) {
+ this.number = number;
+ }
+ }
+
+ /**
+ * Breaks the given number down and formats it according to the rules
+ * for different number plans and different network.
+ *
+ * @param number destination number which need to be format
+ * @param activeMcc current network's mcc
+ * @param networkType current network type
+ *
+ * @return the number after formatting.
+ */
+ private static String formatNumber(Context context, String number,
+ String activeMcc,
+ int networkType) {
+ if (number == null ) {
+ throw new IllegalArgumentException("number is null");
+ }
+
+ if (activeMcc == null || activeMcc.trim().length() == 0) {
+ throw new IllegalArgumentException("activeMcc is null or empty!");
+ }
+
+ String networkPortionNumber = PhoneNumberUtils.extractNetworkPortion(number);
+ if (networkPortionNumber == null || networkPortionNumber.length() == 0) {
+ throw new IllegalArgumentException("Number is invalid!");
+ }
+
+ NumberEntry numberEntry = new NumberEntry(networkPortionNumber);
+ ArrayList<String> allIDDs = getAllIDDs(context, activeMcc);
+
+ // First check whether the number is a NANP number.
+ int nanpState = checkNANP(numberEntry, allIDDs);
+ if (DBG) Rlog.d(TAG, "NANP type: " + getNumberPlanType(nanpState));
+
+ if ((nanpState == NP_NANP_LOCAL)
+ || (nanpState == NP_NANP_AREA_LOCAL)
+ || (nanpState == NP_NANP_NDD_AREA_LOCAL)) {
+ return networkPortionNumber;
+ } else if (nanpState == NP_NANP_NBPCD_CC_AREA_LOCAL) {
+ if (networkType == CDMA_HOME_NETWORK
+ || networkType == CDMA_ROAMING_NETWORK) {
+ // Remove "+"
+ return networkPortionNumber.substring(1);
+ } else {
+ return networkPortionNumber;
+ }
+ } else if (nanpState == NP_NANP_LOCALIDD_CC_AREA_LOCAL) {
+ if (networkType == CDMA_HOME_NETWORK) {
+ return networkPortionNumber;
+ } else if (networkType == GSM_UMTS_NETWORK) {
+ // Remove the local IDD and replace with "+"
+ int iddLength = numberEntry.IDD != null ? numberEntry.IDD.length() : 0;
+ return PLUS_SIGN + networkPortionNumber.substring(iddLength);
+ } else if (networkType == CDMA_ROAMING_NETWORK) {
+ // Remove the local IDD
+ int iddLength = numberEntry.IDD != null ? numberEntry.IDD.length() : 0;
+ return networkPortionNumber.substring(iddLength);
+ }
+ }
+
+ int internationalState = checkInternationalNumberPlan(context, numberEntry, allIDDs,
+ NANP_IDD);
+ if (DBG) Rlog.d(TAG, "International type: " + getNumberPlanType(internationalState));
+ String returnNumber = null;
+
+ switch (internationalState) {
+ case NP_NBPCD_HOMEIDD_CC_AREA_LOCAL:
+ if (networkType == GSM_UMTS_NETWORK) {
+ // Remove "+"
+ returnNumber = networkPortionNumber.substring(1);
+ }
+ break;
+
+ case NP_NBPCD_CC_AREA_LOCAL:
+ // Replace "+" with "011"
+ returnNumber = NANP_IDD + networkPortionNumber.substring(1);
+ break;
+
+ case NP_LOCALIDD_CC_AREA_LOCAL:
+ if (networkType == GSM_UMTS_NETWORK || networkType == CDMA_ROAMING_NETWORK) {
+ int iddLength = numberEntry.IDD != null ? numberEntry.IDD.length() : 0;
+ // Replace <Local IDD> to <Home IDD>("011")
+ returnNumber = NANP_IDD + networkPortionNumber.substring(iddLength);
+ }
+ break;
+
+ case NP_CC_AREA_LOCAL:
+ int countryCode = numberEntry.countryCode;
+
+ if (!inExceptionListForNpCcAreaLocal(numberEntry)
+ && networkPortionNumber.length() >= 11 && countryCode != NANP_CC) {
+ // Add "011"
+ returnNumber = NANP_IDD + networkPortionNumber;
+ }
+ break;
+
+ case NP_HOMEIDD_CC_AREA_LOCAL:
+ returnNumber = networkPortionNumber;
+ break;
+
+ default:
+ // Replace "+" with 011 in CDMA network if the number's country
+ // code is not in the HbpcdLookup database.
+ if (networkPortionNumber.startsWith(PLUS_SIGN)
+ && (networkType == CDMA_HOME_NETWORK || networkType == CDMA_ROAMING_NETWORK)) {
+ if (networkPortionNumber.startsWith(PLUS_SIGN + NANP_IDD)) {
+ // Only remove "+"
+ returnNumber = networkPortionNumber.substring(1);
+ } else {
+ // Replace "+" with "011"
+ returnNumber = NANP_IDD + networkPortionNumber.substring(1);
+ }
+ }
+ }
+
+ if (returnNumber == null) {
+ returnNumber = networkPortionNumber;
+ }
+ return returnNumber;
+ }
+
+ /**
+ * Query International direct dialing from HbpcdLookup.db
+ * for specified country code
+ *
+ * @param mcc current network's country code
+ *
+ * @return the IDD array list.
+ */
+ private static ArrayList<String> getAllIDDs(Context context, String mcc) {
+ ArrayList<String> allIDDs = IDDS_MAPS.get(mcc);
+ if (allIDDs != null) {
+ return allIDDs;
+ } else {
+ allIDDs = new ArrayList<String>();
+ }
+
+ String projection[] = {MccIdd.IDD, MccIdd.MCC};
+ String where = null;
+
+ // if mcc is null : return all rows
+ // if mcc is empty-string : return those rows whose mcc is emptry-string
+ String[] selectionArgs = null;
+ if (mcc != null) {
+ where = MccIdd.MCC + "=?";
+ selectionArgs = new String[] {mcc};
+ }
+
+ Cursor cursor = null;
+ try {
+ cursor = context.getContentResolver().query(MccIdd.CONTENT_URI, projection,
+ where, selectionArgs, null);
+ if (cursor.getCount() > 0) {
+ while (cursor.moveToNext()) {
+ String idd = cursor.getString(0);
+ if (!allIDDs.contains(idd)) {
+ allIDDs.add(idd);
+ }
+ }
+ }
+ } catch (SQLException e) {
+ Rlog.e(TAG, "Can't access HbpcdLookup database", e);
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+
+ IDDS_MAPS.put(mcc, allIDDs);
+
+ if (DBG) Rlog.d(TAG, "MCC = " + mcc + ", all IDDs = " + allIDDs);
+ return allIDDs;
+ }
+
+
+ /**
+ * Verify if the the destination number is a NANP number
+ *
+ * @param numberEntry including number and IDD array
+ * @param allIDDs the IDD array list of the current network's country code
+ *
+ * @return the number plan type related NANP
+ */
+ private static int checkNANP(NumberEntry numberEntry, ArrayList<String> allIDDs) {
+ boolean isNANP = false;
+ String number = numberEntry.number;
+
+ if (number.length() == NANP_SHORT_LENGTH) {
+ // 7 digits - Seven digit phone numbers
+ char firstChar = number.charAt(0);
+ if (firstChar >= '2' && firstChar <= '9') {
+ isNANP = true;
+ for (int i=1; i< NANP_SHORT_LENGTH; i++ ) {
+ char c= number.charAt(i);
+ if (!PhoneNumberUtils.isISODigit(c)) {
+ isNANP = false;
+ break;
+ }
+ }
+ }
+ if (isNANP) {
+ return NP_NANP_LOCAL;
+ }
+ } else if (number.length() == NANP_MEDIUM_LENGTH) {
+ // 10 digits - Three digit area code followed by seven digit phone numbers/
+ if (isNANP(number)) {
+ return NP_NANP_AREA_LOCAL;
+ }
+ } else if (number.length() == NANP_LONG_LENGTH) {
+ // 11 digits - One digit U.S. NDD(National Direct Dial) prefix '1',
+ // followed by three digit area code and seven digit phone numbers
+ if (isNANP(number)) {
+ return NP_NANP_NDD_AREA_LOCAL;
+ }
+ } else if (number.startsWith(PLUS_SIGN)) {
+ number = number.substring(1);
+ if (number.length() == NANP_LONG_LENGTH) {
+ // '+' and 11 digits -'+', followed by NANP CC prefix '1' followed by
+ // three digit area code and seven digit phone numbers
+ if (isNANP(number)) {
+ return NP_NANP_NBPCD_CC_AREA_LOCAL;
+ }
+ } else if (number.startsWith(NANP_IDD) && number.length() == NANP_LONG_LENGTH + 3) {
+ // '+' and 14 digits -'+', followed by NANP IDD "011" followed by NANP CC
+ // prefix '1' followed by three digit area code and seven digit phone numbers
+ number = number.substring(3);
+ if (isNANP(number)) {
+ return NP_NANP_NBPCD_HOMEIDD_CC_AREA_LOCAL;
+ }
+ }
+ } else {
+ // Check whether it's NP_NANP_LOCALIDD_CC_AREA_LOCAL
+ for (String idd : allIDDs) {
+ if (number.startsWith(idd)) {
+ String number2 = number.substring(idd.length());
+ if(number2 !=null && number2.startsWith(String.valueOf(NANP_CC))){
+ if (isNANP(number2)) {
+ numberEntry.IDD = idd;
+ return NP_NANP_LOCALIDD_CC_AREA_LOCAL;
+ }
+ }
+ }
+ }
+ }
+
+ return NP_NONE;
+ }
+
+ private static boolean isNANP(String number) {
+ if (number.length() == NANP_MEDIUM_LENGTH
+ || (number.length() == NANP_LONG_LENGTH && number.startsWith(NANP_NDD))) {
+ if (number.length() == NANP_LONG_LENGTH) {
+ number = number.substring(1);
+ }
+ return (PhoneNumberUtils.isNanp(number));
+ }
+ return false;
+ }
+
+ /**
+ * Verify if the the destination number is an internal number
+ *
+ * @param numberEntry including number and IDD array
+ * @param allIDDs the IDD array list of the current network's country code
+ *
+ * @return the number plan type related international number
+ */
+ private static int checkInternationalNumberPlan(Context context, NumberEntry numberEntry,
+ ArrayList<String> allIDDs,String homeIDD) {
+ String number = numberEntry.number;
+ int countryCode = -1;
+
+ if (number.startsWith(PLUS_SIGN)) {
+ // +xxxxxxxxxx
+ String numberNoNBPCD = number.substring(1);
+ if (numberNoNBPCD.startsWith(homeIDD)) {
+ // +011xxxxxxxx
+ String numberCountryAreaLocal = numberNoNBPCD.substring(homeIDD.length());
+ if ((countryCode = getCountryCode(context, numberCountryAreaLocal)) > 0) {
+ numberEntry.countryCode = countryCode;
+ return NP_NBPCD_HOMEIDD_CC_AREA_LOCAL;
+ }
+ } else if ((countryCode = getCountryCode(context, numberNoNBPCD)) > 0) {
+ numberEntry.countryCode = countryCode;
+ return NP_NBPCD_CC_AREA_LOCAL;
+ }
+
+ } else if (number.startsWith(homeIDD)) {
+ // 011xxxxxxxxx
+ String numberCountryAreaLocal = number.substring(homeIDD.length());
+ if ((countryCode = getCountryCode(context, numberCountryAreaLocal)) > 0) {
+ numberEntry.countryCode = countryCode;
+ return NP_HOMEIDD_CC_AREA_LOCAL;
+ }
+ } else {
+ for (String exitCode : allIDDs) {
+ if (number.startsWith(exitCode)) {
+ String numberNoIDD = number.substring(exitCode.length());
+ if ((countryCode = getCountryCode(context, numberNoIDD)) > 0) {
+ numberEntry.countryCode = countryCode;
+ numberEntry.IDD = exitCode;
+ return NP_LOCALIDD_CC_AREA_LOCAL;
+ }
+ }
+ }
+
+ if (!number.startsWith("0") && (countryCode = getCountryCode(context, number)) > 0) {
+ numberEntry.countryCode = countryCode;
+ return NP_CC_AREA_LOCAL;
+ }
+ }
+ return NP_NONE;
+ }
+
+ /**
+ * Returns the country code from the given number.
+ */
+ private static int getCountryCode(Context context, String number) {
+ int countryCode = -1;
+ if (number.length() >= MIN_COUNTRY_AREA_LOCAL_LENGTH) {
+ // Check Country code
+ int[] allCCs = getAllCountryCodes(context);
+ if (allCCs == null) {
+ return countryCode;
+ }
+
+ int[] ccArray = new int[MAX_COUNTRY_CODES_LENGTH];
+ for (int i = 0; i < MAX_COUNTRY_CODES_LENGTH; i ++) {
+ ccArray[i] = Integer.parseInt(number.substring(0, i+1));
+ }
+
+ for (int i = 0; i < allCCs.length; i ++) {
+ int tempCC = allCCs[i];
+ for (int j = 0; j < MAX_COUNTRY_CODES_LENGTH; j ++) {
+ if (tempCC == ccArray[j]) {
+ if (DBG) Rlog.d(TAG, "Country code = " + tempCC);
+ return tempCC;
+ }
+ }
+ }
+ }
+
+ return countryCode;
+ }
+
+ /**
+ * Gets all country Codes information with given MCC.
+ */
+ private static int[] getAllCountryCodes(Context context) {
+ if (ALL_COUNTRY_CODES != null) {
+ return ALL_COUNTRY_CODES;
+ }
+
+ Cursor cursor = null;
+ try {
+ String projection[] = {MccLookup.COUNTRY_CODE};
+ cursor = context.getContentResolver().query(MccLookup.CONTENT_URI,
+ projection, null, null, null);
+
+ if (cursor.getCount() > 0) {
+ ALL_COUNTRY_CODES = new int[cursor.getCount()];
+ int i = 0;
+ while (cursor.moveToNext()) {
+ int countryCode = cursor.getInt(0);
+ ALL_COUNTRY_CODES[i++] = countryCode;
+ int length = String.valueOf(countryCode).trim().length();
+ if (length > MAX_COUNTRY_CODES_LENGTH) {
+ MAX_COUNTRY_CODES_LENGTH = length;
+ }
+ }
+ }
+ } catch (SQLException e) {
+ Rlog.e(TAG, "Can't access HbpcdLookup database", e);
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ return ALL_COUNTRY_CODES;
+ }
+
+ private static boolean inExceptionListForNpCcAreaLocal(NumberEntry numberEntry) {
+ int countryCode = numberEntry.countryCode;
+ boolean result = (numberEntry.number.length() == 12
+ && (countryCode == 7 || countryCode == 20
+ || countryCode == 65 || countryCode == 90));
+ return result;
+ }
+
+ private static String getNumberPlanType(int state) {
+ String numberPlanType = "Number Plan type (" + state + "): ";
+
+ if (state == NP_NANP_LOCAL) {
+ numberPlanType = "NP_NANP_LOCAL";
+ } else if (state == NP_NANP_AREA_LOCAL) {
+ numberPlanType = "NP_NANP_AREA_LOCAL";
+ } else if (state == NP_NANP_NDD_AREA_LOCAL) {
+ numberPlanType = "NP_NANP_NDD_AREA_LOCAL";
+ } else if (state == NP_NANP_NBPCD_CC_AREA_LOCAL) {
+ numberPlanType = "NP_NANP_NBPCD_CC_AREA_LOCAL";
+ } else if (state == NP_NANP_LOCALIDD_CC_AREA_LOCAL) {
+ numberPlanType = "NP_NANP_LOCALIDD_CC_AREA_LOCAL";
+ } else if (state == NP_NANP_NBPCD_HOMEIDD_CC_AREA_LOCAL) {
+ numberPlanType = "NP_NANP_NBPCD_HOMEIDD_CC_AREA_LOCAL";
+ } else if (state == NP_NBPCD_HOMEIDD_CC_AREA_LOCAL) {
+ numberPlanType = "NP_NBPCD_HOMEIDD_CC_AREA_LOCAL";
+ } else if (state == NP_HOMEIDD_CC_AREA_LOCAL) {
+ numberPlanType = "NP_HOMEIDD_CC_AREA_LOCAL";
+ } else if (state == NP_NBPCD_CC_AREA_LOCAL) {
+ numberPlanType = "NP_NBPCD_CC_AREA_LOCAL";
+ } else if (state == NP_LOCALIDD_CC_AREA_LOCAL) {
+ numberPlanType = "NP_LOCALIDD_CC_AREA_LOCAL";
+ } else if (state == NP_CC_AREA_LOCAL) {
+ numberPlanType = "NP_CC_AREA_LOCAL";
+ } else {
+ numberPlanType = "Unknown type";
+ }
+ return numberPlanType;
+ }
+
+ /**
+ * Filter the destination number if using VZW sim card.
+ */
+ public static String filterDestAddr(Context context, int subId, String destAddr) {
+ if (DBG) Rlog.d(TAG, "enter filterDestAddr. destAddr=\"" + Rlog.pii(TAG, destAddr) + "\"" );
+
+ if (destAddr == null || !PhoneNumberUtils.isGlobalPhoneNumber(destAddr)) {
+ Rlog.w(TAG, "destAddr" + Rlog.pii(TAG, destAddr) +
+ " is not a global phone number! Nothing changed.");
+ return destAddr;
+ }
+
+ final TelephonyManager telephonyManager = ((TelephonyManager) context
+ .getSystemService(Context.TELEPHONY_SERVICE)).createForSubscriptionId(subId);
+ final String networkOperator = telephonyManager.getNetworkOperator();
+ String result = null;
+
+ if (needToConvert(context, subId)) {
+ final int networkType = getNetworkType(telephonyManager);
+ if (networkType != -1 && !TextUtils.isEmpty(networkOperator)) {
+ String networkMcc = networkOperator.substring(0, 3);
+ if (networkMcc != null && networkMcc.trim().length() > 0) {
+ result = formatNumber(context, destAddr, networkMcc, networkType);
+ }
+ }
+ }
+
+ if (DBG) {
+ Rlog.d(TAG, "destAddr is " + ((result != null)?"formatted.":"not formatted."));
+ Rlog.d(TAG, "leave filterDestAddr, new destAddr=\"" + (result != null ? Rlog.pii(TAG,
+ result) : Rlog.pii(TAG, destAddr)) + "\"");
+ }
+ return result != null ? result : destAddr;
+ }
+
+ /**
+ * Returns the current network type
+ */
+ private static int getNetworkType(TelephonyManager telephonyManager) {
+ int networkType = -1;
+ int phoneType = telephonyManager.getPhoneType();
+
+ if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
+ networkType = GSM_UMTS_NETWORK;
+ } else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
+ if (isInternationalRoaming(telephonyManager)) {
+ networkType = CDMA_ROAMING_NETWORK;
+ } else {
+ networkType = CDMA_HOME_NETWORK;
+ }
+ } else {
+ if (DBG) Rlog.w(TAG, "warning! unknown mPhoneType value=" + phoneType);
+ }
+
+ return networkType;
+ }
+
+ private static boolean isInternationalRoaming(TelephonyManager telephonyManager) {
+ String operatorIsoCountry = telephonyManager.getNetworkCountryIso();
+ String simIsoCountry = telephonyManager.getSimCountryIso();
+ boolean internationalRoaming = !TextUtils.isEmpty(operatorIsoCountry)
+ && !TextUtils.isEmpty(simIsoCountry)
+ && !simIsoCountry.equals(operatorIsoCountry);
+ if (internationalRoaming) {
+ if ("us".equals(simIsoCountry)) {
+ internationalRoaming = !"vi".equals(operatorIsoCountry);
+ } else if ("vi".equals(simIsoCountry)) {
+ internationalRoaming = !"us".equals(operatorIsoCountry);
+ }
+ }
+ return internationalRoaming;
+ }
+
+ private static boolean needToConvert(Context context, int subId) {
+ // Calling package may not have READ_PHONE_STATE which is required for getConfig().
+ // Clear the calling identity so that it is called as self.
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ CarrierConfigManager configManager = (CarrierConfigManager)
+ context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+ if (configManager != null) {
+ PersistableBundle bundle = configManager.getConfigForSubId(subId);
+ if (bundle != null) {
+ return bundle.getBoolean(CarrierConfigManager
+ .KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ // by default this value is false
+ return false;
+ }
+}
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index 67b252e..bc29b59 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -3962,13 +3962,21 @@
public static final Uri CONTENT_URI = Uri.parse("content://cellbroadcasts");
/**
- * The id of the subscription which received this cell broadcast message.
+ * The subscription which received this cell broadcast message.
+ * @deprecated use {@link #SLOT_INDEX} instead.
* <P>Type: INTEGER</P>
* @hide
*/
public static final String SUB_ID = "sub_id";
/**
+ * The slot which received this cell broadcast message.
+ * <P>Type: INTEGER</P>
+ * @hide
+ */
+ public static final String SLOT_INDEX = "slot_index";
+
+ /**
* Message geographical scope. Valid values are:
* <ul>
* <li>{@link android.telephony.SmsCbMessage#GEOGRAPHICAL_SCOPE_CELL_WIDE}. meaning the
@@ -4202,7 +4210,7 @@
public static final String MAXIMUM_WAIT_TIME = "maximum_wait_time";
/**
- * Query columns for instantiating {@link android.telephony.CellBroadcastMessage} objects.
+ * Query columns for instantiating com.android.cellbroadcastreceiver.CellBroadcastMessage.
* @hide
*/
@NonNull
@@ -4235,6 +4243,7 @@
*/
public static final String[] QUERY_COLUMNS_FWK = {
_ID,
+ SLOT_INDEX,
GEOGRAPHICAL_SCOPE,
PLMN,
LAC,
diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java
index 432978d..b7dab16 100644
--- a/telephony/java/android/telephony/CellIdentity.java
+++ b/telephony/java/android/telephony/CellIdentity.java
@@ -35,6 +35,15 @@
/** @hide */
public static final int INVALID_CHANNEL_NUMBER = -1;
+ /**
+ * parameters for validation
+ * @hide
+ */
+ public static final int MCC_LENGTH = 3;
+
+ private static final int MNC_MIN_LENGTH = 2;
+ private static final int MNC_MAX_LENGTH = 3;
+
// Log tag
/** @hide */
protected final String mTag;
@@ -207,6 +216,17 @@
dest.writeString(mAlphaShort);
}
+ /** Used by phone interface manager to verify if a given string is valid MccMnc
+ * @hide
+ */
+ public static boolean isValidPlmn(@NonNull String plmn) {
+ if (plmn.length() < MCC_LENGTH + MNC_MIN_LENGTH
+ || plmn.length() > MCC_LENGTH + MNC_MAX_LENGTH) {
+ return false;
+ }
+ return (isMcc(plmn.substring(0, MCC_LENGTH)) && isMnc(plmn.substring(MCC_LENGTH)));
+ }
+
/**
* Construct from Parcel
* @hide
@@ -267,10 +287,10 @@
/** @hide */
private static boolean isMcc(@NonNull String mcc) {
// ensure no out of bounds indexing
- if (mcc.length() != 3) return false;
+ if (mcc.length() != MCC_LENGTH) return false;
// Character.isDigit allows all unicode digits, not just [0-9]
- for (int i = 0; i < 3; i++) {
+ for (int i = 0; i < MCC_LENGTH; i++) {
if (mcc.charAt(i) < '0' || mcc.charAt(i) > '9') return false;
}
@@ -280,7 +300,7 @@
/** @hide */
private static boolean isMnc(@NonNull String mnc) {
// ensure no out of bounds indexing
- if (mnc.length() < 2 || mnc.length() > 3) return false;
+ if (mnc.length() < MNC_MIN_LENGTH || mnc.length() > MNC_MAX_LENGTH) return false;
// Character.isDigit allows all unicode digits, not just [0-9]
for (int i = 0; i < mnc.length(); i++) {
@@ -289,4 +309,5 @@
return true;
}
+
}
diff --git a/telephony/java/android/telephony/ModemActivityInfo.java b/telephony/java/android/telephony/ModemActivityInfo.java
index 43bc85c..d105fe3 100644
--- a/telephony/java/android/telephony/ModemActivityInfo.java
+++ b/telephony/java/android/telephony/ModemActivityInfo.java
@@ -20,11 +20,10 @@
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
-
import android.os.SystemClock;
import android.util.Range;
+
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
/**
@@ -64,17 +63,20 @@
mTimestamp = timestamp;
mSleepTimeMs = sleepTimeMs;
mIdleTimeMs = idleTimeMs;
- if (txTimeMs != null) {
- populateTransmitPowerRange(txTimeMs);
- }
+ populateTransmitPowerRange(txTimeMs);
mRxTimeMs = rxTimeMs;
}
/** helper API to populate tx power range for each bucket **/
private void populateTransmitPowerRange(@NonNull int[] transmitPowerMs) {
- for (int i = 0; i < Math.min(transmitPowerMs.length, TX_POWER_LEVELS); i++) {
+ int i = 0;
+ for ( ; i < Math.min(transmitPowerMs.length, TX_POWER_LEVELS); i++) {
mTransmitPowerInfo.add(i, new TransmitPower(TX_POWER_RANGES[i], transmitPowerMs[i]));
}
+ // Make sure that mTransmitPowerInfo is fully initialized.
+ for ( ; i < TX_POWER_LEVELS; i++) {
+ mTransmitPowerInfo.add(i, new TransmitPower(TX_POWER_RANGES[i], 0));
+ }
}
@Override
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 8587be7..1d00b4f 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -963,6 +963,9 @@
case RIL_RADIO_TECHNOLOGY_LTE_CA:
rtString = "LTE_CA";
break;
+ case RIL_RADIO_TECHNOLOGY_NR:
+ rtString = "LTE_NR";
+ break;
default:
rtString = "Unexpected";
Rlog.w(LOG_TAG, "Unexpected radioTechnology=" + rt);
@@ -1529,6 +1532,7 @@
return AccessNetworkType.CDMA2000;
case RIL_RADIO_TECHNOLOGY_LTE:
case RIL_RADIO_TECHNOLOGY_LTE_CA:
+ case RIL_RADIO_TECHNOLOGY_NR:
return AccessNetworkType.EUTRAN;
case RIL_RADIO_TECHNOLOGY_IWLAN:
return AccessNetworkType.IWLAN;
@@ -1577,6 +1581,8 @@
return ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN;
case TelephonyManager.NETWORK_TYPE_LTE_CA:
return ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA;
+ case TelephonyManager.NETWORK_TYPE_NR:
+ return ServiceState.RIL_RADIO_TECHNOLOGY_NR;
default:
return ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN;
}
@@ -1667,7 +1673,8 @@
|| radioTechnology == RIL_RADIO_TECHNOLOGY_GSM
|| radioTechnology == RIL_RADIO_TECHNOLOGY_TD_SCDMA
|| radioTechnology == RIL_RADIO_TECHNOLOGY_IWLAN
- || radioTechnology == RIL_RADIO_TECHNOLOGY_LTE_CA;
+ || radioTechnology == RIL_RADIO_TECHNOLOGY_LTE_CA
+ || radioTechnology == RIL_RADIO_TECHNOLOGY_NR;
}
diff --git a/telephony/java/android/telephony/SmsCbMessage.java b/telephony/java/android/telephony/SmsCbMessage.java
index c078764..dc991b9 100644
--- a/telephony/java/android/telephony/SmsCbMessage.java
+++ b/telephony/java/android/telephony/SmsCbMessage.java
@@ -207,17 +207,19 @@
/** CMAS warning area coordinates. */
private final List<Geometry> mGeometries;
+ private int mSlotIndex = 0;
+
/**
* Create a new SmsCbMessage with the specified data.
*/
public SmsCbMessage(int messageFormat, int geographicalScope, int serialNumber,
@NonNull SmsCbLocation location, int serviceCategory, @Nullable String language,
@Nullable String body, int priority, @Nullable SmsCbEtwsInfo etwsWarningInfo,
- @Nullable SmsCbCmasInfo cmasWarningInfo) {
+ @Nullable SmsCbCmasInfo cmasWarningInfo, int slotIndex) {
this(messageFormat, geographicalScope, serialNumber, location, serviceCategory, language,
body, priority, etwsWarningInfo, cmasWarningInfo, 0 /* maximumWaitingTime */,
- null /* geometries */, System.currentTimeMillis());
+ null /* geometries */, System.currentTimeMillis(), slotIndex);
}
/**
@@ -227,7 +229,8 @@
public SmsCbMessage(int messageFormat, int geographicalScope, int serialNumber,
SmsCbLocation location, int serviceCategory, String language, String body,
int priority, SmsCbEtwsInfo etwsWarningInfo, SmsCbCmasInfo cmasWarningInfo,
- int maximumWaitTimeSec, List<Geometry> geometries, long receivedTimeMillis) {
+ int maximumWaitTimeSec, List<Geometry> geometries, long receivedTimeMillis,
+ int slotIndex) {
mMessageFormat = messageFormat;
mGeographicalScope = geographicalScope;
mSerialNumber = serialNumber;
@@ -241,6 +244,7 @@
mReceivedTimeMillis = receivedTimeMillis;
mGeometries = geometries;
mMaximumWaitTimeSec = maximumWaitTimeSec;
+ mSlotIndex = slotIndex;
}
/**
@@ -278,6 +282,7 @@
String geoStr = in.readString();
mGeometries = geoStr != null ? CbGeoUtils.parseGeometriesFromString(geoStr) : null;
mMaximumWaitTimeSec = in.readInt();
+ mSlotIndex = in.readInt();
}
/**
@@ -312,6 +317,7 @@
dest.writeString(
mGeometries != null ? CbGeoUtils.encodeGeometriesToString(mGeometries) : null);
dest.writeInt(mMaximumWaitTimeSec);
+ dest.writeInt(mSlotIndex);
}
@NonNull
@@ -423,6 +429,14 @@
}
/**
+ * Get the slotIndex associated with this message.
+ * @return the slotIndex associated with this message
+ */
+ public int getSlotIndex() {
+ return mSlotIndex;
+ }
+
+ /**
* Get the message format ({@link #MESSAGE_FORMAT_3GPP} or {@link #MESSAGE_FORMAT_3GPP2}).
* @return an integer representing 3GPP or 3GPP2 message format
*/
@@ -502,6 +516,7 @@
+ (mEtwsWarningInfo != null ? (", " + mEtwsWarningInfo.toString()) : "")
+ (mCmasWarningInfo != null ? (", " + mCmasWarningInfo.toString()) : "")
+ ", maximumWaitingTime = " + mMaximumWaitTimeSec
+ + ", slotIndex = " + mSlotIndex
+ ", geo=" + (mGeometries != null
? CbGeoUtils.encodeGeometriesToString(mGeometries) : "null")
+ '}';
@@ -522,6 +537,7 @@
@NonNull
public ContentValues getContentValues() {
ContentValues cv = new ContentValues(16);
+ cv.put(CellBroadcasts.SLOT_INDEX, mSlotIndex);
cv.put(CellBroadcasts.GEOGRAPHICAL_SCOPE, mGeographicalScope);
if (mLocation.getPlmn() != null) {
cv.put(CellBroadcasts.PLMN, mLocation.getPlmn());
@@ -563,6 +579,7 @@
}
cv.put(CellBroadcasts.MAXIMUM_WAIT_TIME, mMaximumWaitTimeSec);
+ cv.put(CellBroadcasts.SLOT_INDEX, mSlotIndex);
return cv;
}
@@ -584,6 +601,7 @@
String body = cursor.getString(cursor.getColumnIndexOrThrow(CellBroadcasts.MESSAGE_BODY));
int format = cursor.getInt(cursor.getColumnIndexOrThrow(CellBroadcasts.MESSAGE_FORMAT));
int priority = cursor.getInt(cursor.getColumnIndexOrThrow(CellBroadcasts.MESSAGE_PRIORITY));
+ int slotIndex = cursor.getInt(cursor.getColumnIndexOrThrow(CellBroadcasts.SLOT_INDEX));
String plmn;
int plmnColumn = cursor.getColumnIndex(CellBroadcasts.PLMN);
@@ -681,7 +699,7 @@
return new SmsCbMessage(format, geoScope, serialNum, location, category,
language, body, priority, etwsInfo, cmasInfo, maximumWaitTimeSec, geometries,
- receivedTimeMillis);
+ receivedTimeMillis, slotIndex);
}
/**
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index a893288..1b87657 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -2110,19 +2110,6 @@
return phoneId >= 0 && phoneId < TelephonyManager.getDefault().getMaxPhoneCount();
}
- /**
- * When getPhoneCount and getMaxPhoneCount return different value, isValidPhoneId being true
- * doesn't mean the phoneId has a corresponding active slot / logical modem. If a DSDS capable
- * device is in single SIM mode, phoneId=1 is valid but not active.
- *
- * TODO: b/139642279 combine with SubscriptionManager#isValidPhoneId when phone objects
- * are dynamically allocated instead of always based on getMaxPhoneCount.
- * @hide
- */
- public static boolean isActivePhoneId(int slotIndex) {
- return slotIndex < TelephonyManager.getDefault().getPhoneCount();
- }
-
/** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId) {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index f3215d4..2442023 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -70,7 +70,6 @@
import android.telephony.Annotation.RadioPowerState;
import android.telephony.Annotation.SimActivationState;
import android.telephony.VisualVoicemailService.VisualVoicemailTask;
-import android.telephony.data.ApnSetting;
import android.telephony.emergency.EmergencyNumber;
import android.telephony.emergency.EmergencyNumber.EmergencyServiceCategories;
import android.telephony.ims.ImsMmTelManager;
@@ -1172,6 +1171,35 @@
"android.telephony.extra.VOICEMAIL_SCRAMBLED_PIN_STRING";
/**
+ * Broadcast intent that indicates multi-SIM configuration is changed. For example, it changed
+ * from single SIM capable to dual-SIM capable (DSDS or DSDA) or triple-SIM mode.
+ *
+ * It doesn't indicate how many subscriptions are actually active, or which states SIMs are,
+ * or that all steps during multi-SIM change are done. To know those information you still need
+ * to listen to SIM_STATE changes or active subscription changes.
+ *
+ * See extra of {@link #EXTRA_NUM_OF_ACTIVE_SIM_SUPPORTED} for updated value.
+ */
+ public static final String ACTION_MULTI_SIM_CONFIG_CHANGED =
+ "android.telephony.action.MULTI_SIM_CONFIG_CHANGED";
+
+
+ /**
+ * The number of active SIM supported by current multi-SIM config. It's not related to how many
+ * SIM/subscriptions are currently active.
+ *
+ * For single SIM mode, it's 1.
+ * For DSDS or DSDA mode, it's 2.
+ * For triple-SIM mode, it's 3.
+ *
+ * Extra of {@link #ACTION_MULTI_SIM_CONFIG_CHANGED}.
+ *
+ * type: integer
+ */
+ public static final String EXTRA_NUM_OF_ACTIVE_SIM_SUPPORTED =
+ "android.telephony.extra.NUM_OF_ACTIVE_SIM_SUPPORTED";
+
+ /**
* @hide
*/
public static final String USSD_RESPONSE = "USSD_RESPONSE";
@@ -1867,11 +1895,23 @@
/**
* Returns the Network Access Identifier (NAI). Return null if NAI is not available.
*
- * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
- * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
+ * profile owner and have the READ_PHONE_STATE permission, or that the calling app has carrier
+ * privileges (see {@link #hasCarrierPrivileges}). The profile owner is an app that owns a
+ * managed profile on the device; for more details see <a
+ * href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner
+ * access is deprecated and will be removed in a future release.
+ *
+ * <ul>
+ * <li>If the calling app's target SDK is API level 28 or lower and the app has the
+ * READ_PHONE_STATE permission then null is returned.</li>
+ * <li>If the calling app's target SDK is API level 28 or lower and the app does not have
+ * the READ_PHONE_STATE permission, or if the calling app is targeting API level 29 or
+ * higher, then a SecurityException is thrown.</li>
+ * </ul>
*/
- @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public String getNai() {
return getNaiBySubscriberId(getSubId());
}
@@ -1879,6 +1919,21 @@
/**
* Returns the NAI. Return null if NAI is not available.
*
+ * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
+ * profile owner and have the READ_PHONE_STATE permission, or that the calling app has carrier
+ * privileges (see {@link #hasCarrierPrivileges}). The profile owner is an app that owns a
+ * managed profile on the device; for more details see <a
+ * href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner
+ * access is deprecated and will be removed in a future release.
+ *
+ * <ul>
+ * <li>If the calling app's target SDK is API level 28 or lower and the app has the
+ * READ_PHONE_STATE permission then null is returned.</li>
+ * <li>If the calling app's target SDK is API level 28 or lower and the app does not have
+ * the READ_PHONE_STATE permission, or if the calling app is targeting API level 29 or
+ * higher, then a SecurityException is thrown.</li>
+ * </ul>
+ *
* @param slotIndex of which Nai is returned
*/
/** {@hide}*/
@@ -2717,6 +2772,8 @@
/** Class of broadly defined "4G" networks. {@hide} */
@UnsupportedAppUsage
public static final int NETWORK_CLASS_4_G = 3;
+ /** Class of broadly defined "5G" networks. {@hide} */
+ public static final int NETWORK_CLASS_5_G = 4;
/**
* Return general class of network type, such as "3G" or "4G". In cases
@@ -2749,6 +2806,8 @@
case NETWORK_TYPE_IWLAN:
case NETWORK_TYPE_LTE_CA:
return NETWORK_CLASS_4_G;
+ case NETWORK_TYPE_NR:
+ return NETWORK_CLASS_5_G;
default:
return NETWORK_CLASS_UNKNOWN;
}
@@ -6793,6 +6852,40 @@
}
/**
+ * Replace the contents of the forbidden PLMN SIM file with the provided values.
+ * Passing an empty list will clear the contents of the EFfplmn file.
+ * If the provided list is shorter than the size of EFfplmn, then the list will be padded
+ * up to the file size with 'FFFFFF'. (required by 3GPP TS 31.102 spec 4.2.16)
+ * If the list is longer than the size of EFfplmn, then the file will be written from the
+ * beginning of the list up to the file size.
+ *
+ * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ *
+ * @param fplmns a list of PLMNs to be forbidden.
+ *
+ * @return number of PLMNs that were successfully written to the SIM FPLMN list.
+ * This may be less than the number of PLMNs passed in where the SIM file does not have enough
+ * room for all of the values passed in. Return -1 in the event of an unexpected failure
+ */
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public int setForbiddenPlmns(@NonNull List<String> fplmns) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony == null) return 0;
+ return telephony.setForbiddenPlmns(
+ getSubId(), APPTYPE_USIM, fplmns, getOpPackageName());
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "setForbiddenPlmns RemoteException: " + ex.getMessage());
+ } catch (NullPointerException ex) {
+ // This could happen before phone starts
+ Rlog.e(TAG, "setForbiddenPlmns NullPointerException: " + ex.getMessage());
+ }
+ return 0;
+ }
+
+ /**
* Get P-CSCF address from PCO after data connection is established or modified.
* @param apnType the apnType, "ims" for IMS APN, "emergency" for EMERGENCY APN
* @return array of P-CSCF address
@@ -11375,10 +11468,13 @@
* 3) APN type is whitelisted. E.g. MMS is whitelisted if
* {@link SubscriptionManager#setAlwaysAllowMmsData} is turned on.
*
+ * @param apnType Value indicating the apn type. Apn types are defined in {@link ApnSetting}.
* @return whether data is enabled for a apn type.
*
* @hide
*/
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public boolean isDataEnabledForApn(@ApnType int apnType) {
String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
try {
diff --git a/telephony/java/android/telephony/TelephonyScanManager.java b/telephony/java/android/telephony/TelephonyScanManager.java
index 28747da..9ff8515 100644
--- a/telephony/java/android/telephony/TelephonyScanManager.java
+++ b/telephony/java/android/telephony/TelephonyScanManager.java
@@ -104,7 +104,7 @@
private final Looper mLooper;
private final Messenger mMessenger;
- private SparseArray<NetworkScanInfo> mScanInfo = new SparseArray<NetworkScanInfo>();
+ private final SparseArray<NetworkScanInfo> mScanInfo = new SparseArray<NetworkScanInfo>();
public TelephonyScanManager() {
HandlerThread thread = new HandlerThread(TAG);
@@ -204,14 +204,16 @@
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
- int scanId = telephony.requestNetworkScan(
- subId, request, mMessenger, new Binder(), callingPackage);
- if (scanId == INVALID_SCAN_ID) {
- Rlog.e(TAG, "Failed to initiate network scan");
- return null;
+ synchronized (mScanInfo) {
+ int scanId = telephony.requestNetworkScan(
+ subId, request, mMessenger, new Binder(), callingPackage);
+ if (scanId == INVALID_SCAN_ID) {
+ Rlog.e(TAG, "Failed to initiate network scan");
+ return null;
+ }
+ saveScanInfo(scanId, request, executor, callback);
+ return new NetworkScan(scanId, subId);
}
- saveScanInfo(scanId, request, executor, callback);
- return new NetworkScan(scanId, subId);
}
} catch (RemoteException ex) {
Rlog.e(TAG, "requestNetworkScan RemoteException", ex);
@@ -223,9 +225,7 @@
private void saveScanInfo(
int id, NetworkScanRequest request, Executor executor, NetworkScanCallback callback) {
- synchronized (mScanInfo) {
- mScanInfo.put(id, new NetworkScanInfo(request, executor, callback));
- }
+ mScanInfo.put(id, new NetworkScanInfo(request, executor, callback));
}
private ITelephony getITelephony() {
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index cabd4df..5a90cb1 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -32,6 +32,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.telephony.TelephonyManager;
+import android.telephony.euicc.EuiccCardManager.ResetOption;
import com.android.internal.telephony.euicc.IEuiccController;
@@ -821,17 +822,22 @@
}
/**
- * Erase all subscriptions and reset the eUICC.
+ * Erase all operational subscriptions and reset the eUICC.
*
* <p>Requires that the calling app has the
* {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission.
*
* @param callbackIntent a PendingIntent to launch when the operation completes.
+ *
+ * @deprecated From R, callers should specify a flag for specific set of subscriptions to erase
+ * and use @link{eraseSubscriptionsWithOptions} instead
+ *
* @hide
*/
@SystemApi
@RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
- public void eraseSubscriptions(PendingIntent callbackIntent) {
+ @Deprecated
+ public void eraseSubscriptions(@NonNull PendingIntent callbackIntent) {
if (!isEnabled()) {
sendUnavailableError(callbackIntent);
return;
@@ -844,6 +850,32 @@
}
/**
+ * Erase all specific subscriptions and reset the eUICC.
+ *
+ * <p>Requires that the calling app has the
+ * {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission.
+ *
+ * @param options flag indicating specific set of subscriptions to erase
+ * @param callbackIntent a PendingIntent to launch when the operation completes.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
+ public void eraseSubscriptionsWithOptions(
+ @ResetOption int options, @NonNull PendingIntent callbackIntent) {
+ if (!isEnabled()) {
+ sendUnavailableError(callbackIntent);
+ return;
+ }
+ try {
+ getIEuiccController().eraseSubscriptionsWithOptions(mCardId, options, callbackIntent);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Ensure that subscriptions will be retained on the next factory reset.
*
* <p>By default, all subscriptions on the eUICC are erased the first time a device boots (ever
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 4d90579..fd7ec56 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1612,6 +1612,18 @@
String[] getForbiddenPlmns(int subId, int appType, String callingPackage);
/**
+ * Set the forbidden PLMN list from the givven app type (ex APPTYPE_USIM) on a particular
+ * subscription.
+ *
+ * @param subId subId the id of the subscription
+ * @param appType appType the uicc app type, must be USIM or SIM.
+ * @param fplmns plmns the Forbiden plmns list that needed to be written to the SIM.
+ * @param content callingPackage the op Package name.
+ * @return number of fplmns that is successfully written to the SIM
+ */
+ int setForbiddenPlmns(int subId, int appType, in List<String> fplmns, String callingPackage);
+
+ /**
* Check if phone is in emergency callback mode
* @return true if phone is in emergency callback mode
* @param subId the subscription ID that this action applies to.
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index c9ec0f8..c19ae7b 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -170,7 +170,7 @@
public static final int RIL_CARD_MAX_APPS = 8;
- public static final int DEFAULT_CARD_INDEX = 0;
+ public static final int DEFAULT_SLOT_INDEX = 0;
public static final int MAX_PHONE_COUNT_SINGLE_SIM = 1;
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index d892e55..4654437 100644
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -878,8 +878,9 @@
* Parses a broadcast SMS, possibly containing a CMAS alert.
*
* @param plmn the PLMN for a broadcast SMS
+ * @param subId
*/
- public SmsCbMessage parseBroadcastSms(String plmn) {
+ public SmsCbMessage parseBroadcastSms(String plmn, int subId) {
BearerData bData = BearerData.decode(mEnvelope.bearerData, mEnvelope.serviceCategory);
if (bData == null) {
Rlog.w(LOG_TAG, "BearerData.decode() returned null");
@@ -895,7 +896,7 @@
return new SmsCbMessage(SmsCbMessage.MESSAGE_FORMAT_3GPP2,
SmsCbMessage.GEOGRAPHICAL_SCOPE_PLMN_WIDE, bData.messageId, location,
mEnvelope.serviceCategory, bData.getLanguage(), bData.userData.payloadStr,
- bData.priority, null, bData.cmasWarningInfo);
+ bData.priority, null, bData.cmasWarningInfo, subId);
}
/**
diff --git a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
index 2016915..7422863 100644
--- a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
+++ b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
@@ -44,5 +44,7 @@
oneway void updateSubscriptionNickname(int cardId, int subscriptionId, String nickname,
String callingPackage, in PendingIntent callbackIntent);
oneway void eraseSubscriptions(int cardId, in PendingIntent callbackIntent);
+ oneway void eraseSubscriptionsWithOptions(
+ int cardId, int options, in PendingIntent callbackIntent);
oneway void retainSubscriptionsForFactoryReset(int cardId, in PendingIntent callbackIntent);
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java b/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java
index c65c45f..c3d490a 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java
@@ -90,9 +90,10 @@
* Create a new SmsCbMessage object from a header object plus one or more received PDUs.
*
* @param pdus PDU bytes
+ * @slotIndex slotIndex for which received sms cb message
*/
public static SmsCbMessage createSmsCbMessage(Context context, SmsCbHeader header,
- SmsCbLocation location, byte[][] pdus)
+ SmsCbLocation location, byte[][] pdus, int slotIndex)
throws IllegalArgumentException {
long receivedTimeMillis = System.currentTimeMillis();
if (header.isEtwsPrimaryNotification()) {
@@ -104,7 +105,7 @@
header.getSerialNumber(), location, header.getServiceCategory(), null,
getEtwsPrimaryMessage(context, header.getEtwsInfo().getWarningType()),
SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY, header.getEtwsInfo(),
- header.getCmasInfo(), 0, null /* geometries */, receivedTimeMillis);
+ header.getCmasInfo(), 0, null /* geometries */, receivedTimeMillis, slotIndex);
} else if (header.isUmtsFormat()) {
// UMTS format has only 1 PDU
byte[] pdu = pdus[0];
@@ -138,7 +139,7 @@
header.getGeographicalScope(), header.getSerialNumber(), location,
header.getServiceCategory(), language, body, priority,
header.getEtwsInfo(), header.getCmasInfo(), maximumWaitingTimeSec, geometries,
- receivedTimeMillis);
+ receivedTimeMillis, slotIndex);
} else {
String language = null;
StringBuilder sb = new StringBuilder();
@@ -154,7 +155,7 @@
header.getGeographicalScope(), header.getSerialNumber(), location,
header.getServiceCategory(), language, sb.toString(), priority,
header.getEtwsInfo(), header.getCmasInfo(), 0, null /* geometries */,
- receivedTimeMillis);
+ receivedTimeMillis, slotIndex);
}
}
diff --git a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
index 9c69e2d..f2d4624 100644
--- a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
+++ b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
@@ -22,11 +22,13 @@
import android.graphics.Color;
import android.telephony.Rlog;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.GsmAlphabet;
import dalvik.annotation.compat.UnsupportedAppUsage;
import java.io.UnsupportedEncodingException;
+import java.util.List;
/**
* Various methods, useful for dealing with SIM data.
@@ -34,6 +36,11 @@
public class IccUtils {
static final String LOG_TAG="IccUtils";
+ // 3GPP specification constants
+ // Spec reference TS 31.102 section 4.2.16
+ @VisibleForTesting
+ static final int FPLMN_BYTE_SIZE = 3;
+
// A table mapping from a number to a hex character for fast encoding hex strings.
private static final char[] HEX_CHARS = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
@@ -896,4 +903,27 @@
}
return 0;
}
+
+ /**
+ * Encode the Fplmns into byte array to write to EF.
+ *
+ * @param fplmns Array of fplmns to be serialized.
+ * @param dataLength the size of the EF file.
+ * @return the encoded byte array in the correct format for FPLMN file.
+ */
+ public static byte[] encodeFplmns(List<String> fplmns, int dataLength) {
+ byte[] serializedFplmns = new byte[dataLength];
+ int offset = 0;
+ for (String fplmn : fplmns) {
+ if (offset >= dataLength) break;
+ stringToBcdPlmn(fplmn, serializedFplmns, offset);
+ offset += FPLMN_BYTE_SIZE;
+ }
+ //pads to the length of the EF file.
+ while (offset < dataLength) {
+ // required by 3GPP TS 31.102 spec 4.2.16
+ serializedFplmns[offset++] = (byte) 0xff;
+ }
+ return serializedFplmns;
+ }
}
diff --git a/tests/Codegen/runTest.sh b/tests/Codegen/runTest.sh
index 82e9f03..0e90dea 100755
--- a/tests/Codegen/runTest.sh
+++ b/tests/Codegen/runTest.sh
@@ -16,6 +16,7 @@
header_and_eval codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java && \
header_and_eval codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java && \
header_and_eval codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java && \
+ header_and_eval codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java && \
cd $ANDROID_BUILD_TOP &&
header_and_eval mmma -j16 frameworks/base/tests/Codegen && \
header_and_eval adb install -r -t "$(find $ANDROID_TARGET_OUT_TESTCASES -name 'CodegenTests.apk')" && \
diff --git a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java
index 9e9ddae4..10eba6a 100644
--- a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java
+++ b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java
@@ -32,7 +32,7 @@
- // Code below generated by codegen v1.0.5.
+ // Code below generated by codegen v1.0.7.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -94,8 +94,8 @@
};
@DataClass.Generated(
- time = 1570231100269L,
- codegenVersion = "1.0.5",
+ time = 1570576455287L,
+ codegenVersion = "1.0.7",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java",
inputSignatures = "private int mBaseData\nclass HierrarchicalDataClassBase extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genSetters=true)")
@Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java
index 27a6933..1085a6a 100644
--- a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java
+++ b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java
@@ -46,7 +46,7 @@
- // Code below generated by codegen v1.0.5.
+ // Code below generated by codegen v1.0.7.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -116,8 +116,8 @@
};
@DataClass.Generated(
- time = 1570231101208L,
- codegenVersion = "1.0.5",
+ time = 1570576456245L,
+ codegenVersion = "1.0.7",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java",
inputSignatures = "private @android.annotation.NonNull java.lang.String mChildData\nclass HierrarchicalDataClassChild extends com.android.codegentest.HierrarchicalDataClassBase implements []\n@com.android.internal.util.DataClass(genParcelable=true, genConstructor=false, genSetters=true)")
@Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java b/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java
index dafece1..75ef963 100644
--- a/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java
+++ b/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java
@@ -48,7 +48,7 @@
- // Code below generated by codegen v1.0.5.
+ // Code below generated by codegen v1.0.7.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -374,8 +374,8 @@
}
@DataClass.Generated(
- time = 1570231099316L,
- codegenVersion = "1.0.5",
+ time = 1570576454326L,
+ codegenVersion = "1.0.7",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java",
inputSignatures = " @android.annotation.NonNull java.lang.String[] mStringArray\n @android.annotation.NonNull int[] mIntArray\n @android.annotation.NonNull java.util.List<java.lang.String> mStringList\n @android.annotation.NonNull java.util.Map<java.lang.String,com.android.codegentest.SampleWithCustomBuilder> mMap\n @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.String> mStringMap\n @android.annotation.NonNull android.util.SparseArray<com.android.codegentest.SampleWithCustomBuilder> mSparseArray\n @android.annotation.NonNull android.util.SparseIntArray mSparseIntArray\nclass ParcelAllTheThingsDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)")
@Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
index 1d73736..14010a9 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
@@ -342,7 +342,7 @@
- // Code below generated by codegen v1.0.5.
+ // Code below generated by codegen v1.0.7.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -1868,8 +1868,8 @@
}
@DataClass.Generated(
- time = 1570231097226L,
- codegenVersion = "1.0.5",
+ time = 1570576452225L,
+ codegenVersion = "1.0.7",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java",
inputSignatures = "public static final java.lang.String STATE_NAME_UNDEFINED\npublic static final java.lang.String STATE_NAME_ON\npublic static final java.lang.String STATE_NAME_OFF\npublic static final int STATE_UNDEFINED\npublic static final int STATE_ON\npublic static final int STATE_OFF\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_AUGMENTED_REQUEST\nprivate int mNum\nprivate int mNum2\nprivate int mNum4\nprivate @android.annotation.Nullable java.lang.String mName\nprivate @android.annotation.NonNull java.lang.String mName2\nprivate @android.annotation.NonNull java.lang.String mName4\nprivate @android.annotation.Nullable android.view.accessibility.AccessibilityNodeInfo mOtherParcelable\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.codegentest.MyDateParcelling.class) @android.annotation.NonNull java.util.Date mDate\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) @android.annotation.NonNull java.util.regex.Pattern mPattern\nprivate @android.annotation.NonNull java.util.List<android.net.LinkAddress> mLinkAddresses2\nprivate @com.android.internal.util.DataClass.PluralOf(\"linkAddress\") @android.annotation.NonNull java.util.ArrayList<android.net.LinkAddress> mLinkAddresses\nprivate @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses4\nprivate @com.android.codegentest.SampleDataClass.StateName @android.annotation.NonNull java.lang.String mStateName\nprivate @com.android.codegentest.SampleDataClass.RequestFlags int mFlags\nprivate @com.android.codegentest.SampleDataClass.State int mState\npublic @android.annotation.NonNull java.lang.CharSequence charSeq\nprivate final @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses5\nprivate transient android.net.LinkAddress[] mLinkAddresses6\ntransient int[] mTmpStorage\nprivate @android.annotation.StringRes int mStringRes\nprivate @android.annotation.IntRange(from=0L, to=6L) int mDayOfWeek\nprivate @android.annotation.Size(2L) @android.annotation.NonNull @com.android.internal.util.DataClass.Each @android.annotation.FloatRange(from=0.0) float[] mCoords\nprivate static java.lang.String defaultName4()\nprivate int[] lazyInitTmpStorage()\npublic android.net.LinkAddress[] getLinkAddresses4()\nprivate boolean patternEquals(java.util.regex.Pattern)\nprivate int patternHashCode()\nprivate void onConstructed()\npublic void dump(java.io.PrintWriter)\nclass SampleDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genConstructor=true, genEqualsHashCode=true, genToString=true, genForEachField=true, genSetters=true)")
@Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
index 2efa193..b5f6c73 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
@@ -85,7 +85,7 @@
- // Code below generated by codegen v1.0.5.
+ // Code below generated by codegen v1.0.7.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -249,8 +249,8 @@
}
@DataClass.Generated(
- time = 1570231098303L,
- codegenVersion = "1.0.5",
+ time = 1570576453295L,
+ codegenVersion = "1.0.7",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java",
inputSignatures = " long delayAmount\n @android.annotation.NonNull java.util.concurrent.TimeUnit delayUnit\n long creationTimestamp\nprivate static java.util.concurrent.TimeUnit unparcelDelayUnit(android.os.Parcel)\nprivate void parcelDelayUnit(android.os.Parcel,int)\nclass SampleWithCustomBuilder extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)\nabstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayAmount(long)\npublic abstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayUnit(java.util.concurrent.TimeUnit)\npublic com.android.codegentest.SampleWithCustomBuilder.Builder setDelay(long,java.util.concurrent.TimeUnit)\nclass BaseBuilder extends java.lang.Object implements []")
@Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java b/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java
new file mode 100644
index 0000000..0ce8aba
--- /dev/null
+++ b/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2019 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.codegentest;
+
+import android.annotation.NonNull;
+
+import com.android.internal.util.DataClass;
+
+/**
+ * Test for some false positive pitfalls for
+ * {@link android.processor.staledataclass.StaleDataclassProcessor}
+ *
+ * Relies on the detector being run, failing the build should any of things here falsely
+ * register as stale.
+ */
+@DataClass(genConstructor = false, genBuilder = false)
+public class StaleDataclassDetectorFalsePositivesTest {
+
+ /** Interfaces should be ignored */
+ public interface SomeListener {
+ void onEvent();
+ }
+
+ /** Enums should be ignored */
+ private enum SomeEnum { ONE, TWO }
+
+ /** Annotations should be ignored */
+ public @interface SomeAnnotation {}
+
+ /* Static initializers should be ignored */
+ static {}
+
+ /* Initializers should be ignored */
+ {}
+
+ /** Unrelated methods should be noted, without triggering staleness false positives */
+ public @NonNull String someMethod(int param) { return null; }
+
+
+
+ // Code below generated by codegen v1.0.7.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java
+
+
+ @DataClass.Generated(
+ time = 1570576457249L,
+ codegenVersion = "1.0.7",
+ sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java",
+ inputSignatures = "public @android.annotation.NonNull java.lang.String someMethod(int)\nclass StaleDataclassDetectorFalsePositivesTest extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false)")
+ @Deprecated
+ private void __metadata() {}
+
+}
diff --git a/tests/net/common/java/android/net/LinkPropertiesTest.java b/tests/net/common/java/android/net/LinkPropertiesTest.java
index b0464d9..ae8285b 100644
--- a/tests/net/common/java/android/net/LinkPropertiesTest.java
+++ b/tests/net/common/java/android/net/LinkPropertiesTest.java
@@ -99,6 +99,7 @@
assertFalse(lp.isIpv4Provisioned());
assertFalse(lp.isIpv6Provisioned());
assertFalse(lp.isPrivateDnsActive());
+ assertFalse(lp.isWakeOnLanSupported());
}
private LinkProperties makeTestObject() {
@@ -120,6 +121,7 @@
lp.setMtu(MTU);
lp.setTcpBufferSizes(TCP_BUFFER_SIZES);
lp.setNat64Prefix(new IpPrefix("2001:db8:0:64::/96"));
+ lp.setWakeOnLanSupported(true);
return lp;
}
@@ -158,6 +160,9 @@
assertTrue(source.isIdenticalTcpBufferSizes(target));
assertTrue(target.isIdenticalTcpBufferSizes(source));
+ assertTrue(source.isIdenticalWakeOnLan(target));
+ assertTrue(target.isIdenticalWakeOnLan(source));
+
// Check result of equals().
assertTrue(source.equals(target));
assertTrue(target.equals(source));
@@ -1057,4 +1062,13 @@
lp.clear();
assertFalse(lp.isPrivateDnsActive());
}
+
+ @Test
+ public void testWakeOnLanSupported() {
+ final LinkProperties lp = makeTestObject();
+ assertTrue(lp.isWakeOnLanSupported());
+
+ lp.clear();
+ assertFalse(lp.isWakeOnLanSupported());
+ }
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 41440ab..bffbbfd 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -274,6 +274,7 @@
private static final String CLAT_PREFIX = "v4-";
private static final String MOBILE_IFNAME = "test_rmnet_data0";
private static final String WIFI_IFNAME = "test_wlan0";
+ private static final String WIFI_WOL_IFNAME = "test_wlan_wol";
private static final String[] EMPTY_STRING_ARRAY = new String[0];
private MockContext mServiceContext;
@@ -343,6 +344,12 @@
"mobile_mms,2,0,2,60000,true",
});
+ when(mResources.getStringArray(
+ com.android.internal.R.array.config_wakeonlan_supported_interfaces))
+ .thenReturn(new String[]{
+ WIFI_WOL_IFNAME,
+ });
+
mContentResolver = new MockContentResolver();
mContentResolver.addProvider(Settings.AUTHORITY, settingsProvider);
}
@@ -5947,6 +5954,24 @@
assertContainsExactly(uidCaptor.getValue(), APP2_UID);
}
+ @Test
+ public void testLinkPropertiesWithWakeOnLanForActiveNetwork() throws Exception {
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+
+ LinkProperties wifiLp = new LinkProperties();
+ wifiLp.setInterfaceName(WIFI_WOL_IFNAME);
+ wifiLp.setWakeOnLanSupported(false);
+
+ // Default network switch should update ifaces.
+ mWiFiNetworkAgent.connect(false);
+ mWiFiNetworkAgent.sendLinkProperties(wifiLp);
+ waitForIdle();
+
+ // ConnectivityService should have changed the WakeOnLanSupported to true
+ wifiLp.setWakeOnLanSupported(true);
+ assertEquals(wifiLp, mService.getActiveLinkProperties());
+ }
+
private TestNetworkAgentWrapper establishVpn(LinkProperties lp, int establishingUid,
Set<UidRange> vpnRange) throws Exception {
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index 7029218..3fdba6e 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -54,7 +54,6 @@
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
-import android.content.pm.PackageList;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.UserInfo;
@@ -70,6 +69,7 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.server.LocalServices;
+import com.android.server.pm.PackageList;
import org.junit.Before;
import org.junit.Test;
diff --git a/tools/codegen/src/com/android/codegen/SharedConstants.kt b/tools/codegen/src/com/android/codegen/SharedConstants.kt
index a36f2c83..47f774f 100644
--- a/tools/codegen/src/com/android/codegen/SharedConstants.kt
+++ b/tools/codegen/src/com/android/codegen/SharedConstants.kt
@@ -1,7 +1,7 @@
package com.android.codegen
const val CODEGEN_NAME = "codegen"
-const val CODEGEN_VERSION = "1.0.5"
+const val CODEGEN_VERSION = "1.0.7"
const val CANONICAL_BUILDER_CLASS = "Builder"
const val BASE_BUILDER_CLASS = "BaseBuilder"
diff --git a/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt b/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt
index d00def6..7fe21c7 100644
--- a/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt
+++ b/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt
@@ -182,6 +182,11 @@
.filterNot {
it.kind == ElementKind.CLASS
|| it.kind == ElementKind.CONSTRUCTOR
+ || it.kind == ElementKind.INTERFACE
+ || it.kind == ElementKind.ENUM
+ || it.kind == ElementKind.ANNOTATION_TYPE
+ || it.kind == ElementKind.INSTANCE_INIT
+ || it.kind == ElementKind.STATIC_INIT
|| isGenerated(it)
}.map {
elemToString(it)